Hi all!!
How to generate variable frequency in lpc11xx controller, currently i'm getting fixed frequency on pin 27[CT16B0_MAT0] of 96.2hz, but I need to generate freq from 6hz to 20hz.
Below is the part of the code which I have compared:
void init_timer16(uint8_t timer_num, uint32_t TimerInterval) { if ( timer_num == 0 ) { LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7); LPC_IOCON->PIO0_2 &= ~0x07; /* Timer0_16 I/O config */ LPC_IOCON->PIO0_2 |= 0x02; /* Timer0_16 CAP0 */ LPC_IOCON->PIO0_8 &= ~0x07; LPC_IOCON->PIO0_8 |= 0x02; /* Timer0_16 MAT0 */ LPC_IOCON->PIO0_9 &= ~0x07; LPC_IOCON->PIO0_9 |= 0x02; /* Timer0_16 MAT1 */ #ifdef __JTAG_DISABLED LPC_IOCON->JTAG_TCK_PIO0_10 &= ~0x07; LPC_IOCON->JTAG_TCK_PIO0_10 |= 0x03; /* Timer0_16 MAT2 */ #endif timer16_0_counter = 0; LPC_TMR16B0->MR0 = TimerInterval; LPC_TMR16B0->MCR = 3; /* Interrupt and Reset on MR0 */ /* Enable the TIMER0 Interrupt */ NVIC_EnableIRQ(TIMER_16_0_IRQn); } else if ( timer_num == 1 ) { LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8); LPC_IOCON->PIO1_8 &= ~0x07; /* Timer1_16 I/O config */ LPC_IOCON->PIO1_8 |= 0x01; /* Timer1_16 CAP0 */ LPC_IOCON->PIO1_9 &= ~0x07; LPC_IOCON->PIO1_9 |= 0x01; /* Timer1_16 MAT0 */ LPC_IOCON->PIO1_10 &= ~0x07; LPC_IOCON->PIO1_10 |= 0x02; /* Timer1_16 MAT1 */ timer16_1_counter = 0; LPC_TMR16B1->MR0 = TimerInterval; LPC_TMR16B1->MCR = 3; /* Interrupt and Reset on MR1 */ /* Enable the TIMER1 Interrupt */ NVIC_EnableIRQ(TIMER_16_1_IRQn); } return; }
Kindly suggest how to process further.
Thank you.
And have you seen any significant issues with using a different timer interval?
No issues in the timer interval, but the problem is getting the variable frequencies, it's constant.
"the problem is getting the variable frequencies, it's constant"
Please explain: you have TimerInterval as a parameter to your function - why can't you just vary the value of that parameter??
The processor isn't going to produce varying frequencies. But it is possible to regularly change the frequency a single timer or DAC or PWM produces.
So I have to repeat my question - have you seen any problem using a different timer value? There are many different ways that a program may decide how/when it's time to modify the timer interval, resulting in a different generated frequency. But you - the designer - must figure out what your needs are and what solution that would work best for you.
I have changed the value of parameter timer interval & checked the output of Timer16B0 of MAT0 pin no 27[PIO0_8] to check the o/p connected an led across this pin but led goes high but it not returns to low & high state. Please check the first part of code[since the msg txt is too long] below. Help me how to attach the complete code.
#include <stdio.h> #include "LPC11xx.h" unsigned char msTicks; volatile uint32_t timer16_0_counter[4] = {0,0,0,0}; volatile uint32_t timer16_1_counter[4] = {0,0,0,0}; volatile uint32_t timer16_0_capture[4] = {0,0,0,0}; volatile uint32_t timer16_1_capture[4] = {0,0,0,0}; volatile uint32_t timer16_0_period = 0; volatile uint32_t timer16_1_period = 0; /***************************************************************************** ** Function name: delayMs ** ** Descriptions: Start the timer delay in milo seconds ** until elapsed ** ** parameters: timer number, Delay value in milo second ** ** Returned value: None ** *****************************************************************************/ void delayMs(uint8_t timer_num, uint32_t delayInMs) { if (timer_num == 0) { /* * setup timer #0 for delay */ LPC_TMR16B0->TCR = 0x02; /* reset timer */ LPC_TMR16B0->PR = 0x00; /* set prescaler to zero */ LPC_TMR16B0->MR0 = delayInMs * (SystemCoreClock / 1000); LPC_TMR16B0->IR = 0xff; /* reset all interrrupts */ LPC_TMR16B0->MCR = 0x04; /* stop timer on match */ LPC_TMR16B0->TCR = 0x01; /* start timer */ /* wait until delay time has elapsed */ while (LPC_TMR16B0->TCR & 0x01); } else if (timer_num == 1) { /* * setup timer #1 for delay */ LPC_TMR16B1->TCR = 0x02; /* reset timer */ LPC_TMR16B1->PR = 0x00; /* set prescaler to zero */ LPC_TMR16B1->MR0 = delayInMs * (SystemCoreClock / 1000); LPC_TMR16B1->IR = 0xff; /* reset all interrrupts */ LPC_TMR16B1->MCR = 0x04; /* stop timer on match */ LPC_TMR16B1->TCR = 0x01; /* start timer */ /* wait until delay time has elapsed */ while (LPC_TMR16B1->TCR & 0x01); } return; }
/****************************************************************************** ** Function name: init_timer16PWM ** ** Descriptions: Initialize timer as PWM ** ** parameters: timer number, period and match enable: ** match_enable[0] = PWM for MAT0 ** match_enable[1] = PWM for MAT1 ** match_enable[2] = PWM for MAT2 ** ** Returned value: None ** ******************************************************************************/ void init_timer16PWM(uint8_t timer_num, uint32_t period, uint8_t match_enable, uint8_t cap_enabled) { disable_timer16(timer_num); if (timer_num == 1) { /* Some of the I/O pins need to be clearfully planned if you use below module because JTAG and TIMER CAP/MAT pins are muxed. */ LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8); /* Setup the external match register */ // LPC_TMR16B1->EMR = (1<<EMC3)|(1<<EMC2)|(1<<EMC1)|(2<<EMC0)|(1<<3)|(match_enable); LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5) | (1<<7) | (1<<10) |(match_enable) ; /* Setup the outputs */ /* If match0 is enabled, set the output */ set_timer16_match(timer_num, match_enable, 0 ); /* Enable the selected PWMs and enable Match3 */ LPC_TMR16B1->PWMC = (1<<3)|(match_enable); /* Setup the match registers */ /* set the period value to a global variable */ timer16_1_period = period; LPC_TMR16B1->MR3 = timer16_1_period; LPC_TMR16B1->MR0 = timer16_1_period/2; LPC_TMR16B1->MR1 = timer16_1_period/2; LPC_TMR16B1->MR2 = timer16_1_period/2; /* Set match control register */ LPC_TMR16B1->MCR = 1<<10;// | 1<<9; /* Reset on MR3 */ if (cap_enabled) { /* Use location 0 for test. */ set_timer16_capture( timer_num, 0 ); LPC_TMR16B1->IR = 0xF; /* clear interrupt flag */ /* Set the capture control register */ LPC_TMR16B1->CCR = 7; } /* Enable the TIMER1 Interrupt */ NVIC_EnableIRQ(TIMER_16_1_IRQn); } else { LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7); /* Setup the external match register */ // LPC_TMR16B1->EMR = (1<<EMC3)|(1<<EMC2)|(1<<EMC1)|(2<<EMC0)|(1<<3)|(match_enable); LPC_TMR16B0->EMR = (1<<0)|(1<<1)|(1<<3)|(1<<5) | (1<<7) | (1<<10) |(match_enable); /* Setup the outputs */ /* If match0 is enabled, set the output */ set_timer16_match(timer_num,match_enable,0); /* Enable the selected PWMs and enable Match3 */ LPC_TMR16B0->PWMC = (1<<0) | (1<<1) | (1<<3)|(match_enable); /* Setup the match registers */ /* set the period value to a global variable */ LPC_TMR16B0->PR=timer16_0_period; timer16_0_period = period; //LPC_TMR16B0->MR3 = timer16_1_period; LPC_TMR16B0->MR0 = timer16_1_period/2; LPC_TMR16B0->MR1 = timer16_1_period/2; LPC_TMR16B0->MR2 = timer16_1_period; LPC_TMR16B0->TC=1;// added now // LPC_IOCON->PIO0_8 &= ~0x07; //clear pin settings // LPC_IOCON->PIO0_8 |= 0x02; // set as Timer0_16 MAT0 // LPC_IOCON->PIO0_9 &= ~0x07; //clear pin settings // LPC_IOCON->PIO0_9 |= 0x02; // set as Timer0_16 MAT0 // LPC_TMR16B0->PWMC = (1<<3) // set the Match3 // | (1<<0) // set PWM0 // | (1<<1) // set PWM1 // ; // LPC_TMR16B0->MR2 = 500;//timer16_0_period; // set the period to 1us // LPC_TMR16B0->MR0 = 1000;//timer16_0_period/2; // 50% duty cycle // LPC_TMR16B0->MR1 = 1000;//timer16_0_period/4; // /* Set match control register */ LPC_TMR16B0->MCR = 1<<10;// | 1<<9; /* Reset on MR3 */ LPC_TMR16B0->TCR=1; /* Enable the TIMER1 Interrupt */ NVIC_EnableIRQ(TIMER_16_0_IRQn); } } /****************************************************************************** ** Function name: pwm16_setMatch ** ** Descriptions: Set the pwm16 match values ** ** parameters: timer number, match numner and the value ** ** Returned value: None ** ******************************************************************************/ void setMatch_timer16PWM(uint8_t timer_num, uint8_t match_nr, uint32_t value) { if(timer_num) { switch(match_nr) { case 0: LPC_TMR16B1->MR0 = value; break; case 1: LPC_TMR16B1->MR1 = value; break; case 2: LPC_TMR16B1->MR2 = value; break; case 3: LPC_TMR16B1->MR3 = value; break; default: break; } } else { switch(match_nr) { case 0: LPC_TMR16B0->MR0 = value; break; case 1: LPC_TMR16B0->MR1 = value; break; case 2: LPC_TMR16B0->MR2 = value; break; case 3: LPC_TMR16B0->MR3 = value; break; default: break; } } }
Yes I have changed the values for timer interval, but I didn't get any desired o/p. Presently i'm not using external circuit, testing on the prototype board. I need to generate multiple frequencies on MAT registers.
Note that you normally only get one frequency from a single timer - but by playing with the different match registers, you can get square waves of same frequency but different phase or different pulse width.
When you write PWM in your code, the question then comes: Are you trying to generate square wave with different pulse width, or are you trying to simulate analog values by the use of an external low-pass filter?
Nowhere in your code do you indicate what you actually want to do - but you do post quite a number of commented-away code lines that seems to indicate that you currently uses the "trial and error" method which isn't really a quick way to get the expected result.
Ok sir. For example in MAT0 & MAT1 register I should generate 9.6hz & 14.1hz respectively. So it seems different frequencies for MAT register using 16/32 bit timer with 50% duty cycle[square waves]
Maybe you should explain how you plan to get two frequencies out of the same timer.
Remember that you use one match register to reset the timer. This match register will decide the frequency of the reset of the timer. And it will also decide the frequency that the timer may match any of the other match registers for the same timer.
Let's say the timer ticks once every us.
Let's say you use one match register to restart the timer after 10000 ticks (10000-1 means at the value 9999). That would then be 10000us or 10ms.
Let's say that you also use this match to produce a match event - then you get one match event ever 10ms. If that events toggles a pin, you get a 20ms period or 50Hz.
Now let's say you take a couple of other match registers and set at arbitrary values no larger than 10000 ticks (which you can't pass since you always reset after 10000 ticks).
If one of these matches happens at 2000 ticks it would mean 2ms. But then it's 8ms left until the timer ticks and then 2ms until the timer once more reaches 2000. So this match will also happen every 10ms - same frequency as you restart the timer. The only difference is that you got a timer match with 2ms offset.
In theory, you could have a match on 2500 and one on 7500 and they togeter will represent twice as many matches as the timer is reset - but what you then got is exactly twice the frequency. Not an arbtrary frequency.
You talk about 9.6 Hz and 14.1 Hz. But they aren't a factor two from each other. So you can't get the lower frequency by just making twice as many ticks as the timer reset. The method then would be to let the match registers produce an interrupt - and on every interrupt you reprogram the match registers and let the timer continue to run instead of constantly being reset. This is asy to do, since your two frequencies are so low.
So if 9.6 Hz represents N1 ticks of the timer and 14.1 Hz represents N2 ticks of the timer, then you configure the timer with one match event after N1 ticks and a different match event after N2 ticks. When N1 happens, you reprogram that match register to make the next match after 2*N1 ticks. When the N2 match happens, you reprogram the match register to get the next match after 2*N2 ticks. When you reach the 32-bit limit of the timer, you just overflow, i.e. (x*N1+N1) mod TIMER_RANGE will work well.
Doing this, means a single timer can produce one frequency for every match register - as long as the processor is fast enough to handle the match register interrupts.
Thank you for the detail explanation.Will work on it. Any idea of how to reset & set the tick function for this particular controller.
"Any idea of how to reset & set the tick function for this particular controller."
I don't even understand the question. It's trivial to reset the timer, and you have already posted code that makes use of that function. But since it isn't code you have written, you may not understand what it does. That's why the manufacturer did make an excellent user manual for the processor.