UART write buffer with PDC - c

I'm having a problem with writing to a USARt using const char buffer and char arrray.
Here is my UART write function:
unsigned int USART_Send( unsigned char *p_pucData,
unsigned int p_unLen)
{
AT91C_BASE_US2->US_TPR = (unsigned int)p_pucData;
AT91C_BASE_US2->US_TCR = p_unLen;
AT91C_BASE_US2->US_PTCR = AT91C_PDC_TXTEN;
while((AT91C_BASE_US2->US_CSR & ((0x1 << 11) | (0x1 << 4) ) ) == 0);
AT91C_BASE_US2->US_PTCR = AT91C_PDC_TXTDIS;
return p_unLen;
}
Below function working with const char* like:
USART_Send("IsitDone?",9); //Working
If I use a array buffer like below it is showing garbage characters, wonder why ?
unsigned char arr[10];
memcpy(arr, "HelloWorld", 10);
USART_Send(arr, sizeof(arr)); //Not working properly displaying Garbage chars

Ricardo Crudo is correct. You run into the following problem:
arr is created on the stack
arr is filled
call USART_Send
fill transmit pointer, counter, enable tx requests
/* peripheral state is TXBUFE = '0' and ENDTX = '0' because: */
/* TXBUFE = '0' when PERIPH_TCR != 0 and */
/* ENDTX = '0' when PERIPH_TCR != 0 */
/* but we just wrote to PERIPH_TCR, so it's != 0 */
/* both conditions are satisfied, b/c the transfer hasn't started yet! */
wait until (TXBUFE = '0' and ENDTX = '0')
/* your code thinks PDC is done here */
/* but in reality, PDC is getting started */
disable tx requests
return from sub-function
overwrite stack (and arr) with unrelated data here
/* PDC might push out last word(s) here due to pipelining/ */
/* instruction cache/side effects/you-name-it */
/* even though its matrix requests were disabled a few cycles ago */
Solutions:
copy to a global buffer or
wait some cycles between enabling tx requests and checking if the PDC is done (possibly a whole baud tick) or
read back PERIPH_TCR and check if it's zero instead of checking the flags
Ideally, you would allocate some dynamic memory for strings and deallocate it after the PDC is done asynchronously to your actual code. You might want to check if you can get some kind of interrupt after the PDC/peripheral is done, then deallocate the memory it read from.
If you don't have dynamic memory allocation, then use the a global ring buffer and abstract your string/char send function to use this buffer instead.

Related

Pass array that is part of struct as uint8_t pointer to function

I am working with the Renesas RA2A1 using their Flexible software package, trying to send data over a uart.
I am sending ints and floats over the uart, so I created a union of a float and a 4 byte uint8_t array, same for ints.
I put a few of these in a struct, and then put that in a union with an array that is the size of all the data contained in the struct.
I can't get it to work by passing the array in the struct to the function.. If I create an array of uint8_t, that passes in and works OK... I'm not sure what's wrong with trying to pass the array as I am.
It is failing an assert in R_SCI_UART_WRITE that checks the size, which is failing because it is 0.
typedef union{
float num_float;
uint32_t num_uint32;
int32_t num_int32;
uint8_t num_array[4];
} comms_data_t;
typedef struct{
comms_data_t a;
comms_data_t b;
comms_data_t c;
comms_data_t d;
comms_data_t e;
uint8_t lr[2];
} packet_data_t;
typedef union{
packet_data_t msg_packet_data;
uint8_t packet_array[22];
}msg_data_t;
/* Works */
uint8_t myData[10] = "Hi Dave!\r\n";
uart_print_main_processor_msg(myData);
/* Doesn't work */
msg_data_t msg_data;
/* code removed that puts data into msg_data,ex below */
msg_data.msg_packet_data.a.num_float = 1.2f;
uart_print_main_processor_msg(msg_data.packet_array);
// Functions below
/****************************************************************************************************************/
fsp_err_t uart_print_main_processor_msg(uint8_t *p_msg)
{
fsp_err_t err = FSP_SUCCESS;
uint8_t msg_len = RESET_VALUE;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
char *p_temp_ptr = (char *)p_msg;
/* Calculate length of message received */
msg_len = ((uint8_t)(strlen(p_temp_ptr)));
/* Reset callback capture variable */
g_uart_event = RESET_VALUE;
/* Writing to terminal */
err = R_SCI_UART_Write (&g_uartMainProcessor_ctrl, p_msg, msg_len);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Write API Failed **\r\n");
return err;
}
/* Check for event transfer complete */
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
APP_ERR_PRINT ("\r\n** UART Error Event Received **\r\n");
return FSP_ERR_TRANSFER_ABORTED;
}
}
if(RESET_VALUE == local_timeout)
{
err = FSP_ERR_TIMEOUT;
}
return err;
}
fsp_err_t R_SCI_UART_Write (uart_ctrl_t * const p_api_ctrl, uint8_t const * const p_src, uint32_t const bytes)
{
#if (SCI_UART_CFG_TX_ENABLE)
sci_uart_instance_ctrl_t * p_ctrl = (sci_uart_instance_ctrl_t *) p_api_ctrl;
#if SCI_UART_CFG_PARAM_CHECKING_ENABLE || SCI_UART_CFG_DTC_SUPPORTED
fsp_err_t err = FSP_SUCCESS;
#endif
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
err = r_sci_read_write_param_check(p_ctrl, p_src, bytes);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
FSP_ERROR_RETURN(0U == p_ctrl->tx_src_bytes, FSP_ERR_IN_USE);
#endif
/* Transmit interrupts must be disabled to start with. */
p_ctrl->p_reg->SCR &= (uint8_t) ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);
/* If the fifo is not used the first write will be done from this function. Subsequent writes will be done
* from txi_isr. */
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth > 0U)
{
p_ctrl->tx_src_bytes = bytes;
p_ctrl->p_tx_src = p_src;
}
else
#endif
{
p_ctrl->tx_src_bytes = bytes - p_ctrl->data_bytes;
p_ctrl->p_tx_src = p_src + p_ctrl->data_bytes;
}
#if SCI_UART_CFG_DTC_SUPPORTED
/* If a transfer instance is used for transmission, reset the transfer instance to transmit the requested
* data. */
if ((NULL != p_ctrl->p_cfg->p_transfer_tx) && p_ctrl->tx_src_bytes)
{
uint32_t data_bytes = p_ctrl->data_bytes;
uint32_t num_transfers = p_ctrl->tx_src_bytes >> (data_bytes - 1);
p_ctrl->tx_src_bytes = 0U;
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
/* Check that the number of transfers is within the 16-bit limit. */
FSP_ASSERT(num_transfers <= SCI_UART_DTC_MAX_TRANSFER);
#endif
err = p_ctrl->p_cfg->p_transfer_tx->p_api->reset(p_ctrl->p_cfg->p_transfer_tx->p_ctrl,
(void const *) p_ctrl->p_tx_src,
NULL,
(uint16_t) num_transfers);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
}
#endif
#if SCI_UART_CFG_FLOW_CONTROL_SUPPORT
if ((((sci_uart_extended_cfg_t *) p_ctrl->p_cfg->p_extend)->uart_mode == UART_MODE_RS485_HD) &&
(p_ctrl->flow_pin != SCI_UART_INVALID_16BIT_PARAM))
{
R_BSP_PinAccessEnable();
R_BSP_PinWrite(p_ctrl->flow_pin, BSP_IO_LEVEL_HIGH);
R_BSP_PinAccessDisable();
}
#endif
/* Trigger a TXI interrupt. This triggers the transfer instance or a TXI interrupt if the transfer instance is
* not used. */
p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth == 0U)
#endif
{
/* On channels with no FIFO, the first byte is sent from this function to trigger the first TXI event. This
* method is used instead of setting TE and TIE at the same time as recommended in the hardware manual to avoid
* the one frame delay that occurs when the TE bit is set. */
if (2U == p_ctrl->data_bytes)
{
p_ctrl->p_reg->FTDRHL = *((uint16_t *) (p_src)) | (uint16_t) ~(SCI_UART_FIFO_DAT_MASK);
}
else
{
p_ctrl->p_reg->TDR = *(p_src);
}
}
return FSP_SUCCESS;
#else
FSP_PARAMETER_NOT_USED(p_api_ctrl);
FSP_PARAMETER_NOT_USED(p_src);
FSP_PARAMETER_NOT_USED(bytes);
return FSP_ERR_UNSUPPORTED;
#endif
}
There are several issues with this program. A large part of this code relies on undefined behavior. Unions are also UB if used for aliasing, even if pretty much all C compilers tend to allow it, but if you are using a union I would still prefer using a char[] for the array used for aliasing. As mentioned in the comments, "Hi Dave!\r\n"; actually takes up 11 bytes with the null-character. It's safer to use uint8_t myData[] = "Hi Dave!\r\n"; or const * uint8_t = "Hi Dave!\r\n"; and spare yourself the trouble.
Second problem is that strlen cannot work correctly for binary data. strlen works by searching for the first occurrence of the null-character in the string, so it's not applicable for binary data. If you pass a floating point value which has a single zero byte in its IEEE 754 representation, it will mark the end of this "string".
Plain and simple, your function should be declared as fsp_err_t uart_write(const char * msg, size_t msg_len); and be called using uart_write(data_array, sizeof data_array);. If you want to transmit messages of variable size over the UART, you will also have to define a certain communication protocol, i.e. create a message that can be unambiguously parsed. This will likely mean: 1) some cookie at the beginning, 2) length of the transmitted data, 3) actual data, 4) crc -- but this is outside the scope of this question.
So, strlen won't tell you the length of the data, you will pass it to the function yourself, and you don't need unions at all. If you choose not to properly serialize the data (e.g. using protobuf or some other protocol), you can simply pass the pointer to the struct to the function, i.e. call the above mentioned uart_write((char*)&some_struct, sizeof some_struct); and it will work as if you passed an array.
Note that char in this case doesn't mean "ascii character", or "character in a string". The point with using the char* is that it's the only pointer which is legally allowed to alias other pointers. So, you acquire a pointer to your struct (&str), cast it to a char*, and pass it to a function which can then read its representation in memory. I am aware that R_SCI_UART_Write is likely generated by your IDE, and unfortunately these blocks often use uint8_t* instead of char*, so you will probably have to cast to uint8_t* at some point.

sprintf re-entry into 64bit operation in 32 bit MCU with interrupts

In reference to SO question: 52164135
The setup:
I have a function which converts many double values into a predefined string. The input is a array of struct from which we concatenate two double values into a string. A double is of size 8 bytes or 64 bits and my MCU of operation is STM32, a 32 bit ARM micro-controller.
An interrupt is also running parallelly.
The data should look like:
[[12.11111111,12.11111111],[12.22222222,12.22222222],...]
But I get (very rarely):
[[12.11111111,12.11111111],[55.01[12.33333333,12.33333333],...]
Note: I missed out [12.22222222,12.22222222]
sprintf is not re-entrant:
According to this discussion, on AVRFreaks, sprintf is not re-entrant. (The discussion is on using sprintf in a interrupt enabled hardware environment.) Which means if an interrupt occurs in-between a sprintf operation the stack fails to continue the operation it was doing.
Since my MCU is a 32 bit one, to perform a 64 bit operation it will take two clock cycles. And if we assume an interrupt occurred in between the sprintf operation according the the above discussion sprintf should fail.
Question
1. Will sprintf fail in case it is interrupted?
Here is the string function, an interrupt routine also runs in the background which deals with other sensor data (local and global)
/* #brief From the array of GPS structs we create a string of the format
* [[lat,long],[lat,long],..]
* #param input The input array of GPS structs
* #param output The output string which will contain lat, long
* #param sz Size left in the output buffer
* #return 0 Successfully completed operation
* 1 Failed / Error
*/
int get_gps60secString(GPS_periodic_t input[GPS_PERIODIC_ARRAY_SIZE],
char *output, size_t sz)
{
int cnt = snprintf(output, sz, "[");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
int i = 0;
for (i = 0; i < GPS_PERIODIC_ARRAY_SIZE; i++) {
cnt = snprintf(output, sz, "[%0.8f,%0.8f]%s",
input[i].point.latitude, input[i].point.longitude,
i + 1 == GPS_PERIODIC_ARRAY_SIZE ? "" : ",");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
}
cnt = snprintf(output, sz, "]");
if (cnt < 0 || cnt >= sz)
return 1;
return 0; // no error
}
What's happening inside the interrupt routine
void GPS_InterruptHandler(UART_HandleTypeDef *UartHandle)
{
gps_UART_RxInterrupt_Disable();
GPS_t l_sGpsInfo;
memset(&l_sGpsInfo,0,sizeof(GPS_t));
status=Validate_get_gpsInfo((char*)g_gps_readBuff,&l_sGpsInfo,100);
MEMS_interruptHandler(); //Inertial sensor ISR
gps_UART_RxInterrupt_Enable();
}
sprintf will ony fail during an interrupt if it is called again during that interrupt (assuming it uses global variables that are re-used; would it use only stack variables, then it is re-entrant).
So if your interrupt handler is calling sprintf and during that call a new, same or higher priority interrupt occurs then it can fail. However, during the processing of an interrupt, interrupts are normally disabled so there can't (shouldn't!) be another interupt of the same type occurring.
But why convert this raw data during interrupt handling? Why not store/pass this data to the user-level routine via a buffer and have that functionality convert the raw data? That would be consistent with the idea that an interrupt handler should be as short (fast) as possible.

How can the index in this code snippet ever reach 2154? (gcc, embedded C, ARM Cortex M0)

I'm writing a driver for a GSM modem running on an ARM Cortex M0. The only UART on the system is in use for talking to the modem, so the best I can do for logging the UART conversation with the modem is to build up a string in memory and watch it with GDB.
Here are my UART logging functions.
// Max number of characters user in the UART log, when in use.
#define GSM_MAX_UART_LOG_CHARS (2048)
static char m_gsm_uart_log[GSM_MAX_UART_LOG_CHARS] = "";
static uint16_t m_gsm_uart_log_index = 0;
// Write a character to the in-memory log of all UART messages.
static void gsm_uart_log_char(const char value)
{
m_gsm_uart_log_index++;
if (m_gsm_uart_log_index > GSM_MAX_UART_LOG_CHARS)
{
// Clear and restart log.
memset(&m_gsm_uart_log, 0, GSM_MAX_UART_LOG_CHARS); // <-- Breakpoint here
m_gsm_uart_log_index = 0;
}
m_gsm_uart_log[m_gsm_uart_log_index] = value;
}
// Write a string to the in-memory log of all UART messages.
static void gsm_uart_log_string(const char *value)
{
uint16_t i = 0;
char ch = value[i++];
while (ch != '\0')
{
gsm_uart_log_char(ch);
ch = value[i++];
}
}
If I set a breakpoint on the line shown above, the first time it's reached, m_gsm_uart_log_index is already well over 2048. I've seen 2154 and a bunch of other values between 2048 and 2200 or so.
How is this possible? There's no other code that touches m_gsm_uart_log_index anywhere.
You have a buffer overflow happening which could trample on m_gsm_uart_log_index.
The check for end of buffers should be:
if (m_gsm_uart_log_index >= GSM_MAX_UART_LOG_CHARS) {
...
}
As it stands, m_gsm_uart_log_index can reach 2048, and so writing m_gsm_uart_log_index[2048] is likely to be at the location where m_gsm_uart_log_index is stored.
You are writing to the buffer when m_gsm_uart_log_index == GSM_MAX_UART_LOG_CHARS, which means that you are overrunning the buffer by 1 character. This writes into the first byte of m_gsm_uart_log_index and corrupts it.
Change:
if (m_gsm_uart_log_index > GSM_MAX_UART_LOG_CHARS)
to:
if (m_gsm_uart_log_index >= GSM_MAX_UART_LOG_CHARS)

C char array address issue

I am having a problem in C with addressing char array in a structure. When I write characters in the array it writes them in word boundaries and not character boundaries. Here is the structure declaration.
typedef struct RxBuffer {
int Status;
int ByteCount;
int Index;
char Data[SCI_BUFFER_LENGTH];
} RxBuffer;
and here is the code that actually does the write,
RxBuffer SciaRxBuffer;
char SciaRxData;
int LoopBackCrFlag;
int RxDataReady;
interrupt void scia_rx_isr()
{
// Get Rx Data and first LoopBack
SciaRxData = SciaRegs.SCIRXBUF.all; // Read data
SciaRegs.SCITXBUF = SciaRxData; // Send loop back Tx data
// Check to see if carriage return
if (SciaRxData == CR)
{
// Set the loopback flag so Line-feed is transmitted
LoopBackCrFlag = TRUE;
}
//!
//! Problem is right here. SciaRxData is being written into
//! SciaRxBuffer.Data[SciaRxBuffer.ByteCount++] on Word
//! boundaries instead of byte boundaries.
//!
// Stuff RxBuffer & Mark as busy
SciaRxBuffer.Data[SciaRxBuffer.ByteCount++] = SciaRxData;
SciaRxBuffer.Status = RX_BUSY;
if (SciaRxData == CR)
{
SciaRxBuffer.Status = RX_READY;
SciaRxBuffer.Index = 0;
RxDataReady = TRUE;
}
// Clear Overflow and interrupt flags
SciaRegs.SCIFFRX.bit.RXFFOVRCLR = 1; // Clear Overflow flag
SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1; // Clear Interrupt flag
// Issue the PIE ack
PieCtrlRegs.PIEACK.all|=0x100;
}
Any help is welcome
Best Regards,
Steve Mansfield
Thank you for everyone's input. I just did some digging into the hardware and found out that the TI DSP that I am using does not support byte operations. It's smallest operation is a word (2 bytes). Even though I declared the array as a char array, when I write to the array it writes it as an integer. If I want to handle byte operations I will have to shift left the first character 8 bits and then OR the next character and then write it into the array. Like everyone always says, if there is a problem with the hardware -- fix it in software!
Best Regards,
Steve Mansfield

How is this tcp socket code handling the rx buffer?

I came across this tcp server example, provided with the Altera Nios II processor, and I'm not getting the section on handling the rx_buffer.
server.h
typedef struct SSS_SOCKET {
enum {
READY, COMPLETE, CLOSE
} state;
int fd;
int close;
INT8U rx_buffer[SSS_RX_BUF_SIZE];
INT8U *rx_rd_pos; /* position we've read up to */
INT8U *rx_wr_pos; /* position we've written up to */
} SSSConn;
server.c
int data_used = 0, rx_code = 0;
INT8U *lf_addr;
conn->rx_rd_pos = conn->rx_buffer;
conn->rx_wr_pos = conn->rx_buffer;
printf("[sss_handle_receive] processing RX data\n");
while (conn->state != CLOSE) {
/* Find the Carriage return which marks the end of the header */
lf_addr = strchr(conn->rx_buffer, '\n');
if (lf_addr) {
/* go off and do whatever the user wanted us to do */
sss_exec_command(conn);
}
/* No newline received? Then ask the socket for data */
else {
rx_code = recv(conn->fd, conn->rx_wr_pos,
SSS_RX_BUF_SIZE - (conn->rx_wr_pos - conn->rx_buffer) -1, 0);
if (rx_code > 0) {
conn->rx_wr_pos += rx_code;
/* Zero terminate so we can use string functions */
*(conn->rx_wr_pos + 1) = 0;
}
}
/*
* When the quit command is received, update our connection state so that
* we can exit the while() loop and close the connection
*/
conn->state = conn->close ? CLOSE : READY;
/* Manage buffer */
data_used = conn->rx_rd_pos - conn->rx_buffer;
memmove(conn->rx_buffer, conn->rx_rd_pos,
conn->rx_wr_pos - conn->rx_rd_pos);
conn->rx_rd_pos = conn->rx_buffer;
conn->rx_wr_pos -= data_used;
memset(conn->rx_wr_pos, 0, data_used);
}
Specifically, I don't see the purpose of the data_used variable. rx_rd_pos is pointing to rx_buffer and there doesn't appear to be an operation on either, so how will they be different? In fact, the only thing that seems to happen under Manage buffer is the copying of data into rx_buffer. I'm sure I'm missing something simple, but I can't seem to see it.
Thanks for any help in advance.
Edit: Here's the sss_exec_command() function.
void sss_exec_command(SSSConn* conn) {
int bytes_to_process = conn->rx_wr_pos - conn->rx_rd_pos;
INT8U tx_buf[SSS_TX_BUF_SIZE];
INT8U *tx_wr_pos = tx_buf;
INT8U error_code;
/*
* "SSSCommand" is declared static so that the data will reside
* in the BSS segment. This is done because a pointer to the data in
* SSSCommand
* will be passed via SSSLedCommandQ to the LEDManagementTask.
* Therefore SSSCommand cannot be placed on the stack of the
* SSSSimpleSocketServerTask, since the LEDManagementTask does not
* have access to the stack of the SSSSimpleSocketServerTask.
*/
static INT32U SSSCommand;
SSSCommand = CMD_LEDS_BIT_0_TOGGLE;
while (bytes_to_process--) {
SSSCommand = toupper(*(conn->rx_rd_pos++));
if (SSSCommand >= ' ' && SSSCommand <= '~') {
tx_wr_pos += sprintf(tx_wr_pos,
"--> Simple Socket Server Command %c.\n",
(char) SSSCommand);
if (SSSCommand == CMD_QUIT) {
tx_wr_pos += sprintf(tx_wr_pos,
"Terminating connection.\n\n\r");
conn->close = 1;
} else {
error_code = OSQPost(SSSLEDCommandQ, (void *) SSSCommand);
alt_SSSErrorHandler(error_code, 0);
}
}
}
send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0);
return;
}
Answers below are correct. I missed the pointer arithmetic on rx_rd in the command function :P
That section removes data from the buffer once it has been processed. The code you posted never uses the data stores in the buffer, but the sss_exec_command function will, after a newline is received. That function is passed the connection, so it can increment the read position by however much it uses.
After data is used, the buffer management section reclaims the space. The amount of data left in the buffer is the difference between the write and read positions. This much data is moved from the write position to the start of the buffer, then the read and write pointer are updated to their new positions. The read position is set to the start of the buffer, and the write position is decremented by data_used, which is the original difference between the start of the buffer and the read pointer, i.e. the amount of data used.
Assuming the code actually works, then data_used = conn->rx_rd_pos - conn->rx_buffer implies rx_rd_pos is being changed; this would be being changed when the code has consumed the data written into the buffer (it's written in at rx_wr_pos and consumed from rx_rd_pos). This would imply that sss_exec_command(conn) is adjusting conn. Is that the case?

Resources