OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 649|回复: 3

stm32f013 串口刷写程序 bootload

[复制链接]

66

主题

246

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1141
金钱
1141
注册时间
2015-11-29
在线时间
149 小时
发表于 2026-3-16 13:54:05 | 显示全部楼层 |阅读模式
20金钱
目前已经写好iap和app,程序写入后app不执行。不知道问题出在哪里?其中iap程序以串口收到kkkkkk为开始升级,收到kk为数据接收完成,iap部分代码帮忙分析一下

// ==================== Flash 分区定义 ====================
#define FLASH_PAGE_SIZE        1024         // STM32F1 每页1KB
#define IAP_ADDRESS            0x08000000   // IAP程序起始地址APP_ADDRESS
#define APP_ADDRESS            0x08004000   // App程序起始地址
#define FLASH_END_ADDRESS      0x08010000   // F103C8T6 Flash结束地址(64KB)


#define APP_MAX_SIZE           0x0000C000   // App区最大48KB

// ==================== 串口接收相关 ====================
#define UART_BUF_SIZE          51200
uint8_t UART_RxBuffer[UART_BUF_SIZE];       // 串口接收缓冲区
uint16_t UART_RxLen = 0;                    // 接收数据长度APP_ADDRESS
uint8_t UART_UpgradeFlag = 0;               // 升级标志
//#define UART_BUF_SIZE          51200        // 缓冲区50KB(大于App最大48KB)
#define FINISH_FLAG            "kk"         // 接收完成标志(小写kk)
#define FLAG_LEN               2            // 标志长度





while(waitTime--)
    {
        Delay_1ms(1);

        // 接收串口数据(非阻塞)
         rxByte = USART1_ReceiveByte(1); // 1ms超时
        if(rxByte != 0xFF) // 接收到有效数据
        {
            UART_RxBuffer[UART_RxLen++] = rxByte;

            // 检测升级指令 "UPDATE"(长度6)
            if(UART_RxLen >= 6)
            {
                if(memcmp(UART_RxBuffer, "kkkkkk", 6) == 0)
                {
                    UART_UpgradeFlag = 1;
                    USART1_SendString((uint8_t*)"Upgrade start...\r\n");
                    UART_RxLen = 0; // 清空缓冲区,准备接收固件
                    break;
                }
                // 指令不匹配,清空缓冲区(防止脏数据)
               // else
                {
                   // UART_RxLen = 0;
                }
            }
        }
    }

     if(UART_UpgradeFlag)
    {
        // 持续接收数据(30秒超时,适配大文件)
        uint64_t recvTimeout = 300000000000;
                          char len_str[10];
        while(recvTimeout--)
        {
            uint8_t rxByte = USART1_ReceiveByte(1);
            if(rxByte != 0xFF)
            {
                // 防止缓冲区溢出
                if(UART_RxLen < UART_BUF_SIZE)
                {
                    UART_RxBuffer[UART_RxLen++] = rxByte;
                    recvTimeout = 300000000000; // 收到数据重置超时
                }
                else
                {
                    USART1_SendString((uint8_t*)"\r\nBuffer full!\r\n");
                    break;
                }

                // 检测完成标志"kk"
                if(UART_RxLen >= FLAG_LEN)
                {
                    if(Check_FinishFlag() == 1)
                    {
                        UART_RecvComplete = 1;
                        break;
                    }
                }
            }
        }

        // 接收完成,开始写入Flash
        if(UART_RecvComplete)
        {
            // 剔除末尾的"kk"标志,得到实际固件长度
            uint16_t firmware_len = UART_RxLen - FLAG_LEN;
            USART1_SendString((uint8_t*)"\r\nRecv complete! Firmware size: ");

            sprintf(len_str, "%d bytes\r\n", firmware_len);
            USART1_SendString((uint8_t*)len_str);

            // 校验固件长度是否合法
            if(firmware_len == 0 || firmware_len > APP_MAX_SIZE)
            {
                USART1_SendString((uint8_t*)"Firmware size error!\r\n");
            }
            else
            {
                // 批量写入App区(按页写入)
                uint32_t appAddr = APP_ADDRESS;
                uint16_t write_len = 0;
                USART1_SendString((uint8_t*)"Writing to Flash...\r\n");

                while(write_len < firmware_len)
                {
                    // 每次写入1页,最后一次写剩余字节
                    uint16_t current_write = (firmware_len - write_len) > FLASH_PAGE_SIZE ?
                                             FLASH_PAGE_SIZE : (firmware_len - write_len);

                    // 写入Flash
                    if(FLASH_Write(appAddr, &UART_RxBuffer[write_len], current_write) == 0)
                    {
                        appAddr += current_write;
                        write_len += current_write;
                        USART1_SendString((uint8_t*)"."); // 进度提示
                    }
                    else
                    {
                        USART1_SendString((uint8_t*)"\r\nWrite Flash failed!\r\n");
                        break;
                    }
                }

                // 写入完成提示
                if(write_len == firmware_len)
                {
                    USART1_SendString((uint8_t*)"\r\nUpgrade success!\r\n");
                }
            }
        }
        else
        {
            USART1_SendString((uint8_t*)"\r\nRecv timeout or no finish flag!\r\n");
        }
    }

    // 跳转到App程序
    IAP_JumpToApp();




uint8_t FLASH_Write(uint32_t addr, uint8_t *pData, uint16_t len)
{
         uint32_t pageAddr=0;
         uint16_t i = 0;
         uint16_t *pHalfWord=NULL;
         uint16_t data=0;
    // 1. 检查地址合法性
    if(addr < APP_ADDRESS || (addr + len) > FLASH_END_ADDRESS)
    {
        return 1; // 地址越界
    }

    // 2. 解锁Flash
    FLASH_Unlock();

    // 3. 擦除需要写入的Flash页
     pageAddr = addr;
    while(pageAddr < (addr + len))
    {
        // 等待上一次擦除完成
        while(FLASH_GetStatus() != FLASH_COMPLETE);
        // 擦除一页
        if(FLASH_ErasePage(pageAddr) != FLASH_COMPLETE)
        {
            FLASH_Lock();
            return 2; // 擦除失败
        }
        pageAddr += FLASH_PAGE_SIZE;
    }

    // 4. 逐半字写入(STM32F1仅支持16位写入)

     pHalfWord = (uint16_t*)pData;
    while(i < len)
    {
        // 等待Flash就绪
        while(FLASH_GetStatus() != FLASH_COMPLETE);

         data = 0;
        if(i+1 < len)
        {
            data = (pData[i+1] << 8) | pData[i]; // 小端模式
        }
        else
        {
            data = pData[i]; // 剩余1字节,高位补0
        }

        // 写入半字
        if(FLASH_ProgramHalfWord(addr + i, data) != FLASH_COMPLETE)
        {
            FLASH_Lock();
            return 3; // 写入失败
        }
        i += 2;
    }

    // 5. 锁定Flash
    FLASH_Lock();
    return 0; // 成功
}



void IAP_JumpToApp(void)
{
    // 函数指针类型定义
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;
    uint32_t JumpAddress;

    // 1. 检查App区栈地址是否合法(F103C8T6 SRAM: 0x20000000-0x20005000)
   // if(((uint32_t*)APP_ADDRESS)[0] > 0x20000000 && ((uint32_t*)APP_ADDRESS)[0] < 0x20005000)
    {
        // 2. 关闭所有中断
        __disable_irq();

        // 3. 关闭串口和外设时钟
        USART_Cmd(USART2, DISABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, DISABLE);

        // 4. 重置SysTick
        SysTick->CTRL = 0;
        SysTick->LOAD = 0;
        SysTick->VAL = 0;

        // 5. 获取App入口地址(中断向量表第1项:栈地址,第2项:复位函数)
        JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
        JumpToApplication = (pFunction)JumpAddress;

        // 6. 设置主栈指针(MSP)
        __set_MSP(*(__IO uint32_t*)APP_ADDRESS);

        // 7. 跳转到App程序
        JumpToApplication();
    }
}

显示写入成功倒是跳转就没有反应了。

回复

使用道具 举报

66

主题

246

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1141
金钱
1141
注册时间
2015-11-29
在线时间
149 小时
 楼主| 发表于 2026-3-16 13:54:40 | 显示全部楼层
单独刷app程序可以运行
回复

使用道具 举报

2

主题

473

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
5080
金钱
5080
注册时间
2018-5-14
在线时间
1049 小时
发表于 2026-3-16 15:58:30 | 显示全部楼层
问题来了,单刷APP可以执行,APP编译在哪个地址,如果是0x08000000的地址,那么说明APP问题,APP的system_init中需要改中断向量表到实际的地址的。
回复

使用道具 举报

2

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2015-1-7
在线时间
48 小时
发表于 2026-3-23 09:07:46 | 显示全部楼层
应用程序编译的时候,起始地址要修改为0x8004000;另外中断向量表有修改吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-4-2 07:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表