Try using the "volatile" keyword for any global variables changed in interrupt routines. You may be fighting compiler optimizations.
Yes the variable is volatile
#ifndef MYFILE_HPP
#define MYFILE_HPP
extern int myvar;
// your codes
#endif // MYFILE_HPP
// myfile.c
int myvar;
// or volatile int myvar;
When you change something that is global - like say a common header file - you have to ensure that all the modules that are affected by the change are also re-compiled - this should be written into your make file, but it's not always the case. You might have to force a re-compile of the whole project for the changes to take effect.
#include <inttypes.h>
#include <avr/io.h>
#include "main.h"
// System variables
extern uint16_t timer;
int main(void)
{
setup();
// test code
PORTA.DIRSET = 0x01 << PA7;
while (1)
{
if(timer > 10)
{
schedule_10ms();
timer = 0;
// test code
PORTA.OUTTGL = 0x01 << PA7;
}
}
}
#include "main.h"
// System variables
volatile uint16_t timer;
volatile uint16_t pulse0;
volatile uint16_t pulse1;
volatile uint8_t mode;
volatile uint8_t diagnostic = 0;
volatile uint16_t fan_speed;
volatile uint16_t scav_speed;
void setup(){
PORTF.DIRCLR = 0x01 << 4; // button input
PORTF.PIN4CTRL = 0x01 << 3; // enable button pin pullup
PORTD.DIRCLR = 0x01 << 3 || 0x01 << 4; //taco 0 & 1 input
PORTD.DIRSET = 0b11100000; // led outputs 0-2 PD5:7
PORTF.DIRSET = 0x1 << PF3; // led output 3
PORTF.DIRSET = 0x1 << PF0; //power switch control
PORTC.DIRSET = 0x01 << PC0; // fan_pwm
PORTC.DIRSET = 0x01 << PC1; // scav_pwm
PORTC.DIRSET = 0x01 << PC2; // charge pump pwm
PORTMUX.TCAROUTEA = 0x02; // Set TCA output on portC
TCA0.SINGLE.INTCTRL = 0x01; //enable OFL interrupt
TCA0.SINGLE.CTRLB = 0b01110011; // single slope PWM with all 3 output channel enabled
TCA0.SINGLE.CMP0 = 0xF; // Channel 0 compare value
TCA0.SINGLE.CMP1 = 0xF; // Channel 1 compare value
TCA0.SINGLE.CMP2 = 0xF; // Channel 2 compare value
TCA0.SINGLE.PER = 3333; // Top value for PWM counter to give 1KHz with a (10/3)MHz CLK_PER
TCA0.SINGLE.CTRLA = 0x01; //enable counter with no clock scaler
TCB0.CTRLB = (( TCB0.CTRLB & ~( 0x07 )) | ( 0x05 << 0 )); // Set counter mode to input capture frequency and pulse width measurement
TCB0.INTCTRL = ( TCB0.INTCTRL & ~0x01 ) | ( 0x01 << 0 ); // Enable capture compare interrupt
EVSYS.CHANNEL2 = 0b01001011; // event channel 2 connects to pin PD3
EVSYS.USERTCB0 = 3; // connect the counter to event channel 2 (3-1)
TCB0.CTRLA = (( TCB0.CTRLA & ~( 0x03 << 1 )) | ( 0x0 << 1 )); // Set clock to main clock (CLK_PER)
TCB0.CTRLA = (( TCB0.CTRLA & ~0x01 ) | 0x01 ); // Enable the counter (connects the counter to the clock source)
TCB1.CTRLB = (( TCB1.CTRLB & ~( 0x07 )) | ( 0x05 << 0 )); // Set counter mode to input capture frequency and pulse width measurement
TCB1.INTCTRL = ( TCB1.INTCTRL & ~0x01 ) | ( 0x01 << 0 ); // Enable capture compare interrupt
EVSYS.CHANNEL3 = 0b01001100; // event channel 2 connects to pin PD4
EVSYS.USERTCB1 = 4; // connect the counter to event channel 3 (4-1)
TCB1.CTRLA = (( TCB1.CTRLA & ~( 0x03 << 1 )) | ( 0x0 << 1 )); // Set clock to main clock (CLK_PER)
TCB1.CTRLA = (( TCB1.CTRLA & ~0x01 ) | 0x01 ); // Enable the counter (connects the counter to the clock source)
sei();
}
#include "main.h"
#include <avr/interrupt.h>
// System variables
extern uint16_t timer;
extern uint16_t pulse0;
extern uint16_t pulse1;
ISR(TCA0_OVF_vect){
timer = timer + 1;
TCA0.SINGLE.INTFLAGS = 0x01;
}
ISR ( TCB0_INT_vect ){
pulse0 = TCB0.CCMP;
TCB0.INTFLAGS = 0x01;
}
ISR ( TCB1_INT_vect ){
pulse1 = TCB1.CCMP;
TCB1.INTFLAGS = 0x01;
}
Just a thought here. You said you used the volatile qualifier, but how?
If you're just using it at the declaration, such as: "volatile int myvar;" but fail to add it in the header file (which would be: "extern volatile int myvar;", but maybe you just wrote: "extern int myvar;"), I think it's going to be ignored by the compiler while compiling any other C source file that includes the header. SO it must be added to the extern declaration as well.
Ideally I wanted to put all external (and volatile) variables in the one header file so that they are universally available.
I think the variable needs to be declared "volatile" in the header where it is "extern" as well as in the c file where the variable is actually declared.
QuoteIdeally I wanted to put all external (and volatile) variables in the one header file so that they are universally available.
That's fine. Just don't forget to make all your extern declarations fully qualified (ie. contain the same qualifiers as in the original declarations).
Not going to discuss the merits or drawbacks of using an excessive number of global variables here. I will just suggest limiting them when you can, because it can get messy real fast.
A few critical globals - that's fine.
One possible approach with your timer example, unless accessing (reading) the variable is extremely time-critical, you could use an accessor function instead of making the variable global. Said function is declared inside the same C file as the variable, and just returns its value. Just export the prototype of the function. Several added benefits of this (to name a few): it makes the possibility of modifying the variable outside of its intended scope impossible (it becomes effectively "read-only" to the outside source files), and it allows to add extra tests or guarding instructions when reading it: for instance, if the variable is too large to be read atomically on your target, your accessor function can include guarding instructions (for instance: disabling the timer interrupt, reading the variable in a local variable, re-enabling the timer interrupt, and finally returning the local variable...)
what is an atomic declaration?
what is re-ordering evaluation.
With regard to the timer variable it needs up-counting by the interrupt routine, testing by the main if statement which could be done with what yo describe but it needs zeroing again by the "if"s code.
With regard to the timer variable it needs up-counting by the interrupt routine, testing by the main if statement which could be done with what yo describe but it needs zeroing again by the "if"s code.
Which in the same approach, can be perfectly done adding another function that resets the counter. And call that instead of directly assigning "0" to the variable.
Probably not be worthwhile on a small or embedded project, but then again, embedded CPUs are awfully powerful these days; a Cortex M0 at 160MHz doing the job of a PIC at 8MHz say? Lots of room for verbosity.