• stm32_iap记录!


    STM32——IAP

    前几天派发紧急任务,因为程序BUG太多,每次修改都要拆机,车间受不了了,MMP,尽快完成STM32在线升级。

    选用ST官方的stm32f4_iap_using_usart,软件用的ExtraPuTTY,文件协议为Ymodem。

    Ymodem 协议简介:

    1. Ymodem通信数据包的格式
      数据包的格式是: 类型 + 序号 + 序号反码 + 数据区(128或1024) + 校验和(两字节)
    2. Ymodem通信数据包的序号增长规律
      数据包的序号从00开始直到255,然后又从00开始。不大于255K字节的数据包,所有发送数据包的
      序号是唯一的。大于255K的数据包,按照1K字节分包,第一个数据包序号是1,第二个数据包的序号是2
      。。。第255个数据包的序号是255,第256个数据包的序号,又从0开始。
    3. Ymodem通信的大小数据包
      Ymodem通信有128字节和1024字节两种类型的数据包,数据包开头有3字节(类型+ 序号+序号反码),
      末尾crc16是2个字节,所以可以说有133字节的小数据包和1029字节的大数据包。
    • 133字节数据包的特点、字符填充规则
      以SOH(0x01)开始的数据包,数据区是128字节。发送端第一个含有文件信息的数据包是3+128+2 = 133字节。
      发送最后一个数据包时,剩余数据字节数若小于128,则以0x1A填充,仍发送133字节数据包。
    • 1029字节数据包的特点、字符填充规则
      以STX(0x02)开始的数据包,数据区是1024字节。若发送的文件大于1024字节,文件信息包之后的第一个
      数据包则为1029字节,随后剩余的数据若不小于1024字节,则均以1029大数据包发送。
      4处理Ymodem通信最后一个数据包时,需要考虑的情况
      Ymodem通信按照1024字节分包,最后一个数据包的大小不会超过1024字节。编程时需要考虑以下几种情况:
      (1)数据个数等于1024字节,按1029字节发送。
      (2)数据个数小于1024字节,但大于128字节,按1029字节发送,无效数据区域以0x1A字符填充。
      (3)数据个数等于128字节,按133字节发送。
      (4)数据个数小于128字节,按133字节发送,无效数据区域以0x1A字符填充。
      二、Ymodem通信crc16计算说明:
      1 小包3 + 128 字节,大包 3 + 1024字节,末尾2字节是crc16。
      2 crc16计算从第4字节开始(不包括SOH(0x01) 序号 序号反码三字节),小包计算长度128字节,大包计算长度1024字节
      3 最后一个空包,除前三字节外全是0,末尾2个字节也是0,不用计算crc16。

    Ymodem 协议大致流程

    SENDER RECEIVER
    "sending in batch mode etc."
    C
    SOH 00 FF filename 0x00 filesize 0x00 NUL[] CRC CRC
    ACK
    STX 01 FE Data[1024] CRC CRC
    ACK
    STX n (255-n) Data[m] CPMEOF[1024-M] CRC CRC
    ACK
    ........
    EOT
    ACK
    SOH 00 FF NUL[128] CRC CRC
    ACK

    文件传输过程的开启: 
    (1)开启是由接收方开启传输,它发一个大写字母C开启传输。然后进入等待(SOH)状态,如果没有回应,就会超时退出。 
    (2)发送方开始时处于等待过程中,等待C。收到C以后,发送(SOH)数据包开始信号,发送序号(00),补码(FF),“文件名”,“空格”“文件大小”“除去序号外,补满128字节”,CRC校验两个字节。进入等待(ACK)状态。 
    (3)接收方收到以后,CRC校验满足,则发送ACK。发送方接收到ACK,又进入等待“文件传输开启”信号,即重新进入等待“C”的状态。 
    (4)前面接收方只是收到了一个文件名,限制正式开启文件传输,Ymodem支持128字节和1024字节一个数据包。128字节以(SOH)开始,1024字节以(STX)开始。接收方又发出一个“C”信号,开始准备接收文件。进入等待“SOH”或者“STX”状态。 
    (5)发送接收到“C”以后,发送数据包,(SOH)((01序号) (FE补码) (128位数据) (CRC校验),等待接收方“ACK”。 
    (6)文件发送完以后,发送方发出一个“EOT”信号,接收方也以“ACK”回应。 然后接收方会再次发出“C”开启另一次传输,若接着发送方会发出一个“全0数据包”,接收方“ACK”以后,本次通信正式结束。 
    (7)当然Ymodem相对于Xmodem改进的地方就在于传输再次开启以后,又可以发送另外一个文件,即一次传输允许发送多个文件。

    Bootloader

    因为厂里老催催催,那就怎么简单怎么来,不和上位机人员沟通,直接用超级终端发送。

    上电之前按键,进入引导程序,否则跳入应用程序。

    引导程序跳转之前,需要检测堆栈的栈顶是否合法

    /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
    if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    { 
       /* Jump to user application */
       JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
       Jump_To_Application = (pFunction) JumpAddress;
       /* Initialize user application's Stack Pointer */
       __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
       Jump_To_Application();
     }
    

    检测应用程序的头4个字节,栈顶是否合法,可以看starup_stm32f40_41xxx.s文件,

    __Vectors       DCD     __initial_sp               ; Top of Stack
                    DCD     Reset_Handler              ; Reset Handler
                    DCD     NMI_Handler                ; NMI Handler
                    DCD     HardFault_Handler          ; Hard Fault Handler
                    DCD     MemManage_Handler          ; MPU Fault Handler
                    DCD     BusFault_Handler           ; Bus Fault Handler
                    DCD     UsageFault_Handler         ; Usage Fault Handler
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     0                          ; Reserved
                    DCD     SVC_Handler                ; SVCall Handler
                    DCD     DebugMon_Handler           ; Debug Monitor Handler
                    DCD     0                          ; Reserved
                    .....
    

    中断向量表中,打头的是栈顶,只要其头四个字节是大小在0x2000 0000 - 0x 2000 2000范围内就合法,其实我stm32407vet6的ram为192k,范围应该比0x20000大,如果程序中确实用的比128K大,可以修改程序,这里比128K小,所以不理会,但是MDK中确实这么定义的。

    打开一个应用程序的bin文件,如图,头四个字节为0x20013930,在合法范围内。

    再来看看这个0x20013930怎么来的,打开这个工程的.map文件。因为stm32的栈是向下生长的,所以栈顶是最大值,看最后一行,0x0x20013530+0x00000400 = 0x20013930。或者Base: 0x20000000, +Size: 0x00013930

    Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x00013930, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x0000006c])
    
        Base Addr    Size         Type   Attr      Idx    E Section Name        Object
    
        0x20000000   0x00000009   Data   RW          497    .data               display.o
        0x20000009   0x00000003   PAD
        0x2000000c   0x00000036   Data   RW          688    .data               keyboard.o
        0x20000042   0x00000001   Data   RW          690    .data               keyboard.o
        .....
        0x20013330   0x00000200   Zero   RW         1578    HEAP            startup_stm32f40_41xxx.o
        0x20013530   0x00000400   Zero   RW         1577    STACK           startup_stm32f40_41xxx.o
    

    还有,怎么确定这个bin文件需要占多大flash?还是map文件

    ==============================================================================
    
        Total RO  Size (Code + RO Data)               123564 ( 120.67kB)
        Total RW  Size (RW Data + ZI Data)             80176 (  78.30kB)
        Total ROM Size (Code + RO Data + RW Data)     123672 ( 120.77kB)
    
    ==============================================================================
    

    栈顶检测合法后,进行跳转,JumpAddress = (__IO uint32_t) (APPLICATION_ADDRESS + 4);。加4,是因为头四个字节存的是栈顶地址。

    crc校验

    因为官方的串口IAP中在传输的时候不进行校验,只对编号的是否补码检测一下,个人觉得不靠谱,所以就自己加了校验,校验函数如下。

    uint16_t Y_Modem_CRC(uint8_t * buf, uint16_t len)
    {
        uint16_t chsum;
        uint16_t stat;
        uint16_t i;
        uint8_t * in_ptr;
       
        //指向要计算的crC缓冲区开头
        in_ptr = buf;
        chsum = 0;
        for (stat = len ; stat > 0; stat--) //len是所要计算的长度
        {
            chsum = chsum^(uint16_t)(*in_ptr++) << 8;
            for (i=8; i!=0; i--) {
                if (chsum & 0x8000){
                    chsum = chsum << 1 ^ 0x1021;
                } else {
                    chsum = chsum << 1;
                }
            }
        }
        return chsum;
    }
    ...
      这里只校验数据包里的内容,如果出错,则置Error标志为1,在传输完成时,提示出错,且不可跳转。
         memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
         ramsource = (uint32_t)buf;
    	if(packet_data[0] == STX)
    	{
    		CRC16_Cal = Y_Modem_CRC(&packet_data[3],1024);
    		CRC16_Tmp  = packet_data[1027];
    		CRC16_Tmp  = CRC16_Tmp<<8;
    		CRC16_Tmp |= packet_data[1028];
    		if(CRC16_Tmp != CRC16_Cal)
    		{
    			Error = 1;
    		}
        }
    

    Application Program设置

    生成bin文件

    E:Program FilesMDK5.14ARMARMCCinfromelf.exe --bin -o E:WorkSS3325J_Frontpanel_APP OBJSS3325J_Frontpanel.bin E:WorkSS3325J_Frontpanel_APPOBJSS3325J_Frontpanel.axf
    

    设置程序起始地址


    stm32f407VET6为512K,分别为16K 16K 16K 16K 64K 128K 128K 128K

    把这个应用才程序放到第5扇区,第六第七放用户数据,第1和第2放一些日志信息。所以IROM1起始放到0x8020000,SIZE相应为384K。

    设定偏移

    可以用一个函数,NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset),也可以直接在system_stm32f4xx.c中修改VECT_TAB_OFFSET,

    #define VECT_TAB_OFFSET  0x20000
    

    烧写

    打开ExtraPuTTy超级终端,选择”Serial”,在”Serial line”中输入记录的CH340对应的端口号,”Speed”改为115200,可以在”Save Sessions”中,输入记录名,点击Save后,可保存此配置。点击Open。

    1. 点击Open后,继续配置,点击Session->Change Settings…,在弹出的窗口中点击左侧栏中最下方的”Serial”,配置如图,点击应用

    2. 在电源关机状态下次啊,按住编码器按钮,打开电源,电源进入引导升级程序,此时超级终端打印如图。

    3. 鼠标点击超级终端,按下数字键盘”1”,超级终端继续打印如下图,并且一直打印”C”此时电源正在等待超级终端发送程序。

    4. 点击超级终端菜单栏中的Files Transfer->Ymodem->send,选择SK3325J_Frontelpanel.bin,即可发送升级程序,发送过程如图。

    5. 发送完成后,超级终端打印如图,并且电源自动进入应用程序。

    懒惰不会让你一下子跌到 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
  • 相关阅读:
    Go反射
    Go_CSP并发模型
    Go_select
    Go计时器
    day9:vcp考试
    day8:vcp考试
    day7:vcp考试
    day6:vcp考试
    day5:vcp考试
    day4:vcp考试
  • 原文地址:https://www.cnblogs.com/Rainingday/p/7803158.html
Copyright © 2020-2023  润新知