|
本帖最后由 LZY 于 2021-12-1 16:16 编辑
采用FM33LCO46芯片,FLASH大小为256K,其中64K空间作为bootloader程序运行,剩余192K作为用户程序,bootloader程序主要参考正点原子例程,现在用JLINK分别烧写bootlaoder程序和用户程序到各自指定地址后,bootloader程序运行跳转程序到用户程序地址后,用户程序可以运行。但是在bootloader程序中利用串口接收用户程序的bin文件,然后将数据烧写到指定地址的flash上,这种方式跳转后单片机死机。
下面附上bootloader程序代码
int main(void)
{
MF_Clock_Init();
MF_SystemClock_Config();
MF_Config_Init();
LedInit();
Key_GPIO_Config();
UserInit();
Uart0_Init(115200);
printf("运行BOOTLOADER代码\r\n" );
while(1)
{
if(USART_RX_CNT)
{
if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
{
applenth=USART_RX_CNT;
oldcount=0;
USART_RX_CNT=0;
printf("用户程序接收完成!\r\n");
printf("代码长度:%dBytes\r\n",applenth);
}
else oldcount=USART_RX_CNT;
}
t++;
DelayMs(10);
if( Key_Scan(KEY1_GPIO,KEY1_PIN) == KEY_ON )
{
printf("KEY1被按下\n");
printf("串口接收问题%d\r\n",USART_RX_CNT);
iap_write_appbin(FLASH_APP1_ADDR,(u8*)USART_RX_BUF,USART_RX_CNT);//更新FLASH代码
//FM_FLASH_Write(ProgAddr,(u32*)TEXT_Buffer,SIZE);
//LL_FLASH_Program_String(FLASH,ProgAddr,(u32*)TEXT_Buffer,SIZE);
}
if( Key_Scan(KEY4_GPIO,KEY4_PIN) == KEY_ON )
{
printf("KEY4被按下\r\n");
printf("开始执行FLASH用户代码!!\r\n");
//if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x00000000)//判断是否为0X08XXXXXX.
iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
}
// LED1_TOG();
}
}
iap_write_appbin函数是将8位的数据转成32位,并写入到FLASH
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{
u32 t;
u32 i=0;
u32 temp;
u32 fwaddr=appxaddr;//当前写入的地址
u8 *dfu=appbuf;
for(t=0;t<appsize;t+=4)
{
temp=(u32)dfu[3]<<24;
temp|=(u32)dfu[2]<<16;
temp|=(u32)dfu[1]<<8;
temp|=(u32)dfu[0];
dfu+=4;//偏移4个字节
iapbuf[i++]=temp;
if(i==512)
{
i=0;
FM_FLASH_Write(fwaddr,iapbuf,512);
fwaddr+=2048;//偏移2048
}
}
if(i)FM_FLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.
}
iap_write_appbin函数是将串口接收的缓存的数组写入到指定地址的flash中,已测试利用ap_write_appbin函数将少量的数据到写道flash,然后读出来,数据没有问题。
现在怀疑是不是数据大于2K,跳转扇区的时候数据出错了,有没有大佬帮忙分析一下ap_write_appbin函数。
以下是FM_FLASH_Write函数:
void FM_FLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{
u32 secpos; //扇区地址 第几个扇区
u32 secoff; //扇区内偏移地址(32位字计算)
u32 secremain; //扇区内剩余地址(32位字计算)
u32 i;
u32 offaddr; //去掉0X00000000后的地址
if(WriteAddr<FLASH_BASE||(WriteAddr>=(FLASH_BASE+1024*FM33_FLASH_SIZE)))return;//非法地址
offaddr=WriteAddr-FLASH_BASE; //实际偏移地址.
secpos=offaddr/FM_SECTOR_SIZE; //扇区地址(即第几个扇区)
secoff=(offaddr%FM_SECTOR_SIZE)/4; //在扇区内的偏移(4个字节为基本单位.)
secremain=FM_SECTOR_SIZE/4-secoff; //扇区剩余空间大小
if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
while(1)
{
FM_FLASH_Read(secpos*FM_SECTOR_SIZE+FLASH_BASE,FM_FLASH_BUF,FM_SECTOR_SIZE/4);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(FM_FLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
LL_FLASH_SectorErase(FLASH, secpos*FM_SECTOR_SIZE+FLASH_BASE); //擦除这个扇区
for(i=0;i<secremain;i++)//复制
{
FM_FLASH_BUF[i+secoff]=pBuffer;
}
FM33_FLASH_Write_NoCheck(FLASH ,secpos*FM_SECTOR_SIZE+FLASH_BASE,FM_FLASH_BUF,FM_SECTOR_SIZE/4);//写入整个扇区
}
else FM33_FLASH_Write_NoCheck(FLASH,WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.
if(NumToWrite==secremain)break;//写入结束了
else//写入未结束
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
NumToWrite-=secremain; //字节(16位)数递减
if(NumToWrite>(FM_SECTOR_SIZE/4))secremain=FM_SECTOR_SIZE/4;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}
};
}
FM33_FLASH_Write_NoCheck函数:
void FM33_FLASH_Write_NoCheck(FLASH_Type* FLASHx,u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{
u32 i;
for(i=0;i<NumToWrite;i++)
{
LL_FLASH_Program_Word(FLASH,WriteAddr,pBuffer);
WriteAddr+=4;//地址增加4.
}
}
LL_FLASH_Program_Word函数就是库函数了
|
|