S29GL128P norflash 读写擦除问题
最近用stm32调试S29GL128P norflash,遇到一些细节问题,和大家分享一下,希望大家能少走弯路。 因为这个项目是半路接手,已经有产品了,我的任务就是在此基础上升级改bug.之前的程序写的不是特别好 从新整理一下。 ????由于S29GL128P用的是成品模块,卖家送的驱动历程。开始没有深究,直接调用测试一下读写,可以用就没有深究。测试代码如下: /****************************************************************************** * Function Name : FSMC_NOR_Test * Description : NOR Test * Input : None * Output : None * Return : None * Attention???????? : None *******************************************************************************/ void FSMC_NOR_Test(void) { uint16_t index; NOR_IDTypeDef NOR_ID; ? /* Initialize the FSMC NOR Flash Interface */ FSMC_NOR_Init(); /* Set the NOR read modes */ FSMC_NOR_ReturnToReadMode(); ? FSMC_NOR_ReadID(&NOR_ID); printf("Nor Flash ID = %04X,%04X,%04X ",NOR_ID.Manufacturer_Code,NOR_ID.Device_Code1, NOR_ID.Device_Code2,NOR_ID.Device_Code3 ); FSMC_NOR_ReturnToReadMode(); ? if( ( NOR_ID.Manufacturer_Code == 0x0001 ) && (NOR_ID.Device_Code1 == 0x227E) && ???? ( NOR_ID.Device_Code2 == 0x2212 ) && ( NOR_ID.Device_Code3 == 0x2200 ) ) { printf("Type = AM29LV128MLrn"); } else if ( ( NOR_ID.Manufacturer_Code == 0x0001 ) && ( NOR_ID.Device_Code1 == 0x227E ) && ???????? ( NOR_ID.Device_Code2 == 0x2221 ) && ( NOR_ID.Device_Code3 == 0x2201 ) ) { ???? printf("Type = S29GL128Prn"); } else if ( ( NOR_ID.Manufacturer_Code == 0x0020 ) && ( NOR_ID.Device_Code1 == 0x227E ) && ???????? ( NOR_ID.Device_Code2 == 0x2220 ) && ( NOR_ID.Device_Code3 == 0x2200 ) ) { ???? printf("Type = M29DW128Frn"); } else { ???? printf("Type = Unknowrn"); } ? /* Erase the NOR memory block to write on */ FSMC_NOR_EraseBlock(WRITE_READ_ADDR); ? /* Write data to FSMC NOR memory */ /* Fill the buffer to send */ for (index = 0; index < BUFFER_SIZE; index++ ) { TxBuffer[index] = index + 0x1234;//index+0x3210 } ? FSMC_NOR_WriteBuffer(TxBuffer,WRITE_READ_ADDR,BUFFER_SIZE); ? /* Read data from FSMC NOR memory */ FSMC_NOR_ReadBuffer(RxBuffer,BUFFER_SIZE); ???? // ????for (index = 0; index < BUFFER_SIZE; index++ ) // { // printf("TxBuffer[%d]=%drn",index,TxBuffer[index]); // ????????printf("RxBuffer[%d]=%drn",RxBuffer[index]); // } // ???? if( memcmp( (char*)TxBuffer,(char*)RxBuffer,BUFFER_SIZE ) == 0 ) { printf("Nor Flash is OK rn"); } else { printf("Nor Flash is error rn"); } } 如果大家用过norflash 一定知道这个驱动程序是谁写的,我发现最早的版本是火牛开发板带的,被卖家都走当历程送了。 网上现在有两个版本的驱动程序 一个是火牛的 一个是armfly出的驱动。重底层开始写可能就不会出这个问题了。 所以坑爹之路就这么开始了。 开始查看数据手册,看看存储结构如下: 从这个表上可以知道如下信息: 1、S29GL128P有128Mbit位存储 也就是有 128/8 = 8M byte 的存储大小 (目前使用过的存储器 都是按位计数的) 2、S29GL128P一个扇区有128Kb的字节数/或者64个字 这里面的字和我们通常说的字不一样 这里的 word = 2byte 3、S29GL128P 有128个扇区 扇区0-扇区127 4、扇区0的范围是 0x000000 - 0x00ffff 也就是说有64K个地址 ,对应128K 所以每个地址能保存16bit 5、起始地址是 0x000000 结束地址是0x7fffff 6、S29GL128P写之前要擦除,擦除最小单位是一个扇区 128Kb ? 有了这些知识就可以使用了 /****************************************************************************** * Function Name : FSMC_NOR_ReadID * Description : Reads NOR memory's Manufacturer and Device Code. * Input : - NOR_ID: pointer to a NOR_IDTypeDef structure which will hold * the Manufacturer and Device Code. * Output : None * Return : None * Attention???????? : None *******************************************************************************/ void FSMC_NOR_ReadID(NOR_IDTypeDef* NOR_ID) { NOR_WRITE(ADDR_SHIFT(0x0555),0x00AA); NOR_WRITE(ADDR_SHIFT(0x02AA),0x0055); NOR_WRITE(ADDR_SHIFT(0x0555),0x0090); ? NOR_ID->Manufacturer_Code = *(vu16 *) ADDR_SHIFT(0x0000); NOR_ID->Device_Code1 = *(vu16 *) ADDR_SHIFT(0x0001); NOR_ID->Device_Code2 = *(vu16 *) ADDR_SHIFT(0x000E); NOR_ID->Device_Code3 = *(vu16 *) ADDR_SHIFT(0x000F); } ? /******************************************************************************* * Function Name : FSMC_NOR_EraseBlock * Description : Erases the specified Nor memory block. * Input : - BlockAddr: address of the block to erase. * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_EraseBlock(uint32_t BlockAddr) { NOR_WRITE(ADDR_SHIFT(0x0555),0x0080); NOR_WRITE(ADDR_SHIFT(0x0555),0x0055); NOR_WRITE((NOR_FLASH_START_ADDR + BlockAddr),0x30); ? return (FSMC_NOR_GetStatus(BlockErase_Timeout)); } ? /******************************************************************************* * Function Name : FSMC_NOR_EraseChip * Description : Erases the entire chip. * Input : None * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_EraseChip(void) { NOR_WRITE(ADDR_SHIFT(0x0555),0x0010); ? return (FSMC_NOR_GetStatus(ChipErase_Timeout)); } ? /****************************************************************************** * Function Name : FSMC_NOR_WriteHalfWord * Description : Writes a half-word to the NOR memory. * Input : - WriteAddr : NOR memory internal address to write to. * - Data : Data to write. * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_WriteHalfWord(uint32_t WriteAddr,uint16_t Data) { NOR_WRITE(ADDR_SHIFT(0x0555),0x00A0); NOR_WRITE((NOR_FLASH_START_ADDR + WriteAddr),Data); ? return (FSMC_NOR_GetStatus(Program_Timeout)); } ? /******************************************************************************* * Function Name : FSMC_NOR_WriteBuffer * Description : Writes a half-word buffer to the FSMC NOR memory. * Input : - pBuffer : pointer to buffer. * - WriteAddr : NOR memory internal address from which the data * will be written. * - NumHalfwordToWrite : number of Half words to write. * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_WriteBuffer(uint16_t* pBuffer,uint32_t WriteAddr,uint32_t NumHalfwordToWrite) { NOR_Status status = NOR_ONGOING; ? do { /* Transfer data to the memory */ status = FSMC_NOR_WriteHalfWord(WriteAddr,*pBuffer++); WriteAddr = WriteAddr + 2; NumHalfwordToWrite--; } while((status == NOR_SUCCESS) && (NumHalfwordToWrite != 0)); ? return (status); } ? /******************************************************************************* * Function Name : FSMC_NOR_ProgramBuffer * Description : Writes a half-word buffer to the FSMC NOR memory. This function nor a0-a15 stm32 a1-a16 * must be used only with S29GL128P NOR memory. * Input : - pBuffer : pointer to buffer. * - WriteAddr: NOR memory internal address from which the data * will be written. * - NumHalfwordToWrite: number of Half words to write. * The maximum allowed value is 32 Half words (64 bytes). * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_ProgramBuffer(uint16_t* pBuffer,uint32_t NumHalfwordToWrite) { uint32_t lastloadedaddress = 0x00; uint32_t currentaddress = 0x00; uint32_t endaddress = 0x00; ? /* Initialize variables */ currentaddress = WriteAddr; endaddress = WriteAddr + NumHalfwordToWrite - 1; lastloadedaddress = WriteAddr; ? /* Issue unlock command sequence */ NOR_WRITE(ADDR_SHIFT(0x00555),0x00AA); ? NOR_WRITE(ADDR_SHIFT(0x02AA),0x0055); ? /* Write Write Buffer Load Command */ NOR_WRITE(ADDR_SHIFT(WriteAddr),0x0025); NOR_WRITE(ADDR_SHIFT(WriteAddr),(NumHalfwordToWrite - 1)); ? /* Load Data into NOR Buffer */ while(currentaddress <= endaddress) { /* Store last loaded address & data value (for polling) */ lastloadedaddress = currentaddress; ? NOR_WRITE(ADDR_SHIFT(currentaddress),*pBuffer++); currentaddress += 1; } ? NOR_WRITE(ADDR_SHIFT(lastloadedaddress),0x29); ? return(FSMC_NOR_GetStatus(Program_Timeout)); } ? /****************************************************************************** * Function Name : FSMC_NOR_ReadHalfWord * Description : Reads a half-word from the NOR memory. * Input : - ReadAddr : NOR memory internal address to read from. * Output : None * Return : Half-word read from the NOR memory * Attention???????? : None *******************************************************************************/ uint16_t FSMC_NOR_ReadHalfWord(uint32_t ReadAddr) { NOR_WRITE(ADDR_SHIFT(0x00555),0x00AA); NOR_WRITE(ADDR_SHIFT(0x002AA),0x0055); NOR_WRITE((NOR_FLASH_START_ADDR + ReadAddr),0x00F0 ); ? return (*(vu16 *)((NOR_FLASH_START_ADDR + ReadAddr))); } ? /******************************************************************************* * Function Name : FSMC_NOR_ReadBuffer * Description : Reads a block of data from the FSMC NOR memory. * Input : - pBuffer : pointer to the buffer that receives the data read * from the NOR memory. * - ReadAddr : NOR memory internal address to read from. * - NumHalfwordToRead : number of Half word to read. * Output : None * Return : None * Attention???????? : None *******************************************************************************/ void FSMC_NOR_ReadBuffer(uint16_t* pBuffer,uint32_t ReadAddr,uint32_t NumHalfwordToRead) { NOR_WRITE(ADDR_SHIFT(0x0555),0x00F0); ? for(; NumHalfwordToRead != 0x00; NumHalfwordToRead--) /* while there is data to read */ { /* Read a Halfword from the NOR */ *pBuffer++ = *(vu16 *)((NOR_FLASH_START_ADDR + ReadAddr)); ReadAddr = ReadAddr + 2; } } ? /****************************************************************************** * Function Name : FSMC_NOR_ReturnToReadMode * Description : Returns the NOR memory to Read mode. * Input : None * Output : None * Return : NOR_SUCCESS * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_ReturnToReadMode(void) { NOR_WRITE(NOR_FLASH_START_ADDR,0x00F0); ? return (NOR_SUCCESS); } ? /****************************************************************************** * Function Name : FSMC_NOR_Reset * Description : Returns the NOR memory to Read mode and resets the errors in * the NOR memory Status Register. * Input : None * Output : None * Return : NOR_SUCCESS * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_Reset(void) { NOR_WRITE(ADDR_SHIFT(0x00555),0x0055); NOR_WRITE(NOR_FLASH_START_ADDR,0x00F0); ? return (NOR_SUCCESS); } ? /****************************************************************************** * Function Name : FSMC_NOR_GetStatus * Description : Returns the NOR operation status. * Input : - Timeout: NOR progamming Timeout * Output : None * Return : NOR_Status:The returned value can be: NOR_SUCCESS,NOR_ERROR * or NOR_TIMEOUT * Attention???????? : None *******************************************************************************/ NOR_Status FSMC_NOR_GetStatus(uint32_t Timeout) { uint16_t val1 = 0x00,val2 = 0x00; NOR_Status status = NOR_ONGOING; uint32_t timeout = Timeout; ? /* Poll on NOR memory Ready/Busy signal ------------------------------------*/ while((GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6) != RESET) && (timeout > 0)) { timeout--; } ? timeout = Timeout; ? while((GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6) == RESET) && (timeout > 0)) { timeout--; } ? /* Get the NOR memory operation status -------------------------------------*/ while((Timeout != 0x00) && (status != NOR_SUCCESS)) { Timeout--; ? ???? /* Read DQ6 and DQ5 */ val1 = *(vu16 *)(NOR_FLASH_START_ADDR); val2 = *(vu16 *)(NOR_FLASH_START_ADDR); ? /* If DQ6 did not toggle between the two reads then return NOR_Success */ if((val1 & 0x0040) == (val2 & 0x0040)) { return NOR_SUCCESS; } ? if((val1 & 0x0020) != 0x0020) { status = NOR_ONGOING; } ? val1 = *(vu16 *)(NOR_FLASH_START_ADDR); val2 = *(vu16 *)(NOR_FLASH_START_ADDR); ? if((val1 & 0x0040) == (val2 & 0x0040)) { return NOR_SUCCESS; } else if((val1 & 0x0020) == 0x0020) { return NOR_ERROR; } } ? if(Timeout == 0x00) { status = NOR_TIMEOUT; } ? /* Return the operation status */ return (status); } ? ? 调用上述函数就可以对flash进行操作了。 ? 按照手册上写的写入之前要擦除 #define WRITE_READ_ADDR 0x000000 /* Erase the NOR memory block to write on */ FSMC_NOR_EraseBlock(WRITE_READ_ADDR); FSMC_NOR_WriteBuffer(TxBuffer,BUFFER_SIZE); /* Read data from FSMC NOR memory */ FSMC_NOR_ReadBuffer(RxBuffer,BUFFER_SIZE); ? 结果完全正确 ? ? 按照手册上写的写入第二个扇区试试 #define WRITE_READ_ADDR 0x010000 /* Erase the NOR memory block to write on */ FSMC_NOR_EraseBlock(WRITE_READ_ADDR); FSMC_NOR_WriteBuffer(TxBuffer,BUFFER_SIZE); ? 错误。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 What??? 按照手册上写的为啥会错。。。。 纠结了好久 各种找资料 就两个版本程序 没有太大帮助。 出这个错误本应该能发现的 但是由于期间有其他的事情要做耽搁几天,回来按着手册来写,就想不到问题所在了 还好今天灵光一闪 想到问题了所在了 原来是地址没有对齐 由于stm32 FSMC 16位模式时 地址线是错开的 也就是说 在我正常的地址要左移一位在写进去才是真实的地址 #define WRITE_READ_ADDR (0x010000<<1) /* Erase the NOR memory block to write on */ FSMC_NOR_EraseBlock(WRITE_READ_ADDR); FSMC_NOR_WriteBuffer(TxBuffer,BUFFER_SIZE); ? 这样就对了。 万恶的历程,能不走点心,不要单纯的测试一个扇区了,要说明啊,卖flash的客服给点力啊!别跟小白一样啊 ? 大家做事情一定要做完 在去干别的 要不然真的很坑啊 ,地址移位这个问题 做的时候已经发现了,但是中耽搁了, 在捡起,潜意识里已经认为做完了,就没有在忘上面想,结果浪费了好几天的时间。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |