STM32CubeWL/Drivers/BSP/Components/mx25l4006/mx25l4006.c

552 lines
15 KiB
C

/**
******************************************************************************
* @file mx25l4006.c
* @Author MCD Application Team
* @brief This file provides the MX25L4006 drivers.
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "mx25l4006.h"
/** @addtogroup BSP
* @{
*/
/** @addtogroup Components
* @{
*/
/** @defgroup MX25L4006 MX25L4006
* @{
*/
#define MX25L4006_SPI_TIMEOUT 1000U /* 1000ms */
/** @defgroup MX25L4006_Exported_Functions MX25L4006 Exported Functions
* @{
*/
/**
* @brief Get Flash information
* @param pInfo pointer to Device Info structure
* @retval Status
* - MX25L4006_OK
*/
int32_t MX25L4006_GetFlashInfo(MX25L4006_Info_t *pInfo)
{
/* Configure the structure with the memory configuration */
pInfo->FlashSize = MX25L4006_FLASH_SIZE;
pInfo->EraseSectorSize = MX25L4006_BLOCK_64K;
pInfo->EraseSectorsNumber = (MX25L4006_FLASH_SIZE / MX25L4006_BLOCK_64K);
pInfo->EraseSubSectorSize = MX25L4006_SECTOR_4K;
pInfo->EraseSubSectorNumber = (MX25L4006_FLASH_SIZE / MX25L4006_SECTOR_4K);
pInfo->EraseSubSector1Size = MX25L4006_SECTOR_4K;
pInfo->EraseSubSector1Number = (MX25L4006_FLASH_SIZE / MX25L4006_SECTOR_4K);
pInfo->ProgPageSize = MX25L4006_PAGE_SIZE;
pInfo->ProgPagesNumber = (MX25L4006_FLASH_SIZE / MX25L4006_PAGE_SIZE);
return MX25L4006_OK;
}
/**
* @brief Wait until Write In Progress (WIP) bit is equal to 0
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_AUTOPOLLING
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_AutoPollingMemReady(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t statusRegister;
uint8_t cmd = MX25L4006_READ_STATUS_REG_CMD;
/* Send the command */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
do
{
if (HAL_SPI_Receive(Ctx, &statusRegister, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_AUTOPOLLING;
}
} while ((ret == MX25L4006_OK) && ((statusRegister & MX25L4006_SR_WIP) != 0U));
}
return ret;
}
/**
* @brief Wait until Write Enable Latch (WEL) bit is set to 1
* @param Component object pointer
* @retval Status
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_AutoPollingMemReadyToWrite(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t statusRegister;
uint8_t cmd = MX25L4006_READ_STATUS_REG_CMD;
/* Send the command */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
do
{
if (HAL_SPI_Receive(Ctx, &statusRegister, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
} while ((ret == MX25L4006_OK) && ((statusRegister & MX25L4006_SR_WREN) != MX25L4006_SR_WREN));
}
return ret;
}
/* Read/Write Array Commands (3 Byte Address Command Set) *********************/
/**
* @brief Reads an amount of data from the memory.
* @param Ctx Component object pointer
* @param pData Pointer to data to be read
* @param ReadAddr Read start address
* @param Size Size of data to read in Byte
* @retval Status
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_Read(SPI_HandleTypeDef *Ctx, uint8_t *pData, uint32_t ReadAddr, uint16_t Size)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[4U];
/* Send the command */
cmd[0U] = MX25L4006_READ_CMD;
cmd[1U] = (uint8_t)((ReadAddr & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)((ReadAddr & 0x0000FF00U) >> 8);
cmd[3U] = (uint8_t)(ReadAddr & 0x000000FFU);
if (HAL_SPI_Transmit(Ctx, cmd, 4U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
if (HAL_SPI_Receive(Ctx, pData, Size, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
}
return ret;
}
/**
* @brief Reads an amount of data from the memory.
* @param Ctx Component object pointer
* @param pData Pointer to data to be read
* @param ReadAddr Read start address
* @param Size Size of data to read in Byte
* @retval Status
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_FastRead(SPI_HandleTypeDef *Ctx, uint8_t *pData, uint32_t ReadAddr, uint16_t Size)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[5U];
/* Send the command */
cmd[0U] = MX25L4006_FAST_READ_CMD;
cmd[1U] = (uint8_t)((ReadAddr & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)((ReadAddr & 0x0000FF00U) >> 8);
cmd[3U] = (uint8_t)(ReadAddr & 0x000000FFU);
cmd[4U] = 0xAAU; /* Dummy */
if (HAL_SPI_Transmit(Ctx, cmd, 5U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
if (HAL_SPI_Receive(Ctx, pData, Size, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
}
return ret;
}
/**
* @brief Writes an amount of data to the SPI memory.
* For 256 bytes page program, the 8 least significant address bits byte
* should be set to 0 this function otherwise returns MX25L4006_ERROR_ADDRESS
* @param Ctx Component object pointer
* @param pData Pointer to data to be written
* @param WriteAddr Write start address
* @param Size Size of data to write. Range 1 ~ 256
* @retval Status
* - MX25L4006_ERROR_ADDRESS
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_ERROR_TRANSMIT
* - MX25L4006_OK
*/
int32_t MX25L4006_PageProgram(SPI_HandleTypeDef *Ctx, uint8_t *pData, uint32_t WriteAddr, uint16_t Size)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[4U];
if ((Size >= MX25L4006_PAGE_SIZE) && ((WriteAddr & 0x000000FFU) != 0U))
{
ret = MX25L4006_ERROR_ADDRESS;
}
else
{
/* 1- Send Page Program (PP) command */
cmd[0U] = MX25L4006_PAGE_PROG_CMD;
cmd[1U] = (uint8_t)((WriteAddr & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)((WriteAddr & 0x0000FF00U) >> 8);
cmd[3U] = (uint8_t)(WriteAddr & 0x000000FFU);
if (HAL_SPI_Transmit(Ctx, cmd, 4U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
/* 2- Send the data */
if (HAL_SPI_Transmit(Ctx, pData, Size, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_TRANSMIT;
}
}
}
return ret;
}
/**
* @brief Erases the specified sector of the SPI memory
* MX25L4006 support 4K size block erase command.
* @param Ctx Component object pointer
* @param SectorAddress Sector address to erase
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_SectorErase(SPI_HandleTypeDef *Ctx, uint32_t SectorAddress)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[4U];
/* 1- Send Sector Erase (SE) for erasing the data of chosen block */
cmd[0U] = MX25L4006_SECTOR_ERASE_4K_CMD;
cmd[1U] = (uint8_t)((SectorAddress & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)((SectorAddress & 0x0000FF00U) >> 8);
cmd[3U] = (uint8_t)(SectorAddress & 0x000000FFU);
if (HAL_SPI_Transmit(Ctx, cmd, 4U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
return MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief Erases the specified block of the SPI memory
* MX25L4006 64K size block erase command.
* @param Ctx Component object pointer
* @param BlockAddress Block address to erase
* @param BlockSize Block size to erase
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_BlockErase(SPI_HandleTypeDef *Ctx, uint32_t BlockAddress, MX25L4006_Erase_t BlockSize)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[4U];
/* Setup erase command */
switch (BlockSize)
{
default :
case MX25L4006_ERASE_4K :
cmd[0U] = MX25L4006_SECTOR_ERASE_4K_CMD;
break;
case MX25L4006_ERASE_64K :
cmd[0U] = MX25L4006_BLOCK_ERASE_64K_CMD;
break;
case MX25L4006_ERASE_CHIP :
return MX25L4006_ChipErase(Ctx);
break;
}
/* 1- Send Block Erase (BE) for erasing the data of chosen block */
cmd[1U] = (uint8_t)((BlockAddress & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)((BlockAddress & 0x0000FF00U) >> 8);
cmd[3U] = (uint8_t)(BlockAddress & 0x000000FFU);
if (HAL_SPI_Transmit(Ctx, cmd, 4U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief Whole chip erase of the SPI memory
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_ChipErase(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_CHIP_ERASE_CMD;
/* 1- Send Chip Erase (CE) command to erase whole chip */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/* Register/Setting Commands **************************************************/
/**
* @brief This function sets the (WEL) Write Enable Latch bit
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_WriteEnable(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_WRITE_ENABLE_CMD;
/* Send Write Enable (WREN) command to set Write Enable Latch (WEL) bit in the Status Register */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief This function resets the (WEL) Write Enable Latch bit
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_WriteDisable(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_WRITE_DISABLE_CMD;
/* Send Write Disable (WRDI) command to unset Write Enable Latch (WEL) bit in the Status Register */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
return MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief Read Flash Status register
* @param Ctx Component object pointer
* @param Value pointer to status register value
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_OK
*/
int32_t MX25L4006_ReadStatusRegister(SPI_HandleTypeDef *Ctx, uint8_t *Value)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_READ_STATUS_REG_CMD;
/* Send the command */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
if (HAL_SPI_Receive(Ctx, Value, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
}
return ret;
}
/**
* @brief Write Flash Status register value
* @param Ctx Component object pointer
* @param Value Status register value
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_WriteStatusRegister(SPI_HandleTypeDef *Ctx, uint8_t Value)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[2U];
/* Send the command */
cmd[0U] = MX25L4006_WRITE_STATUS_REG_CMD;
cmd[1U] = Value;
if (HAL_SPI_Transmit(Ctx, cmd, 2U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief Deep power down
* The device is not active and all Write/Program/Erase instruction are ignored.
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_EnterDeepPowerDown(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_DEEP_POWER_DOWN_CMD;
/* Send Deep Powerdown (DP) command to enter deep powerdown mode */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/**
* @brief Release Deep power down
* The device is now active and all Write/Program/Erase instruction are available.
* @param Ctx Component object pointer
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_OK
*/
int32_t MX25L4006_ReleaseDeepPowerDown(SPI_HandleTypeDef *Ctx)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_RELEASE_FROM_DEEP_POWER_DOWN_CMD;
/* Send Release from Deep Powerdown (RDP) command to exit from deep powerdown mode */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
return ret;
}
/* ID/Security Commands *******************************************************/
/**
* @brief Read Flash 3 Byte IDs
* Manufacturer ID, Memory type, Memory density
* @param Ctx Component object pointer
* @param ID pointer to flash id value
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_OK
*/
int32_t MX25L4006_ReadID(SPI_HandleTypeDef *Ctx, uint8_t *ID)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd = MX25L4006_READ_ID_CMD;
/* Send the command */
if (HAL_SPI_Transmit(Ctx, &cmd, 1U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
if (HAL_SPI_Receive(Ctx, ID, 3U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
}
return ret;
}
/**
* @brief Reads an amount of data from the memory
* @param Ctx Component object pointer
* @param pData Pointer to data to be read
* @param ReadAddr Read start address
* @param Size Size of data to read in Byte
* @retval Status
* - MX25L4006_ERROR_COMMAND
* - MX25L4006_ERROR_RECEIVE
* - MX25L4006_OK
*/
int32_t MX25L4006_ReadSFDP(SPI_HandleTypeDef *Ctx, uint8_t *pData, uint32_t ReadAddr, uint16_t Size)
{
int32_t ret = MX25L4006_OK;
uint8_t cmd[5U];
/* Send the command */
cmd[0U] = MX25L4006_READ_SERIAL_FLASH_DISCO_PARAM_CMD;
cmd[1U] = (uint8_t)((ReadAddr & 0x00FF0000U) >> 16);
cmd[2U] = (uint8_t)(ReadAddr & 0x0000FF00U) >> 8;
cmd[3U] = (uint8_t)(ReadAddr & 0x000000FFU);
cmd[4U] = 0xAAU; /* Dummy */
if (HAL_SPI_Transmit(Ctx, cmd, 5U, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_COMMAND;
}
else
{
if (HAL_SPI_Receive(Ctx, pData, Size, MX25L4006_SPI_TIMEOUT) != HAL_OK)
{
ret = MX25L4006_ERROR_RECEIVE;
}
}
return ret;
}