I'm writing code for stm32l011 MCU and it have to do one basic task for now - wait for a specific byte(predefined by me) from the UART and following "\r\n" or "\n\r" sequence. If it receives that, it set's a null pointer to the address of the predefined char, which is read and handled in the main loop.
volatile uint8_t uart_buff[UART_BUFF_LEN] = {'\0'};
volatile uint8_t *uart_data = NULL;
volatile uint8_t *uart_stack = uart_buff+2;
void USART2_IRQHandler(void){
if(LL_USART_IsActiveFlag_RXNE(USART2)){
*uart_stack = LL_USART_ReceiveData8(USART2);
user_uart_send_byte(*uart_stack);
//same as if(!(strcmp((uart_stack-1), "\r\n") || strcmp((uart_stack-1), "\n\r")))
if((*uart_stack == '\r' || *uart_stack == '\n') && (*(uart_stack-1) == '\r' || *(uart_stack-1) == '\n'))
{
uart_data = uart_stack - 2;
uart_stack = uart_buff+2;
}
uart_stack++;
}
}
and main:
extern volatile uint32_t systick_counter_ms;
extern volatile uint8_t *uart_data;
int main(void){
init();
while(1)
{
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_3);
//delay_ms(1); //without that it doesn't want to work
if(uart_data)
{
adc_transmit_reading(*uart_data);
uart_data = NULL;
}
}
}
I wrote the C program above and it didn't seem to work. But when I introduced delay in the main loop it just magically sprang to life. Why is that? Key things to note:
There's echo from the UART so I'm sure that it handles the interrupt properly in both cases, also I tried to remove optimizations of the compiler(which optimizes for size(Os)) by using volatile variables. Also the delay is made by while loop, which waits interrupt which increments variable every millisecond.
My layman's guess is that because I'm only looping around that uart_data pointer, somehow the synchronization between the interrupt and main loop isn't happening.
Thanks in advance :)
The problem is that you have indicated that your uart_data points to volatile data. But in your loop, you are testing the pointer and not the data.
So you must indicate that your pointer is volatile as well:
extern volatile uint8_t * volatile uart_data;
You can find more information in this post: Why is a point-to-volatile pointer, like "volatile int * p", useful?
Using a 8-bit AVR micro, I arrived to a simple situation which might not be that easy to solve.
Consider the following snippet:
static volatile uint8_t counter;
//fires often and I need all the values of the counter.
void isr(void) {
counter++;
}
int main (void) {
while(1) {
send_uart(counter);
counter = 0;
delay_ms(1000); //1 sec pause
}
return 0;
}
1.) It can happen that send_uart is followed by an isr which increases the counter, and then the next statement zeroes it out.
Therefore I'll miss one data from the counter.
2.) If I use ATOMIC_BLOCK(ATOMIC_RESTORESTATE) in the main fn, I can avoid the problems declared in (1), but it can happen that I miss an ISR because in this case INTs are disabled for a short time.
Is there a better way to pass information from the main fn to ISR?
If the counter is sampled rather than reset, there won't be any timing issues. Increments happening while sending will be accounted for in the next iteration. The unsigned data type of the counter variables will guarantee well-defined overflow behavior.
uint8_t cs = 0; // counter sample at time of sending
uint8_t n = 0; // counter as last reported
while (1) {
cs = counter; // sample the counter
send_uart((uint8_t)(cs - n)); // report difference between sample and last time
n = cs; // update last reported value
delay_ms(1000);
}
I am using atmel's lwip example. Interfacing with PHY is ok. It can link and even auto negotiate. Netif is going up. But when i start polling netif nothing happens. Ive narrowed down problem to EMAC_Poll
unsigned char EMAC_Poll(unsigned char *pFrame, unsigned int frameSize, unsigned int *pRcvSize)
{
unsigned short bufferLength;
unsigned int tmpFrameSize=0;
unsigned char *pTmpFrame=0;
unsigned int tmpIdx = rxTd.idx;
volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;
ASSERT(pFrame, "F: EMAC_Poll\n\r");
char isFrame = 0;
// Set the default return value
*pRcvSize = 0;
// Process received RxTd
while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) {
// Never got there.
...
}
return EMAC_RX_NO_DATA;
}
typedef struct {
volatile EmacRxTDescriptor td[RX_BUFFERS];
EMAC_RxCallback rxCb; /// Callback function to be invoked once a frame has been received
unsigned short idx;
} RxTd;
/// Describes the type and attribute of Receive Transfer descriptor.
typedef struct _EmacRxTDescriptor {
unsigned int addr;
unsigned int status;
} __attribute__((packed, aligned(8))) EmacRxTDescriptor, *PEmacRxTDescriptor;
There is while loop, but condition is never goes true.
I have very vague presentation what is RxTd and what exacly this condition means. However i can not see how thise RxTd Would change to pass condition. All references of RxTd leads to same emac.c module. Most of them in that polling function and rest in EMAC_ResetRx function.
static void EMAC_ResetRx(void)
{
unsigned int Index;
unsigned int Address;
// Disable RX
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_RE;
// Setup the RX descriptors.
rxTd.idx = 0;
for(Index = 0; Index < RX_BUFFERS; Index++) {
Address = (unsigned int)(&(pRxBuffer[Index * EMAC_RX_UNITSIZE]));
// Remove EMAC_RX_OWNERSHIP_BIT and EMAC_RX_WRAP_BIT
rxTd.td[Index].addr = Address & EMAC_ADDRESS_MASK;
rxTd.td[Index].status = 0;
}
rxTd.td[RX_BUFFERS - 1].addr |= EMAC_RX_WRAP_BIT;
// Receive Buffer Queue Pointer Register
AT91C_BASE_EMAC->EMAC_RBQP = (unsigned int) (rxTd.td);
}
I do not realy understand last line, but it looks like that rxTd is auto filled with AT91 itself. If it is so, there may be packing/aligment problem, but Atmel added __attribute__ ((packed, aligned(8))) on RxTd structure definition. Any way, can someone describe mechanism of data input or tell me where proble might be?
By the way i am using gcc, if that matters.
UPD:
Ive checked RSR and notice that it is start with 0, then goes to 2 after second. 2- means new data was captured.
UPD:
So i've read about function of emac in datasheet for my chip. I was right. That RBQP register must point to array of descriptors. Each descriptor consists of address and status field. The datasheet states that "bit zero of address field is written to one to show the buffer has been used". Then ARM uses another rx descriptor from that array. I guess by "has been used" they mean that that buffer is filled with frame data and ready to be processed. This must mean that data just not going to that buffer. But it must be there because REC goes high. Additionaly i've checked that RE in NCR is up and MI is enabled. I have no idea what is wrong.
I've spend whole week to solve it. The funny thing is that if i've dump memory and looked at all those addresses - The data was there whole time! So the key was to disable I and D caching and MMU itself. Hope it will help someone.
I made a program that plays a song (using buzzer) saved in array:
(...)
//function which plays a single note
void playNote(int8 wavelength, int duration) {
if (wavelength != 1) {
OCR0A = wavelength; /* set pitch */
SPEAKER_DDR |= (1 << SPEAKER); /* enable output on speaker */
}
while (duration) { /* Variable delay */
_delay_ms(1);
duration--;
}
SPEAKER_DDR &= ~(1 << SPEAKER); /* turn speaker off */
//function which plays song from array
void playSong( int8 *song,int tempo){
int length_16_note = tempo;
for( int8 i = 0;song[i]) ; i += 2){
playNote(song[i],song[i+1]*length_16_note);
_delay_ms(15);
}
}
int main(void){
//array of macros and lenghts of notes
int8 song1[] = {
C,4, E1,4, F1,3, E1,3, F1,2,
F1,2, F1, 2, B1,2, A1,2, G1,1, F1,2, G1,5,
G1,4, B1,4, C1,3, F1,3, E1,2,
B1,2, B1,2, G1,2, B1,2,
B1,3, C1,13, 0};
//initialize a timer
initTimer();
//play song
playSong(song1, 150)
}
I omitted some parts of it, but this code works just fine. And now I want to save my song into program memory so I change:
#include <avr/pgmspace.h>
(...)
int8 song1[] PROGMEM = {...}
void playSong( int8 *song, int tempo){
int length_16_note = tempo;
for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2){
playNote(pgm_read_byte(&(song[i])), pgm_read_byte(&(song[i+1]))*length_16_note);
_delay_ms(15);
}
}
And when I run that code on Arduino, I get random beeps with random duration (much longer that expected). It looks like pgm_read_byte(&(song[i])) returns random values.
I tried to extract code from function playSong to main in order not to pass an array as an argument to the function and nothing changed. So what is wrong with this code?
I'm not sure this is the reason but my first guess is that you get longer durations than expected because your for loop looks like this:
for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2)
This means every time the for loop is executed, the program checks the data in program space, as it is the loop condition.
There is a warning stated in the avr-libc user manual concerning the use of program memory reads in loops and functions, see below.
The macros and functions used to retrieve data from the Program Space have to generate some extra code in order to actually load the data from the Program Space. This incurs some extra overhead in terms of code space (extra opcodes) and execution time. (...) But you should be aware of this so you can minimize the number of calls within a single function that gets the same piece of data from Program Space.
Moreover, you make two additional calls to program flash inside the for loop. All this means, that to change the note, the program needs to wait for 3 byte reads from program memory and an additional 15 ms delay. As a result, the notes are much longer than expected.
I suggest the program should first read the whole song into some kind of a buffer in RAM, and play it afterwards directly from RAM.
Problem solved. The issue here was the fact that array song1 is declared in main() function. I had to declare array as global data before function definitions:
#include (...)
#define (...)
const int8 song1[] PROGMEM = {
C,4, E1,4, F1,3, E1,3, F1,2,
F1,2, F1, 2, B1,2, A1,2, G1,1, F1,2, G1,5,
G1,4, B1,4, C1,3, F1,3, E1,2,
B1,2, B1,2, G1,2, B1,2,
B1,3, C1,13, 0};
void playNote(int8 wavelength, int16 duration){...}
void playSong( int8 *song, int16 tempo){...}
int main(void){...}
It was hard to see the problem in my question above, because I wrote code in misleading way (in second quote I wrote array before function definition - but in original code it was in the same place as before). I'm sorry for that.
this is a bit of a strange use case so searching for existing discussion is difficult. I'm programming for embedded systems (Microchip PIC24 using XC16 compiler) and am currently implementing a communication protocol identically across 3 separate UART channels (each UART will grab data from a master data table).
The way I started out writing the project was to have each UART handled by a separate module, with a lot of code duplication, along the lines of the following pseudocode:
UART1.c:
static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;
void interrupt UART1Receive (void) {
buffer[pointer++] = UART1RX_REG;
if (end of packet condition) packet_received = 1;
}
void processUART1(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}
UART2.c:
static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;
void interrupt UART2Receive (void) {
buffer[pointer++] = UART2RX_REG;
if (end of packet condition) packet_received = 1;
}
void processUART2(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}
While the above is neat and works well, in practice the communication protocol itself is quite complex, so having it duplicated three times (simply with changes to references to the UART registers) is increasing the opportunity for bugs to be introduced. Having a single function and passing pointers to it is not an option, since this will have too great an impact on speed. The code needs to be physically duplicated in memory for each UART.
I gave it a lot of thought and despite knowing the rules of never putting functions in a header file, decided to try a specific header file that included the duplicate code, with references as #defined values:
protocol.h:
// UART_RECEIVE_NAME and UART_RX_REG are just macros to be defined
// in calling file
void interrupt UART_RECEIVE_NAME (void) {
buffer[pointer++] = UART_RX_REG;
if (end of packet condition) packet_received = 1;
}
UART1.c:
static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;
#define UART_RECEIVE_NAME UART1Receive
#define UART_RX_REG UART1RX_REG
#include "protocol.h"
void processUART1(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}
UART2.c:
static unsigned char buffer[128];
static unsigned char pointer = 0;
static unsigned char packet_received = 0;
#define UART_RECEIVE_NAME UART2Receive
#define UART_RX_REG UART2RX_REG
#include "protocol.h"
void processUART2(void) { // This is called regularly from main loop
if (packet_received) {
// Process packet
}
}
I was slightly surprised when the code compiled without any errors! It does seem to work though, and post compilation MPLAB X can even work out all of the symbol references so that every macro reference in UART1.c and UART2.c don't get identified as an unresolvable identifier. I did then realise I should probably rename the protocol.h file to protocol.c (and update the #includes accordingly), but that's not practically a big deal.
There is only one downside: the IDE has no idea what to do while stepping through code included from protocol.h while simulating or debugging. It just stays at the calling instruction while the code executes, so debugging will be a little more difficult.
So how hacky is this solution? Will the C gods smite me for even considering this? Are there any better alternatives that I've overlooked?
An alternative is to define a function macro that contains the body of code. Some token pasting operators can automatically generate the symbol names required. Multi-line macros can be generated by using \ at the end of all but the last line.
#define UART_RECEIVE(n) \
void interrupt UART##n##Receive (void) { \
buffer[pointer++] = UART##n##RX_REG; \
if (end of packet condition) packet_received = 1; \
}
UART_RECEIVE(1)
UART_RECEIVE(2)
Using macros for this purpose seems for mee to be a bad idea. Making debugging impossible is just one disadvantage. It also makes it difficult to understand, by hiding the real meaning of symbols. And interrupt routines should realy be kept independant and short, with common functions hidden in handler functions.
The first thing I would do is to define a common buffer struct for each UART. This makes it possible with simultanous communications. If each uart needs a separate handler function for the messages, it can be included as a function pointer. The syntax is a bit
complicated, but it results in efficient code.
typedef struct uart_buf uart_buf_t;
struct uart_buf {
uint8_t* buffer;
int16_t inptr;
bool packet_received;
void (*handler_func)(uart_buf_t*);
};
uart_buf_t uart_buf_1;
uart_buf_t uart_buf_2;
Then each interrupt handler will be like this:
void interrupt UART1Receive (void) {
handle_input(UART1RX_REG, &uart_buf_1);
}
void interrupt UART2Receive (void) {
handle_input(UART2RX_REG, &uart_buf_2);
}
And the common handler will be:
void handle_input(uint8_t in_char, *buff) {
buf->buffer[buf->inptr++] = in_char;
if (in_char=LF)
buf->packet_received = true;
buf->handler_func(buf);
}
}
And the message handler is:
void hadle_packet(uart_buf_t* buf) {
... code to handle message
buf->packet_received=0;
}
And the function pointers must be initialized:
void init() {
uart_buf_1.handler_func=handler1;
uart_buf_2.handler_func=handler1;
}
The resulting code is very flexible, and can be easily changed. Single-steping the code is no problem.