STM32-仿真调试时的SystemInit陷阱

2019-06-14来源: eefocus关键字:STM32  仿真调试  SystemInit陷阱

我在开始STM32的仿真调试时,遇到一个问题,就是调试时程序一直停在SystemInit()中的等待晶振中,怎么也出不来。


SystemInit()前面部分的代码,都能走过,就是在执行到最后一个函数时出问题了。

最后一个函数是:SetSysClock(); 

执行到下面这个循环之后,出不来了:

  /* 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));


这里,我就有疑问了:

1,我希望的是直接进main函数,那么,这个SystemInit()函数是从哪里来的?

2,为什么会进入死循环?


我全工程搜索“SystemInit”,发现在startup_stm32f0xx.s中有这样的代码:

        IMPORT  __main

        IMPORT  SystemInit  

                 LDR     R0, =SystemInit

                 BLX     R0

                 LDR     R0, =__main

                 BX      R0

                 ENDP

看来,系统是先执行SystemInit,然后才执行main的啊。


接下来是第二个问题,为什么进入死循环?

看看注释:/* Wait till HSE is ready and if Time out is reached exit */

等待HSE准备就绪且超时时间到达。超时时间且不去管它,这个HSE是什么?


HSE(High Speed External Clock signal),高速外部时钟信号,是接外部时钟源的。

相应的还有HSI(High Speed Internal Clock signal),高速内部时钟信号,是stm32芯片自带的。


看到这个概念,我就明白问题所在了:是我用的板子,没有接外部晶振啊!

所以,等待HSE准备就绪,这是永远不能达成的条件啊。

所以,这里需要修改一下,不再等待HSE了,其实是不使用HSE了,而是修改为使用HSI。


当我准备修改文件的时候,发现了一个问题,我居然修改不了这个文件!

敲了字母,它不出现在代码中!?

上网一查,原来是system_stm32f0xx.c这个文件是只读的。

好吧,从windows的文件夹中找到文件,查看属性,

见下图:


去掉“只读”即可。



不依赖于HSE,使用HSI,我修改后的代码如下:


/**

  * @brief  Configures the System clock frequency, 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)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  

  /* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/

//  /* 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));


    

//    RCC_HSEConfig(RCC_HSE_OFF);//外部晶振关闭!

    RCC->CR |= ((uint32_t)RCC_CR_HSION);//使用内部晶振

    

    

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)

  {

    HSEStatus = (uint32_t)0x01;

  }

  else

  {

    HSEStatus = (uint32_t)0x00;

  }  


  if (HSEStatus == (uint32_t)0x01)

  {

    /* Enable Prefetch Buffer and set Flash Latency */

    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;

 

    /* HCLK = SYSCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

      

    /* PCLK = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;


    /* PLL configuration = HSE * 6 = 48 MHz */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);

            

    /* Enable PLL */

    RCC->CR |= RCC_CR_PLLON;


    /* Wait till PLL is ready */

    while((RCC->CR & RCC_CR_PLLRDY) == 0)

    {

    }


    /* Select PLL as system clock source */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    


    /* Wait till PLL is used as system clock source */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)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 */

        

          //设置系统时钟8MHz

                RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);

                while(0x00 != RCC_GetSYSCLKSource());//等待设置成功       8--PLL  4--HSE   0--

HSI


                RCC_HCLKConfig(RCC_SYSCLK_Div1);//HCLK 8MHz

                RCC_PCLKConfig(RCC_HCLK_Div1);//PLCK 8MHz

        

                RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_SYSCFG,ENABLE);

                RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_GPIOB,ENABLE);    

        

                RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);//ADC1时钟频率 2MHz

  }  

    

}


这样修改之后,再进入在线调试,果然走过了SystemInit(),然后进入了main()。

这样,就解决了在线调试总是进不来main()的问题了。


不过,我还是有个疑问:为什么,这样的代码,在调试时有问题,而在全速运行的时候就没有问题呢?


再次仔细查看这段代码:

  do

  {

    HSEStatus = RCC->CR & RCC_CR_HSERDY;

    StartUpCounter++;  

  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

其实并不是一个死循环,跳出的条件有两个:HSE准备好了,或者超时。

由于我的板子没有接外接晶振,第一个条件是不能达到的,那么,第二个条件其实是可以达到的啊,为什么我会以为是个死循环呢?


让我们来看看 HSE_STARTUP_TIMEOUT 是个什么值吧:


查看定义,是这样的:

#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500) /*!< Time out for HSE start up */


其实,不是死循环,只是循环次数值太大(1280=0x500),单步调试,不能点击走这么多的循环次数(另外,在这里,想进行断点执行跳过循环也不管用,不清楚是什么原因,是因为还没有到执行到main()吗?若有知道原因的高手,请指点,谢谢!)。


这样,我就考虑到了有几个办法解决这个问题了:


1,改小HSE_STARTUP_TIMEOUT,例如:1        

    评估:危险!我们尽量不要去修改厂家提供的宏。万一以后需要用HSE呢?另外还要考虑这个值是否有其它地方的调用。

2,调试时,修改StartUpCounter变量值,为4ff,则很快达到0x500,跳出循环。

    评估:可行,但是比较麻烦,每次运行都需要修改一次。

    若不想修改任何代码,这倒也是一个选择。

3,像前文说的那样,修改SystemInit,默认选择HSI。

    评估:可行。不过,代码修改量比较大。或许我们还有更好的选择?

4,修改startup_stm32f0xx.s,不执行SystemInit了

如下修改:

        IMPORT  __main

;        IMPORT  SystemInit  

;                 LDR     R0, =SystemInit

;                 BLX     R0

                 LDR     R0, =__main

                 BX      R0

                 ENDP

    实测,可行。修改时注意,这个文件也是只读的,需要去掉只读属性后才能修改代码。

    改动量较小。不过风险可不小,因为我还不能准确评估去掉 SystemInit 那部分代码的影响。

    可行的原因分析:系统复位后,HSI振荡器默认被选为系统时钟。

5,去掉SystemIit() 中对 SetSysClock() 的调用;

    实测,可行。

    改动最较小,只是把那句调用代码注释掉即可。且通过分析SetSysClock()函数,可以知道,若没有启用HSE,则相当于没有执行任何有效操作。可以说,对于使用HSI的情况,逻辑上没有任何差别。

    

最终,我采用了第5种修改方法,调试运行,一切正常。


关键字:STM32  仿真调试  SystemInit陷阱

编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic464654.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32-使用定时器做延时函数时遇到的坑
下一篇:STM32-基于汇编来分析延时

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

集性能、紧凑、灵活、能效于一身,ST8引脚STM32微控制器问市

意法半导体8引脚STM32微控制器(MCU)现已上市,紧凑、经济的封装让简单的嵌入式开发项目也能利用32位MCU的性能和灵活性。 新推出的四款STM32G0 微控制器是8引脚经济性和32位性能的完美组合,在市场绝无仅有,基于59 DMIPS的 64MHzArm®Cortex®-M0 + CPU,片上高达8KB的RAM和32KB闪存,高性能外设包括2.5Msps ADC、高分辨率定时器和高速SPI接口。灵活的I/O引脚映射和MCU内部功能,让设计人员轻松升级终端产品功能,不会牺牲电路板空间或物料清单成本。高稳定内部振荡器,在宽温度和宽压范围内精度达到±1%,为开发者节省了外部时钟元件。 
发表于 2019-09-20
集性能、紧凑、灵活、能效于一身,ST8引脚STM32微控制器问市

6.STM32外设函数分类

发表于 2019-09-20
6.STM32外设函数分类

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved