From e64a9d2bf9751e505d344eb5024da4772c3f4e50 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 10 Feb 2011 19:58:51 +1300 Subject: [PATCH 1/4] Minor cleanup of usb. Template driver for STM32F107 added. --- include/libopencm3/stm32/otg_fs.h | 2 +- include/libopencm3/usb/usbd.h | 1 + lib/stm32/Makefile | 2 +- lib/usb/usb.c | 2 +- lib/usb/usb_f103.c | 6 +- lib/usb/usb_f107.c | 163 ++++++++++++++++++++++++++++++ lib/usb/usb_private.h | 14 +-- 7 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 lib/usb/usb_f107.c diff --git a/include/libopencm3/stm32/otg_fs.h b/include/libopencm3/stm32/otg_fs.h index e7a4a234..0f07e89d 100644 --- a/include/libopencm3/stm32/otg_fs.h +++ b/include/libopencm3/stm32/otg_fs.h @@ -21,7 +21,7 @@ #define LIBOPENCM3_OTG_FS_H #include -#include +#include /* Core Global Control and Status Registers */ #define OTG_FS_OTGCTL MMIO32(USB_OTG_FS_BASE + 0x000) diff --git a/include/libopencm3/usb/usbd.h b/include/libopencm3/usb/usbd.h index e3c75f54..fab63046 100644 --- a/include/libopencm3/usb/usbd.h +++ b/include/libopencm3/usb/usbd.h @@ -24,6 +24,7 @@ typedef struct _usbd_driver usbd_driver; extern const usbd_driver stm32f103_usb_driver; +extern const usbd_driver stm32f107_usb_driver; /* Static buffer for control transactions: * This is defined as weak in the library, applicaiton diff --git a/lib/stm32/Makefile b/lib/stm32/Makefile index 966cb033..6ffcc4ad 100644 --- a/lib/stm32/Makefile +++ b/lib/stm32/Makefile @@ -31,7 +31,7 @@ ARFLAGS = rcs OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \ rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \ usb_f103.o usb.o usb_control.o usb_standard.o can.o \ - timer.o + timer.o usb_f107.o VPATH += ../usb diff --git a/lib/usb/usb.c b/lib/usb/usb.c index dbdb8225..eb8e6d82 100644 --- a/lib/usb/usb.c +++ b/lib/usb/usb.c @@ -46,7 +46,7 @@ int usbd_init(const usbd_driver *driver, const struct usb_device_descriptor *dev, const struct usb_config_descriptor *conf, const char **strings) { - _usbd_device.driver = (usbd_driver *)driver; + _usbd_device.driver = driver; _usbd_device.desc = dev; _usbd_device.config = conf; _usbd_device.strings = strings; diff --git a/lib/usb/usb_f103.c b/lib/usb/usb_f103.c index a587978d..ef97670f 100644 --- a/lib/usb/usb_f103.c +++ b/lib/usb/usb_f103.c @@ -35,10 +35,10 @@ static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len); static void stm32f103_poll(void); const struct _usbd_driver stm32f103_usb_driver = { - ._init = stm32f103_usbd_init, - ._set_address = stm32f103_set_address, + .init = stm32f103_usbd_init, + .set_address = stm32f103_set_address, .ep_setup = stm32f103_ep_setup, - ._ep_reset = stm32f103_endpoints_reset, + .ep_reset = stm32f103_endpoints_reset, .ep_stall_set = stm32f103_ep_stall_set, .ep_stall_get = stm32f103_ep_stall_get, .ep_write_packet = stm32f103_ep_write_packet, diff --git a/lib/usb/usb_f107.c b/lib/usb/usb_f107.c new file mode 100644 index 00000000..338735af --- /dev/null +++ b/lib/usb/usb_f107.c @@ -0,0 +1,163 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include "usb_private.h" + +static void stm32f107_usbd_init(void); +static void stm32f107_set_address(u8 addr); +static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, + void (*callback) (u8 ep)); +static void stm32f107_endpoints_reset(void); +static void stm32f107_ep_stall_set(u8 addr, u8 stall); +static u8 stm32f107_ep_stall_get(u8 addr); +static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len); +static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len); +static void stm32f107_poll(void); + +const struct _usbd_driver stm32f107_usb_driver = { + .init = stm32f107_usbd_init, + .set_address = stm32f107_set_address, + .ep_setup = stm32f107_ep_setup, + .ep_reset = stm32f107_endpoints_reset, + .ep_stall_set = stm32f107_ep_stall_set, + .ep_stall_get = stm32f107_ep_stall_get, + .ep_write_packet = stm32f107_ep_write_packet, + .ep_read_packet = stm32f107_ep_read_packet, + .poll = stm32f107_poll, +}; + +/** Initialize the USB device controller hardware of the STM32. */ +static void stm32f107_usbd_init(void) +{ + /* TODO: Enable interrupts on Reset, Transfer, Suspend and Resume */ +} + +static void stm32f107_set_address(u8 addr) +{ + (void)addr; + /* TODO: Set device address and enable. */ +} + +static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, + void (*callback) (u8 ep)) +{ + /* TODO: Configure endpoint address and type. + * Allocate FIFO memory for endpoint. + * Install callback funciton. + */ + (void)type; (void)max_size; + + u8 dir = addr & 0x80; + addr &= 0x7f; + + if (dir || (addr == 0)) { + if (callback) { + _usbd_device. + user_callback_ctr[addr][USB_TRANSACTION_IN] = + (void *)callback; + } + } + + if (!dir) { + if (callback) { + _usbd_device. + user_callback_ctr[addr][USB_TRANSACTION_OUT] = + (void *)callback; + } + } +} + +static void stm32f107_endpoints_reset(void) +{ + /* TODO: Reset all endpoints. */ +} + +static void stm32f107_ep_stall_set(u8 addr, u8 stall) +{ + /* TODO: set or clear stall condition */ + (void)addr; (void)stall; +} + +static u8 stm32f107_ep_stall_get(u8 addr) +{ + /* TODO: return 1 if STALL set. */ + (void)addr; + + return 0; +} + +static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len) +{ + addr &= 0x7F; + + /* TODO: Send packet on endpoint */ + (void)buf; + + return len; +} + +static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len) +{ + /* TODO: Read packet from endpoint */ + (void)addr; (void)buf; (void)len; + + return len; +} + +static void stm32f107_poll(void) +{ + /* TODO: Read interrupt status register */ + + /* TODO: Handle USB RESET condition */ + if (0) { + _usbd_reset(); + return; + } + + /* TODO: Handle transfer complete condition */ + if (0) { + u8 ep; + u8 type; + + if (_usbd_device.user_callback_ctr[ep][type]) + _usbd_device.user_callback_ctr[ep][type] (ep); + /* TODO: clear any interrupt flag */ + } + + /* TODO: Handle suspend condition */ + if (0) { + /* TODO: Clear suspend interrupt flag */ + if (_usbd_device.user_callback_suspend) + _usbd_device.user_callback_suspend(); + } + + /* TODO: Handle wakeup condition */ + if (0) { + /* TODO: Clear wakeup interrupt flag */ + if (_usbd_device.user_callback_resume) + _usbd_device.user_callback_resume(); + } + + /* TODO: Handle SOF condition */ +} + diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index bef225d0..1bc6b3fc 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -54,7 +54,7 @@ extern struct _usbd_device { /* User callback function for some standard USB function hooks */ void (*user_callback_set_config)(u16 wValue); - struct _usbd_driver *driver; + const struct _usbd_driver *driver; } _usbd_device; enum _usbd_transaction { @@ -73,10 +73,10 @@ void _usbd_reset(void); /* Functions provided by the hardware abstraction. */ struct _usbd_driver { - void (*_init)(void); - void (*_set_address)(u8 addr); + void (*init)(void); + void (*set_address)(u8 addr); void (*ep_setup)(u8 addr, u8 type, u16 max_size, void (*cb)(u8 ep)); - void (*_ep_reset)(void); + void (*ep_reset)(void); void (*ep_stall_set)(u8 addr, u8 stall); u8 (*ep_stall_get)(u8 addr); u16 (*ep_write_packet)(u8 addr, const void *buf, u16 len); @@ -84,8 +84,8 @@ struct _usbd_driver { void (*poll)(void); }; -#define _usbd_hw_init() _usbd_device.driver->_init() -#define _usbd_hw_set_address(addr) _usbd_device.driver->_set_address(addr) -#define _usbd_hw_endpoints_reset() _usbd_device.driver->_ep_reset() +#define _usbd_hw_init() _usbd_device.driver->init() +#define _usbd_hw_set_address(addr) _usbd_device.driver->set_address(addr) +#define _usbd_hw_endpoints_reset() _usbd_device.driver->ep_reset() #endif From f0a1282d429023958e750a7821c577c132365485 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 17 Feb 2011 21:38:38 +1300 Subject: [PATCH 2/4] Added ITM and TPIU register definitions. --- include/libopencm3/cm3/itm.h | 74 ++++++++++++++++++++++ include/libopencm3/cm3/memorymap.h | 1 + include/libopencm3/cm3/scs.h | 27 +++++--- include/libopencm3/cm3/tpiu.h | 98 ++++++++++++++++++++++++++++++ include/libopencm3/stm32/dbgmcu.h | 2 +- 5 files changed, 191 insertions(+), 11 deletions(-) create mode 100644 include/libopencm3/cm3/itm.h create mode 100644 include/libopencm3/cm3/tpiu.h diff --git a/include/libopencm3/cm3/itm.h b/include/libopencm3/cm3/itm.h new file mode 100644 index 00000000..232c2a7a --- /dev/null +++ b/include/libopencm3/cm3/itm.h @@ -0,0 +1,74 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_ITM_H +#define LIBOPENCM3_CM3_ITM_H + +/* Cortex-M3 Instrumentation Trace Macrocell (ITM) */ + +/* --- ITM registers ------------------------------------------------------- */ + +/* Stimulus Port x (ITM_STIM[x]) */ +#define ITM_STIM ((volatile u32*)(ITM_BASE)) + +/* Trace Enable ports (ITM_TER[x]) */ +#define ITM_TER ((volatile u32*)(ITM_BASE + 0xE00)) + +/* Trace Privilege (ITM_TPR) */ +#define ITM_TPR MMIO32(ITM_BASE + 0xE40) + +/* Trace Control (ITM_TCR) */ +#define ITM_TCR MMIO32(ITM_BASE + 0xE80) + +/* TODO: PID, CID */ + +/* --- ITM_STIM values ----------------------------------------------------- */ +/* Bits 31:0 - Write to port FIFO for forwarding as software event packet */ +/* Bits 31:1 - RAZ */ +#define ITM_STIM_FIFOREADY (1 << 0) + +/* --- ITM_TER values ------------------------------------------------------ */ +/* Bits 31:0 - Stimulus port #N is enabled with STIMENA[N] is set */ + +/* --- ITM_TPR values ------------------------------------------------------ */ +/* + * Bits 31:0 - Bit [N] of PRIVMASK controls stimulus ports 8N to 8N+7 + * 0: User access allowed to stimulus ports + * 1: Privileged access only to stimulus ports + */ + +/* --- ITM_TCR values ------------------------------------------------------ */ +/* Bits 31:24 - Reserved */ +#define ITM_TCR_BUSY (1 << 23) +#define ITM_TCR_TRACE_BUS_ID_MASK (0x3f << 16) +/* Bits 15:10 - Reserved */ +#define ITM_TCR_TSPRESCALE_NONE (0 << 8) +#define ITM_TCR_TSPRESCALE_DIV4 (1 << 8) +#define ITM_TCR_TSPRESCALE_DIV16 (2 << 8) +#define ITM_TCR_TSPRESCALE_DIV64 (3 << 8) +#define ITM_TCR_TSPRESCALE_MASK (3 << 8) +/* Bits 7:5 - Reserved */ +#define ITM_TCR_SWOENA (1 << 4) +#define ITM_TCR_TXENA (1 << 3) +#define ITM_TCR_SYNCENA (1 << 2) +#define ITM_TCR_TSENA (1 << 1) +#define ITM_TCR_ITMENA (1 << 0) + + +#endif diff --git a/include/libopencm3/cm3/memorymap.h b/include/libopencm3/cm3/memorymap.h index b1b51729..13c3a8f4 100644 --- a/include/libopencm3/cm3/memorymap.h +++ b/include/libopencm3/cm3/memorymap.h @@ -30,6 +30,7 @@ /* PPBI_BASE + 0x3000 (0xE000 3000 - 0xE000 DFFF): Reserved */ #define SCS_BASE (PPBI_BASE + 0xE000) /* PPBI_BASE + 0xF000 (0xE000 F000 - 0xE003 FFFF): Reserved */ +#define TPIU_BASE (PPBI_BASE + 0x40000) /* --- ITM: Instrumentation Trace Macrocell --- */ /* TODO */ diff --git a/include/libopencm3/cm3/scs.h b/include/libopencm3/cm3/scs.h index 5646a186..d4dbca48 100644 --- a/include/libopencm3/cm3/scs.h +++ b/include/libopencm3/cm3/scs.h @@ -46,15 +46,22 @@ #define SCS_DCRSR_REGSEL_PSP 0x00000012 /* Debug Exception and Monitor Control Register (DEMCR) */ -#define SCS_DEMCR_VC_CORERESET 0x00000001 -#define SCS_DEMCR_VC_MMERR 0x00000010 -#define SCS_DEMCR_VC_NOCPERR 0x00000020 -#define SCS_DEMCR_VC_CHKERR 0x00000040 -#define SCS_DEMCR_VC_STATERR 0x00000080 -#define SCS_DEMCR_VC_BUSERR 0x00000100 -#define SCS_DEMCR_VC_INTERR 0x00000200 -#define SCS_DEMCR_VC_HARDERR 0x00000400 -#define SCS_DEMCR_VC_MON_EN 0x00010000 -#define SCS_DEMCR_VC_MON_PEND 0x00020000 +/* Bits 31:25 - Reserved */ +#define SCS_DEMCR_TRCENA (1 << 24) +/* Bits 23:20 - Reserved */ +#define SCS_DEMCR_MON_REQ (1 << 19) +#define SCS_DEMCR_MON_STEP (1 << 18) +#define SCS_DEMCR_VC_MON_PEND (1 << 17) +#define SCS_DEMCR_VC_MON_EN (1 << 16) +/* Bits 15:11 - Reserved */ +#define SCS_DEMCR_VC_HARDERR (1 << 10) +#define SCS_DEMCR_VC_INTERR (1 << 9) +#define SCS_DEMCR_VC_BUSERR (1 << 8) +#define SCS_DEMCR_VC_STATERR (1 << 7) +#define SCS_DEMCR_VC_CHKERR (1 << 6) +#define SCS_DEMCR_VC_NOCPERR (1 << 5) +#define SCS_DEMCR_VC_MMERR (1 << 4) +/* Bits 3:1 - Reserved */ +#define SCS_DEMCR_VC_CORERESET (1 << 0) #endif diff --git a/include/libopencm3/cm3/tpiu.h b/include/libopencm3/cm3/tpiu.h new file mode 100644 index 00000000..5dfdcbd5 --- /dev/null +++ b/include/libopencm3/cm3/tpiu.h @@ -0,0 +1,98 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2011 Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBOPENCM3_CM3_TPIU_H +#define LIBOPENCM3_CM3_TPIU_H + +/* Cortex-M3 Trace Port Interface Unit (TPIU) */ + +/* --- TPIU registers ------------------------------------------------------ */ + +/* Supported Synchronous Port Size (TPIU_SSPSR) */ +#define TPIU_SSPSR MMIO32(TPIU_BASE + 0x000) + +/* Current Synchronous Port Size (TPIU_CSPSR) */ +#define TPIU_CSPSR MMIO32(TPIU_BASE + 0x004) + +/* Asynchronous Clock Prescaler (TPIU_ACPR) */ +#define TPIU_ACPR MMIO32(TPIU_BASE + 0x010) + +/* Selected Pin Protocol (TPIU_SPPR) */ +#define TPIU_SPPR MMIO32(TPIU_BASE + 0x0F0) + +/* Formatter and Flush Status Register (TPIU_FFSR) */ +#define TPIU_FFSR MMIO32(TPIU_BASE + 0x300) + +/* Formatter and Flush Control Register (TPIU_FFCR) */ +#define TPIU_FFCR MMIO32(TPIU_BASE + 0x304) + +/* (TPIU_DEVID) */ +#define TPIU_DEVID MMIO32(TPIU_BASE + 0xFC8) + +/* TODO: PID, CID */ + +/* --- TPIU_SSPSR values --------------------------------------------------- */ +/* + * bit[N] == 0, trace port width of (N+1) not supported + * bit[N] == 1, trace port width of (N+1) supported + */ +#define TPIU_SSPSR_BYTE (1 << 0) +#define TPIU_SSPSR_HALFWORD (1 << 1) +#define TPIU_SSPSR_WORD (1 << 3) + +/* --- TPIU_SSPSR values --------------------------------------------------- */ +/* Same format as TPIU_SSPSR, except only one is set */ +#define TPIU_CSPSR_BYTE (1 << 0) +#define TPIU_CSPSR_HALFWORD (1 << 1) +#define TPIU_CSPSR_WORD (1 << 3) + +/* --- TPIU_ACPR values ---------------------------------------------------- */ +/* Bits 31:16 - Reserved */ +/* Bits 15:0 - SWO output clock = Asynchronous_Reference_Clock/(value +1) */ + +/* --- TPIU_SPPR values ---------------------------------------------------- */ +/* Bits 31:2 - Reserved */ +#define TPIU_SPPR_SYNC (0x0) +#define TPIU_SPPR_ASYNC_MANCHESTER (0x1) +#define TPIU_SPPR_ASYNC_NRZ (0x2) + +/* --- TPIU_FFSR values ---------------------------------------------------- */ +/* Bits 31:4 - Reserved */ +#define TPIU_FFSR_FTNONSTOP (1 << 3) +#define TPIU_FFSR_TCPRESENT (1 << 2) +#define TPIU_FFSR_FTSTOPPED (1 << 1) +#define TPIU_FFSR_FLINPROG (1 << 0) + +/* --- TPIU_FFCR values ---------------------------------------------------- */ +/* Bits 31:9 - Reserved */ +#define TPIU_FFCR_TRIGIN (1 << 8) +/* Bits 7:2 - Reserved */ +#define TPIU_FFCR_ENFCONT (1 << 1) +/* Bit 0 - Reserved */ + +/* --- TPIU_DEVID values ---------------------------------------------------- */ +/* Bits 31:16 - Reserved */ +/* Bits 15:12 - Implementation defined */ +#define TPUI_DEVID_NRZ_SUPPORTED (1 << 11) +#define TPUI_DEVID_MANCHESTER_SUPPORTED (1 << 10) +/* Bit 9 - RAZ, indicated that trace data and clock are supported */ +#define TPUI_DEVID_FIFO_SIZE_MASK (7 << 6) +/* Bits 5:0 - Implementation defined */ + +#endif diff --git a/include/libopencm3/stm32/dbgmcu.h b/include/libopencm3/stm32/dbgmcu.h index 1229e901..e753f5ed 100644 --- a/include/libopencm3/stm32/dbgmcu.h +++ b/include/libopencm3/stm32/dbgmcu.h @@ -26,7 +26,7 @@ /* --- DBGMCU registers ---------------------------------------------------- */ #define DBGMCU_IDCODE MMIO32(DBGMCU_BASE + 0x00) -#define DBGMCU_CR MMIO32(DBGCMU_BASE + 0x04) +#define DBGMCU_CR MMIO32(DBGMCU_BASE + 0x04) /* DBGMCU_CR bits */ #define DBGMCU_CR_SLEEP 0x00000001 From 4ed536c988bc933a852405caff8173c5eeaef418 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 17 Feb 2011 21:50:00 +1300 Subject: [PATCH 3/4] Added example using ITM and TPIU for TRACESWO output. --- examples/stm32/stm32-h103/Makefile | 10 +- examples/stm32/stm32-h103/traceswo/Makefile | 23 ++++ examples/stm32/stm32-h103/traceswo/README | 11 ++ examples/stm32/stm32-h103/traceswo/traceswo.c | 100 ++++++++++++++++++ .../stm32/stm32-h103/traceswo/traceswo.ld | 31 ++++++ 5 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 examples/stm32/stm32-h103/traceswo/Makefile create mode 100644 examples/stm32/stm32-h103/traceswo/README create mode 100644 examples/stm32/stm32-h103/traceswo/traceswo.c create mode 100644 examples/stm32/stm32-h103/traceswo/traceswo.ld diff --git a/examples/stm32/stm32-h103/Makefile b/examples/stm32/stm32-h103/Makefile index af901000..a319da6c 100644 --- a/examples/stm32/stm32-h103/Makefile +++ b/examples/stm32/stm32-h103/Makefile @@ -24,7 +24,7 @@ Q := @ MAKEFLAGS += --no-print-directory endif -all: miniblink fancyblink usart usb_cdcacm usb_hid button exti_both +all: miniblink fancyblink usart usb_cdcacm usb_hid button exti_both traceswo miniblink: @printf " BUILD examples/stm32/stm32-h103/miniblink\n" @@ -58,6 +58,10 @@ exti_both: @printf " BUILD examples/stm32/stm32-h103/exti_both\n" $(Q)$(MAKE) -C exti_both +traceswo: + @printf " BUILD examples/stm32/stm32-h103/traceswo\n" + $(Q)$(MAKE) -C traceswo + clean: @printf " CLEAN examples/stm32/stm32-h103/miniblink\n" $(Q)$(MAKE) -C miniblink clean @@ -75,6 +79,8 @@ clean: $(Q)$(MAKE) -C button clean @printf " CLEAN examples/stm32/stm32-h103/exti_both\n" $(Q)$(MAKE) -C exti_both clean + @printf " CLEAN examples/stm32/stm32-h103/traceswo\n" + $(Q)$(MAKE) -C traceswo clean -.PHONY: miniblink fancyblink usart spi usb_cdcacm usb_hid button exti_both clean +.PHONY: miniblink fancyblink usart spi usb_cdcacm usb_hid button exti_both traceswo clean diff --git a/examples/stm32/stm32-h103/traceswo/Makefile b/examples/stm32/stm32-h103/traceswo/Makefile new file mode 100644 index 00000000..37510d5f --- /dev/null +++ b/examples/stm32/stm32-h103/traceswo/Makefile @@ -0,0 +1,23 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program 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 General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . +## + +BINARY = traceswo + +include ../../Makefile.include + diff --git a/examples/stm32/stm32-h103/traceswo/README b/examples/stm32/stm32-h103/traceswo/README new file mode 100644 index 00000000..34b5227f --- /dev/null +++ b/examples/stm32/stm32-h103/traceswo/README @@ -0,0 +1,11 @@ +------------------------------------------------------------------------------ +README +------------------------------------------------------------------------------ + +This experimental program sends some characters on the TRACESWO pin using +the Instrumentation Trace Macrocell (ITM) and Trace Port Interface +Unit (TPIU). + +The SWJ-DP port must be in SWD mode and not JTAG mode for the output +to be visible. + diff --git a/examples/stm32/stm32-h103/traceswo/traceswo.c b/examples/stm32/stm32-h103/traceswo/traceswo.c new file mode 100644 index 00000000..ac461bb4 --- /dev/null +++ b/examples/stm32/stm32-h103/traceswo/traceswo.c @@ -0,0 +1,100 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include + +void clock_setup(void) +{ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + /* Enable GPIOC clock. */ + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN); +} + +void trace_setup(void) +{ + /* Enable trace subsystem (we'll use ITM and TPIU) */ + SCS_DEMCR |= SCS_DEMCR_TRCENA; + + /* Use Manchester code for asynchronous transmission */ + TPIU_SPPR = TPIU_SPPR_ASYNC_MANCHESTER; + TPIU_ACPR = 7; + + /* Data width is 1 byte */ + TPIU_CSPSR = TPIU_CSPSR_BYTE; + + /* Formatter and flush control */ + TPIU_FFCR &= ~TPIU_FFCR_ENFCONT; + + /* Enable TRACESWO pin for async mode */ + DBGMCU_CR = DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_ASYNC; + + /* Unlock access to ITM registers */ + /* FIXME: Magic numbers... Is this Cortex-M3 generic? */ + *((volatile uint32_t*)0xE0000FB0) = 0xC5ACCE55; + + /* Enable ITM with ID = 1 */ + ITM_TCR = (1 << 16) | ITM_TCR_ITMENA; + /* Enable stimulus port 1 */ + ITM_TER[0] = 1; + +} + +void gpio_setup(void) +{ + /* Set GPIO12 (in GPIO port C) to 'output push-pull'. */ + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); +} + +void trace_send_blocking(char c) +{ + while(!(ITM_STIM[0] & ITM_STIM_FIFOREADY)); + ITM_STIM[0] = c; +} + +int main(void) +{ + int i, j = 0, c = 0; + + clock_setup(); + gpio_setup(); + trace_setup(); + + /* Blink the LED (PC12) on the board with every transmitted byte. */ + while (1) { + gpio_toggle(GPIOC, GPIO12); /* LED on/off */ + trace_send_blocking(c + '0'); + c = (c == 9) ? 0 : c + 1; /* Increment c. */ + if ((j++ % 80) == 0) { /* Newline after line full. */ + trace_send_blocking('\r'); + trace_send_blocking('\n'); + } + for (i = 0; i < 800000; i++) /* Wait a bit. */ + __asm__("NOP"); + } + + return 0; +} diff --git a/examples/stm32/stm32-h103/traceswo/traceswo.ld b/examples/stm32/stm32-h103/traceswo/traceswo.ld new file mode 100644 index 00000000..7ea2b92c --- /dev/null +++ b/examples/stm32/stm32-h103/traceswo/traceswo.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32.ld + From 554feb7f274d853fc024165b3c3074d38a01e0c0 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sun, 20 Feb 2011 12:28:23 +1300 Subject: [PATCH 4/4] USB driver for Connectivity-line devices partially working. --- include/libopencm3/stm32/otg_fs.h | 177 +++++++++++++++++++++++++++- include/libopencm3/stm32/rcc.h | 4 + include/libopencm3/usb/cdc.h | 2 +- lib/usb/usb_f107.c | 188 +++++++++++++++++++++++++++--- 4 files changed, 354 insertions(+), 17 deletions(-) diff --git a/include/libopencm3/stm32/otg_fs.h b/include/libopencm3/stm32/otg_fs.h index 0f07e89d..d39593e2 100644 --- a/include/libopencm3/stm32/otg_fs.h +++ b/include/libopencm3/stm32/otg_fs.h @@ -78,8 +78,10 @@ #define OTG_FS_DOEPTSIZ(x) MMIO32(USB_OTG_FS_BASE + 0xB10 + 0x20*(x)) /* Power and clock gating control and status register */ -#define OTH_FS_PCGCR MMIO32(USB_OTG_FS_BASE + 0xE00) +#define OTG_FS_PCGCCTL MMIO32(USB_OTG_FS_BASE + 0xE00) +/* Data FIFO */ +#define OTG_FS_FIFO(x) ((u32*)(USB_OTG_FS_BASE + (((x) + 1) << 12))) /* Global CSRs */ /* OTG_FS AHB configuration register (OTG_FS_GAHBCFG) */ @@ -91,11 +93,58 @@ #define OTG_FS_GUSBCFG_TOCAL 0x00000003 #define OTG_FS_GUSBCFG_SRPCAP 0x00000100 #define OTG_FS_GUSBCFG_HNPCAP 0x00000200 -#define OTG_FS_GUSBCFG_TRDT 0x00003C00 +#define OTG_FS_GUSBCFG_TRDT_MASK (0xf << 10) +#define OTG_FS_GUSBCFG_TRDT_16BIT (0x5 << 10) +#define OTG_FS_GUSBCFG_TRDT_8BIT (0x9 << 10) #define OTG_FS_GUSBCFG_NPTXRWEN 0x00004000 #define OTG_FS_GUSBCFG_FHMOD 0x20000000 #define OTG_FS_GUSBCFG_FDMOD 0x40000000 #define OTG_FS_GUSBCFG_CTXPKT 0x80000000 +/* WARNING: not in reference manual */ +#define OTG_FS_GUSBCFG_PHYSEL (1 << 6) + +/* OTG_FS reset register (OTG_FS_GRSTCTL) */ +#define OTG_FS_GRSTCTL_AHBIDL (1 << 31) +/* Bits 30:11 - Reserved */ +#define OTG_FS_GRSTCTL_TXFNUM_MASK (0x1f << 6) +#define OTG_FS_GRSTCTL_TXFFLSH (1 << 5) +#define OTG_FS_GRSTCTL_RXFFLSH (1 << 4) +/* Bit 3 - Reserved */ +#define OTG_FS_GRSTCTL_FCRST (1 << 2) +#define OTG_FS_GRSTCTL_HSRST (1 << 1) +#define OTG_FS_GRSTCTL_CSRST (1 << 0) + +/* OTG_FS interrupt status register (OTG_FS_GINTSTS) */ +#define OTG_FS_GINTSTS_WKUPINT (1 << 31) +#define OTG_FS_GINTSTS_SRQINT (1 << 30) +#define OTG_FS_GINTSTS_DISCINT (1 << 29) +#define OTG_FS_GINTSTS_CIDSCHG (1 << 28) +/* Bit 27 - Reserved */ +#define OTG_FS_GINTSTS_PTXFE (1 << 26) +#define OTG_FS_GINTSTS_HCINT (1 << 25) +#define OTG_FS_GINTSTS_HPRTINT (1 << 24) +/* Bits 23:22 - Reserved */ +#define OTG_FS_GINTSTS_IPXFR (1 << 21) +#define OTG_FS_GINTSTS_INCOMPISOOUT (1 << 21) +#define OTG_FS_GINTSTS_IISOIXFR (1 << 20) +#define OTG_FS_GINTSTS_OEPINT (1 << 19) +#define OTG_FS_GINTSTS_IEPINT (1 << 18) +/* Bits 17:16 - Reserved */ +#define OTG_FS_GINTSTS_EOPF (1 << 15) +#define OTG_FS_GINTSTS_ISOODRP (1 << 14) +#define OTG_FS_GINTSTS_ENUMDNE (1 << 13) +#define OTG_FS_GINTSTS_USBRST (1 << 12) +#define OTG_FS_GINTSTS_USBSUSP (1 << 11) +#define OTG_FS_GINTSTS_ESUSP (1 << 10) +/* Bits 9:8 - Reserved */ +#define OTG_FS_GINTSTS_GONAKEFF (1 << 7) +#define OTG_FS_GINTSTS_GINAKEFF (1 << 6) +#define OTG_FS_GINTSTS_NPTXFE (1 << 5) +#define OTG_FS_GINTSTS_RXFLVL (1 << 4) +#define OTG_FS_GINTSTS_SOF (1 << 3) +#define OTG_FS_GINTSTS_OTGINT (1 << 2) +#define OTG_FS_GINTSTS_MMIS (1 << 1) +#define OTG_FS_GINTSTS_CMOD (1 << 0) /* OTG_FS interrupt mask register (OTG_FS_GINTMSK) */ #define OTG_FS_GINTMSK_MMISM 0x00000002 @@ -125,15 +174,139 @@ #define OTG_FS_GINTMSK_SRQIM 0x40000000 #define OTG_FS_GINTMSK_WUIM 0x80000000 +/* OTG_FS Receive Status Pop Register (OTG_FS_GRXSTSP) */ +/* Bits 31:25 - Reserved */ +#define OTG_FS_GRXSTSP_FRMNUM_MASK (0xf << 21) +#define OTG_FS_GRXSTSP_PKTSTS_MASK (0xf << 17) +#define OTG_FS_GRXSTSP_PKTSTS_GOUTNAK (0x1 << 17) +#define OTG_FS_GRXSTSP_PKTSTS_OUT (0x2 << 17) +#define OTG_FS_GRXSTSP_PKTSTS_OUT_COMP (0x3 << 17) +#define OTG_FS_GRXSTSP_PKTSTS_SETUP_COMP (0x4 << 17) +#define OTG_FS_GRXSTSP_PKTSTS_SETUP (0x6 << 17) +#define OTG_FS_GRXSTSP_DPID_MASK (0x3 << 15) +#define OTG_FS_GRXSTSP_DPID_DATA0 (0x0 << 15) +#define OTG_FS_GRXSTSP_DPID_DATA1 (0x2 << 15) +#define OTG_FS_GRXSTSP_DPID_DATA2 (0x1 << 15) +#define OTG_FS_GRXSTSP_DPID_MDATA (0x3 << 15) +#define OTG_FS_GRXSTSP_BCNT_MASK (0x7ff << 4) +#define OTG_FS_GRXSTSP_EPNUM_MASK (0xf << 0) + +/* OTG_FS general core configuration register (OTG_FS_GCCFG) */ +/* Bits 31:21 - Reserved */ +#define OTG_FS_GCCFG_SOFOUTEN (1 << 20) +#define OTG_FS_GCCFG_VBUSBSEN (1 << 19) +#define OTG_FS_GCCFG_VBUSASEN (1 << 18) +/* Bit 17 - Reserved */ +#define OTG_FS_GCCFG_PWRDWN (1 << 16) +/* Bits 15:0 - Reserved */ + /* Device-mode CSRs */ +/* OTG_FS device control register (OTG_FS_DCTL) */ +/* Bits 31:12 - Reserved */ +#define OTG_FS_DCTL_POPRGDNE (1 << 11) +#define OTG_FS_DCTL_CGONAK (1 << 10) +#define OTG_FS_DCTL_SGONAK (1 << 9) +#define OTG_FS_DCTL_SGINAK (1 << 8) +#define OTG_FS_DCTL_TCTL_MASK (7 << 4) +#define OTG_FS_DCTL_GONSTS (1 << 3) +#define OTG_FS_DCTL_GINSTS (1 << 2) +#define OTG_FS_DCTL_SDIS (1 << 1) +#define OTG_FS_DCTL_RWUSIG (1 << 0) + /* OTG_FS device configuration register (OTG_FS_DCFG) */ #define OTG_FS_DCFG_DSPD 0x0003 #define OTG_FS_DCFG_NZLSOHSK 0x0004 #define OTG_FS_DCFG_DAD 0x07F0 #define OTG_FS_DCFG_PFIVL 0x1800 +/* OTG_FS Device IN Endpoint Common Interrupt Mask Register (OTG_FS_DIEPMSK) */ +/* Bits 31:10 - Reserved */ +#define OTG_FS_DIEPMSK_BIM (1 << 9) +#define OTG_FS_DIEPMSK_TXFURM (1 << 8) +/* Bit 7 - Reserved */ +#define OTG_FS_DIEPMSK_INEPNEM (1 << 6) +#define OTG_FS_DIEPMSK_INEPNMM (1 << 5) +#define OTG_FS_DIEPMSK_ITTXFEMSK (1 << 4) +#define OTG_FS_DIEPMSK_TOM (1 << 3) +/* Bit 2 - Reserved */ +#define OTG_FS_DIEPMSK_EPDM (1 << 1) +#define OTG_FS_DIEPMSK_XFRCM (1 << 0) +/* OTG_FS Device OUT Endpoint Common Interrupt Mask Register (OTG_FS_DOEPMSK) */ +/* Bits 31:10 - Reserved */ +#define OTG_FS_DOEPMSK_BOIM (1 << 9) +#define OTG_FS_DOEPMSK_OPEM (1 << 8) +/* Bit 7 - Reserved */ +#define OTG_FS_DOEPMSK_B2BSTUP (1 << 6) +/* Bit 5 - Reserved */ +#define OTG_FS_DOEPMSK_OTEPDM (1 << 4) +#define OTG_FS_DOEPMSK_STUPM (1 << 3) +/* Bit 2 - Reserved */ +#define OTG_FS_DOEPMSK_EPDM (1 << 1) +#define OTG_FS_DOEPMSK_XFRCM (1 << 0) + +/* OTG_FS Device Control IN Endpoint 0 Control Register (OTG_FS_DIEPCTL0) */ +#define OTG_FS_DIEPCTL0_EPENA (1 << 31) +#define OTG_FS_DIEPCTL0_EPDIS (1 << 30) +/* Bits 29:28 - Reserved */ +#define OTG_FS_DIEPCTL0_SNAK (1 << 27) +#define OTG_FS_DIEPCTL0_CNAK (1 << 26) +#define OTG_FS_DIEPCTL0_TXFNUM_MASK (0xf << 22) +#define OTG_FS_DIEPCTL0_STALL (1 << 21) +/* Bit 20 - Reserved */ +#define OTG_FS_DIEPCTL0_EPTYP_MASK (0x3 << 18) +#define OTG_FS_DIEPCTL0_NAKSTS (1 << 17) +/* Bit 16 - Reserved */ +#define OTG_FS_DIEPCTL0_USBAEP (1 << 15) +/* Bits 14:2 - Reserved */ +#define OTG_FS_DIEPCTL0_MPSIZ_MASK (0x3 << 0) +#define OTG_FS_DIEPCTL0_MPSIZ_64 (0x0 << 0) +#define OTG_FS_DIEPCTL0_MPSIZ_32 (0x1 << 0) +#define OTG_FS_DIEPCTL0_MPSIZ_16 (0x2 << 0) +#define OTG_FS_DIEPCTL0_MPSIZ_8 (0x3 << 0) + +/* OTG_FS Device Control OUT Endpoint 0 Control Register (OTG_FS_DOEPCTL0) */ +#define OTG_FS_DOEPCTL0_EPENA (1 << 31) +#define OTG_FS_DOEPCTL0_EPDIS (1 << 30) +/* Bits 29:28 - Reserved */ +#define OTG_FS_DOEPCTL0_SNAK (1 << 27) +#define OTG_FS_DOEPCTL0_CNAK (1 << 26) +/* Bits 25:22 - Reserved */ +#define OTG_FS_DOEPCTL0_STALL (1 << 21) +#define OTG_FS_DOEPCTL0_SNPM (1 << 20) +#define OTG_FS_DOEPCTL0_EPTYP_MASK (0x3 << 18) +#define OTG_FS_DOEPCTL0_NAKSTS (1 << 17) +/* Bit 16 - Reserved */ +#define OTG_FS_DOEPCTL0_USBAEP (1 << 15) +/* Bits 14:2 - Reserved */ +#define OTG_FS_DOEPCTL0_MPSIZ_MASK (0x3 << 0) +#define OTG_FS_DOEPCTL0_MPSIZ_64 (0x0 << 0) +#define OTG_FS_DOEPCTL0_MPSIZ_32 (0x1 << 0) +#define OTG_FS_DOEPCTL0_MPSIZ_16 (0x2 << 0) +#define OTG_FS_DOEPCTL0_MPSIZ_8 (0x3 << 0) + +/* OTG_FS Device IN Endpoint Interrupt Register (OTG_FS_DIEPINTx) */ +/* Bits 31:8 - Reserved */ +#define OTG_FS_DIEPINTX_TXFE (1 << 7) +#define OTG_FS_DIEPINTX_INEPNE (1 << 6) +/* Bit 5 - Reserved */ +#define OTG_FS_DIEPINTX_ITTXFE (1 << 4) +#define OTG_FS_DIEPINTX_TOC (1 << 3) +/* Bit 2 - Reserved */ +#define OTG_FS_DIEPINTX_EPDISD (1 << 1) +#define OTG_FS_DIEPINTX_XFRC (1 << 0) + +/* OTG_FS Device OUT Endpoint 0 Transfer Size Regsiter (OTG_FS_DOEPTSIZ0) */ +/* Bit 31 - Reserved */ +#define OTG_FS_DIEPSIZ0_STUPCNT_1 (0x1 << 29) +#define OTG_FS_DIEPSIZ0_STUPCNT_2 (0x2 << 29) +#define OTG_FS_DIEPSIZ0_STUPCNT_3 (0x3 << 29) +#define OTG_FS_DIEPSIZ0_STUPCNT_MASK (0x3 << 29) +/* Bits 28:20 - Reserved */ +#define OTG_FS_DIEPSIZ0_PKTCNT (1 << 19) +/* Bits 18:7 - Reserved */ +#define OTG_FS_DIEPSIZ0_XFRSIZ_MASK (0x7f << 0) #endif diff --git a/include/libopencm3/stm32/rcc.h b/include/libopencm3/stm32/rcc.h index 08806273..a6184393 100644 --- a/include/libopencm3/stm32/rcc.h +++ b/include/libopencm3/stm32/rcc.h @@ -230,6 +230,10 @@ /* --- RCC_AHBENR values --------------------------------------------------- */ +#define RCC_AHBENR_ETHMACENRX (1 << 16) +#define RCC_AHBENR_ETHMACENTX (1 << 15) +#define RCC_AHBENR_ETHMACEN (1 << 14) +#define RCC_AHBENR_OTGFSEN (1 << 12) #define RCC_AHBENR_SDIOEN (1 << 10) #define RCC_AHBENR_FSMCEN (1 << 8) #define RCC_AHBENR_CRCEN (1 << 6) diff --git a/include/libopencm3/usb/cdc.h b/include/libopencm3/usb/cdc.h index 2bdc18bc..808d0041 100644 --- a/include/libopencm3/usb/cdc.h +++ b/include/libopencm3/usb/cdc.h @@ -112,7 +112,7 @@ struct usb_cdc_line_coding { /* Table 30: Class-Specific Notification Codes for PSTN subclasses */ /* ... */ -#define USB_CDC_NOTIFY_SERIAL_STATE 0x28 +#define USB_CDC_NOTIFY_SERIAL_STATE 0x20 /* ... */ /* Notification Structure */ diff --git a/lib/usb/usb_f107.c b/lib/usb/usb_f107.c index 338735af..a681b608 100644 --- a/lib/usb/usb_f107.c +++ b/lib/usb/usb_f107.c @@ -23,6 +23,8 @@ #include #include "usb_private.h" +#include + static void stm32f107_usbd_init(void); static void stm32f107_set_address(u8 addr); static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, @@ -34,6 +36,10 @@ static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len); static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len); static void stm32f107_poll(void); +/* We keep a backup copy of the out endpoint size registers to restore them + * after a transaction */ +static u32 doeptsiz[4]; + const struct _usbd_driver stm32f107_usb_driver = { .init = stm32f107_usbd_init, .set_address = stm32f107_set_address, @@ -49,13 +55,49 @@ const struct _usbd_driver stm32f107_usb_driver = { /** Initialize the USB device controller hardware of the STM32. */ static void stm32f107_usbd_init(void) { + int i; /* TODO: Enable interrupts on Reset, Transfer, Suspend and Resume */ + + /* WARNING: Undocumented! Select internal PHY */ + OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_PHYSEL; + /* Enable VBUS sensing in device mode and power down the phy */ + OTG_FS_GCCFG |= OTG_FS_GCCFG_VBUSBSEN | OTG_FS_GCCFG_PWRDWN; + + for(i = 0; i < 800000; i++) __asm__("nop"); + + /* Wait for AHB idle */ + while(!(OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_AHBIDL)); + /* Do core soft reset */ + OTG_FS_GRSTCTL |= OTG_FS_GRSTCTL_CSRST; + while(OTG_FS_GRSTCTL & OTG_FS_GRSTCTL_CSRST); + + for(i = 0; i < 800000; i++) __asm__("nop"); + + /* Force peripheral only mode. */ + OTG_FS_GUSBCFG |= OTG_FS_GUSBCFG_FDMOD; + + /* Full speed device */ + OTG_FS_DCFG |= OTG_FS_DCFG_DSPD; + + /* Restart the phy clock */ + OTG_FS_PCGCCTL = 0; + + + /* Unmask interrupts for TX and RX */ + OTG_FS_GINTMSK &= OTG_FS_GINTMSK_RXFLVLM; } static void stm32f107_set_address(u8 addr) { - (void)addr; + /* There is something badly wrong gere! */ + /* TODO: Set device address and enable. */ + + /* This I think is correct, but doesn't work at all... */ + //OTG_FS_DCFG = (OTG_FS_DCFG & ~OTG_FS_DCFG_DAD) | (addr << 4); + + /* This is obviously incorrect, but sometimes works... */ + OTG_FS_DCFG |= addr << 4; } static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, @@ -65,12 +107,39 @@ static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, * Allocate FIFO memory for endpoint. * Install callback funciton. */ - (void)type; (void)max_size; - u8 dir = addr & 0x80; addr &= 0x7f; - if (dir || (addr == 0)) { + if(addr == 0) { /* For the default control endpoint */ + /* Configure IN part */ + if(max_size >= 64) { + OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_64; + } else if(max_size >= 32) { + OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_32; + } else if(max_size >= 16) { + OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_16; + } else { + OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_8; + } + OTG_FS_DIEPTSIZ0 = (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + OTG_FS_DIEPCTL0 |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK; + + /* Configure OUT part */ + doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 | (1 << 19) | + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + OTG_FS_DOEPTSIZ(0) = doeptsiz[0]; + OTG_FS_DOEPCTL(0) |= OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK; + + return; + } + + /* TODO: Configuration for other endpoints */ + if (dir) { + OTG_FS_DIEPTSIZ(addr) = (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_EPENA | + OTG_FS_DIEPCTL0_SNAK | (type << 18) | + (addr << 22) | max_size; + if (callback) { _usbd_device. user_callback_ctr[addr][USB_TRANSACTION_IN] = @@ -79,6 +148,12 @@ static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, } if (!dir) { + doeptsiz[addr] = (1 << 19) | + (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK); + OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr]; + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA | + OTG_FS_DIEPCTL0_CNAK | (type << 18) | max_size; + if (callback) { _usbd_device. user_callback_ctr[addr][USB_TRANSACTION_OUT] = @@ -94,8 +169,28 @@ static void stm32f107_endpoints_reset(void) static void stm32f107_ep_stall_set(u8 addr, u8 stall) { - /* TODO: set or clear stall condition */ - (void)addr; (void)stall; + if(addr == 0) { + if(stall) + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_STALL; + else + OTG_FS_DOEPCTL(addr) &= ~OTG_FS_DOEPCTL0_STALL; + } + + if(addr & 0x80) { + addr &= 0x7F; + + if(stall) + OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_STALL; + else + OTG_FS_DIEPCTL(addr) &= ~OTG_FS_DIEPCTL0_STALL; + /* TODO: Reset to DATA0 */ + } else { + if(stall) + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_STALL; + else + OTG_FS_DOEPCTL(addr) &= ~OTG_FS_DOEPCTL0_STALL; + /* TODO: Reset to DATA0 */ + } } static u8 stm32f107_ep_stall_get(u8 addr) @@ -108,18 +203,51 @@ static u8 stm32f107_ep_stall_get(u8 addr) static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len) { + const u32 *buf32 = buf; + int i; + addr &= 0x7F; - /* TODO: Send packet on endpoint */ - (void)buf; + /* Enable endpoint for transmission */ + OTG_FS_DIEPTSIZ(addr) = (1 << 19) | len; + OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_CNAK; + + /* Copy buffer to endpoint FIFO */ + u32 *fifo = OTG_FS_FIFO(addr); + for(i = len; i > 0; i -= 4) { + *fifo++ = *buf32++; + } return len; } +/* Received packet size for each endpoint. This is assigned in + * stm32f107_poll() which reads the packet status push register GRXSTSP + * for use in stm32f107_ep_read_packet(). + */ +static uint16_t rxbcnt[4]; + static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len) { - /* TODO: Read packet from endpoint */ - (void)addr; (void)buf; (void)len; + int i; + u32 *buf32 = buf; + u32 extra; + + len = MIN(len, rxbcnt[addr]); + rxbcnt[addr] = 0; + + u32 *fifo = OTG_FS_FIFO(addr); + for(i = len; i >= 4; i -= 4) { + *buf32++ = *fifo++; + } + + if(i) { + extra = *fifo; + memcpy(buf32, &extra, i); + } + + OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr]; + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA | OTG_FS_DOEPCTL0_CNAK; return len; } @@ -127,23 +255,55 @@ static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len) static void stm32f107_poll(void) { /* TODO: Read interrupt status register */ + u32 intsts = OTG_FS_GINTSTS; - /* TODO: Handle USB RESET condition */ - if (0) { + if (intsts & OTG_FS_GINTSTS_ENUMDNE) { + /* TODO: Handle USB RESET condition */ + OTG_FS_GINTSTS = OTG_FS_GINTSTS_ENUMDNE; _usbd_reset(); return; } /* TODO: Handle transfer complete condition */ - if (0) { - u8 ep; + /* Note: RX and TX handled differently in this device. */ + if (intsts & OTG_FS_GINTSTS_RXFLVL) { + /* Receive FIFO non-empty */ + u32 rxstsp = OTG_FS_GRXSTSP; + u32 pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK; + if((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) && + (pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP)) return; + + u8 ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK; u8 type; + if(pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP) + type = USB_TRANSACTION_SETUP; + else + type = USB_TRANSACTION_OUT; + + /* Save packet size for stm32f107_ep_read_packet() */ + rxbcnt[ep] = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4; if (_usbd_device.user_callback_ctr[ep][type]) _usbd_device.user_callback_ctr[ep][type] (ep); /* TODO: clear any interrupt flag */ } + /* There is no global interrupt flag for transmit complete. + * the XFRC bit must be checked in each OTG_FS_DIEPINT(x) + */ + /* TODO: Check on endpoint interrupt... */ + { + int i; + for (i = 0; i < 4; i++) { /* Iterate over endpoints */ + if(OTG_FS_DIEPINT(i) & OTG_FS_DIEPINTX_XFRC) { + /* Transfer complete */ + if (_usbd_device.user_callback_ctr[i][USB_TRANSACTION_IN]) + _usbd_device.user_callback_ctr[i][USB_TRANSACTION_IN] (i); + OTG_FS_DIEPINT(i) = OTG_FS_DIEPINTX_XFRC; + } + } + } + /* TODO: Handle suspend condition */ if (0) { /* TODO: Clear suspend interrupt flag */