擦除内部flash导致的串口接收数据异常

问题描述:

stm32h743程序运行过程中,有指令保存数据到内部flash,在执行操作的时候,影响到了另一个串口接收数据。

在存内部flash的过程中,有关闭中断,挂起其他任务的操作。但是均没有解决问题。

打印发现,另一个任务的DMA接收只能接收一个字节,接收的第一个字节是正确的,后面的字节丢失。

串口3的接收使用的是全局变量,将全局变量改成局部变量依旧没有解决问题。

检查写入程序,写入程序只做了擦除和写入操作,一条条注释发现是擦除操作导致的问题。

擦除内部flash的时候影响到了串口3的接收,在擦除之前使用HAL_UART_AbortReceive(&huart3);关闭串口三的串口接收,在写入完毕 使用HAL_UART_Receive_DMA(&huart3,...,...),解决问题。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个基于STM32的Ymodem协议串口接收数据的示例代码: ```c #include "stm32f10x.h" #include "stdio.h" #include "stdbool.h" #define SOH 0x01 #define STX 0x02 #define EOT 0x04 #define ACK 0x06 #define NAK 0x15 #define CAN 0x18 #define CRC16 0x43 #define PACKET_SIZE 128 // 数据包大小 #define PACKET_1K_SIZE 1024 // 1K数据包大小 #define HEAD_SIZE 3 // 数据包头大小 #define TAIL_SIZE 2 // 数据包尾大小 #define PACKET_DATA_SIZE 128-3 // 每个数据包的数据大小 #define FLASH_APP_ADDRESS 0x08008000 // APP程序的存储器地址 bool Ymodem_Receive(uint8_t *); uint8_t Ymodem_WaitACK(void); uint8_t Ymodem_SendPacket(uint8_t *, uint16_t, uint8_t); uint16_t Ymodem_CalcCRC16(uint8_t *, uint16_t); void Ymodem_EraseAppArea(void); void Ymodem_WriteToFlash(uint32_t, uint8_t *, uint16_t); uint8_t PacketBuffer[PACKET_1K_SIZE]; uint8_t ReceiveBuffer[PACKET_1K_SIZE]; uint8_t TxBuf[PACKET_SIZE+TAIL_SIZE]; uint8_t RxBuf[PACKET_SIZE+HEAD_SIZE+TAIL_SIZE]; int main(void) { USART_InitTypeDef USART_InitStructure; /* 使能DMA时钟 */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* 使能USART1时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE); /* 将USART1 Tx的GPIO配置为推挽复用模式 */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 将USART1 Rx的GPIO配置为浮空输入模式 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* USART1初始化设置 */ USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); /* 使能USART1 */ USART_Cmd(USART1, ENABLE); /* 等待串口稳定 */ int i; for (i = 0; i < 1000000; i++); /* 清空Flash */ Ymodem_EraseAppArea(); /* 接收数据 */ Ymodem_Receive(ReceiveBuffer); while (1); } /** * @brief Ymodem协议接收函数 * @param[in] pBuffer 存储接收数据的缓冲区 * @retval true: 接收成功 false: 接收失败 */ bool Ymodem_Receive(uint8_t *pBuffer) { uint8_t ch; uint8_t packet_number = 1; uint32_t packet_length = 0; uint32_t received_packet_count = 0; uint16_t crc16 = 0; uint32_t i; /* 等待发送方发送数据 */ while (1) { ch = Ymodem_WaitACK(); if (ch == 'C') { break; } else if (ch == NAK) { continue; } else { return false; } } /* 开始接收数据 */ while (1) { /* 发送一个ACK,以示准备接收数据 */ USART_SendData(USART1, ACK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); /* 接收数据包头 */ for (i = 0; i < (PACKET_SIZE+HEAD_SIZE+TAIL_SIZE); i++) { while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); RxBuf[i] = USART_ReceiveData(USART1); } /* 判断数据包类型 */ if (RxBuf[0] == SOH) // 数据包大小为128字节 { packet_length = PACKET_SIZE; } else if (RxBuf[0] == STX) // 数据包大小为1024字节 { packet_length = PACKET_1K_SIZE; } else if (RxBuf[0] == EOT) // 数据接收完成 { /* 发送一个ACK,表示数据接收完成 */ USART_SendData(USART1, ACK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); /* 等待发送方发送下一批数据 */ while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); ch = USART_ReceiveData(USART1); if (ch == EOT) { /* 发送最后一个ACK */ USART_SendData(USART1, ACK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return true; } else { return false; } } else // 其他情况 { return false; } /* 判断数据包序号 */ if (RxBuf[1] == packet_number && RxBuf[2] == (255 - packet_number)) { packet_number++; /* 计算CRC校验值 */ crc16 = Ymodem_CalcCRC16(&RxBuf[HEAD_SIZE], packet_length); /* 校验CRC校验值 */ if (crc16 == ((RxBuf[PACKET_SIZE+HEAD_SIZE]<<8)|RxBuf[PACKET_SIZE+HEAD_SIZE+1])) { /* 将数据保存到缓冲区中 */ memcpy(&pBuffer[received_packet_count * packet_length], &RxBuf[HEAD_SIZE], packet_length); received_packet_count++; /* 发送ACK,以示数据接收成功 */ USART_SendData(USART1, ACK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } else { /* 发送NAK,表示数据接收失败 */ USART_SendData(USART1, NAK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } } else { /* 发送NAK,表示数据接收失败 */ USART_SendData(USART1, NAK); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } } } /** * @brief 等待发送方发送ACK或C * @retval 发送方发送的字符 */ uint8_t Ymodem_WaitACK(void) { uint8_t ch; while (1) { while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); ch = USART_ReceiveData(USART1); if (ch == ACK || ch == 'C') { return ch; } } } /** * @brief 发送数据包 * @param[in] pBuffer 存储数据的缓冲区 * @param[in] packet_length 数据包大小 * @param[in] packet_number 数据包序号 * @retval 发送结果 */ uint8_t Ymodem_SendPacket(uint8_t *pBuffer, uint16_t packet_length, uint8_t packet_number) { uint16_t crc16 = 0; uint16_t i; /* 填充数据包头 */ TxBuf[0] = SOH; TxBuf[1] = packet_number; TxBuf[2] = (255 - packet_number); /* 填充数据 */ memcpy(&TxBuf[HEAD_SIZE], pBuffer, packet_length); /* 计算CRC校验值 */ crc16 = Ymodem_CalcCRC16(&TxBuf[HEAD_SIZE], packet_length); /* 填充CRC校验值 */ TxBuf[PACKET_SIZE+HEAD_SIZE] = (crc16 >> 8) & 0xFF; TxBuf[PACKET_SIZE+HEAD_SIZE+1] = crc16 & 0xFF; /* 发送数据包 */ for (i = 0; i < (PACKET_SIZE+TAIL_SIZE); i++) { USART_SendData(USART1, TxBuf[i]); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } /* 等待接收ACK */ while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return USART_ReceiveData(USART1); } /** * @brief 计算CRC16校验值 * @param[in] pBuffer 存储数据的缓冲区 * @param[in] length 数据长度 * @retval CRC16校验值 */ uint16_t Ymodem_CalcCRC16(uint8_t *pBuffer, uint16_t length) { uint16_t crc16 = 0; uint16_t i, j; for (i = 0; i < length; i++) { crc16 ^= (uint16_t)pBuffer[i] << 8; for (j = 0; j < 8; j++) { if (crc16 & 0x8000) { crc16 = (crc16 << 1) ^ CRC16; } else { crc16 = crc16 << 1; } } } return crc16; } /** * @brief 擦除APP程序区域 */ void Ymodem_EraseAppArea(void) { FLASH_Unlock(); // 解锁Flash FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清除错误标志 FLASH_ErasePage(FLASH_APP_ADDRESS); // 擦除整个APP程序区域 FLASH_Lock(); // 上锁Flash } /** * @brief 将数据写入Flash * @param[in] addr Flash地址 * @param[in] pBuffer 存储数据的缓冲区 * @param[in] length 数据长度 */ void Ymodem_WriteToFlash(uint32_t addr, uint8_t *pBuffer, uint16_t length) { uint32_t i; uint16_t *pDst = (uint16_t *)addr; uint16_t *pSrc = (uint16_t *)pBuffer; FLASH_Unlock(); // 解锁Flash FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清除错误标志 for (i = 0; i < length/2; i++) { FLASH_ProgramHalfWord((uint32_t)pDst, *pSrc); // 写入数据 pDst++; pSrc++; } FLASH_Lock(); // 上锁Flash } ``` 注意:以上代码仅供参考,实际使用时需要根据具体情况进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值