subrepo:
  subdir:   "libopencm3"
  merged:   "f5813a54"
upstream:
  origin:   "https://github.com/libopencm3/libopencm3"
  branch:   "master"
  commit:   "f5813a54"
git-subrepo:
  version:  "0.4.3"
  origin:   "???"
  commit:   "???"
This commit is contained in:
2021-09-30 16:34:10 +03:00
parent 1a441e5806
commit 244fdbc35c
1125 changed files with 185440 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
openocd.*.local.cfg
generated.*

View File

@@ -0,0 +1,6 @@
# Put this in /etc/udev/rules.d/70-libopencm3.rules
# then do "sudo udevadm control --reload" and unplug/replug the usb device.
# This grants user accesss to the "cafe" USB Vendor ID used/hijacked/squatted by the test gadget
# libopencm hacking
SUBSYSTEMS=="usb", ATTRS{idVendor}=="cafe", TAG+="uaccess"

View File

@@ -0,0 +1,84 @@
pipeline {
agent {label 'locm3-usb'}
parameters {
string(name:'pr_from_git_url', description:'the git url we are going to clone the pr from')
string(name:'pr_from_sha', description:'what we are going to build')
}
stages {
stage('checkout') {
steps {
sh "echo karl we are building $pr_from_sha"
checkout([$class: 'GitSCM', branches: [[name: "$pr_from_sha"]], userRemoteConfigs: [[url: "$pr_from_git_url"]]])
step([
$class: "GitHubCommitStatusSetter",
commitShaSource: [$class: "ManuallyEnteredShaSource", sha: "$pr_from_sha"],
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/libopencm3/libopencm3"],
contextSource: [$class: "DefaultCommitContextSource"],
statusResultSource: [ $class: "DefaultStatusResultSource"]
]);
}
}
stage('prepare') {
steps {
sh label: 'preparing python', script: '''
[ -f .env3 ] || python3 -m venv .env3
. .env3/bin/activate
pip install pyusb
pip install unittest-xml-reporting
'''
}
}
stage('build') {
steps {
sh '''
. .env3/bin/activate
make V=1
make -C tests/gadget-zero all V=s
'''
}
}
stage('Testprepare') {
steps {
sh label: 'gadget0', script: '''
cd tests/gadget-zero
echo "hla_serial 53FF6E066765505136472567" > openocd.stm32f3-disco.local.cfg
echo "hla_serial 57FF6B064967485630481087" > openocd.stm32f4disco.local.cfg
'''
}
}
stage('flashin') {
steps {
dir('tests/gadget-zero') {
sh '''
make -f Makefile.stm32f3-disco flash V=1
make -f Makefile.stm32f4disco flash V=1
'''
}
}
}
stage('run-test') {
steps {
sh '''
. .env3/bin/activate
cd tests/gadget-zero
rm -rf tests
python test_gadget0.py -X
for x in tests/*; do TT=$(basename \$x); sed -i "s/testcase\\ classname=\\"/testcase\\ classname=\\"\${TT}./g" \$x/TEST-*; done
'''
}
}
}
post {
always {
step([$class: "GitHubCommitStatusSetter",
commitShaSource: [$class: "ManuallyEnteredShaSource", sha: "$pr_from_sha"],
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/libopencm3/libopencm3"],
contextSource: [$class: "DefaultCommitContextSource"],
statusResultSource: [ $class: "DefaultStatusResultSource"]
]);
junit 'tests/gadget-zero/tests/*/TEST-*.xml'
}
}
}

View File

@@ -0,0 +1,15 @@
# This is just a stub makefile used for travis builds
# to keep things all compiling. Normally you'd use
# one of the makefiles directly.
# These hoops are to enable parallel make correctly.
GZ_ALL := $(wildcard Makefile.*)
all: $(GZ_ALL:=.all)
clean: $(GZ_ALL:=.clean)
%.all:
$(MAKE) -f $* all
%.clean:
$(MAKE) -f $* clean

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = efm32hg309-generic
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c
CFILES += delay_efm32.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=efm32hg309f64
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32f072disco
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32f072rb
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32f103-generic
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../../
### This section can go to an arch shared rules eventually...
DEVICE=stm32f103x8
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32f3-disco
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32f303xc
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32f429i-disco
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32f405re
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32f4disco
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32f405re
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32l053disco
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32l053x8
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = stm32l1-generic
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=stm32l151c8
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,40 @@
##
## This file is part of the libopencm3 project.
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
BOARD = tilm4f120xl
PROJECT = usb-gadget0-$(BOARD)
BUILD_DIR = bin-$(BOARD)
SHARED_DIR = ../shared
CFILES = main-$(BOARD).c
CFILES += usb-gadget0.c trace.c trace_stdio.c
#CFILES += delay.c
VPATH += $(SHARED_DIR)
INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
OPENCM3_DIR=../..
### This section can go to an arch shared rules eventually...
DEVICE=lm4f120xl
OOCD_FILE = openocd.$(BOARD).cfg
include $(OPENCM3_DIR)/mk/genlink-config.mk
include $(OPENCM3_DIR)/mk/genlink-rules.mk
include ../rules.mk

View File

@@ -0,0 +1,71 @@
This project, inspired by [usbtest](http://www.linux-usb.org/usbtest/) and
the linux usb gadget zero driver is used for regression testing changes to the
libopencm3 usb stack.
The firmware itself is meant to be portable to any supported hardware, and then
identical unit test code is run against all platforms. This project can and
should be built for multiple devices.
## Requirements:
* [pyusb](https://walac.github.io/pyusb/) for running the tests.
* [OpenOCD](http://openocd.org/) >= 0.9 for automated flashing of specific boards
* python3 for running the tests at the command line.
* unittest-xml-reporting, only if running in CI mode. XX
### Building the device firmware
There are Makefile.xxxxx files for all the currently tested targets.
```
make -f Makefile.stm32f4disco clean all V=1
```
The ```V=1``` is optional, and turns on verbose mode, which can be useful if
things don't work. This will give you a .elf file you can program using your
own toolchain, but if you have a functional OpenOCD installed, then...
```
make -f Makefile.stm32f4disco clean all flash
```
Will handle flashing as well.
### Setting up the test runner (using python virtual environments)
```
pyvenv .env # ensures a python3 virtual env
. .env/bin/activate
pip install pyusb
```
If you have multiple test boards connected, have a look at opencd.common.cfg
for some tips on selectively matching the right board. For people with just
a single matching board, you don't need to do anything.
Tests marked as @unittest.skip are either for functionality that is known to be
broken, and are awaiting code fixes, or are long running performance tests
### Access rights
On some systems (most linux systems) you probably won't have access to the
usb vendor id being used/hijacked by the test cases. See 70-libopencm3.rules
for installation instructions, or, if you have your own system, grant yourself
access to the usb vid: 0xcafe
## Running the tests
Below is an example of running the full suite of tests from the command line.
The argument specifies the serial number to look for in the usb gadget, if
you have more than one. No argument will the tests against all
gadget-zero's found.
```
$ python test_gadget0.py
Running tests for DUT: stm32f072disco
.........ss................
----------------------------------------------------------------------
Ran 27 tests in 0.388s
OK (skipped=2)
```
To be even more brutal, run this in a shell loop.
```
$ while true; do python test_gadget0.py -d stm32f072disco; done
```
You can also run individual tests, or individual sets of tests, see the [unittest documentation](https://docs.python.org/3/library/unittest.html) for more information.
Many development environments, such as [PyCharm](https://www.jetbrains.com/pycharm/) can
also be used to edit and run the tests, in whole or individually, with a nice visual test runner.

View File

@@ -0,0 +1,50 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file implements some simple busy timers. They are designed to be
* portable, not performant.
* TIM6 is appropriated for usage.
*/
#include <stdint.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/timer.h>
#include "delay.h"
void delay_setup(void)
{
/* set up a microsecond free running timer for ... things... */
rcc_periph_clock_enable(RCC_TIM6);
/* microsecond counter */
timer_set_prescaler(TIM6, rcc_apb1_frequency / 1000000 - 1);
timer_set_period(TIM6, 0xffff);
timer_one_shot_mode(TIM6);
}
void delay_us(uint16_t us)
{
TIM_ARR(TIM6) = us;
TIM_EGR(TIM6) = TIM_EGR_UG;
TIM_CR1(TIM6) |= TIM_CR1_CEN;
//timer_enable_counter(TIM6);
while (TIM_CR1(TIM6) & TIM_CR1_CEN);
}

View File

@@ -0,0 +1,39 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* Initialize the timers used for delays.
*/
void delay_setup(void);
/**
* busy wait for a number of usecs.
* @param us number of usecs to delay.
*/
void delay_us(uint16_t us);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,45 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2018 Seb Holzapfel <schnommus@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <libopencm3/efm32/cmu.h>
#include <libopencm3/efm32/timer.h>
#include "delay.h"
extern const uint32_t ahb_frequency;
void delay_setup(void)
{
cmu_periph_clock_enable(CMU_TIMER2);
/* efm32hg doesn't support a nice 1us prescaler */
timer_start(TIMER2);
}
void delay_us(uint16_t us)
{
volatile uint16_t time_now = 0;
/* Convert microseconds into timer ticks */
uint16_t delay_ahb_cycles = us * (ahb_frequency / 1000000);
TIMER2_CNT = 0;
while (time_now < delay_ahb_cycles) {
time_now = TIMER2_CNT;
}
}

View File

@@ -0,0 +1,57 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
* Copyright (C) 2018 Seb Holzapfel <schnommus@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/common.h>
#include <libopencm3/cm3/vector.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h>
#include <stdio.h>
#include "usb-gadget0.h"
/* no trace on cm0 #define ER_DEBUG */
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
const uint32_t ahb_frequency = 14000000;
#include "trace.h"
void trace_send_blocking8(int stimulus_port, char c)
{
(void)stimulus_port;
(void)c;
}
int main(void)
{
usbd_device *usbd_dev = gadget0_init(&efm32hg_usb_driver,
"efm32hg309-generic");
ER_DPRINTF("bootup complete\n");
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/crs.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <stdio.h>
#include "usb-gadget0.h"
/* no trace on cm0 #define ER_DEBUG */
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
#include "trace.h"
void trace_send_blocking8(int stimulus_port, char c)
{
(void)stimulus_port;
(void)c;
}
int main(void)
{
rcc_clock_setup_in_hsi48_out_48mhz();
crs_autotrim_usb_enable();
rcc_set_usbclk_source(RCC_HSI48);
/* LED on for boot progress */
rcc_periph_clock_enable(RCC_GPIOC);
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO7);
gpio_set(GPIOC, GPIO7);
usbd_device *usbd_dev = gadget0_init(&st_usbfs_v2_usb_driver,
"stm32f072disco");
ER_DPRINTF("bootup complete\n");
gpio_clear(GPIOC, GPIO7);
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,71 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <stdio.h>
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
int main(void)
{
rcc_clock_setup_pll(&rcc_hsi_configs[RCC_CLOCK_HSI_48MHZ]);
/* LED to indicate boot process */
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
gpio_set(GPIOC, GPIO13);
rcc_periph_clock_enable(RCC_GPIOA);
/*
* Vile hack to reenumerate, physically _drag_ d+ low.
* do NOT do this if you're board has proper usb pull up control!
* (need at least 2.5us to trigger usb disconnect)
*/
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOA, GPIO12);
for (unsigned int i = 0; i < 800000; i++) {
__asm__("nop");
}
rcc_periph_clock_enable(RCC_OTGFS);
usbd_device *usbd_dev = gadget0_init(&st_usbfs_v1_usb_driver,
"stm32f103-generic");
ER_DPRINTF("bootup complete\n");
gpio_clear(GPIOC, GPIO13);
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,75 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* "generic" could be any L1 board, but this file is pre-configured for the
* libopencm3-tests "hw1" board, with an stm32l151c8-A part.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/syscfg.h>
#include <stdio.h>
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
int main(void)
{
rcc_periph_clock_enable(RCC_GPIOE);
gpio_mode_setup(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO11|GPIO12);
gpio_set(GPIOE, GPIO12);
rcc_clock_setup_pll(&rcc_hse8mhz_configs[RCC_CLOCK_HSE8_72MHZ]);
rcc_periph_clock_enable(RCC_GPIOA);
/*
* Vile hack to reenumerate, physically _drag_ d+ low.
* do NOT do this if you're board has proper usb pull up control!
* (need at least 2.5us to trigger usb disconnect)
*/
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12);
gpio_clear(GPIOA, GPIO12);
for (unsigned int i = 0; i < 800000; i++) {
__asm__("nop");
}
/* now return PA11/PA12 to usb AF */
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11|GPIO12);
gpio_set_af(GPIOA, GPIO_AF14, GPIO11|GPIO12);
usbd_device *usbd_dev = gadget0_init(&st_usbfs_v1_usb_driver,
"stm32f3-disco");
ER_DPRINTF("bootup complete\n");
gpio_clear(GPIOE, GPIO12);
static int i = 0;
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <stdio.h>
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
int main(void)
{
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_OTGHS);
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,
GPIO13 | GPIO14 | GPIO15);
gpio_set_af(GPIOB, GPIO_AF12, GPIO13 | GPIO14 | GPIO15);
/* LEDS on discovery board */
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15);
usbd_device *usbd_dev = gadget0_init(&otghs_usb_driver, "stm32f429i-disco");
ER_DPRINTF("bootup complete\n");
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <stdio.h>
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
int main(void)
{
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_OTGFS);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
/* LEDS on discovery board */
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15);
usbd_device *usbd_dev = gadget0_init(&otgfs_usb_driver, "stm32f4disco");
ER_DPRINTF("bootup complete\n");
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,90 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/crs.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/syscfg.h>
#include <stdio.h>
#include "usb-gadget0.h"
/* no trace on cm0 #define ER_DEBUG */
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
#include "trace.h"
void trace_send_blocking8(int stimulus_port, char c)
{
(void)stimulus_port;
(void)c;
}
int main(void)
{
/* LED for boot progress */
rcc_periph_clock_enable(RCC_GPIOA);
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5);
gpio_set(GPIOA, GPIO5);
/* PLL from HSI16, just to exercise that code */
struct rcc_clock_scale myclock = {
.ahb_frequency = 32e6,
.apb1_frequency = 32e6,
.apb2_frequency = 32e6,
.flash_waitstates = 1,
.pll_source = RCC_CFGR_PLLSRC_HSI16_CLK, /* not even sure there's hse on l053 disco */
/* .msi_range doesn't matter */
.pll_mul = RCC_CFGR_PLLMUL_MUL4,
.pll_div = RCC_CFGR_PLLDIV_DIV2,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE1_NODIV,
.ppre2 = RCC_CFGR_PPRE2_NODIV,
};
rcc_clock_setup_pll(&myclock);
/* HSI48 needs the vrefint turned on */
rcc_periph_clock_enable(RCC_SYSCFG);
SYSCFG_CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48 | SYSCFG_CFGR3_EN_VREFINT;
while (!(SYSCFG_CFGR3 & SYSCFG_CFGR3_REF_HSI48_RDYF));
/* For USB, but can't use HSI48 as a sysclock on L0 */
crs_autotrim_usb_enable();
rcc_set_hsi48_source_rc48();
rcc_osc_on(RCC_HSI48);
rcc_wait_for_osc_ready(RCC_HSI48);
usbd_device *usbd_dev = gadget0_init(&st_usbfs_v2_usb_driver,
"stm32l053disco");
ER_DPRINTF("bootup complete\n");
gpio_clear(GPIOA, GPIO5);
while (1) {
gadget0_run(usbd_dev);
}
}

View File

@@ -0,0 +1,81 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* "generic" could be any L1 board, but this file is pre-configured for the
* libopencm3-tests "hw1" board, with an stm32l151c8-A part.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/syscfg.h>
#include <stdio.h>
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
const struct rcc_clock_scale this_clock_config = {
/* 32MHz PLL from 16MHz HSE, 96MHz for USB on PLL VCO out */
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.pll_mul = RCC_CFGR_PLLMUL_MUL6,
.pll_div = RCC_CFGR_PLLDIV_DIV3,
.hpre = RCC_CFGR_HPRE_SYSCLK_NODIV,
.ppre1 = RCC_CFGR_PPRE1_HCLK_NODIV,
.ppre2 = RCC_CFGR_PPRE2_HCLK_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 1,
.ahb_frequency = 32000000,
.apb1_frequency = 32000000,
.apb2_frequency = 32000000,
};
int main(void)
{
rcc_periph_clock_enable(RCC_GPIOB);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8|GPIO9);
gpio_set(GPIOB, GPIO8);
rcc_clock_setup_pll(&this_clock_config);
/* Enable built in USB pullup on L1 */
rcc_periph_clock_enable(RCC_SYSCFG);
SYSCFG_PMC |= SYSCFG_PMC_USB_PU;
usbd_device *usbd_dev = gadget0_init(&st_usbfs_v1_usb_driver,
"stm32l1-generic");
ER_DPRINTF("bootup complete\n");
gpio_clear(GPIOB, GPIO8);
while (1) {
gpio_set(GPIOB, GPIO9);
gadget0_run(usbd_dev);
gpio_clear(GPIOB, GPIO9);
}
}

View File

@@ -0,0 +1,70 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2018 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/lm4f/gpio.h>
#include <libopencm3/lm4f/rcc.h>
#include <libopencm3/lm4f/systemcontrol.h>
#include <stdio.h>
#include "delay.h"
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
/* FIXME - implement delay functionality for better test coverage */
void delay_setup(void) {
}
void delay_us(uint16_t us) {
(void)us;
}
int main(void)
{
gpio_enable_ahb_aperture();
#define PLL_DIV_80MHZ 5
rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLL_DIV_80MHZ);
periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(GPIOD, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4 | GPIO5);
/* blue LED on board */
periph_clock_enable(RCC_GPIOF);
gpio_mode_setup(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2);
gpio_set_output_config(GPIOF, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, GPIO2);
usbd_device *usbd_dev = gadget0_init(&lm4f_usb_driver, "tilm4f120xl");
ER_DPRINTF("bootup complete\n");
while (1) {
gpio_set(GPIOF, GPIO2);
gadget0_run(usbd_dev);
gpio_clear(GPIOF, GPIO2);
}
}

View File

@@ -0,0 +1,10 @@
# Shared openocd script helpers
# put things like "hla_serial 'asdfadfa'" in openocd.<board>.local.cfg to support
# multiple simultaneously connected boards.
proc optional_local { LOCAL_FILE } {
if { [ file exists $LOCAL_FILE ] } {
puts "Loading custom local settings from $LOCAL_FILE"
source $LOCAL_FILE
}
}

View File

@@ -0,0 +1,14 @@
# Generic efm32hg309 on Tomu board, using stm32l053-disco as debugger
source [find interface/stlink-v2-1.cfg]
transport select hla_swd
adapter_khz 1000
set CHIPNAME efm32hg309
set CPUTAPID 0x0bc11477
source [find target/efm32.cfg]
source openocd.common.cfg
optional_local "openocd.efm32hg309-generic.local.cfg"
init
targets
reset halt

View File

@@ -0,0 +1,14 @@
source [find interface/stlink-v2.cfg]
set WORKAREASIZE 0x4000
source [find target/stm32f0x.cfg]
source openocd.common.cfg
optional_local "openocd.stm32f072disco.local.cfg"
# no trace on cm0
#tpiu config internal swodump.stm32f4disco.log uart off 168000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,15 @@
# Unfortunately, with no f103 disco, we're currently
# using a separate disco board
source [find interface/stlink-v2.cfg]
set WORKAREASIZE 0x2000
source [find target/stm32f1x.cfg]
source openocd.common.cfg
optional_local "openocd.stm32f103-generic.local.cfg"
tpiu config internal swodump.stm32f103-generic.log uart off 72000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,14 @@
source [find interface/stlink-v2.cfg]
set WORKAREASIZE 0x4000
source [find target/stm32f3x.cfg]
# Include a local serial config file if available
source openocd.common.cfg
optional_local "openocd.stm32f3-disco.local.cfg"
tpiu config internal swodump.stm32f3-disco.log uart off 72000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,13 @@
source [find interface/stlink-v2.cfg]
set WORKAREASIZE 0x4000
source [find target/stm32f4x.cfg]
source openocd.common.cfg
optional_local "openocd.stm32f429i-disco.local.cfg"
tpiu config internal swodump.stm32f429i-disco.log uart off 168000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,13 @@
source [find interface/stlink-v2.cfg]
set WORKAREASIZE 0x4000
source [find target/stm32f4x.cfg]
source openocd.common.cfg
optional_local "openocd.stm32f4disco.local.cfg"
tpiu config internal swodump.stm32f4disco.log uart off 168000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,14 @@
source [find interface/stlink-v2-1.cfg]
set WORKAREASIZE 0x1000
source [find target/stm32l0.cfg]
source openocd.common.cfg
optional_local "openocd.stm32l053disco.local.cfg"
# no trace on cm0
#tpiu config internal swodump.stm32f4disco.log uart off 168000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,13 @@
# l1 generic, using a l4 disco board
source [find interface/stlink-v2-1.cfg]
set WORKAREASIZE 0x2000
source [find target/stm32l1.cfg]
source openocd.common.cfg
optional_local "openocd.stm32l1-generic.local.cfg"
tpiu config internal swodump.stm32l1-generic.log uart off 32000000
# Uncomment to reset on connect, for grabbing under WFI et al
reset_config srst_only srst_nogate
# reset_config srst_only srst_nogate connect_assert_srst

View File

@@ -0,0 +1,4 @@
__author__ = 'karlp'
def config_switch():
pass

View File

@@ -0,0 +1,545 @@
#!/usr/bin/env python3
"""
Tests for the libopencm3 USB stack. Uses pyusb to make a variety of transfers, both legal and illegal to
exercise as many paths of the stack as possible for consistency and functionality.
By default, will attempt to run the test suite against any detected compatible firmware, based on a fixed
VID:PID pair defined in the firmware. Can also be told to test just a single device
Requires pyusb. unittest-xml-reporting also required for xUnit reports
"""
import argparse
import array
import datetime
import random
import usb.core
import usb.util as uu
import random
import sys
import unittest
VENDOR_ID=0xcafe
PRODUCT_ID=0xcafe
# you only need to worry about these if you are trying to explicitly test
# a single target. Normally, the test will autofind the attached target
DUT_SERIAL=None
#DUT_SERIAL = "stm32f429i-disco"
#DUT_SERIAL = "stm32f4disco"
#DUT_SERIAL = "stm32f103-generic"
#DUT_SERIAL = "stm32l1-generic"
#DUT_SERIAL = "stm32f072disco"
#DUT_SERIAL = "stm32l053disco"
GZ_REQ_SET_PATTERN=1
GZ_REQ_PRODUCE=2
GZ_REQ_SET_ALIGNED=3
GZ_REQ_SET_UNALIGNED=4
GZ_REQ_WRITE_LOOPBACK_BUFFER=10
GZ_REQ_READ_LOOPBACK_BUFFER=11
GZ_REQ_INTEL_WRITE=0x5b
GZ_REQ_INTEL_READ=0x5c
class find_by_serial(object):
def __init__(self, serial):
self._serial = serial
def __call__(self, device):
return usb.util.get_string(device, device.iSerialNumber)
class TestGadget0(unittest.TestCase):
# TODO - parameterize this with serial numbers so we can find
# gadget 0 code for different devices. (or use different PIDs?)
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.longMessage = True
def tearDown(self):
uu.dispose_resources(self.dev)
def test_sanity(self):
self.assertEqual(2, self.dev.bNumConfigurations, "Should have 2 configs")
def test_config_switch_2(self):
"""
Uses the API if you're interested in the cfg block
"""
cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(cfg, "Config 2 should exist")
self.dev.set_configuration(cfg)
def test_config_switch_3(self):
"""
Uses the simple API
"""
self.dev.set_configuration(3)
def test_config_zero_addressed(self):
self.dev.set_configuration(0)
x = self.dev.ctrl_transfer(0x80, 0x08, 0, 0, 1)
self.assertEqual(0, x[0], "Should be configuration 0 before configuration is set")
def test_fetch_config(self):
self.dev.set_configuration(3)
# FIXME - find a way to get the defines for these from pyusb
x = self.dev.ctrl_transfer(0x80, 0x08, 0, 0, 1)
self.assertEqual(3, x[0], "Should get the actual bConfigurationValue back")
def test_invalid_config(self):
try:
# FIXME - find a way to get the defines for these from pyusb
self.dev.ctrl_transfer(0x00, 0x09, 99)
self.fail("Request of invalid cfg should have failed")
except usb.core.USBError as e:
# Note, this might not be as portable as we'd like.
self.assertIn("Pipe", e.strerror)
class TestIntelCompliance(unittest.TestCase):
"""
Part of intel's usb 2.0 compliance is writing and reading back control transfers
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg)
def tearDown(self):
uu.dispose_resources(self.dev)
def inner_t(self, mylen):
data = [random.randrange(255) for x in range(mylen)]
written = self.dev.ctrl_transfer(uu.CTRL_OUT | uu.CTRL_RECIPIENT_INTERFACE | uu.CTRL_TYPE_VENDOR, GZ_REQ_INTEL_WRITE, 0, 0, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
# now. in _theory_ I should be able to make a bulk transfer here and have it not "interfere"
# fixme - try this out?
read = self.dev.ctrl_transfer(uu.CTRL_IN | uu.CTRL_RECIPIENT_INTERFACE | uu.CTRL_TYPE_VENDOR, GZ_REQ_INTEL_READ, 0, 0, mylen)
self.assertEqual(mylen, len(read))
expected = array.array('B', [x for x in data])
self.assertEqual(expected, read, "should have read back what we wrote")
def test_ctrl_loopbacks(self):
self.inner_t(0)
self.inner_t(10)
self.inner_t(63)
self.inner_t(64)
self.inner_t(65)
self.inner_t(140)
self.inner_t(183)
class TestConfigSourceSink(unittest.TestCase):
"""
We could inherit, but it doesn't save much, and this saves me from remembering how to call super.
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg)
self.intf = self.cfg[(0, 0)]
# heh, kinda gross...
self.ep_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT][0]
self.ep_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN][0]
def tearDown(self):
uu.dispose_resources(self.dev)
def test_write_simple(self):
"""
here we go, start off with just a simple write of < bMaxPacketSize and just make sure it's accepted
:return:
"""
data = [x for x in range(int(self.ep_out.wMaxPacketSize / 2))]
written = self.dev.write(self.ep_out, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
def test_write_zlp(self):
written = self.ep_out.write([])
self.assertEqual(0, written, "should have written zero for a zero length write y0")
def test_write_batch(self):
"""
Write 50 max sized packets. Should not stall. Will stall if firmware isn't consuming data properly
:return:
"""
for i in range(50):
data = [x for x in range(int(self.ep_out.wMaxPacketSize))]
written = self.dev.write(self.ep_out, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
def test_write_mixed(self):
for i in range(int(self.ep_out.wMaxPacketSize / 4), self.ep_out.wMaxPacketSize * 10, 11):
data = [x & 0xff for x in range(i)]
written = self.ep_out.write(data)
self.assertEqual(written, len(data), "should have written all bytes plz")
def test_read_zeros(self):
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 0)
self.ep_in.read(self.ep_in.wMaxPacketSize) # Clear out any prior pattern data
# unless, you know _exactly_ how much will be written by the device, always read
# an integer multiple of max packet size, to avoid overflows.
# the returned data will have the actual length.
# You can't just magically read out less than the device wrote.
read_size = self.ep_in.wMaxPacketSize * 10
data = self.dev.read(self.ep_in, read_size)
self.assertEqual(len(data), read_size, "Should have read as much as we asked for")
expected = array.array('B', [0 for x in range(read_size)])
self.assertEqual(data, expected, "In pattern 0, all source data should be zeros: ")
def test_read_sequence(self):
# switching to the mod63 pattern requires resynching carefully to read out any zero frames already
# queued, but still make sure we start the sequence at zero.
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 1)
self.ep_in.read(self.ep_in.wMaxPacketSize) # Potentially queued zeros, or would have been safe.
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 1)
self.ep_in.read(self.ep_in.wMaxPacketSize) # definitely right pattern now, but need to restart at zero.
read_size = self.ep_in.wMaxPacketSize * 3
data = self.dev.read(self.ep_in, read_size)
self.assertEqual(len(data), read_size, "Should have read as much as we asked for")
expected = array.array('B', [x % 63 for x in range(read_size)])
self.assertEqual(data, expected, "In pattern 1, Should be % 63")
def test_read_write_interleaved(self):
for i in range(1, 20):
ii = self.ep_in.read(self.ep_in.wMaxPacketSize * i)
dd = [x & 0xff for x in range(i * 20 + 3)]
oo = self.ep_out.write(dd)
self.assertEqual(len(ii), self.ep_in.wMaxPacketSize * i, "should have read full packet")
self.assertEqual(oo, len(dd), "should have written full packet")
def test_control_known(self):
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 0)
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 1)
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 99)
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, GZ_REQ_SET_PATTERN, 0)
def test_control_unknown(self):
try:
self.dev.ctrl_transfer(uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE, 42, 69)
self.fail("Should have got a stall")
except usb.core.USBError as e:
# Note, this might not be as portable as we'd like.
self.assertIn("Pipe", e.strerror)
class TestConfigLoopBack(unittest.TestCase):
"""
We could inherit, but it doesn't save much, and this saves me from remembering how to call super.
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=3)
self.assertIsNotNone(self.cfg, "Config 3 should exist")
self.dev.set_configuration(self.cfg)
self.intf = self.cfg[(0, 0)]
# heh, kinda gross...
self.eps_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT]
self.eps_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN]
def tearDown(self):
uu.dispose_resources(self.dev)
def _inner_basic(self, ep_out, ep_in, data):
written = self.dev.write(ep_out, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
read = self.dev.read(ep_in, len(data))
self.assertEqual(len(data), len(read))
expected = array.array('B', [x for x in data])
self.assertEqual(expected, read, "should have read back what we wrote")
def test_simple_loop(self):
"""Plain simple loopback, does it work at all"""
eout = self.eps_out[0]
ein = self.eps_in[0]
data = [random.randrange(255) for _ in range(eout.wMaxPacketSize)]
self._inner_basic(eout, ein, data)
def test_dual_loop(self):
"""Testing that we don't mix our data up, just plain and simple"""
dlen = self.eps_out[0].wMaxPacketSize
data = [
[0xaa for _ in range(dlen)],
[0xbb for _ in range(dlen)],
]
for epo, epi, data in zip(self.eps_out, self.eps_in, data):
self._inner_basic(epo, epi, data)
def test_dual_loop_back_to_back(self):
"""
write to both, _before_ we read back...
This can expose problems with buffer management
"""
dlen = self.eps_out[0].wMaxPacketSize
data = [
[0xaa for _ in range(dlen)],
[0xbb for _ in range(dlen)],
]
written = [
self.dev.write(self.eps_out[0], data[0]),
self.dev.write(self.eps_out[1], data[1]),
]
read = [
self.dev.read(self.eps_in[0], dlen),
self.dev.read(self.eps_in[1], dlen),
]
for w, r, dat in zip(written, read, data):
self.assertEqual(w, len(dat), "Should have written all bytes plz")
self.assertEqual(len(dat), len(r), "Should have read back same size")
expected = array.array('B', [x for x in dat])
self.assertEqual(expected, r, "should have read back what we wrote")
@unittest.skip("Perf tests only on demand (comment this line!)")
class TestConfigSourceSinkPerformance(unittest.TestCase):
"""
Read/write throughput, roughly
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg)
self.intf = self.cfg[(0, 0)]
# heh, kinda gross...
self.ep_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT][0]
self.ep_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN][0]
def tearDown(self):
uu.dispose_resources(self.dev)
def tput(self, xc, te):
return (xc / 1024 / max(1, te.seconds + te.microseconds /
1000000.0))
def test_read_perf(self):
# I get around 990kps here...
ts = datetime.datetime.now()
rxc = 0
while rxc < 5 * 1024 * 1024:
desired = 100 * 1024
data = self.ep_in.read(desired, timeout=0)
self.assertEqual(desired, len(data), "Should have read all bytes plz")
rxc += len(data)
te = datetime.datetime.now() - ts
print("read %s bytes in %s for %s kps" % (rxc, te, self.tput(rxc, te)))
def test_write_perf(self):
# caps out around 420kps?
ts = datetime.datetime.now()
txc = 0
data = [x & 0xff for x in range(100 * 1024)]
while txc < 5 * 1024 * 1024:
w = self.ep_out.write(data, timeout=0)
self.assertEqual(w, len(data), "Should have written all bytes plz")
txc += w
te = datetime.datetime.now() - ts
print("wrote %s bytes in %s for %s kps" % (txc, te, self.tput(txc, te)))
class TestControlTransfer_Reads(unittest.TestCase):
"""
https://github.com/libopencm3/libopencm3/pull/194
and
https://github.com/libopencm3/libopencm3/pull/505
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg)
self.req = uu.CTRL_IN | uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE
def inner_t(self, wVal, read_len):
wVal = int(wVal)
read_len = int(read_len)
q = self.dev.ctrl_transfer(self.req, GZ_REQ_PRODUCE, wVal, 0, read_len)
self.assertEqual(len(q), wVal, "Should have read as much as we asked for?")
def tearDown(self):
uu.dispose_resources(self.dev)
def test_basic(self):
x = self.dev.ctrl_transfer(self.req, GZ_REQ_PRODUCE, 32, 0, 32)
self.assertEqual(32, len(x))
def test_matching_sizes(self):
"""
Can we request x control in when we tell the device to produce x?
:return:
"""
def inner(x):
x = int(x)
q = self.dev.ctrl_transfer(self.req, GZ_REQ_PRODUCE, x, 0, x)
self.assertEqual(len(q), x, "Should have read as much as we asked for")
ep0_size = self.dev.bMaxPacketSize0
inner(ep0_size)
inner(ep0_size * 3)
inner(ep0_size / 3)
inner(ep0_size - 7)
inner(ep0_size + 11)
inner(ep0_size * 4 + 11)
def test_waytoobig(self):
"""
monster reads should fail, but not fatally.
(Don't make them too, big, or libusb will reject you outright, see MAX_CTRL_BUFFER_LENGTH in libusb sources)
"""
try:
self.dev.ctrl_transfer(self.req, GZ_REQ_PRODUCE, 10 * self.dev.bMaxPacketSize0, 0, 10 * self.dev.bMaxPacketSize0)
self.fail("Should have got a stall")
except usb.core.USBError as e:
# Note, this might not be as portable as we'd like.
self.assertIn("Pipe", e.strerror)
def test_read_longer(self):
"""
Attempt to read more than the device replied with.
This is explicitly allowed by spec:
"On an input request, a device must never return more data than is indicated
by the wLength value; it may return less"
"""
ep0_size = self.dev.bMaxPacketSize0
self.inner_t(ep0_size / 2, ep0_size)
self.inner_t(ep0_size / 2, ep0_size * 2)
self.inner_t(ep0_size + 31, ep0_size * 5)
def test_read_needs_zlp(self):
ep0_size = self.dev.bMaxPacketSize0
self.inner_t(ep0_size, ep0_size + 10)
self.inner_t(ep0_size * 2, ep0_size * 5)
def test_read_zero(self):
"""
try and read > 0, but have the device only produce 0
"""
self.inner_t(0, self.dev.bMaxPacketSize0)
self.inner_t(0, 200)
def test_read_nothing(self):
"""
Don't read anything, don't create anything (no data stage)
"""
self.inner_t(0, 0)
def test_mean_limits(self):
"""
tell the device to produce more than we ask for.
Note, this doesn't test the usb stack, it tests the application code behaves.
"""
q = self.dev.ctrl_transfer(self.req, GZ_REQ_PRODUCE, 100, 0, 10)
self.assertEqual(len(q), 10, "In this case, should have gotten wLen back")
class TestUnaligned(unittest.TestCase):
"""
M0 and M0+ cores don't support unaligned memory accesses. These test
how the stack behaves with aligned vs unaligned buffers.
https://github.com/libopencm3/libopencm3/issues/401
https://github.com/libopencm3/libopencm3/issues/461
"""
def setUp(self):
self.dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=find_by_serial(DUT_SERIAL))
self.assertIsNotNone(self.dev, "Couldn't find locm3 gadget0 device")
self.cfg = uu.find_descriptor(self.dev, bConfigurationValue=2)
self.assertIsNotNone(self.cfg, "Config 2 should exist")
self.dev.set_configuration(self.cfg);
self.req = uu.CTRL_OUT | uu.CTRL_TYPE_VENDOR | uu.CTRL_RECIPIENT_INTERFACE
self.intf = self.cfg[(0, 0)]
# heh, kinda gross...
self.ep_out = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_OUT][0]
self.ep_in = [ep for ep in self.intf if uu.endpoint_direction(ep.bEndpointAddress) == uu.ENDPOINT_IN][0]
def tearDown(self):
uu.dispose_resources(self.dev)
def set_unaligned(self):
# GZ_REQ_SET_UNALIGNED
self.dev.ctrl_transfer(self.req, GZ_REQ_SET_UNALIGNED, 0, 0)
def set_aligned(self):
# GZ_REQ_SET_ALIGNED
self.dev.ctrl_transfer(self.req, GZ_REQ_SET_ALIGNED, 0, 0)
def do_readwrite(self):
"""
transfer garbage data to/from bulk EP; alignment issues will hardfault the target
"""
data = [x for x in range(int(self.ep_out.wMaxPacketSize / 2))]
written = self.dev.write(self.ep_out, data)
self.assertEqual(written, len(data), "Should have written all bytes plz")
read_size = self.ep_in.wMaxPacketSize * 10
data = self.dev.read(self.ep_in, read_size)
self.assertEqual(len(data), read_size, "Should have read as much as we asked for")
def test_aligned(self):
self.set_aligned()
self.do_readwrite()
def test_unaligned(self):
self.set_unaligned()
self.do_readwrite()
def run_ci_test(dut):
# Avoids the import for non-CI users!
import xmlrunner
print("Running (CI) tests for DUT: ", dut)
#with open("TEST-%s.xml" % dut, 'wb') as output:
unittest.main(exit=False, argv=[__file__], testRunner=xmlrunner.XMLTestRunner(output="tests/test-%s" % dut))
def run_user_test(dut):
print("Running (user) tests for DUT: ", dut)
unittest.main(exit=False, argv=[__file__])
def get_parser():
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("-d", "--dut", help="Specify a particular DUT serial to test")
parser.add_argument("-X", "--xunit", help="Write xml 'junit' style outputs, intended for CI use", action="store_true")
parser.add_argument("-l", "--list", help="List all detected matching devices, but don't run any tests", action="store_true")
return parser
if __name__ == "__main__":
p = get_parser()
opts = p.parse_args()
runner = run_user_test
if opts.xunit:
runner = run_ci_test
if opts.dut:
runner(opts.dut)
else:
# scan for available and try them all!
devs = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, find_all=True)
for dev in devs:
DUT_SERIAL = dev.serial_number
if opts.list:
print("Detected %s on bus:port-address: %s:%s-%s" % (DUT_SERIAL, dev.bus, '.'.join(map(str,dev.port_numbers)), dev.address))
else:
runner(DUT_SERIAL)

View File

@@ -0,0 +1,409 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file implements linux's "Gadget zero" functionality, both the
* "source sink" functional interface, and the "loopback" interface.
* It _only_ uses usb includes, do _not_ include any target specific code here!
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <libopencm3/usb/usbd.h>
#include "trace.h"
#include "delay.h"
#include "usb-gadget0.h"
#define ER_DEBUG
#ifdef ER_DEBUG
#include <stdio.h>
#define ER_DPRINTF(fmt, ...) \
do { printf(fmt, ## __VA_ARGS__); } while (0)
#else
#define ER_DPRINTF(fmt, ...) \
do { } while (0)
#endif
/*
* USB Vendor:Interface control requests.
*/
#define GZ_REQ_SET_PATTERN 1
#define GZ_REQ_PRODUCE 2
#define GZ_REQ_SET_ALIGNED 3
#define GZ_REQ_SET_UNALIGNED 4
#define INTEL_COMPLIANCE_WRITE 0x5b
#define INTEL_COMPLIANCE_READ 0x5c
/* USB configurations */
#define GZ_CFG_SOURCESINK 2
#define GZ_CFG_LOOPBACK 3
#define BULK_EP_MAXPACKET 64
static const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = USB_CLASS_VENDOR,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = BULK_EP_MAXPACKET,
/* when we're compatible with gadget 0
* #define DRIVER_VENDOR_NUM 0x0525
* #define DRIVER_PRODUCT_NUM 0xa4a0
*/
.idVendor = 0xcafe,
.idProduct = 0xcafe,
.bcdDevice = 0x0001,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 2,
};
static const struct usb_endpoint_descriptor endp_bulk[] = {
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = BULK_EP_MAXPACKET,
.bInterval = 1,
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = BULK_EP_MAXPACKET,
.bInterval = 1,
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x2,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = BULK_EP_MAXPACKET,
.bInterval = 1,
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = BULK_EP_MAXPACKET,
.bInterval = 1,
},
};
static const struct usb_interface_descriptor iface_sourcesink[] = {
{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR,
.iInterface = 0,
.endpoint = endp_bulk,
}
};
static const struct usb_interface_descriptor iface_loopback[] = {
{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0, /* still 0, as it's a different config...? */
.bAlternateSetting = 0,
.bNumEndpoints = 4,
.bInterfaceClass = USB_CLASS_VENDOR,
.iInterface = 0,
.endpoint = endp_bulk,
}
};
static const struct usb_interface ifaces_sourcesink[] = {
{
.num_altsetting = 1,
.altsetting = iface_sourcesink,
}
};
static const struct usb_interface ifaces_loopback[] = {
{
.num_altsetting = 1,
.altsetting = iface_loopback,
}
};
static const struct usb_config_descriptor config[] = {
{
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 1,
.bConfigurationValue = GZ_CFG_SOURCESINK,
.iConfiguration = 4, /* string index */
.bmAttributes = 0x80,
.bMaxPower = 0x32,
.interface = ifaces_sourcesink,
},
{
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 1,
.bConfigurationValue = GZ_CFG_LOOPBACK,
.iConfiguration = 5, /* string index */
.bmAttributes = 0x80,
.bMaxPower = 0x32,
.interface = ifaces_loopback,
}
};
static char serial[] = "0123456789.0123456789.0123456789";
static const char *usb_strings[] = {
"libopencm3",
"Gadget-Zero",
serial,
"source and sink data",
"loop input to output"
};
/* Buffer to be used for control requests. */
static uint8_t usbd_control_buffer[5*BULK_EP_MAXPACKET];
static usbd_device *our_dev;
/* Private global for state */
static struct {
uint8_t pattern;
int pattern_counter;
int test_unaligned; /* If 0 (default), use 16-bit aligned buffers. This should not be declared as bool */
} state = {
.pattern = 0,
.pattern_counter = 0,
.test_unaligned = 0,
};
static void gadget0_ss_out_cb(usbd_device *usbd_dev, uint8_t ep)
{
(void) ep;
uint16_t x;
/* TODO - if you're really keen, perf test this. tiva implies it matters */
/* char buf[64] __attribute__ ((aligned(4))); */
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
uint8_t *dest;
trace_send_blocking8(0, 'O');
if (state.test_unaligned) {
dest = buf + 1;
} else {
dest = buf;
}
x = usbd_ep_read_packet(usbd_dev, ep, dest, BULK_EP_MAXPACKET);
trace_send_blocking8(1, x);
}
static void gadget0_ss_in_cb(usbd_device *usbd_dev, uint8_t ep)
{
(void) usbd_dev;
uint8_t buf[BULK_EP_MAXPACKET + 1] __attribute__ ((aligned(2)));
uint8_t *src;
trace_send_blocking8(0, 'I');
if (state.test_unaligned) {
src = buf + 1;
} else {
src = buf;
}
switch (state.pattern) {
case 0:
memset(src, 0, BULK_EP_MAXPACKET);
break;
case 1:
for (unsigned i = 0; i < BULK_EP_MAXPACKET; i++) {
src[i] = state.pattern_counter++ % 63;
}
break;
}
uint16_t x = usbd_ep_write_packet(usbd_dev, ep, src, BULK_EP_MAXPACKET);
/* As we are calling write in the callback, this should never fail */
trace_send_blocking8(2, x);
if (x != BULK_EP_MAXPACKET) {
ER_DPRINTF("failed to write?: %d\n", x);
}
/*assert(x == sizeof(buf));*/
}
static void gadget0_in_cb_loopback(usbd_device *usbd_dev, uint8_t ep)
{
(void) usbd_dev;
ER_DPRINTF("loop IN %x\n", ep);
/* Nothing to do here, basically just indicates they read us. */
}
static void gadget0_out_cb_loopback(usbd_device *usbd_dev, uint8_t ep)
{
uint8_t buf[BULK_EP_MAXPACKET];
/* Copy data we received on OUT ep back to the paired IN ep */
int x = usbd_ep_read_packet(usbd_dev, ep, buf, BULK_EP_MAXPACKET);
int y = usbd_ep_write_packet(usbd_dev, 0x80 | ep, buf, x);
ER_DPRINTF("loop OUT %x got %d => %d\n", ep, x, y);
}
static enum usbd_request_return_codes gadget0_control_request(usbd_device *usbd_dev,
struct usb_setup_data *req,
uint8_t **buf,
uint16_t *len,
usbd_control_complete_callback *complete)
{
(void) usbd_dev;
(void) complete;
(void) buf;
ER_DPRINTF("ctrl breq: %x, bmRT: %x, windex :%x, wlen: %x, wval :%x\n",
req->bRequest, req->bmRequestType, req->wIndex, req->wLength,
req->wValue);
/* TODO - what do the return values mean again? */
switch (req->bRequest) {
case GZ_REQ_SET_PATTERN:
state.pattern_counter = 0;
state.pattern = req->wValue;
return USBD_REQ_HANDLED;
case INTEL_COMPLIANCE_WRITE:
/* accept correctly formed ctrl writes */
if (req->bmRequestType != (USB_REQ_TYPE_VENDOR|USB_REQ_TYPE_INTERFACE)) {
return USBD_REQ_NOTSUPP;
}
if (req->wValue || req->wIndex) {
return USBD_REQ_NOTSUPP;
}
if (req->wLength > sizeof(usbd_control_buffer)) {
return USBD_REQ_NOTSUPP;
}
/* ok, mark it as accepted. */
return USBD_REQ_HANDLED;
case INTEL_COMPLIANCE_READ:
if (req->bmRequestType != (USB_REQ_TYPE_IN|USB_REQ_TYPE_VENDOR|USB_REQ_TYPE_INTERFACE)) {
return USBD_REQ_NOTSUPP;
}
if (req->wValue || req->wIndex) {
return USBD_REQ_NOTSUPP;
}
if (req->wLength > sizeof(usbd_control_buffer)) {
return USBD_REQ_NOTSUPP;
}
/* ok, return what they left there earlier */
*len = req->wLength;
return USBD_REQ_HANDLED;
case GZ_REQ_SET_UNALIGNED:
state.test_unaligned = 1;
return USBD_REQ_HANDLED;
case GZ_REQ_SET_ALIGNED:
state.test_unaligned = 0;
return USBD_REQ_HANDLED;
case GZ_REQ_PRODUCE:
ER_DPRINTF("fake loopback of %d\n", req->wValue);
if (req->wValue > sizeof(usbd_control_buffer)) {
ER_DPRINTF("Can't write more than out control buffer! %d > %d\n",
req->wValue, sizeof(usbd_control_buffer));
return USBD_REQ_NOTSUPP;
}
/* Don't produce more than asked for! */
if (req->wValue > req->wLength) {
ER_DPRINTF("Truncating reply to match wLen\n");
*len = req->wLength;
} else {
*len = req->wValue;
}
return USBD_REQ_HANDLED;
default:
ER_DPRINTF("Unhandled request!\n");
return USBD_REQ_NOTSUPP;
}
return USBD_REQ_NEXT_CALLBACK;
}
static void gadget0_set_config(usbd_device *usbd_dev, uint16_t wValue)
{
ER_DPRINTF("set cfg %d\n", wValue);
switch (wValue) {
case GZ_CFG_SOURCESINK:
state.test_unaligned = 0;
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_ss_out_cb);
usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_ss_in_cb);
usbd_register_control_callback(
usbd_dev,
USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
gadget0_control_request);
/* Prime source for IN data. */
gadget0_ss_in_cb(usbd_dev, 0x81);
break;
case GZ_CFG_LOOPBACK:
/*
* The ordering here is important, as it defines the addresses
* locality. We want to have both out endpoints in sequentially,
* so we can test for overrunning our memory space, if that's a
* concern on the usb peripheral.
*/
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_out_cb_loopback);
usbd_ep_setup(usbd_dev, 0x02, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_out_cb_loopback);
usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_in_cb_loopback);
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, BULK_EP_MAXPACKET,
gadget0_in_cb_loopback);
break;
default:
ER_DPRINTF("set configuration unknown: %d\n", wValue);
}
}
usbd_device *gadget0_init(const usbd_driver *driver, const char *userserial)
{
#ifdef ER_DEBUG
setbuf(stdout, NULL);
#endif
if (userserial) {
usb_strings[2] = userserial;
}
our_dev = usbd_init(driver, &dev, config,
usb_strings, 5,
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(our_dev, gadget0_set_config);
delay_setup();
return our_dev;
}
void gadget0_run(usbd_device *usbd_dev)
{
usbd_poll(usbd_dev);
/* This should be more than allowable! */
delay_us(100);
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USB_GADGET0_H
#define USB_GADGET0_H
#include <libopencm3/usb/usbd.h>
/**
* Start up the gadget0 framework.
* @param driver which usbd hardware driver to use.
* @param userserial if non-null, will become the serial number.
* You should provide this to help the test code find something particular
* to the hardware.
* @return the usbd_device created.
*/
usbd_device *gadget0_init(const usbd_driver *driver, const char *userserial);
/**
* Call this forever.
* @param usbd_dev the object returned in _init.
* @sa gadget0_init
*/
void gadget0_run(usbd_device *usbd_dev);
#endif