近几日,闲来无事,决定把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;
}
}