1

i am working on STM32F4 and pretty new at it. I know basics of C but with more than 1 day research, i still not found a solution of this.

I simply want to make a delay function myself, processor runs at 168MHz ( HCLK ). So my intuition says that it produces 168x10^6 clock cycles at each seconds. So the method should be something like that,

1-Store current clock count to a variable

2-Time diff = ( clock value at any time - stored starting clock value ) / 168000000

This flow should give me time difference in terms of seconds and then i can use it to convert whatever i want.

But, unfortunately, despite it seems so easy, I just cant implement any methods to MCU.

I tried time.h but it did not work properly. For ex, clock() gave same result over and over, and time( the one returns seconds since 1970 ) gave hexadecimal 0xFFFFFFFF ( -1, I guess means error ) .

Thanks.

Edit : While writing i assumed that some func like clock() will return total clock count since the start of program flow, but now i think after 4Billion/168Million secs it will overflow uint32_t size. I am really confused.

muyustan
  • 1,555
  • 1
  • 11
  • 23
  • systick interrupt. `clock()` is a standard library function. Most probably you use `gcc` with` newlib` with `nosys.specs` which just implements `clock` as retunrning -1. Also `clock()` returns `clock_t`, which may not be `uint32_t`, rather what you want. – KamilCuk Jun 26 '19 at 16:32
  • @Kamil Cuk Is it something related to TIMERS? – muyustan Jun 26 '19 at 16:35
  • The [datashett](https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf) rather specifically mentions "SysTick", not a timer, it's a separate interrupt. Usually people use [hal functions](https://www.st.com/content/ccc/resource/technical/document/user_manual/2f/71/ba/b8/75/54/47/cf/DM00105879.pdf/files/DM00105879.pdf/jcr:content/translations/en.DM00105879.pdf) with the implementation. Are you aiming to touch registers yourself or use some HAL layer? – KamilCuk Jun 26 '19 at 16:39
  • If you happen to use `newlib` with `nosys`, then [clock()](https://github.com/littlekernel/newlib/blob/master/newlib/libc/time/clock.c) just calls [_times_r()](https://github.com/littlekernel/newlib/blob/master/libgloss/libnosys/times.c) that just returns -1 and sets errno=ENOSYS. On embedded platforms you have to implement the system yourself (or use some implementation). With `newlib` you can add `machine/_types.h` file with your implementation of `clock_t` and compile with your own implementation of `clock_t clock(void) { return HAL_GetTick(); }` – KamilCuk Jun 26 '19 at 16:42
  • Peripheral clocks (those driving timers and other peripheral hardware) are very often much slower than CPU clocks. It does not surprise me that you get the same time several times. Be patient, it might only change once a second. Write a loop polling until change and make some kind of output. You might see a 1Hz pattern. – Yunnosch Jun 26 '19 at 17:13
  • @Kamil Cuk I don't have to use clock(), what does HAL_GetTick() itself return? Can i use it to achieve what I want? For example, ------ uint32_t start = HAL_GetTick(); while(HAL_GetTick() - start < 100 ) {} ------- How much time does this while loop delay the system? I am not with the board now so i can't try myself, sorry for that. – muyustan Jun 26 '19 at 17:57
  • Usually systick is configured as a 1ms. The counter is incremented in the interrupt. It's [plain simple](https://github.com/nodtem66/STM32F411RE/blob/master/system/src/stm32f4-hal/stm32f4xx_hal.c#L304). The `HAL_IncTick()` is called from [systick interrupt](https://github.com/fboris/STM32Cube_FW_F4/blob/master/Projects/STM32F4-Discovery/Examples/UART/UART_TwoBoards_ComDMA/Src/stm32f4xx_it.c#L158). If you start your way with embedded programing, start with something that will help you, ex. [STM32cubemx](https://www.st.com/en/development-tools/stm32cubemx.html) – KamilCuk Jun 26 '19 at 18:06
  • @muyustan maybe some googling would help.... http://embeddedsystemengineering.blogspot.com/2015/04/stm32f4-discovery-tutorial-4-make-delay.html – bigwillydos Jun 26 '19 at 18:07
  • @Kamil Cuk thanks for all – muyustan Jun 26 '19 at 18:10
  • @bigwillydos I actually searched a lot but didn't see that one, thanks – muyustan Jun 26 '19 at 18:11

1 Answers1

1

The answer depends on the required precision and intervals.

For shorter intervals with sub-microsecond precision there is a cycle counter. Your suspicion is correct, it would overflow after 232/168*106 ~ 25.5 seconds.

For longer intervals there are timers that can be prescaled to support any possible subdivision of the 168 MHz clock. The most commonly used setup is the SysTick timer set to generate an interrupt at 1 kHz frequency, which increments a software counter. Reading this counter would give the number of milliseconds elapsed since startup. As it is usually a 32 bit counter, it would overflow after 49.7 days. The HAL library sets SysTick up this way, the counter can then be queried using the HAL_GetTick() function.

For even longer or more specialized timing requirements you can use the RTC peripheral which keeps calendar time, or the TIM peripherals (basic, general and advanced timers), these have their own prescalers, and they can be arranged in a master-slave setup to give almost arbitrary precision and intervals.

  • Hey, thanks for your answer. I used `HAL_GetTick()` and achieved a ms precision time calculation based on the comments above. What I don't understand clearly with your answer is : What does 1kHz freq interrupt mean exactly? Is it based on time or clock cycles ? `1000 increment / 1 seconds` or `1 increment per 1000 clock cycles` ? It looks like it is the former one, right ? – muyustan Jun 27 '19 at 05:26
  • Right. 1 [kHz](https://en.wikipedia.org/wiki/Hertz) means that something happens 1000 times / second. If the system clock is 168 MHz (168 million cycles/sec), then SysTick should be configured to trigger an interrupt in every 168000 cycles. – followed Monica to Codidact Jun 27 '19 at 05:54
  • hey, thanks for the answer. I am near to crying, I am reading documentation of systick hal functions for hours, please tell me one reason why `HAL_SetTickFreq(100);` does not cause the system to enter `SysTick_Handler` at each 100 miliseconds instead of each miliseconds ? I am writing `HAL_SetTickFreq(100);` before while(1) loop and never set it back to 1 again, I wrote in `SysTick_Handler` that XOR an LED but I cannot observe the blinking it is just ON. `void SysTick_Handler(void) { HAL_IncTick(); GPIOD->ODR ^= LED4_Pin ; }` – muyustan Jun 27 '19 at 09:23
  • You won't get anywhere with HAL and its so-called documentation. Forget it *now*, or it'd become much worse later. If you drop HAL, SysTick becomes easy: `SysTick->LOAD = 16799999;SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;` and the interrupt comes 10 times / sec (load value = system clock / desired freq - 1). Full documentation of SysTick is in the Programming Manual, other timers are in the Reference Manual, [both available from ST](https://www.st.com/en/microcontrollers-microprocessors/stm32f407-417.html#resource) – followed Monica to Codidact Jun 27 '19 at 12:45
  • thanks, i will try it now, I also want to learn things from basics but I don't know actually how to proceed, if you have time later, can you post a comment about how can i proceed ? – muyustan Jun 27 '19 at 13:12
  • I could not achieve, same again Interrupt does not happen at each 100ms – muyustan Jun 27 '19 at 13:36
  • 1
    `SysTick->LOAD = 168000000 / 10 - 1 ;` I realized by debugging that after executing this line LOAD value becomes `22783` instead of what it should be `167999999`. I checked it is `uint32_t`, so I could not understand why such a thing happens. Edit : I now am sure that it is something about this overflowish thing because both ways HAL and direct register coding, I cannot get 10Hz freq , while 1kHz and 100Hz are achievable. – muyustan Jun 27 '19 at 13:55
  • Oops, it's just over the 24 bit limit (see the programming manual). So it won't work direcly winth SysTick. You can set it to 2^24 - 1 just to see if that works, then move on to the real timers in the reference manual. – followed Monica to Codidact Jun 27 '19 at 13:59
  • it is like a huge joke, all it was about that size issue, and 2^24 -1 differed desired frequency from 10 to only 10.0136. It is crazy. Thanks again. – muyustan Jun 27 '19 at 14:42