历史上的今天
返回首页

历史上的今天

今天是:2025年03月24日(星期一)

正在发生

2019年03月24日 | STM32-仿真调试时的SystemInit陷阱

2019-03-24 来源: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种修改方法,调试运行,一切正常。


推荐阅读

史海拾趣

南京国博公司的发展小趣事

国博电子的前身可以追溯到2000年成立的上海华信集成电路有限公司,起初专注于射频芯片的研发与生产。随着技术的积累和市场的拓展,公司逐步从单一的射频芯片企业成长为覆盖射频芯片、模块、组件的完整产业平台。这一跨越不仅体现了公司在技术上的深厚积累,也反映了其对市场需求的敏锐洞察和快速响应能力。通过不断的技术创新和产品研发,国博电子成功在无线通信、移动通信等领域占据了一席之地。

创世(CS)公司的发展小趣事

创世公司(CS)的创立源于对未来技术趋势的敏锐洞察。在5G、人工智能、物联网等行业还未广泛崛起的初期,创世公司就预见到这些技术将引领未来电子行业的发展。基于这种战略眼光,创世公司决定专注于SD NAND存储产品的研发和生产。这一决策不仅为公司的后续发展奠定了坚实的基础,也展示了创始团队对未来技术趋势的坚定信心。

Dynawave Incorporated公司的发展小趣事

Dynawave Incorporated的创始人李明,是一位在电子行业有着丰富经验的工程师。他深知随着科技的发展,无线通信技术将成为未来发展的重要方向。因此,李明带领一支技术团队,夜以继日地研发新型无线通信技术。经过数月的努力,他们成功开发出了一种具有高效能、低能耗特点的无线传输技术,这一技术为Dynawave在行业中赢得了初步声誉。

EPIC公司的发展小趣事

近年来,随着元宇宙概念的兴起,Epic Games也开始在这一领域进行布局。公司首席执行官Tim Sweeney对元宇宙的发展潜力持乐观态度,并认为这将是未来游戏和社交领域的重要发展方向。为了实现这一愿景,Epic Games不仅在技术上进行了大量投入和研发,还与多个合作伙伴共同推动元宇宙生态的建设和发展。这些举措使得Epic Games在元宇宙领域取得了显著的进展,并有望在未来成为该领域的领军企业之一。

Display Engineering Services公司的发展小趣事

2006年,Epic Games公布了基于Xbox 360游戏平台的《战争机器》。这款游戏以其出色的画面效果、紧张刺激的战斗场景和深入人心的故事情节,迅速在市场上取得了成功。它的畅销不仅进一步巩固了Epic Games在游戏开发领域的地位,也证明了虚幻引擎在开发高质量游戏方面的强大能力。

百蓉(ECE)公司的发展小趣事

随着公司的发展,百蓉公司意识到技术创新是保持竞争力的关键。他们决定投入更多资源在研发上,特别是集成电路设计领域。经过几年的努力,百蓉成功开发出了一系列高效能、低功耗的集成电路芯片,广泛应用于消费电子、汽车电子和工业控制等领域。这些芯片在市场上大受欢迎,进一步提升了百蓉在电子行业中的地位。

问答坊 | AI 解惑

使DC/DC变换器限流特性线性化的热敏电阻器网络

核心器件: MAX1714 最近推出的各种集成式降压   DC/DC变换器均已采取对外接低侧MOSFET同步整流器的电压降采样的方法,无需高侧电流检测电阻器。这种拓扑节省了检测电阻器的成本和印制电路板的空间,也适当提高了电路效率。但是,MOS ...…

查看全部问答>

电子系统设计基本知识

本文有模拟电路、数字电路、单片机电路、ARM硬件、ARM编程等基础知识,里面还有电阻、电容、半导体二级管三极管等元器件的介绍,还有电源电路、电路设计、通信系统等。欢迎想学电子基础知识的人下载。…

查看全部问答>

大家A有整体方案了没有

本帖最后由 paulhyde 于 2014-9-15 09:04 编辑 大家A有整体方案了没有  …

查看全部问答>

DO-254中的高设计可靠性的逻辑综合(二)

书接上文 https://bbs.eeworld.com.cn/thread-92283-1-1.html 逻辑综合 如图中所示,逻辑综合是PLD,FPGA,ASIC设计的中心环节。在数十年中,逻辑综合工具把高级语言转换为门级电路,使设计师能够在更高的抽象层次上进行硬件设计,极大的提高 ...…

查看全部问答>

防水鞋套

现在已经很少有人因为下雨而穿雨靴了,但是真碰上雨下大的时候,普通的鞋子还真是不堪一击,很快就会被湿透。这个时候,你或许需要这样一款独特的“雨衣”。它并不是给身体挡雨的,而是用来保护鞋子的。这其实就是一双防水鞋套,可以跟雨衣和雨伞放 ...…

查看全部问答>

单片机实现液晶显示的开发方案

我们的产品希望用液晶屏显示,不知各位高人有什么比较好的实现方法吗?(接口可以是232或者485)…

查看全部问答>

三星S3C241O的中断问题

我最近在学华恒ARM9,用的是三星S3C2410当做到中断这个问题的时候,遇到了问题,还请各位大虾帮忙 问题如下: 1、不管我把中断置一还是置零都没看到区别,和芯片资料有出入,为什么会这样 2、我把中断待决寄存器和源待决寄存器的值读出来,发现 ...…

查看全部问答>

请问哪里有无线协议的详细文档下载?

刚学GPRS开发,想找些无线通讯协议看看,google了一下,没找到,所以想请教一下,哪里有这一类的完整文档下载,谢谢!…

查看全部问答>

求助。。。。

用iar for msp430怎么下载程序到430里? 求具体过程,最好能有×××××× 还有就是怎么看程序是否在下载?单片机是否在运行? 本人初学,只有一点51的基础,还请各位多多指教…

查看全部问答>

请各位朋友来帮小弟看看这段代码

代码如下: /  UART初始化 void uartInit(void) {     SysCtlPeriEnable(SYSCTL_PERIPH_UART1);                  //  使能UART模块   &nbs ...…

查看全部问答>