OpenEdv-开源电子网

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

求助大佬我使用的是STM32L151芯片 做在线升级 更新完程序后无法跳转

[复制链接]

13

主题

49

帖子

0

精华

高级会员

Rank: 4

积分
542
金钱
542
注册时间
2017-10-17
在线时间
118 小时
发表于 2023-7-14 17:08:04 | 显示全部楼层 |阅读模式
30金钱
本帖最后由 冯必兴 于 2023-7-15 22:56 编辑

1.首先就是参考原子哥的代码做出修改寄存器可以看到已经写入但是就是无法跳转到APP里面
2.通过keil将app层代码下载进去,在boot通过命令能跳转运行的,说明APP层代码是对的没有问题3.直接通过串口将数据接受并通过以下函数进行写进去。因为L1是要求一次性写4bit的数(也就是U32如0xffffffff)


下面是我修改有疑问觉得不对的地方想请大佬参考一下
void STMFLASH_Write(u32 WriteAddr, uint32_t* pBuffer, u16 NumToWrite)
{
    u32 secpos;           //扇区地址
    u32 secoff;           //扇区内偏移地址(16位字计算)
    u32 secremain; //扇区内剩余地址(16位字计算)
    u32 i;
    u32 offaddr;   //去掉0X08000000后的地址
    if(WriteAddr < STM32_FLASH_BASE || WriteAddr % 4)return; //非法地址

    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR\
                    | FLASH_FLAG_SIZERR | FLASH_FLAG_OPTVERR | FLASH_FLAG_OPTVERRUSR | FLASH_FLAG_RDERR);
//    FLASH_ErasePage(WriteAddr);
    offaddr = WriteAddr - STM32_FLASH_BASE;                //实际偏移地址.
    secpos = offaddr / STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6
    secoff = (offaddr % STM_SECTOR_SIZE) / 4;                //在扇区内的偏移(2个字节为基本单位.)
    secremain = STM_SECTOR_SIZE / 4 - secoff;                //扇区剩余空间大小
    if(NumToWrite <= secremain)secremain = NumToWrite; //不大于该扇区范围
    FLASH_Unlock();                                                //解锁
    while(1)
    {
        STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, (uint32_t*)STMFLASH_BUF, STM_SECTOR_SIZE / 4); //读出整个扇区的内容
        for(i = 0; i < secremain*4; i++) //校验数据
        {
            if(STMFLASH_BUF[(secoff*4) + i] != 0XFFFFFFFF)break; //需要擦除
        }

                if(i<secremain*4)//需要擦除
                {
        FLASH_ErasePage(secpos * (STM_SECTOR_SIZE) + STM32_FLASH_BASE); //擦除这个扇区


        for(u16 i = 0; i < (secremain*4); i++)
                                {
            (STMFLASH_BUF)[i+(secoff*4)] = (pBuffer);
                                }
        STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 4);
                                data_addr = secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE;
                }
                else
                {
                        STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                        
                }
        if(NumToWrite == secremain)break; //写入结束了
        else//写入未结束
        {
            secpos++;                                //扇区地址增1
            secoff = 0;                                //偏移位置为0
            pBuffer += secremain;          //指针偏移
            WriteAddr += (secremain * 4);        //写地址偏移
            NumToWrite -= secremain;        //字节(16位)数递减
            if(NumToWrite > (STM_SECTOR_SIZE / 4))secremain = STM_SECTOR_SIZE / 4; //下一个扇区还是写不完
            else secremain = NumToWrite; //下一个扇区可以写完了
        }
    }
    FLASH_Lock();//上锁
}



最佳答案

查看完整内容[请看2#楼]

由于stm32l152系列的单片机是在擦除的时候是整页擦除的,而写的时候是半页半页写的 所以需要改动的代码有: 步骤1: uint32_t iapbuf[256]; //appxaddr:应用程序的起始地址 //appbuf:应用程序CODE. //appsize:应用程序大小(字节). void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize) { uint16_t t; uint16_t i=0; uint32_t temp; u32 fwaddr=appxaddr;//当前写入的地址 u8 *dfu=appbuf; for(t=0;t
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

49

帖子

0

精华

高级会员

Rank: 4

积分
542
金钱
542
注册时间
2017-10-17
在线时间
118 小时
 楼主| 发表于 2023-7-14 17:08:05 | 显示全部楼层
由于stm32l152系列的单片机是在擦除的时候是整页擦除的,而写的时候是半页半页写的
所以需要改动的代码有:
步骤1:
uint32_t iapbuf[256];   
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
        uint16_t t;
        uint16_t i=0;
        uint32_t temp;
        u32 fwaddr=appxaddr;//当前写入的地址
        u8 *dfu=appbuf;
        for(t=0;t<appsize;t+=4)
        {
                temp=(uint32_t)dfu[3]<<24;
                temp|=(uint32_t)dfu[2]<<16;                        
                temp|=(uint32_t)dfu[1]<<8;
                temp|=(uint32_t)dfu[0];          
                dfu+=4;//偏移4个字节
                iapbuf[i++]=temp;            
                if(i == 32 )
                {
                        i=0;
                        STMFLASH_Write(fwaddr,iapbuf,32);       
                        fwaddr+=128;//偏移2048  16=2*8.所以要乘以2.
                }
        }
        if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
//                                        FLASH_WritePage(pack_num,appbuf);
//                                pack_num++;
}
步骤2:
#include "stmflash.h"
#include "delay.h"
#include "usb_data_process.h"
#include "stm32l1xx_flash.h"

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u32 STMFLASH_ReadHalfWord(u32 faddr)
{
    return *(vu32*)faddr;
}
#if STM32_FLASH_WREN        //如果使能了写   
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
void STMFLASH_Write_NoCheck(u32 WriteAddr, uint32_t* pBuffer, u16 NumToWrite)
{
    u16 i;
    for(i = 0; i < NumToWrite; i++)
    {
        FLASH_FastProgramWord(WriteAddr, pBuffer[i]);
        WriteAddr += 4; //地址增加2.
    }
}
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 128 //字节
#else
#define STM_SECTOR_SIZE        2048
#endif
uint32_t STMFLASH_BUF[STM_SECTOR_SIZE / 4]; //最多是2K字节
u32 data_addr = 0;
char CLEAN_STM_SECTOR_SIZE = (256 / STM_SECTOR_SIZE);
void STMFLASH_Write(u32 WriteAddr, uint32_t* pBuffer, u16 NumToWrite)
{
    u32 secpos;           //扇区地址
    u32 secoff;           //扇区内偏移地址(16位字计算)
    u32 secremain; //扇区内剩余地址(16位字计算)
    u32 i;
    u32 offaddr;   //去掉0X08000000后的地址
    if(WriteAddr < STM32_FLASH_BASE || WriteAddr % 4)return; //非法地址

    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR\
                    | FLASH_FLAG_SIZERR | FLASH_FLAG_OPTVERR | FLASH_FLAG_OPTVERRUSR | FLASH_FLAG_RDERR);
//    FLASH_ErasePage(WriteAddr);
    offaddr = WriteAddr - STM32_FLASH_BASE;                //实际偏移地址.
    secpos = offaddr / STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6
    secoff = (offaddr % STM_SECTOR_SIZE) / 4;                //在扇区内的偏移(2个字节为基本单位.)
    secremain = STM_SECTOR_SIZE / 4 - secoff;                //扇区剩余空间大小
    if(NumToWrite <= secremain)secremain = NumToWrite; //不大于该扇区范围
    FLASH_Unlock();                                                //解锁

    while(1)
    {
        STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, (uint32_t*)STMFLASH_BUF, STM_SECTOR_SIZE / 4); //读出整个扇区的内容
        for(i = 0; i < secremain * 4; i++) //校验数据
        {
            if(STMFLASH_BUF[(secoff * 4) + i] != 0XFFFFFFFF)break; //需要擦除
        }

//                if(CLEAN_STM_SECTOR_SIZE == 0 )//需要擦除
        if(offaddr % 256 == 0) //需要擦除
        {

            FLASH_ErasePage(secpos * (STM_SECTOR_SIZE) + STM32_FLASH_BASE); //擦除这个扇区


            for(u16 i = 0; i < (secremain); i++)
            {
                (STMFLASH_BUF)[i + (secoff * 4)] = (pBuffer)[i];
            }
            STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 4);
            data_addr = secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE;
            CLEAN_STM_SECTOR_SIZE = 256 / STM_SECTOR_SIZE;
        }
        else
        {
            STMFLASH_Write_NoCheck(WriteAddr, pBuffer, secremain); //写已经擦除了的,直接写入扇区剩余区间.
        }
        if(NumToWrite == secremain)break; //写入结束了
        else//写入未结束
        {
            secpos++;                                //扇区地址增1
            secoff = 0;                                //偏移位置为0
            pBuffer += secremain;          //指针偏移
            WriteAddr += (secremain * 4);        //写地址偏移
            NumToWrite -= secremain;        //字节(16位)数递减
            if(NumToWrite > (STM_SECTOR_SIZE / 4))secremain = STM_SECTOR_SIZE / 4; //下一个扇区还是写不完
            else secremain = NumToWrite; //下一个扇区可以写完了
        }
    }
    CLEAN_STM_SECTOR_SIZE -= 1;
    FLASH_Lock();//上锁
}
#endif

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr, u32* pBuffer, u16 NumToRead)
{
    u16 i;
    for(i = 0; i < NumToRead; i++)
    {
        pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr); //读取2个字节.
        ReadAddr += 4; //偏移2个字节.
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr, uint32_t WriteData)
{
    STMFLASH_Write(WriteAddr, &WriteData, 1); //写入一个字
}

回复

使用道具 举报

0

主题

26

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
287
金钱
287
注册时间
2019-9-5
在线时间
67 小时
发表于 2023-7-14 18:12:10 | 显示全部楼层
无法跳转的原因可太多了,比如1.你的app程序没有做向量表偏移;2.你的iap程序关闭了全局中断但是app没有打开中断等等,建议仔细参考学习研究下别人的代码。
回复

使用道具 举报

13

主题

49

帖子

0

精华

高级会员

Rank: 4

积分
542
金钱
542
注册时间
2017-10-17
在线时间
118 小时
 楼主| 发表于 2023-7-15 00:18:35 | 显示全部楼层
Stefen 发表于 2023-7-14 18:12
无法跳转的原因可太多了,比如1.你的app程序没有做向量表偏移;2.你的iap程序关闭了全局中断但是app没有打 ...

都是开了的,我直接通过keil下载代码然后在boot层可以跳转过去的,所以我就觉得是我这一段写的哪里不对。
回复

使用道具 举报

31

主题

1951

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4417
金钱
4417
注册时间
2018-5-11
在线时间
922 小时
发表于 2023-7-15 17:30:41 | 显示全部楼层
既然可以正常写入,
你贴这一段写FLASH的程序干什么
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

13

主题

49

帖子

0

精华

高级会员

Rank: 4

积分
542
金钱
542
注册时间
2017-10-17
在线时间
118 小时
 楼主| 发表于 2023-7-15 22:52:28 | 显示全部楼层
warship 发表于 2023-7-15 17:30
既然可以正常写入,
你贴这一段写FLASH的程序干什么

其实写入是,我直接就是通过keil软件把app层的代码下载进去,因为我的跳转是在boot通过命令将其跳转的,所以现象反应能跳转过去能运行说明APP层是对的,只有在写flash进去的时候有问题,所以把这部分贴出来就是想让大佬看看这个有没有问题
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2023-4-24
在线时间
6 小时
发表于 2024-1-8 16:43:48 | 显示全部楼层
求一个stm32l151c8t6a的寄存器手册
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-23 12:54

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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