DWT计数器在cortex-m7上不能正常工作的解决办法

近几日,闲来无事,决定把LiteOS移植到STM32F746ZG_NUCLEO开发板上,调试过程中发现HUAWEI提供有dwt.c/.h的实现,心痒痒就决定弄个闪烁LED试一下,结果发现不能正常运行,断点跟踪发现DWT_CYCCNT计数器的值始终为0,也就是说DWT压根就没进行计数操作,但是F4和F1系列却可以正常工作。这说明M7核心的配置肯定跟M3和M4有所不同,打开core_m4.h和core_m7.h对比了一下,果然有所发现有些地方不一样,下面是DWT结构体在core_m4.h和core_m7.h中的定义

core_m4.h中的DWT结构体

typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  Control Register */
  __IOM uint32_t CYCCNT;                 /*!< Offset: 0x004 (R/W)  Cycle Count Register */
  __IOM uint32_t CPICNT;                 /*!< Offset: 0x008 (R/W)  CPI Count Register */
  __IOM uint32_t EXCCNT;                 /*!< Offset: 0x00C (R/W)  Exception Overhead Count Register */
  __IOM uint32_t SLEEPCNT;               /*!< Offset: 0x010 (R/W)  Sleep Count Register */
  __IOM uint32_t LSUCNT;                 /*!< Offset: 0x014 (R/W)  LSU Count Register */
  __IOM uint32_t FOLDCNT;                /*!< Offset: 0x018 (R/W)  Folded-instruction Count Register */
  __IM  uint32_t PCSR;                   /*!< Offset: 0x01C (R/ )  Program Counter Sample Register */
  __IOM uint32_t COMP0;                  /*!< Offset: 0x020 (R/W)  Comparator Register 0 */
  __IOM uint32_t MASK0;                  /*!< Offset: 0x024 (R/W)  Mask Register 0 */
  __IOM uint32_t FUNCTION0;              /*!< Offset: 0x028 (R/W)  Function Register 0 */
        uint32_t RESERVED0[1U];
  __IOM uint32_t COMP1;                  /*!< Offset: 0x030 (R/W)  Comparator Register 1 */
  __IOM uint32_t MASK1;                  /*!< Offset: 0x034 (R/W)  Mask Register 1 */
  __IOM uint32_t FUNCTION1;              /*!< Offset: 0x038 (R/W)  Function Register 1 */
        uint32_t RESERVED1[1U];
  __IOM uint32_t COMP2;                  /*!< Offset: 0x040 (R/W)  Comparator Register 2 */
  __IOM uint32_t MASK2;                  /*!< Offset: 0x044 (R/W)  Mask Register 2 */
  __IOM uint32_t FUNCTION2;              /*!< Offset: 0x048 (R/W)  Function Register 2 */
        uint32_t RESERVED2[1U];
  __IOM uint32_t COMP3;                  /*!< Offset: 0x050 (R/W)  Comparator Register 3 */
  __IOM uint32_t MASK3;                  /*!< Offset: 0x054 (R/W)  Mask Register 3 */
  __IOM uint32_t FUNCTION3;              /*!< Offset: 0x058 (R/W)  Function Register 3 */
} DWT_Type;

core_m7.h中结构体的定义

typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  Control Register */
  __IOM uint32_t CYCCNT;                 /*!< Offset: 0x004 (R/W)  Cycle Count Register */
  __IOM uint32_t CPICNT;                 /*!< Offset: 0x008 (R/W)  CPI Count Register */
  __IOM uint32_t EXCCNT;                 /*!< Offset: 0x00C (R/W)  Exception Overhead Count Register */
  __IOM uint32_t SLEEPCNT;               /*!< Offset: 0x010 (R/W)  Sleep Count Register */
  __IOM uint32_t LSUCNT;                 /*!< Offset: 0x014 (R/W)  LSU Count Register */
  __IOM uint32_t FOLDCNT;                /*!< Offset: 0x018 (R/W)  Folded-instruction Count Register */
  __IM  uint32_t PCSR;                   /*!< Offset: 0x01C (R/ )  Program Counter Sample Register */
  __IOM uint32_t COMP0;                  /*!< Offset: 0x020 (R/W)  Comparator Register 0 */
  __IOM uint32_t MASK0;                  /*!< Offset: 0x024 (R/W)  Mask Register 0 */
  __IOM uint32_t FUNCTION0;              /*!< Offset: 0x028 (R/W)  Function Register 0 */
        uint32_t RESERVED0[1U];
  __IOM uint32_t COMP1;                  /*!< Offset: 0x030 (R/W)  Comparator Register 1 */
  __IOM uint32_t MASK1;                  /*!< Offset: 0x034 (R/W)  Mask Register 1 */
  __IOM uint32_t FUNCTION1;              /*!< Offset: 0x038 (R/W)  Function Register 1 */
        uint32_t RESERVED1[1U];
  __IOM uint32_t COMP2;                  /*!< Offset: 0x040 (R/W)  Comparator Register 2 */
  __IOM uint32_t MASK2;                  /*!< Offset: 0x044 (R/W)  Mask Register 2 */
  __IOM uint32_t FUNCTION2;              /*!< Offset: 0x048 (R/W)  Function Register 2 */
        uint32_t RESERVED2[1U];
  __IOM uint32_t COMP3;                  /*!< Offset: 0x050 (R/W)  Comparator Register 3 */
  __IOM uint32_t MASK3;                  /*!< Offset: 0x054 (R/W)  Mask Register 3 */
  __IOM uint32_t FUNCTION3;              /*!< Offset: 0x058 (R/W)  Function Register 3 */
        uint32_t RESERVED3[981U];
  __OM  uint32_t LAR;                    /*!< Offset: 0xFB0 (  W)  Lock Access Register */
  __IM  uint32_t LSR;                    /*!< Offset: 0xFB4 (R  )  Lock Status Register */
} DWT_Type;

发现core_m7.h中有两个成员变量很特别,就是下面两行

  __OM  uint32_t LAR;                    /*!< Offset: 0xFB0 (  W)  Lock Access Register */
  __IM  uint32_t LSR;                    /*!< Offset: 0xFB4 (R  )  Lock Status Register */

看注释知道这是一个访问锁寄存器,我们暂时猜测这个寄存器的功能是“不解锁就不能对DWT其他寄存器进行写操作”,那么该写一个什么样的值才能解锁呢,找了一大圈也没找到相关的内容,最后在参考手册的1687页看到了这么一张表(ITM单元的)

查看core_m7.h中ITM_Type结构体的定义,果然也有同样的“访问锁寄存器”,既然ITM写入0xC5ACCE55 可以解锁,那么DWT的LAR寄存器写入0xC5ACCE55 是不是也可以解锁呢,抱着试一试的态度,在dwt.h文件中添加两行了代码

#define  DWT_LAR     *(volatile uint32_t *)0xE0001FB0

#define  DWT_LAR_UNLOCK          (uint32_t)0xC5ACCE55

 然后又在dwt.c文件中添加了一行代码

void dwt_init(uint32_t clk)
{
    cpuclkfeq = clk;
    DWT_LAR        |= DWT_LAR_UNLOCK;    //新添加的代码
    DEM_CR         |= (uint32_t)DEM_CR_TRCENA;
    DWT_CYCCNT      = (uint32_t)0u;
    DWT_CR         |= (uint32_t)DWT_CR_CYCCNTENA;
}

重新编译,下载,果然开发板上的LED1开始闪烁,也就是说成功了,有时候你会发现,一个小BUG调试起来真的是好费劲啊^_^

最后,附上修改后的全部源代码

dwt.h 头文件


#ifndef __DWT_H_
#define __DWT_H_



#include "stm32f7xx.h"
//#include "los_hwi.h"



#define  DWT_CR      *(volatile uint32_t *)0xE0001000

#define  DWT_CYCCNT  *(volatile uint32_t *)0xE0001004
#define  DWT_LAR     *(volatile uint32_t *)0xE0001FB0

#define  DWT_LAR_UNLOCK          (uint32_t)0xC5ACCE55

#define  DEM_CR      *(volatile uint32_t *)0xE000EDFC

#define  DEM_CR_TRCENA                   (1 << 24)

#define  DWT_CR_CYCCNTENA                (1 <<  0)

#define delayms(msec)         delayus(msec*1000)

void dwt_init(uint32_t clk);   
void delayus(uint32_t usec);
void delay10ms(__IO uint32_t nTime);


#endif
dwt.c源文件

#include "dwt.h"



static uint32_t cpuclkfeq;

void dwt_init(uint32_t clk)
{
    cpuclkfeq = clk;
    DWT_LAR        |= DWT_LAR_UNLOCK;
    DEM_CR         |= (uint32_t)DEM_CR_TRCENA;
    DWT_CYCCNT      = (uint32_t)0u;
    DWT_CR         |= (uint32_t)DWT_CR_CYCCNTENA;
}

void delayus(uint32_t usec)

{
    uint32_t startts, endts, ts;
    uint32_t uwIntSave;
    startts = DWT_CYCCNT;

    ts =  usec * (cpuclkfeq / (1000 * 1000));
    endts = startts + ts;
    //uwIntSave = LOS_IntLock();
    if(endts > startts)
    {
        while(DWT_CYCCNT < endts);
    }
    else
    {
        while(DWT_CYCCNT > endts);
        while(DWT_CYCCNT < endts);
    }
    //(VOID)LOS_IntRestore(uwIntSave);
}

void delay10ms(__IO uint32_t nTime)
{
    delayus(1000 * nTime);
}
main.c源文件

#include "stm32f7xx.h"
#include "stm32f7xx_nucleo_144.h"
#include "sys_init.h"
#include "dwt.h"


__IO FlagStatus SwitchClock = RESET;


/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  //HAL_Init();

   
  /* Enable HSI oscillator and configure the PLL to reach the max system frequency (216 MHz)
     when using HSI oscillator as PLL clock source. */
  SystemClock_Config();
  
  dwt_init(SystemCoreClock);        //初始化DWT单元
  
  /* Configure LED1 */
  BSP_LED_Init(LED1);

  /* Initialize User push-button, will be used to trigger an interrupt each time it's pressed.*/
  BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);

  /* Toggle some leds in an infinite loop */
  while (1)
  {  
    /* Toggle LED1 */
    BSP_LED_Toggle(LED1);        //翻转触发器
   // HAL_Delay(100);
    delayms(100);                //调用DWT延时接口,其实这是一个宏定义,在dwt.h文件里
  }
}

/**
  * @brief  EXTI line detection callbacks.
  * @param  GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == KEY_BUTTON_PIN)
  {
    SwitchClock = SET;
  }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值