I have a timer which at each interrupt first stops itself and then set its own next delay:
HAL_TIM_Base_Stop_IT(&htim);
// do stuff
__HAL_TIM_SET_PRESCALER(&htim, new_p);
__HAL_TIM_SET_AUTORELOAD(&htim, new_a);
__HAL_TIM_CLEAR_FLAG(&htim, TIM_FLAG_UPDATE);
HAL_TIM_Base_Start_IT(&htim);
everything works well. But if I stop the timer before it overflows and interrupts, and then fill it with new values, it keeps finishing its last delay. For example, I stop it a second into a 15-second delay and fill it with values for 1 second delay, after I start it again, it takes ~13 seconds to interrupt instead of 1 second.
New value of the prescaler, written in the PSC register, is loaded in the actual prescaler register only at the next update event. If you don't want to wait for next counter overflow - generate a software update event by writing the UG bit in TIMx_EGR register.
New auto-reload value is loaded in the actual auto-reload register immediately, unless "auto-reload preload" option is enabled with the ARPE bit in TIMx_CR1 register. In this case the actual auto-reload register is also loaded with an update event.
Related
Has anyone heard of a hardware-timer which can count by different values with one timer tick?
Normally a timer of a µC counts up or down by one. But I have a challenge where I need to add e.g. 500 each timer tick.
There are multiple options for your question. Depending on your microcontroller and timer you could:
Use the interrupt generation of the timer to manually up a variable by a set amount. 500 in your case.
Change the timer prescalers such that instead of 500 times in an expected period, the timer only triggers once during the expected period.
I personally don't know of a timer that has a variable increase amount but that doesn't mean that it doesn't exist. Maybe creating such a timer in VHDL or verilog may be a option.
I have a timer set up in the cube to make a PWM... Just setting ARR and CCR to different values.
I'm using the callback functions for both events that HAL set up for me, I think one is for the CCR compare event and the other is for the ARR compare event.
Anyway, in both of those I'm toggling a GPIO port like this:
GPIOC->ODR = foo;
Anyway, I want to sample the values of 3 ADC1 channels during the high pulse, but I'm not sure how to do that accurately. I'm using DMA in circular mode with the ADC1 right now.
I don't want to sample immediately after setting the pins, because there's propagation delay, noise, etc.
So, I want to:
Set the pins, wait a very short and constant amount of time, sample all the channels and then do some math on the results.
This is for a Bldc motor controller, by the way... Im trying to sample the BEMF on the positive side of the PWM drive signal, and I'm driving it at 18khz, 5% duty cycle, so my pulse lasts for 2.7us.
I'm not sure how to handle or debug this because it's so timing related and I need the motor to deliver the signal that I'm using... If the motor isn't spinning, then there's no feedback signal to work on. It sure seems like I'm trying to do too much in the timer ISRs, though.
Sorry I can't post any code right now... Im at the grocery store, but I'll put some up when I get back.
I'am currently working on tinyos and I Am trying to reset timer
lets say to 2 seconds when it is running at 45 seconds
but it is not working, i can't figure out why,
can someone help me figure it out
here is the code:
printf("timer before resetting it %ld",call Timer1.getNow());
offset = ((TimeMote_t*) payload)->tdata;
call Timer1.startPeriodic(offset);
printf("timer after resetting it %ld",call Timer1.getNow());
now actually it should have reset the timer to offset but it's not resetting it.
both printf statements are giving the same time.
No, it shouldn't. Timer.getNow() returns absolute time, which can't be changed or reset. Timer interface can be used to schedule events at a particular moment in the future. Timer.startPeriodic(offset) starts the timer, meaning that the event Timer.fired() will be signaled in the future. In this particular example, the event will be signaled offset units from the call to Timer.startPeriodic and then repeated every offset units infinitely or until call to Timer.stop(). Return value of Timer.getNow() doesn't change and increases monotonically regardless of whether the timer is started or not.
See: Interface: tos.lib.timer.Timer
I'm using the PIC16F88X which has a 200ns internal clock period and I want to program the TIMER0 to make 4 measurements per second.
According to microchip tutorial on programming timer 0 (page 10) I can use PS0, PS1 and PS2 to assign TMR0 RATE to 1:256 but this only makes my clock period scale to 51,2 micro seconds.
There is also the possibility to program an initial value for TMR0 but I don't think it will affect the clock I want to reach. Is there anything on the big picture that I'm missing?
It is expected that timer prescaler can't cover any range that user may want. In order to achieve larger intervals you have to add additional logic in yours timer interrupt routine. Basically you have to add additional variable/counter which you have to increment, let's say on 50us (you will tune timer from 51,2us to 50us by adding initial value to TMR0). When your counter reaches 5000 then you have wanted 1/4s resolution.
Hope it helps...
Looking at the specification sheet (http://ww1.microchip.com/downloads/en/DeviceDoc/41291D.pdf) page 76 we see that the timer1 available on this micro-controller is 16bit and has up to 8 pre-scaler. My own approach would be to use timer1 with a prescaller of 8. Without seeding the value manually, this gives :
<osc speed>/(4*<prescaller>*2^16)
5MHz/(4*8*2^16) = 2.38Hz
To get exactly 4Hz, you can seed the counter on every rollover to a value of :
2^16-<osc speed>/(<desired speed>*4*<prescaller>)
2^16-5MHz/(4Hz*4*8) = 26474
I am using the Atmel SAM3x8E micro-controller and trying to do a simple LED toggle when I press a button. I am using pull-up configuration button to trigger an interrupt routine.
This is the initialization for the interrupt:
// Set button pins as pull-up inputs
pio_set_input(PIOC, BUTTON_1, PIO_PULLUP);
pio_set_input(PIOC, BUTTON_2, PIO_PULLUP);
// Configure button input pin interrupt mode and handler (Rising Edge)
pio_handler_set(PIOC, ID_PIOC, BUTTON_1, PIO_IT_RISE_EDGE, button_press_handler);
pio_handler_set(PIOC, ID_PIOC, BUTTON_2, PIO_IT_RISE_EDGE, button_press_handler);
// Enable the interrupts
pio_enable_interrupt(PIOC, BUTTON_1);
pio_enable_interrupt(PIOC, BUTTON_2);
NVIC_EnableIRQ(PIOC_IRQn);
NVIC_EnableIRQ(PIOC_IRQn);
Then this is the interrupt routine:
// Interrupt handler for button press
void button_press_handler(uint32_t a, uint32_t b)
{
pio_toggle_pin_group(PIOC, BLUE_LED4); // NOT TOGGLING LED (ONLY TURNS IT ON)
}
Yet when I run it, I cannot get the LED to toggle. It simply turns on and stays on. The function that pio_toggle_pin_group calls is the following:
* \param p_pio Pointer to a PIO instance.
* \param ul_mask Bitmask of one or more pin(s) to configure.
*/
void pio_toggle_pin_group(Pio *p_pio, uint32_t ul_mask)
{
if (p_pio->PIO_ODSR & ul_mask) {
/* Value to be driven on the I/O line: 0. */
p_pio->PIO_CODR = ul_mask;
} else {
/* Value to be driven on the I/O line: 1. */
p_pio->PIO_SODR = ul_mask;
}
}
Any ideas as to why my LED is not toggling the way I want? I've refereed to the Atmel ASF documentation but I still cannot figure this out.
I cannot help you with the actual function calls, but suppose you use a edge interrupt. As far as I see, you call an interrupt handler for each rising edge. However, after the first rising edge, you need to trigger on button release, which would be a falling edge, so you need to change the edge within the interrupt handler.
But you must take into account that mechanical buttons do not generate a clean, single edge when pressed or released. It does instead bounce. For normal momentary contact buttons with pullup (or down) resistor, this results in multiple pulses for each event, so the LED may turn on/off multiple times and stay in an arbitrary state which might - by chance - be "on" far by most times. If available, check with an oscilloscope.
This can be circumvented in hardware by a capacitor or in software using a timer with a dead time after the relevant edge before reacting to any other button event.
The dead time depends on the type of button, but typical values are 5 to 20ms and should be mentioned in the datasheet of the button. If in doubt, use the highest acceptable value.
This is what ended up working for me:
// Interrupt handler for button press
void button_press_handler(uint32_t a, uint32_t b)
{
// Turn the LED's on or off
if (pio_get(PIOC, PIO_TYPE_PIO_OUTPUT_0, BLUE_LED4))
pio_clear(PIOC, BLUE_LED4);
else
pio_set(PIOC, BLUE_LED4);
}
and here is the called "set" function which worked to turn the LED on:
void pio_set(Pio *p_pio, const uint32_t ul_mask)
{
p_pio->PIO_SODR = ul_mask;
}
To avoid those random spikes generated by the bouncing button try to use a debouncing input filter. On the sam3x8e you can enable this by setting the register PIO?->PIO_DIFSR to BUTTON_1 or BUTTON_2 in your case.
Also clear the status register of the PIO interrupt by reading PIO?->PIO_ISR. This clears all input changes and enables the interrupt to be entered multiple times.