解决stm32f103的flash写出错、升级一半就会失败问题
项目中使用stm32f407与stm32f103通过I2C升级。
STM32F407作为主机,外接4个从机103,根据地址的不同进行升级。
本人发现在测试中,利用stm32自带的硬件I2C功能进行升级。
过程中发现,407能与103正常通信,但是由于升级数据比较大,写到%10随机的一个数据后,就会报错,经单步调试发现,
写进去的数据跟读出来的数据不一样,再判断发现根本没写进flash里去。flash_unlock();也启用了,但是仍旧有这个问题。
一直以为是STM32自身的I2C有问题,但实际上发现,链路是通的,103的确可以收到数据。虽然众多网友反映它的I2C不好使,但在升级这里还是可以的。
排除I2C链路造成的干扰,还是把重点放在写flash这一块。
之前也做过写flash作为用户数据,保存一些少量的数据作为掉电不丢失来用,只要flash地址没有被占用,读写保存数据还是可以用的。
那问题出在哪里?
公布一点源码
这是升级的分析函数
u8 buffer[270];
void arm_update_handler(unsigned char * receive,unsigned char * transfer)
{
uint16_t PageSize = PAGE_SIZE;
uint32_t RamSource;
int ret, EraseCounter, j;
memcpy(buffer,receive,270);(后来添加原来这里的指针溢出,开辟一个空间解决问题)
switch (buffer,receive[11])
{
case PREPARE:
TPI_EDID_PRINT("PREPARE\n");
update_state = UPDATE_OK;
break;
case ERASE ://擦除应用包程序
update_state = UPDATE_BUSY;
FlashDestination = ApplicationAddress;
for (EraseCounter = 0; EraseCounter < NBROFPAGE; EraseCounter++)
{
ret = FLASH_ErasePage(FlashDestination + (PageSize * EraseCounter));
if(ret != FLASH_COMPLETE)
{
update_state = UPDATE_ERROR;
return;
}
}
update_state = UPDATE_OK;
break;
case WRITE_BLOCK0:
update_state = UPDATE_BUSY;
TPI_EDID_PRINT("WRITE_BLOCK0\n");
// RamSource = (uint32_t)&receive[12];//不能使用这种指针方式来升级,因为数据过大,内存溢出的话 数据就会出错
RamSource = (uint32_t)&buffer[12];//必须用这种数组的方式
for (j = 0;(j < PACKETLEN) && (FlashDestination < 0x803ffff); j += 4)
{
/* Program the data received into STM32F10x Flash */
FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);//烧写4个字节
if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
{//判断读出来的数据是否一样
/* End session */
FlashDestination = ApplicationAddress;
update_state = UPDATE_ERROR;
return;
}
FlashDestination += 4;
RamSource += 4;
}
update_state=UPDATE_OK;
break;
case WRITE_CONTINUE_BLOCK:
update_state = UPDATE_BUSY;
// RamSource = (uint32_t)&receive[12];// receive 是一个指针 这里的I2C buffe竟然开辟了512个字节 其实用不了r
RamSource = (uint32_t)&buffer[12];
for (j = 0; (j < PACKETLEN) && (FlashDestination < 0x0803ffff); j += 4)
{
/* Program the data received into STM32F10x Flash */
FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
// Delay_ms(1);
tempdata=*(uint32_t*)RamSource;
tempdata2=*(uint32_t*)FlashDestination;
if (tempdata2 != tempdata)
{
/* FLASH_ErasePage(FlashDestination);
FLASH_ProgramWord(FlashDestination, *(uint32_t*)RamSource);
// Delay_ms(5);
*/
// if (*(uint32_t*)FlashDestination != *(uint32_t*)RamSource)
{
FlashDestination = ApplicationAddress;
update_state = UPDATE_ERROR;
return;
}
}
FlashDestination += 4;
RamSource += 4;
}
update_state = UPDATE_OK;
break;
case END:
update_state = UPDATE_BUSY;
TPI_EDID_PRINT("END\n");
FlashDestination = ApplicationAddress;
update_state = UPDATE_OK;
Delay_ms(1000);
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
/* Jump to user application */
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
break;
default:
break;
}
}
经过上述描述,是由于I2C的内存开的过大。而这里使用一个 未知的* receive 做指针,并靠它来读取数据导致失败。将有用到的数据copy到一个已知的静态buffer里,这样的他的地址其实就已经固定了,不会乱套。