I am using stm32 timer interrupt.
File 1: (interrupt function)
static int flag = 50;
void timer_inter_handler(){
//...
flag = some changes integer;// not 0, it is changed
#if 0 // **** note
printf("%d\r\n", flag);
#endif
}
int get_flag(){
return flag;
}
File 2: (other file)
int task1(){
static int fccount = 0;
while(1){
fccount++;
if ( fccount%50000 == 0 )
{
printf("%d\r\n", get_flag());
// ...
}
}//while(1)
}
Note:
If this on, task1 could print correct flag data changes. But if it is off, task1 could only print default 50value during system initialization for a couple of time. Then all the flag data printed is 0.
I do not know why this happen. No other place update the var flag. Any clue?
What you need is:
volatile static int flag = 50;
The volatile keyword tells the compiler that the flag variable can change in an interrupt. If the keyword is not there, then the flag variable will not be able to change. That is why you don't see it changing. The #if 0 printf(...) might be forcing the compiler to access the variable.
I found the problem.The problem is inside timer interrupt, hal_adc_start(read and stop), by reading adc value, the timer interrupt routine is hold.
Once I move hal_adc_read, it works fine.
Related
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'm waiting some time for a real-world event (e.g. push a button for 3 seconds) on an AVR or STM32 MCU, and I have trouble with code like:
#define PRESS_BUTTON
int waiting = 0;
int t_ms = 0; // time counter
//...
int main(void)
{
while(1)
{
waiting = t_ms + 3000; // waiting button 3 sec
while ((t_ms < waiting) && (!PRESS_BUTTON)) // infinite loop
{}
printf("out"); // not printed
waiting = t_ms = 0;
}
}
ISR( TIMER0_OVF_vect ) // timer interrupt
{
t_ms++;
}
But if I add a printf() inside the while loop, it works!
The same thing happens if I use a do...while loop either. What is causing this?
You need to declare t_ms with volatile
volatile int t_ms =0;
Volatile tells the compiler that the variable may be changed due to external factors, and because of this the compiler will never assume it will stay the same.
In other words, it will force the compiler to check every loop to see if t_ms has changed instead of assuming it will never change.
In the code below, I can see that the timer is working normally as the LED is always blinking. But the value of the count variable never changes inside the second while.
I don't know what could possibly go wrong?
// count variable used only in main and TIM2_IRQHandler.
uint8_t count=0;
int main(void)
{
count=0;
SystemInit();
GPIOInit();
NVIC_Configuration();
TIM_Configuration();
init_USART3(115200);
// All initialization is ok.
USART_puts(USART3, "\r\nConnection ok.\r\n");// Working normally
while (1)
{
if(asterixok==1)// No problem. This code if ok ->>process continue next step.
{
GPIO_SetBits(GPIOD , GPIO_Pin_12); // Led on (ok)
count=0;// count going to zero, timer working, must be change in there
while(1)
{
//Led blinking continue
//Timer query working normal led (13) blink.
//There is a problem
if(count>5) // Timer working, count never change in timer interrupt query (WHY)
{
GPIO_SetBits(GPIOD , GPIO_Pin_14); // LED OFFFFFFFFFFFFFFFF
USART_puts(USART3, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n");
goto nextstate;
}
}
nextstate:
GPIO_SetBits(GPIOD , GPIO_Pin_15); // Led never going on because code step in while loop.
}
}
}
void USART3_IRQHandler(void)
{
if( USART_GetITStatus(USART3, USART_IT_RXNE) )
{
unsigned char t = USART3->DR;
if(t=='*')
{
asterixok=1;
}
}
}
void TIM2_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
count++;
if(count>100)
count=0;
if( display )
{
GPIO_ResetBits(GPIOD , GPIO_Pin_13);
}
else
{
GPIO_SetBits(GPIOD , GPIO_Pin_13);
}
display = ~display;
}
}
I have tried with another Discovery board but the problem continues.
Please help. I'm going crazy!
You should declare count as volatile, as such :
volatile uint8_t count;
While compiling main the compiler was able to prove that count was not modified in the loop body, and so it probably cached its value in a register and maybe even optimized out the if statement. You could verify that by looking at a disassembly. The compiler does not know about interrupts as per the standard and so is permitted to perform such optimizations. Qualifying count as volatile will forbid the compiler from making these optimizations, forcing it to reload the variable from memory each time it is used.
In this simple case volatile will be enough but please be aware that it doesn't guarantee atomicity of operations, and it doesn't prevent the compiler and CPU from reordering instructions around accesses to the variable. It only forces the compiler to generate memory access instructions each time the variable is used. For atomicity you need locks, and to prevent reordering you need memory barriers.
I have a handler for SysTick exception which counts ticks and calls other functions (f1, f2, f3) whose execution time can be longer than SysTick period. These functions set and clear their active status (global variables) so if a SysTick exception occurs it can detect an overload and return to interrupted function.
I have assigned fixed priority to SysTick exception (let's say 16). I want to somehow make possible for SysTick to generate an exception regardless of it's prior active status, go to SysTickHandler, increase tick counter and return to interrupted function.
One solution which may be useful is to use BASEPRI. It can be set to priority lower than SysTick so it would enable that exception. Unfortunately, using BASEPRI got me nowhere because nothing happened (I set it to max value). BASEPRI value was 0 inside SysTickHandler before I changed it. Should that value be equal to SysTick priority when processor enters handler function? Is exception priority loaded automatically in BASEPRI?
I have also considered for NVIC to have an issue with preempting already active exception but found nothing regarding that in ARM documentation.
Also, return from handler when oveload is detected could set the processor state to thread mode. Let's ignore that for now.
void SysTickHandler(void) {
ticks++;
//set_BASEPRI(max_value);
if (f1_act || f2_act || f3_act) return;
else {
f1();
f2();
f3();
}
}
A simpler example for this problem (without return) would be to increase tick counter when having an infinite loop inside handler.
void SysTickHandler(void) {
ticks++;
set_BASEPRI(max_value);
while(1);
}
If the interrupt becomes pending while its handler is already running, the handler will run to completion and immediately re-enter. Your tick will be aperiodic, and if the functions consistently take longer that one tick period, you may never leave the interrupt context.
It may be possible I suppose to increase the priority of the interrupt in the handler so that it will preempt itself, but even if that were to work, I would hesitate to recommend it.
It sounds that what you actually need is an RTOS.
Sorry to disappoint you, but it seems a overall design problem to me...
Why won't you just set some flag in SysTick and read it somewhere else?
Like:
#include <stdbool.h>
volatile bool flag = false;
//Consider any form of atomicity here
//atomic_bool or LDREX/STREX instructions here. Bitbanding will also work
void sysTickHandler(void) {
ticks++;
if (f1_act || f2_act || f3_act) return;
else {
flag = true; //or increment some counter if you want to keep track of the amount of executions
}
And somewhere else:
int main() {
// some init code
//main loop
for(;;) {
foo();//do sth
bar(x); //do sth else
if (flag) {
f1();
f2();
f3();
flag = false;
}
}
}
Or if we assume that every interrupt wakes the microcontroller and power-down mode is needed, then sth. like this might work:
if (flag) {
f1();
f2();
f3();
flag = false;
}
goToSleep(powerDownModeX); //whatever;
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.