发帖数

53

原创数

53

关注者

11

阅读数

9154

点赞数

1

黄忠

  • 什么是Map文件,它有什么用?

         大家好!我是张飞实战电子黄忠老师;前文章《不要再找啦,关于Cortex-Mx芯片的启动没有比这里更清楚啦》STM32单片机的启动流程以及main函数的执行做了一个详细的分析,今天我们MDK编译、链接后生成的map文件简单分析一下,加深对链接器、嵌入式系统可执行映像特点的了解。

    什么是map文件?简单的说map文件是通过编译器编译之后,集众多信息为一身的一种映射文件。很多工程师在遇到内存越界溢出情况分析map文件。通过map文件可以知道函数大小,入口地址等一些重要信息。最直观的的在Keil编译之后,编译窗口会显示类似如下一段信息:Program Size这一段提示信息汇总了程序和数据的信息,这些信息是单个模块汇总而成,在map文件里有详细列表。

    图片1.png 

    1.Section Cross References,主要是各个源文件生成的模块之间相互引用的关系。

    图片2.png
    上面这句话,main.omain.c生成的目标文件模块,start.ostart.s生成的目标文件模块,上面这2个含义是:用户在start.o启动代码中调用了__main.o模块中的StartProgram函数,StartProgram又调用了同文件中Led_Init函数。
     
    2.Removing Unused input sections from the image. 就是将库中没有用到的函数从可执行映像中删除掉,减小程序的体积。
    3.Image Symbol Table

    图片3.png
     

    Local Symbols 是系统内部的局部标号以及用户的一些局部标号
    图片4.png
    Global Symbols此部分描述了系统以及外部标号的所属地址、所占空间大小、所属文件等信息。
    图片5.png     

    4. Memory Map of the image映像的内存分布图片6.png
    1>.Image Entry point : 0x08000009,这个指的是复位程序RESET_Handler的地址。
    2>.Load Region LR_1 (Base: 0x08000000, Size: 0x00000044, Max:0xFFFFFFFF, ABSOLUTE),是程序的加载映像地址和长度,0x00000044=Start.0文件的大小(0x0C) + main.oLed_Init函数的大小(0x3C) + main.oStartProgram函数的大小(0x08)
    3>.Execution Region ER_RO (Base: 0x08000000, Size: 0x00000044, Max:0xFFFFFFFF, ABSOLUTE,指的是程序中的代码段和常量。
    4>.Execution Region ER_RW(Base: 0x20000000, Size: 0x00000000, Max: 0xFFFFFFFF, ABSOLUTE) 指的是可读写的全局变量和静态变量区域,因为我们现在只是一个简单的测试程序,没有变量,所以这里Size大小为0

    5>.Execution Region ER_ZI(Base: 0x20000000, Size: 0x00000000, Max: 0xFFFFFFFF, ABSOLUTE) 指的是程序中被初始化为零的变量,这里Size大小为0的原因同上。

    6>6.Image component sizes 这是指各个模块的大小信息

    图片7.png
    Total RO  Size (Code + RO Data)                680.07kB)
    Total RW  Size (RW Data + ZI Data)              68 (   0.00kB)
    Total ROM Size (Code + RO Data + RW Data)      68 (  0.07kB)

    图片8.png
    由于我们测试程序总没有定义一些变量,只是简单的操作了3个寄存器,所以RW Data + Zi Data0,其余全是代码指令信息,共680x44)个字节,程序总大小为68/10241KB = 1024个字节), 约0.07Kb

    至此我们已经解开了Map文件的神秘面纱,文件包含的信息全部分析完成,从文件中我们可以得出一些有用的信息,便于我们在分析调试代码的时候使用,当然Map配合链接文件(.sct)可能会看到直接的效果,后期有机会我们聊一聊链接文件,谢谢大家。




    收藏 0 回复 0 浏览 1218
  • 单片机的几种复位电路

    大家好,我是张飞实战电子黄忠老师;在单片机的使用中,经常会接触到复位电路,它是单片机最小系统重要的一个构成部分。同样它也是非常重要的一部分。

    复位就是让单片机从初始化状态开始重新运行,即程序从头开始执行。复位电路设计的好坏,直接影响整个系统是否稳定可靠。复位电路与单片机的RESET/NRST引脚相连,拿STM32系列单片机举例,当系统正常工作时,如果RESET引脚电压低于某一阈值,则单片机进入复位状态。单片机的复位可分为低电平复位和高电平复位,这是由厂家决定的,区分的方式可以看数据手册,手册中的复位章节会写清楚是什么电平复位。单片机的复位可以分为:上电复位、掉电复位、软件复位、外部手动复位等。

    上电复位:单片机每次上电都会给RESET脚一个复位信号,让单片机从一个固定的相同状态重新开始工作;

    掉电复位:单片机复位引脚电压低于某一阈值电位时,单片机会进入复位状态。

    软件复位:程序员执行某一特定的复位指令,来使单片机进行复位,或者当程序在一定时间失去响应的情况下通过看门狗电路控制单片机进行复位。

    外部手动复位可以通过一个复位按键让死机或跑飞的程序重新运行。

        图片15.png图片15.png

    下面我们一起看一下常见的几种复位电路。

    图片16.png     图片17.png

                1                                                                                                                                                 2

    1是最常见的低电平上电复位原理图,我们来分析这个过程,上电前电容两端电压为0。上电后,电流从3.3V流经电阻、电容到地,由于电容两端电压不能突变,所以上电瞬间RESET脚上电压也为零,并保持一小段时间低电平,这段时间触发单片机复位;随着时间推移,电容两端电压太高超过某一阈值电位,复位完成。这个电阻、电容的取值大小影响到复位引脚电平的上升时间(电容的充电时间)。

    2 手动按键复位原理图,手动按钮复位在GND和RESET之间接一个按钮。当人为按下按钮时, RESET脚就会被GND拉为低电平,使单片机进入复位状态,如果手不松掉,那么会一直处于复位状态,直至手松掉之后,复位引脚电平恢复。下图位ST单片机内部的复位波形,上电的时候VDD大于Vpor并持续一定的时间,单片机脱离复位状态,掉电的时候Vdd电压低于Vpdr电压,单片机进行复位。

                 图片19.png

    软件复位也分两种,我们可以使用复位指令,直接使单片机进行复位,另外一种使用单片机内置看门狗,配置启动看门狗,在主循环程序中每隔一定地时间刷新看门狗,俗称喂狗。如果一定的时间没有喂狗,可以认为程序跑飞,则看门狗模块会复位单片机,内置看门狗又分窗口看门狗和独立看门狗,区别如下:

    时钟不同

    1、独立看门狗:独立看门狗使用的是内部专门的 40Khz低速时钟,不需要使能时钟操作。

    2、窗口看门狗:窗口看门狗使用的是 PCLK1的时钟,使用前需要先使能时钟。

    中断不同

    1、独立看门狗:独立看门狗没有中断,超时直接复位。

    2、窗口看门狗:窗口看门狗可以在中断中做复位前的函数操作,比如报错一些数据等。

    使用场景不同

    1、独立看门狗:独立看门狗一般用于避免程序跑飞或者死循环。

    2、窗口看门狗:窗口看门狗避免程序不安预定逻辑执行,比如先于理想环境完成,或者后于极限时间超时。

    当然复位衍生出来的电路形态可能不止上述的两种,但是基本上都是围绕上述的电路进行变换,最后强调一点,RESET的走线越短越好,复位电路一定要尽可能靠近MCU, 因为复位电路到单片机这一段的走线,可能会引入其他外界因素的干扰,是单片机处于不稳定的状态。关于复位的内容就跟大家分享到这里,大家有没有遇到过关于一些复位引起的问题呢?


    收藏 0 回复 0 浏览 593
  • 图解边沿对齐,中心对齐PWM....

    大家好,我是张飞实战电子黄忠老师,今天我们来讲解下图解边沿对齐,中心对齐PWM...

    在说边沿对齐,中心对齐前,我们先来段铺垫,PWM又称脉冲宽度调制,我们通过调节脉冲的占空比,我们可以控制电压的大小(比如我们满占空比时电压为12V,我们可以通过调节占空比让电压变为7V5V甚至变为0V,实现输出电压可控)

    调节占空比后,输出电压怎么就变化了呢?可以用等效面积法来解释,例如在1ms周期里,满占空比时输出电压为12V50%占空比时(即高低电平各占时间为0.5ms)高电平在整个周期的面积只有原来的1/2了,此时输出电压就等效为12*1/2=6V,那么通过调节不同的占空比,也就实现了输出电压调节。如图:

    图片18.png 

    STM32中是怎么生成PWM波的呢?时钟是芯片的心脏,没有时钟,芯片就是一块“废物”,有了时钟,芯片才能有条不紊的工作,那时钟跟我们要讲的PWM有什么关系呢?请看下图,STM32内部的定时器框图,看看它是如何生成PWM的。

    图片19.png 

    方框内部的CNT Counter计数器会根据输入的时钟沿跳变来进行递加/减,时钟的频率决定了计数器递加/减的频率,这个计数器的值同时会和Auto-reload register(控制周期)、Capture/Compare x register(控制占空比)进行比较,当与控制占空比的寄存器值发生匹配时则控制输出引脚TIMx_CHx发生电平反转,当与控制周期寄存器值发生匹配时,周期结束,引脚电平置位,再次重复如上动作,就在引脚上输出了变化不同的电平,这个就是我们需要的PWM

    这个定时器模块可以根据软件编程设置出不同的PWM模式,定时器内部CNT Counter可被编程为向上、向下、向上向下运行,我们说的边沿对齐,和中心对齐就要从这个计数方式上切入,下面我们先来看三种不同的计数方式。

    1.CNT被设置为向上计数时,计数器从0递增向上计数到自动重载值(Auto-reload register),然后计数器又回到0,重新开始。

    图片20.png图片21.png 

    2.CNT被设置向下计数时,计数器从自动重载值递减向下计数,计数到0,计数器又回到重载值,重新开始。

    图片22.png图片23.png 

    3.CNT被设置向上向下计数时,计数器从0递增向上计数到自动重载值,然后计数器从自动重载值递减向下计数,计数到0然后又开始递增向上计数。

    图片24.png图片25.png 

    那这三种模式和2PWM又是什么关系呢?PWM是怎么从引脚上输出的呢?请看下图:

    1.向上/下计数模式PWM生成(只展示出了向上计数,向下计数同理):

    图片28.png图片29.png 

    2.向上向下计数模式PWM生成:

    图片26.png图片27.png 

    上文中提到的向上计数/向下计数,这两种生成PWM的方式,我们通常称为边沿对齐PWM;既向上又向下这种生成PWM的方式,我们称为中心对齐PWM当然,发生匹配的时候引脚电平如何变化,是变高还是变低,这个可以通过软件编程来设置。

    通过PWM调节输出电压,比如可以控制做呼吸灯,也可以实现电机的调速,不同的调速算法,会用到不同的PWM等等。


    收藏 0 回复 0 浏览 447
  • 烧写算法FLM文件如何实现呢?

    大家好!我是张飞实战电子黄忠老师!今天给大家分享烧写算法FLM文件如何实现的

    当我们在开发过程中用到MDK下载程序的时候可能都知道,在下载程序之前需要都在Debug设置的Flash Download子选项卡选择编程算法。大多数时候,我们只要安装了芯片包之后,就可以直接得到对应的编程算法,并不需要我们去修改它。但是,当我们是一个芯片包的开发者,或者我们有独特的下载需求(比如在程序里加入一些校验信息),这个时候我们就需要去了解它了!

    image.png

    编程算法其实就是一段程序,主要功能就是擦除相应的内存块,并将我们的程序写入到相应的内存区域上去。在点击下载按钮的时候,这段程序会被先下载到RAM上(RAM for Algorithm上的设置),然后才会通过它,将用户写的程序写入到指定的内存区域内。


    怎么去实现一个自己的编程算法?首先我们找到自己的MDK的安装路径,进入到ARMFlash文件夹下。这里有个编程算法的工程模板,复制这个工程到你的工程文件夹下,重命名你自己的想要的名字。

    image.png

    打开工程,里面主要有两个文件 FlashPrg.c 和 FlashDev.c:

    image.png

    FlashDev.c主要实现了一个设备相关的结构体(根据自己的Flash情况去实现)

    image.png

    比如STM32F103实现如下:

    image.png

    FlashPrg.c实现了几个Flash编程相关的函数:

    image.png

    根据自己的需要去实现,从上面我们就可以看出,下载程序的时候就是调用了上面的几个函数,跟我们自己写Flash没有太大的区别。那么程序都编程完成之后,怎么生成FLM文件呢?我们先编译工程,完成之后你去看你的工程输出目录,这个时候你就已经可以找到FLM后缀的文件了,这个就是我们自己的编程算法,把它复制到 ' MDK安装路径 'ARMFlash下面就可以了,在选项卡里选择我们自己的编程算法就可以使用了。但是为什么我们自己的工程就生成不了FLM文件呢?工程中的.axf文件跟.FLM文件是一样的,把.axf后缀改为.FLM即可。


    怎么样?心动嘛?赶快去写一个文件试试吧!



    收藏 0 回复 0 浏览 428
  • 你知道USB的NRZI编码吗?

     大家好!我是张飞实战电子黄忠老师!今天给大家分享USB的NRZI编码。

    标准的USB连接线使用4芯电缆:5V电源线、差分数据线D-、差分数据线D+、以及GNDUSB协议规定,设备在未配置前,可以从Vbus上最多获取100mA的电流,在配置之后,最多可以从Vbus上获取500mA的电流)。

    USB OTG中,又增加了一种MINI USB接头,使用的是5根线,比标准的USB多了一条身份识别(ID)线,USB使用的是差分传输模式,因而有2条数据线,分别是D+D-。在USB的低速和全速模式中,采用的是电压传输模式;而在高速模式下,则是用电流传输模式。

    USB2.0支持3中传输模式,低速模式(1.5Mb/s)、全速模式(12Mb/s)、高速模式(480Mb/s)、传输速度是指总线上每秒传输的位数,实际的数据速率要比这个速度低一些,因为还有很多的协议开销。

    USB使用的是NRZI编编码方式,NRZI编码是一种映射一个二进制信号的方法,以便通过USB线缆传输该信号,在该编码方案中,当数据为0时,电平翻转,数据为1时,电平不翻转。如下图所示。顶部是将要通过 USB 传送的数据。底部是编码的 NRZI 数据。

    image.png

    为了防止出现长时间电平不变化(这样不利于时钟信号的提取),在发送数据前要经过位填充处理。通过在 6 个连续的逻辑 1 后面插入一个逻辑 0 可以实现位填充。位填充是为了通过保持锁相环(PLL)对 USB 硬件进行同步化。如果该数据内有太多的逻辑 1,那么 NRZI 编码流中将没有足够用于实现同步化的转换。USB 硬件上的接收器会自动检测额外位,并忽略它。该额外位填充是引起 USB 上的额外开销的原因。下图显示的是一个带有位填充的NRZI 数据的示例。请注意,“Data to Send”(将要发送的数据)流为 8 个逻辑 1。在该编码数据中,在第六个逻辑1 后面插入了一个逻辑 0。这样,第七和第八个逻辑 1 将位于逻辑 0

    image.png

    经过位填充后的数据,由串行接口引擎SIE将数据串行化和NRZI编码后,发送到USB的差分数据线上。在接收端,刚好是一个相反的过程。接收端采样数据线,由SIE将数据并行化(反串行化),然后去掉条重围(反位填充),恢复处原来的数据。

    通常我们使用现成的USB芯片,如位填充、串行化、反串行化、CRC校验等处理过程,芯片内部的硬件已经帮我们做好了,因此可以不用关心这些细节。但是往往知道这些细节,在处理问题的时候,非常有用。你会了吗?


    收藏 0 回复 0 浏览 335
×
黄忠