ITM_SendChar

试验原因

以前在用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 Character

    The 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 startup
       files 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 = 84000000
  SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
  
  /* Infinite loop */
  while (1)
  {
    Delay(1000); // delay ms
    printf("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
    │      
    └─src
            misc.c
            stm32f4xx_adc.c
            stm32f4xx_can.c
            stm32f4xx_cec.c
            stm32f4xx_crc.c
            stm32f4xx_cryp.c
            stm32f4xx_cryp_aes.c
            stm32f4xx_cryp_des.c
            stm32f4xx_cryp_tdes.c
            stm32f4xx_dac.c
            stm32f4xx_dbgmcu.c
            stm32f4xx_dcmi.c
            stm32f4xx_dfsdm.c
            stm32f4xx_dma.c
            stm32f4xx_dma2d.c
            stm32f4xx_dsi.c
            stm32f4xx_exti.c
            stm32f4xx_flash.c
            stm32f4xx_flash_ramfunc.c
            stm32f4xx_fmc.c
            stm32f4xx_fmpi2c.c
            stm32f4xx_fsmc.c
            stm32f4xx_gpio.c
            stm32f4xx_hash.c
            stm32f4xx_hash_md5.c
            stm32f4xx_hash_sha1.c
            stm32f4xx_i2c.c
            stm32f4xx_iwdg.c
            stm32f4xx_lptim.c
            stm32f4xx_ltdc.c
            stm32f4xx_pwr.c
            stm32f4xx_qspi.c
            stm32f4xx_rcc.c
            stm32f4xx_rng.c
            stm32f4xx_rtc.c
            stm32f4xx_sai.c
            stm32f4xx_sdio.c
            stm32f4xx_spdifrx.c
            stm32f4xx_spi.c
            stm32f4xx_syscfg.c
            stm32f4xx_tim.c
            stm32f4xx_usart.c
            stm32f4xx_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 startup
       files 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 = 84000000
  SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
  
  /* Infinite loop */
  while (1)
  {
    Delay(1000); // delay ms
    printf("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, you
        can 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 - __Vectors

                AREA    |.text|, CODE, READONLY

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit ; 系统初始化函数,里面初始化了系统时钟
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  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_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->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 clock
         configuration. 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 clock
         configuration. 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          0x01000000

int 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.htm
	if (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");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值