en:pfw:usb_cdc_driver_for_rp2040
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:pfw:usb_cdc_driver_for_rp2040 [2025-12-27 12:54] – [Pseudo code] willem | en:pfw:usb_cdc_driver_for_rp2040 [2026-01-13 18:16] (current) – [The idea] willem | ||
|---|---|---|---|
| Line 17: | Line 17: | ||
| < | < | ||
| hex | hex | ||
| - | Function DEVICE-DECRIPTOR \ 18 bytes | + | Function: DEVICE-DECRIPTOR \ 18 bytes |
| + | The USB CDC device descriptor | ||
| + | |||
| + | Function: CONFIGURATION-DESCRIPTOR \ 9 or 75 bytes | ||
| + | The complex USB CDC device descriptor | ||
| + | |||
| + | Function: USB-STATE | ||
| + | Hold current USB state in first half word: 3 = ready | ||
| + | In second half word are memory for the 900/880 requests | ||
| + | The English/US language ID string | ||
| + | CDC Line data: 115k2, Stop bits, Parity, Data bits | ||
| + | |||
| + | Function: START-USB | ||
| + | Initialise the RP2040 USB hardware, restart the USB hardware, | ||
| + | erase the USB DPRAM, enable USB controller, set USB address to zero. | ||
| + | Setup used endpoints and used interrupts & enable full speed USB. | ||
| + | |||
| + | Function: PAD ( -- a ) | ||
| + | Reserve 64 bytes RAM as scratchpad area | ||
| + | |||
| + | Function: EP0 ( -- a ) | ||
| + | Function: EP1 ( -- a ) | ||
| + | Function: EP2 ( -- a ) | ||
| + | Function: EP3 ( -- a ) | ||
| + | Seven cells data structures to control endpoint-0, 1, 2 & 3 | ||
| + | The first four cells a variable data | ||
| + | The three cells thereafter contain USB pointers & register addresses | ||
| + | |||
| + | Function: @VAL ( -- +n ) | ||
| + | Read the wValue from any eight bytes setup packet | ||
| + | Function: @LEN ( -- +n ) | ||
| + | Read the wLength from any eight bytes setup packet | ||
| + | |||
| + | Function: > | ||
| + | Store the ASCII string to a unicode string tailored for USB | ||
| + | |||
| + | Function: > | ||
| + | Function: > | ||
| + | Function: > | ||
| + | Function: > | ||
| + | Function: > | ||
| + | Function: > | ||
| + | Function: > | ||
| + | Seven functions that calculate the address of each field in the | ||
| + | endpoint data structures | ||
| + | |||
| + | Function: EP-IN ( ep -- org buf pkt ) | ||
| + | Calculate data to send for ' | ||
| + | |||
| + | Function: PREPARE | ||
| + | Prepare data packet from address ' | ||
| + | |||
| + | Function: > | ||
| + | Get next packet size for ' | ||
| + | data to send | ||
| + | |||
| + | Function: !PKT ( pkt ep -- ictrl ) | ||
| + | Store next packet to send for ' | ||
| + | |||
| + | Function: PREP-RCV ( ep -- ) | ||
| + | Enable endpoint ' | ||
| + | |||
| + | Function: GONE? ( ep -- f ) | ||
| + | Leave true when the data in ' | ||
| + | |||
| + | Function: USB? ( -- +n ) | ||
| + | Leave three when the host & device are connected | ||
| + | |||
| + | Function: USB-SEND ( ep -- ) | ||
| + | Transmit the prepared data packet to ' | ||
| + | |||
| + | Function: USB-RCV | ||
| + | Enable the receiving of a data packet on ' | ||
| + | from the stack | ||
| + | |||
| + | Function: BUS=RESET ( -- ) | ||
| + | Handle a USB bus reset, clearing the device address to zero, the USB | ||
| + | state to zero, reinitialise the receiving & transmitting endpoints | ||
| + | |||
| + | Function: SETUP> | ||
| + | Handle the answer data packet ' | ||
| + | When done wait for a ZLP from the host to signal a correct answer | ||
| + | |||
| + | Function: XTABLE | ||
| + | Define an execution table entry for ' | ||
| + | Define: | ||
| + | Create a table with " | ||
| + | Action: | ||
| + | Execute the action for ' | ||
| + | when the ' | ||
| + | |||
| + | Function: ZLP> | ||
| + | Send a zero length package through endpoint zero. This is used | ||
| + | to signal the handling of a request that sends no data back | ||
| + | |||
| + | Define four action in front that leave their execution tokens on the stack | ||
| + | 0302 action xt | ||
| + | 0300 action xt | ||
| + | 0200 action xt | ||
| + | 0100 action xt | ||
| + | Function: HANDLE-SETUP ( req0 .. req3 4 -- ) | ||
| + | |||
| + | 2221 action xt | ||
| + | 21A1 action xt | ||
| + | 2021 action xt | ||
| + | 0900 action xt | ||
| + | 0880 action xt | ||
| + | 0680 action xt | ||
| + | 0500 action xt | ||
| + | Function: HANDLE-REQ) | ||
| + | |||
| + | Function: HANDLE-REQ | ||
| + | Reset setup request interrupt, read bmrequest type and do HANDLE-REQ) | ||
| + | |||
| + | Function: #L ( -- +n ) | ||
| + | Ring buffer size, must be a power of two | ||
| + | Function: #R ( -- +n ) | ||
| + | this is equal to #L - 1 | ||
| + | |||
| + | Function: #RX ( -- +n ) | ||
| + | Leave number of characters in receive buffer | ||
| + | Function: #TX ( -- +n ) | ||
| + | Leave number of characters in transmit buffer | ||
| + | |||
| + | Function: > | ||
| + | Store character ' | ||
| + | Function: > | ||
| + | Store character ' | ||
| + | |||
| + | Function: RX> | ||
| + | Read character ' | ||
| + | Function: TX> | ||
| + | Read character ' | ||
| + | |||
| + | Function: IFLAG | ||
| + | Reserve one cell space for receive interrupt flag | ||
| + | |||
| + | Function: ENDPOINTS | ||
| + | Handle EP1 & EP3 endpoints, save received data interrupt flag in IFLAG | ||
| + | Release all interrupt flags | ||
| + | |||
| + | Function: REQUESTS | ||
| + | Handle all USB interrupts, that are the USB bus reset, setup requests & endpoints | ||
| + | |||
| + | Function: USB-HANDLER | ||
| + | Handle the receiving of the RX data using iFLAG and use the low level USB | ||
| + | ACK/NAK handshake to move data from an endpoint to the RX ring buffer in a controlled way. | ||
| + | Handle the transmitting of TX data, but only when a connection is made. Before filling | ||
| + | the TX endpoint check if the previous data packet was sent too. | ||
| + | |||
| + | Function: USB-KEY? | ||
| + | Leave true flag when there is data in the RX ring buffer, otherwise false | ||
| + | Call the USB-HANDLER once too | ||
| + | |||
| + | Function: USB-KEY | ||
| + | Leave character ' | ||
| + | Call the USB-HANDLER waiting for space in the RX ring buffer | ||
| + | |||
| + | Function: USB-EMIT | ||
| + | Store character ' | ||
| + | Call the USB-HANDLER waiting for space in the TX ring buffer | ||
| + | |||
| + | Function: USB-ON | ||
| + | Initialise the USB DPRAM, call START-USB, clear USB-STATE & IFLAG | ||
| + | finally initialse the KEY?, KEY and EMIT vectors of the used system. | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== Generic Forth implementation example ===== | ||
| + | |||
| + | <code forth> | ||
| + | \ This program assumes 32-bit cells. | ||
| + | \ Non standard words used are: | ||
| + | \ : C@+ ( a1 -- a2 b ) count ; | ||
| + | \ : H@ ( a -- h ) count swap c@ 8 lshift | ||
| + | \ : H! ( h a -- ) >r dup r@ c! 8 rshift | ||
| + | \ : @+ ( a1 -- a2 x ) >r r@ cell+ r> @ ; | ||
| + | \ : **BIS ( msk a -- ) >r r@ @ or r> ! ; | ||
| + | \ : **BIC ( msk a -- ) >r invert r@ @ and r> ! ; | ||
| + | \ : **BIX ( msk a -- ) >r r@ @ xor r> ! ; | ||
| + | \ : BIT** ( msk a -- b ) @ and ; | ||
| + | |||
| + | hex \ USB device data structures | ||
| + | create DEV-DESCR | ||
| 12 c, 01 c, 10 c, 01 c, ( 1.10 ) EF c, 02 c, 01 c, 40 c, 66 c, 66 c, ( 6666 ) | 12 c, 01 c, 10 c, 01 c, ( 1.10 ) EF c, 02 c, 01 c, 40 c, 66 c, 66 c, ( 6666 ) | ||
| 10 c, 66 c, ( 6610 ) 00 c, 01 c, ( vsn 1.00 ) 00 c, 02 c, 00 c, 01 c, align | 10 c, 66 c, ( 6610 ) 00 c, 01 c, ( vsn 1.00 ) 00 c, 02 c, 00 c, 01 c, align | ||
| - | + | create CONFIG-DESCR \ Configuration descriptor (9 or 75 bytes) | |
| - | Function CONFIGURATION-DESCRIPTOR | + | |
| 9 c, 2 c, 4B c, 0 c, 2 c, 1 c, 0 c, 80 c, FA c, \ Maximum power = 500mA | 9 c, 2 c, 4B c, 0 c, 2 c, 1 c, 0 c, 80 c, FA c, \ Maximum power = 500mA | ||
| 8 c, 0B c, 0 c, 2 c, 2 c, 2 c, 1 c, 0 c, \ Interface Association Descriptor - CDC 0 | 8 c, 0B c, 0 c, 2 c, 2 c, 2 c, 1 c, 0 c, \ Interface Association Descriptor - CDC 0 | ||
| Line 33: | Line 215: | ||
| 7 c, 5 c, 82 c, 2 c, 40 c, 0 c, 0 c, \ Endpoint 2 IN descriptor | 7 c, 5 c, 82 c, 2 c, 40 c, 0 c, 0 c, \ Endpoint 2 IN descriptor | ||
| 7 c, 5 c, 3 c, 2 c, 40 c, 0 c, 0 c, align \ Endpoint 3 OUT descriptor | 7 c, 5 c, 3 c, 2 c, 40 c, 0 c, 0 c, align \ Endpoint 3 OUT descriptor | ||
| + | |||
| + | create PAD ( -- a ) 40 allot \ Scratchpad memory | ||
| decimal | decimal | ||
| - | Function | + | create |
| - | | + | \ Second |
| - | 4 c, 3 c, 9 c, 4 c, \ English/US = language ID | + | 4 c, 3 c, 9 c, 4 c, |
| - | 115200 , 0 c, 0 c, 8 c, | + | 115200 , 0 c, 0 c, 8 c, \ Line data: 115k2, Stop bits, Parity, Data bits |
| + | align hex | ||
| + | |||
| + | : START-USB | ||
| + | 1000000 | ||
| + | 2dup **bis 2dup **bic \ Restart USB | ||
| + | begin 2dup 8 + bit** until \ Wait until USB is ready | ||
| + | 2drop 50100000 1000 false fill \ Erase USB ram | ||
| + | 00000009 | ||
| + | 0000000C | ||
| + | 00000001 | ||
| + | 20000000 | ||
| + | false | ||
| + | 00011010 | ||
| + | AC000180 | ||
| + | A8000200 | ||
| + | A8000280 | ||
| + | 00010000 | ||
| + | |||
| + | \ Endpoint data structures, 4 variable cells & 3 constant cells | ||
| + | \ Name: CNT ORG PKT PID | ||
| + | \ Offsets: 00 | ||
| + | create EP0 4 cells allot | ||
| + | create EP1 4 cells allot | ||
| + | create EP2 4 cells allot | ||
| + | create EP3 4 cells allot | ||
| + | |||
| + | : @VAL ( -- +n ) | ||
| + | : @LEN ( -- +n ) | ||
| + | |||
| + | : > | ||
| + | dup 2* 302 + pad h! 0 \ String length & notifier | ||
| + | ?do c@+ pad i 2* + 2 + h! loop drop pad ; | ||
| + | |||
| + | \ Addresssing tools for the endpoint data structures | ||
| + | : > | ||
| + | : > | ||
| + | : > | ||
| + | : > | ||
| + | : > | ||
| + | : > | ||
| + | : > | ||
| + | |||
| + | \ Primitive endpoint functionality | ||
| + | : EP-IN ( ep -- org buf pkt ) \ Calculate data to send for EPx | ||
| + | >r r@ >org @ r@ >buf @ r> >pkt @ ; | ||
| + | |||
| + | : PREPARE | ||
| + | >r dup r@ >cnt ! 40 min r@ >pkt ! r> >org ! ; | ||
| + | |||
| + | : > | ||
| + | >r r@ >pkt @ r@ >org @ + r@ >org ! | ||
| + | r@ >pkt @ r@ @ over - dup r@ ! 40 min r> >pkt ! ; | ||
| + | |||
| + | : !PKT ( pkt ep -- ictrl ) \ pid + pkt + mask - Store next packet to send for EPx | ||
| + | > | ||
| + | |||
| + | : PREP-RCV | ||
| + | >r r@ >octrl @ r@ >pid @ 40 or over ! | ||
| + | 2000 r> >pid **bix 400 swap **bis ; | ||
| + | |||
| + | : GONE? ( ep -- f ) > | ||
| + | : USB? ( -- +n ) | ||
| + | |||
| + | \ Basic receive & transmit packet handlers | ||
| + | : USB-SEND | ||
| + | : USB-RCV | ||
| + | |||
| + | : BUS-RESET | ||
| + | 80000 50113050 | ||
| + | false 50110000 | ||
| + | false ep3 usb-rcv | ||
| + | |||
| + | : SETUP> | ||
| + | 2000 ep0 >pid ! ep0 prepare | ||
| + | begin | ||
| + | ep0 ep-in move ep0 usb-send | ||
| + | 1 50110058 | ||
| + | begin 2dup bit** until **bis | ||
| + | ep0 @ 0= until 2000 ep0 usb-rcv ; \ Handle ZLP | ||
| + | |||
| + | : XTABLE | ||
| + | create | ||
| + | does> @+ ( req -- ) | ||
| + | >r r@ for 2dup @ = if \ Token found? | ||
| + | nip rdrop r> cells + \ Yes, calc. cell with XT | ||
| + | @ execute | ||
| + | then | ||
| + | cell+ | ||
| + | next rdrop 2drop \ No token found | ||
| + | 1 5011,0068 ! 800 5010,0080 ! ; \ Send EP0 stall | ||
| + | |||
| + | : ZLP> | ||
| + | |||
| + | : | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | 4 xtable HANDLE-SETUP | ||
| + | 0100 , 0200 , 0300 , 0302 , | ||
| + | ( dev ) , ( conf ) , ( 300 ) , ( 302 ) , | ||
| + | |||
| + | : | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | 7 xtable HANDLE-REQ) | ||
| + | 0500 , 0680 , 0880 , 0900 , 2021 , 21A1 , 2221 , | ||
| + | , , | ||
| + | |||
| + | : HANDLE-REQ | ||
| + | |||
| + | \ Ring buffer structure for serial I/O | ||
| + | \ | ||
| + | \ 0 = Number of used storage units (CNT) | ||
| + | \ 1 = In pointer (IN) | ||
| + | \ 2 = Out pointer (OUT) | ||
| + | \ 3 = Start of ring buffer | ||
| + | 100 | ||
| + | #L 1- | ||
| + | |||
| + | 50100300 | ||
| + | buffer1 #l + 3 cells + constant BUFFER2 \ Start of out buffer | ||
| + | : #RX ( -- +n ) | ||
| + | : #TX ( -- +n ) | ||
| + | |||
| + | : > | ||
| + | buffer1 cell+ >r | ||
| + | r@ @ r@ 2 cells + + c! \ Yes, add char to buffer | ||
| + | r@ @ 1+ #r and r@ ! \ Increase & protect write pointer | ||
| + | 1 r> cell- +! ; \ Increase used space | ||
| + | : RX> | ||
| + | buffer1 2 cells + >r | ||
| + | r@ @ r@ cell+ + c@ \ Read char. from buffer | ||
| + | r@ @ 1+ #r and r@ ! \ Increase & protect read pointer | ||
| + | true r> 2 cells - +! ; \ Decrease used space | ||
| + | |||
| + | : > | ||
| + | buffer2 cell+ >r | ||
| + | r@ @ r@ 2 cells + + c! \ Yes, add char to buffer | ||
| + | r@ @ 1+ #r and r@ ! \ Increase & protect write pointer | ||
| + | 1 r> cell- +! ; \ Increase used space | ||
| + | : TX> | ||
| + | buffer2 2 cells + >r | ||
| + | r@ @ r@ cell+ + c@ \ Read char. from buffer | ||
| + | r@ @ 1+ #r and r@ ! \ Increase & protect read pointer | ||
| + | true r> 2 cells - +! ; \ Decrease used space | ||
| + | |||
| + | 0 value IFLAG | ||
| + | : ENDPOINTS ( -- ) \ Handle used endpoints | ||
| + | 50110058 @ >r | ||
| + | r@ 04 and if zlp> | ||
| + | iflag r@ 80 and or to iflag \ EP3 active, remember | ||
| + | r> 50110058 ! ; | ||
| + | |||
| + | : REQUESTS | ||
| + | 50110098 @ >r ( ints ) | ||
| + | r@ 10 and if endpoints | ||
| + | r@ 1000 and if bus-reset | ||
| + | r> 10000 and if handle-req | ||
| + | |||
| + | : USB-HANDLER | ||
| + | requests | ||
| + | iflag if \ Next RX packet wanted? | ||
| + | #L #tx - 40 > \ Yes, enough space in TX buffer? | ||
| + | #L #rx - 40 > and if \ And next RX packet fits too? | ||
| + | ep3 >buf @ 5010009C c@ | ||
| + | 0 ?do c@+ >rx loop \ Yes, fill RX buffer | ||
| + | drop false to iflag \ Done | ||
| + | ep3 prep-rcv | ||
| + | then | ||
| + | then | ||
| + | usb? if \ Still connected? | ||
| + | #tx if \ EP2 Any chars to send? | ||
| + | ep2 gone? if \ Yes, previous packet gone? | ||
| + | ep2 >buf @ #tx 40 umin \ Packet place & size | ||
| + | 2dup ep2 prepare | ||
| + | ?do tx> i c! loop \ Place data in EP2-buffer | ||
| + | ep2 usb-send | ||
| + | then | ||
| + | then | ||
| + | then ; | ||
| + | |||
| + | : USB-KEY? | ||
| + | : USB-KEY | ||
| + | : USB-EMIT | ||
| + | |||
| + | : USB-ON | ||
| + | 50100300 | ||
| + | start-usb | ||
| + | ['] usb-key? to ' | ||
| + | ['] usb-key | ||
| + | ['] usb-emit to 'emit ; | ||
| - | hex | + | usb-on |
| </ | </ | ||
| - | ===== Implementation example | + | ===== Implementations |
| + | [[https:// | ||
en/pfw/usb_cdc_driver_for_rp2040.1766836471.txt.gz · Last modified: 2025-12-27 12:54 by willem