‎2021-02-01 04:33 PM
I have to keep a pin high for a certain amount of time, about 1us, I figured that it probably makes sense to do this with a timer. I was going to use SysTick but I decided that it makes mores sense to learn the timer peripherals.
I think I have the configuration and execution steps correct to make a simple function to create an approx. delay (for testing purposes) but I cannot seem to get it working as desired. I did notice that I was not able to see the CEN bit enabled when debugging, but I imagine that this is not possible? Below is my code, any hints appreciated!
// GPIO registers previously enabled and set up, they are
// confirmed to work.
/* config TIM6 */
// Enable TIMER6 as it is on the APB1 bus
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
// One pulse mode (counter stops counting after event)
TIM6->CR1 |= (TIM_CR1_OPM);
/* Function for delay */
void delay1us(void)
{
/* execute a delay */
// Clear update event flag
TIM6->SR = 0;
// Prescaler
TIM6->PSC = 0;
// Preload
TIM6->ARR = 84; // 336 for 4us
// Start timer
TIM6->CR1 |= TIM_CR1_CEN; // CEN bit
// Wait for delay to elapse
while(~(TIM6->SR & TIM_SR_UIF));
// Clear timer flag
TIM6->SR = 0;
}
while(1)
{
// Make pin high
GPIOE->ODR |= (1 << 2U);
delay1us();
// Make pin low
GPIOE->ODR &= ~(1 << 2U);
delay1us();
}
Solved! Go to Solution.
‎2021-02-01 05:34 PM
> I was not able to see the CEN bit enabled when debugging
One-Pulse mode works so that it clears CEN upon overflow (Update). Are you capable of reading it out within 1us? :)
You can slow down the timer by using a slow primary clock (e.g. HSI without PLL, maybe even divided down in RCC) and a high prescaler (don't forget that it does not get active until the next Update, as it's unconditionally preloaded). Sometimes it's fun to watch the timer's CNT running in debugger, and observe the various flags being set as it runs.
You can stop the timer during debugging by setting the respective bit in DBGMCU_APBx_FZ, but it's not always a good idea, and the exact behaviour may depend on the particular toolset used.
But your main problem is here:
> // Wait for delay to elapse
> while(~(TIM6->SR & TIM_SR_UIF));
~ (tilde - the forum is using a bad font, zoom it up) is a bitwise negation, i.e. when UIF is not set, the & results in 0 and ~ results in 0xFFFFFFFF; when UIF is set the & results in 1 and ~ results in 0xFFFFFFFE.
You want to use ! instead of ~.
JW
‎2021-02-01 05:34 PM
> I was not able to see the CEN bit enabled when debugging
One-Pulse mode works so that it clears CEN upon overflow (Update). Are you capable of reading it out within 1us? :)
You can slow down the timer by using a slow primary clock (e.g. HSI without PLL, maybe even divided down in RCC) and a high prescaler (don't forget that it does not get active until the next Update, as it's unconditionally preloaded). Sometimes it's fun to watch the timer's CNT running in debugger, and observe the various flags being set as it runs.
You can stop the timer during debugging by setting the respective bit in DBGMCU_APBx_FZ, but it's not always a good idea, and the exact behaviour may depend on the particular toolset used.
But your main problem is here:
> // Wait for delay to elapse
> while(~(TIM6->SR & TIM_SR_UIF));
~ (tilde - the forum is using a bad font, zoom it up) is a bitwise negation, i.e. when UIF is not set, the & results in 0 and ~ results in 0xFFFFFFFF; when UIF is set the & results in 1 and ~ results in 0xFFFFFFFE.
You want to use ! instead of ~.
JW
‎2021-02-01 06:06 PM
Well don't I feel silly.... I somehow kept thinking ~ meant ! :tired_face: Thank you, this did the trick and I can see the timing working as intended on my logic analyzer.
Ya maybe I was thinking that 1us would be slowed or something in debugger. Still getting used to the debug feature with the STM32Cube IDE. The debugger has helped me crawl out of a lot of holes, guess this one was too deep haha.