I am a newbie with programming and I am having trouble getting my interrupts to work the way I want them to for my application. I want to send serial data over the UART to the PSoC, store the values every second, and then echo back the stored values. I am using a RX interrupt (RX FIFO not empty, priority 2) and a timer interrupt with the TC (priority 3). Attached is the TopDesign configuration. Currently, I am trying to get this code to work (just a sample code to see if I can get the interrupts to work correctly). I send the PSoC a string containing a character 'o', I should be reading only 'o' and '-', but the code always gets stuck in one of the interrupts with the other one never working. Could anyone tell me what I am doing incorrectly? Much appreciated! The board is CY8CKIT-042.
#include <project.h>//Contains
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
uint16 ms_count = 0;
uint8 ch;
CY_ISR_PROTO(Timer_ISR);
CY_ISR_PROTO(RX_ISR);
CY_ISR(Timer_ISR){//Every millisecond, the code goes here
ms_count++;
if (ms_count == 1000){//Every second
ms_count = 0;
LED_Write(!LED_Read());
while(ch != 'o')UART_UartPutChar('-');
}
}
CY_ISR(RX_ISR){
uint8 status = UART_rx_ClearInterrupt();//Clear interrupt flag
uint8 sub;
sub = UART_UartGetChar();
if (sub != 0u){//Make sure grabbed character is not an empty
ch = sub;
if (ch == 'o'){
UART_UartPutChar(ch);
}
}
}
int main()
{
/* Start SCB UART TX+RX operation */
Timer_1_Start();
Time_ISR_StartEx(Timer_ISR);
RX_ISR_StartEx(RX_ISR);
CyGlobalIntEnable;
/* Start SCB UART TX+RX operation */
UART_Start();
UART_UartPutString("fdssf\n");
for(;;)
{
}
}
I want to send serial data over the UART to the PSoC, store the values every second, and then echo back the stored values. I am using a RX interrupt (RX FIFO not empty, priority 2) and a timer interrupt with the TC (priority 3).
One important principle for interrupt service routines (ISR's) is to make them as short as possible. Another is to make sure they don't block. As pointed out by Hans Passant in the comments, your Timer_ISR is blocking with the while loop. It's going to continually spam putting the '-' character into the UART and not allow anything else to happen. That's a bad idea. IMHO, enabling nested interrupts isn't really a good idea here.
It actually looks like you're already echoing the character 'o' with this line:
if (ch == 'o'){
UART_UartPutChar(ch);
}
You aren't actually waiting a second to echo back the 'o' here, it's happening immediately. You can simply add UART_UartPutChar('-')
inside that if
statement to also send the dash character immediately. It sounds like you're writing a simple test application for now just to get things working, and I wouldn't bother waiting until the timer ISR fires off to echo back the 'o' or the '-' for a simple test application.
Alternatively, if you only want to print the dash once per second if the letter 'o' is the most recently read letter, you can replace the while
loop with a simple if
statement:
if(ch == 'o')UART_UartPutChar('-');
Keep in mind that would only work if 'o' was the most recently read character, since you're overwriting the ch
variable with every new character read (including new lines). I'm not sure what purpose that would serve, but there it is.
Something you might consider in the future when using ISR's is letting an ISR set a flag and having the main loop watch for that flag and then do something to react to it, for example:
volatile int flag = 0;
CY_ISR(Timer_ISR){//Every millisecond, the code goes here
if (some event) {
flag=1;
}
void main() {
while (1) {
if (flag) {
flag=0;
do_something_in_a_long_loop();
}
}
}
(Read more about volatile here).
This is only one way of approaching this problem of long loops. Also, whether you want to clear the flag before or after the long block of code depends on your application. This does have the (very likely) potential of missing events if your block of code is too long and the events come too frequently. In that case, it may be a good idea to start use threading or real-time operating systems. How you design your program obviously depends on the problem that you're solving.
A word of warning: when sharing global variables between ISR's and main code, or when dealing with multi-threaded applications, it's very easy to run into race conditions. You need to be aware of these potential pitfalls and the various strategies for dealing with them properly. I'd suggest picking up a book or taking a class about embedded programming and/or real-time operating systems. Welcome to the very complex world of embedded and real-time programming!