/* * nor_flash.c * * Created on: 16-Jan-2023 * Author: Vecmocon Technology */ #include #include #include #include "../../nor_flash.h" #include "../../platform/flash_interface.h" #define NOR_TIMEOUT 50 #define ERASE_TIMEOUT 400 static flashStatus_t flash_wEnable(void); static flashStatus_t flash_wDisable(void); static flashStatus_t flash_readStatusReg1(flash_statusReg_Struct* statusReg); static flashStatus_t flash_writeSetup(void); static flashStatus_t flash_readWIP(bool* WIP); static flashStatus_t flash_writeToPage(uint8_t* txBuff, uint8_t* rxBuff, uint16_t length); //static flashStatus_t flash_eraseCommands(uint32_t address, flash_eraseCmds command); /** * Send write enable command to NOR Flash * * @returns A status code indicating the result of the operation. */ static flashStatus_t flash_wEnable(void){ uint8_t rxBuff[1] = {0}; uint8_t txBuff[1] = {0}; txBuff[0] = WriteEnable; flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, 1); /*Variable to check Write in progress bit*/ bool wip = 0; /*Do while loop as WIP is to be read at-least once*/ uint32_t startTime = flash_msTick(); do{ /*Read WIP bit*/ retStat = flash_readWIP(&wip); if(retStat != FLASH_STATUS_OK){ break; } if((flash_msTick() - startTime) > NOR_TIMEOUT){ __asm("nop"); retStat = FLASH_STATUS_WRITE_BLOCKED; break; } }while(wip != 0 ); __asm("nop"); return retStat; } /** * Send write disable command to NOR Flash. * * @returns A status code indicating the result of the operation. */ static flashStatus_t flash_wDisable(void){ uint8_t rxBuff[1] = {0}; uint8_t txBuff[1] = {0}; txBuff[0] = WriteDisable; flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, 1); return retStat; } /** * Reads the status register 1 of the flash. * * @returns The status register 1 of the flash. */ static flashStatus_t flash_readStatusReg1(flash_statusReg_Struct* statusReg){ uint8_t rxBuff[2] = {0}; uint8_t txBuff[2] = {0}; txBuff[0] = STAT_REG_1; flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, 2); __asm("nop"); if(retStat == FLASH_STATUS_OK){ memcpy(statusReg, &rxBuff[1], sizeof(uint8_t)); } return retStat; } /** * Setup the NOR Flash for a write/erase. * * @returns A status code indicating the success of the function call. */ static flashStatus_t flash_writeSetup(void){ /*Temporary structure for status register*/ flash_statusReg_Struct tmp_flash_statusRegister = {0}; /*Variable for transaction status check*/ flashStatus_t retStat = FLASH_STATUS_ERROR; /*Send write enable command*/ retStat = flash_wEnable(); /*If all transactions are successful*/ if(retStat == FLASH_STATUS_OK){ /*Read status register 1, as status register 2 is not of importance here*/ retStat = flash_readStatusReg1(&tmp_flash_statusRegister); if(retStat == FLASH_STATUS_OK){ if(tmp_flash_statusRegister.WEL == 1) /*Write Enable Latch Bit is set i.e write is allowed*/ return FLASH_STATUS_WRITE_ALLOWED; else return FLASH_STATUS_WRITE_BLOCKED; } } return retStat; } /** * Read the Write in progress bit of status register 1 * * @param statusRegister The status register of the flash. * * @returns The status of the operation. */ static flashStatus_t flash_readWIP(bool* WIP){ /*Temporary structure for status register*/ flash_statusReg_Struct tmp_flash_statusRegister = {0}; /*Variable for transaction status check*/ flashStatus_t retStat = FLASH_STATUS_ERROR; /*Read status register 1, as status register 2 is not of importance here*/ retStat = flash_readStatusReg1(&tmp_flash_statusRegister); /*If all transactions are successful*/ if(retStat == FLASH_STATUS_OK){ *WIP = (bool)tmp_flash_statusRegister.WIP; } return retStat; } /** * Writes data to the flash memory. * * @param txBuff The buffer containing the data to be written. * @param rxBuff The buffer to receive the data. * @param length The number of bytes to be written. * * @returns The status of the write operation. */ static flashStatus_t flash_writeToPage(uint8_t* txBuff, uint8_t* rxBuff, uint16_t length){ /*Variable for transaction status*/ flashStatus_t retStat = FLASH_STATUS_ERROR; /*setup write before Page Erase*/ retStat = flash_writeSetup(); if(retStat == FLASH_STATUS_WRITE_ALLOWED){ __asm("nop"); retStat = flash_sendData(txBuff, rxBuff, length); if(retStat != FLASH_STATUS_OK){ __asm("nop"); return retStat; } /*Variable to check Write in progress bit*/ bool wip = 0; /*Do while loop as WIP is to be read at-least once*/ uint32_t startTime = flash_msTick(); do{ /*Read WIP bit*/ retStat = flash_readWIP(&wip); if(retStat != FLASH_STATUS_OK){ break; } if((flash_msTick() - startTime) > NOR_TIMEOUT){ __asm("nop"); retStat = FLASH_STATUS_WRITE_BLOCKED; break; } }while(wip != 0); } return retStat; } /*----------------------------------------------------------------------------------------------------*/ /*________________________________________________API_________________________________________________*/ /*----------------------------------------------------------------------------------------------------*/ /** * Erases the flash memory. * * @param address The address to start erasing. * @param command The erase command to use. * * @returns The status of the erase operation. */ flashStatus_t flash_eraseCommands(uint32_t address, flash_eraseCmds command){ /*Variable for transaction status*/ flashStatus_t retStat = FLASH_STATUS_ERROR; /*Do while loop as WIP is to be read at-least once*/ static volatile uint32_t startTime = 0; static volatile uint32_t timeNow = 0; /*setup write before Page Erase*/ retStat = flash_writeSetup(); /*If write is allowed*/ if(retStat == FLASH_STATUS_WRITE_ALLOWED){ uint8_t txBuff[4] = {0}; uint8_t rxBuff[4] = {0}; /*Fill the Tx buffer*/ txBuff[0] = command; /*Erase Command*/ txBuff[1] = (address >> 16) & 0xFF; /*MSB of address*/ txBuff[2] = (address >> 8) & 0xFF; /*Mid part of address*/ txBuff[3] = (address >> 0) & 0xFF; /*LSB of address*/ __asm("nop"); /*SPI Transaction*/ retStat = flash_sendData(txBuff, rxBuff, 4); if(retStat != FLASH_STATUS_OK){ __asm("nop"); return retStat; } /*Variable to check Write in progress bit*/ bool wip = 0; startTime = flash_msTick(); do{ /*Read WIP bit*/ retStat = flash_readWIP(&wip); if(retStat != FLASH_STATUS_OK){ break; } timeNow = flash_msTick(); if((timeNow - startTime) > ERASE_TIMEOUT){ __asm("nop"); retStat = FLASH_STATUS_WRITE_BLOCKED; break; } }while(wip != 0 ); } timeNow++; startTime++; __asm("nop"); return retStat; } /********************************************************************************************************************/ /** * Reads the unique ID of the flash chip. * * @param uID The unique ID of the flash chip. * * @returns The status of the operation. */ flashStatus_t flash_getUID(uint8_t* uID){ uint8_t rxBuff[21] = {0}; uint8_t txBuff[21] = {0}; txBuff[0] = UID; volatile flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, 21); __asm("nop"); if(retStat == FLASH_STATUS_OK){ memcpy(uID, &rxBuff[5], 16*sizeof(uint8_t)); } return retStat; } /** * Gets the manufacturer ID and device ID of the flash. * * @param mID The manufacturer ID. * @param dID The device ID. * * @returns The status of the operation. */ flashStatus_t flash_getMID(uint8_t* mID, uint8_t* dID){ uint8_t rxBuff[6] = {0}; uint8_t txBuff[6] = {0}; txBuff[0] = DEVICE_ID; txBuff[1] = 0xFF; txBuff[2] = 0xFF; txBuff[3] = 0; flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, 6); if(retStat == FLASH_STATUS_OK){ memcpy(mID, &rxBuff[4], sizeof(uint8_t)); memcpy(dID, &rxBuff[5], sizeof(uint8_t)); } return retStat; } /** * Read the Manufacturer ID, and ID of the flash (???) * * @param mID The manufacturer ID. * @param id The device ID. * * @returns The status of the operation. */ flashStatus_t flash_getRID(uint8_t* mID, uint16_t* id){ #define l_BUFF_SIZE 4 uint8_t rxBuff[l_BUFF_SIZE] = {0}; uint8_t txBuff[l_BUFF_SIZE] = {0}; txBuff[0] = READ_ID; flashStatus_t retStat = FLASH_STATUS_ERROR; retStat = flash_sendData(txBuff, rxBuff, l_BUFF_SIZE); if(retStat == FLASH_STATUS_OK){ memcpy(mID, &rxBuff[1], sizeof(uint8_t)); uint8_t tempBuff[2] = {0}; for (int ijk = 0; ijk < (l_BUFF_SIZE-2); ijk++){ memcpy((tempBuff + ijk), &rxBuff[(l_BUFF_SIZE - 1) - ijk], 1); } memcpy(id, tempBuff, sizeof(tempBuff)); } #undef l_BUFF_SIZE return retStat; } /** * Writes data to a page of flash. * * @param address The address of the page to write to. * @param data The data to write to the page. * @param length The length of the data to write. * * @returns The status of the write operation. */ flashStatus_t flash_programPage(uint32_t address, const uint8_t *data, uint16_t length){ /*Variable for transaction status*/ flashStatus_t retStat = FLASH_STATUS_ERROR; if(length > MAX_RW_ALLOWED){ return FLASH_STATUS_ERROR; } uint8_t txBuff[MAX_RW_ALLOWED + 4] = {0}; // uint8_t rxBuff[MAX_RW_ALLOWED + 4] = {0}; uint32_t pageStart = PAGE_ADDRESS(address); uint32_t pageEnd = pageStart + 0xFF; if((address + length) <= pageEnd+1) { /*Fill the Tx buffer*/ txBuff[0] = PageProgram; /*Page program command*/ txBuff[1] = (address >> 16) & 0xFF; /*MSB of address*/ txBuff[2] = (address >> 8) & 0xFF; /*Mid part of address*/ txBuff[3] = (address >> 0) & 0xFF; /*LSB of address*/ memcpy(&txBuff[4], data, length); /*Data bytes to program*/ /*SPI Transaction*/ __asm("nop"); retStat = flash_writeToPage(txBuff, NULL, length + 4); } else { __asm("nop"); uint8_t breakLength = (pageEnd - address) + 1; /*Fill the Tx buffer*/ txBuff[0] = PageProgram; /*Page program command*/ txBuff[1] = (address >> 16) & 0xFF; /*MSB of address*/ txBuff[2] = (address >> 8) & 0xFF; /*Mid part of address*/ txBuff[3] = (address >> 0) & 0xFF; /*LSB of address*/ memcpy(&txBuff[4], data, breakLength); /*Data bytes to program*/ /*SPI Transaction*/ __asm("nop"); retStat = flash_writeToPage(txBuff, NULL, breakLength + 4); /*Fill the Tx buffer*/ txBuff[0] = PageProgram; /*Page program command*/ txBuff[1] = ((pageEnd+1) >> 16) & 0xFF; /*MSB of address*/ txBuff[2] = ((pageEnd+1) >> 8) & 0xFF; /*Mid part of address*/ txBuff[3] = ((pageEnd+1) >> 0) & 0xFF; /*LSB of address*/ memcpy(&txBuff[4], (uint8_t*)&data[breakLength], length - breakLength); /*Data bytes to program*/ /*SPI Transaction*/ __asm("nop"); retStat |= flash_writeToPage(txBuff, NULL, (length - breakLength) + 4); } if(retStat != FLASH_STATUS_OK){ __asm("nop"); } return retStat; } /** * Reads data from the flash. * * @param address The address to read from. * @param data The data read from the flash. * @param length The length of the data to read. * * @returns The status of the read operation. */ flashStatus_t flash_readData(uint32_t address, uint8_t *data, uint16_t length){ /*Variable for transaction status*/ flashStatus_t retStat = FLASH_STATUS_ERROR; if(length > MAX_RW_ALLOWED){ return FLASH_STATUS_ERROR; } /*Variable to check Write in progress bit*/ bool wip = 0; /*Do while loop as WIP is to be read at-least once*/ uint32_t startTime = flash_msTick(); do{ /*Read WIP bit*/ retStat = flash_readWIP(&wip); if(retStat != FLASH_STATUS_OK){ break; } if((flash_msTick() - startTime) > NOR_TIMEOUT){ retStat = FLASH_BUSY_IN_OPERATION; break; } }while(wip != 0 ); __asm("nop"); uint8_t txBuff[MAX_RW_ALLOWED + 4] = {0}; uint8_t rxBuff[MAX_RW_ALLOWED + 4] = {0}; /*Fill the Tx buffer*/ txBuff[0] = ReadData; txBuff[1] = (address >> 16) & 0xFF; txBuff[2] = (address >> 8 ) & 0xFF; txBuff[3] = (address >> 0 ) & 0xFF; retStat = flash_sendData(txBuff, rxBuff, length+4); __asm("nop"); memcpy(data, &rxBuff[4], length); return retStat; }