Browse Source

WIP: usb for f072.

across
flabbergast 2 years ago
parent
commit
4c83b15183
  1. 13
      suf072/Makefile
  2. 82
      suf072/README.md
  3. 44
      suf072/bat-072.fs
  4. 5
      suf072/dump.fs
  5. 5
      suf072/ex/big.fs
  6. 15
      suf072/ex/long.fs
  7. 41
      suf072/f-common.fs
  8. 31
      suf072/f-maplemini.fs
  9. 91
      suf072/hal-stm32f0.fs
  10. 60
      suf072/hal-stm32f1.fs
  11. 332
      suf072/usb.fs
  12. 313
      suf072/usb.fs.orig

13
suf072/Makefile

@ -0,0 +1,13 @@
# build the .bin file corresponding to each .hex file
# the list is constructed from all the "f-*.fs" source files
SRCS = $(wildcard f-*.fs)
BINS = $(SRCS:f-%.fs=usb-%.bin)
all: $(BINS)
%.bin: %.hex
srec_cat -Output $@ -Binary $< -Intel
clean:
rm -f $(BINS)

82
suf072/README.md

@ -0,0 +1,82 @@
Serial USB driver for Forth - see <http://jeelabs.org/2016/06/standalone-usb-firmware/>
### Boards
* **generic** - many boards, see [eBay](http://www.ebay.com/itm/311156408508) - PA12 high enables USB (sort of)
* **hotcbo** - HotMCU Core Board 1xx see [Haoyu](http://www.hotmcu.com/hystm32f1xxcore144-coredev-board-p-2.html?cPath=1_20) - PF10 low enables USB
* **hytiny** - Hy-TinySTM103T, see [Haoyu](http://www.hotmcu.com/stm32f103tb-arm-cortex-m3-development-board-p-222.html?cPath=1_20) - PA0 low enables USB
* **maplemini** - LeafLabs Maple Mini etc, see [eBay](http://www.ebay.com/itm/400569863658) - PB9 pulsed high enables USB
* **olimexino** - LeafLabs Maple and similar, see [Olimex](https://www.olimex.com/Products/Duino/STM32/OLIMEXINO-STM32/) - PC12 low enables USB
* **olip103** - Olimex STM32 P103 board [Olimex](https://www.olimex.com/Products/ARM/ST/STM32-P103/) - PC11 low enables USB
* **port103z** - Port103Z, see [WaveShare](http://www.waveshare.com/wiki/Port103Z) -
PA3 low enables USB
> Note: `generic` and `hytiny` have now been combined into a single `common`
> image, which checks the board type at run time and adjusts the USB control
> pin accordingly.
The `.hex` and `.bin` files can be used to flash a board from scratch. These
include the
[g6u/board.fs](https://github.com/jeelabs/embello/blob/master/explore/1608-forth/g6u/board.fs)
and
[g6u/core.fs](https://github.com/jeelabs/embello/blob/master/explore/1608-forth/g6u/core.fs)
code, with drivers and libraries - i.e. _batteries included!_
To upload using [Folie](https://github.com/jeelabs/folie) and a
[SerPlus](http://jeelabs.org/article/1649f/), enter the following command:
!u path/to/usb-common.hex
Or, even simpler, you can upload directly from the last version on GitHub:
!u https://raw.githubusercontent.com/jeelabs/embello/master/explore/1608-forth/suf/usb-common.hex
Be sure to refer to the actual _raw_ file contents, not the GitHub page itself!
### Builds
The `f-*.fs` files are used to create these images. Here is an example
transcript of loading the `f-common.fs` file into Folie, while connected to an
F103-based Blue Pill:
```
$ folie
Folie v2.11
Select the serial port:
1: /dev/cu.Bluetooth-Incoming-Port
2: /dev/cu.usbmodem32212431
3: /dev/cu.usbmodem3430DC31
4: /dev/cu.usbmodemC92AED31
4
Enter '!help' for additional help, or ctrl-d to quit.
[connected to /dev/cu.usbmodemC92AED31]
!s f-common.fs
1> f-common.fs 3: Erase block at 00005000 from Flash
1> f-common.fs 4: Erase block at 00005400 from Flash
Erase block at 00005800 from Flash
[...]
Erase block at 0000B800 from Flash
Finished. Reset �Mecrisp-Stellaris RA 2.3.6 for STM32F103 by Matthias Koch
1> f-common.fs 11: Redefine init. ok.
1> f-common.fs 35: ( usb end: ) 000063D0 ok.
1> f-common.fs 36: Redefine eraseflash. ok.
5> board.fs 5: ( board start: ) 00006400 ok.
5> board.fs 36: Redefine init. ok.
5> board.fs 45: 64 KB <g6u> 32212433 ram/flash: 19108 27648 free ok.
18> core.fs 5: ( core start: ) 00009400 ok.
18> core.fs 14: 64 KB <g6u> 32212433 ram/flash: 16792 17408 free ok.
1> f-common.fs 41: hexdump
:100000008C030020EF4D0000074800000748000067
:1000100007480000074800000748000000000000F3
[...]
:10BBE0000000000000000000000000000000000055
:10BBF0000000000000000000000000000000000045
:00000001FF
ok.
```
As you can see, the hex dump is generated as last step in this process and can
be copied manually to the `usb-common.hex` file. Note that on the next reset,
the serial connection will be dropped and the board will start listening on its
USB interface. To prevent this, enter `$5000 eraseflashfrom` - this will remove
all the above code again.

44
suf072/bat-072.fs

@ -0,0 +1,44 @@
\ USB console for the bat board with F072
\ modelled after Jean-Claude Wippler's USB console for F103 boards
\ in embello: https://git.jeelabs.org/jcw/embello
$5000 eraseflashfrom \ this must be loaded on top of a *clean* Mecrisp image!
cr
compiletoflash
include hal-stm32f0.fs
include ../flib/any/ring.fs
include usb.fs
: led-on 1 15 lshift $48000018 bis! ;
: led-of 1 31 lshift $48000018 bis! ;
: do-usb
23 bit RCC-APB1ENR bis! \ USBEN (also done in usb-io, but need this for DPPU here
usb-clk
15 bit USB-BCDR hbic! \ disconnect USB
100000 0 do loop
15 bit USB-BCDR hbis! \ enable pullup on D+ line (DPPU)
usb-io \ switch to USB as console
;
: init ( -- )
init
\ with the 'spezial' mecrisp base, mecrisp's init doesn't run so...
%111 17 lshift RCC-AHBENR bis! \ enable GPIO ABC
48MHz-after-reset
\ 48MHz
$68280000 $48000000 ! \ PA15 LED output
;
include ../flib/mecrisp/hexdump-min.fs
( usb end: ) here hex.
cornerstone eraseflash
\ include ../g6u/board.fs
\ include ../g6u/core.fs
( enter "hexdump" for a full dump of flash memory... ) space

5
suf072/dump.fs

@ -0,0 +1,5 @@
\ include this to dump the loaded image as Intel hex code
compiletoram
include ../flib/mecrisp/hexdump.fs
hexdump

5
suf072/ex/big.fs

@ -0,0 +1,5 @@
\ test long input lines, i.e. more than one 64-byte USB packet
PA1 ioc! OMODE-PP PA1 io-mode! PA1 ios! 2 ms
1234567890-abcdefghijklmnopqrstuvwxyz+ABCDEFGHIJKLMNOPQRSTUVWXYZ=0987654321/zyxwvutsrqpomnlkjihgfedcba.ZYXWVUTSRQPOMNLKJIHGFEDCBA?1234567890?11223344556677889900

15
suf072/ex/long.fs

@ -0,0 +1,15 @@
\ test long input lines, i.e. more than one 64-byte USB packet
forgetram
: a ." abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" ;
a
: b ." abcdefghijabcdefghijabcdefghijabcdefghij"
." abcdefghijabcdefghijabcdefghijabcdefghij" ;
b
: c ." abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" ;
c
: d ." abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" ;
d
: e ." abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" ;
e

41
suf072/f-common.fs

@ -0,0 +1,41 @@
\ USB console for HyTiny-STM32F103TB and BluePill-STM32F103C8 boards
$5000 eraseflashfrom \ this must be loaded on top of a *clean* Mecrisp image!
cr
compiletoflash
include hal-stm32f1.fs
include ../flib/any/ring.fs
include usb.fs
: init ( -- )
$3D RCC-APB2ENR ! \ enable AFIO and GPIOA..D clocks
72MHz \ this is required for USB use
\ board-specific way to enable USB
flash-kb 128 = if
\ it looks like it's a HyTiny ...
%1111 $40010800 bic! \ PA0: output, push-pull, 2 MHz
%0010 $40010800 bis!
0 bit $4001080C bis! \ set PA0 high
100000 0 do loop
0 bit $4001080C bic! \ set PA0 low
else
\ nope, it must be a Blue Pill or similar ...
%1111 16 lshift $40010804 bic! \ PA12: output, push-pull, 2 MHz
%0010 16 lshift $40010804 bis! \ ... this affects CRH iso CRL
12 bit $4001080C bic! \ set PA12 low
100000 0 do loop
12 bit $4001080C bis! \ set PA12 high
then
usb-io \ switch to USB as console
;
( usb end: ) here hex.
cornerstone eraseflash
include ../g6u/board.fs
include ../g6u/core.fs
( enter "hexdump" for a full dump of flash memory... ) space

31
suf072/f-maplemini.fs

@ -0,0 +1,31 @@
\ USB console for Leaflabs Maple Mini and other similar boards
$5000 eraseflashfrom \ this must be loaded on top of a *clean* Mecrisp image!
cr
compiletoflash
include hal-stm32f1.fs
include ../flib/any/ring.fs
include usb.fs
: init ( -- )
$3D RCC-APB2ENR ! \ enable AFIO and GPIOA..D clocks
72MHz \ this is required for USB use
\ board-specific way to enable USB
%1111 4 lshift $40010C04 bic! \ PB9: output, push-pull, 2 MHz
%0010 4 lshift $40010C04 bis! \ ... this affects CRH iso CRL
9 bit $40010C0C bis! \ set PB9 high
100000 0 do loop
9 bit $40010C0C bic! \ set PB9 low
usb-io \ switch to USB as console
;
( usb end: ) here hex.
cornerstone eraseflash
include ../g6u/board.fs
include ../g6u/core.fs
hexdump

91
suf072/hal-stm32f0.fs

@ -0,0 +1,91 @@
\ base definitions for STM32F072 (STRIPPED-DOWN version for USB driver use!)
\ adapted from jcw's embello for STM32F103
\ adapted from mecrisp-stellaris 2.2.1a (GPL3)
: chipid ( -- u1 u2 u3 3 ) \ unique chip ID as N values on the stack
$1FFFF7AC @ $1FFFF7B0 @ $1FFFF7B4 @ 3 ;
: hwid ( -- u ) \ a "fairly unique" hardware ID as single 32-bit int
chipid 1 do xor loop ;
: flash-kb ( -- u ) \ return size of flash memory in KB
$1FFFF7CC h@ ;
: flash-pagesize ( addr - u ) \ return size of flash page at given address
drop 2048 ; \ f07x f09x ; f03x f04x have 1024
: bit ( u -- u ) \ turn a bit position into a single-bit mask
1 swap lshift 1-foldable ;
$40021000 constant RCC
RCC $00 + constant RCC-CR
RCC $04 + constant RCC-CFGR
RCC $14 + constant RCC-AHBENR
RCC $18 + constant RCC-APB2ENR
RCC $1C + constant RCC-APB1ENR
RCC $30 + constant RCC-CFGR3
RCC $34 + constant RCC-CR2
$40022000 constant FLASH
FLASH $0 + constant FLASH-ACR
$40006C00 constant CRS
CRS $00 + constant CRS-CR
CRS $04 + constant CRS-CFGR
\ : 48MHz ( -- ) \ set the main clock to 48MHz (HSI -> PLL)
\ 0 bit RCC-CR bis! \ switch on HSI
\ begin 1 bit RCC-CR bit@ until \ wait for HSIRDY
\ %11 RCC-CFGR bic! \ HSI as system clock (HSI:%00 HSI48:%11)
\ RCC-CFGR @
\ %1111111 4 lshift bic \ clear HPRE PPRE (no div AHB & APB clocks)
\ RCC-CFGR ! \ write back RCC-CFGR
\ 4 bit FLASH-ACR bis! \ enable prefetch buffer (PRFTBE)
\ 0 bit FLASH-ACR bis! \ one wait state for flash
\ RCC-CFGR @ \ 8MHz * 12 / 2 = 48MHz
\ %1111011 15 lshift bic \ prepare setting PLLMUL and PLLSRC
\ %1000 18 lshift or RCC-CFGR ! \ PLL x 12 \ HSI/2 PLLSRC = 00 \ write back
\
\ 24 bit RCC-CR bis! \ enable PLL
\ begin 25 bit RCC-CR bit@ until \ wait for PLLRDY
\ %10 RCC-CFGR bis! \ PLL as system clock
\ %11 RCC-CFGR3 bis! \ set HSI as USART1 source (so we don't lose prompt)
\ ;
: 48MHz-after-reset ( -- ) \ set the main clock to 48MHz (HSI->PLL) assuming we're out of RESET
%10001 flash-acr bis!
%1000 18 lshift rcc-cfgr !
24 bit rcc-cr bis!
begin 25 bit rcc-cr bit@ until
%10 rcc-cfgr bis!
%11 rcc-cfgr3 bis! \ USART1 clocked from HSI
;
: usb-clk ( -- ) \ enable autotrim and clock to USB
16 bit RCC-CR2 bis! \ switch on HSI48
begin 17 bit RCC-CR2 bit@ until \ wait for HSI48RDY
27 bit RCC-APB1ENR bis! \ enable CRS
CRS-CFGR @ %11 28 lshift bic \ prepare setting SYNCSRC
%10 28 lshift or CRS-CFGR ! \ set USB SOF, write back
6 bit 5 bit or CRS-CR bis! \ set AUTOTRIMEN and CEN
7 bit RCC-CFGR3 bic! \ HSI48 is USB clock source
;
\ emulate c, which is not available in hardware on some chips.
\ copied from Mecrisp's common/charcomma.txt
0 variable c,collection
: c, ( c -- ) \ emulate c, with h,
c,collection @ ?dup if $FF and swap 8 lshift or h,
0 c,collection !
else $100 or c,collection ! then ;
: calign ( -- ) \ must be called to flush after odd number of c, calls
c,collection @ if 0 c, then ;
: cornerstone ( "name" -- ) \ define a flash memory cornerstone
<builds begin here dup flash-pagesize 1- and while 0 h, repeat
does> begin dup dup flash-pagesize 1- and while 2+ repeat cr
eraseflashfrom ;

60
suf072/hal-stm32f1.fs

@ -0,0 +1,60 @@
\ base definitions for STM32F103 (STRIPPED-DOWN version for USB driver use!)
\ adapted from mecrisp-stellaris 2.2.1a (GPL3)
\ needs the definition of "bit" from io.fs
: chipid ( -- u1 u2 u3 3 ) \ unique chip ID as N values on the stack
$1FFFF7E8 @ $1FFFF7EC @ $1FFFF7F0 @ 3 ;
: hwid ( -- u ) \ a "fairly unique" hardware ID as single 32-bit int
chipid 1 do xor loop ;
: flash-kb ( -- u ) \ return size of flash memory in KB
$1FFFF7E0 h@ ;
: flash-pagesize ( addr - u ) \ return size of flash page at given address
drop flash-kb 128 <= if 1024 else 2048 then ;
: bit ( u -- u ) \ turn a bit position into a single-bit mask
1 swap lshift 1-foldable ;
$40010000 constant AFIO
AFIO $4 + constant AFIO-MAPR
$40021000 constant RCC
RCC $00 + constant RCC-CR
RCC $04 + constant RCC-CFGR
RCC $14 + constant RCC-AHBENR
RCC $18 + constant RCC-APB2ENR
RCC $1C + constant RCC-APB1ENR
$40022000 constant FLASH
FLASH $0 + constant FLASH-ACR
\ adjusted for STM32F103 @ 72 MHz (original STM32F100 by Igor de om1zz, 2015)
: 72MHz ( -- ) \ set the main clock to 72 MHz
$12 FLASH-ACR ! \ two flash mem wait states
16 bit RCC-CR bis! \ set HSEON
begin 17 bit RCC-CR bit@ until \ wait for HSERDY
1 16 lshift \ HSE clock is 8 MHz Xtal source for PLL
7 18 lshift or \ PLL factor: 8 MHz * 9 = 72 MHz = HCLK
4 8 lshift or \ PCLK1 = HCLK/2
2 14 lshift or \ ADCPRE = PCLK2/6
2 or RCC-CFGR ! \ PLL is the system clock
24 bit RCC-CR bis! \ set PLLON
begin 25 bit RCC-CR bit@ until \ wait for PLLRDY
;
\ emulate c, which is not available in hardware on some chips.
\ copied from Mecrisp's common/charcomma.txt
0 variable c,collection
: c, ( c -- ) \ emulate c, with h,
c,collection @ ?dup if $FF and swap 8 lshift or h,
0 c,collection !
else $100 or c,collection ! then ;
: calign ( -- ) \ must be called to flush after odd number of c, calls
c,collection @ if 0 c, then ;
: cornerstone ( "name" -- ) \ define a flash memory cornerstone
<builds begin here dup flash-pagesize 1- and while 0 h, repeat
does> begin dup dup flash-pagesize 1- and while 2+ repeat cr
eraseflashfrom ;

332
suf072/usb.fs

@ -0,0 +1,332 @@
\ USB driver
\ from jcw's embello
\ js: WHY WHY WHY is the F103 address into USBMEM so weird (2x if even, 2x-1 if odd)?
\ js: difference in 'buffer descriptor table' in the reference manuals:
\ F1: "words on 32bit-aligned addresses"; F0: nothing special
: led-on 1 15 lshift $48000018 bis! ;
: led-of 1 31 lshift $48000018 bis! ;
create usb:dev
18 c, \ bLength
$01 c, \ USB_DEVICE_DESCRIPTOR_TYPE
$00 c,
$02 c, \ bcdUSB = 2.00
$02 c, \ bDeviceClass: CDC
$00 c, \ bDeviceSubClass
$00 c, \ bDeviceProtocol
$40 c, \ bMaxPacketSize0
$83 c,
$04 c, \ idVendor = 0x0483
$40 c,
$57 c, \ idProduct = 0x7540
$00 c,
$02 c, \ bcdDevice = 2.00
1 c, \ Index of string descriptor describing manufacturer
2 c, \ Index of string descriptor describing product
3 c, \ Index of string descriptor describing the device's serial number
$01 c, \ bNumConfigurations
calign
create usb:conf \ total length = 67 bytes
\ USB Configuration Descriptor
9 c, \ bLength: Configuration Descriptor size
$02 c, \ USB_CONFIGURATION_DESCRIPTOR_TYPE
67 c, \ VIRTUAL_COM_PORT_SIZ_CONFIG_DESC
0 c,
2 c, \ bNumInterfaces: 2 interface
1 c, \ bConfigurationValue
0 c, \ iConfiguration
$C0 c, \ bmAttributes: self powered
$32 c, \ MaxPower 0 mA
\ Interface Descriptor
9 c, \ bLength: Interface Descriptor size
$04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
$00 c, \ bInterfaceNumber: Number of Interface
$00 c, \ bAlternateSetting: Alternate setting
$01 c, \ bNumEndpoints: One endpoints used
$02 c, \ bInterfaceClass: Communication Interface Class
$02 c, \ bInterfaceSubClass: Abstract Control Model
$01 c, \ bInterfaceProtocol: Common AT commands
$00 c, \ iInterface:
\ Header Functional Descriptor
5 c, \ bLength: Endpoint Descriptor size
$24 c, \ bDescriptorType: CS_INTERFACE
$00 c, \ bDescriptorSubtype: Header Func Desc
$10 c, \ bcdCDC: spec release number
$01 c,
\ Call Management Functional Descriptor
5 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$01 c, \ bDescriptorSubtype: Call Management Func Desc
$00 c, \ bmCapabilities: D0+D1
$01 c, \ bDataInterface: 1
\ ACM Functional Descriptor
4 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$02 c, \ bDescriptorSubtype: Abstract Control Management desc
$02 c, \ bmCapabilities
\ Union Functional Descriptor
5 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$06 c, \ bDescriptorSubtype: Union func desc
$00 c, \ bMasterInterface: Communication class interface
$01 c, \ bSlaveInterface0: Data Class Interface
\ Endpoint 2 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$82 c, \ bEndpointAddress: (IN2)
$03 c, \ bmAttributes: Interrupt
8 c, \ VIRTUAL_COM_PORT_INT_SIZE
0 c,
$FF c, \ bInterval:
\ Data class interface descriptor
9 c, \ bLength: Endpoint Descriptor size
$04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
$01 c, \ bInterfaceNumber: Number of Interface
$00 c, \ bAlternateSetting: Alternate setting
$02 c, \ bNumEndpoints: Two endpoints used
$0A c, \ bInterfaceClass: CDC
$00 c, \ bInterfaceSubClass:
$00 c, \ bInterfaceProtocol:
$00 c, \ iInterface:
\ Endpoint 3 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$03 c, \ bEndpointAddress: (OUT3)
$02 c, \ bmAttributes: Bulk
64 c, \ VIRTUAL_COM_PORT_DATA_SIZE
0 c,
$00 c, \ bInterval: ignore for Bulk transfer
\ Endpoint 1 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$81 c, \ bEndpointAddress: (IN1)
$02 c, \ bmAttributes: Bulk
64 c, \ VIRTUAL_COM_PORT_DATA_SIZE
0 c,
$00 c, \ bInterval
calign
create usb:langid
4 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
$0409 h, \ LangID = U.S. English
create usb:vendor
40 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
char M h, char e h, char c h, char r h, char i h, char s h, char p h,
bl h, char ( h, char S h, char T h, char M h, char 3 h, char 2 h,
char F h, char 1 h, char 0 h, char x h, char ) h,
create usb:product
36 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
char F h, char o h, char r h, char t h, char h h, bl h, char S h,
char e h, char r h, char i h, char a h, char l h, bl h, char P h,
char o h, char r h, char t h,
create usb:line
hex 00 c, C2 c, 01 c, 00 c, 01 c, 00 c, 08 c, 00 c, decimal
create usb:init
hex
0080 h, \ ADDR0_TX control - rx: 64b @ +040/080, tx: 64b @ +080/100
0000 h, \ COUNT0_TX
0040 h, \ ADDR0_RX
8400 h, \ COUNT0_RX
00C0 h, \ ADDR1_TX bulk - tx: 64b @ +0C0/180
0000 h, \ COUNT1_TX
0000 h, \ ADDR1_RX
0000 h, \ COUNT1_RX
0140 h, \ ADDR2_TX interrupt - tx: 8b @ +140/280
0000 h, \ COUNT2_TX
0000 h, \ ADDR2_RX
0000 h, \ COUNT2_RX
0000 h, \ ADDR3_TX bulk - rx: 64b @ +100/200
0000 h, \ COUNT3_TX
0100 h, \ ADDR3_RX
8400 h, \ COUNT3_RX
decimal
$40005C00 constant USB
USB $00 + constant USB-EP0R
USB $40 + constant USB-CNTR
USB $44 + constant USB-ISTR
USB $48 + constant USB-FNR
USB $4C + constant USB-DADDR
USB $50 + constant USB-BTABLE
USB $58 + constant USB-BCDR
$40006000 constant USBMEM
\ : usb-pma ( pos -- addr ) dup 1 and negate swap 2* + USBMEM + ;
\ : usb-pma@ ( pos -- u ) usb-pma h@ ;
\ : usb-pma! ( u pos -- ) usb-pma h! ;
: usb-pma ( pos -- addr ) USBMEM + 1-foldable ;
: usb-pma@ ( pos -- u ) usb-pma dup 1 and if c@ else h@ then ;
: usb-pma! ( u pos -- ) usb-pma dup 1 and if c! else h! then ;
: ep-addr ( ep -- addr ) cells USB-EP0R + ;
: ep-reg ( ep n -- addr ) 2* swap 8 * + usb-pma ;
: rxstat! ( ep u -- ) \ set stat_rx without toggling/setting any other fields
swap ep-addr >r
12 lshift r@ h@ tuck xor
\ R^rrseekT^ttnnnn
\ 5432109876543210
%0011000000000000 and swap
%0000111100001111 and
%1000000010000000 or
or r> h! ;
: txstat! ( ep u -- ) \ set stat_tx without toggling/setting any other fields
swap ep-addr >r
4 lshift r@ h@ tuck xor
\ R^rrseekT^ttnnnn
\ 5432109876543210
%0000000000110000 and swap
%0000111100001111 and
%1000000010000000 or
or r> h! ;
: ep-reset-rx# ( ep -- ) $8400 over 3 ep-reg h! 3 rxstat! ;
: rxclear ( ep -- ) ep-addr dup h@ $7FFF and $8F8F and swap h! ;
: txclear ( ep -- ) ep-addr dup h@ $FF7F and $8F8F and swap h! ;
0 0 2variable usb-pend
18 buffer: usb-serial
: set-serial ( -- addr ) \ fill serial number in as UTF-16 descriptor
base @ hex
hwid 0 <# 8 0 do # loop #> ( base addr 8 )
0 do dup c@ i 1+ 2* usb-serial + h! 1+ loop
drop base !
usb-serial $0312 over h! ;
: send-data ( addr n -- ) usb-pend 2! ;
: send-next ( -- )
usb-pend 2@ 64 min $46 usb-pma@ min
>r ( addr R: num )
r@ even 0 ?do
dup i + h@ $80 i + usb-pma!
2 +loop drop
r@ $02 usb-pma! 0 3 txstat!
usb-pend 2@ r> dup negate d+ usb-pend 2! ;
: send-desc ( -- )
$42 usb-pma@ case
$0100 of usb:dev 18 endof
$0200 of usb:conf 67 endof
$0300 of usb:langid 4 endof
$0301 of usb:vendor 40 endof
$0302 of usb:product 36 endof
$0303 of set-serial 18 endof
true ?of 0 0 endof
endcase send-data ;
: usb-reset ( -- )
256 0 do 0 i 2* usb-pma! loop 0 USB-BTABLE h!
usb:init 32 0 do \ js: 64->32
dup h@ i USBMEM + h!
2+
2 +loop drop \ js: changed 4->2
$3210 0 ep-addr h!
$0021 1 ep-addr h!
$0622 2 ep-addr h!
$3003 3 ep-addr h!
$80 USB-DADDR h! ;
create zero 0 ,
128 4 + buffer: usb-in-ring \ RX ring buffer, ample for mecrisp input lines
64 4 + buffer: usb-out-ring \ TX ring buffer, for outbound bytes
: ep-setup ( ep -- ) \ setup packets, sent from host to config this device
dup rxclear
$41 usb-pma c@ case
$00 of zero 2 send-data endof
$06 of send-desc endof
( default ) 0 0 send-data
endcase
ep-reset-rx# send-next ;
0 variable tx.pend
0 variable usb.ticks
: usb-pma-c! ( b pos -- ) \ careful, can't write high bytes separately
dup 1 and if
1- dup usb-pma@ rot 8 lshift or swap
then usb-pma! ;
: usb-fill ( -- ) \ fill the USB outbound buffer from the TX ring buffer
usb-out-ring ring# ?dup if
dup tx.pend !
dup 0 do usb-out-ring ring> $C0 i + usb-pma-c! loop
1 1 ep-reg h! 1 3 txstat!
then ;
: ep-out ( ep -- ) \ outgoing packets, sent from host to this device
\ dup 2 rxstat! \ set RX state to NAK
dup if \ only pick up data for endpoint 3
usb-in-ring ring# 60 > if drop exit then \ reject if no room in ring
dup 3 ep-reg h@ $7F and 0 ?do
i $100 + usb-pma c@ usb-in-ring >ring
loop
then
dup rxclear
ep-reset-rx# ;
: ep-in ( ep -- ) \ incoming polls, sent from this device to host
dup if
0 usb.ticks ! 0 tx.pend ! usb-fill
else
$41 usb-pma c@ $05 = if $42 usb-pma@ $80 or USB-DADDR h! then
send-next
then
txclear ;
: usb-ctr ( istr -- )
led-on
dup $07 and swap $10 and if
dup ep-addr h@ $800 and if ep-setup else ep-out then
else ep-in then ;
: usb-flush
usb-in-ring 128 init-ring
usb-out-ring 64 init-ring ;
: usb-poll
\ clear ring buffers if pending output is not getting sent to host
tx.pend @ if
1 usb.ticks +!
usb.ticks @ 10000 u> if usb-flush then
then
\ main USB driver polling
USB-ISTR h@
\ dup dup $100 bic if hex. else drop then
\ dup 1 8 lshift and if led-on then
\ dup $100 bic if 0 ep-addr h@ hex. then
dup $200 and if 124 emit $FDFF USB-ISTR h! then
dup $100 and if 61 emit $FEFF USB-ISTR h! then
dup $8000 and if dup usb-ctr then
dup $0400 and if usb-reset 64 emit $FBFF USB-ISTR h! then
dup $0800 and if %1100 USB-CNTR hbis! 118 emit $F7FF USB-ISTR h! then
$1000 and if %1000 USB-CNTR hbic! 94 emit $EFFF USB-ISTR h! then ;
: usb-key? ( -- f ) pause usb-poll usb-in-ring ring# 0<> ;
: usb-key ( -- c ) begin usb-key? until usb-in-ring ring> ;
: usb-emit? ( -- f ) usb-poll usb-out-ring ring? ;
: usb-emit ( c -- ) begin usb-emit? until usb-out-ring >ring
tx.pend @ 0= if usb-fill then ;
: usb-io ( -- ) \ start up USB and switch console I/O to it
23 bit RCC-APB1ENR bis! \ USBEN
$0001 USB-CNTR h! ( 10 us ) $0000 USB-CNTR h! \ FRES
usb-flush
\ ['] usb-key? hook-key? !
\ ['] usb-key hook-key !
\ 1000000 0 do usb-poll loop
\ ['] usb-emit? hook-emit? !
\ ['] usb-emit hook-emit ! ;
1000000 0 do usb-poll loop ;
\ begin usb-poll again ;

313
suf072/usb.fs.orig

@ -0,0 +1,313 @@
\ USB driver
create usb:dev
18 c, \ bLength
$01 c, \ USB_DEVICE_DESCRIPTOR_TYPE
$00 c,
$02 c, \ bcdUSB = 2.00
$02 c, \ bDeviceClass: CDC
$00 c, \ bDeviceSubClass
$00 c, \ bDeviceProtocol
$40 c, \ bMaxPacketSize0
$83 c,
$04 c, \ idVendor = 0x0483
$40 c,
$57 c, \ idProduct = 0x7540
$00 c,
$02 c, \ bcdDevice = 2.00
1 c, \ Index of string descriptor describing manufacturer
2 c, \ Index of string descriptor describing product
3 c, \ Index of string descriptor describing the device's serial number
$01 c, \ bNumConfigurations
calign
create usb:conf \ total length = 67 bytes
\ USB Configuration Descriptor
9 c, \ bLength: Configuration Descriptor size
$02 c, \ USB_CONFIGURATION_DESCRIPTOR_TYPE
67 c, \ VIRTUAL_COM_PORT_SIZ_CONFIG_DESC
0 c,
2 c, \ bNumInterfaces: 2 interface
1 c, \ bConfigurationValue
0 c, \ iConfiguration
$C0 c, \ bmAttributes: self powered
$32 c, \ MaxPower 0 mA
\ Interface Descriptor
9 c, \ bLength: Interface Descriptor size
$04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
$00 c, \ bInterfaceNumber: Number of Interface
$00 c, \ bAlternateSetting: Alternate setting
$01 c, \ bNumEndpoints: One endpoints used
$02 c, \ bInterfaceClass: Communication Interface Class
$02 c, \ bInterfaceSubClass: Abstract Control Model
$01 c, \ bInterfaceProtocol: Common AT commands
$00 c, \ iInterface:
\ Header Functional Descriptor
5 c, \ bLength: Endpoint Descriptor size
$24 c, \ bDescriptorType: CS_INTERFACE
$00 c, \ bDescriptorSubtype: Header Func Desc
$10 c, \ bcdCDC: spec release number
$01 c,
\ Call Management Functional Descriptor
5 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$01 c, \ bDescriptorSubtype: Call Management Func Desc
$00 c, \ bmCapabilities: D0+D1
$01 c, \ bDataInterface: 1
\ ACM Functional Descriptor
4 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$02 c, \ bDescriptorSubtype: Abstract Control Management desc
$02 c, \ bmCapabilities
\ Union Functional Descriptor
5 c, \ bFunctionLength
$24 c, \ bDescriptorType: CS_INTERFACE
$06 c, \ bDescriptorSubtype: Union func desc
$00 c, \ bMasterInterface: Communication class interface
$01 c, \ bSlaveInterface0: Data Class Interface
\ Endpoint 2 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$82 c, \ bEndpointAddress: (IN2)
$03 c, \ bmAttributes: Interrupt
8 c, \ VIRTUAL_COM_PORT_INT_SIZE
0 c,
$FF c, \ bInterval:
\ Data class interface descriptor
9 c, \ bLength: Endpoint Descriptor size
$04 c, \ USB_INTERFACE_DESCRIPTOR_TYPE
$01 c, \ bInterfaceNumber: Number of Interface
$00 c, \ bAlternateSetting: Alternate setting
$02 c, \ bNumEndpoints: Two endpoints used
$0A c, \ bInterfaceClass: CDC
$00 c, \ bInterfaceSubClass:
$00 c, \ bInterfaceProtocol:
$00 c, \ iInterface:
\ Endpoint 3 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$03 c, \ bEndpointAddress: (OUT3)
$02 c, \ bmAttributes: Bulk
64 c, \ VIRTUAL_COM_PORT_DATA_SIZE
0 c,
$00 c, \ bInterval: ignore for Bulk transfer
\ Endpoint 1 Descriptor
7 c, \ bLength: Endpoint Descriptor size
$05 c, \ USB_ENDPOINT_DESCRIPTOR_TYPE
$81 c, \ bEndpointAddress: (IN1)
$02 c, \ bmAttributes: Bulk
64 c, \ VIRTUAL_COM_PORT_DATA_SIZE
0 c,
$00 c, \ bInterval
calign
create usb:langid
4 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
$0409 h, \ LangID = U.S. English
create usb:vendor
40 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
char M h, char e h, char c h, char r h, char i h, char s h, char p h,
bl h, char ( h, char S h, char T h, char M h, char 3 h, char 2 h,
char F h, char 1 h, char 0 h, char x h, char ) h,
create usb:product
36 c, 3 c, \ USB_STRING_DESCRIPTOR_TYPE,
char F h, char o h, char r h, char t h, char h h, bl h, char S h,
char e h, char r h, char i h, char a h, char l h, bl h, char P h,
char o h, char r h, char t h,
create usb:line
hex 00 c, C2 c, 01 c, 00 c, 01 c, 00 c, 08 c, 00 c, decimal
create usb:init
hex
0080 h, \ ADDR0_TX control - rx: 64b @ +040/080, tx: 64b @ +080/100
0000 h, \ COUNT0_TX
0040 h, \ ADDR0_RX
8400 h, \ COUNT0_RX
00C0 h, \ ADDR1_TX bulk - tx: 64b @ +0C0/180
0000 h, \ COUNT1_TX
0000 h, \ ADDR1_RX
0000 h, \ COUNT1_RX
0140 h, \ ADDR2_TX interrupt - tx: 8b @ +140/280
0000 h, \ COUNT2_TX
0000 h, \ ADDR2_RX
0000 h, \ COUNT2_RX
0000 h, \ ADDR3_TX bulk - rx: 64b @ +100/200
0000 h, \ COUNT3_TX
0100 h, \ ADDR3_RX
8400 h, \ COUNT3_RX
decimal
$40005C00 constant USB
USB $00 + constant USB-EP0R
USB $40 + constant USB-CNTR
USB $44 + constant USB-ISTR
USB $48 + constant USB-FNR
USB $4C + constant USB-DADDR
USB $50 + constant USB-BTABLE
$40006000 constant USBMEM
: usb-pma ( pos -- addr ) dup 1 and negate swap 2* + USBMEM + ;
: usb-pma@ ( pos -- u ) usb-pma h@ ;
: usb-pma! ( u pos -- ) usb-pma h! ;
: ep-addr ( ep -- addr ) cells USB-EP0R + ;
: ep-reg ( ep n -- addr ) 2* swap 8 * + usb-pma ;
: rxstat! ( ep u -- ) \ set stat_rx without toggling/setting any other fields
swap ep-addr >r
12 lshift r@ h@ tuck xor
\ R^rrseekT^ttnnnn
\ 5432109876543210
%0011000000000000 and swap
%0000111100001111 and
%1000000010000000 or
or r> h! ;
: txstat! ( ep u -- ) \ set stat_tx without toggling/setting any other fields
swap ep-addr >r
4 lshift r@ h@ tuck xor
\ R^rrseekT^ttnnnn
\ 5432109876543210
%0000000000110000 and swap
%0000111100001111 and
%1000000010000000 or
or r> h! ;
: ep-reset-rx# ( ep -- ) $8400 over 3 ep-reg h! 3 rxstat! ;
: rxclear ( ep -- ) ep-addr dup h@ $7FFF and $8F8F and swap h! ;
: txclear ( ep -- ) ep-addr dup h@ $FF7F and $8F8F and swap h! ;
0 0 2variable usb-pend
18 buffer: usb-serial
: set-serial ( -- addr ) \ fill serial number in as UTF-16 descriptor
base @ hex
hwid 0 <# 8 0 do # loop #> ( base addr 8 )
0 do dup c@ i 1+ 2* usb-serial + h! 1+ loop
drop base !
usb-serial $0312 over h! ;
: send-data ( addr n -- ) usb-pend 2! ;
: send-next ( -- )
usb-pend 2@ 64 min $46 usb-pma@ min
>r ( addr R: num )
r@ even 0 ?do
dup i + h@ $80 i + usb-pma!
2 +loop drop
r@ $02 usb-pma! 0 3 txstat!
usb-pend 2@ r> dup negate d+ usb-pend 2! ;
: send-desc ( -- )
$42 usb-pma@ case
$0100 of usb:dev 18 endof
$0200 of usb:conf 67 endof
$0300 of usb:langid 4 endof
$0301 of usb:vendor 40 endof
$0302 of usb:product 36 endof
$0303 of set-serial 18 endof
true ?of 0 0 endof
endcase send-data ;
: usb-reset ( -- )
256 0 do 0 i 2* usb-pma! loop 0 USB-BTABLE h!
usb:init 64 0 do
dup h@ i USBMEM + h!
2+
4 +loop drop
$3210 0 ep-addr h!
$0021 1 ep-addr h!
$0622 2 ep-addr h!
$3003 3 ep-addr h!
$80 USB-DADDR h! ;
create zero 0 ,
128 4 + buffer: usb-in-ring \ RX ring buffer, ample for mecrisp input lines
64 4 + buffer: usb-out-ring \ TX ring buffer, for outbound bytes
: ep-setup ( ep -- ) \ setup packets, sent from host to config this device
dup rxclear
$41 usb-pma c@ case
$00 of zero 2 send-data endof
$06 of send-desc endof
( default ) 0 0 send-data
endcase
ep-reset-rx# send-next ;
0 variable tx.pend
0 variable usb.ticks
: usb-pma-c! ( b pos -- ) \ careful, can't write high bytes separately
dup 1 and if
1- dup usb-pma@ rot 8 lshift or swap
then usb-pma! ;
: usb-fill ( -- ) \ fill the USB outbound buffer from the TX ring buffer
usb-out-ring ring# ?dup if
dup tx.pend !
dup 0 do usb-out-ring ring> $C0 i + usb-pma-c! loop
1 1 ep-reg h! 1 3 txstat!
then ;
: ep-out ( ep -- ) \ outgoing packets, sent from host to this device
\ dup 2 rxstat! \ set RX state to NAK
dup if \ only pick up data for endpoint 3
usb-in-ring ring# 60 > if drop exit then \ reject if no room in ring
dup 3 ep-reg h@ $7F and 0 ?do
i $100 + usb-pma c@ usb-in-ring >ring
loop
then
dup rxclear
ep-reset-rx# ;
: ep-in ( ep -- ) \ incoming polls, sent from this device to host
dup if
0 usb.ticks ! 0 tx.pend ! usb-fill
else
$41 usb-pma c@ $05 = if $42 usb-pma@ $80 or USB-DADDR h! then
send-next
then
txclear ;
: usb-ctr ( istr -- )
dup $07 and swap $10 and if
dup ep-addr h@ $800 and if ep-setup else ep-out then
else ep-in then ;
: usb-flush
usb-in-ring 128 init-ring
usb-out-ring 64 init-ring ;
: usb-poll
\ clear ring buffers if pending output is not getting sent to host
tx.pend @ if
1 usb.ticks +!
usb.ticks @ 10000 u> if usb-flush then
then
\ main USB driver polling
USB-ISTR h@
dup $8000 and if dup usb-ctr then
dup $0400 and if usb-reset $FBFF USB-ISTR h! then
dup $0800 and if %1100 USB-CNTR hbis! $F7FF USB-ISTR h! then
$1000 and if %1000 USB-CNTR hbic! $EFFF USB-ISTR h! then ;
: usb-key? ( -- f ) pause usb-poll usb-in-ring ring# 0<> ;
: usb-key ( -- c ) begin usb-key? until usb-in-ring ring> ;
: usb-emit? ( -- f ) usb-poll usb-out-ring ring? ;
: usb-emit ( c -- ) begin usb-emit? until usb-out-ring >ring
tx.pend @ 0= if usb-fill then ;
: usb-io ( -- ) \ start up USB and switch console I/O to it
23 bit RCC-APB1ENR bis! \ USBEN
$0001 USB-CNTR h! ( 10 us ) $0000 USB-CNTR h! \ FRES
usb-flush
['] usb-key? hook-key? !
['] usb-key hook-key !
1000000 0 do usb-poll loop
['] usb-emit? hook-emit? !
['] usb-emit hook-emit ! ;
\ : init ( -- ) init usb-io ;
Loading…
Cancel
Save