3 months, 2 weeks ago.

UART interrupt control

Hi,

I am trying to use interrupts to read serial data coming from PC. However, I want to disable the interrupt when full message is read, but it is not getting disabled. Reason for this is that I want to process the message after it has been read and then to read a new one. I tried also the disable_irq() function but it didn't work either. What happens is that it reads the message in full twice or reads a new message while being in statesLoop() function. I am interested in disabling only the RX interrupt. Below I add a snippet of my code:

code

#include "../include/read_functions/read_functions.h"
#include "../include/read_functions/formating.h"
#include "../include/read_functions/message_generation.h"
#include "../include/read_functions/handshake.h"
#include "../include/read_functions/stateMachine.h"
#include "../include/read_functions/uart_functions.h"

SPI spi(PA_7, PA_6, PA_5); //For L476RG
DigitalOut cs(PB_6); 
InterruptIn drdy(PB_3);   
DigitalOut rst(PB_5, 0);
RawSerial pc(PA_2, PA_3);
vector<uint8_t> buf;
vector<uint8_t> t_buf;
MTHand mth;
MTUart mtu;
MTRead mtr;
MTStateMachine mts;
Nucleo_handshake_byte_data h_byte;

void masterConfiguration(void)
{
    while(pc.readable()){ // busy waiting for data available
    mtu.readUart(&pc, &buf);
    t_buf.push_back(buf.back());
    }
}

int main() {
    pc.baud(115200);
    pc.format(8,SerialBase::None, 1);
    spi.frequency(1000000);
    spi.format(8,3);   
    cs=1;

    pc.attach(&masterConfiguration, RawSerial::RxIrq);

    while(1)
    {
        if(t_buf[0] == 0x4E && t_buf[buf.size() - 1] == 0x45)
        {
            NVIC_DisableIRQ(USART2_IRQn);
            // __disable_irq();
            mtu.setReadMsg(&t_buf);
            mts.statesLoop(&mth, &mtr, &mtu, &mts, &h_byte, &pc);
 //           
        }
    }
}

Are you sure that you want to disable the interrupt? I understand that you don't want more data arriving in your buffer while you process the message but there are better ways of doing that that don't risk dropping data if your processing takes too long.

I'd recommend using two buffers. Either a) in the interrupt put data into one buffer until you have a full message (and not a byte more) and then switch buffers and set a flag telling the main loop that there is data ready. Or b) in the main loop disable all interrupts, copy the data from the serial buffer to a message to process buffer, delete it from the serial buffer, re-enable interrupts and then process the message. The first option is more efficient (no copies needed, just a couple of pointers that change) but also little harder to get your head around at times.

posted by Andy A 04 Nov 2019

1 Answer

3 months, 2 weeks ago.

Hi Edvardas,

Andy's comment is very good. Use two buffers. And in general don't parse received message in interrupt.

Regards, Pekka