试验原因

以前在用ITM打印时,都按照 http://www.keil.com/support/man/docs/jlink/jlink_trace_itm_viewer.htm 的资料来写.

今天在STM32F407G-DISC1试验时,发现ITM打印不好使,再找一块开发板,就好使。
这说明STM32F407G-DISC1内建的STLINK升级后,不支持ITM, 可能有啥bug.
记得以前用ST官方板子,使用内建的STLINK(只需要用USB线连上官方板子就行)是可以打印ITM信息的。

在查资料时,突然看到有人说打印ITM只需要调用ITM_SendChar(). 只记得前段时间,作H7的实现,是这样的。没在F1和F4上试验。

在F4工程上试了一下,果真可以。
去查ITM_SendChar的实现,是在core_cm4.h中.
再去查了core_cm3.h, 也有ITM_SendChar的实现.
也就是说,ITM_SendChar在CMSIS库中已经实现好了.

ITM_SendChar()的实现在core_cm4.h中如下:

/** \brief  ITM Send CharacterThe function transmits a character via the ITM channel 0, and\li Just returns when no debugger is connected that has booked the output.\li Is blocking when a debugger is connected, but the previous character sent has not been transmitted.\param [in]     ch  Character to transmit.\returns            Character to transmit.*/
__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)
{if ((ITM->TCR & ITM_TCR_ITMENA_Msk)                  &&      /* ITM enabled */(ITM->TER & (1UL << 0)        )                    )     /* ITM Port #0 enabled */{while (ITM->PORT[0].u32 == 0);ITM->PORT[0].u8 = (uint8_t) ch;}return (ch);
}

可以看到ITM_SendChar()的实现和MDK官方的ITM使用指南资料,基本上是一样的。
那MDK官方为啥不说, 只调用ITM_SendChar()就能实现ITM呢? 费解.

试验

如果自己需要一个干净的F4固件库模板,可以从en.stm32f4_dsp_stdperiph_lib\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Templates中拷贝一个工程出来,按照自己的喜好, 将不用的东西(e.g. group)去掉,将文件补全(工程模板单独从SPL库中拷贝出来后,依赖的文件都不在了),编译过, 就可以整理出一个干净的模板。

/********************************************************************************* @file    Project/STM32F4xx_StdPeriph_Templates/main.c * @author  MCD Application Team* @version V1.8.0* @date    04-November-2016* @brief   Main program body******************************************************************************* @attention** <h2><center>&copy; COPYRIGHT 2016 STMicroelectronics</center></h2>** Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");* You may not use this file except in compliance with the License.* You may obtain a copy of the License at:**        http://www.st.com/software_license_agreement_liberty_v2** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.********************************************************************************//* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdio.h>int fputc(int ch, FILE *f) {return ITM_SendChar(ch); // ITM_SendChar declare on core_cm4.h
}/** @addtogroup Template_Project* @{*/ /* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static __IO uint32_t uwTimingDelay;
RCC_ClocksTypeDef RCC_Clocks;/* Private function prototypes -----------------------------------------------*/
static void Delay(__IO uint32_t nTime);/* Private functions ---------------------------------------------------------*//*** @brief  Main program* @param  None* @retval None*/
int main(void)
{int i_loop_cnt = 0;/*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startupfiles before to branch to application main.To reconfigure the default setting of SystemInit() function, refer to system_stm32f4xx.c file *//* SysTick end of count event each 1ms */RCC_GetClocksFreq(&RCC_Clocks);// RCC_Clocks.SYSCLK_Frequency = 168000000// RCC_Clocks.HCLK_Frequency = 168000000// RCC_Clocks.PCLK1_Frequency = 42000000// RCC_Clocks.PCLK2_Frequency = 84000000SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);/* Infinite loop */while (1){Delay(1000); // delay msprintf("i_loop_cnt = %d\n", ++i_loop_cnt);}
}/*** @brief  Inserts a delay time.* @param  nTime: specifies the delay time length, in milliseconds.* @retval None*/
void Delay(__IO uint32_t nTime)
{ uwTimingDelay = nTime;while(uwTimingDelay != 0);
}/*** @brief  Decrements the TimingDelay variable.* @param  None* @retval None*/
void TimingDelay_Decrement(void)
{if (uwTimingDelay != 0x00){ uwTimingDelay--;}
}#ifdef  USE_FULL_ASSERT/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t* file, uint32_t line)
{ /* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* Infinite loop */while (1){}
}
#endif/*** @}*//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

干净模板的配置
工程预处理宏
USE_STDPERIPH_DRIVER,STM32F40_41xxx
头文件包含路径
…\CMSIS;…\STM32F4xx_StdPeriph_Driver\inc
加入和整理的文件列表



.
├─CMSIS
│      startup_stm32f401xx.s
│      startup_stm32f40xx.s
│      startup_stm32f40_41xxx.s
│      startup_stm32f410xx.s
│      startup_stm32f411xe.s
│      startup_stm32f412xg.s
│      startup_stm32f413_423xx.s
│      startup_stm32f427x.s
│      startup_stm32f427_437xx.s
│      startup_stm32f429_439xx.s
│      startup_stm32f446xx.s
│      startup_stm32f469_479xx.s
│      stm32f4xx.h
│      stm32f4xx_conf.h
│      system_stm32f4xx.c
│      system_stm32f4xx.h
│
├─MDK
│      Project.uvoptx
│      Project.uvprojx
│      readme.txt
│
├─src
│      main.c
│      main.h
│      readme.txt
│      Release_Notes.html
│      stm32f4xx_it.c
│      stm32f4xx_it.h
│
└─STM32F4xx_StdPeriph_Driver│  Release_Notes.html│  ├─inc│      misc.h│      stm32f4xx_adc.h│      stm32f4xx_can.h│      stm32f4xx_cec.h│      stm32f4xx_crc.h│      stm32f4xx_cryp.h│      stm32f4xx_dac.h│      stm32f4xx_dbgmcu.h│      stm32f4xx_dcmi.h│      stm32f4xx_dfsdm.h│      stm32f4xx_dma.h│      stm32f4xx_dma2d.h│      stm32f4xx_dsi.h│      stm32f4xx_exti.h│      stm32f4xx_flash.h│      stm32f4xx_flash_ramfunc.h│      stm32f4xx_fmc.h│      stm32f4xx_fmpi2c.h│      stm32f4xx_fsmc.h│      stm32f4xx_gpio.h│      stm32f4xx_hash.h│      stm32f4xx_i2c.h│      stm32f4xx_iwdg.h│      stm32f4xx_lptim.h│      stm32f4xx_ltdc.h│      stm32f4xx_pwr.h│      stm32f4xx_qspi.h│      stm32f4xx_rcc.h│      stm32f4xx_rng.h│      stm32f4xx_rtc.h│      stm32f4xx_sai.h│      stm32f4xx_sdio.h│      stm32f4xx_spdifrx.h│      stm32f4xx_spi.h│      stm32f4xx_syscfg.h│      stm32f4xx_tim.h│      stm32f4xx_usart.h│      stm32f4xx_wwdg.h│      └─srcmisc.cstm32f4xx_adc.cstm32f4xx_can.cstm32f4xx_cec.cstm32f4xx_crc.cstm32f4xx_cryp.cstm32f4xx_cryp_aes.cstm32f4xx_cryp_des.cstm32f4xx_cryp_tdes.cstm32f4xx_dac.cstm32f4xx_dbgmcu.cstm32f4xx_dcmi.cstm32f4xx_dfsdm.cstm32f4xx_dma.cstm32f4xx_dma2d.cstm32f4xx_dsi.cstm32f4xx_exti.cstm32f4xx_flash.cstm32f4xx_flash_ramfunc.cstm32f4xx_fmc.cstm32f4xx_fmpi2c.cstm32f4xx_fsmc.cstm32f4xx_gpio.cstm32f4xx_hash.cstm32f4xx_hash_md5.cstm32f4xx_hash_sha1.cstm32f4xx_i2c.cstm32f4xx_iwdg.cstm32f4xx_lptim.cstm32f4xx_ltdc.cstm32f4xx_pwr.cstm32f4xx_qspi.cstm32f4xx_rcc.cstm32f4xx_rng.cstm32f4xx_rtc.cstm32f4xx_sai.cstm32f4xx_sdio.cstm32f4xx_spdifrx.cstm32f4xx_spi.cstm32f4xx_syscfg.cstm32f4xx_tim.cstm32f4xx_usart.cstm32f4xx_wwdg.c

改好的HSE=25HMZ的F407工程模板 : STM32F407VG_StdPeriph_Templates_2020_0316_1945.zip
这个工程用的晶振是25MHZ. 如果开发板晶振是不是25MHZ, 打印不出ITM信息。(2020_0317_1428)

改好的HSE=8HMZ的F407工程模板 : STM32F407VG_StdPeriph_Templates_8MHZ_2020_0317_1608.zip
这个工程用的晶振是8MHZ. 适用于STM32F4DISCOVERY板子(2020_0317_1610), 可以打印出ITM信息

调试为啥打印不出ITM信息

因为在其他板子上,可以打印出ITM信息。
有点怀疑这块 STM32F407G-DISC1 坏掉了,因为ST官方板子总是能打印出ITM信息的, 想再验证下。

试验1

按照官方的用户手册, 将CN3的2个跳线摘掉,手工焊接SWD的6根线到CN2, 用万用表量过了,确定没焊错。上电,接上独立的STLINK, 状态不对,原来烧好的程序跑不起来了。

因为CN2是和板载的STLINK通讯,所以外接的STLINK的管脚焊在CN2上是不对的。

试验2

现在将外接STLINK需要的SWD管脚直接焊接到板子下方F407引出的2个插排(P1,P2)上。
接上外接的STLINK, 上电,这回板子上烧好的程序跑的正确。
用MDK的调试器选项,打开STLINK, 芯片识别正确。
单步可以执行,但是还是打印不出ITM信息。
MCU的SWO管脚坏掉了?

STM32F407G-DISC1 板子的上下2块(板载STLINK和下面的F407电路)之间没有供掰断的PCB槽,也没法将板载的STLINK的MCU吹下来, 没办法验证只保留下面的F407电路是否可以输出ITM信息。

就这样了,一会再换个板子(最小系统板,IO大部分引出),再看看ITM信息是否能打印出来。
如果打印出来了,就再去接外部的SPI方式的TF卡模块,继续作试验。

留张板子试验快照

需要接的6根线如下:

2020_0317_1422 ITM打印问题解决

我今天在另外一块板子上,用同样的程序,也打不出ITM信息。
但是那块板子有demo工程,可以打印出ITM信息。这说明我的试验工程有问题,和板子无关。
这下比对知道问题在哪了。原来是板子上的晶振频率不一样。
STM32F407G-DISC1的晶振是8MHZ, 从官方固件库工程模板直接整理出的工程,晶振是25MHZ…

在工程中按照实际晶振频率改系统时钟频率的方法

首先要在程序入口处,取一下时钟频率,然后手工设置时钟频率.
如果不主动设置时钟频率, 程序跑起来后,不会进SysTick_Handler(), 那就没有时钟了。所有和时基,延时相关的函数都死循环,程序不能正常跑了。

对于F407, 晶振频率是168MHZ(一般大家都用F407的标称频率). RCC_Clocks.HCLK_Frequency取出的值是168000000.

int main(void)
{int i_loop_cnt = 0;/*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startupfiles before to branch to application main.To reconfigure the default setting of SystemInit() function, refer to system_stm32f4xx.c file *//* SysTick end of count event each 1ms */RCC_GetClocksFreq(&RCC_Clocks);// RCC_Clocks.SYSCLK_Frequency = 168000000// RCC_Clocks.HCLK_Frequency = 168000000// RCC_Clocks.PCLK1_Frequency = 42000000// RCC_Clocks.PCLK2_Frequency = 84000000SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);/* Infinite loop */while (1){Delay(1000); // delay msprintf("i_loop_cnt = %d\n", ++i_loop_cnt);}
}

RCC_GetClocksFreq() 中取时钟频率时,用到了HSE_VALUE, 这是外部晶振的频率,要设置的和实际晶振频率相同.
\STM32F407VG_StdPeriph_Templates\CMSIS\stm32f4xx.h

/*** @brief In the following line adjust the value of External High Speed oscillator (HSE)used in your application Tip: To avoid modifying this file each time you need to use different HSE, youcan define the HSE value in your toolchain compiler preprocessor.*/
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx)  || defined(STM32F429_439xx) || defined(STM32F401xx) || \defined(STM32F410xx) || defined(STM32F411xE) || defined(STM32F469_479xx)#if !defined  (HSE_VALUE) // #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */#define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */#endif /* HSE_VALUE */
#elif defined (STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)#if !defined  (HSE_VALUE) #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */#endif /* HSE_VALUE */
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F411xE || STM32F469_479xx */

上面这段代码说,也可以在预编译宏中设置HSE_VALUE的值.
还是直接在代码中写死比较好。以后直接拷贝到其他工程,晶振频率也不会变。

如果设置了正确的HSE_VALUE值,取到的RCC_Clocks.HCLK_Frequency不是168000000, 就需要看PLL锁相环的参数设置的是否正确。

去启动文件中,找到系统初始化函数Reset_Handler()
STM32F407VG_StdPeriph_Templates\CMSIS\startup_stm32f40_41xxx.s

__Vectors_Size  EQU  __Vectors_End - __VectorsAREA    |.text|, CODE, READONLY; Reset handler
Reset_Handler    PROCEXPORT  Reset_Handler             [WEAK]IMPORT  SystemInitIMPORT  __mainLDR     R0, =SystemInit ; 系统初始化函数,里面初始化了系统时钟BLX     R0LDR     R0, =__mainBX      R0ENDP; Dummy Exception Handlers (infinite loops which can be modified)NMI_Handler     PROCEXPORT  NMI_Handler                [WEAK]B       .ENDP

点击SystemInit(), F12去看系统初始化函数的实现。

void SystemInit(void)
{/* FPU settings ------------------------------------------------------------*/#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */#endif/* Reset the RCC clock configuration to the default reset state ------------*//* Set HSION bit */RCC->CR |= (uint32_t)0x00000001;/* Reset CFGR register */RCC->CFGR = 0x00000000;/* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset PLLCFGR register */RCC->PLLCFGR = 0x24003010;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Disable all interrupts */RCC->CIR = 0x00000000;#if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM *//* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/SetSysClock(); // 这里初始化了系统时钟/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

SystemInit()调用了SetSysClock()初始化了系统时钟,去看SetSysClock()

/*** @brief  Configures the System clock source, PLL Multiplier and Divider factors, *         AHB/APBx prescalers and Flash settings* @Note   This function should be called only once the RCC clock configuration  *         is reset to the default reset state (done in SystemInit() function).   * @param  None* @retval None*/
static void SetSysClock(void)
{#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)|| defined(STM32F469_479xx)
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* Enable HSE */RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}if (HSEStatus == (uint32_t)0x01){/* Select regulator voltage output Scale 1 mode */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;/* HCLK = SYSCLK / 1*/RCC->CFGR |= RCC_CFGR_HPRE_DIV1;#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) ||  defined(STM32F412xG) || defined(STM32F446xx) || defined(STM32F469_479xx)    /* PCLK2 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx  || STM32F412xG || STM32F446xx || STM32F469_479xx */#if defined(STM32F401xx) || defined(STM32F413_423xx)/* PCLK2 = HCLK / 1*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
#endif /* STM32F401xx || STM32F413_423xx */#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)    /* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
#endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */#if  defined(STM32F412xG) || defined(STM32F413_423xx) || defined(STM32F446xx)/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24) | (PLL_R << 28);
#endif /* STM32F412xG || STM32F413_423xx || STM32F446xx */    /* Enable the main PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till the main PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)/* Enable the Over-drive to extend the clock frequency to 180 Mhz */PWR->CR |= PWR_CR_ODEN;while((PWR->CSR & PWR_CSR_ODRDY) == 0){}PWR->CR |= PWR_CR_ODSWEN;while((PWR->CSR & PWR_CSR_ODSWRDY) == 0){}      /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F427_437x || STM32F429_439xx || STM32F446xx || STM32F469_479xx */#if defined(STM32F40_41xxx)  || defined(STM32F412xG)  /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F40_41xxx  || STM32F412xG */#if defined(STM32F413_423xx)  /* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_3WS;
#endif /* STM32F413_423xx */#if defined(STM32F401xx)/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
#endif /* STM32F401xx *//* Select the main PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= RCC_CFGR_SW_PLL;/* Wait till the main PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);{}}else{ /* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}
#elif defined(STM32F410xx) || defined(STM32F411xE)
#if defined(USE_HSE_BYPASS)
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* Enable HSE and HSE BYPASS */RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}if (HSEStatus == (uint32_t)0x01){/* Select regulator voltage output Scale 1 mode */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;/* HCLK = SYSCLK / 1*/RCC->CFGR |= RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);/* Enable the main PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till the main PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;/* Select the main PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= RCC_CFGR_SW_PLL;/* Wait till the main PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);{}}else{ /* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}
#else /* HSI will be used as PLL clock source *//* Select regulator voltage output Scale 1 mode */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;/* HCLK = SYSCLK / 1*/RCC->CFGR |= RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24); /* Enable the main PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till the main PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;/* Select the main PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= RCC_CFGR_SW_PLL;/* Wait till the main PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);{}
#endif /* USE_HSE_BYPASS */
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F469_479xx */
}

SetSysClock()算系统时钟参数的配置代码如下

#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)    /* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
#endif /* STM32F40_41xxx || STM32F401xx || STM32F427_437x || STM32F429_439xx || STM32F469_479xx */

从上面的时钟配置代码看, SetSysClock() 中算系统时钟参数时,用到了以下几个宏.
PLL_M
PLL_N
PLL_P
RCC_PLLCFGR_PLLSRC_HSE
PLL_Q
点击这几个参数,F12可以去看实际的值定义。
\STM32F407VG_StdPeriph_Templates\CMSIS\system_stm32f4xx.c中定义如下

#define PLL_M      8
#define PLL_N      336
#define PLL_P      2
#define  RCC_PLLCFGR_PLLSRC_HSE              ((uint32_t)0x00400000)
#define PLL_Q      7

如果这几个值和HSE_VALUE配合算出的值不是168MHZ, 可以用STM32CubeMX新建一个F407的工程,看看时钟配置那里,当HSE = 8MHZ时,剩下的PLL参数怎么配置,能使主时钟算到168MHZ.

2020_0412_1349

知道了keil官方给的ITM例子为啥不使用ITM_SendChar()来实现发送ITM信息
因为寄存器版本中没有ITM_SendChar()的实现包含, 或人家的工程就包含了必要的寄存器定义。
这样,keil官方必须给出一个通用的例子或给出不同库的ITM例子.

#define ITM_Port8(n)    (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n)   (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n)   (*((volatile unsigned long *)(0xE0000000+4*n)))#define DEMCR           (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA          0x01000000int fputc(int ch, FILE* f)
{// ITM_SendChar 是在库函数版本中用的// return ITM_SendChar(ch); // ITM_SendChar declare on core_cm4.h// keil官方给的ITM例子,是在寄存器版本中用的// http://www.keil.com/support/man/docs/jlink/jlink_trace_itm_viewer.htmif (DEMCR & TRCENA) {while (ITM_Port32(0) == 0);ITM_Port8(0) = ch;}return (ch);// 如果在库函数版本用ITM, 就不能使用ITM_SendChar(STM32库实现没包含进来), 编译不过.// 所以说, keil官方给的ITM例子是通用的, 在库函数版本和寄存器版本中都能用
}int  main (void)
{printf(">> main\n");

ITM_SendChar相关推荐

  1. (转)jLink使用ITM机制实现调试stm32单片机

    ----------------------------------------------------------------------------------------------- 作者:p ...

  2. 嵌入式开发输出调试信息的几种方法(常规法及非常规法)

    这篇文章对于研发查找问题和测试都有很大帮助,在这里保存记录一下. 论语>有云:"工欲善其事,必先利其器".输出调试信息是软件开发中必不可少的调试利器,在出现bug时如果没有调 ...

  3. keil debug如何在watch直接修改变量值_printf系列教程03_SWO打印输出配置,基于Keil『Debug(printf)Viewer』...

    本文原创作者『strongerHuang』 首发于微信公众号『嵌入式专栏』,同时也更新在我的个人网站:EmbeddedDevelop 标签:printf. SWD. SWO. SWV. ITM. JL ...

  4. scanf调试_STM32调试利器之ITM

    STM32 有一个代码跟踪功能,即 ITM,这个调试功能非常强大,可以替代串口输入输出功能,而且只需要占用一根 I/O 线就可以实现.当然它的好处不仅仅体现在这里,在调试嵌入式操作系统代码时你会发现相 ...

  5. 没有串口,如何打印单片机调试信息?

    输出调试信息是嵌入式开发中必不可少的调试利器,嵌入式开发的一个特点是很多时候没有操作系统,或者没有文件系统,常规的打印log到文件的方法基本不适用. 最常用的是通过串口输出uart log,例如51单 ...

  6. 009:semihost/ITM机制浅析以及使用JLINK通过ITM调试stm32单片机(转)

    ----------------------------------------------------------------------------------------------- 作者:p ...

  7. ITM机制-不用串口也能printf

    在PC上编写过C语言的人都知道,printf可以向控制台输出,scanf可以从控制台获取输入,这里的printf/scanf都是标准库函数,利用这些函数,我们可以很方便的调试程序. printf的方式 ...

  8. STM32 使用 ITM 输出调试信息

    本文开发环境: MCU型号:STM32F103ZE IDE环境: MDK 5.27 调试器:ST-LINK 本文内容: 使用 ITM 输出调试信息 文章目录 一.ITM 简介 二.ITM 输出功能的配 ...

  9. 关于STM32仿真ITM调试那些事(STM32+JLINK+KEIL)

    在刚刚学习的STM32单片机之后,我就想知道是否可以查看单片机内部的运行参数以及运行时间,直到看到鱼鹰的文章后,我了解到了MDK的仿真不止有断点和变量窗口,原来有很多功能. ITM调试机制 这是一种新 ...

最新文章

  1. Xilinx Select IO的介绍
  2. python怎么加载图片-如何用python获取图像
  3. muduo之LogFile
  4. php 处理html,PHP解析HTML代码
  5. 这些解决 Bug 的套路,你都会了不?
  6. LeetCode 326. Power of Three
  7. 如何修改mysql物理文件存放地址_如何防封号物理地址和网络地址修改攻略
  8. 威马汽车CEO沈晖:汽车“报复性”消费不现实
  9. JS -------------------设置弹出框位置屏幕的中间
  10. AcWing 1934. 贝茜放慢脚步(二路归并)
  11. android camera API1调用camera HAL3流程学习总结
  12. 我的世界android制作教程,《我的世界手机版》怎么制作mod制作JS教程图文攻略
  13. Redhat开机丢失引导
  14. 如何把word ppt 思维导图这类文件转化为高清晰度的图片(要干货只看粗体黑字)
  15. 软件测试实例:登录功能怎么设计测试用例
  16. Emulator: Process finished with exit code -1073741515 (0xC0000135)错误
  17. 信安知识竞赛培训笔记
  18. 小目标检测算法SNIPER—— SNIP的实战版本 (目标检测)(two-stage)(深度学习)(Arvix 2018)
  19. Matlab语句:rmoutliers(检测并删除数据中的离群值)
  20. 查看OracleVMVirtualBox虚拟机的ip地址

热门文章

  1. 遇到类似问题不急手机维修知识与技巧
  2. js实现520倒计时
  3. 淘票票sign----js(5: 继续淘票票--sign 生成完成)
  4. 51单片机下载完程序后不亮_为什么要学习单片机?如何开始上手学习单片机?...
  5. ScyllaDB 1.2 国内安装更新源发布
  6. cassandra(scylladb)数据备份和还原
  7. 整理了4000字的Google数据可视化指南!
  8. 史上最详细的自动驾驶汽车技术介绍【硬件+软件】
  9. java olap oracle_【案例】Oracle数据库升级OLAP组件异常 删除OLAP组件
  10. 有限责任公司章程(中英文版)