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?
Related
I'm using MikroC for PIC v7.2, to program a PIC18f67k40.
Within functii.h, I have the following variable declaration:
extern volatile unsigned char byte_count;
Within main.c, the following code:
#include <functii.h>
// ...
volatile unsigned char byte_count = 0;
// ...
void interrupt () {
if (RC1IF_bit) {
uart_rx = Uart1_read();
uart_string[byte_count] = uart_rx;
byte_count++;
}
// ...
}
Then, within command.c, I have the following code:
#include <functii.h>
void how_many_bytes () {
// ...
uart1_write(byte_count);
// ...
}
In main.c, I process data coming through the UART, using an interrupt. Once the end of transmission character is received, I call how_many_bytes(), which sends back the length of the message that was received (plus the data bytes themselves, the code for which I didn't include here, but those are all OK!!).
The problem is that on the uart1_write() call, byte_count is always 0, instead of having been incremented in the interrupt sequence.
Probably you need some synchronization between the interrupt handler and the main processing.
If you do something like this
if(byte_count != 0) {
uart1_write(byte_count);
byte_count = 0;
}
the interrupt can occur anywhere, for example
between if(byte_count != 0)and uart1_write(byte_count); or
during the processing of uart1_write(byte_count); which uses a copy of the old value while the value gets changed or
between uart1_write(byte_count); and byte_count = 0;.
With the code above case 1 is no problem but 2 and 3 are. You would lose all characters received after reading byte_count for the function call.
Maybe you can disable/enable interrupts at certain points.
A better solution might be to not reset byte_count outside of interrupt() but instead implement a ring buffer with separate read and write index. The read index would be modified by how_many_bytes() (or uart1_write()) only and the write index by interrupt() only.
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.
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.
My program contains few global variables , whose values are set during the interrupt service routine (USCI_A0_ISR()) execution.
Once the execution of USCI_A0_ISR() is done , will the global variables hold the value assigned or will be set back to void/0.????
//Global variables
int ptr = 0;
char rxBuffer[16];
int flag = -1;
int check[2];
void __set_flag(void)
{
if (strcmp(rxBuffer,"OK") == 0) flag = 0;
else if (strcmp(rxBuffer,"CONNECT") == 0) flag = 1;
else if (strcmp(rxBuffer,"NO CARRIER") == 0) flag = 3;
else if (strcmp(rxBuffer,"ERROR") == 0) flag = 4;
}
void __GSM_client(void)
{
while (flag == -1);
if (flag == 0) check[0] = buflen(rxBuffer);
}
void main(void)
{
__Buffer_init();
__low_level_init(); //WDT
__UART0_init(); //UART
__bis_SR_register(GIE); //interrupts enabled
__delay_cycles(1000); // wait till UART intial
__GSM_client();
__no_operation(); // For debugger
}
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
char byte;
while (!(UCA0IFG&UCTXIFG));
byte= UCA0RXBUF;
UCA0TXBUF = byte;
if (byte == '\r') {
//push_char(byte);
ptr = 0;
__set_flag();
//__Buffer_init();
}
else{
push_char(byte);
}
}
Here is the code snippet of what I am doing. I am setting the "flag" based on the response obtained . When I see the register view in Code Composer Studio , the "flag" value is set correctly , but if try using the value of "flag" elsewhere the value of "flag " is not reflected.
Any pointers over concepts of the interrupt service routine or when loopholes in my coding method appreciated
Thanks in Advance
AK
Within the interrupt, you are directly or indirectly changing several global variables, e.g. ptr, flag, and I'm assuming rxBuffer[?]. They are not declared "volatile" so their value may or may not change when you return from the interrupt. This is a bug because the behavior can change based on where in the execution of the code the interrupt occurs and what the level of optimization is. As a rule of thumb, any variable modified by an interrupt routine should always be declared volatile.
If you're sure that making the shared variables volatile isn't working then I'd suspect you have redefined a global variable as a local variable somewhere. Check the address of the flag variable when you are debugging and make sure it is the same in __set_flag() and outwith the interrupt, where you think it has not been updated.
I also think that the polling loop in your ISR is poor code and you should find a better way to wait for the transmitter to be ready for the next character.
Thanks to all the feedback i got from the members. Well the idea of declaring all the "variables volatile" did the trick . strcmp() uses const var* so i couldn't use it . I had to write my own custom string compare function. All this minor things solved my problems.