├── dwt_delay.h ├── LICENSE ├── dwt_delay.c └── README.md /dwt_delay.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple microseconds delay routine, utilizing ARM's DWT 3 | * (Data Watchpoint and Trace Unit) and HAL library. 4 | * Intended to use with gcc compiler, but I hope it can be used 5 | * with any other C compiler across the Universe (provided that 6 | * ARM and CMSIS already invented) :) 7 | * Max K 8 | * 9 | * 10 | * This file is part of DWT_Delay package. 11 | * DWT_Delay is free software: you can redistribute it and/or modify it 12 | * under the terms of the MIT License. 13 | */ 14 | 15 | #if defined(__CORTEX_M) && __CORTEX_M < 3U 16 | #warning DWT_Delay in useless in this project since DWT unit is not accessible \ 17 | by processor on Cortex-M0/0+/1 cores. You may want to implement microdelays \ 18 | with hardware timer. 19 | #endif 20 | 21 | #ifndef INC_DWT_DELAY_H_ 22 | #define INC_DWT_DELAY_H_ 23 | 24 | #include 25 | 26 | #define DWT_DELAY_NEWBIE 0 27 | 28 | void DWT_Init(void); 29 | void DWT_Delay(uint32_t us); 30 | 31 | #endif /* INC_DWT_DELAY_H_ */ 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 and so on 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dwt_delay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple microseconds delay routine, utilizing ARM's DWT 3 | * (Data Watchpoint and Trace Unit) and HAL library. 4 | * Intended to use with gcc compiler, but I hope it can be used 5 | * with any other C compiler across the Universe (provided that 6 | * ARM and CMSIS already invented) :) 7 | * Max K 8 | * 9 | * 10 | * This file is part of DWT_Delay package. 11 | * DWT_Delay is free software: you can redistribute it and/or modify it 12 | * under the terms of the MIT License 13 | */ 14 | 15 | #include "stm32f1xx_hal.h" // change to whatever MCU or Cortex-M core you use 16 | #include "dwt_delay.h" 17 | 18 | /** 19 | * Initialization routine. 20 | * You might need to enable access to DWT registers on Cortex-M7 21 | * DWT->LAR = 0xC5ACCE55 22 | */ 23 | void DWT_Init(void) 24 | { 25 | if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) { 26 | CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 27 | DWT->CYCCNT = 0; 28 | DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 29 | } 30 | } 31 | 32 | #if DWT_DELAY_NEWBIE 33 | /** 34 | * If you are a newbie and see magic in DWT_Delay, consider this more 35 | * illustrative function, where you explicitly determine a counter 36 | * value when delay should stop while keeping things in bounds of uint32. 37 | * 38 | * @param uint32_t us Number of microseconds to delay for 39 | */ 40 | void DWT_Delay(uint32_t us) 41 | { 42 | uint32_t startTick = DWT->CYCCNT, 43 | targetTick = DWT->CYCCNT + us * (SystemCoreClock/1000000); 44 | 45 | // Must check if target tick is out of bounds and overflowed 46 | if (targetTick > startTick) { 47 | // Not overflowed 48 | while (DWT->CYCCNT < targetTick); 49 | } else { 50 | // Overflowed 51 | while (DWT->CYCCNT > startTick || DWT->CYCCNT < targetTick); 52 | } 53 | } 54 | #else 55 | /** 56 | * Delay routine itself. 57 | * Time is in microseconds (1/1000000th of a second), not to be 58 | * confused with millisecond (1/1000th). 59 | * 60 | * No need to check an overflow. Let it just tick :) 61 | * 62 | * @param uint32_t us Number of microseconds to delay for 63 | */ 64 | void DWT_Delay(uint32_t us) 65 | { 66 | uint32_t startTick = DWT->CYCCNT, 67 | delayTicks = us * (SystemCoreClock/1000000); 68 | 69 | while (DWT->CYCCNT - startTick < delayTicks); 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dwt_delay 2 | Microseconds delay lib based on DWT for STM32 or whatever ARM supporting it. 3 | Just include `dwt_delay.h` in your project, call `DWT_Init()` and then use delays as needed. 4 | 5 | Depending on MCU used, you may need to include another header file (with MCU peripherals defines) in `dwt_delay.h`. 6 | The `stm32f1xx.h` is included by default, allowing STM32F1xx to start out of the box. 7 | If you don't use STM32 MCU or CubeMX, read a section at the end. 8 | 9 | Functions are named as DWT_* to be HAL-alike. Feel free to do whatever you like with this lib, 10 | change names, indents, coding style, use it in LHC firmware. 11 | 12 | 13 | ## Example 14 | 15 | ```c 16 | /* main.c */ 17 | 18 | #include "dwt_delay.h" 19 | 20 | 21 | void main (void) 22 | { 23 | // Init section of your code 24 | DWT_Init(); 25 | 26 | 27 | while(1) { 28 | // Delay for 42us 29 | DWT_Delay(42); 30 | } 31 | 32 | } 33 | ``` 34 | 35 | ## Notes on Cortex-M0/0+/1 36 | Unfortunately, these are not supported, since cores have no access to DWT. CMSIS library states: 37 | ``` 38 | Cortex-M0/0+/1 Core Debug Registers are only accessible over DAP and not via processor 39 | ``` 40 | You may want a delay function based on hardware timer instead. 41 | 42 | 43 | ## What about Cortex-M35/55/85? 44 | I don't have any of these to check, but in theory they are supported. 45 | Anyway you have to change `CoreDebug` to `DCB`, because `CoreDebug` is deprecated in these cores. 46 | 47 | Hence, init sequence should be something like: 48 | ```c 49 | DCB->DEMCR |= ‎DCB_DEMCR_TRCENA_Msk; 50 | ``` 51 | 52 | 53 | ## I'm not with STM but need microsec delays 54 | There's an option to try! Also suits those, who use STM32, but dont use HAL/LL libs. 55 | 56 | Include a CMSIS header file according to your core in `dwt_delay.c` and change `SystemCoreClock` 57 | variable to whatever you probably have in the project representing clock frequency (in Hz). 58 | 59 | Something like this: 60 | ```c 61 | // In dwt_delay.c 62 | 63 | #include "dwt_delay.h" 64 | #include "core_cm4.h" // CMSIS header 65 | 66 | #define SystemCoreClock NameOfTheGlobalVariableInYourProject_or_AnotherDefine 67 | // or at least 68 | #define SystemCoreClock 48000000UL // Clock is 48Mhz 69 | ... 70 | ``` 71 | 72 | 73 | ## Changelog 74 | - **2018-01-06** 75 | This lib emerged. 76 | 77 | - **2019-02-19** 78 | Overflow check added. 79 | 80 | - **2019-03-26** 81 | Typo in definition fixed. Got back to short and simpler function. 82 | 83 | - **2023-11-21** 84 | Now it is MIT License. Added warning for Cortex-M0/0+/1 and notes regarding other Cortex-M cores. 85 | --------------------------------------------------------------------------------