Hey all, I'm trying very hard to understand how UART over USB works by following through the USB CDC ACM example in SDK 17.0.2 on the nRF52840DK, but I'm still new to this so I'm missing something. I see that on APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN
, we so an initial app_usbd_cdc_acm_read
which presumably writes to SIZE.EPOUT
register like it shows in the datasheet (Figure 202 on page 540 in v1.2) then sets up the EasyDMA transfer with the buffer your pass to it and kicks off the STARTEPOUT
task? Then, I guess, we get the APP_USBD_CDC_ACM_USER_EVT_RX_DONE
event on the ENDEPOUT
event register and load up a new EasyDMA buffer and kick off another STARTEPOUT
task?
I ask all this because I am not seeing the data I expect to see. First, I have an array of 16 ArrayLists, each with a 64 byte buffer (same size as USB buffer). I modified READ_SIZE
from 1 to 64. After each app_usbd_cdc_acm_read
I put an app_usbd_cdc_acm_write
(the only change to cdc_acm_user_ev_handler
) to echo back to the terminal. When I send more than 64 bytes at a time, I see that all of the data appears in the buffer when I look in the debugger, but not in my terminal echo. Instead I consistently seem to be missing the first 148 bytes in the echo when I send something like 660 bytes at a time. Since I'm not able to echo those first bytes, I'm also not able to process with them, which is the thing that has me stymied. Here is the pertinent code:
#define ARRAY_LIST_SIZE 16 #define READ_SIZE 64 typedef struct { uint8_t buffer[READ_SIZE]; } ArrayList_t; static ArrayList_t m_rx_buffer[ARRAY_LIST_SIZE]; static char m_tx_buffer[NRF_DRV_USBD_EPSIZE]; static uint16_t m_send_flag = 0; static uint16_t m_cdc_buffer_idx = 0; ... static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, app_usbd_cdc_acm_user_event_t event) { app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst); switch (event) { case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: { //bsp_board_led_on(LED_CDC_ACM_OPEN); /*Setup first transfer*/ ret_code_t ret = app_usbd_cdc_acm_read(p_cdc_acm, m_rx_buffer[m_cdc_buffer_idx].buffer, READ_SIZE); app_usbd_cdc_acm_write(p_cdc_acm, m_rx_buffer[m_cdc_buffer_idx].buffer, READ_SIZE); if (++m_cdc_buffer_idx > ARRAY_LIST_SIZE) m_cdc_buffer_idx = 0; UNUSED_VARIABLE(ret); break; } case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE: //bsp_board_led_off(LED_CDC_ACM_OPEN); break; case APP_USBD_CDC_ACM_USER_EVT_TX_DONE: //bsp_board_led_invert(LED_CDC_ACM_TX); break; case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: { ret_code_t ret; //NRF_LOG_INFO("Bytes waiting: %d", app_usbd_cdc_acm_bytes_stored(p_cdc_acm)); do { /*Get amount of data transfered*/ size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm); //NRF_LOG_INFO("RX: size: %lu char: %c", size, m_rx_buffer); /* Fetch data until internal buffer is empty */ ret = app_usbd_cdc_acm_read(p_cdc_acm, m_rx_buffer[m_cdc_buffer_idx].buffer, READ_SIZE); } while (ret == NRF_SUCCESS); /* echo */ app_usbd_cdc_acm_write(p_cdc_acm, m_rx_buffer[m_cdc_buffer_idx].buffer, READ_SIZE); if (++m_cdc_buffer_idx > ARRAY_LIST_SIZE) m_cdc_buffer_idx = 0; break; } default: break; } }
What I was hoping to do was send a file with a standard header of size ~600 bytes, grab 64 bytes at a time, and look for a few particular fields - one being the first few bytes as a validation and another that could appear at anywhere from 100 to 600 bytes from the start of the file. That field contains the size of the remainder of the file that I would then write to some flash. The same protocol also will be used to communicate with the host in 64byte messages.