【轉】STM32 不占用定時器(包括SysTick)實現精確延時(巧用DWT)



/** ****************************************************************** * file core_delay.c * author fire * version V1.0 * date 2018-xx-xx * [url=home.php?mod=space&uid=247401]@brief[/url] 使用內核寄存器精確延時 ****************************************************************** * @attention * * 實驗平台:野火 STM32開發板 * 論壇 :http://www.firebbs.cn * 淘寶 :https://fire-stm32.taobao.com * ****************************************************************** */ #include "./delay/core_delay.h" /* ********************************************************************** * 時間戳相關寄存器定義 ********************************************************************** */ /* 在Cortex-M里面有一個外設叫DWT(Data Watchpoint and Trace), 該外設有一個32位的寄存器叫CYCCNT,它是一個向上的計數器, 記錄的是內核時鍾運行的個數,最長能記錄的時間為: 10.74s=2的32次方/400000000 (假設內核頻率為400M,內核跳一次的時間大概為1/400M=2.5ns) 當CYCCNT溢出之后,會清0重新開始向上計數。 使能CYCCNT計數的操作步驟: 1、先使能DWT外設,這個由另外內核調試寄存器DEMCR的位24控制,寫1使能 2、使能CYCCNT寄存器之前,先清0 3、使能CYCCNT寄存器,這個由DWT_CTRL(代碼上宏定義為DWT_CR)的位0控制,寫1使能 */
 
    #define  DWT_CR      *(__IO uint32_t *)0xE0001000 //< 0xE0001000 DWT_CTRL RW The Debug Watchpoint and Trace (DWT) unit
    #define  DWT_CYCCNT  *(__IO uint32_t *)0xE0001004 //< 0xE0001004 DWT_CYCCNT RW Cycle Count register, 
    #define  DEM_CR      *(__IO uint32_t *)0xE000EDFC //< 0xE000EDFC DEMCR RW Debug Exception and Monitor Control Register.


    #define  DEM_CR_TRCENA                   (1 << 24)  //DEMCR的DWT使能位
    #define  DWT_CR_CYCCNTENA                (1 <<  0)  //DWT的SYCCNT使能位
    /**
      * @brief  初始化時間戳
      * @param  無
      * @retval 無
      * [url=home.php?mod=space&uid=536309]@NOTE[/url]   使用延時函數前,必須調用本函數
      */
    HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
    {
        /* 使能DWT外設 */
        DEM_CR |= (uint32_t)DEM_CR_TRCENA;               

        /* DWT CYCCNT寄存器計數清0 */
        DWT_CYCCNT = (uint32_t)0u;

        /* 使能Cortex-M DWT CYCCNT寄存器 */
        DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
      
        return HAL_OK;
    }

    /**
      * @brief  讀取當前時間戳
      * @param  無
      * @retval 當前時間戳,即DWT_CYCCNT寄存器的值
      */
    uint32_t CPU_TS_TmrRd(void)
    {        
      return ((uint32_t)DWT_CYCCNT);
    }

    /**
      * @brief  讀取當前時間戳
      * @param  無
      * @retval 當前時間戳,即DWT_CYCCNT寄存器的值
      */
    uint32_t HAL_GetTick(void)
    {        
      return ((uint32_t)DWT_CYCCNT/SysClockFreq*1000);
    }


    /**
      * @brief  采用CPU的內部計數實現精確延時,32位計數器
      * @param  us : 延遲長度,單位1 us
      * @retval 無
      * [url=home.php?mod=space&uid=536309]@NOTE[/url]   使用本函數前必須先調用CPU_TS_TmrInit函數使能計數器,
                或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
                最大延時值為8秒,即8*1000*1000
      */
    void CPU_TS_Tmr_Delay_US(uint32_t us)
    {
      uint32_t ticks;
      uint32_t told,tnow,tcnt=0;

      /* 在函數內部初始化時間戳寄存器, */  
    #if (CPU_TS_INIT_IN_DELAY_FUNCTION)  
      /* 初始化時間戳並清零 */
      HAL_InitTick(5);
    #endif
      
      ticks = us * (GET_CPU_ClkFreq() / 1000000);  /* 需要的節拍數 */      
      tcnt = 0;
      told = (uint32_t)CPU_TS_TmrRd();         /* 剛進入時的計數器值 */

      while(1)
      {
        tnow = (uint32_t)CPU_TS_TmrRd();  
        if(tnow != told)
        {
            /* 32位計數器是遞增計數器 */   
          if(tnow > told)
          {
            tcnt += tnow - told;  
          }
          /* 重新裝載 */
          else
          {
            tcnt += UINT32_MAX - told + tnow;
          }
          
          told = tnow;

          /*時間超過/等於要延遲的時間,則退出 */
          if(tcnt >= ticks)break;
        }  
      }
    }

    /*********************************************END OF FILE**********************/
    #ifndef __CORE_DELAY_H
    #define __CORE_DELAY_H

    #include "stm32h7xx.h"

    /* 獲取內核時鍾頻率 */
    #define GET_CPU_ClkFreq()       HAL_RCC_GetSysClockFreq()
    #define SysClockFreq            (218000000)
    /* 為方便使用,在延時函數內部調用CPU_TS_TmrInit函數初始化時間戳寄存器,
       這樣每次調用函數都會初始化一遍。
       把本宏值設置為0,然后在main函數剛運行時調用CPU_TS_TmrInit可避免每次都初始化 */  

    #define CPU_TS_INIT_IN_DELAY_FUNCTION   0  


    /*******************************************************************************
    * 函數聲明
    ******************************************************************************/
    uint32_t CPU_TS_TmrRd(void);
    HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority);

    //使用以下函數前必須先調用CPU_TS_TmrInit函數使能計數器,或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
    //最大延時值為8秒
    void CPU_TS_Tmr_Delay_US(uint32_t us);
    #define HAL_Delay(ms)     CPU_TS_Tmr_Delay_US(ms*1000)
    #define CPU_TS_Tmr_Delay_S(s)       CPU_TS_Tmr_Delay_MS(s*1000)


    #endif /* __CORE_DELAY_H */

 

上面代碼的核心是:采用Cortex-M3/4內核中的跟蹤組件DWT的時鍾周期計數CYCCNT實現

參考鏈接

http://www.firebbs.cn/forum.php?mod=viewthread&tid=19059&fromuid=1

https://blog.csdn.net/linux_liulu/article/details/44998581


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM