Using CCS, embededded programming, MSP430F63736A
In my app I´m usingTimer A to switching LED(ON/OFF) for various time.
For example:
Led is ON - 0.5 sec
Led is OFF- 3 sec
I need to reset timer when it reach the value in register TA1CCR0. These times(0.5 s and 3 s) are in the register TA1CCR0. The problem is, that if I change the value of register TA1CCR0 from 0.5 sec to 3 sec, it will count from 0.5 to 3 sec. And I need a full 3 sec so I need a reset timer.
Thats the interrupt routine where I´m switching LED
if (P4OUT == 0x00)
{
P4OUT ^= BIT6; // LED ON
TA1CCR0 = (sekunda*t1); //t1- 3 s.... pc 2s
}
else
{
P4OUT = 0x00;
TA1CCR0 = (sekunda*t2);
}
}
Which counter mode are you using? You need to set the mode by writing to the TA1CTL register. The modes are:
#define MC_0 (0x0000) /* Timer A mode control: 0 - Stop */
#define MC_1 (0x0010) /* Timer A mode control: 1 - Up to CCR0 */
#define MC_2 (0x0020) /* Timer A mode control: 2 - Continuous up */
#define MC_3 (0x0030) /* Timer A mode control: 3 - Up/Down */
"Continuous" mode is typically the most used one. It counts until the overflow of the timer register, then restarts from zero. If you have it enabled, add to CCR continuously rather than setting it to the interval value:
TA1CCR0 += (sekunda*t1);
You can also use the "up" mode. In that case the timer counter should automatically reset to zero after reaching CCR. If you're modifying CCR within the ISR and then apparently this reset does not happen, you can modify the timer counter register (TAR or TA1R) by subtracting the value of the shortest period. Do not just set the timer register to zero, as it's usually not a good coding practice: it opens doors for timing inaccuracy accumulation in case the ISR calls are occasionally delayed (e.g. because some other interrupt is execution for multiple ticks).
In your ISR add an offset to TA1CCR0 and not reset it:
Say you want a 1 sec delay after the first interrupt, and let's say to generate 1 sec delay the timer must count up to 50000. So what you need to do in you ISR is TA1CCR0 +=50000.
In your case:
if (P4OUT == 0x00)
{
P4OUT ^= BIT6; // LED ON
TA1CCR0 += (sekunda*t1); //t1- 3 s.... pc 2s
}
else
{
P4OUT = 0x00;
TA1CCR0 += (sekunda*t2);
}
}
For an a complete example please see
Related
I'm trying to figure out if there is a way of using any of the timers to generate interrupts at more than one delay time.
E.G. I want to be able to start a timer, then have it cause interrupts at say 20us, 50us, 100us, 300us.
I can see that its perfectly possibly (and easy) to have timers cause an interrupt when the end of the count has elapsed (using HAL) but having trouble working out if I can do what I want using only one timer.
I notice some timers are 4 channel but not sure if they can be set as required.
I guess my fall back is to use one timer for each (but ideally I would like to keep other timers in case they are needed for other tasks).
I've read the docs but having trouble understanding if the device can be configured as I want it to.
The easiest way - is to change the timer period (write a different value to the ARR register, use __HAL_TIM_SET_AUTORELOAD macro if you prefer HAL) in each interrupt. This way every other period could be different.
Just keep in mind ARR buffering, or Auto-reload preload, see ARPE bit decription in TIMx_CR1. if it is enabled - the new value of ARR will be taken in account only after the next update event.
You can have more than one interrupt generated during one cycle. You need to use output compare registers and enable their interrupts.
In the timer interrupt handler routine you will need to check what has triggered the interrupt.
There are multiple ways you can achieve it. One a little blunt and simple, another one slightly more complicated, but once set up, very effective and quick to process.
Approach number 1, a little limited, but also a little simpler: use capture/compare (in this case, compare specifically) to trigger an interrupt. Since timers have up to 4 capture/compare values, you can have up to 4 interrupts. You will have to check which exactly interrupt fired tho in the handler. Which specifically compare value, I mean.
Approach number 2, more flexible, more precise, but a bit more hassle to set up: master-slave timers. You can have one timer (including basic) be the clock source for the other timers ("tick" on the rising edge of master slave setting). For example, master timer ticks at 10kHz, and its slave timer uses its output as a clock source and ticks to, say, 50. Or 100. You can have multiple slaves. Depending on what timer's interrupt fires, you know right away how much time exactly passed, no need to check values in compare register or anything.
Mixed method: slave timers can have capture/compare too by the way, if you're into that. You can create huge timer chains if you want to.
You have a dozen timers in your MCU, you can probably spare 1 or 2 more for this purpose. Once you get it working, should make your life very easy.
This is how I set up a timer that is a slave, but also a master to another timer. TMR is TIM3 with TIM1 as a master:
/*
* CR1 reset value = 0x00000000
* ARR is not buffered
* upcounter (default)
* update request source: only overflow/underflow
*
* */
TMR->CR1 = 0x00; //reset
TMR->CR1 |= TIM_CR1_URS;
/*
* 108MHz Clock, 64000 prescaler -> 2kHz Timer Clock
* Reload value 6, Period = 6/2000s = 3ms
* */
TMR->PSC = (108000U / 2U) - 1U; //APB1 is 54MHz, timer is 2x APB1 Freq, so now the timer is at 2kHz; 16-bit value!!! 65535 max!
TMR->ARR = 6U - 1U; //6 ticks at 2kHz is 3ms
TMR->CNT = 0x00; //start value
TMR->EGR |= TIM_EGR_UG; //force update event and load all values into registers
TMR->SR &= ~TIM_SR_UIF; //force clear update event
/*
* SMCR Slave Mode Control Register reset value = 0x00000000
* Trigger Selection - ITR0 (TIM1 as Master for TIM3)
* Slave Mode Selection - Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
* reset). Only the start of the counter is controlled (0b0110)
*/
TMR->SMCR = 0x00; //reset
TMR->SMCR |= (0x00 << TIM_SMCR_TS_Pos) | (0x00 << 16U) | (0x06 << TIM_SMCR_SMS_Pos);
/*
* CR2 reset value = 0x00000000
* Master Mode Selection 1: OC1REF Triggers TRGO to start another timer
* Master Mode Selection 2: reset
* Compare value: 4 (output LOW: CNT = 0, 1, 2, 3; output HIGH CNT = 4, 5)
* Duty cycle: 33.33%
* Output compare 1 mode - PWM mode 2 (0b0111)
*
* */
TMR->CR2 = 0x00; //reset
TMR->CR2 |= (0x04 << TIM_CR2_MMS_Pos); //OC1REF as TRGO
TMR->CCR1 = 4U;
TMR->CCMR1 = 0x00;
TMR->CCMR1 |= (0x07 << TIM_CCMR1_OC1M_Pos);
/*
* Capture Compare Enable Register
* Polarity: default - active high
* Capture Compare Output Enable
* */
TMR->CCER = 0x00; //reset
TMR->CCER |= TIM_CCER_CC1E;
The rest of my example/training project, including screenshots of waveform, are here: Github Chained Timers Demo. There you will find TIM1 to be the master, TIM3 its slave and the master of TIM5, and so on. Timers are connected in different master-slave modes.
I'm creating part of a program right now for a personal project. This is my first year ACTUALLY coding and have been studying for hours to understand many concepts so please be nice and try not to be rude as others have...
The project of mine is an AVRDUDE using a chip called ATMEGA328P in a program called Microchip studios.
[This project is having 3 LED count every time a switch is pressed, I should have them count continuously and change to the next number every second using a TIMER 1.
**counting in binary from 0-8 then rolling over **
I need some help on one aspect of it which is using interrupts after I have already created a blinking LED to use a TIMER0 instead of delays.
I have made my fourth LED flash at 5Hz which is the blinking part of my code include below at the end of this question.
Now the problem I am running into is trying to create interrupts for the 3 LEDS count every time a switch is pressed, I should instead have them continually count, changing to the next number approximately every second, using TIMER1.]
This is my code for the project
Again please be nice and at least lead me in some type of direction...
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
int global = 0 ;
volatile uint8_t overflow0; // Variable for counting overflows for first timer
volatile uint8_t overflow1; // Variable for counting overflows for second timer
void FirstTimer() // Initialize Timer 1
{
TCCR0B |= (1<<CS02) | (1<<CS00); // Prescaler of 1024
TCNT0 = 0;
}
void SecondTimer() //Initialize Timer 2
{
TCCR1B |= (1<<CS11) | (1<<CS10);
TCNT1 = 0;
}
int main(void)
{
DDRB |= (1 << DDB0);
FirstTimer(); // Calling timer 1 and 2 initialization
SecondTimer();
while (1)
{
{
if (TCNT0 >= 195) // Amount of ticks needed
{
PORTB ^= (1 << PORTB0); //LED on
TCNT0 = 0; //Reset counter
}
}
{
if (TCNT1 >= 15625) // Ticks needed
{
TCNT1 = 0; // Timer reset
}
}
}
}
An approach you could use is keeping a count variable (unsigned char - assuming 8 bit register width) and in your Timer ISR simply increment the count and write that value to the output register. Once count > 8 set to zero.
Configure the Timer mode to trigger on overflow w/ reset to zero.
Then you do some basic math using the clock speed and timer ceiling (overflow value) to calculate the frequency you want the overflow ISR to occur (increment the LED count values).
Note that for this to work the LEDs need to be on the first 3 pins.
i.e.
P1.0 = LED1
P1.1 = LED2
P1.2 = LED3
...
If not connected like this then you can still make it work with additional bit manipulation (shifts and masks).
How to get accurate milliseconds?
I need to calculate the delay of sending data from Arduino A to Arduino B. I tried to use DS3231 but I cannot get milliseconds. What should I do to get accurate milliseconds from DS3231?
The comment above is correct, but using millis() when you have a dedicated realtime clock makes no sense. I'll provide you with better instructions.
First thing in any hardware interfacing project is a close reading of the datasheet. The DS3231 datasheeet reveals that there are five possible frequencies of sub-second outputs (see page 13):
32 KHz
1 KHz
1.024 KHz
4.096 KHz
8.192 KHz
These last four options are achieved by various combinations of the RS1 and RS2 control bits.
So, for example, to get exact milliseconds, you'd target option 2, 1KHz. You set RS1 = 0 and RS2 = 0 (see page 13 of the datasheet you provided) and INTCN = 0 (page 9). Then you'd need an ISR to capture interrupts from the !INT/SQW pin of the device to a digital input pin on your Arduino.
volatile uint16_t milliseconds; // volatile important here since we're changing this variable inside an interrupt service routine:
ISR(INT0_vect) // or whatever pin/interrupt you choose
{
++milliseconds;
if(milliseconds == 999) // roll over to zero
milliseconds = 0;
}
OR:
const int RTCpin = 3; // use any digital pin you need.
void setup()
{
pinmode(RTCpin, INPUT);
// Global Enable INT0 interrupt
GICR |= ( 1 < < INT0);
// Signal change triggers interrupt
MCUCR |= ( 1 << ISC00);
MCUCR |= ( 0 << ISC01);
}
If these commands in setup() don't work on your Arduino, google 'Arduino external interrupt INT0'. I've shown you two ways, one with Arduino code and one in C.
Once you have this ISR working and pin3 of the DS3231 connected to a digital input pin of your choosing, that pin will be activated at 1KHz, or every millisecond. Perfect!
// down in main program now you have access to milliseconds, you might want to start off by setting:
// When 1-second RTC changes seconds:
milliseconds = 0; // So you can measure milliseconds since last second.
That's all there is to it. All you need to learn now is how to set the command register using I2C commands and you're all set.
The C code example gains 1ms every second. Should be:
{
if (milliseconds == 999) // roll over to zero
milliseconds = 0;
else
++milliseconds;
}
The problem is that the timing behavior is totally wrong (factor 30).
I have an ATmega 644PA which is running with 8 Mhz (CKDIV8 fuse is not set).
I wanted an interrupt every 1 ms. I use Timer1 (16 bit timer) in the compare mode.
The prescaler was choiced by the timing range which i need.
Here 1 ms to ~2s. (limited through the 16 bit timer reg.)
Calculation
CPU: 8.000.000 Hz
Prescaler: 256
8.000.000 Hz / 256 = 31250 Cycles / s (Hz)
1000 ms = 31250 Cycles
1 ms = 30.25 Cycles (31.25 - 1, timer reg. start by 0)
From here i can calculate it up, for example:
100 ms = 3025 Cycles
2s = 60500 Cycles
Code
Timer Init
cli(); // disable global interrupts
TCCR1A = (1 << WGM01); // CTC ON
TCCR1B = 0x04; // Prescaler 256
OCR1A = 30; // set compare reg.
TIMSK1 = (1 << OCIE1A); // set interrupt mask
TCNT1 = 0x00; // set counter reg. to zero
sei(); // enable global interrupts
ISR:
ISR(TIMER1_COMPA_vect)
{
// start own code
...
// end own code
TCNT1 = 0x00; // reset counter reg. to zero after match (same which should CTC do)
}
Now i have for example a volatile variable which will be incremented in the ISR function.
I'm polling the variable and wait so long till it reach 60500, which is equal to 2s.
After it i just set an led on.
I measured it by phone and it takes 1 minute till the led goes on.
It takes to long with the factor 30 => 60s divided by 2s are 30.
I also tried to use an external program to calculate it, it came to the same results. (0x1E = 30)
Someone an idea where my mistake is ?
2 seconds is 60500 cycles. But your ISR is incrementing the volatile variable every 1 millisecond. Naturally, it will take 60.5 seconds for the variable to reach 60500.
As a side note, it is better to change the compare value, rather than reset TCNT, to avoid timing drift. That is, let the counter run freely, and use OCR1A += 31; to hit the next interrupt. Resetting TCNT as you do will ignore the time inside the ISR.
I developed an application to generate the pulses(pwm) using timer of lpc1769. The period of pulse is 10milli seconds and pulse width can be varied as required. The pulse width is generated depending on the reference signal which is a square wave of 10milli seconds(with on period of 7.2ms and off period of 2.8ms). whenever there is rising edge of this signal PWM pulse should start. Now this is working fine. To detect the rising edge i used GPIO interrupt with external interrupt3 the ISR is as :
1) if rising edge on GPIO pin(P2.11)
2) Clear the rising edge status on the pin.
3) then set the timer for few milli seconds
and in timer ISR
1) Clear any pending Timer IRQs
2)Make the GPIO pin high on which generating PWM pulse(P2.6)
3) set the timer for few milli seconds and then clear the pin(P2.6)(same timer is used in both the ISRs)
4) Disabling the timer and re enabling the rising edge interrupt on GPIO pin(P2.11), so again serves the ISR of external interrupt3 on rising edge of reference signal and it continues as above.
Now i am getting the problem in the code in developing the application as,
1) if rising edge disable the interrupt and set timer to 8 milli seconds delay.
2) In timer ISR generate 10 pwm cycles after this re enable the external interrupt. (the same timer is used in both ISRs).
3) so my output should be with respect to rising edge of reference signal 8 milli second delay then 10 pwm cycles(all have time period of 10ms) again 8ms delay with respect to rising edge of reference signal and 10 pwm cycles.
But once after 10 cycles when i re enable the external interrupt irrespective of rising edge of reference signal a delay of 8ms is added.
whenever last 10th cycle is complete I am enabling the interrupt again, so from this point only it adding a 8ms delay. My question is if interrupt is enabled for rising edge of reference signal then it should serve ISR for rising edge only. But this is not happening in this case. I am not understanding this behaviour.
/////////////////////////////////////////////////////////////////////////////////////////////////////
This is my code, this is ISR for external interrupt3
void GPIO_IRQ_HANDLER(void)
{
uit32_t i;
if(((Chip_GPIOINT_GetStatusRising(LPC_GPIOINT, GPIO_INTERRUPT1_PORT) >> GPIO_INTERRUPT1_PIN) & 0x01) != 0) /*Group 1*/
{
count1 = 0;
start_timer1((HALF_WAVE_PERIOD - DELAY) * timerTick);
NVIC_ClearPendingIRQ(GPIO_INTERRUPT_NVIC_NAME);
NVIC_DisableIRQ(GPIO_INTERRUPT_NVIC_NAME);
}
}
Timer1 ISR is
void TIMER1_IRQHandler(void)
{
if (Chip_TIMER_MatchPending(LPC_TIMER1, 1) == 0)
{
return;
}
Chip_TIMER_ClearMatch(LPC_TIMER1, 1);
if(count1 > 10)
{
LPC_GPIO1->PIN = (LPC_GPIO1->PIN & ~(1 << 19));
stop_timer1();
}
else
{
switch(state1)
{
case 1:
state1 = 2;
LPC_GPIO1->PIN = (LPC_GPIO1->PIN | (1 << 19));
set_timer1(2000 * timerTick);
break;
case 2:
state1 = 1;
LPC_GPIO1->PIN = (LPC_GPIO1->PIN & ~(1 << 19));
count1++;
set_timer1((HALF_WAVE_PERIOD - DELAY) * timerTick);
break;
default:
break;
}
}
}
where,
HALF_WAVE_PERIOD = 10000 microseconds
DELAY = 2800 microseconds
GPIO_INTERRUPT1_PORT= PORT2
GPIO_INTERRUPT1_PIN = P2.12
GPIO_INTERRUPT_NVIC_NAME = EINT3_IRQn
GPIO_IRQ_HANDLER = EINT3_IRQHandler
and functions start_timer1 is used to initialize the timer1 and set the timer1 for given number of ticks and interrupt on match.
set_timer1 : set timer1 for given ticks and interrupt.
stop_timer1 : disable the timer1 and enables the external interrupt3.