Timer Interrupt and UART Receive Interrupt - c

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!

Related

Using threads in C to create an asynchronous timer

I am not even sure if threads are a way to go with what I am trying to accomplish, but my intuition is telling me so.
I am implemeting a simple input in a while loop, character by character. If the time between the character input is greater than 2 seconds, the timeout should occur. The timeout is currently a simple printf in the main function.
This is my code:
typedef struct {
clock_t startTime;
} timerStruct;
void *TimerThread(void *arg) {
timerStruct timerThreadArgument = *((timerStruct *) arg);
clock_t differenceTime;
while(1) {
differenceTime = clock() - timerThreadArgument.startTime;
int millis = differenceTime * 1000 / CLOCKS_PER_SEC;
if (millis >= TIMEOUT_TIME) {
return (void *) 2;
}
}
}
int main() {
pthread_t timerThreadId;
void *threadReturn;
char inputChar;
printf("Input characters one by one or paste the string:\n");
while (1) {
timerStruct *timerThreadArgument = malloc(sizeof(*timerThreadArgument));
timerThreadArgument->startTime = clock();
pthread_create(&timerThreadId, NULL, TimerThread, timerThreadArgument);
pthread_join(timerThreadId, &threadReturn);
if ((int) threadReturn == 2) {
printf("Timeout!\n");
}
scanf(" %c", &inputChar);
}
}
The problem is, since I am using the pthread_join function, it blocks the main thread from executing and asking for input. I am aware why this is happening. If I don't use the pthread_join function, I am not going to be able to return the data from the thread, which is important because I wish to break the while loop if the timeout has occurred.
If anyone has an idea on how I could approach this, please share it.
Thank you in advance for your time.
There are a number of problems with what you are attempting. One of them is that stdio (ie. scanf) involves buffering; so you won't get a single character until a whole line is available. The other is that what you have implemented is more akin to sleep() than a timeout.
In order to have direct control over tty input, you need to inform the device driver in the kernel of your desire. The standard interface to this is tcgetattr, tcsetattr; which enables rather fine grained control of the tty. The n?curses library is a little coarser, but much, much easier to use.
There are a lot of advantages to designing your system as a set of asynchronous services which provide events to one another. In this, your keyboard handling might occupy a thread sending "Key Events" to some sort of dispatcher; and maybe another sending "Alarm Events" around to track timeouts. This isn't a particularly easy pattern though. Its value only comes to the fore in relatively large systems.
Some newer programming languages, Go for instance, have constructs specifically geared to this sort of architecture. You might find it worthwhile to look at it, at least to get a flavour of how tidily it can be accomplished.

without while(1) why this code in MPLAB is running continuously

In this code I have not used while(1), only when it enters 'if' condition it calls TIMER_ISR function which has been initialised for every 250ms. But when it enters else condition there is no any timer function or anything but then also why it is running continuously.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/eusart1.h"
void main(void)
{
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
char temp1[] = "ok";
char temp2[3] = { '\0', '\0', '\0' };
char temp3[3], temp4[3];
int i, j;
for (i = 0; temp1[i] != '\0'; i++)
{
temp3[i] = temp1[i] - 32;
EUSART1_Write(temp3[i]);
}
EUSART1_String("\r\n");
for (i = 0; i < 2; i++)
{
temp2[i] = EUSART1_Read();
EUSART1_Write(temp2[i]);
}
EUSART1_String("\r\n");
if (strcmp(temp1, temp2) == 0)
{
for (i = 0; temp1[i] != '\0'; i++)
{
if (temp1[i] >= 'a' && temp1[i] <= 'z')
{
temp1[i] = temp1[i] - 32;
}
}
for (j = 0; temp1[j]; j++)
EUSART1_Write(temp1[j]);
//Timer initialization (timer is initialized for every 250mS)
TMR0_Initialize();
}
else
EUSART1_String("\r\nERROR GIVE'ok'");
}
In case the question is: does it make sense to return from main() on a bare metal MCU application, then TL;DR: No it doesn't make sense because there is nobody to return to. No OS to hold your hand - your application is all there is.
Detailed explanation:
All modern MCUs have a point of entry called "reset interrupt". Where you can end up when you get a power-on, or perhaps after a watchdog circuit has reset the MCU, or because you have an external /reset signal on the MCU reset pin.
The program counter then starts the program by entering the interrupt service routine for power-on reset (sometimes called reset vector). From here on, the most basic stuff on the MCU are set, then typically it will call a "C run-time" (CRT), which is compiler-specific start-up code for the purpose of initializing all memory regions to enable a standard C environment, such as initializing variables etc. When the CRT is done with all that, it calls main().
Or in case you wrote everything in assembler, you wouldn't have to bother with the CRT but can call whatever function you like from the reset ISR. Often this is done with a direct jump instead of a function call, without stacking any parameters, because you don't expect to ever return. You'd only waste stack space needlessly.
That's why the most common form of main() in embedded systems is void main (void), rather than the strictly C conforming int main (void) - the latter may waste space on the stack needlessly due to calling convention. (On the gcc compiler, always pick embedded "freestanding" systems as your target with -ffreestanding.)
Now if you wrote the program in C and were to return from main(), you will at best crash back out into the CRT code, where if you are lucky, some kind person wrote a for(;;){} loop there to catch the program counter. This is common with rookie-friendly environments. Alternatively you could crash all the way back out to the power-on reset ISR.
Or more likely, in case main() was called the assembler way described above (either from the CRT or from your custom code) you jump straight into the unknown since no return address was saved.
From there, the program counter will run out in random memory locations, starting to execute whatever it comes across next in the memory it ends up, interpreting the contents of those cells as OP codes, whether they are that or not - you get "runaway code", which is a severe and dangerous bug condition. It will keep doing this either until it stumbles upon something that causes a hardware exception, like accessing protected memory, or until the watchdog resets everything, in case the watchdog is enabled.

Unable to get interrupt handlers to work in C

I am currently having trouble getting interrupt handlers to work in C. The idea with my code is to set a vector to IRQ 0, which is the PIT, and from what I can find is interrupt 8 (0x08), after setting the PIT to operate on about 40hz (which from what I can find this is by setting a value of 29829, or 0x7485.
The final intended result of the program is to count to a second, print something to screen, and then repeat that 20 times, at which point it uninstalls itself.
This program was compiled using Borland's Turbo C on an Am486-DX4-100 running at 120mhz with IBM's PC-DOS 2000. The board is the Socket 3 EXP-4045 by DataExpert, but I have the same results on DOSBox.
Here is the code:
#include <dos.h>
#include <stdio.h>
int a = 0;
int b = 0;
void interrupt clocktick(){
if(a == 40){
if(b == 20){
setvect(8, NULL);
}else b++;
}else a++;
}
int main(void){
/* set PIT mode*/
outp(0x34, 0x43);
outp(0x85,0x40); /* send low byte*/
outp(0x74,0x40); /* send high byte*/
setvect(0x08, clocktick);
while(1==1){
printf("a%i, b%i", a, b);
}
getchar();
return 0;
}
The code compiles fine, and when ran, the while look does show that A has been incremented once, but doesn't fire again. Obviously something is generating an interrupt, and it may even be the PIT, but it's not doing it more than once.
I am trying to follow the 1987 user's manual for Turbo C, which tries to describe the method for installing interrupt vectors, but I've obviously done something wrong.
I also need to say I am sorry for not knowing this stuff. I don't mean to waste people's time, but I am in genuine need of a helping hand. My examples were vauge, and after some comments I do see there is stuff I could have done to try to figure out what was going on.
You'd need to tell the PIC that you've finished handling the interrupt, otherwise it won't signal it again. Typically this is done by sending an EOI (0x20) to the PIC base port (0x20), so it would essentially be something like outportb(0x20, 0x20);, preferably near the end of your handler.
There's some information about the PIC at e.g. https://wiki.osdev.org/8259_PIC

Loop until user inputs an Integer, but skip the read in if no integer exists on the terminal

Im trying to create an application that will count pulses from an Oscilloscope, my problem is this:
I need a loop to run constantly, until a user input is entered. However I dont want getch() to be called unless there is an input on the terminal ready to be read. How would I go about checking for a character or integer existing on the terminal?
If you're coding for UNIX, you'll need to use either poll(2) or select(2).
Since you mention the non-standard getch you might also have kbhit which tests if there is input waiting. But don't slug your oscilloscope with that every loop: you can ease the flow by checking occasionally.
#include <conio.h>
#include <stdio.h>
#define POLLMASK 0xFFFF
int main(void){
int poll = 0;
int ch = 0;
while(ch != 27) {
// ... oscilloscope details
if ((poll++ & POLLMASK) == 0 && _kbhit()) {
ch = _getch();
// ... do something with input
}
}
return 0;
}
Use scanf() . It's standard, it already waits for a character in the buffer, and it's pretty much universal.
EDIT:
In the case of an unnamed OS, this is simply not to be done. Standard C has no way of reading raw data from a terminal and guaranteeing verbatim, unformatted results. It's entirely up to your terminal handler.
However, if your microcontroller has some sort of serial library, I would suggest doing something like this:
if characters in buffer is greater than 0, and the character just read is not a terminating character, report it. Otherwise, keep waiting for a character in the buffer.
until a user input is entered. this sentence indicates the user will use the keyboard eventually, therefore, you can track keyboard callback event to track the user's input. There are several libraries that provide you with such keyboard events (e.g. GLUT, SDL)

Is it possible to create multi-threading program for PIC12 MCU in HI-TECH C

My friend asks me to help him write a small program for PIC12 MCU. We want
The program stops running when input voltage is less than 1.9V during 2 seconds.
The program reacts immediately when input voltage exceeds 2.5V.
I try to solve the 1st problem by reading and comparing the system's timestamp:
#include <time.h>
... ...
time_t beg, end;
beg = 0;
end = 0;
while(1){
if(INP_VOL < 1.9){
if(beg == 0){
/* Read timestamp when voltage < 1.9 */
gmtime(&beg);
}
/* Campare timestamp */
gmtime(&end);
if(end - beg > 2){
break; /* !!stop running!! */
}
}
else{
/* if voltage back to normal, reset beg timestamp. */
beg = 0;
}
}
I've found the function gmtime(time_t *) in PIC12 User Manual, but I'm not sure if it a good solution.
But I can't figure out how to solve the 2nd problem. It should be kind of independent thread which moniters the input voltage during the execution of the program. And the program should react immediately (by calling an other function) before the circuit is damaged.
I'm computer programmer, but I've never coded for MCU. I'd like to know if it's possible to do such thing in HI-TECH C ?
The typical thing to do here is to use interrupts, specifically timer interrupts.
You set up an interrupt to run e.g. every 1 ms, and in that interrupt code you do whatever the program needs to react quickly to. That leaves the normal execution flow alone, and emulates that the two tasks are done in parallel.
You could have a circuit attached to the external interrupt pin, that gives 1 when voltage goes above 2.5. The external interrupt can be programmed to kick whenever its input goes from 0 to 1.
I don't think C language is the best solutions for PIC12 family.
My suggest is to use ASM. It's very simple by few instructions.
After set the ADC you can use substraction instruction and check the C (carry)
In this manner you can verify IF > or IF <
Test C and skip if zero. Skip the next instruction, the one with the call.
you can also change micro and use PIC18 for better c code performance.

Resources