最近做STM32的升级程序,原来做过标准库的升级,这次用的是HAL库的升级。原本以为很简单,但缺困扰了我好几天。首先是FLASH的读写。
TestStatus FLASH_Write_NWord(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t Num)
{
uint32_t i;
FLASH_Status FLASHStatus = FLASH_COMPLETE;
TestStatus MemoryProgramStatus = PASSED;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGAERR | FLASH_FLAG_WRPERR | FLASH_FLAG_BSY);
for(i = 0;i < Num;i += 4)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr, *pBuffer) != HAL_OK)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr, *pBuffer) != HAL_OK)
{
MemoryProgramStatus = FAILED;
break;
}
}
WriteAddr += 4;
pBuffer ++;
}
HAL_FLASH_Lock();
return MemoryProgramStatus;
}
void FLASH_Read_NWord(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t Num)
{
uint32_t i;
for(i = 0;i < Num;i++)
{
pBuffer[i]=*(__IO uint32_t*)ReadAddr;
ReadAddr += 4;
}
}
void FLASH_Erase_NWord(long WriteAddr,long Num)
{
unsigned char PageNum,j;
FLASH_Status FLASHStatus = FLASH_COMPLETE;
PageNum = Num / FLASH_PAGE_SIZE;
FLASH_EraseInitTypeDef My_Flash;
uint32_t PageError = 0;
if(Num % FLASH_PAGE_SIZE != 0)
PageNum ++;
My_Flash.TypeErase = FLASH_TYPEERASE_PAGES;
My_Flash.PageAddress = WriteAddr;
My_Flash.NbPages = PageNum;
__disable_irq();
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGAERR | FLASH_FLAG_WRPERR);
HAL_FLASHEx_Erase(&My_Flash, &PageError);
HAL_FLASH_Lock();
__enable_irq();
}
用这三句代替之前的标准库的:写 读 擦 在升级过程中遇到了4个问题,第一个问题是,收到分包内容之后,就被清理了,之后串口BUF里的数据变成了一个不对的数,这导致一个包需要重复传3次左右才成功,大大影响了升级效率。后来改了stm32l1xx_hal_uart.c才解决了这个问题。在HAL串口库里有这么一句:
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
其实DEBUG一下,也知道是USART_SR_FE的问题,即:帧错误。 但是实在是找不到为什么帧错误。索性就把**if (errorflags == RESET)**屏蔽了。之后还屏蔽了一处:
#if 0
if (--huart->RxXferCount == 0U)
{
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
huart->RxState = HAL_UART_STATE_READY;
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
}
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
huart->RxEventCallback(huart, huart->RxXferSize);
#else
HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif
}
else
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
huart->RxCpltCallback(huart);
#else
HAL_UART_RxCpltCallback(huart);
#endif
}
return HAL_OK;
}
#endif
这个问题得以解决。至于原因,后续再探讨,实在是没有时间看着一块。
第二个问题是,升级过程中到了第16包溢出,但换个板子就没事了。或者在最后跳转的时候,进入到了HardFault_Handler中,原因不明。最后无解,换了个单片机之后,溢出和HardFault_Handler也都不见了。至于为什么用着用着单片机就不行了,可能是硬件设计有问题。
第三个问题,就是换了单片机之后,晶振不起振,卡死到HAL_RCC_OscConfig函数中。只能去重新修改时钟树,改为内部的晶振。这个不起振在L系列见的比较多,在F系列还没见到。看得文章也不少了,原因大概率和电源有关。可靠的解决办法2个,要么设计的时候设计成有源晶振,要么用单片机内部的晶振(总不能单片机自带的晶振也不行吧?)
第四个问题,跳转了之后程序不正常。可能是在跳转之前关闭了一些东西,但即便如此,挑转到了新程序的地方也有初始化啊,但就是不行。后来在写完程序之后,加了一个复位。即:程序写到制定位置之后,复位HAL_NVIC_SystemReset(); 之后再跳转。这样就没问题了。因为要复位,所以要借助于FLASH给标记。
|