Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 9 months ago.
Interrupt handler locks up
I am using a STM32F747 Disco development board. I have conected a MIDI device to the USART6_RX pin (D0). Furthermore, I have connected a external device using SPI.
A software timer fires a software interrupt every 500 ms. This interrupt routine will send a command through SPI to the device. Furthermore, I am using a counter that increments an integer on the screen once a second.
After receiving one byte of serial data on USART6_RX, this interrupt handler seems to lock up. This results in the main loop locking up (so it stops running through the while loop. The interesting part is that the software interrupt (that sends a SPI command every 500 ms) keeps running.
What is going on here?
Main program code
#include "mbed.h" #include "LCD_DISCO_F746NG.h" #include "RF22.h" LCD_DISCO_F746NG lcd; //LCD Object Buzzer mySpiDevice(D10,D11,D12,D13,D2); //SPI object Serial midi(D1, D0); //Midi Object Serial pc(USBTX, USBRX); //PC Object - For debugging purposes Ticker commandTimer; //Software Timer that creates software IRQ Timer updateNumberTimer; //Software Timer to create non-blocking delays /* * Commands the SPI device to send a message */ void sendCommand() { mySpiDevice.sendMessage(); } /* * Is called in the event of an Serial RX interrupt * Please note that this can be on ANY UART port (so also from the debugger) */ void Rx_interrupt() { //Now it's empty return; } int main() { midi.baud(31250); //Initializes the midi to correct baudrate pc.baud(115200); //Selected highest baudrate for USB to be sure that is is faster than midi midi.attach(&Rx_interrupt, Serial::RxIrq); //If an serial RX interrupt occurs, the RX_interrupt function will be called commandTimer.attach(&sendCommand, .5); //Initializes the software timer firing a soft IRQ every 500 ms pc.printf("Initialisation OK\r\n"); lcd.Clear(LCD_COLOR_WHITE); lcd.SetTextColor(LCD_COLOR_BLACK); lcd.SetFont(&Font20); lcd.SetBackColor(LCD_COLOR_WHITE); int nCounter = 0; updateNumberTimer.start(); //Starts the counter char pNumberBuf[10]; while (1) { if (updateNumberTimer.read_ms() > 1000) { pc.printf("Teller is: %d\r\n", nCounter); nCounter++; sprintf(pNumberBuf, "Time: %04d\0", nCounter); lcd.DisplayStringAt(50, 50, (uint8_t *)pNumberBuf, LEFT_MODE); updateNumberTimer.reset(); //Reset counter to 0 } } }
Buzzer via SPI sendMessage
void Buzzer::sendMessage() { uint8_t data[3] = {"0x10, 0x11, 0x12}; //Blink command send(data, sizeof(data)); //Send byte } void Buzzer::send(const uint8_t* data, uint8_t len) { __disable_irq(); //memcpy the data to TX buffer before sending it to the buzzer __enable_irq(); spiWrite(REG_PACKET_LENGTH, len); //Send first byte only (for now as test) } void spiWrite(uint8_t reg, uint8_t val) { __disable_irq(); // Disable Interrupts _slaveSelectPin = 0; _spi.write(reg | SPI_WRITE_MASK); _spi.write(val); _slaveSelectPin = 1; __enable_irq(); // Enable Interrupts }
So bottomline; Why - after receiving one byte of serial data - does the main thread lock up and does the software interrupt continue to send messages as it should?
2 Answers
8 years, 9 months ago.
I have no idea why your timer interrupt keeps functioning. Only reason that should happen is because it has higher priority set, but as far as I am aware every interrupt initializes with the maximum priority if you don't specifically change it.
To solve your real issue: Put in your RX interrupt a midi.getc(). Later you can actually do something with it, but the issue is if you don't clear the received byte from the buffer, it will keep firing that same interrupt since it considers it not yet handled, there is still something in the receive buffer.
8 years, 9 months ago.
In addition to Erik's answer you have an issue with
sprintf(pNumberBuf, "Time: %04d\0", nCounter);
This isn't going to cause the problem you have right now but it could come back to bite you in the future,
"Time: %04d\0" is 11 characters long, sprintf will then add a null on the end automatically meaning this function call will write 12 bytes to pNumberBuf. pNumberBuf only has 10 bytes allocated.
Remove the \0 at the end of the string, its redundant, sprintf adds it, and increase the size of pNumberBuf by a few bytes.
Ideally also use snprintf rather than sprintf in order to ensure there are no nasty gotchas that don't show up in testing but do when you try to use the code (e.g. after 2 3/4 hours nCounter will hit 5 digits and your string length will increase by 1).
Hi Andy, thanks for your message. It was kind of messy of me and corrected it directly. One weird problem left: Every now and then the USART seems to lock up and then midi.readable() keeps returning false...Seems that the interrupt flag in the USARt register isn't set anymore. Could this be because a buffer overflow?
posted by 01 Jun 2016