GPS UART data written multiple times to Buffer - c

I am receiving/reading data from a GPS module sent via USART3 to the STM32F091.
The data gets there just fine which I confirm by sending it to my PC COM3 port and feeding it to 'u-center' (GPS evaulation software).
My problem is that I want to evaluate the data myself in my C program, and for that purpose I feed it into a Ring Buffer, however, every character of the GPS signal is written multiple times to the buffer, instead of one by one.
For example
GGGGGGGPPPPPPPPSSSSSSSS instead of GPS
I am unsure what I'm doing wrong, maybe it's something really obvious I'm overlooking after staring at this code so long.
Here's the relevant code.
stm32f0xx_it.c
#include <main.h>
void USART3_8_IRQHandler(void)
{
if (USART_FLAG_RXNE != RESET)
{
uint16_t byte = 0;
/* Data reception */
/* Clear Overrun Error Flag, necessary when RXNE is used */
USART_GetITStatus(USART3, USART_IT_ORE);
/* Read from Receive Data Register and put into byte */
byte = USART_ReceiveData(USART3);
(*pRXD3).wr = ((*pRXD3).wr + 1) % (*pRXD3).max;
(*pRXD3).Buffer[(*pRXD3).wr] = byte;
/* Send Data to PC, and reset Transmission Complete Flag */
USART_GetITStatus(USART1, USART_IT_TC);
USART_SendData(USART1, byte);
return;
}
return;
}
uartGPS.h
....
struct GPSuart
{
BYTE Buffer[255];
WORD max;
WORD re;
WORD wr;
};
....
main.h
....
extern volatile BYTE B_ser_txd_3[255];
extern volatile BYTE B_ser_rxd_3[255];
extern volatile struct GPSuart TXD_uart_3;
extern volatile struct GPSuart RXD_uart_3;
extern volatile struct GPSuart *pRXD3;
extern volatile struct GPSuart *pTXD3;
....
Let me know if I should provide additional information.

This:
if (USART_FLAG_RXNE != RESET)
does not test a flag, that code is inspecting the flag constant itself, which is not what you meant.
You need more code, to access the UART's status register and check the flag:
if (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) != RESET)

Related

STM32F411E-DISCO Uart circular buffer on interrupts

I would like to receive and transmit data that will be put into a circular buffer. I have functions for inserting characters and reading characters.
How can I use these functions and where should I put them? Currently I transmit and receive what I send to the terminal and it works fine.
I am just learning, please give me some advice
#define UART_RX_BUF_SIZE 7
#define UART_TX_BUF_SIZE 7
int8_t uart_put_char(char data);
int8_t uart_get_char(char *data);
volatile char uart_rxBuff[UART_RX_BUF_SIZE];
volatile char uart_txBuff[UART_TX_BUF_SIZE];
void uart_put_string(char *s);
typedef struct {
volatile char *const buffer;
uint8_t head;
uint8_t tail;
} circ_buffer_t;
volatile circ_buffer_t uart_rx_circBuff = {uart_rxBuff, 0, 0};
volatile circ_buffer_t uart_tx_circBuff = {uart_txBuff, 0, 0};
uint8_t received_char;
int8_t uart_put_char(char data) {
uint8_t head_temp = uart_tx_circBuff.head + 1;
if (head_temp == UART_TX_BUF_SIZE)
head_temp = 0;
if (head_temp == uart_tx_circBuff.tail)
return 0;
uart_tx_circBuff.buffer[head_temp] = data;
uart_tx_circBuff.head = head_temp;
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
return 1;
}
int8_t uart_get_char(char *data) {
if (uart_rx_circBuff.head == uart_rx_circBuff.tail)
return 0;
uart_rx_circBuff.tail++;
if (uart_rx_circBuff.tail == UART_RX_BUF_SIZE)
uart_rx_circBuff.tail = 0;
*data = uart_rx_circBuff.buffer[uart_rx_circBuff.tail];
return 1;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// uart_put_char(&received_char);
HAL_UART_Transmit(&huart1, &received_char, 1, 100);
// uart_get_char(received_char);
HAL_UART_Receive_IT(&huart1, &received_char, 1);
}
}
I want to put a side-note first, so it doesn't get missed:
I would suggest incrementing your head and tail indices after you've put the byte in the buffer. So, upon initialisation, head is 0. When you call put_tx, the byte will be stored at index 0 and then be incremented to 1. When the interrupt calls get_tx, the tail is still 0 so you'll get that first character, then it'll be incremented to 1. Doesn't really matter, but I think it's easier to write clean code if you think in this way.
Also, it's totally a micro-optimisation, but think about setting your buffer size to a power of 2. That way, instead of going if (head==BUF_SIZE) head=0; you can go head &= BUF_SIZE-1; and you'll save a few clock cycles, no need for a test. ;-)
It definitely is a pain to set up, but very much worth it if you can get around the multiple steps. The HAL will probably handle much of this for you, but I don't know enough about that.
You need an interrupt handler for UART events.
You need to tell the UART to raise interrupts for RXNE (receive not empty), and TXE (transmit empty) when you've sent a character.
You need to tell the NVIC to enable the UART interrupt.
I definitely recommend having push and pop (or put and get) functions for both buffers. The interrupts will call put_rx and get_tx, while user code will call put_tx and get_rx. Or better yet, write some wrapper functions, like Uart_Send(char), Uart_SendBuffer(const char*, size_t), Uart_TryReceive(char*, size_t) that will call put_tx and get_rx.
If the HAL is as smart as I think it is, you can can probably combine steps 1-3 into a single step, and just implement HAL_UART_RxCpltCallback (as you've done) and HAL_UART_TxCpltCallback.
I don't know how the HAL works enough to give you an exact solution (all my STM32 work is built on headers I made myself before I realised even CMSIS existed - whoops!) so here's how I would do it in low-level code.
void USART1_IRQHandler() __attribute__((interrupt))
{
// This would probably be handled in HAL_UART_RxCpltCallback
if (USART1->SR.RXNE) // We've received a byte!
uart_push_rx(USART1->DR); // Push the received byte onto the back
// of the RX buffer.
// This would probably be handled in HAL_UART_TxCpltCallback
if (USART1->SR.TXE) // Transmit buffer is empty - send next byte
{
char nextByte;
if (uart_pop_tx(&nextByte)) // Get the next byte in the buffer and
USART1->DR = nextByte; // shove it in the UART data register.
else // No more data in the circular buffer,
USART1->CR1.TXEIE = 0; // so disable the TXE interrupt or we'll
// end up stuck in a loop.
}
if (USART1->SR.TC) // There's also a flag for 'transmit complete'. This
{ } // is different from TXE in that TXE means "Okay, I've started this
// one, tell me what'll come next," whereas TC says "Okay, I've
// finished sending everything now. Anything else, boss?"
// We won't use it, but be aware of the terminology. The HAL might
// try and confuse you with its words.
}
void InitialiseUart()
{
HAL_UART_Configure(&huart1, baud, stopBits, andStuff, probably, etc);
HAL_UART_Enable(&huart1);
// You probably don't need to worry about anything below here,
// if the HAL is smart. But I've included it for completeness,
// so you can understand more of what the MCU is doing.
// Enable RXNE (receive not empty) interrupt
USART1->CR1.RXNEIE = 1;
// Don't enable TXE (transmit empty) interrupt yet. Only when you send
// a character, or the interrupt will fire immediately.
// Enable UART interrupts at the system level
NVIC_EnableIRQ(USART1_IRQn);
}
If you need me to, I'll look into the HAL code and try and give you some more direct guidance, but I think it's valuable to take this, understand it, and translate it to your implementation.
I've had a closer look at the HAL source code, and it looks like by using the HAL_xxxx_IT() functions, all the interrupt code is already handled for you. That said, there are a lot of similarities to doing it in bare metal in your application, since you're only sending and receiving one character at a time.
When you call __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE) you're telling the microcontroller to fire an interrupt when the data register is empty. But the HAL interrupt routine doesn't know what to transmit, so it'll send out garbage until it thinks it's finished.
I think another problem might be caused by directly accessing your circular buffer in multiple places, causing clashes. You'd be better off calling your HAL functions with a temporary buffer (or pointer to a single char) that either is taken from, or stores into, your circular buffer.
Main function
// Entry point
int main(void)
{
// Initialise system and peripherals
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM10_Init();
// Enable interrupts
HAL_NVIC_EnableIRQ(USART1_IRQn);
// Prepare reception of the first character
HAL_UART_Receive_IT(&huart1, &received_char, 1);
while (1)
{
char downloaded;
if (UartReceiveChar(&downloaded) && downloaded == 'x')
UartSendChar(downloaded);
}
}
UART wrapper
// Function declarations
int8_t UartSendChar (char data);
void UartSendString (char* str);
int8_t UartReceiveChar (char* data);
// Variables
int8_t isTransmitting = 0;
uint8_t sendingChar;
uint8_t receivedChar;
// Function definitions
// Callback function for when a character has finished sending by the HAL
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
// The HAL has just sent the tail byte from the TX buffer
// If there is still data in the buffer, we want to send the
// next byte in the buffer.
if (buffer_pop_tx(&sendingChar))
HAL_UART_Transmit_IT(huart, &sendingChar, 1);
else
isTransmitting = 0;
}
// Callback function for when a character is received by the HAL
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// The HAL has received a character into 'receivedChar'
// All we need to do is push it onto our circular buffer
buffer_push_rx(receviedChar);
// and prepare to receive the next character
HAL_UART_Receive_IT(huart, &receivedChar, 1);
}
// Send a character
int8_t UartSendChar(char data)
{
// Push the character onto the buffer
int8_t returnValue = buffer_push_tx(data);
// Start sending the buffer, if we're not already transmitting
if (!isTransmitting)
{
sendingChar = data;
isTransmitting = 1;
HAL_UART_Transmit_IT(&huart1, &sendingChar, 1);
}
return returnValue;
}
// Send a null-terminated string
int8_t UartSendString(char* str)
{
// Iterate through all the non-null characters
while (*str)
{
// Send the character; Wait if the buffer is full
while (!UartSendChar(*str)) ;
++str;
}
return 1;
}
// Receive a character
int8_t UartReceiveChar(char* data)
{
// Just a wrapper for buffer_pop_rx
return buffer_pop_rx(data);
}
Buffer implementation
// I've changed your circular buffer size for optimisation purposes
#define UART_RX_BUF_SIZE 8
#define UART_TX_BUF_SIZE 8
// Buffer type definition
typedef struct
{
volatile char *const buffer;
uint8_t head;
uint8_t tail;
uint8_t isFull : 1;
uint8_t isEmpty : 1;
uint8_t hasOverflowed : 1; // Overflow and underflow are only relevant if we choose to
uint8_t hasUnderflowed : 1; // allow pushing and popping with an empty/full buffer
} circ_buffer_t;
// Function declarations
int8_t buffer_push_tx (char data);
int8_t buffer_push_rx (char data);
int8_t buffer_pop_tx (char* data);
int8_t buffer_pop_rx (char* data);
// Variables
volatile char uart_rxBuff[UART_RX_BUF_SIZE];
volatile char uart_txBuff[UART_TX_BUF_SIZE];
volatile circ_buffer_t uart_rx_circBuff = {uart_rxBuff, 0, 0};
volatile circ_buffer_t uart_tx_circBuff = {uart_txBuff, 0, 0};
// Function definitions
// Push a character onto the transmit buffer
int8_t buffer_push_tx(char data)
{
if (uart_tx_circBuff.isFull) // buffer is full
{
// uart_tx_circBuff.hasOverflowed = 1; // Nasty things can happen if we allow overflows. But in some special cases, it may be necessary.
return 0;
}
// Put the character at the head position and increment the head index
uart_tx_circBuff.buffer[uart_tx_circBuff.head++] = data;
uart_tx.circBuff.head &= (UART_TX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_tx_circBuff.isFull = (uart_tx_circBuff.head == uart_tx_circBuff.tail);
uart_tx_circBuff.isEmpty = 0;
// OK
return 1;
}
// Push a character onto the receive buffer
int8_t buffer_push_rx(char data)
{
if (uart_rx_circBuff.isFull) // buffer is full
{
// uart_rx_circBuff.hasOverflowed = 1;
return 0;
}
// Put the character at the head position and increment the head index
uart_rx_circBuff.buffer[uart_rx_circBuff.head++] = data;
uart_rx.circBuff.head &= (UART_RX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_rx_circBuff.isFull = (uart_rx_circBuff.head == uart_rx_circBuff.tail);
uart_rx_circBuff.isEmpty = 0;
// OK
return 1;
}
// Try to get a character from the receive buffer.
int8_t uart_pop_rx(char *data)
{
if (uart_rx_circBuff.isEmpty) // buffer is empty
{
// uart_rx_circBuff.hasUnderflowed = 1;
return 0;
}
// Put the character from the tail position of the buffer into 'data' and increment the tail index
*data = uart_rx_circBuff.buffer[uart_rx_circBuff.tail++];
uart_rx_circBuff.tail &= (UART_RX_BUF_SIZE - 1); // // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_rx_circBuff.isEmpty = (uart_rx_circBuff.head == uart_rx_circBuff.tail);
uart_rx_circBuff.isFull = 0;
// OK
return 1;
}
// Try to get a character from the transmit buffer.
int8_t uart_pop_rx(char *data)
{
if (uart_tx_circBuff.head == uart_tx_circBuff.tail) // buffer is empty
{
// uart_tx_circBuff.hasUnderflowed = 1;
return 0;
}
// Put the character from the tail position of the buffer into 'data' and increment the tail index
*data = uart_tx_circBuff.buffer[uart_tx_circBuff.tail++];
uart_tx_circBuff.tail &= (UART_TX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_tx_circBuff.isEmpty = (uart_tx_circBuff.head == uart_tx_circBuff.tail);
uart_tx_circBuff.isFull = 0;
// OK
return 1;
}

Array's data is changed if I don't printf it

I am writing a C program on Eclipse to communicate from my ARM Cortex M4-F microcontroller in I2C with its master, another MCU.
In my I2C library, I use a static global variable to store all the parameters of the communication (address, lenghts, data buffers). The issue is that a part (an array containing the data to be transmitted, which are 8 bits integers) of this variable gets modified when the interrupt (Start condition followed by the slave's address on the I2C bus) happens, even before executing the code I put the handler. It gets assigned to 8, whatever the initial value.
I tried to put breakpoints basically everywhere, and a watchpoint on the variable, the changes arises seemingly from nowhere, not in the while loop, and before the call to my_I2C_Handler(), so the interrupt is the cause apparently.
I also tried setting the variable as volatile, but that changed nothing.
I noticed one interesting thing: putting a printf of the array's data during my_I2C_Init() or my_SlaveAsync(), like so:
printf("%d\n", req.tx_data[0]);
corrects this problem, but why? I want to remove all prints after debugging.
#include <stdint.h>
#include "my_i2c.h"
void I2C1_IRQHandler(void)
{
printf("\nI2C Interrupt\n");
my_I2C_Handler(MXC_I2C1); // MXC_I2C1 is a macro for the registry used
}
int main(void)
{
int error = 0;
printf("\nStarting I2C debugging\n");
// Setup the I2C
my_I2C_Shutdown(MXC_I2C1);
my_I2C_Init(MXC_I2C1);
NVIC_EnableIRQ(I2C1_IRQn); // Enable interrupt
my_I2C_SlaveAsync(MXC_I2C1); // Prepare to receive communication
while (1)
{
LED_On(0);
LED_Off(0);
}
printf("\nDone testing\n");
return 0;
}
The structure of the request containing the parameters of the communication is like this:
typedef struct i2c_req i2c_req_t;
struct i2c_req {
uint8_t addr; // I2C 7-bit Address
unsigned tx_len; // Length of tx data
unsigned rx_len; // Length of rx
unsigned tx_num; // Number of tx bytes sent
unsigned rx_num; // Number of rx bytes sent
uint8_t *tx_data; // Data for mater write/slave read
uint8_t *rx_data; // Data for master read/slave write
};
Is declared like so in the beginning of the file:
static i2c_req_t req;
and assigned this way in my_I2C_Init():
uint8_t rx[1] = {0};
uint8_t tx[1] = {12};
req.addr = 0xAA;
req.tx_data = tx;
req.tx_len = 1;
req.rx_data = rx;
req.rx_len = 1;
req.tx_num = 0;
req.rx_num = 0;
Many thanks for your help

Problems with code to send request and receive response over UART on Atmel SAM L21 Xplained Pro

I'm currently developing a system which involves sending a request string to a sensor device connected via UART to an Atmel SAML21 Xplained Pro board. I'm testing with an Arduino board as the "sensor device", but eventually, it'll be for a Rotronic HC-2 sensor.
The process goes something like this:
MCU sends string { 99RDD} over UART to sensor
-> delay of up to 500ms
-> Response string of 99 bytes sent back via UART
-> Response transmitted to virtual com port on embedded debugger
My issue is that for some reason, I'm either not getting anything sent back, or it's sending back the variable request_msg
I know that the response from the sensor should be 99 bytes of ASCII, and I've tested both the actual sensor, and the Arduino test board over serial connectors to ensure that the readings are coming back correctly.
The software is using Atmel ASF v4.0, which is great when it works, but the documentation is fairly flaky, so I was hoping someone with more experience could point me as to where I'm going wrong in the code.
I have the following code for my main application:
#include "atmel_start.h"
#include "atmel_start_pins.h"
#include <string.h>
static uint8_t example_hello_world[14] = "Hello World!\n";
static uint8_t example_error_msg[13] = "UART Error!\n";
static uint8_t request_msg[24] = "Sending Sensor Request\n";
static uint8_t rotronic_ascii[8] = "{ 99RDD}";
volatile static uint32_t data_arrived = 0;
volatile static uint32_t reading_received = 0;
static void tx_cb_EDBG_COM(const struct usart_async_descriptor *const io_descr)
{
/* Transfer completed */
gpio_toggle_pin_level(LED0);
}
static void rx_cb_EDBG_COM(const struct usart_async_descriptor *const io_descr)
{
/* Receive completed */
data_arrived = 1;
}
static void err_cb_EDBG_COM(const struct usart_async_descriptor *const io_descr)
{
/* error handle */
io_write(&EDBG_COM.io, example_error_msg, 13);
}
static void tx_cb_COM1(const struct usart_async_descriptor *const io_descr)
{
/* Transfer completed */
gpio_toggle_pin_level(LED0);
}
static void rx_cb_COM1(const struct usart_async_descriptor *const io_descr)
{
/* Receive completed */
reading_received = 1;
}
static void err_cb_COM1(const struct usart_async_descriptor *const io_descr)
{
/* error handle */
io_write(&COM1.io, example_error_msg, 13);
}
int main(void)
{
volatile uint8_t recv_char[99];
atmel_start_init();
// Setup the EDBG Serial Port
usart_async_register_callback(&EDBG_COM, USART_ASYNC_TXC_CB, tx_cb_EDBG_COM);
usart_async_register_callback(&EDBG_COM, USART_ASYNC_RXC_CB, rx_cb_EDBG_COM);
usart_async_register_callback(&EDBG_COM, USART_ASYNC_ERROR_CB, err_cb_EDBG_COM);
usart_async_enable(&EDBG_COM);
// Send a test string to ensure EDBG Serial is working
io_write(&EDBG_COM.io, example_hello_world, 14);
// Setup the Rotronic [Arduino] Serial Port
usart_async_register_callback(&COM1, USART_ASYNC_TXC_CB, tx_cb_COM1);
usart_async_register_callback(&COM1, USART_ASYNC_RXC_CB, rx_cb_COM1);
usart_async_register_callback(&COM1, USART_ASYNC_ERROR_CB, err_cb_COM1);
usart_async_enable(&COM1);
while (1) {
if (reading_received == 0)
{
// Delay for a Bit
delay_ms(5000);
// Notify the EDBG COM Port
io_write(&EDBG_COM.io, request_msg, 24);
// Send the Rotronic ASCII
io_write(&COM1.io, rotronic_ascii, 8);
}
// Check if Reading has been Received
if (reading_received == 1)
{
while (io_read(&COM1.io, &recv_char, 99) == 99)
{
// Write what's on the buffer from the receiver
io_write(&EDBG_COM.io, recv_char, 99);
}
// Reset the flag
reading_received = 0;
}
}
}
You seem to be coding for ASFv3 - v4 will trigger your receive callback for any incoming bytes, not only once when your buffer is full (and you have received every 99 characters).
That means that io_read will most probably never return 99 (because it was only a partial read of your message) and you will most probably never send anything back.
Note the docs say (Scroll down to "different read function behavior..."):
In ASFv4 a data reception type callback in a driver with a ring buffer is triggered for every received data.
The UART apparently is a driver with a ring buffer.
You need to repeatedly call io_read and sum up the number of received bytes until you have got 99. Only then proceed. The ASF docs have an example for that. Make sure you copy code from there that fits your version.

STM32F0 USB CDC_Init_FS() and CDC_Receive_FS() using CubeMX

I am using this code to capture data over the USB. The top code crashes the program once a character is received. The bottom works just fine, although I cannot save the data as I want. The top crashes (endless loop) even before calling CDC_Receive_FS()...which is never called. The bottom calls CDC_Receive_FS() as expected.
For the life of me, I cannot see what is wrong with how I am calling my struct that holds an array of buffers that I loop through.
/* Send Data over USB CDC are stored in this buffer */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
#define MAX_COMMANDS_IN_BUFFER 10 //max commands that can be received and saved without overwriting. Each command has a max size of APP_RX_DATA_SIZE
/* Define size for the receive and transmit buffer over CDC */
/* It's up to user to redefine and/or remove those define */
#define APP_RX_DATA_SIZE 256
#define APP_TX_DATA_SIZE 256
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
static struct
{
uint32_t Buffer_Number_Receiving, Buffer_Number_Processing; //Buffer_Number_Receiving is the current position in buffer to receive incoming data. Buffer_Number_Processing is the index of buffer which is being processed.
uint8_t IsCommandDataReceived; // > 0 , data were received. 0 means no data is available
uint8_t UserRxBufferFS[MAX_COMMANDS_IN_BUFFER][APP_RX_DATA_SIZE];//it could save <MaxCommandsInBuffer> number of commands
uint8_t CommandsLens[MAX_COMMANDS_IN_BUFFER]; //save the len of each command
} s_RxBuffers;
static int8_t CDC_Init_FS(void)
{
hUsbDevice_0 = &hUsbDeviceFS;
/* USER CODE BEGIN 3 */
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(hUsbDevice_0, s_RxBuffers.UserRxBufferFS[s_RxBuffers.Buffer_Number_Receiving] );//Set the buffer to receive incoming data
USBD_CDC_ReceivePacket(hUsbDevice_0);
return (USBD_OK);
/* USER CODE END 3 */
}
This does not:
/* Received Data over USB are stored in this buffer */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
/* Send Data over USB CDC are stored in this buffer */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
static int8_t CDC_Init_FS(void)
{
hUsbDevice_0 = &hUsbDeviceFS;
/* USER CODE BEGIN 3 */
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS);
USBD_CDC_ReceivePacket(hUsbDevice_0);
return (USBD_OK);
}
Loop
The line here (the use of this buffer) seems to be the culprit:
USBD_CDC_SetRxBuffer(hUsbDevice_0, s_RxBuffers.UserRxBufferFS[s_RxBuffers.Buffer_Number_Receiving] );//Set the buffer to receive incoming data
Any help/insight would be greatly appreciated.
I would make the Rx_Buffer monodimensional and handle the command history separatly.
static struct
{
uint32_t Buffer_Number_Receiving, Buffer_Number_Processing; //Buffer_Number_Receiving is the current position in buffer to receive incoming data. Buffer_Number_Processing is the index of buffer which is being processed.
uint8_t IsCommandDataReceived; // > 0 , data were received. 0 means no data is available
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
uint8_t CommandsLens[MAX_COMMANDS_IN_BUFFER]; //save the len of each command
} s_RxBuffers;
Apart from this, since you are usinc a struct (s_RxBuffers type), I think you are not passing the buffer as a pointer in the right way to your function.
I think you should do something like this:
USBD_CDC_SetRxBuffer(hUsbDevice_0, &s_RxBuffers.UserRxBufferFS[0] );//Set the buffer to receive incoming data

Correct way of implementing a uart receive buffer in a small ARM microcontroller?

I am looking for ideas for a receive buffer for a small application dealing with 15 byte packets at 921.6Kbaud over rs485. I am thinking of using a circular buffer as the interface between the UART ISR and main. As it is a microprocessor I was wanting to put
while (uartindex!=localindex) { do stuff }
in the
while (;;) {do forever}
part of main but I have been told this is not acceptable.
How do people deal with their uarts under similar circumstances?
ISR should fill a FIFO. Main should consume it.
Bellow a very simple fifo algorithm:
#define RINGFIFO_SIZE (1024) /* serial buffer in bytes (power 2) */
#define RINGFIFO_MASK (RINGFIFO_SIZE-1ul) /* buffer size mask */
/* Buffer read / write macros */
#define RINGFIFO_RESET(ringFifo) {ringFifo.rdIdx = ringFifo.wrIdx = 0;}
#define RINGFIFO_WR(ringFifo, dataIn) {ringFifo.data[RINGFIFO_MASK & ringFifo.wrIdx++] = (dataIn);}
#define RINGFIFO_RD(ringFifo, dataOut){ringFifo.rdIdx++; dataOut = ringFifo.data[RINGFIFO_MASK & (ringFifo.rdIdx-1)];}
#define RINGFIFO_EMPTY(ringFifo) (ringFifo.rdIdx == ringFifo.wrIdx)
#define RINGFIFO_FULL(ringFifo) ((RINGFIFO_MASK & ringFifo.rdIdx) == (RINGFIFO_MASK & (ringFifo.wrIdx+1)))
#define RINGFIFO_COUNT(ringFifo) (RINGFIFO_MASK & (ringFifo.wrIdx - ringFifo.rdIdx))
/* buffer type */
typedef struct{
uint32_t size;
uint32_t wrIdx;
uint32_t rdIdx;
uint8_t data[RINGFIFO_SIZE];
} RingFifo_t;
RingFifo_t gUartFifo;
(Care must be taken with this FIFO algorithm, size MUST be power of 2)
The ISR should behave like this:
void ISR_Handler()
{
uint8_t c;
while(UART_NotEmpty()) {
c = UART_GetByte();
RINGFIFO_WR(gUartFifo, c);
}
}
And the Main:
while(1)
{
if (!RINGFIFO_EMPTY(gUartFifo)) {
/* consume fifo using RINGFIFO_RD */
}
}
This algorithm reads the FIFO directly from the main loop, you should use a intermediate layer that checks if there is a full packet in the buffer, and deals with it, in such a manner that main would be like this:
uint8_t ptrToPacket;
uint32_t packetSize;
while(1)
{
if (!Uart_HasValidPacket()) {
Uart_GetPacket(&ptrToPacket, &packetSize)
/* Process packet using ptrToPacket and packetSize */
}
}
The approach you suggest would probably be workable if the uartindex is never written in the main loop (except to initialize it while interrupts are disabled), and localindex is never touched by the interrupt routine.
I would suggest that you make your buffer size be a power of 2, use unsigned integers for the two indices, and allow them to count freely over their full 32-bit size; use bit masking when indexing your buffer in both the "stuff" and "fetch" routines. If you do that, then
(unsigned)(uartindex-localindex)
should indicate how many characters are in the buffer, even when it's completely full, without requiring special-case behavior in the buffer-full case and without limiting an N-byte buffer to holding N-1 items.
Note that while the typecast in the aforementioned expression isn't strictly necessary, I would recommend including it since it makes obvious that the wrapping behavior when subtracting unsigned quantities is deliberate and expected.

Resources