2018-04-25 07:03 AM
Hey Guys,
I don't know what I am doing wrong here and really would appreciate some help:
I created a function called
void DELAY_1_5us(uint16_t period)
{
delay = true;
__HAL_TIM_SET_AUTORELOAD(&htim7, period);
LCD_CS_LOW;
HAL_TIM_Base_Start_IT(&htim7);
while(delay);
}�?�?�?�?�?�?�?�?
this function uses TIM7 of the STM32F429ZI-DISC1 discovery board as a simple programmable timer for approx. x time 1,5µs delay. with the 16-Bit ARR value I get maximum 2^16 x 1,5µs delays because of the following init routine (84MHz/128 = 656,250kHz = 1,5238 µs counter tick):
void MX_TIM7_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;
htim7.Instance = TIM7;
htim7.Init.Prescaler = 128;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 1;
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
In the ISR I just set the delay value so the while loop in the dely function is interrupted. The LCD_CS pin is just to measure the elapsed time on an oscilloscope.
void TIM7_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_IRQn 0 */
HAL_TIM_Base_Stop_IT(&htim7);
LCD_CS_HIGH;
delay = false;
/* USER CODE END TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_IRQn 1 */
/* USER CODE END TIM7_IRQn 1 */
}�?�?�?�?�?�?�?�?�?�?�?�?
The problem now is, that the function -regardless which value for the delay period of the DELAY_1_5_us functionI choose - the timer shows only approx. 1µs delay on the oscilloscope. I checked the register entry for TIM7_ARR and it changes with each function call. I also thought this might have to do something with the UG bit to generate an UE so that the timer loads the new ARR value.
But even with htim7.instance->EGR = 0x1 nothing is happening. Also when I try to activate the preload buffer with htim7.instance->CR1 |= 0x0080; nothing is changing in the appropriate reigisters.
I would really appreciate if someone could help me. I tried the code with ATOLLIC TrueStudio and SW4STM32 all set with optimize for debug.
best regads
Benjamin
#delay-function #stm32f4 #tim7 #changing-arr-in-run2018-04-30 08:01 AM
I often use a free running timer and count the cycles for delay. That free running timer could be the systic or any other timer. Or even dwt.
In your case, you may want to convert the duration to the number of cycles and then set the timer to expire at end of that cycle.
I can post something later if this isn't clear to you.
2018-04-30 08:28 AM
Yes I tried to do this with my last post and the rewrite of the delay function. I have read another
https://www.carminenoviello.com/2015/09/04/precisely-measure-microseconds-stm32/
where the problem is explained and also the variant you suggested with the DWT is used. I think I will try that DWT solution..2018-04-30 09:26 AM
The basic construct is quite simple:
1. Read the current timer counter.
2. Loop around until the current timer counter minus the counter value read in 1 above is bigger than your desired cycles.
3. Exit.
If you are mostly married about small delays, no need to use any interrupt and simply read systick->Val or dwt->cyccnt.
A couple of lines will do. Note that systick- is a down counter.
2018-04-30 06:06 PM
Interrupting at 1 MHz is a fools errand.
If you clock a free running TIM at 1 MHz you can read the TIM->CNT register until it advances the desired number of ticks.
start = TIM->CNT;
while((TIM->CNT - start) < 10); // Wait 10 us
2018-04-30 06:09 PM
Here is what I would do.
1. define your timer tick read-out:
&sharpdefine systick() (-SysTick->VAL) //24-bit downcounter
&sharpdefine coretick() (DWT->CYCCNT) //32-bit upcounter&sharpdefine tim7tick() (TIM7->CNT) //using TIM7they are for SysTick, DWT, and TIM7 timers, or whatever timing mechanism you want to use.
2. write a timing routine based on those mechanisms
/delay a few cycles using systick()
void delay_systick(uint32_t cnt) { uint32_t tmp = systick(); //time stamp the beginning while (systick() - tmp < cnt) continue; //wait until time expires}//delay a few cycles using coretick()
void delay_coretick(uint32_t cnt) { uint32_t tmp = coretick(); //time stamp the beginning while (coretick() - tmp < cnt) continue; //wait until time expires}I provided two examples above, using SysTick or DWT. If you want, you can easily write your own using TIM7 or whatever timer you want.
3. perform a delay:
IO_FLP(LEDG_PORT, LEDG); //flip ledg
//delay using systick delay_systick(SystemCoreClock / 10); //waste sometime = 1/10th a second //alternatively, delay using coretick //delay_coretick(SystemCoreClock / 10); //waste sometime = 1/10th a secondHere, I simply blinked an LED and used systick to generate a delay. the commented out section used DWT to generate a section. You can use TIM7 for that, as well, if you write your own timing routine.
Obviously you will need to initialize SysTick / DWT / TIM7 or whatever you want to use before hand. No interrupt required as you just need short delays.
I have heard numerous times here people thought using SysTick is difficult as it is a 24-bit downcounter but as you can see, it is every bit as easy as using a regular counter.
hope it helps.
PS: written those lines on tested so you may need to debug them a little.
2018-04-30 06:14 PM
I would hesitate using that, for two reasons:
1) you want to have a generic version that takes cycles to be delayed as a parameter and then you can write a us-based version using the cycle delay routine.
2) I would put the GPIO operation outside of your routine so the delay routine is generic and can be reused. In your case, I would do this:
IO_CLR(GPIOC, TEST_PIN); //clear test pin
delay_DWT(cycles_1us5); //delay a few units of 1us5
IO_SET(GPIOC, TEST_PIN); //set test pin
With that, you can use delay_DWT() sometime in the future, in other projects.
Remember that the only reason you are writing a piece of code is so that you don't have to write it again in the future. With re-usability, your time spent writing a piece of code is an investment, not an expense.
2018-04-30 06:23 PM
I wrote the tim7 delay routines like this:
//delay a few cycles using tim7
void delay_tim7tick(uint32_t cnt) { uint32_t tmp = tim7tick(); //time stamp the beginning while (tim7tick() - tmp < cnt) continue; //wait until time expires}coupled with the following:
IO_FLP(LEDG_PORT, LEDG); //flip ledg
delay_tim7tick(SystemCoreClock / 10 / 256); //256:1 prescaler picked to form an effective 24-bit timebaseI could replicate the same 24-bit timebase used earlier.
and I just tested all the code pieces above and they all work as expected.
2018-05-01 05:15 AM
Hey dhenry,
thanks again for your advise and code snippets. What I don't understand is why use so much different counter clocks, like systick or DWT or a timer. As far as I have understood the routine I found in the Link, which I posted above, I just need one function that counts with the system core clk as a counter tick. After scaling the counts to be precise one us I can achieve every delay I want. And it is very precise. Off course I can put the system clock scaling outside the routine but would nevertheless only need one version. Or did I miss something here?
best regards
Benjamin