• STM32 仿真 SystemInit


    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种修改方法,调试运行,一切正常。
    ————————————————
    版权声明:本文为CSDN博主「lintax」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lintax/article/details/83242525

    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芯片自带的。

    是DEBUG里面的设置有问题,调用的DLL错误,在Dialogue DLL中填DARMSTM.DLL, Parameter 填-pSTM32F103ZE(根据你板子的型号决定) 仿真stm的那一款就对应填那个参数,这是仿真STM32的动态链接,具体为什么这样还等大虾来解决;
    ————————————————
    版权声明:本文为CSDN博主「@liyanglong」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/linhao__/article/details/107153170

  • 相关阅读:
    'telnet' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
    Linux学习_009_VMware12.0 Pro 中安装 CentOS 6.8_超详解 + 高清大图
    Linux学习_008_Linux下的JDK和OpenJDK有什么具体的区别
    实战CentOS系统部署Hadoop集群服务
    开源多线程性能测试工具-sysbench
    Hadoop集群中Hbase的介绍、安装、使用
    Docker基础技术:Linux Namespace(上)
    带你走进rsync的世界
    5分钟教你Windows 10中将“运行”固定到开始菜单
    使用 Github Pages 发布你的项目文档
  • 原文地址:https://www.cnblogs.com/2eggs/p/13304327.html
Copyright © 2020-2023  润新知