M2的ymodem写falsh(sFLASH_WritePage)
/** - @brief Writes more than one byte to the FLASH with a single WRITE cycle - (Page WRITE sequence). - @note The number of byte can't exceed the FLASH page size. - @param pBuffer: pointer to the buffer containing the data to be written - to the FLASH. - @param WriteAddr: FLASH's internal address to write to. - @param NumByteToWrite: number of bytes to write to the FLASH, must be equal - or less than "sFLASH_PAGESIZE" value. - @retval None */ void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) { /*!< Enable the write access to the FLASH */ sFLASH_WriteEnable(); /*!< Select the FLASH: Chip Select low */ sFLASH_CS_LOW(); /*!< Send "Write to Memory " instruction */ sFLASH_SendByte(sFLASH_CMD_WRITE); /*!< Send WriteAddr high nibble address byte to write to */ sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16); //第一步 /*!< Send WriteAddr medium nibble address byte to write to */ sFLASH_SendByte((WriteAddr & 0xFF00) >> 8); //第二步 /*!< Send WriteAddr low nibble address byte to write to */ sFLASH_SendByte(WriteAddr & 0xFF); /*!< while there is data to be written on the FLASH */ while (NumByteToWrite--) //第三步 { /*!< Send the current byte */ sFLASH_SendByte(*pBuffer); /*!< Point on the next byte to be written */ pBuffer++; } /*!< Deselect the FLASH: Chip Select high */ sFLASH_CS_HIGH(); /*!< Wait the end of Flash writing */ sFLASH_WaitForWriteEnd(); } //nor_falsh,页编程
页编程两种方式:Page Program和Quad Page Program (32H)
SPI Flash仅支持页编程(GDP5Q28E页大小256字节),所有其它大批量数据的写入都是以页为单位。这里注意所说的页编程含义,页编程分为以上代码的三步。
页编程的含义恰恰就体现在第3步了,如果用户设置的“起始地址+数据长度”所确定的地址范围超过了此起始地址所在的页,地址自增不会超过页范围,而是重新回到了此页的首地进行编写。
注:擦除大小最小为一个扇区(4KB)
页回卷
许多SPI Flash设备来说,单次页编程操作通常限于页的最大容量。如果尝试写入的数据量超过了页的限制,那么超出的部分数据将不会被写入,或者可能导致写入操作失败。此外,如果未正确管理地址,写入操作可能会覆盖之前存储的数据,导致数据丢失。
如何处理超过页大小的数据写入?
1.分页写入: 首先,确定SPI Flash的页大小。 然后,将需要写入的数据分割成多个不超过页大小的数据块。 对于每个数据块,使用页编程命令将其写入到Flash的相应页中。 在写入每个数据块之前,确保指定了正确的页地址。
2.地址管理: 使用循环或递增的方式来管理地址,确保每次写入操作都指向正确的页。 在写入完一个页后,更新地址以指向下一个页。
3.错误处理: 检查写入操作的状态,确保数据已正确写入。 如果发生错误(如地址超出范围、写入失败等),则采取适当的错误处理措施。
4.考虑边界情况: 如果写入的数据量恰好是页大小的整数倍,则处理起来相对简单。 如果写入的数据量不是页大小的整数倍,则最后一个页可能只被部分写入。在这种情况下,需要特别小心以确保不会覆盖或丢失数据。
M2_BOOT的ymodem写入falsh函数(FLASH_If_Writ)
/** - @brief This function writes a data buffer in flash (data are 32-bit aligned). - @note After writing data buffer, the flash content is checked. - @param FlashAddress: start address for writing data buffer - @param Data: pointer on data buffer - @param DataLength: length of data buffer (unit is 32-bit word) - @retval 0: Data successfully written to Flash memory - 1: Error occurred while writing data in Flash memory - 2: Written Data in flash memory is different from expected one */ uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength) { uint32_t i = 0; for (i = 0; (i < DataLength) && (*FlashAddress <= (USER_FLASH_END_ADDRESS-4)); i++) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by word */ if (FLASH_ProgramWord(*FlashAddress, *(uint32_t*)(Data+i)) == FLASH_COMPLETE) { /* Check the written value */ if (*(uint32_t*)*FlashAddress != *(uint32_t*)(Data+i)) { /* Flash content doesn't match SRAM content */ return(2); } /* Increment FLASH destination address */ *FlashAddress += 4; } else { /* Error occurred while writing data in Flash memory */ return (1); } } return (0); }
上述两个代码段的主要区别在于它们操作的Flash类型、数据写入的方式以及是否直接处理Flash的物理层细节。
第一个代码段 (sFLASH_WritePage
)
-
操作对象:很可能是通过SPI或其他串行接口连接的外部串行Flash。
-
数据写入方式:按字节(byte)为单位进行写入,这反映了SPI Flash通常的写入模式。
-
地址处理:直接通过发送地址字节来指定写入位置,包括地址的高位、中位和低位字节。
-
物理层交互:直接控制Flash的片选(CS)信号、发送写入指令和地址字节,以及数据字节,这显示了与Flash硬件的直接交互。
-
错误处理:通过
sFLASH_WaitForWriteEnd()
函数等待写入操作完成,但代码中未直接显示写入失败的错误处理逻辑(可能包含在sFLASH_WaitForWriteEnd()
内部)。 -
抽象级别:较低,需要处理与Flash硬件直接交互的所有细节。
第二个代码段 (FLASH_If_Write
)
-
操作对象:可能是微控制器(MCU)内部集成的Flash存储器,或者是一个通过某种接口(如SPI、QSPI等)连接的外部Flash,但函数内部使用了HAL库或类似的抽象层来隐藏物理层细节。
-
数据写入方式:按
uint32_t
(即4字节)为单位进行写入,这可能是因为内部Flash或外部Flash接口支持按字(word)或更大的块大小进行写入。 -
地址处理:通过指针算术来递增Flash地址,而不是直接发送地址字节。
-
错误检查:在写入后验证Flash中的数据是否与预期匹配,增加了数据完整性的检查。
-
抽象级别:较高,隐藏了与Flash硬件直接交互的细节。
总结
两个代码段的主要区别在于它们操作的Flash类型、数据写入的方式、地址处理的方式、错误检查的详细程度以及抽象级别的不同。第一个代码段更适合于处理内部Flash或高度抽象化的外部Flash接口,而第二个代码段则更直接地反映了与SPI Flash等外部串行Flash的交互过程。