interrupt C timers - c

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.

Related

STM32 Using TIMer to break loop

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.

Timer1 on PIC24F16KA102 don't work

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

Embedded C code to control a DC motor with a PIC microcontroller

Im trying to create an embedded c code to control a dc motor with the PIC32MX460F512L microcontroller. Ive Configured the system clock at 80MHz, and the peripheral clock at 10MHz, Am using Timer 1 for pulsing the PWM with a given duty cycle, and Timer 2 for measuring the motor run time. I have a header file(includes.h) that contains system configuration information eg clock. Ive created most of the functions but some are a bit challenging. For example, initializing the LEDS and the functions for forward, backward movements and stop, I wanted the dc motor to run in forward direction for 4 sec at 70% duty cycle, then stop for 1 sec then reverse for 3 sec at 50% duty cycle and then stop for 1 sec and then forward again for 3 sec at 40% duty cycle, stop for 1 sec and finally forward for 5 sec at 20% duty cycle. Any suggestions for the forward, stop, and reverse functions
#include <stdio.h>
#include <stdlib.h>
#include <includes.h>
void main()
{
// Setting up PIC modules such as Timers, IOs OCs,Interrupts, ...
InitializeIO();
InitializeLEDs();
InitializeTimers();
while(1) {
WaitOnBtn1();
Forward(4.0,70);
Stop(1.0);
Backward(3.0,50);
Stop(2);
Forward(3.0,40);
Stop(1.0);
Backward(2.0,20);
LEDsOFF();
}
return;
}
void InitializeIO(){
TRISAbits.TRISA6 = 1;
TRISAbits.TRISA7 = 1;
TRISGbits.TRISG12 = 0;
TRISGbits.TRISB13 = 0;
LATGbits.LATB12 = 0;
LATGbits.LATB13 = 0;
return;
}
void InitializeLEDs(){
//code to initialize LEDS
}
void InitializeTimers(){
// Initialize Timer1
T1CON = 0x0000; // Set Timer1 Control to zeros
T1CONbits.TCKPS=3; // prescale by 256
T1CONbits.ON = 1; // Turn on Timer
PR1= 0xFFFF; // Period of Timer1 to be full
TMR1 = 0; // Initialize Timer1 to zero
// Initialize Timer2
T2CON = 0;
T2CONbits.TCKPS = 7; // prescale by 256
T2CONbits.T32 = 1; // use 32 bits timer
T2CONbits.ON = 1;
PR2 = 0xFFFFFFFF; // Period is set for 32 bits
TMR2 = 0;
}
void WaitOnBtn1(){
// wait on Btn1 indefinitely
while(PORTAbits.RA6 == 0);
// Turn On LED1 indicating it is Btn1 is Pushed
LATBbits.LATB10 = 1;
return;
}
void Forward(float Sec, int D){
int RunTime = (int)(Sec*39000); // convert the total
time to number of Tics
TMR2 = 0;
//LEDs
LATGbits.LATG12 = 1; // forward Direction
LATBbits.LATB12 = 0;
LATBbits.LATB13 = 0;
LATBbits.LATB11 = 1;
// Keep on firing the PWM as long as Run time is not
elapsed
while (TMR2 < RunTime){
PWM(D);
}
return;
}
void PWM(int D){
TMR1 = 0;
int Period = 400;
while (TMR1< Period) {
if (TMR1 < Period*D/100){
LATGbits.LATG13 = 1;
}
else{
LATGbits.LATG13 = 0;
}
}
Functions, not methods, to be precise.
So what is exactly the question?
What I can say from a quick look on a source code:
LEDs initialisation should be done as you did in InitializeIO() function. Simply set proper TRISx bits to 0 to configure LED pins as output.
For the PWM and motor control functions you should take some time and try to understand how builtin PWM peripheral works. It is a part of OC (Output Compare) and it is very easy to use. Please, take look on following link http://ww1.microchip.com/downloads/en/DeviceDoc/61111E.pdf
and this one for the minimal implementation using builtin peripheral libraries https://electronics.stackexchange.com/questions/69232/pic32-pwm-minimal-example
Basically you need to set up OC registers to "make" OC module acts like PWM. You need to allocate one of the timers to work with OC module (it will be used for base PWM frequency) and that's it.
All you need after that is to set PWM duty cycle value by setting timer PRx register, you don't need to swap bits like in your PWM routine.
To stop it simple stop it simply disable the timer.
To run it again run the timer.
To change direction (it depends of your driver for the motor) I guess you need just to toggle direction pin.
I hope it helps...

Interrupt timer stuck when run parallel with while(1)

first code:
//------------------------------------------------------------------------------
/// Interrupt handlers for TC interrupts. Toggles the state of LEDs
//------------------------------------------------------------------------------
char token = 0;
void TC0_IrqHandler(void) {
volatile unsigned int dummy;
dummy = AT91C_BASE_TC0->TC_SR;
if(token == 1) {
PIO_Clear(&leds[0]);
PIO_Set(&leds[1]);
token = 0;
}
else {
PIO_Set(&leds[0]);
PIO_Clear(&leds[1]);
token = 1;
}
}
//------------------------------------------------------------------------------
/// Configure Timer Counter 0 to generate an interrupt every 250ms.
//------------------------------------------------------------------------------
void ConfigureTc(void) {
unsigned int div;
unsigned int tcclks;
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0; // Enable peripheral clock
TC_FindMckDivisor(1, BOARD_MCK, &div, &tcclks); // Configure TC for a 4Hz frequency and trigger on RC compare
TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
AT91C_BASE_TC0->TC_RC = (BOARD_MCK / div) / 1; // timerFreq / desiredFreq
IRQ_ConfigureIT(AT91C_ID_TC0, 0, TC0_IrqHandler); // Configure and enable interrupt on RC compare
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
IRQ_EnableIT(AT91C_ID_TC0);
printf(" -- timer has started \n\r");
TC_Start(AT91C_BASE_TC0);
}
it's just interrupt timer and it's event (handler) but when I run some
while(1) {
// action
after ConfigureTc() it both cycle and interrupt timer are freezes... Why could that be? Should I add another timer and avoid while(1) ?
while(1) {
printf("hello");
}
-- this breaks (freeze) loops (yes, if I don't use timer it works as it must)
I'll venture an actual answer here. IME, 99% of the time my boards 'go out' with no response on any input and no 'heartbeat' LED-flash from the low-priority 'blinky' thread, the CPU has flown off to a prefetch or data abort handler. These handlers are entered by interrupt and most library-defined default handlers do not re-enable interrupts, so stuffing the entire system. Often, they're just endless loops and, with interrupts disabled, that's the end of the story:(
I have changed my default handlers to output suitable 'CRITICAL ERROR' messages to the UART, (by polling it - the OS/interrupts are stuft!).

Timer in Up mode

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;
}

Resources