esp32 higher timer frequency and lower clock divider - timer

I'm measuring with the esp32 very short time intervals for the load curve of a small capacity. Is there a way to increase the clock frequency of timer? I tried out to change the clock frequency of cpu. It works but it had no effect at the clock frequency of timer.
I also have tried out to reduce clock divider. I figured out that the lowest allowed value is 2. Could I use the timer without frequency divider? My timer config:
timer_config_t config = {
.alarm_en = TIMER_ALARM_DIS,
.counter_en = TIMER_AUTORELOAD_DIS,
.intr_type = TIMER_INTR_LEVEL,
.counter_dir = TIMER_COUNT_UP,
.auto_reload = TIMER_AUTORELOAD_DIS,
.divider = 2 // 1 / 250 ns per tick
};
A few weeks ago I asked a similar question but it was only about changing clock frequency and not timer frequency.

Related

FreeRTOS timer Tick too fast in SAM L21 Xplained Pro

When I call vTaskDelay, the delay lasts half of the supposed time. I have traced back the problem and I see that the Tick rate value is the double of what it should be as defined in configTICK_RATE_HZ. I checked this using the tick hook to toggle a led and measuring the frequency with an oscilloscope.
I am configuring the Atmel SAM L21 Xplained pro A board (ATSAML21J18A), with Atmel Studio 7 and FreeRTOS v8.0.1, based on the files of an ASF example called "FreeRTOS tickless demo using OLED1 Xplained".
My CPU clock runs at 12MHz from the SYSTEM_CLOCK_SOURCE_OSC16M. The configured tick rate is 100 Hz, from a timer clocked from GLCK_O(CPU clock). However, when I change the CPU clock rate at 4MHz instead 12 MHz, the Tick rate is correct, so I guess I'm missing some configuration somewhere for the timer which runs the OS tick.
Here are some values of OS tick rate I get with different CPU clock rates:
CPU: 4 MHz - Tick rate: 100 Hz
CPU: 8 MHz - Tick rate: 548 Hz
CPU: 12 MHz - Tick rate: 218 Hz
CPU: 16 MHz - Tick rate: 548 Hz
CPU: 48 MHz - Tick rate: 2,25 kHz
Also, when I configure the OS tick timer clock source as the internal ultra low power oscilator ULPOSC32k running at 32kHz, the tick rate is correct, independently of the CPU clock frequency (100Hz).
Moreover, when I select tickless mode (1 or 2), even with the configuration that works well in tick mode, with the CPU at 4MHz and the tick interrupt generated from the Systick timer, I have the same problem, the dalay lasts half of what it should.
In FreeRTOSConfig I have:
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 1
#define configPRIO_BITS 2
#define configCPU_CLOCK_HZ ( system_gclk_gen_get_hz(GCLK_GENERATOR_0) )
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
The tick timer configuration is:
void vPortSetupTimerInterrupt(void)
{
// Struct for configuring TC
struct tc_config tcconf;
// Set up configuration values
tc_get_config_defaults(&tcconf);
tcconf.clock_source = GCLK_GENERATOR_0;
tcconf.counter_size = TC_COUNTER_SIZE_32BIT;
tcconf.run_in_standby = true;
tcconf.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
tcconf.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
// Initialize the TC
tc_init(&tc, TICK_TC, &tcconf);
// Register and enable callback for freeRTOS tick handler
tc_register_callback(&tc, (tc_callback_t) xPortSysTickHandler, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
// Set top value equal to one os tick
tc_set_top_value(&tc, TIMER_RELOAD_VALUE_ONE_TICK);
// Enable the timer
tc_enable(&tc);
}
where TIMER_RELOAD_VALUE_ONE_TICK comes from:
//! Frequency of timer
#define TIMER_HZ ( configCPU_CLOCK_HZ )
//! Value per os tick of timer
#define TIMER_RELOAD_VALUE_ONE_TICK ( TIMER_HZ / configTICK_RATE_HZ )
//! Maximum value of timer
#define TIMER_MAX_COUNT ( 0xffffffff )
//! Maximum possible suppressed ticks with timer
#define TIMER_MAX_POSSIBLE_SUPPRESSED_TICKS ( TIMER_MAX_COUNT / TIMER_RELOAD_VALUE_ONE_TICK )
I would appreciate very much any insight on this timer issue, which keeps me stuck. I have already checked two similar questions related to this:
STM32 SysTick counting twice as fast as it should
freertos tick factor 2 too fast on stm32f4xx
The saml21 has 5 timer/counters TC0 - TC4. The count registers are 16bit. You can use TC0 and TC1(or TC2 and TC3) together to make it 32bit. TC4, the only timer in PDO, does not have another timer paired with it. It can't be used as a 32bit timer(though it will allow you to try).
Change TIMER_MAX_COUNT to 0xffff and tcconf.counter_size to TC_COUNTER_SIZE_16BIT and you will be able to use TC4 instead of TC2.
Changing the Timer instance from TC4 to TC2 solves the issue.
// Initialize the TC
tc_init(&tc, TICK_TC, &tcconf);
//! Timer/Counter instance to use as tick timer
//#define TICK_TC TC4
#define TICK_TC TC2
Now it generates a correct 100 Hz tick independently of the CPU clock frequency configured.
However, I still have to see the implications this will have when I activate the low power modes, as it seems the TC4 is the only timer active in Power Domain 0
(PD0)(the lowest power domain).

Software implementation of an oscillator in C

I have been developing a control software in C language. I have decided to spent
some time with development general function blocks usable in other programs which I will develop in future (some type of library). My software is divided into two main parts from application point of view. One part is the control part
(PI controller, modulator, phase locked loop etc.) and the second one is logic
part (finite state machine of the application etc.). The logic part works with logic signals. These signals are procesed by software implementation of logic gates and flip-flops. My goal is to also implement some software version of an oscillator. I mean some function block which is able to produce oscillations between 0 and 1 with prescribed period and duty cycle at its output. In principle I can have several such oscillators in one program. So I have
decided to implement the oscillator in following manner. The oscillations production is done by a function and each instance of the oscillator is implemented by an instance of previously defined structure. The structure contains as main items the oscillations period, duty cycle and oscillator execution period i.e. execution period of the RTOS task in which the instance of the oscillator is placed. Based on the oscillations period and task execution period produces the oscillator function the oscillations
void OSC(uint32_t output, Osc_t *p){
// p->T is the task execution period in ms
// p->period is the desired oscillations period in ms
// p->counter is the internal state of the oscillator
p->delay_count = (uint16_t)((p->period)/(2*p->T));
if(++(p->counter) >= p->delay_count){
p->counter = 0;
NegLogicSignal(output);
}
}
}
Below is the structure which contains the state of individual oscillator instances
typedef struct{
float period; // period of the oscillations (ms)
float T; // function execution period (ms)
uint16_t counter; // initial number of execution periods
uint16_t delay_count; // number of execution periods corresponding to half
// period
}Osc_t;
and the usage of oscillator function is following
Debug_LED_Oscillator_state.T = 1; // T = 1 ms
Debug_LED_Oscillator_state.period = 500; // period 0.5 s = 500 ms
OSC(LDbgLedOsc, &Debug_LED_Oscillator_state);
My problem is that I had to place one of my oscillators in the fastest task (task with execution period 1 ms)
because I wasn't able to achieve the period 500 ms (half period 250 ms) in another tasks because the rest of my tasks have inapproprite execution periods for 500 ms (20 ms and 100 ms i.e. 250/20 = 12.5 - not an integer value and 250/100 = 2.5 - also not an integer value). The problem is that I have the rest of application logic in another task.
The intended use is to produce logic signal for LEDs blinking pattern. The problem is that I had to move the oscillator to logically different task only because I am not able to achieve desired timing accuracy in the logicaly appropriate task (because of non integer values of the quotient half_period/execution_period). I am thinking about different implementation which enables place the oscillator to logicaly appropriate task and achieve the desired timing accuracy.
I have thought following solution. I will define set of global variables (uint16_t Timer_1ms, uint16_t Timer_5ms etc.). These global variables will be incremented in highest priority task (in my case Task_1ms). I will redefine OSC function
void OSC(uint32_t output, Osc_t *p){
float act_time;
taskENTER_CRITICAL();
switch(p->timer_type){
case TMR_1MS:
act_time = Timer_1ms;
break;
case TMR_5MS:
act_time = Timer_5ms;
break;
}
taskEXIT_CRITICAL();
if(p->init){
SetLogicSignal(output);
switch(p->timer_type){
case TMR_1MS:
p->delta = ((p->period)/(2*1*p->T));
break;
case TMR_5MS:
p->delta = ((p->period)/(2*5*p->T));
break;
}
p->stop_time = (act_time + p->delta);
p->init = FALSE;
}
if(act_time >= (p->stop_time)){
NegLogicSignal(output);
p->stop_time = (act_time + p->delta);
}
}
and oscillator structure
// oscillator state
typedef struct{
float period; // period of the oscillations (ms)
float T; // function execution period (ms)
float delta; // half_period in timer counts
float stop_time; // timer counts when to negate the output
BOOL init; // force initialization of the timer
timer_e timer_type;
}Osc_t;
I have tried this solution and it seems to be not functional. Does anybody have an idea why? Thanks in advance for any sugestions.
Threads of RTOS are very useful when you perform tasks with soft deadline. Soft deadline means that if the execution delays the system will not fail. In your case, the oscillator has a hard deadline e.g. if the duty cycle of PWM is not precise and stable the motor will not be having the desirable constant angular velocity. In this case you have to use the available Timer/Counter peripheral of the MCU.
You can set a timer to interrupt the CPU on a given interval and toggle the output in the ISR (Interrupt Service Routine). Using this approach the load of time-counting is moved from the CPU to the timer peripheral, allowing both precise oscillating output and smooth execution of other tasks.
You do not make clear which RTOS or MCU/CPU you are using, but all of them have timer/counter peripherals. If not supported directly from the RTOS, look in the CPU vendor datasheet.

How to generate note without library?

I'm trying to generate note for example Do , do's frequency is 523.
I wrote some codes but, i did not work
Systick 8 mhz
void note1(void){ // Note Do
for (int i = 0; i < 523; i++){
GPIOE->ODR = 0x4000;
delay_ms(1);
GPIOE->ODR = 0x0000;
delay_ms(1);
}
}
How can we solve this problem ?
EasyMx Pro v7
I'm calling the function like that
void button_handler(void)
{
note1();
// Clear pending bit depending on which one is pending
if (EXTI->PR & (1 << 0)){
EXTI->PR = (1 << 0);
}
else if (EXTI->PR & (1 << 1)){
EXTI->PR = (1 << 1);
}
}
523 times sending 1 and 0 and delay_ms 1 = 1 ms
1000 = 1 sec
On STM32 (as I can see you have it) you have timers which can be configured as PWM output.
So use timer, set period and prescaler values according to your needed frequency and set duty cycle on channel to 50%.
If you need 523Hz PWM output, then set your timer PWM to 523Hz using prescaler and period value:
timer_overflow_frequency = timer_input_clock /
(prescaler_value + 1) /
(period_value + 1) ;
Then, for your output channel set value half of timer period value.
For standard peripheral library, tutorial can be used from here:
https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-discovery-pwm-tutorial/
Link from unwind for Cube https://electronics.stackexchange.com/questions/179546/getting-pwm-to-work-on-stm32f4-using-sts-hal-libraries
You appear to have a fundamental misunderstanding. In your code note1(), the value 523 will affect only the duration of the note, nit its frequency. With 1ms high, 1ms low repeated 523 times you will generate a tone of approximately 500Hz for approximately 1.43 seconds. I say "approximately" because there will be some small overhead in the loop other then the time delays.
A time delay resolution 1ms is insufficient to generate an accurate tone in that manner. To do it in the manner you have, each delay would need to be 1/2f seconds, so for 523Hz approximately 956ms. The loop iteration count would need to be ft, so for say .25 seconds, 131 iterations.
However if button_handler() is as it appears to be an interrupt handler, you really should not be spending 1.46 seconds in an interrupt handler!
In any event this is an extraordinarily laborious, CPU intensive and inaccurate method of generating a specific frequency. The STM32 on your board is well endowed with hardware timers with direct GPIO output that will generate the frequency you need accurately with zero software over head. Even if none of the timers map to a suitable GPIO output that you need to use, ou can still get one to generate an interrupt at 1/2f and toggle the pin in the interrupt handler. Either way that will leave the processor free to do useful stuff while the tone is being output.

microcontroller TMR0 timer counter interrupt

I am programming the microcontroller PIC16F676 SPI interface with MCP2515. It will set a flag in every 224ms, and timercounter will increase from 0*F8 to 0*FF then overflow to set this flag. Therefore, 32ms * 07H = 224ms. The question is how to let the timer interrupt every 32ms,WHERE this 32ms comes from.
//Timer interrupts every 32ms and set a flag every 224ms (32ms * 07H = 224ms)
//Initial value = FFH - 07H = F8H
if(T0IF) //TMR0 overflow interrupt flag bit
{
TimerCounter++;
if(!TimerCounter) //if rolled over, set flag. Main will handle the rest.
{
TimerCounter = 0*F8;
gSampleFlag = 1;
}
T0IF = 0; //reset for next flag
}
The 32 ms period of the timer is determined by the configuration of the timer, which is not included in your code excerpt (i.e., it may be done elsewhere in your code). Read section 4.0 of the PIC16F630/676 datasheet, which explains the TIMER0 Module.
Timer0 is configured as follows:
T0CS is either:
cleared to select the internal clock source (Timer mode) for Timer0,
or set to select the external clock source (Counter mode).
T0IE is set to enable the Timer0 interrupt.
The prescaler may be used in conjunction with the internal clock source to adjust the tick rate of Timer0
PSA is cleared to assign the prescaler to Timer0.
PS2:PS0 are set to select the prescaler rate.
So either the external clock source or the internal clock source and prescaler determine the tick rate of Timer0.
32ms is the time period of clock source which your timer counter is counting for 0x07 times.
Your timer unit is synchronised with common clock source which is derived from either external crystal or internal oscillator. During clock configuration you need to decide what should be peripheral bus clock through which your timer unit is interfaced. While configuring timer unit you can further divide this peripheral clock to less frequency using prescaler to increase the range of period.
Now suppose your peripheral bus clock frequency is 1MHz and your prescaler is 1, your counter will increment or decrement every 1us and for 0x07 count, it will generate only 7us of period. In your example you need to set prescaler 32000 (if it allowed to set) as reference clock for counting so that 1 count means 32ms.

Understanding timer and period of interrupts

I am having a hard time understanding some code I found for using a timer and interrupts on an ARM board I have. The timer basically toggles an LED every interrupt between on and off to make it flash.
void main(void) {
/* Pin direction */
led_init();
/* timer setup */
/* CTRL */
#define COUNT_MODE 1 /* Use rising edge of primary source */
#define PRIME_SRC 0xf /* Peripheral clock with 128 prescale (for 24 MHz = 187500 Hz)*/
#define SEC_SRC 0 /* Don't need this */
#define ONCE 0 /* Keep counting */
#define LEN 1 /* Count until compare then reload with value in LOAD */
#define DIR 0 /* Count up */
#define CO_INIT 0 /* Other counters cannot force a re-initialization of this counter */
#define OUT_MODE 0 /* OFLAG is asserted while counter is active */
*TMR_ENBL = 0; /* TMRS reset to enabled */
*TMR0_SCTRL = 0;
*TMR0_CSCTRL = 0x0040;
*TMR0_LOAD = 0; /* Reload to zero */
*TMR0_COMP_UP = 18750; /* Trigger a reload at the end */
*TMR0_CMPLD1 = 18750; /* Compare one triggered reload level, 10 Hz maybe? */
*TMR0_CNTR = 0; /* Reset count register */
*TMR0_CTRL = (COUNT_MODE<<13) |
(PRIME_SRC<<9) |
(SEC_SRC<<7) |
(ONCE<<6) |
(LEN<<5) |
(DIR<<4) |
(CO_INIT<<3) |
(OUT_MODE);
*TMR_ENBL = 0xf; /* Enable all the timers --- why not? */
led_on();
enable_irq(TMR);
while(1) {
/* Sit here and let the interrupts do the work */
continue;
};
}
Right now, the LED flashes at a rate that I cannot determine per second. I'd like it to flash once per second. However, I do not understand the whole comparison and reloading.
Could somebody better explain this code?
As timers are a vendor- and part-specific feature (not a part of the ARM architecture), I can only give general guidance unless you mention which CPU or microcontroller you are dealing with.
Timers have several features:
A size, for instance 16 bits, which means they can count up or down to/from 65535.
A clock input, given as a clock frequency (perhaps from the CPU clock or an external crystal), and a prescaler which divides this clock frequency to another value (or divide by 1).
An interrupt on overflow - when the timer wraps back to 0, there is usually an option to trigger an interrupt.
A compare interrupt - when the timer meets a set value it will issue an interrupt.
In your case, I can see that you are using the compare feature of your timer. By determining your timer clock input, and calculating new values for the prescalers and compare register, you should be able to achieve a 1 Hz rate.
Before trying to understand the code you found, please do understand how a Timer Peripheral Unit works, then understand how you can configure it's registers to get the desired output.
How a Timer Peripheral Unit works?
This is hardware module which is embedded into micro controller along with CPU and other peripherals. Every peripheral modules inside micro controller are synchronized with common clock source. With reference to the code, Timer peripheral clock is 24 MHz which is then pre-scaled by 128 which means it will work at 187500 Hz. Now this frequency will depend upon clock configuration and oscillator.
Now Timer unit has a counter register which can count up to it's bit-size which could be 8,16 or 32 generally. Once you enable counting, this counter starts up-counting or down-counting the rising or falling or on both edges. Now you have choices whether you want to up-count (from 0 towards 255, for 8-bit) or down count (from 255 towards 0) and you want to count on which clock edge.
Now, at 187500 Hz, 1 cycle = 5.333333 us, if you are counting once in 1 cycle either at rising or at falling edge and e.g, if counter value = 100 (Up counting), total time elapsed is 5.33333*100=533us. Now you have to set a compare value value for the counter to set this period which will depend upon your flash rate. This compare value will be compared against your counter value in by comparator of Timer and Once it matches it will send an interrupt signal if you have enabled interrupt generation on compare match, where you can toggle you LED.
I hope you have understood How a Timer works.
In your sample code, Timer is configured to obtain a compare match event at the rate of 10Hz. so compare value is 187500/10 = 18750., for 1sec you can keep it 187500/1.
you have Timer Control Register TMR0_CTRL, where you can configure whether you want to count up or down, count on falling/rising/both edges, count only once/continuous, count upto compare value and then reset or keep counting till it's limit. Refer to micro controller manual for details of each bit fields.

Resources