UART TX_CALLBACK_SIZE question

⚠️
Hi there.. thanks for coming to the forums. Exciting news! we’re now in the process of moving to our new forum platform that will offer better functionality and is contained within the main Dialog website. All posts and accounts have been migrated. We’re now accepting traffic on the new forum only - please POST any new threads at//www.wsdof.com/support. We’ll be fixing bugs / optimising the searching and tagging over the coming days.
3 posts / 0 new
Last post
kqtrinh
Offline
Last seen:3 years 9 months ago
Joined:2016-08-24 00:17
UART TX_CALLBACK_SIZE question

Hi Dialog Engineer,

I am using the DSPS application firmware as my baseline code to start with.
I have a DA communicating with an external MCU via the UART line. This UART is setup at a baudrate of 56.7kbps.

I have implemented two functions to send data across from the DA to the external MCU.

Function 1:
- Upon DA powers up, this function reads from Flash and downloads the external MCU firmware over this UART line. This function is working consistently 100% since the external MCU can actually spin up and run with its firmware. Here is the code:

// Read QPI FWs/Tables from flash address "address" and "size" &
// write it out the UART channel(s) where the QPI(s) attached to
void user_sps_qpi_fw_upload(unsigned int address) {

BYTE buf[2];
// read the firmware size in bytes stored in flash from the Host UI flash program.
// The firmware len is the first two bytes in each FW address section in flash
unsigned int fwLen;
if(spi_flash_read_data(buf, address, USER_FLASH_QPI_FWSIZE_HDR) == USER_FLASH_QPI_FWSIZE_HDR) {
fwLen = (buf[0] << 8) | buf[1];
address += USER_FLASH_QPI_FWSIZE_HDR;
}
unsigned char data_ptr[USER_FLASH_QPI_CI_BLK_SIZE];
// calculate the number of flash reads. Each read is of USER_FLASH_QPI_CI_BLK_SIZE bytes
int n = fwLen/USER_FLASH_QPI_CI_BLK_SIZE + 1;
for(int i=0; i < n; i++) {
// read the QPI FW from Flash. This can be FW, Degamma Table, LUM Tables
unsigned int ret = spi_flash_read_data(data_ptr, address + i*USER_FLASH_QPI_CI_BLK_SIZE,
USER_FLASH_QPI_CI_BLK_SIZE);
uart2_write(data_ptr, USER_FLASH_QPI_CI_BLK_SIZE, NULL);
uart2_finish_transfers();
}
}

- In this function, I am reading USER_FLASH_QPI_CI_BLK_SIZE = 256 bytes at a time from Flash and write over the UART2.

Function 2:
- this function reads from the data coming in from the BLE line and send that across the UART2 bus to the external MCU. Below is the code:

void user_ble_push(uint8_t* wrdata, uint16_t write_amount)
{
ASSERT_ERR(wrdata != NULL);
ASSERT_ERR(write_amount != 0);

bool send_flow_off = false;

// write the BLE "data" to the peripheral buffer "ble_to_periph_buffer"
user_buffer_write_items(&ble_to_periph_buffer, wrdata, write_amount);

//check if buffer is almost full and issue to send a XOFF if so
send_flow_off = user_check_buffer_almost_full(&ble_to_periph_buffer);

//if XOFF must be send, send asap
if(send_flow_off) {
user_send_ble_flow_ctrl(FLOW_OFF);
}
//start transmitting
__disable_irq();

if(!uart_qpi_tx_callbackbusy) {
uart_qpi_tx_callbackbusy = true;
uart_qpi_tx_callback(UART_STATUS_INIT);
}
__enable_irq();
}

——这个函数是需求方样本品的一部分ation firmware. I modified it to use for our own application. uart_qpi_tx_callback() is the same as what's in the DSPS sample. Below is the code for this function for your reference:

static void uart_qpi_tx_callback(uint8_t res)
{
static uint8_t size=0;
uint8_t *periph_tx_ptr = NULL;

//function gets called from uart transmit isr or application when its not running
switch(res)
{
case UART_STATUS_OK:
//get data and pointer
size = user_periph_pull(&periph_tx_ptr, size);
break;
case UART_STATUS_INIT:
size = user_buffer_read_address(&ble_to_periph_buffer, &periph_tx_ptr, TX_CALLBACK_SIZE);
break;
default:
ASSERT_ERROR(0); //error: callback called from unknown source
}
//if there is data available, send data over periph
if(size > 0) {
uart2_write(periph_tx_ptr, size, &uart_qpi_tx_callback);
return;
}
//there is no data in the buffer so the callback is done
uart_qpi_tx_callbackbusy = false;
}

Now my questions/issues with the two functions above::

1. In function 1, I was actually using the UART write with size 256 bytes. I know that the TX FIFO size is only 16 bytes. Why and how did this even work in my case. I am not complaining. I just would like to understand it better.

2.在函数二,我有问题发送任何东西more than 16 bytes to the external MCU. If I sent 16 bytes or less, the MCU received everything. If I sent a packet that is more than 16 bytes, the bytes beyond the 16th byte will not be received. However, if I were to step into the uart2_write() function one line at a time and walk through the uart2_thr_empty_isr() inside uart2_write(), I can see all the data and the data will end up be received by the external MCU correctly. This will happen every time. If I step into the code, it will work. If I let the code run, It will fail every time.

Please let me know what you see and explain to me what's going on?

Thank you for your attention,
--Khai

Device:
MT_dialog
Offline
Last seen:1 month 3 weeks ago
Staff
Joined:2015-06-08 11:34
Hi kqtrinh,

Hi kqtrinh,

1. The FIFO has 16 bytes but that doesn't mean that you can only send 16 bytes at a time, i mean that as long as you keep on pushing data in the FIFO then the UART will output the data and you can keep on pushing data as long as the FIFO has room (if the FIFO has room for additional bytes is checked by the uart2_txfifo_full_getf() ), if the FIFO is full and you keep on pushing data, that means that the data will be overwritten and apparently you will have missing bytes. In the UART driver the first 16 bytes are pushed from the uart2_write() function and as soon as the uart2_txfifo_full_getf() returns 0 (no more room in the FIFO) the function will return and wait for the UART FIFO to get empty, as soon as it gets empty, a UART interrupt will hit indicating an empty FIFO and the uart2_thr_empty_isr() is getting invoked in interrupt context in order to re-fill the FIFO.

2.Regarding the fact that you can see all the data when stepping through the code, and only 16 bytes if run the code normally, i can only assume that this is because manually and via stepping through the code the UART FIFO has time to take the data provided by the MCU and print it out, so there is always room in the UART FIFO (the while(uart2_txfifo_full_getf()) function is always non zero, so all the printing is done from the uart2_thr_empty_isr() which is invoked by the uart2_write()). But in the real case where the processor runs at full speed and you invoke the uart2_write() after the first 16 bytes the FIFO will get full and the uart2_thr_empty_isr() is going to return and wait until the UART FIFO to print all its data, after that a UART interrupt will occur in order to notify that the FIFO is empty and you can push more data into the FIFO, so the UART2_Handler() will get invoked and in order for the uart2_thr_empty_isr() to fill in the next batch of 16 bytes, so apparently the uart2_thr_empty_isr() from the UART2_Handler never gets invoked. I trust that most probably this is the reason why you get only 16 bytes of data in the second case, but you need more debugging on this since this is only an assumption and i cannot forsee what will happen in that case and what is the exact reason that you aren't able to get data on the other side.

Thanks MT_dialog

kqtrinh
Offline
Last seen:3 years 9 months ago
Joined:2016-08-24 00:17
Hi MT,

Hi MT,

Thanks for walking me thru the uart2_write() mechanism. With your explanation of how the FIFO works, I simply placed a 1 msec wait per 16 bytes transaction to allow the FIFO time to empty its data before the next 16 byte chunk is sent again. This works like a champ.

Thank you,
--Khai