2222 epinen uint32
2323 epouten uint32
2424 easyDMABusy volatile.Register8
25+ // epOutFlowControl contains the flow control state of the USB OUT endpoints.
26+ epOutFlowControl [NumberOfUSBEndpoints ]struct {
27+ // nak indicates that we are NAKing any further OUT packets because the rxHandler isn't ready yet.
28+ // When this is true, we do not restart the DMA for the endpoint, effectively pausing it.
29+ nak bool
30+ // dataPending indicates that we have data in the hardware buffer that hasn't been handled yet.
31+ // Having one in the buffer is what generates the NAK responses, this is a signal to handle it.
32+ dataPending bool
33+ }
2534
2635 endPoints = []uint32 {
2736 usb .CONTROL_ENDPOINT : usb .ENDPOINT_TYPE_CONTROL ,
@@ -196,7 +205,16 @@ func handleUSBIRQ(interrupt.Interrupt) {
196205 nrf .USBD .EPOUT [i ].PTR .Set (uint32 (uintptr (unsafe .Pointer (& udd_ep_out_cache_buffer [i ]))))
197206 count := nrf .USBD .SIZE .EPOUT [i ].Get ()
198207 nrf .USBD .EPOUT [i ].MAXCNT .Set (count )
199- nrf .USBD .TASKS_STARTEPOUT [i ].Set (1 )
208+ if ! epOutFlowControl [i ].nak {
209+ // Normal case: We want data, so start DMA immediately
210+ nrf .USBD .TASKS_STARTEPOUT [i ].Set (1 )
211+ epOutFlowControl [i ].dataPending = false
212+ } else {
213+ // NAK case: We want to NAK, so DO NOT start DMA.
214+ // The data stays in HW buffer. Host receives NAKs.
215+ // Mark that we have data waiting so we can fetch it later.
216+ epOutFlowControl [i ].dataPending = true
217+ }
200218 }
201219 }
202220 }
@@ -208,6 +226,10 @@ func handleUSBIRQ(interrupt.Interrupt) {
208226 buf := handleEndpointRx (uint32 (i ))
209227 if usbRxHandler [i ] == nil || usbRxHandler [i ](buf ) {
210228 AckUsbOutTransfer (uint32 (i ))
229+ } else {
230+ // usbRxHandler returned false, so NAK further OUT packets until we're ready
231+ epOutFlowControl [i ].nak = true
232+ nrf .USBD .SIZE .EPOUT [i ].Set (0 )
211233 }
212234 exitCriticalSection ()
213235 }
@@ -229,19 +251,23 @@ func initEndpoint(ep, config uint32) {
229251 switch config {
230252 case usb .ENDPOINT_TYPE_INTERRUPT | usb .EndpointIn :
231253 enableEPIn (ep )
254+ setEPDataPID (ep | usb .EndpointIn , false )
232255
233256 case usb .ENDPOINT_TYPE_BULK | usb .EndpointOut :
234257 nrf .USBD .INTENSET .Set (nrf .USBD_INTENSET_ENDEPOUT0 << ep )
235258 nrf .USBD .SIZE .EPOUT [ep ].Set (0 )
236259 enableEPOut (ep )
260+ setEPDataPID (ep , false )
237261
238262 case usb .ENDPOINT_TYPE_INTERRUPT | usb .EndpointOut :
239263 nrf .USBD .INTENSET .Set (nrf .USBD_INTENSET_ENDEPOUT0 << ep )
240264 nrf .USBD .SIZE .EPOUT [ep ].Set (0 )
241265 enableEPOut (ep )
266+ setEPDataPID (ep , false )
242267
243268 case usb .ENDPOINT_TYPE_BULK | usb .EndpointIn :
244269 enableEPIn (ep )
270+ setEPDataPID (ep | usb .EndpointIn , false )
245271
246272 case usb .ENDPOINT_TYPE_CONTROL :
247273 enableEPIn (0 )
@@ -259,7 +285,7 @@ func SendUSBInPacket(ep uint32, data []byte) bool {
259285 sendUSBPacket (ep , data , 0 )
260286
261287 // clear transfer complete flag
262- nrf .USBD .INTENCLR .Set (nrf .USBD_INTENCLR_ENDEPOUT0 << 4 )
288+ nrf .USBD .INTENCLR .Set (nrf .USBD_INTENCLR_ENDEPOUT0 << ep )
263289
264290 return true
265291}
@@ -304,8 +330,26 @@ func handleEndpointRx(ep uint32) []byte {
304330}
305331
306332// AckUsbOutTransfer is called to acknowledge the completion of a USB OUT transfer.
333+ // It also clears the NAK state and resumes data flow if it was paused.
307334func AckUsbOutTransfer (ep uint32 ) {
308- // set ready for next data
335+ epOutFlowControl [ep ].nak = false
336+
337+ // If we ignored a packet earlier (Buffer Full strategy), we must manually
338+ // trigger the DMA now to pull it from the HW buffer.
339+ if epOutFlowControl [ep ].dataPending {
340+ epOutFlowControl [ep ].dataPending = false
341+
342+ // Prepare DMA to move data from HW Buffer -> RAM
343+ nrf .USBD .EPOUT [ep ].PTR .Set (uint32 (uintptr (unsafe .Pointer (& udd_ep_out_cache_buffer [ep ]))))
344+ count := nrf .USBD .SIZE .EPOUT [ep ].Get ()
345+ nrf .USBD .EPOUT [ep ].MAXCNT .Set (count )
346+
347+ // Kick the DMA
348+ nrf .USBD .TASKS_STARTEPOUT [ep ].Set (1 )
349+ return
350+ }
351+
352+ // Otherwise, just re-arm the endpoint to accept the NEXT packet
309353 nrf .USBD .SIZE .EPOUT [ep ].Set (0 )
310354}
311355
@@ -379,3 +423,69 @@ func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
379423
380424 return b , nil
381425}
426+
427+ // Set the USB endpoint Packet ID to DATA0 or DATA1.
428+ // In endpoints must have bit 7 (0x80) set.
429+ func setEPDataPID (ep uint32 , dataOne bool ) {
430+ val := ep
431+ if dataOne {
432+ val |= nrf .USBD_DTOGGLE_VALUE_Data1 << nrf .USBD_DTOGGLE_VALUE_Pos
433+ } else {
434+ val |= nrf .USBD_DTOGGLE_VALUE_Data0 << nrf .USBD_DTOGGLE_VALUE_Pos
435+ }
436+ nrf .USBD .DTOGGLE .Set (val )
437+ }
438+
439+ // Set ENDPOINT_HALT/stall status on a USB IN endpoint.
440+ func (dev * USBDevice ) SetStallEPIn (ep uint32 ) {
441+ if ep & 0x7F == 0 {
442+ nrf .USBD .TASKS_EP0STALL .Set (1 )
443+ } else if ep & 0x7F < NumberOfUSBEndpoints {
444+ // Stall In Endpoint
445+ val := 0x100 | 0x80 | ep
446+ nrf .USBD .EPSTALL .Set (val )
447+ }
448+ }
449+
450+ // Set ENDPOINT_HALT/stall status on a USB OUT endpoint.
451+ func (dev * USBDevice ) SetStallEPOut (ep uint32 ) {
452+ if ep == 0 {
453+ nrf .USBD .TASKS_EP0STALL .Set (1 )
454+ } else if ep < NumberOfUSBEndpoints {
455+ // Stall Out Endpoint
456+ val := 0x100 | 0x00 | ep
457+ nrf .USBD .EPSTALL .Set (val )
458+ }
459+ }
460+
461+ // Clear the ENDPOINT_HALT/stall on a USB IN endpoint.
462+ func (dev * USBDevice ) ClearStallEPIn (ep uint32 ) {
463+ if ep & 0x7F == 0 {
464+ nrf .USBD .TASKS_EP0STALL .Set (0 )
465+ } else if ep & 0x7F < NumberOfUSBEndpoints {
466+ // Reset the endpoint data PID to DATA0
467+ ep |= 0x80 // Set endpoint direction bit
468+ setEPDataPID (ep , false )
469+
470+ // No-stall In Endpoint
471+ val := 0x000 | 0x80 | ep
472+ nrf .USBD .EPSTALL .Set (val )
473+ }
474+ }
475+
476+ // Clear the ENDPOINT_HALT/stall on a USB OUT endpoint.
477+ func (dev * USBDevice ) ClearStallEPOut (ep uint32 ) {
478+ if ep == 0 {
479+ nrf .USBD .TASKS_EP0STALL .Set (0 )
480+ } else if ep < NumberOfUSBEndpoints {
481+ // Reset the endpoint data PID to DATA0
482+ setEPDataPID (ep , false )
483+
484+ // No-stall Out Endpoint
485+ val := 0x000 | 0x00 | ep
486+ nrf .USBD .EPSTALL .Set (val )
487+
488+ // Write a value to the SIZE register to allow nRF to ACK/accept data
489+ nrf .USBD .SIZE .EPOUT [ep ].Set (0 )
490+ }
491+ }
0 commit comments