I am using MSP430F5418 with IAR EW 5.10.
I want to use Timer B in up mode.
I want to use two interrupts.
TimerB0(1 ms) and TimerB1(1 second).
My Configuration is
TBCTL = MC__UP + TBSSEL__ACLK + TBCLR;
TB0CCTL0 = CCIE;
TB0CCR0 = 32;
TB0CCTL1 = CCIE;
TB0CCR1 = 32768;
On the ISR I just toggled two pins.
But only the pin for TB0CCR0 is toggling.
My Pin Configurations are correct.
Can anyone tell me why??
I suppose your problem is the timer period.
MC__UP Up mode: Timer counts up to TBxCL0
So your timer TBxR will reset to 0 when it reaches TBxCL0 which seems to be the value TB0CCR0.
So it can never reach the value of 32768.
You could switch TB0CCR0 with TB0CCR1, so your period will be 1 second.
And to get your 1ms interrupt you need to increment your TB0CCR1 each time.
INTERRUPT ISR_1MS()
{
TB0CCR1 = (TB0CCR1 + 32) & 0x7FFF;
}
But normally you don't need a second timer for a second intervall.
You could simply count 1000 times your 1ms intervall.
INTERRUPT ISR_1MS()
{
ms_count++;
if (ms_count >= 1000)
{
ms_count=0;
// Do your second stuff
}
}
And if you need more and different intervalls, you could change to another model.
To a system clock time and check only against this time.
volatile unsigned int absolute_time=0;
INTERRUPT ISR_1MS()
{
absolute_time++;
}
unsigned int systime_now(void)
{
unsigned int result;
di();
result = absolute_time;
ei();
return result;
}
uint8_t systime_reached(unsigned int timeAt)
{
uint8_t result;
result = (systime_now() - timeAt ) < 0x1000;
return result;
}
Related
Coming from this question and I just wonder How to calculate maximum time that an Atmega328 timer can give us before trigger an interrupt? I want it to trigger every hour or so in my project but due to the fact that C integer and OCR1A register has some limitation in size it seems far fetch to get an hour from it.
Is it possible to modify my last question code to get some hour delay?
It should be, depending on the frequency of your microcontroller and the prescaler you're going to use.
Atmega 328P is 20 MHz. So if you take 20,000,000/1024 = 19531. Thats the number of cycles in 1 second.
You can find this in the data sheet for a 16 Bit Timer:
volatile uint8_t count = 0;
void set_up_timer() {
TCCR1B = (1 << WGM12); // from the datasheet
OCR1A = 19531; // number of ticks in a second
TIMSK1 = (1 << OCIE1A); // from the data sheet
TCCR1B |= (1 << CS12) | (1 << CS10);
You can set a global variable, and increment it in the ISR Routine until the desired value is achieved. Something along the lines of:
ISR(TIMER1_COMP1_VECT) {
counter++;
if(counter >= 3600) {
// do whatever needs to be done
}
The comment by Jabberwocky translates to this code (based on the other question to which your have posted the link)
... includes
/* In milliseconds */
const unsigned int ISR_QUANTUM = 1000; // once in a second
/* How much time should pass (1 hours = 3600 seconds = 3600 * 1000 ms */
const unsigned long LONG_TIME_INTERVAL = 1000 * 3600;
volatile unsigned long time_counter;
void once_an_hour() {
... do what needs to be done
}
int main(void) {
... setup your timer interrupt (high-precision, "short-range")
// reset your 'seconds' time counter
time_counter = 0;
while (1)
{
// busy-wait for time counter passing
if (time_counter > LONG_TIME_INTERVAL) {
// reset global timer
time_counter = 0;
once_an_hour();
}
// do other things
...
}
}
ISR (TIMER1_COMPA_vect)
{
// action to be done every Xms - just increment the time_counter
time_counter += ISR_QUANTUM;
}
This way you just increment a "global" time counter in a "local" interrupt handler.
So I've initialized a timer which I want to count for 100
main section where stm32 works.
#include "stm32l0xx.h"
#define SYSCLK_FREQ 131072
void timer_tick(uint16_t n_ms);
int main(void)
{
TIM6->PSC = (SYSCLK_FREQ/1000)-1; //100us
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; //one-pulse mode
TIM6->EGR = TIM_EGR_UG; //generate update
TIM6->SR=0; //clear update - after few instructions
...
}
first time I am using the timer there, its declared right after main
void delay(uint16_t n_ms)
{
//upcounting timer - 16bit
TIM6->CNT = 65535-n_ms;
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; //one-pulse mode
while(!(TIM6->SR & TIM_SR_UIF)); //wait
TIM6->SR = 0;
}
than Iam using the same timer (becouse I have only TIM3 which I cannot interupt and TIM6 used only for delay function)
void timer_tick(uint16_t n_ms)
{
//upcounting timer - 16bit
TIM6->CNT = 65535-n_ms;
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; //one-pulse mode
TIM6->ARR = n_ms-1; // Auto reload value
TIM6->CCR1 = n_ms; // Start PWM duty for channel 3
//TIM6->CCR2 = n_ms; // Start PWM duty for channel 4
TIM6->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1; // PWM mode on channel 1 & 2
TIM6->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E; // Enable compare on channel 1 & 2
TIM6->DIER = TIM_DIER_UIE; // Enable TIM6 interrupt
TIM6->SR = 0;
}
And here working on interupt. Iam calling the function to start the clock counting to 100 (Iam assuiming its right) than interuption realising switch that can work only 100 ms - after its gotta stop working on it and break the loop.
void USART1_IRQHandler(void)
{
static enum {00, 01, 02, 03, CRC} next_frame = 00; // frame construction
if(!sending_flag) //half-duplex
{
if(USART1->ISR&USART_ISR_FE) //frame error check&clear
USART1->ICR = USART_ICR_FECF;
else
timer_tick(100);
do {
switch(next_frame)
{
case 00:{ DOSTUFF; next_frame=01; break; } //starting marker
case 01:{ DOSTUFF; next_frame=02; break; }
case 02:{ DOSTUFF; next_frame=03; break; }
case 03:{ DOSTUFF; next_frame=CRC; break; }
case CRC:{ TIM6->SR = ~TIM_SR_CC2IF; break; } // clear flag
default: break;
}
} while (!(TIM6->SR&TIM_SR_CC2IF)); //TIM_SR_UIF
}
if(USART1->ISR & USART_ISR_TC)
{
USART1->ICR = USART_ICR_TCCF;
GPIOA->BSRR = GPIO_BSRR_BR_11 | GPIO_BSRR_BR_12;
sending_flag=0;
}
}
I dont realy understend documentation of my STM about the timers.
Having this line set like that TIM6->CCR1 = n_ms; // Start PWM duty for channel 3 Iam assuming there should be a flag at TIM6->SR&TIM_SR_CC2IF after timer reach TIM6->ARR = n_ms-1; // Auto reload value
After adding this do while loop my STM stopped responding and Iam not able to debug it.
Is the counter set right?
Can I use declared timer twice and call it like I do?
Is the counter set right?
Not really. There are a lot of problems in your timer configuration, lets try to spot some of them:
#define SYSCLK_FREQ 131072
TIM6->PSC = (SYSCLK_FREQ/1000)-1; //100us
Timer is connected to some APB bus (1 or 2), which can be also
divided. If You set new APB divider value, your timer will no longer
work as you would expect.
Clock frequency = 131072 ? Independent of unit, you will not achieve 100us period by dividing it by 1000.
void delay(uint16_t n_ms)
{
//upcounting timer - 16bit
TIM6->CNT = 65535-n_ms;
TIM6->CR1 = TIM_CR1_CEN | TIM_CR1_OPM; //one-pulse mode
while(!(TIM6->SR & TIM_SR_UIF)); //wait
TIM6->SR = 0;
}
This is not the way you use timer. If you want to measure some time, just set ARR to right value and start the counter.
Your timer_tick(uint16_t n_ms) is totaly wrong. Counter is upcounting from 0 to ARR value, then stops (if one pulse mode is set). Firstly, set all the timer configuration registers, then start the counter. If you start the counter, then modify ARR, CCRX or other registers, you can be 100% sure, that timer will fall.
Afternoon all
I'm looking for some assistance please with something that has been confusing me whilst trying to learn timer interrupts
You'd be best treating me as a novice. I have no specific goal here other than learning something that I think would be useful feather to add to my cap!
I have written the below sketch as a stab at a rigid framework for executing different fcns at different rates. I've done something similar using millis() and whilst that worked I found it inelegant that a) there was no obvious way to check for task overruns and backing-up the execution rate and b) the processor is bunged up by checking millis() every program cycle.*
Essentially what I think should be a 1ms timer interrupt on Timer2 (16MHz/64 prescaler /250 compare register =1000hz) is coming out around 0.5ms. I've been confused for hours on this but I'm prepared to accept it could be something fundamental/basic!
What's also throwing a spanner in the works is that using serial comms to try and debug the faster task rates seems to slow things down considerably, so I'm inferring the problem by counting up 1ms tasks to call 10,100 and 1000ms tasks and debugging at the slower level. I suppose chewing through a few characters at 9600baud probably is quite slow.**
I've pasted the code below. Any pointers highly appreciated. Be as harsh as you like :)
cheers
Al
*Whilst not what I'm confused about - any comments on my logic here also welcome
** Although I don't get how Serial.println manages to slow the program down. It's driven from interrupts so it should surely just drop the comms and perform the next ISR - effectively a task overrun. Any comments here also welcome
//NOTES
//https://www.robotshop.com/letsmakerobots/arduino-101-timers-and-interrupts
//https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
//http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf
//
//INITIALISE EVERYTHING
const int ledPin = 13;
volatile int nStepTask1ms = 0; // init 0 - to be used for counting number of 1ms tasks run and hence calling 10ms task
volatile int nStepTask10ms = 0;
volatile int nStepTask100ms = 0;
volatile int nStepTask1000ms = 0;
volatile int LEDFlashState = 0; // init 0 - variable to flip when LED on
volatile int millisNew = 0; // to store up to date time
volatile int millisOld = 0; // to store prev time
volatile int millisDelta = 0; // to store deltas
//
void setup()
{
Serial.begin(9600); //set up serial comms back to PC
pinMode(ledPin,OUTPUT); //to flash the embedded LED
noInterrupts(); //turn off interrupts while we set the registers
//set up TIMER first
TCCR2A = 0; //sets TCCR1A byte to zero, bits to be later individually mod'd
TCCR2B = 0; //sets TCCR1B byte to zero, bits to be later individually mod'd
TCNT2 = 0; //ensures counter value starting from zero
Serial.println("Timer1 vars reset");
TCCR2B |= (1<<WGM12); // bitwise or between itself and WGM12. TCCR2B = TCCR2B | 00001000. Sets WGM12 high. (CTC mode so WGM12=1, WGM 13,11,10 all 0) https://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work
Serial.println("Mode 4 CTC set");
Serial.println("TCCR2B=");
Serial.println(TCCR2B,BIN);
TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)
Serial.println("Prescaler set to 64");
OCR2A = 250; //compare match register for timer2
Serial.println("Compare Register set");
Serial.println("OCR2A=");
Serial.println(OCR2A);
TIMSK2 |= (1 << OCIE2A); //enables interrupts - https://playground2014.wordpress.com/arduino/basics-timer-interrupts/
Serial.println("Interrupt Mask Register Set");
Serial.println("TIMSK2=");
Serial.println(TIMSK2);
interrupts(); //enable interrupts again - not sure if this is required given OCIE1A being set above?
}
//set up ISR for Timer2 - timer structure called every interrump (1ms) that subsequently calls 1,10,100 and 1000msec task fcns
ISR(TIMER2_COMPA_vect)
{
TASK_1ms();
if (nStepTask1ms>9)
{
TASK_10ms();
if (nStepTask10ms>9)
{
TASK_100ms();
if (nStepTask100ms>9)
{
TASK_1000ms();
}
}
}
}
void TASK_1ms()
{
// 1ms tasks here
nStepTask1ms++;
}
void TASK_10ms()
{
//10ms tasks here
nStepTask1ms=0;
nStepTask10ms++;
}
void TASK_100ms()
{
//100ms tasks here
nStepTask10ms=0;
nStepTask100ms++;
//Serial.println(nStepTask100ms);
}
void TASK_1000ms()
{
//1000ms tasks here
nStepTask100ms=0;
//do something
changeLEDFlashState();
//check timing tick of this task
millisNew=millis();
millisDelta=millisNew-millisOld;
Serial.println(millisDelta);
millisOld=millisNew;
nStepTask1000ms++;
}
void changeLEDFlashState()
{
if(LEDFlashState==0)
{
digitalWrite(ledPin,HIGH);
LEDFlashState=1;
//Serial.println("LED Turned On");
}
else
{
digitalWrite(ledPin,LOW);
LEDFlashState=0;
//Serial.println("LED Turned Off");
}
}
void loop()
{
// empty
}
You have two lines here:
TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)
These two lines set the lower three bits of TCCR2B to 011, which is a /32 prescaler.
Note that for Timer1 and Timer2, the prescaler settings are different than Timer0.
For Timer0, the settings above would give you a /64 prescaler.
I want to configure timer1 of PIC24F16KA102 to count it. The clock source must be the internal clock of 8 MHz. I configured the register T1CON and set on high level the bit TON to start the timer. Timer1 is set to go in overflow every 100 us, then with a while cycle I wille increase the variable count. I'am not understanding because timer1 don't work, I observed that it does not increase. Why?
#include <xc.h>
#include "config.h"
int count = 0;
void main(void) {
TRISB = 0;
T1CON = 0; //TRM1 stopped, internal clock source, prescaler 1:1
_TON = 1;
TMR1 = 65135; //overflow of TM1 every 100 us (400 counts)
while (1) {
if (TMR1 == 65535) {
count++; // increase every 100 us
TMR1 = 65135;
}
}
}
Try setting the Timer 1 period register (PR1) and using an interrupt rather than trying to catch and reload TMR1 on its final count. You're trying to catch TMR1 on EXACTLY 65535, and that will almost never work because once TMR1 hits 65535, it's just going to overflow and begin counting from 0 again.
EDIT: Of course, this assumes it counts at all. I don't know what the behavior of a timer is when you leave the period register at 0. It may simply count to it's maximum of 65535 then reset to 0, or it may never count at all and continuously load PRx into TMRx since they match at 0
PRx is meant to define the period you want for a given timer, in this case 100uS. PR1 = 400. Once TMR1 = PR1, the timer will reset itself automatically and raise an interrupt to alert you that the timer has elapsed.
volatile unsigned int count = 0; //Vars that change in an ISR should be volatile
PR1 = 400; //Set Period for Timer1 (100us)
T1CON = 0x8000; //Enable Timer1
IEC0bits.T1IE = 1; //Enable Timer1 Interrupt
IPC0bits.T1IP = 0b011;
Pair this with an ISR function to increment count whenever the timer elapses:
void __attribute__ ((interrupt,no_auto_psv)) _T1Interrupt (void)
{
count++;
IFS0bits.T1IF = 0; //Make sure to clear the interrupt flag
}
You could also try something like this without any interrupts:
void main(void){
unsigned int count = 0;
TMR1 = 0;
T1CON = 0x8000; //TON = 1
while(1){
if (TMR1 >= 400){
count++;
TMR1=0;
}
}
}
However I would recommend using the PR register and an ISR. This is what it's meant to do.
EDIT: I would also recommend reading the PIC24F Reference Manual on timers:
Here
There seems to be a conflict between timer 2 and timer 3. This is a MIPS board and instead of using assembly language to program; I am using C. Timer1 is for a count which works properly. Timer2 is for a blinking LED which works properly. Timer3 is for switching count directions. But there is a conflict between timer2 and timer3. Does anyone know where the conflict is? I have to comment out DelayInit3(); in order for the code to execute properly.
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
// clear the interrupt flag
mT2ClearIntFlag();
PORTToggleBits(IOPORT_B, BIT_10);
}
void __ISR(_TIMER_23_VECTOR, ipl2) Timer23Handler(void)
{
// clear the interrupt flag
mT3ClearIntFlag();
if (direction != 0){
direction < 1;
}
else{
direction != 0;
}
}
int main()
{
DeviceInit();
DelayInit1();
DelayInit2();
// DelayInit3();
}
void DelayInit1()
{
unsigned int tcfg1;
/* Configure Timer 1. This sets it up to count a 10Mhz with a period of 0xFFFF
*/
tcfg1 = T1_ON|T1_IDLE_CON|T1_SOURCE_INT|T1_PS_1_8|T1_GATE_OFF|T1_SYNC_EXT_OFF;
OpenTimer1(tcfg1, 0xFFFF);
}
void DelayInit2()
{
unsigned int tcfg2;
// Config Timer 2. This sets it to count 312500 Hz with a period of T2_TICK
tcfg2 = T2_ON | T2_SOURCE_INT | T2_PS_1_32;
OpenTimer2(tcfg2, T2_TICK);
// Now enable system-wide multi-vector interrupt handling
INTEnableSystemMultiVectoredInt();
// Configure timer 2 interrupt with a priority of 2
ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
// Clear interrupt flag
mT2ClearIntFlag();
}
void DelayInit3()
{
unsigned int tcfg3;
// Config Timer 3. This sets it to count 312500 Hz with a period of T3_TICK
tcfg3 = T3_ON | T3_SOURCE_INT | T3_PS_1_256;
OpenTimer23(tcfg3, T23_TICK);
// Now enable system-wide multi-vector interrupt handling
INTEnableSystemMultiVectoredInt();
// Configure timer 3 interrupt with a priority of 2
ConfigIntTimer23(T23_INT_ON | T23_INT_PRIOR_2);
// Clear interrupt flag
mT3ClearIntFlag();
}
You should also toggle the bits at every timer end. The order that you are toggling is wrong. At every timer finish, you are toggling BIT10 twice, i.e. getting it back to initial position.
You can use code like this.
count = 0; // in Init.
while(1)
{
if (IFS0bits.T2IF == 1)
{
//if timer == period, toggle the LED
count++;
PORTToggleBits(IOPORT_B, BIT_10);
if (count %2 == 0)
{
DelayMs(2);
PORTToggleBits(IOPORT_B, BIT_11);
}
if (count > 3)
count = 0;
mT2ClearIntFlag();
}
}
You are toggleing the Bit 10 with a delay of 2 ms to it's first state. Even if this works, you will not notice.