Merge branch 'ZLP_Request2' of https://github.com/pigrew/tinyusb into pigrew-ZLP_Request2

This commit is contained in:
hathach 2019-10-29 18:19:10 +07:00
commit a29eb87c38
3 changed files with 29 additions and 8 deletions

View File

@ -127,15 +127,27 @@ Also make sure to enable endpoint specific interrupts.
`dcd_edpt_xfer` is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint number and direction which usually determines where to write the buffer info. The buffer and its length are usually written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a register or setting a counter register to 0 for OUT or length for IN.)
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint
number and direction which usually determines where to write the buffer info. The buffer and its length are usually
written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a
register or setting a counter register to 0 for OUT or length for IN.)
TODO: can we promise the buffer is word aligned?
The transmit buffer is NOT guarenteed to be word-aligned.
One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21). Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track some state for yourself and queue up an intermediate USB packet from the interrupt handler.
One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB
packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21).
Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track
some state for yourself and queue up an intermediate USB packet from the interrupt handler.
Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion.
During transmission, the IN data buffer is guarenteed to remain unchanged in memory until the `dcd_xfer_complete` function is called.
TODO: who handles zero-length data packets?
The dcd_edpt_xfer function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required,
then it must be explicitly sent by the module calling dcd_edpt_xfer(), by calling dcd_edpt_xfer() a second time with len=0.
For control transfers, this is automatically done in `usbd_control.c`.
At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new dcd_edpt_xfer() will not
be called again until the driver calls dcd_xfer_complete() (except in cases of USB resets).
##### dcd_xfer_complete

View File

@ -241,6 +241,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
break;
case HID_REQ_CONTROL_SET_REPORT:
TU_VERIFY(p_request->wLength <=sizeof(p_hid->epout_buf));
tud_control_xfer(rhport, p_request, p_hid->epout_buf, p_request->wLength);
break;

View File

@ -43,8 +43,9 @@ typedef struct
tusb_control_request_t request;
void* buffer;
uint16_t total_len;
uint16_t len;
uint16_t total_transferred;
uint16_t requested_len;
bool (*complete_cb) (uint8_t, tusb_control_request_t const *);
} usbd_control_xfer_t;
@ -68,7 +69,7 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request)
// Each transaction is up to endpoint0's max packet size
static bool start_control_data_xact(uint8_t rhport)
{
uint16_t const xact_len = tu_min16(_control_state.total_len - _control_state.total_transferred, CFG_TUD_ENDPOINT0_SIZE);
uint16_t const xact_len = tu_min16(_control_state.len - _control_state.total_transferred, CFG_TUD_ENDPOINT0_SIZE);
uint8_t ep_addr = EDPT_CTRL_OUT;
@ -89,10 +90,16 @@ void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_reque
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
{
// transmitted length must be <= requested length (USB 2.0 spec: 8.5.3.1 )
// FIXME: Should logic be here or in place that calls this function?
if(len > request->wLength)
len = request->wLength;
_control_state.request = (*request);
_control_state.buffer = buffer;
_control_state.total_len = tu_min16(len, request->wLength);
_control_state.total_transferred = 0;
_control_state.requested_len = request->wLength;
_control_state.len = len;
if ( len )
{
@ -124,7 +131,8 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
_control_state.total_transferred += xferred_bytes;
_control_state.buffer = ((uint8_t*)_control_state.buffer) + xferred_bytes;
if ( _control_state.total_len == _control_state.total_transferred || xferred_bytes < CFG_TUD_ENDPOINT0_SIZE )
if ( (_control_state.requested_len == _control_state.total_transferred) || xferred_bytes < CFG_TUD_ENDPOINT0_SIZE )
{
// DATA stage is complete
bool is_ok = true;