diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-22 16:46:45 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-22 16:46:45 +0900 |
commit | 8880a8b1f9a738e9b1ab17712131279a3dfb6881 (patch) | |
tree | 1de56a2bae50bd755acc34aeac705c2b3c683345 /example-cdc | |
parent | aa3fd9876abe2131d2ebda9a418ade6a4b89f72c (diff) |
add cdc example
Diffstat (limited to 'example-cdc')
-rw-r--r-- | example-cdc/Makefile | 31 | ||||
-rw-r--r-- | example-cdc/aes-constant-ft.c | 145 | ||||
-rw-r--r-- | example-cdc/sample.c | 173 | ||||
-rw-r--r-- | example-cdc/sample.ld | 142 | ||||
-rw-r--r-- | example-cdc/sys.c | 600 | ||||
-rw-r--r-- | example-cdc/sys.h | 97 | ||||
-rw-r--r-- | example-cdc/usb-cdc.c | 432 | ||||
-rw-r--r-- | example-cdc/usb_lld.h | 142 | ||||
-rw-r--r-- | example-cdc/usb_stm32f103.c | 1214 |
9 files changed, 2976 insertions, 0 deletions
diff --git a/example-cdc/Makefile b/example-cdc/Makefile new file mode 100644 index 0000000..701aac3 --- /dev/null +++ b/example-cdc/Makefile @@ -0,0 +1,31 @@ +# Makefile for example application of Chopstx + +PROJECT = sample + +CHOPSTX = .. +LDSCRIPT= sample.ld +CSRC = sys.c aes-constant-ft.c sample.c usb-cdc.c usb_stm32f103.c + +################################### +CROSS = arm-none-eabi- +CC = $(CROSS)gcc +LD = $(CROSS)gcc +OBJCOPY = $(CROSS)objcopy + +MCU = cortex-m3 +CWARN = -Wall -Wextra -Wstrict-prototypes +DEFS = -DFREE_STANDING +OPT = -O3 -Os -g +LIBS = + +#################### +include ../rules.mk + +board.h: + @echo Please make a symbolic link \'board.h\' to a file in ../board; + @exit 1 + +sys.c: board.h + +distclean: clean + rm -f board.h diff --git a/example-cdc/aes-constant-ft.c b/example-cdc/aes-constant-ft.c new file mode 100644 index 0000000..21d1ba7 --- /dev/null +++ b/example-cdc/aes-constant-ft.c @@ -0,0 +1,145 @@ +/* + * aes-constant-ft.c - AES forward tables. + * + * We need something useful for the initial flash ROM page (4 Ki + * bytes), which cannot be modified after installation. Even after + * upgrade of the firmware, it stays intact. + * + * We decide to put 3/4 of AES forward tables to fill 3 Ki bytes, as + * its useful and it won't change. + * + * The code was taken from aes.c of PolarSSL version 0.14, and then, + * modified to add section names. + * + * Since this is just a data, it wouldn't be copyright-able, but the + * original auther would claim so. Thus, we put original copyright + * notice here. It is highly likely that there will be no such a + * thing for copyright. Nevertheless, we think that PolarSSL is good + * software to address here, and encourage people using it. + * + */ + +#include <stdint.h> + +/* + * Original copyright notice is below: + */ + +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT }; +#undef V + +#ifdef ORIGINAL_IMPLEMENTATION +#define V(a,b,c,d) 0x##d##a##b##c +const uint32_t FT3[256] = { FT }; +#undef V +#endif diff --git a/example-cdc/sample.c b/example-cdc/sample.c new file mode 100644 index 0000000..6534a26 --- /dev/null +++ b/example-cdc/sample.c @@ -0,0 +1,173 @@ +#include <stdint.h> +#include <stdlib.h> +#include <chopstx.h> +#include "sys.h" /* for set_led */ +#include "usb_lld.h" /* for set_led */ + +static chopstx_mutex_t mtx; +static chopstx_cond_t cnd0; +static chopstx_cond_t cnd1; + +chopstx_mutex_t usb_mtx; +chopstx_cond_t cnd_usb_connection; +chopstx_cond_t cnd_usb_buffer_ready; + +static uint8_t u, v; +static uint8_t m; /* 0..100 */ + +static void * +pwm (void *arg) +{ + (void)arg; + + chopstx_mutex_lock (&mtx); + chopstx_cond_wait (&cnd0, &mtx); + chopstx_mutex_unlock (&mtx); + + while (1) + { + set_led (u&v); + chopstx_usleep (m); + set_led (0); + chopstx_usleep (100-m); + } + + return NULL; +} + +static void * +blk (void *arg) +{ + (void)arg; + + chopstx_mutex_lock (&mtx); + chopstx_cond_wait (&cnd1, &mtx); + chopstx_mutex_unlock (&mtx); + + while (1) + { + v = 0; + chopstx_usleep (200*1000); + v = 1; + chopstx_usleep (200*1000); + } + + return NULL; +} + +#define INTR_REQ_USB 20 + +static void * +usb_intr (void *arg) +{ + extern void usb_lld_init (uint8_t feature); + extern void usb_interrupt_handler (void); + + chopstix_intr_t interrupt; + + (void)arg; + asm volatile ("cpsid i" : : : "memory"); + /* Disable because of usb_lld_init assumes interrupt handler. */ + usb_lld_init (0x80); /* Bus powered. */ + chopstx_intr_register (&interrupt, INTR_REQ_USB); + /* Enable */ + asm volatile ("cpsie i" : : : "memory"); + + while (1) + { + chopstx_wait_intr (&interrupt); + + /* Process interrupt. */ + usb_interrupt_handler (); + } + + return NULL; +} + +#define PRIO_PWM 3 +#define PRIO_BLK 2 +#define PRIO_INTR 4 + +extern uint8_t __process1_stack_base__, __process1_stack_size__; +extern uint8_t __process2_stack_base__, __process2_stack_size__; +extern uint8_t __process3_stack_base__, __process3_stack_size__; + +const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__; +const size_t __stacksize_pwm = (size_t)&__process1_stack_size__; + +const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__; +const size_t __stacksize_blk = (size_t)&__process2_stack_size__; + +const uint32_t __stackaddr_intr = (uint32_t)&__process3_stack_base__; +const size_t __stacksize_intr = (size_t)&__process3_stack_size__; + + +int +main (int argc, const char *argv[]) +{ + chopstx_t thd; + chopstx_attr_t attr; + + (void)argc; + (void)argv; + + chopstx_mutex_init (&mtx); + chopstx_cond_init (&cnd0); + chopstx_cond_init (&cnd1); + + chopstx_mutex_init (&usb_mtx); + chopstx_cond_init (&cnd_usb_connection); + chopstx_cond_init (&cnd_usb_buffer_ready); + + m = 10; + + chopstx_attr_init (&attr); + chopstx_attr_setschedparam (&attr, PRIO_PWM); + chopstx_attr_setstack (&attr, __stackaddr_pwm, __stacksize_pwm); + + chopstx_create (&thd, &attr, pwm, NULL); + + chopstx_attr_setschedparam (&attr, PRIO_BLK); + chopstx_attr_setstack (&attr, __stackaddr_blk, __stacksize_blk); + + chopstx_create (&thd, &attr, blk, NULL); + + chopstx_attr_setschedparam (&attr, PRIO_INTR); + chopstx_attr_setstack (&attr, __stackaddr_intr, __stacksize_intr); + + chopstx_create (&thd, &attr, usb_intr, NULL); + + chopstx_usleep (200*1000); + + chopstx_mutex_lock (&mtx); + chopstx_cond_signal (&cnd0); + chopstx_cond_signal (&cnd1); + chopstx_mutex_unlock (&mtx); + + while (1) + { + extern uint8_t connected; + + /* waiting USB connection */ + chopstx_mutex_lock (&usb_mtx); + if (!connected) + chopstx_cond_wait (&cnd_usb_connection, &usb_mtx); + chopstx_mutex_unlock (&usb_mtx); + + while (1) + { + u ^= 1; + chopstx_usleep (200*1000*6); + + usb_lld_write (ENDP1, "Hello, World with Chopstx!\r\n", 28); + chopstx_mutex_lock (&usb_mtx); + chopstx_cond_wait (&cnd_usb_buffer_ready, &usb_mtx); + if (!connected) + break; + chopstx_mutex_unlock (&usb_mtx); + } + chopstx_mutex_unlock (&usb_mtx); + } + + return 0; +} diff --git a/example-cdc/sample.ld b/example-cdc/sample.ld new file mode 100644 index 0000000..f98d789 --- /dev/null +++ b/example-cdc/sample.ld @@ -0,0 +1,142 @@ +/* + * ST32F103 memory setup. + */ +__main_stack_size__ = 0x0100; /* Exception handlers */ +__process0_stack_size__ = 0x0100; /* Main program */ +__process1_stack_size__ = 0x0100; /* first thread program */ +__process2_stack_size__ = 0x0100; /* second thread program */ +__process3_stack_size__ = 0x0100; /* third thread program */ + +MEMORY +{ + flash0 : org = 0x08000000, len = 4k + flash : org = 0x08000000+0x1000, len = 60k + ram : org = 0x20000000, len = 20k +} + +__flash_start__ = 0x08001000; +__flash_end__ = 0x08020000; + +__ram_start__ = ORIGIN(ram); +__ram_size__ = 20k; +__ram_end__ = __ram_start__ + __ram_size__; + +SECTIONS +{ + . = 0; + + .sys : ALIGN(16) SUBALIGN(16) + { + _sys = .; + KEEP(*(.vectors)) + . = ALIGN(16); + *(.sys.version) + build/sys.o(.text) + build/sys.o(.text.*) + build/sys.o(.rodata) + build/sys.o(.rodata.*) + . = ALIGN(1024); + *(.sys.0) + *(.sys.1) + *(.sys.2) + } > flash0 + + _text = .; + + .startup : ALIGN(128) SUBALIGN(128) + { + KEEP(*(.startup.vectors)) + . = ALIGN (16); + } > flash =0xffffffff + + .text : ALIGN(16) SUBALIGN(16) + { + *(.text.startup.*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + } > flash + + .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash + + .ARM.exidx : { + PROVIDE(__exidx_start = .); + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + PROVIDE(__exidx_end = .); + } > flash + + .eh_frame_hdr : {*(.eh_frame_hdr)} > flash + + .eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash + + .textalign : ONLY_IF_RO { . = ALIGN(8); } > flash + + _etext = .; + _textdata = _etext; + + .process_stack : + { + . = ALIGN(8); + __process3_stack_base__ = .; + . += __process3_stack_size__; + . = ALIGN(8); + __process_stack3_end__ = .; + __process2_stack_base__ = .; + . += __process2_stack_size__; + . = ALIGN(8); + __process_stack2_end__ = .; + __process1_stack_base__ = .; + . += __process1_stack_size__; + . = ALIGN(8); + __process_stack1_end__ = .; + __process0_stack_base__ = .; + . += __process0_stack_size__; + . = ALIGN(8); + __process0_stack_end__ = .; + } > ram + + .main_stack : + { + . = ALIGN(8); + __main_stack_base__ = .; + . += __main_stack_size__; + . = ALIGN(8); + __main_stack_end__ = .; + } > ram + + .data : + { + . = ALIGN(4); + PROVIDE(_data = .); + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + PROVIDE(_edata = .); + } > ram AT > flash + + .bss : + { + . = ALIGN(4); + PROVIDE(_bss_start = .); + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + PROVIDE(_bss_end = .); + } > ram + + PROVIDE(end = .); + _end = .; +} + +__heap_base__ = _end; +__heap_end__ = __ram_end__; diff --git a/example-cdc/sys.c b/example-cdc/sys.c new file mode 100644 index 0000000..af594b0 --- /dev/null +++ b/example-cdc/sys.c @@ -0,0 +1,600 @@ +/* + * sys.c - system routines for the initial page for STM32F103. + * + * Copyright (C) 2013 Flying Stone Technology + * Author: NIIBE Yutaka <gniibe@fsij.org> + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + * + * When the flash ROM is protected, we cannot modify the initial page. + * We put some system routines (which is useful for any program) here. + */ + +#include <stdint.h> +#include <stdlib.h> +#include "board.h" + + +#define CORTEX_PRIORITY_BITS 4 +#define CORTEX_PRIORITY_MASK(n) ((n) << (8 - CORTEX_PRIORITY_BITS)) +#define USB_LP_CAN1_RX0_IRQn 20 +#define STM32_USB_IRQ_PRIORITY 11 + +#define FLASH_PAGE_SIZE 1024 + + + +#define STM32_SW_PLL (2 << 0) +#define STM32_PLLSRC_HSE (1 << 16) + +#define STM32_PLLXTPRE_DIV1 (0 << 17) +#define STM32_PLLXTPRE_DIV2 (1 << 17) + +#define STM32_HPRE_DIV1 (0 << 4) + +#define STM32_PPRE1_DIV2 (4 << 8) + +#define STM32_PPRE2_DIV1 (0 << 11) +#define STM32_PPRE2_DIV2 (4 << 11) + +#define STM32_ADCPRE_DIV4 (1 << 14) +#define STM32_ADCPRE_DIV6 (2 << 14) + +#define STM32_USBPRE_DIV1P5 (0 << 22) + +#define STM32_MCO_NOCLOCK (0 << 24) + +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_HSE +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV2 +#define STM32_PPRE2 STM32_PPRE2_DIV1 +#define STM32_ADCPRE STM32_ADCPRE_DIV6 +#define STM32_MCOSEL STM32_MCO_NOCLOCK +#define STM32_USBPRE STM32_USBPRE_DIV1P5 + +#define STM32_PLLCLKIN (STM32_HSECLK / 1) +#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18) +#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE) +#define STM32_SYSCLK STM32_PLLCLKOUT +#define STM32_HCLK (STM32_SYSCLK / 1) + +#define STM32_FLASHBITS 0x00000012 + +struct NVIC { + uint32_t ISER[8]; + uint32_t unused1[24]; + uint32_t ICER[8]; + uint32_t unused2[24]; + uint32_t ISPR[8]; + uint32_t unused3[24]; + uint32_t ICPR[8]; + uint32_t unused4[24]; + uint32_t IABR[8]; + uint32_t unused5[56]; + uint32_t IPR[60]; +}; + +static struct NVIC *const NVICBase = ((struct NVIC *const)0xE000E100); +#define NVIC_ISER(n) (NVICBase->ISER[n >> 5]) +#define NVIC_ICPR(n) (NVICBase->ICPR[n >> 5]) +#define NVIC_IPR(n) (NVICBase->IPR[n >> 2]) + +static void +nvic_enable_vector (uint32_t n, uint32_t prio) +{ + unsigned int sh = (n & 3) << 3; + + NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (prio << sh); + NVIC_ICPR (n) = 1 << (n & 0x1F); + NVIC_ISER (n) = 1 << (n & 0x1F); +} + + +#define PERIPH_BASE 0x40000000 +#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) +#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) + +struct RCC { + volatile uint32_t CR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + volatile uint32_t APB2RSTR; + volatile uint32_t APB1RSTR; + volatile uint32_t AHBENR; + volatile uint32_t APB2ENR; + volatile uint32_t APB1ENR; + volatile uint32_t BDCR; + volatile uint32_t CSR; +}; + +#define RCC_BASE (AHBPERIPH_BASE + 0x1000) +static struct RCC *const RCC = ((struct RCC *const)RCC_BASE); + +#define RCC_APB1ENR_USBEN 0x00800000 +#define RCC_APB1RSTR_USBRST 0x00800000 + +#define RCC_CR_HSION 0x00000001 +#define RCC_CR_HSIRDY 0x00000002 +#define RCC_CR_HSITRIM 0x000000F8 +#define RCC_CR_HSEON 0x00010000 +#define RCC_CR_HSERDY 0x00020000 +#define RCC_CR_PLLON 0x01000000 +#define RCC_CR_PLLRDY 0x02000000 + +#define RCC_CFGR_SWS 0x0000000C +#define RCC_CFGR_SWS_HSI 0x00000000 + +#define RCC_AHBENR_CRCEN 0x0040 + +struct FLASH { + volatile uint32_t ACR; + volatile uint32_t KEYR; + volatile uint32_t OPTKEYR; + volatile uint32_t SR; + volatile uint32_t CR; + volatile uint32_t AR; + volatile uint32_t RESERVED; + volatile uint32_t OBR; + volatile uint32_t WRPR; +}; + +#define FLASH_R_BASE (AHBPERIPH_BASE + 0x2000) +static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE); + +static void +clock_init (void) +{ + /* HSI setup */ + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) + ; + RCC->CR &= RCC_CR_HSITRIM | RCC_CR_HSION; + RCC->CFGR = 0; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) + ; + + /* HSE setup */ + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR & RCC_CR_HSERDY)) + ; + + /* PLL setup */ + RCC->CFGR |= STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC; + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) + ; + + /* Clock settings */ + RCC->CFGR = STM32_MCOSEL | STM32_USBPRE | STM32_PLLMUL | STM32_PLLXTPRE + | STM32_PLLSRC | STM32_ADCPRE | STM32_PPRE2 | STM32_PPRE1 | STM32_HPRE; + + /* Flash setup */ + FLASH->ACR = STM32_FLASHBITS; + + /* CRC */ + RCC->AHBENR |= RCC_AHBENR_CRCEN; + + /* Switching on the configured clock source. */ + RCC->CFGR |= STM32_SW; + while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2)) + ; +} + +#define RCC_APB2ENR_IOPAEN 0x00000004 +#define RCC_APB2RSTR_IOPARST 0x00000004 +#define RCC_APB2ENR_IOPBEN 0x00000008 +#define RCC_APB2RSTR_IOPBRST 0x00000008 +#define RCC_APB2ENR_IOPCEN 0x00000010 +#define RCC_APB2RSTR_IOPCRST 0x00000010 +#define RCC_APB2ENR_IOPDEN 0x00000020 +#define RCC_APB2RSTR_IOPDRST 0x00000020 + + +struct GPIO { + volatile uint32_t CRL; + volatile uint32_t CRH; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile uint32_t BSRR; + volatile uint32_t BRR; + volatile uint32_t LCKR; +}; + +#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) +#define GPIOA ((struct GPIO *) GPIOA_BASE) +#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) +#define GPIOB ((struct GPIO *) GPIOB_BASE) +#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) +#define GPIOC ((struct GPIO *) GPIOC_BASE) +#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) +#define GPIOD ((struct GPIO *) GPIOD_BASE) +#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) +#define GPIOE ((struct GPIO *) GPIOE_BASE) + +static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE); +static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE); + +static void +gpio_init (void) +{ + /* Enable GPIO clock. */ + RCC->APB2ENR |= RCC_APB2ENR_IOP_EN; + RCC->APB2RSTR = RCC_APB2RSTR_IOP_RST; + RCC->APB2RSTR = 0; + + GPIO_USB->ODR = VAL_GPIO_ODR; + GPIO_USB->CRH = VAL_GPIO_CRH; + GPIO_USB->CRL = VAL_GPIO_CRL; + +#if GPIO_USB_BASE != GPIO_LED_BASE + GPIO_LED->ODR = VAL_GPIO_LED_ODR; + GPIO_LED->CRH = VAL_GPIO_LED_CRH; + GPIO_LED->CRL = VAL_GPIO_LED_CRL; +#endif +} + +static void +usb_cable_config (int enable) +{ +#if defined(GPIO_USB_SET_TO_ENABLE) + if (enable) + GPIO_USB->BSRR = (1 << GPIO_USB_SET_TO_ENABLE); + else + GPIO_USB->BRR = (1 << GPIO_USB_SET_TO_ENABLE); +#elif defined(GPIO_USB_CLEAR_TO_ENABLE) + if (enable) + GPIO_USB->BRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); + else + GPIO_USB->BSRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); +#else + (void)enable; +#endif +} + +void +set_led (int on) +{ +#if defined(GPIO_LED_CLEAR_TO_EMIT) + if (on) + GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT); + else + GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT); +#else + if (on) + GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT); + else + GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT); +#endif +} + +static void wait (int count) +{ + int i; + + for (i = 0; i < count; i++) + asm volatile ("" : : "r" (i) : "memory"); +} + +#define USB_IRQ 20 +#define USB_IRQ_PRIORITY ((11) << 4) + +static void +usb_lld_sys_shutdown (void) +{ + RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + usb_cable_config (0); +} + +static void +usb_lld_sys_init (void) +{ + if ((RCC->APB1ENR & RCC_APB1ENR_USBEN) + && (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0) + /* Make sure the device is disconnected, even after core reset. */ + { + usb_lld_sys_shutdown (); + /* Disconnect requires SE0 (>= 2.5uS). */ + wait (300); + } + + usb_cable_config (1); + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + nvic_enable_vector (USB_LP_CAN1_RX0_IRQn, + CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY)); + /* + * Note that we also have other IRQ(s): + * USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous) + * USBWakeUp_IRQn (suspend/resume) + */ + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + RCC->APB1RSTR = 0; +} + +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +enum flash_status +{ + FLASH_BUSY = 1, + FLASH_ERROR_PG, + FLASH_ERROR_WRP, + FLASH_COMPLETE, + FLASH_TIMEOUT +}; + +static void __attribute__ ((used)) +flash_unlock (void) +{ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; +} + + +#define intr_disable() asm volatile ("cpsid i" : : : "memory") + +#define intr_enable() asm volatile ("msr BASEPRI, %0\n\t" \ + "cpsie i" : : "r" (0) : "memory") + +#define FLASH_SR_BSY 0x01 +#define FLASH_SR_PGERR 0x04 +#define FLASH_SR_WRPRTERR 0x10 +#define FLASH_SR_EOP 0x20 + +#define FLASH_CR_PG 0x0001 +#define FLASH_CR_PER 0x0002 +#define FLASH_CR_MER 0x0004 +#define FLASH_CR_OPTPG 0x0010 +#define FLASH_CR_OPTER 0x0020 +#define FLASH_CR_STRT 0x0040 +#define FLASH_CR_LOCK 0x0080 +#define FLASH_CR_OPTWRE 0x0200 +#define FLASH_CR_ERRIE 0x0400 +#define FLASH_CR_EOPIE 0x1000 + +static int +flash_wait_for_last_operation (uint32_t timeout) +{ + int status; + + do + { + status = FLASH->SR; + if (--timeout == 0) + break; + } + while ((status & FLASH_SR_BSY) != 0); + + return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR); +} + +#define FLASH_PROGRAM_TIMEOUT 0x00010000 +#define FLASH_ERASE_TIMEOUT 0x01000000 + +static int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PG; + + *(volatile uint16_t *)addr = data; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PG; + } + intr_enable (); + + return status; +} + +static int +flash_erase_page (uint32_t addr) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = addr; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PER; + } + intr_enable (); + + return status; +} + +static int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + const uint8_t *p; + + for (p = p_start; p < p_start + size; p++) + if (*p != 0xff) + return 0; + + return 1; +} + +extern uint8_t __flash_start__, __flash_end__; + +static int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int status; + uint32_t flash_start = (uint32_t)&__flash_start__; + uint32_t flash_end = (uint32_t)&__flash_end__; + + if (dst_addr < flash_start || dst_addr + len > flash_end) + return 0; + + while (len) + { + uint16_t hw = *src++; + + hw |= (*src++ << 8); + status = flash_program_halfword (dst_addr, hw); + if (status != 0) + return 0; /* error return */ + + dst_addr += 2; + len -= 2; + } + + return 1; +} + +#define OPTION_BYTES_ADDR 0x1ffff800 + +static int +flash_protect (void) +{ + int status; + uint32_t option_bytes_value; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + FLASH->CR |= FLASH_CR_OPTER; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_OPTER; + } + intr_enable (); + + if (status != 0) + return 0; + + option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR; + return (option_bytes_value & 0xff) == 0xff ? 1 : 0; +} + +static void __attribute__((naked)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + uint32_t addr = (uint32_t)&__flash_start__; + uint32_t end = (uint32_t)&__flash_end__; + int r; + + while (addr < end) + { + r = flash_erase_page (addr); + if (r != 0) + break; + + addr += FLASH_PAGE_SIZE; + } + + if (addr >= end) + (*entry) (); + + for (;;); +} + +struct SCB +{ + volatile uint32_t CPUID; + volatile uint32_t ICSR; + volatile uint32_t VTOR; + volatile uint32_t AIRCR; + volatile uint32_t SCR; + volatile uint32_t CCR; + volatile uint8_t SHP[12]; + volatile uint32_t SHCSR; + volatile uint32_t CFSR; + volatile uint32_t HFSR; + volatile uint32_t DFSR; + volatile uint32_t MMFAR; + volatile uint32_t BFAR; + volatile uint32_t AFSR; + volatile uint32_t PFR[2]; + volatile uint32_t DFR; + volatile uint32_t ADR; + volatile uint32_t MMFR[4]; + volatile uint32_t ISAR[5]; +}; + +#define SCS_BASE (0xE000E000) +#define SCB_BASE (SCS_BASE + 0x0D00) +static struct SCB *const SCB = ((struct SCB *const) SCB_BASE); + +#define SYSRESETREQ 0x04 +static void +nvic_system_reset (void) +{ + SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ); + asm volatile ("dsb"); +} + +static void __attribute__ ((naked)) +reset (void) +{ + asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ + "mov.w r0, #0xed00\n\t" /* r0 = SCR */ + "movt r0, #0xe000\n\t" + "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ + "mov r2, #0x1000\n\t" + "add r1, r1, r2\n\t" + "sub r2, r2, #1\n\t" + "bic r1, r1, r2\n\t" + "str r1, [r0, #8]\n\t" /* Set SCR->VCR */ + "ldr r0, [r1], #4\n\t" + "msr MSP, r0\n\t" /* Main (exception handler) stack. */ + "ldr r0, [r1]\n\t" /* Reset handler. */ + "bx r0\n" + : /* no output */ : /* no input */ : "memory"); +} + +typedef void (*handler)(void); +extern uint8_t __ram_end__; + +extern const unsigned long *FT0, *FT1, *FT2; + +handler vector[] __attribute__ ((section(".vectors"))) = { + (handler)&__ram_end__, + reset, + (handler)set_led, + flash_unlock, + (handler)flash_program_halfword, + (handler)flash_erase_page, + (handler)flash_check_blank, + (handler)flash_write, + (handler)flash_protect, + (handler)flash_erase_all_and_exec, + usb_lld_sys_init, + usb_lld_sys_shutdown, + nvic_system_reset, + clock_init, + gpio_init, + (handler)&FT0, + (handler)&FT1, + (handler)&FT2, +}; + +const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = { + 3*2+2, /* bLength */ + 0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/ + /* sys version: "2.0" */ + '2', 0, '.', 0, '0', 0, +}; diff --git a/example-cdc/sys.h b/example-cdc/sys.h new file mode 100644 index 0000000..bb1ea71 --- /dev/null +++ b/example-cdc/sys.h @@ -0,0 +1,97 @@ +extern const uint8_t sys_version[8]; + +typedef void (*handler)(void); +extern handler vector[18]; + +static inline const uint8_t * +unique_device_id (void) +{ + /* STM32F103 has 96-bit unique device identifier */ + const uint8_t *addr = (const uint8_t *)0x1ffff7e8; + + return addr; +} + +static inline void +set_led (int on) +{ + void (*func) (int) = (void (*)(int))vector[2]; + + return (*func) (on); +} + +#if 0 +static inline void +flash_unlock (void) +{ + (*vector[3]) (); +} +#endif + +static inline int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4]; + + return (*func) (addr, data); +} + +static inline int +flash_erase_page (uint32_t addr) +{ + int (*func) (uint32_t) = (int (*)(uint32_t))vector[5]; + + return (*func) (addr); +} + +static inline int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6]; + + return (*func) (p_start, size); +} + +static inline int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int (*func) (uint32_t, const uint8_t *, size_t) + = (int (*)(uint32_t, const uint8_t *, size_t))vector[7]; + + return (*func) (dst_addr, src, len); +} + +static inline int +flash_protect (void) +{ + int (*func) (void) = (int (*)(void))vector[8]; + + return (*func) (); +} + +static inline void __attribute__((noreturn)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9]; + + (*func) (entry); + for (;;); +} + +static inline void +usb_lld_sys_init (void) +{ + (*vector[10]) (); +} + +static inline void +usb_lld_sys_shutdown (void) +{ + (*vector[11]) (); +} + +static inline void +nvic_system_reset (void) +{ + (*vector[12]) (); +} diff --git a/example-cdc/usb-cdc.c b/example-cdc/usb-cdc.c new file mode 100644 index 0000000..695c2f0 --- /dev/null +++ b/example-cdc/usb-cdc.c @@ -0,0 +1,432 @@ +#include <stdint.h> +#include <stdlib.h> +#include <chopstx.h> +#include "usb_lld.h" + +extern chopstx_mutex_t usb_mtx; +extern chopstx_cond_t cnd_usb_connection; +extern chopstx_cond_t cnd_usb_buffer_ready; + +#define ENDP0_RXADDR (0x40) +#define ENDP0_TXADDR (0x80) +#define ENDP1_TXADDR (0xc0) +#define ENDP2_TXADDR (0x100) +#define ENDP3_RXADDR (0x140) + +#define USB_CDC_REQ_SET_LINE_CODING 0x20 +#define USB_CDC_REQ_GET_LINE_CODING 0x21 +#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 +#define USB_CDC_REQ_SEND_BREAK 0x23 + +/* USB Device Descriptor */ +static const uint8_t vcom_device_desc[18] = { + 18, /* bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSB = 1.1 */ + 0x02, /* bDeviceClass (CDC). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* bMaxPacketSize. */ + 0xFF, 0xFF, /* idVendor */ + 0x01, 0x00, /* idProduct */ + 0x00, 0x01, /* bcdDevice */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1 /* bNumConfigurations. */ +}; + +/* Configuration Descriptor tree for a CDC.*/ +static const uint8_t vcom_configuration_desc[67] = { + 9, + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ + /* Configuration Descriptor.*/ + 67, 0x00, /* wTotalLength. */ + 0x02, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0x80, /* bmAttributes (bus powered). */ + 50, /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + 9, + USB_INTERFACE_DESCRIPTOR_TYPE, + 0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x01, /* bNumEndpoints. */ + 0x02, /* bInterfaceClass (Communications Interface Class, + CDC section 4.2). */ + 0x02, /* bInterfaceSubClass (Abstract Control Model, CDC + section 4.3). */ + 0x01, /* bInterfaceProtocol (AT commands, CDC section + 4.4). */ + 0, /* iInterface. */ + /* Header Functional Descriptor (CDC section 5.2.3).*/ + 5, /* bLength. */ + 0x24, /* bDescriptorType (CS_INTERFACE). */ + 0x00, /* bDescriptorSubtype (Header Functional Descriptor). */ + 0x10, 0x01, /* bcdCDC. */ + /* Call Management Functional Descriptor. */ + 5, /* bFunctionLength. */ + 0x24, /* bDescriptorType (CS_INTERFACE). */ + 0x01, /* bDescriptorSubtype (Call Management Functional + Descriptor). */ + 0x03, /* bmCapabilities (D0+D1). */ + 0x01, /* bDataInterface. */ + /* ACM Functional Descriptor.*/ + 4, /* bFunctionLength. */ + 0x24, /* bDescriptorType (CS_INTERFACE). */ + 0x02, /* bDescriptorSubtype (Abstract Control Management + Descriptor). */ + 0x02, /* bmCapabilities. */ + /* Union Functional Descriptor.*/ + 5, /* bFunctionLength. */ + 0x24, /* bDescriptorType (CS_INTERFACE). */ + 0x06, /* bDescriptorSubtype (Union Functional + Descriptor). */ + 0x00, /* bMasterInterface (Communication Class + Interface). */ + 0x01, /* bSlaveInterface0 (Data Class Interface). */ + /* Endpoint 2 Descriptor.*/ + 7, + USB_ENDPOINT_DESCRIPTOR_TYPE, + ENDP2|0x80, /* bEndpointAddress. */ + 0x03, /* bmAttributes (Interrupt). */ + 0x08, 0x00, /* wMaxPacketSize. */ + 0xFF, /* bInterval. */ + /* Interface Descriptor.*/ + 9, + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ + 0x01, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */ + 0x00, /* bInterfaceSubClass (CDC section 4.6). */ + 0x00, /* bInterfaceProtocol (CDC section 4.7). */ + 0x00, /* iInterface. */ + /* Endpoint 3 Descriptor.*/ + 7, + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + ENDP3, /* bEndpointAddress. */ + 0x02, /* bmAttributes (Bulk). */ + 0x40, 0x00, /* wMaxPacketSize. */ + 0x00, /* bInterval. */ + /* Endpoint 1 Descriptor.*/ + 7, + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + ENDP1|0x80, /* bEndpointAddress. */ + 0x02, /* bmAttributes (Bulk). */ + 0x40, 0x00, /* wMaxPacketSize. */ + 0x00 /* bInterval. */ +}; + + +/* + * U.S. English language identifier. + */ +static const uint8_t vcom_string0[4] = { + 4, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, + 0x09, 0x04 /* LangID = 0x0409: US-English */ +}; + +static const uint8_t vcom_string1[] = { + 23*2+2, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + /* Manufacturer: "Flying Stone Technology" */ + 'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0, + 't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0, + 'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0, +}; + +static const uint8_t vcom_string2[] = { + 14*2+2, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + /* Product name: "Chopstx Sample" */ + 'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0, + 'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0, +}; + +/* + * Serial Number string. + */ +static const uint8_t vcom_string3[28] = { + 28, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + '0', 0, '.', 0, '0', 0, '0', 0, /* Version number */ +}; + + +#define NUM_INTERFACES 2 + +uint32_t bDeviceState = UNCONNECTED; /* USB device status */ + +void +usb_cb_device_reset (void) +{ + /* Set DEVICE as not configured */ + usb_lld_set_configuration (0); + + /* Current Feature initialization */ + usb_lld_set_feature (vcom_configuration_desc[7]); + + usb_lld_reset (); + + /* Initialize Endpoint 0 */ + usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64); +} + + +void +usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value, + uint16_t index, uint16_t len) +{ + (void)req; + (void)req_no; + (void)value; + (void)index; + (void)len; +} + +struct line_coding +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +}; + +static struct line_coding line_coding = { + 115200, /* baud rate: 115200 */ + 0x00, /* stop bits: 1 */ + 0x00, /* parity: none */ + 0x08 /* bits: 8 */ +}; + +uint8_t connected; + +static int +vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value) +{ + if (USB_SETUP_GET (req)) + { + if (req_no == USB_CDC_REQ_GET_LINE_CODING) + { + usb_lld_set_data_to_send (&line_coding, sizeof(line_coding)); + return USB_SUCCESS; + } + } + else /* USB_SETUP_SET (req) */ + { + if (req_no == USB_CDC_REQ_SET_LINE_CODING) + { + usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding)); + return USB_SUCCESS; + } + else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) + { + uint8_t connected_saved = connected; + + if (value != 0) + { + if (connected == 0) + /* It's Open call */ + connected++; + } + else + { + if (connected) + /* Close call */ + connected = 0; + } + + chopstx_mutex_lock (&usb_mtx); + if (connected != connected_saved) + chopstx_cond_signal (&cnd_usb_connection); + chopstx_mutex_unlock (&usb_mtx); + + return USB_SUCCESS; + } + } + + return USB_UNSUPPORT; +} + +int +usb_cb_setup (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len) +{ + uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); + + (void)len; + if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + if (index == 0) + return vcom_port_data_setup (req, req_no, value); + + return USB_UNSUPPORT; +} + +int +usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value) +{ + (void)index; + if (desc_type == DEVICE_DESCRIPTOR) + { + usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc)); + return USB_SUCCESS; + } + else if (desc_type == CONFIG_DESCRIPTOR) + { + usb_lld_set_data_to_send (vcom_configuration_desc, + sizeof (vcom_configuration_desc)); + return USB_SUCCESS; + } + else if (desc_type == STRING_DESCRIPTOR) + { + uint8_t desc_index = value & 0xff; + const uint8_t *str; + int size; + + switch (desc_index) + { + case 0: + str = vcom_string0; + size = sizeof (vcom_string0); + break; + case 1: + str = vcom_string1; + size = sizeof (vcom_string1); + break; + case 2: + str = vcom_string2; + size = sizeof (vcom_string2); + break; + case 3: + str = vcom_string3; + size = sizeof (vcom_string3); + break; + default: + return USB_UNSUPPORT; + } + + usb_lld_set_data_to_send (str, size); + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static void +vcom_setup_endpoints_for_interface (uint16_t interface, int stop) +{ + if (interface == 0) + { + if (!stop) + usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0); + else + usb_lld_stall_tx (ENDP2); + } + else if (interface == 1) + { + if (!stop) + { + usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0); + usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64); + } + else + { + usb_lld_stall_tx (ENDP1); + usb_lld_stall_rx (ENDP3); + } + } +} + +int usb_cb_handle_event (uint8_t event_type, uint16_t value) +{ + int i; + uint8_t current_conf; + + switch (event_type) + { + case USB_EVENT_ADDRESS: + bDeviceState = ADDRESSED; + return USB_SUCCESS; + case USB_EVENT_CONFIG: + current_conf = usb_lld_current_configuration (); + if (current_conf == 0) + { + if (value != 1) + return USB_UNSUPPORT; + + usb_lld_set_configuration (1); + for (i = 0; i < NUM_INTERFACES; i++) + vcom_setup_endpoints_for_interface (i, 0); + bDeviceState = CONFIGURED; + } + else if (current_conf != value) + { + if (value != 0) + return USB_UNSUPPORT; + + usb_lld_set_configuration (0); + for (i = 0; i < NUM_INTERFACES; i++) + vcom_setup_endpoints_for_interface (i, 1); + bDeviceState = ADDRESSED; + } + /* Do nothing when current_conf == value */ + return USB_SUCCESS; + + return USB_SUCCESS; + default: + break; + } + + return USB_UNSUPPORT; +} + + +int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt) +{ + static uint8_t zero = 0; + + if (interface >= NUM_INTERFACES) + return USB_UNSUPPORT; + + switch (cmd) + { + case USB_SET_INTERFACE: + if (alt != 0) + return USB_UNSUPPORT; + else + { + vcom_setup_endpoints_for_interface (interface, 0); + return USB_SUCCESS; + } + + case USB_GET_INTERFACE: + usb_lld_set_data_to_send (&zero, 1); + return USB_SUCCESS; + + default: + case USB_QUERY_INTERFACE: + return USB_SUCCESS; + } +} + +void +EP1_IN_Callback (void) +{ + chopstx_mutex_lock (&usb_mtx); + chopstx_cond_signal (&cnd_usb_buffer_ready); + chopstx_mutex_unlock (&usb_mtx); +} + +void +EP2_IN_Callback (void) +{ +} + +void +EP3_OUT_Callback (void) +{ + usb_lld_rx_enable (ENDP3); +} diff --git a/example-cdc/usb_lld.h b/example-cdc/usb_lld.h new file mode 100644 index 0000000..b98d267 --- /dev/null +++ b/example-cdc/usb_lld.h @@ -0,0 +1,142 @@ +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 + +#define STANDARD_ENDPOINT_DESC_SIZE 0x09 + +/* endpoints enumeration */ +#define ENDP0 ((uint8_t)0) +#define ENDP1 ((uint8_t)1) +#define ENDP2 ((uint8_t)2) +#define ENDP3 ((uint8_t)3) +#define ENDP4 ((uint8_t)4) +#define ENDP5 ((uint8_t)5) +#define ENDP6 ((uint8_t)6) +#define ENDP7 ((uint8_t)7) + +/* EP_TYPE[1:0] EndPoint TYPE */ +#define EP_BULK (0x0000) /* EndPoint BULK */ +#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ +#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ +#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ + +enum RECIPIENT_TYPE +{ + DEVICE_RECIPIENT, /* Recipient device */ + INTERFACE_RECIPIENT, /* Recipient interface */ + ENDPOINT_RECIPIENT, /* Recipient endpoint */ + OTHER_RECIPIENT +}; + +enum DESCRIPTOR_TYPE +{ + DEVICE_DESCRIPTOR = 1, + CONFIG_DESCRIPTOR, + STRING_DESCRIPTOR, + INTERFACE_DESCRIPTOR, + ENDPOINT_DESCRIPTOR +}; + +#define REQUEST_DIR 0x80 /* Mask to get request dir */ +#define REQUEST_TYPE 0x60 /* Mask to get request type */ +#define STANDARD_REQUEST 0x00 /* Standard request */ +#define CLASS_REQUEST 0x20 /* Class request */ +#define VENDOR_REQUEST 0x40 /* Vendor request */ +#define RECIPIENT 0x1F /* Mask to get recipient */ + +#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0) +#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0) + +enum +{ + USB_UNSUPPORT = 0, + USB_SUCCESS = 1, +}; + +void usb_cb_device_reset (void); +void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, + uint16_t value, uint16_t index, uint16_t len); +int usb_cb_setup (uint8_t req, uint8_t req_no, uint16_t value, + uint16_t index, uint16_t len); +int usb_cb_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value); +int usb_cb_handle_event (uint8_t event_type, uint16_t value); +int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t value); + +enum { + USB_EVENT_ADDRESS, + USB_EVENT_CONFIG, + USB_EVENT_SUSPEND, + USB_EVENT_WAKEUP, + USB_EVENT_STALL, +}; + +enum { + USB_SET_INTERFACE, + USB_GET_INTERFACE, + USB_QUERY_INTERFACE, +}; + +enum DEVICE_STATE +{ + UNCONNECTED, + ATTACHED, + POWERED, + SUSPENDED, + ADDRESSED, + CONFIGURED +}; + +extern uint32_t bDeviceState; +extern const uint8_t usb_initial_feature; + +#define STM32_USB_IRQ_PRIORITY 11 + +extern void usb_lld_init (uint8_t feature); + +extern void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n); + +extern void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n); + +extern void usb_lld_stall_tx (int ep_num); + +extern void usb_lld_stall_rx (int ep_num); + +extern int usb_lld_tx_data_len (int ep_num); + +extern void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len); + +extern void usb_lld_tx_enable (int ep_num, size_t len); + +extern void usb_lld_write (uint8_t ep_num, const void *buf, size_t len); + +extern void usb_lld_rx_enable (int ep_num); + +extern int usb_lld_rx_data_len (int ep_num); + +extern void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len); + +extern void usb_lld_reset (void); + +extern void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind, + int ep_rx_addr, int ep_tx_addr, + int ep_rx_memory_size); + +extern void usb_lld_set_configuration (uint8_t config); + +extern uint8_t usb_lld_current_configuration (void); + +extern void usb_lld_set_feature (uint8_t feature); + +extern void usb_lld_set_data_to_send (const void *p, size_t len); + +extern inline void usb_lld_set_data_to_recv (void *p, size_t len) +{ + usb_lld_set_data_to_send ((const void *)p, len); +} + +extern void usb_lld_prepare_shutdown (void); +extern void usb_lld_shutdown (void); + +extern void usb_interrupt_handler (void); diff --git a/example-cdc/usb_stm32f103.c b/example-cdc/usb_stm32f103.c new file mode 100644 index 0000000..887d69f --- /dev/null +++ b/example-cdc/usb_stm32f103.c @@ -0,0 +1,1214 @@ +#ifdef FREE_STANDING +#include <stdint.h> +#include <stdlib.h> +#define TRUE 1 +#define FALSE 0 + +#define NULL 0 + +#define __IO volatile +#else +#include "ch.h" +#include "hal.h" +#endif +#include "sys.h" +#include "usb_lld.h" + +#define USB_MAX_PACKET_SIZE 64 /* For FS device */ + +enum STANDARD_REQUESTS +{ + GET_STATUS = 0, + CLEAR_FEATURE, + RESERVED1, + SET_FEATURE, + RESERVED2, + SET_ADDRESS, + GET_DESCRIPTOR, + SET_DESCRIPTOR, + GET_CONFIGURATION, + SET_CONFIGURATION, + GET_INTERFACE, + SET_INTERFACE, + SYNCH_FRAME, + TOTAL_REQUEST /* Total number of Standard request */ +}; + +/* The state machine states of a control pipe */ +enum CONTROL_STATE +{ + WAIT_SETUP, + SETTING_UP, + IN_DATA, + OUT_DATA, + LAST_IN_DATA, + WAIT_STATUS_IN, + WAIT_STATUS_OUT, + STALLED, + PAUSE +}; + +enum FEATURE_SELECTOR +{ + ENDPOINT_STALL, + DEVICE_REMOTE_WAKEUP +}; + +struct DATA_INFO +{ + uint16_t len; + uint16_t offset; + uint8_t *addr; + uint8_t require_zlp; +}; + +struct CONTROL_INFO +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +struct DEVICE_INFO +{ + uint8_t current_configuration; + uint8_t current_feature; + uint8_t state; +}; + +static struct CONTROL_INFO control_info; +static struct DEVICE_INFO device_info; +static struct DATA_INFO data_info; + +static struct CONTROL_INFO *const ctrl_p = &control_info; +static struct DEVICE_INFO *const dev_p = &device_info; +static struct DATA_INFO *const data_p = &data_info; + +#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */ +#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */ + +/* Control register */ +#define CNTR ((__IO uint16_t *)(REG_BASE + 0x40)) +/* Interrupt status register */ +#define ISTR ((__IO uint16_t *)(REG_BASE + 0x44)) +/* Frame number register */ +#define FNR ((__IO uint16_t *)(REG_BASE + 0x48)) +/* Device address register */ +#define DADDR ((__IO uint16_t *)(REG_BASE + 0x4C)) +/* Buffer Table address register */ +#define BTABLE ((__IO uint16_t *)(REG_BASE + 0x50)) + +#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ +#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ +#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ +#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ +#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ +#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ +#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ +#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ + +#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ +#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ + +#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ +#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ +#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ +#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ +#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ +#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ +#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ +#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ + +#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ +#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ +#define CNTR_ERRM (0x2000) /* ERRor Mask */ +#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ +#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ +#define CNTR_RESETM (0x0400) /* RESET Mask */ +#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ +#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ + +#define CNTR_RESUME (0x0010) /* RESUME request */ +#define CNTR_FSUSP (0x0008) /* Force SUSPend */ +#define CNTR_LPMODE (0x0004) /* Low-power MODE */ +#define CNTR_PDWN (0x0002) /* Power DoWN */ +#define CNTR_FRES (0x0001) /* Force USB RESet */ + +#define DADDR_EF (0x80) +#define DADDR_ADD (0x7F) + +#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ +#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ +#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ +#define EP_SETUP (0x0800) /* EndPoint SETUP */ +#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ +#define EP_KIND (0x0100) /* EndPoint KIND */ +#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ +#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ +#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ +#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ + +#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) + +/* STAT_TX[1:0] STATus for TX transfer */ +#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ +#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ +#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ +#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ +#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ +#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ + +/* STAT_RX[1:0] STATus for RX transfer */ +#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ +#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ +#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ +#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ +#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ + +static void usb_handle_transfer (void); + +static void st103_set_btable (void) +{ + *BTABLE = 0; +} + +static uint16_t st103_get_istr (void) +{ + return *ISTR; +} + +static void st103_set_istr (uint16_t istr) +{ + *ISTR = istr; +} + +static void st103_set_cntr (uint16_t cntr) +{ + *CNTR = cntr; +} + +static void st103_set_daddr (uint16_t daddr) +{ + *DADDR = daddr | DADDR_EF; +} + +static void st103_set_epreg (uint8_t ep_num, uint16_t value) +{ + uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4); + + *reg_p = value; +} + +static uint16_t st103_get_epreg (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4); + + return *reg_p; +} + +static void st103_set_tx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2); + + *reg_p = addr; +} + +static uint16_t st103_get_tx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2); + + return *reg_p; +} + + +static void st103_set_tx_count (uint8_t ep_num, uint16_t size) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2); + + *reg_p = size; +} + +static uint16_t st103_get_tx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2); + + return *reg_p & 0x03ff; +} + + +static void st103_set_rx_addr (uint8_t ep_num, uint16_t addr) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2); + + *reg_p = addr; +} + +static uint16_t st103_get_rx_addr (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2); + + return *reg_p; +} + + +static void st103_set_rx_buf_size (uint8_t ep_num, uint16_t size) +{ /* Assume size is even */ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2); + uint16_t value; + + if (size <= 62) + value = (size & 0x3e) << 9; + else + value = 0x8000 | (((size >> 5) - 1) << 10); + + *reg_p = value; +} + +static uint16_t st103_get_rx_count (uint8_t ep_num) +{ + uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2); + + return *reg_p & 0x03ff; +} + + +static void st103_ep_clear_ctr_rx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_RX & EPREG_MASK; + + st103_set_epreg (ep_num, value); +} + +static void st103_ep_clear_ctr_tx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_TX & EPREG_MASK; + + st103_set_epreg (ep_num, value); +} + +static void st103_ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx, + uint16_t st_tx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT); + value ^= (EPRX_DTOG1 & st_rx); + value ^= (EPRX_DTOG2 & st_rx); + value ^= (EPTX_DTOG1 & st_tx); + value ^= (EPTX_DTOG2 & st_tx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static void st103_ep_set_rx_status (uint8_t ep_num, uint16_t st_rx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPRX_STAT); + value ^= (EPRX_DTOG1 & st_rx); + value ^= (EPRX_DTOG2 & st_rx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static uint16_t st103_ep_get_rx_status (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + return value & EPRX_STAT; +} + +static void st103_ep_set_tx_status (uint8_t ep_num, uint16_t st_tx) +{ + uint16_t value = st103_get_epreg (ep_num); + + value &= (EPREG_MASK|EPTX_STAT); + value ^= (EPTX_DTOG1 & st_tx); + value ^= (EPTX_DTOG2 & st_tx); + value |= EP_CTR_RX | EP_CTR_TX; + st103_set_epreg (ep_num, value); +} + +static uint16_t st103_ep_get_tx_status (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + return value & EPTX_STAT; +} + +static void st103_ep_clear_dtog_rx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + if ((value & EP_DTOG_RX)) + { + value &= EPREG_MASK; + value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX; + st103_set_epreg (ep_num, value); + } +} + +static void st103_ep_clear_dtog_tx (uint8_t ep_num) +{ + uint16_t value = st103_get_epreg (ep_num); + + if ((value & EP_DTOG_TX)) + { + value &= EPREG_MASK; + value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX; + st103_set_epreg (ep_num, value); + } +} + +void usb_lld_init (uint8_t feature) +{ + usb_lld_sys_init (); + + dev_p->state = IN_DATA; + + usb_lld_set_configuration (0); + usb_lld_set_feature (feature); + + /* Reset USB */ + st103_set_cntr (CNTR_FRES); + st103_set_cntr (0); + + /* Clear Interrupt Status Register, and enable interrupt for USB */ + st103_set_istr (0); + st103_set_cntr (CNTR_CTRM | CNTR_RESETM); +} + +void usb_lld_prepare_shutdown (void) +{ + st103_set_istr (0); + st103_set_cntr (0); +} + +void usb_lld_shutdown (void) +{ + st103_set_cntr (CNTR_PDWN); + usb_lld_sys_shutdown (); +} + +void +usb_interrupt_handler (void) +{ + uint16_t istr_value = st103_get_istr (); + + if (istr_value & ISTR_CTR) + usb_handle_transfer (); + + if (istr_value & ISTR_RESET) + { + st103_set_istr (CLR_RESET); + usb_cb_device_reset (); + } + + if (istr_value & ISTR_DOVR) + st103_set_istr (CLR_DOVR); + + if (istr_value & ISTR_ERR) + st103_set_istr (CLR_ERR); +} + +static void handle_datastage_out (void) +{ + if (data_p->addr && data_p->len) + { + uint8_t *buf; + uint32_t len = st103_get_rx_count (ENDP0); + + if (len > data_p->len) + len = data_p->len; + + buf = data_p->addr + data_p->offset; + usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len); + data_p->len -= len; + data_p->offset += len; + } + + if (data_p->len == 0) + { + dev_p->state = WAIT_STATUS_IN; + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID); + } + else + { + dev_p->state = OUT_DATA; + st103_ep_set_rx_status (ENDP0, EP_RX_VALID); + } +} + +static void handle_datastage_in (void) +{ + uint32_t len = USB_MAX_PACKET_SIZE;; + const uint8_t *buf; + + if ((data_p->len == 0) && (dev_p->state == LAST_IN_DATA)) + { + if (data_p->require_zlp == TRUE) + { + data_p->require_zlp = FALSE; + + /* No more data to send. Send empty packet */ + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID); + } + else + { + /* No more data to send, proceed to receive OUT acknowledge.*/ + dev_p->state = WAIT_STATUS_OUT; + st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL); + } + + return; + } + + dev_p->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA; + + if (len > data_p->len) + len = data_p->len; + + buf = (const uint8_t *)data_p->addr + data_p->offset; + usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len); + data_p->len -= len; + data_p->offset += len; + st103_set_tx_count (ENDP0, len); + st103_ep_set_tx_status (ENDP0, EP_TX_VALID); +} + +typedef int (*HANDLER) (uint8_t req, + uint16_t value, uint16_t index, uint16_t length); + +static int std_none (uint8_t req, + uint16_t value, uint16_t index, uint16_t length) +{ + (void)req; (void)value; (void)index; (void)length; + return USB_UNSUPPORT; +} + +static int std_get_status (uint8_t req, + uint16_t value, uint16_t index, uint16_t length) +{ + static uint16_t status_info; + uint8_t rcp = req & RECIPIENT; + + status_info = 0; /* Reset Status Information */ + data_p->addr = (uint8_t *)&status_info; + + if (value != 0 || length != 2 || (index >> 8) != 0 + || (req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (index == 0) + { + /* Get Device Status */ + uint8_t feature = dev_p->current_feature; + + /* Remote Wakeup enabled */ + if ((feature & (1 << 5))) + status_info |= 2; + else + status_info &= ~2; + + /* Bus-powered */ + if ((feature & (1 << 6))) + status_info |= 1; + else /* Self-powered */ + status_info &= ~1; + + data_p->len = 2; + return USB_SUCCESS; + } + } + else if (rcp == INTERFACE_RECIPIENT) + { + int r; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + r = usb_cb_interface (USB_QUERY_INTERFACE, index, 0); + if (r != USB_SUCCESS) + return USB_UNSUPPORT; + + data_p->len = 2; + return USB_SUCCESS; + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint16_t status; + + if ((index & 0x70) != 0 || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + { + status = st103_ep_get_tx_status (endpoint); + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + else if (status == EP_TX_STALL) + status_info |= 1; /* IN Endpoint stalled */ + } + else + { + status = st103_ep_get_rx_status (endpoint); + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + else if (status == EP_RX_STALL) + status_info |= 1; /* OUT Endpoint stalled */ + } + + data_p->len = 2; + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_clear_feature (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length != 0 || index != 0) + return USB_UNSUPPORT; + + if (value == DEVICE_REMOTE_WAKEUP) + { + dev_p->current_feature &= ~(1 << 5); + return USB_SUCCESS; + } + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint16_t status; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + if (length != 0 || (index >> 8) != 0 || value != ENDPOINT_STALL + || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + status = st103_ep_get_tx_status (endpoint); + else + status = st103_ep_get_rx_status (endpoint); + + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + + if (index & 0x80) /* IN endpoint */ + st103_ep_clear_dtog_tx (endpoint); + else /* OUT endpoint */ + st103_ep_clear_dtog_rx (endpoint); + + // event?? + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_feature (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length != 0 || index != 0) + return USB_UNSUPPORT; + + if (value == DEVICE_REMOTE_WAKEUP) + { + dev_p->current_feature |= 1 << 5; + // event?? + return USB_SUCCESS; + } + } + else if (rcp == ENDPOINT_RECIPIENT) + { + uint8_t endpoint = (index & 0x0f); + uint32_t status; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + if (length != 0 || (index >> 8) != 0 || value != 0 || endpoint == ENDP0) + return USB_UNSUPPORT; + + if ((index & 0x80)) + status = st103_ep_get_tx_status (endpoint); + else + status = st103_ep_get_rx_status (endpoint); + + if (status == 0) /* Disabled */ + return USB_UNSUPPORT; + + if (index & 0x80) + /* IN endpoint */ + st103_ep_set_tx_status (endpoint, EP_TX_STALL); + else + /* OUT endpoint */ + st103_ep_set_rx_status (endpoint, EP_RX_STALL); + + // event?? + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_address (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT) + { + if (length == 0 && value <= 127 && index == 0 + && dev_p->current_configuration == 0) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_get_descriptor (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + (void)length; + if (rcp == DEVICE_RECIPIENT) + return usb_cb_get_descriptor ((value >> 8), index, value); + + return USB_UNSUPPORT; +} + +static int std_get_configuration (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + (void)value; (void)index; (void)length; + if (rcp == DEVICE_RECIPIENT) + { + data_p->addr = &dev_p->current_configuration; + data_p->len = 1; + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_set_configuration (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0) + { + int r; + + r = usb_cb_handle_event (USB_EVENT_CONFIG, value); + if (r == USB_SUCCESS) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +static int std_get_interface (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 0) + return USB_UNSUPPORT; + + if (rcp == INTERFACE_RECIPIENT) + { + if (value != 0 || (index >> 8) != 0 || length != 1) + return USB_UNSUPPORT; + + if (dev_p->current_configuration == 0) + return USB_UNSUPPORT; + + return usb_cb_interface (USB_GET_INTERFACE, index, 0); + } + + return USB_UNSUPPORT; +} + +static int std_set_interface (uint8_t req, uint16_t value, + uint16_t index, uint16_t length) +{ + uint8_t rcp = req & RECIPIENT; + + if ((req & REQUEST_DIR) == 1) + return USB_UNSUPPORT; + + if (rcp == INTERFACE_RECIPIENT) + { + int r; + + if (length != 0 || (index >> 8) != 0 || (value >> 8) != 0) + return USB_UNSUPPORT; + + if (dev_p->current_configuration != 0) + return USB_UNSUPPORT; + + r = usb_cb_interface (USB_SET_INTERFACE, index, value); + if (r == USB_SUCCESS) + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + + +static void handle_setup0 (void) +{ + const uint16_t *pw; + uint16_t w; + uint8_t req; + int r = USB_UNSUPPORT; + HANDLER handler; + + pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2)); + w = *pw++; + + ctrl_p->bmRequestType = w & 0xff; + ctrl_p->bRequest = req = w >> 8; + pw++; + ctrl_p->wValue = *pw++; + pw++; + ctrl_p->wIndex = *pw++; + pw++; + ctrl_p->wLength = *pw; + + data_p->addr = NULL; + data_p->len = 0; + data_p->offset = 0; + + if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST) + { + if (req < TOTAL_REQUEST) + { + switch (req) + { + case 0: handler = std_get_status; break; + case 1: handler = std_clear_feature; break; + case 3: handler = std_set_feature; break; + case 5: handler = std_set_address; break; + case 6: handler = std_get_descriptor; break; + case 8: handler = std_get_configuration; break; + case 9: handler = std_set_configuration; break; + case 10: handler = std_get_interface; break; + case 11: handler = std_set_interface; break; + default: handler = std_none; break; + } + + r = (*handler) (ctrl_p->bmRequestType, + ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength); + } + } + else + r = usb_cb_setup (ctrl_p->bmRequestType, req, + ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength); + + if (r != USB_SUCCESS) + dev_p->state = STALLED; + else + { + if (USB_SETUP_GET (ctrl_p->bmRequestType)) + { + uint32_t len = ctrl_p->wLength; + + /* Restrict the data length to be the one host asks for */ + if (data_p->len > len) + data_p->len = len; + + if ((data_p->len % USB_MAX_PACKET_SIZE) == 0) + data_p->require_zlp = TRUE; + else + data_p->require_zlp = FALSE; + + dev_p->state = IN_DATA; + handle_datastage_in (); + } + else if (ctrl_p->wLength == 0) + { + dev_p->state = WAIT_STATUS_IN; + st103_set_tx_count (ENDP0, 0); + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID); + } + else + { + dev_p->state = OUT_DATA; + st103_ep_set_rx_status (ENDP0, EP_RX_VALID); + } + } +} + +static void handle_in0 (void) +{ + if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA) + handle_datastage_in (); + else if (dev_p->state == WAIT_STATUS_IN) + { + if ((ctrl_p->bRequest == SET_ADDRESS) && + ((ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT)) + == (STANDARD_REQUEST | DEVICE_RECIPIENT))) + { + st103_set_daddr (ctrl_p->wValue); + usb_cb_handle_event (USB_EVENT_ADDRESS, ctrl_p->wValue); + } + else + usb_cb_ctrl_write_finish (ctrl_p->bmRequestType, + ctrl_p->bRequest, ctrl_p->wValue, + ctrl_p->wIndex, ctrl_p->wLength); + + dev_p->state = STALLED; + } + else + dev_p->state = STALLED; +} + +static void handle_out0 (void) +{ + if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA) + /* host aborts the transfer before finish */ + dev_p->state = STALLED; + else if (dev_p->state == OUT_DATA) + handle_datastage_out (); + else if (dev_p->state == WAIT_STATUS_OUT) + dev_p->state = STALLED; + /* Unexpect state, STALL the endpoint */ + else + dev_p->state = STALLED; +} + +static void nop_proc (void) +{ +} + +#define WEAK __attribute__ ((weak, alias ("nop_proc"))) +void WEAK EP1_IN_Callback (void); +void WEAK EP2_IN_Callback (void); +void WEAK EP3_IN_Callback (void); +void WEAK EP4_IN_Callback (void); +void WEAK EP5_IN_Callback (void); +void WEAK EP6_IN_Callback (void); +void WEAK EP7_IN_Callback (void); + +void WEAK EP1_OUT_Callback (void); +void WEAK EP2_OUT_Callback (void); +void WEAK EP3_OUT_Callback (void); +void WEAK EP4_OUT_Callback (void); +void WEAK EP5_OUT_Callback (void); +void WEAK EP6_OUT_Callback (void); +void WEAK EP7_OUT_Callback (void); + +static void +usb_handle_transfer (void) +{ + uint16_t ep_value = 0; + uint16_t istr_value; + uint8_t ep_index; + + while (((istr_value = st103_get_istr ()) & ISTR_CTR) != 0) + { + ep_index = (istr_value & ISTR_EP_ID); + if (ep_index == 0) + { + if ((istr_value & ISTR_DIR) == 0) + { /* DIR = 0 */ + /* DIR = 0 => IN int */ + /* DIR = 0 implies that (EP_CTR_TX = 1) always */ + + st103_ep_clear_ctr_tx (ENDP0); + handle_in0 (); + } + else + { /* DIR = 1 */ + /* DIR = 1 & CTR_RX => SETUP or OUT int */ + /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ + + ep_value = st103_get_epreg (ENDP0); + if ((ep_value & EP_SETUP) != 0) + { + st103_ep_clear_ctr_rx (ENDP0); + handle_setup0 (); + } + else if ((ep_value & EP_CTR_RX) != 0) + { + st103_ep_clear_ctr_rx (ENDP0); + handle_out0 (); + } + } + + if (dev_p->state == STALLED) + st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL); + } + else + { + /* Decode and service non control endpoints interrupt */ + /* process related endpoint register */ + ep_value = st103_get_epreg (ep_index); + + if ((ep_value & EP_CTR_RX) != 0) + { + st103_ep_clear_ctr_rx (ep_index); + switch ((ep_index - 1)) + { + case 0: EP1_OUT_Callback (); break; + case 1: EP2_OUT_Callback (); break; + case 2: EP3_OUT_Callback (); break; + case 3: EP4_OUT_Callback (); break; + case 4: EP5_OUT_Callback (); break; + case 5: EP6_OUT_Callback (); break; + case 6: EP7_OUT_Callback (); break; + } + } + + if ((ep_value & EP_CTR_TX) != 0) + { + st103_ep_clear_ctr_tx (ep_index); + switch ((ep_index - 1)) + { + case 0: EP1_IN_Callback (); break; + case 1: EP2_IN_Callback (); break; + case 2: EP3_IN_Callback (); break; + case 3: EP4_IN_Callback (); break; + case 4: EP5_IN_Callback (); break; + case 5: EP6_IN_Callback (); break; + case 6: EP7_IN_Callback (); break; + } + } + } + } +} + +void usb_lld_reset (void) +{ + st103_set_btable (); + st103_set_daddr (0); +} + +void usb_lld_txcpy (const void *src, + int ep_num, int offset, size_t len) +{ + usb_lld_to_pmabuf (src, st103_get_tx_addr (ep_num) + offset, len); +} + +void usb_lld_write (uint8_t ep_num, const void *buf, size_t len) +{ + usb_lld_to_pmabuf (buf, st103_get_tx_addr (ep_num), len); + st103_set_tx_count (ep_num, len); + st103_ep_set_tx_status (ep_num, EP_TX_VALID); +} + +void usb_lld_rxcpy (uint8_t *dst, + int ep_num, int offset, size_t len) +{ + usb_lld_from_pmabuf (dst, st103_get_rx_addr (ep_num) + offset, len); +} + +void usb_lld_tx_enable (int ep_num, size_t len) +{ + st103_set_tx_count (ep_num, len); + st103_ep_set_tx_status (ep_num, EP_TX_VALID); +} + +int usb_lld_tx_data_len (int ep_num) +{ + return st103_get_tx_count (ep_num); +} + +int usb_lld_rx_data_len (int ep_num) +{ + return st103_get_rx_count (ep_num); +} + +void usb_lld_stall_tx (int ep_num) +{ + st103_ep_set_tx_status (ep_num, EP_TX_STALL); +} + +void usb_lld_stall_rx (int ep_num) +{ + st103_ep_set_rx_status (ep_num, EP_RX_STALL); +} + +void usb_lld_rx_enable (int ep_num) +{ + st103_ep_set_rx_status (ep_num, EP_RX_VALID); +} + +void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind, + int ep_rx_addr, int ep_tx_addr, + int ep_rx_buf_size) +{ + uint16_t epreg_value = st103_get_epreg (ep_num); + uint16_t ep_rxtx_status = 0; /* Both disabled */ + + /* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */ + /* Set: Write: EP_T_FIELD, EP_KIND, EPADDR_FIELD */ + /* Set: Toggle: EPRX_STAT, EPTX_STAT */ + epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX); +#if USB_KEEP_CORRECT_TRANSFER_FLAGS + /* Keep: Write 1: EP_CTR_RX, EP_CTR_TX */ + epreg_value |= (EP_CTR_RX|EP_CTR_TX); +#else + /* Clear: Write 0: EP_CTR_RX, EP_CTR_TX */ +#endif + epreg_value |= ep_type; + epreg_value |= ep_kind; + epreg_value |= ep_num; + + if (ep_rx_addr) + { + ep_rxtx_status |= EP_RX_VALID; + st103_set_rx_addr (ep_num, ep_rx_addr); + st103_set_rx_buf_size (ep_num, ep_rx_buf_size); + } + + if (ep_tx_addr) + { + ep_rxtx_status |= EP_TX_NAK; + st103_set_tx_addr (ep_num, ep_tx_addr); + } + + epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status); + epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status); + epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status); + epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status); + + st103_set_epreg (ep_num, epreg_value); +} + +void usb_lld_set_configuration (uint8_t config) +{ + dev_p->current_configuration = config; +} + +uint8_t usb_lld_current_configuration (void) +{ + return dev_p->current_configuration; +} + +void usb_lld_set_feature (uint8_t feature) +{ + dev_p->current_feature = feature; +} + +void usb_lld_set_data_to_send (const void *p, size_t len) +{ + data_p->addr = (uint8_t *)p; + data_p->len = len; +} + +void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n) +{ + const uint8_t *s = (const uint8_t *)src; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2); + w = *p; + w = (w & 0xff) | (*s++) << 8; + *p = w; + p += 2; + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr * 2); + + while (n >= 2) + { + w = *s++; + w |= (*s++) << 8; + *p = w; + p += 2; + n -= 2; + } + + if (n > 0) + { + w = *s; + *p = w; + } +} + +void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n) +{ + uint8_t *d = (uint8_t *)dst; + uint16_t *p; + uint16_t w; + + if (n == 0) + return; + + if ((addr & 1)) + { + p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2); + w = *p; + *d++ = (w >> 8); + p += 2; + n--; + } + else + p = (uint16_t *)(PMA_ADDR + addr * 2); + + while (n >= 2) + { + w = *p; + *d++ = (w & 0xff); + *d++ = (w >> 8); + p += 2; + n -= 2; + } + + if (n > 0) + { + w = *p; + *d = (w & 0xff); + } +} |