bootloader使用完善ymodem协议(优化完善stm的ymodem协议),以及xshell终端结束(超详细教程,简单好学,看了秒懂)

通过研究stm的ymodem协议,发现EOT之后直接就进行ACK回复确认了,没有进行NAK反复确认

所以具体需要修改:

主要是修改Ymodem_Receive函数

首先EOT 之后 直接默认结束传输,所以将ACK修改为NAK

最后在该函数的最后,模拟再次ACK C确认

然后接收一包结束帧,再回复ACK确认

注意:如果是xshell等终端需要再发送一个结束,提示ymodem协议结束

添加基础的注释,便于理解,目前代码还没整理完成,先暂时不上传了,只是上传官方的标准库

链接:https://pan.baidu.com/s/1Y4jVoSSPUTceuIA-O6X6Fg
提取码:n0kw
--来自百度网盘超级会员V4的分享

 /**
   * @brief  使用ymodem接受一个文件
   * @param  buf: 第一个字节的地址.
   * @retval 文件的大小.
   */
 LONG Ymodem_Receive (UCHAR *buf)
 {
    UCHAR packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
    LONG i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
    ULONG flashdestination, ramsource;
    ULONG t = 0;
    UCHAR c = 0;
 
    /* 初始化flash地址 */
    flashdestination = APPLICATION_ADDRESS;
 
    for (session_done = 0, errors = 0, session_begin = 0; ;)
    {
        for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
        {
            switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
            {
                /* 如果接收成功 */
                case 0:
                {
                    /* 错误标志清零 */
                    errors = 0;
                    switch (packet_length)
                    {
                        /* 被发送者终止 */
                        case - 1:
                        {
                            Send_Byte(ACK);
                            return 0;
                        }
                        /* 结束传输 */
                        case 0:
                        {
                            /* 修改该地方 */
                            Send_Byte(NAK);
                            file_done = 1;
                            break;
                        }
                        default:
                            /* 正常包 */
                            if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
                            {
                                Send_Byte(NAK);
                            }
                            else
                            {
                            /* 如果是第一个起始帧 */
                            if (packets_received == 0)
                            {
                                /* 文件名字包 */
                                if (packet_data[PACKET_HEADER] != 0)
                                {
                                    /* file_ptr+3 因为前三个字节是首部 再就是文件名字 */
                                    for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                                    {
                                        FileName[i++] = *file_ptr++;
                                    }
                                    /* 获取到的文件名字字符串 */
                                    FileName[i++] = '\0';

                                    /* 文件名字之后紧接着就是文件大小 */
                                    for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
                                    {
                                        file_size[i++] = *file_ptr++;
                                    }
                                    file_size[i++] = '\0';
                                    /* 将文件大小转换为字符串 */
                                    Str2Int(file_size, &size);

                                    /* 检测被发送镜像bin文件的大小 */
                                    /* 如果镜像bin文件比flash大 */
                                    if (size > (USER_FLASH_SIZE + 1))
                                    {
                                        /* End session */
                                        Send_Byte(CA);
                                        Send_Byte(CA);

                                        /*debug 文件太大 flash太小 没有合适的空间 */
                                        return -1;
                                    }
                                    /* 擦除flash */
                                    FLASH_If_Erase(APPLICATION_ADDRESS);
                                    Send_Byte(ACK);


                                    /* 收到第起始帧后立马回应 发送c */
                                    Send_Byte(CRC16);
                                    }
                                    /* 文件名字包为空,结束传输 */
                                    else
                                    {
                                        Send_Byte(ACK);
                                        file_done = 1;
                                        session_done = 1;
                                        break;
                                    }
                            }
                            /* 数据帧 */
                            else
                            {
                                /* 拷贝当前的数据 */
                                memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
                                ramsource = (ULONG)buf;

                                /* 往flash里边写数据 packet_length/4的原因是一个字占4个字节 */
                                if (FLASH_If_Write(&flashdestination, (ULONG *) ramsource, (USHORT) packet_length/4)  == 0)
                                {
                                    Send_Byte(ACK);
                                }
                                else /* 当往flash写的时候,出现错误 */
                                {
                                    /* 结束传输 */
                                    Send_Byte(CA);
                                    Send_Byte(CA);
                                    return -2;
                                }
                            }
                        packets_received ++;
                        session_begin = 1;
                    }
                }
                break;
            }
            case 1:
            {
                Send_Byte(CA);
                Send_Byte(CA);
                return -3;
            }
            default:
            {
                if (session_begin > 0)
                {
                    errors ++;
                }
                if (errors > MAX_ERRORS)
                {
                    Send_Byte(CA);
                    Send_Byte(CA);
                    return 0;
                }
                Send_Byte(CRC16);
                break;
            }
        }
        if (file_done != 0)
        {
            break;
        }
        }
        if (session_done != 0)
        {
            break;
        }
    }
    Send_Byte(ACK);
    Send_Byte(CRC16);
    /* 最后接收结束帧 该帧其实不管对错 都已经传输完成 */
    Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT);
    Send_Byte(ACK);

    return (LONG)size;
}

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32自举程序USART协议引导加载程序(bootloader)是一种在STM32芯片上运行的特殊程序,用于启动主程序或固件更新。 自举程序是嵌入式系统中的一种特殊程序,负责初始化硬件和加载用户程序。STM32芯片自带的自举程序主要通过串口USART进行固件升级。USART是一种通用同步/异步收发传输方式,其中UART是其异步模式。 自举程序在STM32芯片上运行的方式是通过USART协议进行通信。用户可以通过串口连接至开发板,通过特定的协议与自举程序进行交互,如发送命令、固件升级等。自举程序会接收命令并执行相应的操作,比如从外部存储器加载主程序或新固件至内部存储器,并将控制权交给主程序。 使用USART协议进行自举程序有以下几个优点。首先,USART是一种常见的通信协议,在大部分STM32芯片上都提供了串口接口,方便开发者与自举程序进行交互。其次,USART协议基于硬件UART实现,具备较高的可靠性和稳定性。再者,USART支持异步模式,能够通过设置波特率和其他参数来满足不同应用场景的需求。 总结来说,STM32自举程序USART协议引导加载程序是一种通过串口USART协议进行通信的特殊程序,用于初始化硬件和加载主程序或固件。通过USART协议,用户可以与自举程序进行交互,实现命令的发送和固件的升级。这种方式简单易用,且在STM32开发中得到广泛应用。 ### 回答2: STM32自举程序USART协议Bootloader是指通过USART通信接口对STM32微控制器进行启动程序的升级和更新。通常情况下,开发使用USART通信接口将新的固件程序加载到STM32微控制器的引导区域中,并执行更新操作。 USART协议是一种通信协议,用于在两个设备之间进行串行通信。在STM32的自举程序中,USART被用作与外部设备(如电脑或其他控制器)进行通信的接口。 Bootloader是一个特殊的启动程序,它负责检测和加载新的固件程序,以实现固件的升级和更新。Bootloader是存储在微控制器的引导区域中的一段特殊代码,它在系统加电或复位后首先被执行。 在使用USART协议进行自举程序更新时,开发者首先通过USART接口与目标设备进行连接。然后,利用USART通信接口发送特定的命令和数据,将新的固件程序传输到STM32微控制器的引导区域中。一旦传输完成,系统将自动重启,引导区域的代码将负责从引导区域加载并执行新的固件程序。 通过使用USART协议Bootloader开发者可以方便地对STM32微控制器进行固件程序的升级和更新,而无需使用其他复杂的硬件或工具。这为开发者提供了更加灵活和高效的方法来维护和更新STM32微控制器系统。 ### 回答3: STM32启动程序USART协议引导加载程序是指通过USART通信接口加载和更新STM32微控制器上的固件。在STM32微控制器上,引导加载程序是一个位于片上闪存的特殊程序,它用于加载用户应用程序或固件。USART是一种通信协议,可实现串行通信。通过USART协议,可以将PC上的固件文件传输到STM32微控制器上,并将其写入片上闪存。 使用USART协议进行引导加载程序的过程如下: 首先,将STM32微控制器和PC通过USART串行通信接口连接起来。 然后,在PC上的串口调试工具或者其他串口通信软件上,设置好与STM32微控制器通信的波特率、数据位、停止位和校验位等参数。 接着,将STM32微控制器复位并进入引导加载模式。开发板上通常有一个BOOT0引脚用于控制进入引导加载模式。 在PC上发送特定的命令或数据帧,告知引导加载程序需要进行固件更新操作。 STM32引导加载程序接收到命令或数据后,开始接收来自PC的固件文件。 引导加载程序将接收到的固件文件存储在片上闪存的指定区域。 固件文件传输完成后,引导加载程序将控制权移交给用户应用程序或新的固件。 通过USART协议进行引导加载程序更新的优势是传输速度快,适用于较大的固件文件,同时可以通过简单的串口通信连接进行操作。这种方法广泛应用于STM32微控制器的固件更新和开发过程中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值