问题一:数据丢失
串口IAP升级RAM有限,因此升级较大程序出现RAM不够的问题,因此引入循环写入方式;
main程序
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
#include "stmflash.h"
#include "iap.h"
#include "can.h"
/************************************************
ALIENTEK 阿波罗STM32F429开发板实验52
串口IAP实验-HAL库函数版
技术支持:www.openedv.com
淘宝店铺:http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司
作者:正点原子 @ALIENTEK
************************************************/
int main(void)
{
u8 t;
u16 oldcount=0; //老的串口接收数据值
u32 applenth=0; //接收到的app代码长度
// u8 clearflag=0;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
// LED_Init(); //初始化LED
// KEY_Init(); //初始化按键
SDRAM_Init(); //初始化SDRAM
// CAN1_Mode_Init(CAN_SJW_1TQ,CAN_BS2_6TQ,CAN_BS1_8TQ,24,CAN_MODE_NORMAL); //CAN初始化,波特率125Kbps
// LCD_Init(); //初始化LCD
// POINT_COLOR=RED;
// LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
// LCD_ShowString(30,70,200,16,16,"FLASH EEPROM TEST");
// LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
// LCD_ShowString(30,110,200,16,16,"2016/1/12");
// LCD_ShowString(30,130,200,16,16,"KEY_UP:Copy APP2FLASH");
// LCD_ShowString(30,150,200,16,16,"KEY1:Erase SRAM APP");
// LCD_ShowString(30,170,200,16,16,"KEY0:Run SRAM APP");
// LCD_ShowString(30,190,200,16,16,"KEY2:Run FLASH APP");
// POINT_COLOR=BLUE;
//显示提示信息
// POINT_COLOR=BLUE;//设置字体为蓝色
u8 t1=0;
int update_step =0;
#define cnt 6
int Recive_wait_CNT=10;
u32 delay_cnt=0;
while(1)
{
if(enable_update_Flag)//等待执行刷新命令
{
enable_update_Flag = 0;
USART_RX_CNT =0;
CODE_UP_CNT = 0;
update_step = 100;
enabled_update_Flag =1;
USART_CAN_RX_FLAG =0;
printf("等待用户刷新固件......\r\n");
}
if(enabled_update_Flag)//已经打开升级功能
{
//printf("开始更新固件...\r\n");
if(CODE_UP_send_flag)
{
if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
iap_write_appbin(FLASH_APP1_ADDR+(CODE_UP_cycle_CNT-1)*Code_up_LEN,Code_up_BUF,Code_up_LEN);//更新FLASH代码
printf("固定长度更新 %x \r\n",FLASH_APP1_ADDR+(CODE_UP_cycle_CNT-1)*Code_up_LEN);
CODE_UP_send_flag =0;
}else
{
printf("非FLASH应用程序!\r\n");
}
}
/****************长时间判断是否有新的数据结束**************/
// if((oldcount==USART_RX_CNT)&&(delay_cnt==0x7fffff))
// delay_cnt++;
delay_cnt++;
if(delay_cnt==0x7fffff*1)//等待1秒
{
if((oldcount==USART_RX_CNT)&&(oldcount!=0))
{
if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
{
// iap_write_appbin(FLASH_APP1_ADDR+CODE_UP_cycle_CNT*Code_up_LEN,Code_up_BUF,CODE_UP_CNT);//更新FLASH代码
printf("固件尾端更新 %x-> 固件尾端地址 %x 更新长度: %d \r\n",FLASH_APP1_ADDR+CODE_UP_cycle_CNT*Code_up_LEN,FLASH_APP1_ADDR+CODE_UP_cycle_CNT*Code_up_LEN+CODE_UP_CNT,CODE_UP_cycle_CNT*Code_up_LEN+CODE_UP_CNT);
CODE_UP_send_flag =0;
}else
{
printf("非FLASH应用程序!\r\n");
}
}else{
oldcount=USART_RX_CNT;
}
delay_cnt=0;
printf("循环时间:!!!!");
}
/*****************************/
}
// switch (update_step){
// case 0:
// t++;
// delay_ms(10);
// if(t==50)
// {
// LED0=!LED0;
// t=0;
// t1++;
// printf("启动Flash倒计时%d...\r\n",cnt-t1);
// }
// if(t1>cnt)//延时函数3秒
// {
// update_step = 400;
// } else{
// if(enable_update_Flag)
// {
// enable_update_Flag = 0;
// USART_RX_CNT =0;
// update_step = 100;
// enabled_update_Flag =1;
// USART_CAN_RX_FLAG =0;
// printf("等待用户刷新固件......\r\n");
// }
// }
// break;
// case 100:
// if(USART_CAN_RX_FLAG)
// {
// if(t==0) Recive_wait_CNT--;
// if((t==0)&&(Recive_wait_CNT>=0))
// {
// printf("等待用户持续导入程序倒计时 %d !\r\n",Recive_wait_CNT);//10秒后,默认不在持续导入程序
// }
// if((oldcount==USART_RX_CNT)&&(t==0)&&(Recive_wait_CNT==0))//新周期内,没有收到任何数据,认为本次数据接收完成.
// {
// applenth=USART_RX_CNT;
// oldcount=0;
// USART_CAN_RX_FLAG=0;
// printf("用户程序总共接收...\r\n");
// printf("代码长度:%dBytes\r\n",applenth);
// update_step = 300;
// }else oldcount=USART_RX_CNT;
// }
// t++;
// delay_ms(10);
// if(t==100)
// {
// LED0=!LED0;
// t=0;
// }
if (enable_update_Flag ==3)
{
for(int j=0;j<applenth/2;j++)
{
if (USART_RX_BUF[j]==USART_RX_BUF[j+applenth/2])
;//printf("USART_RX_BUF[%d]:%x",j+applenth/2,USART_RX_BUF[j+applenth/2]);
else
printf("USART_RX_BUF[%d]:%x--->USART_RX_BUF[%d]:%x",j,USART_RX_BUF[j],j+applenth/2,USART_RX_BUF[j+applenth/2]);
}
printf("比对完成!!");enable_update_Flag =10;
}
if (enable_update_Flag ==4)
{
applenth = applenth/2;
update_step = 300;
}
if (enable_update_Flag ==5)
{
for(int j=0;j<applenth;j++)
{
printf("USART_RX_BUF[%d]:%x",j,USART_RX_BUF[j]);
}
}
if (enable_update_Flag ==6)
{
update_step = 300;
}
// break;
// case 300:
// if(applenth)
// {
// printf("开始更新固件...\r\n"); printf("FLASH_APP1_ADDR:%d;USART_RX_BUF:%d;applenth:%d;\r\n",FLASH_APP1_ADDR,USART_RX_CNT,applenth);
// if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
// {
// iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码
// printf("固件更新完成!\r\n");
// update_step = 400;
// }else
// {
// printf("非FLASH应用程序!\r\n");
// }
// }else
// {
// printf("没有可以更新的固件!\r\n");
// }
// break;
// case 400:
// printf("开始执行FLASH用户代码!!\r\n");
// if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
// {
// iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
// }else
// {
// printf("非FLASH应用程序,无法执行!\r\n");
// }
// break;
// }
}
}
串口程序
#include "usart.h"
#include "delay.h"
#include "string.h"
//
//如果使用os,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //os 使用
#endif
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//串口1初始化
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2015/9/7
//版本:V1.5
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//********************************************************************************
//V1.0修改说明
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000+0x2D000=0X2002E000.
u8 Code_up_BUF[Code_up_LEN] __attribute__ ((at(0X2002E000)));//接收缓冲,最Code_up_LEN个字节,起始地址为0X2002E000+0x400=0X2002E400. //中转升级buff
//u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
u32 USART_RX_CNT=0; //接收的字节数
u8 USART_CAN_RX_FLAG=0; // 接收标志
u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; //UART句柄
//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound)
{
//UART 初始化设置
UART1_Handler.Instance=USART1; //USART1
UART1_Handler.Init.BaudRate=bound; //波特率
UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字长为8位数据格式
UART1_Handler.Init.StopBits=UART_STOPBITS_1; //一个停止位
UART1_Handler.Init.Parity=UART_PARITY_NONE; //无奇偶校验位
UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //无硬件流控
UART1_Handler.Init.Mode=UART_MODE_TX_RX; //收发模式
HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()会使能UART1
//HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量(使用回调函数处理中断需要调用该函数)
}
//UART底层初始化,时钟使能,引脚配置,中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟
GPIO_Initure.Pin=GPIO_PIN_9; //PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速
GPIO_Initure.Alternate=GPIO_AF7_USART1; //复用为USART1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9
GPIO_Initure.Pin=GPIO_PIN_10; //PA10
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10
__HAL_UART_DISABLE_IT(huart,UART_IT_TC);
#if EN_USART1_RX
__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE); //开启接收中断
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中断通道
HAL_NVIC_SetPriority(USART1_IRQn,3,3); //抢占优先级3,子优先级3
#endif
}
}
u8 USART1RecFlag = 0;
u8 enable_update_Flag=0;
u8 enabled_update_Flag=0;
u32 CODE_UP_CNT =0;
u32 CODE_UP_cycle_CNT =0;
u8 CODE_UP_send_flag =0;
//串口1中断服务程序
void USART1_IRQHandler(void)
{
u8 Res;
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
if(USART1RecFlag==0)
{
USART_RX_CNT = 0;
}
USART_CAN_RX_FLAG = 1;USART1RecFlag = 1;CANRecFlag =0;
if((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
HAL_UART_Receive(&UART1_Handler,&Res,1,1000);
if(USART_RX_CNT<USART_REC_LEN)
{
USART_RX_BUF[USART_RX_CNT]=Res;
USART_RX_CNT++;
CODE_UP_CNT++;
if(CODE_UP_CNT==Code_up_LEN)
{
if(CODE_UP_send_flag)
printf("上次未成功刷入固件!!");
printf("USART_RX_CNT:%d----CODE_UP_CNT:%d",USART_RX_CNT,CODE_UP_CNT);
CODE_UP_cycle_CNT++;
memcpy(Code_up_BUF,&USART_RX_BUF[USART_RX_CNT-CODE_UP_cycle_CNT*Code_up_LEN],Code_up_LEN);
CODE_UP_CNT = 0;
CODE_UP_send_flag =1;
}
}else
{
USART_RX_CNT =0;//循环存取
}
/*****************************/
if(enabled_update_Flag==0){
if(USART_RX_CNT>=3)
{
if((USART_RX_BUF[0]==0x6d)&&(USART_RX_BUF[1]==0x6a)&&(USART_RX_BUF[2]==0x6d))//mjm
{
enable_update_Flag = 1;
}
}
}
/**************************/
}
HAL_UART_IRQHandler(&UART1_Handler);
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
#endif
/****************************************************************************************/
/****************************************************************************************/
/*************************下面程序通过在回调函数中编写中断控制逻辑*********************/
/****************************************************************************************
***************************************************************************************************
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//如果是串口1
{
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
//串口1中断服务程序
void USART1_IRQHandler(void)
{
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
HAL_UART_IRQHandler(&UART1_Handler); //调用HAL库中断处理公用函数
while (HAL_UART_GetState(&UART1_Handler) != HAL_UART_STATE_READY);//等待就绪
while(HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE) != HAL_OK);//一次处理完成之后,重新开启中断并设置RxXferCount为1
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
**************************************/
问题:使用只循环接收接收数据传输正常:不进行FLash数据写入操作;
接收数据正常
发送开始命令;
发送文件:4572kb;接收4572kb.无错误;
引入FLash写入后出现数据丢失问题:
数据丢失:
发送数据:4572kb; 接收:3073kb;
数据丢失;
已经修改串口中断优先级,但是依然没有效果;
问题二:大文件buff宕机,原因未知
因为RAM给了180kb,所以发送大文件时,进行RAM满以后从新循环存如RAM(下标清零);
但是程序执行至:第一次满180kb以后,在接收第二次数据的第一组后宕机了。
程序停止于:
原因未知: