You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
6.5 KiB
C
196 lines
6.5 KiB
C
/***************************************************************************//**
|
|
* @file
|
|
* @brief Source file for RAIL Flash Data functionality
|
|
*******************************************************************************
|
|
* # License
|
|
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
|
|
*******************************************************************************
|
|
*
|
|
* SPDX-License-Identifier: Zlib
|
|
*
|
|
* The licensor of this software is Silicon Laboratories Inc.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <string.h>
|
|
|
|
#include "rail_types.h"
|
|
#include "rail.h"
|
|
|
|
#include "flash_data_config.h"
|
|
#include "flash_data.h"
|
|
|
|
#include "em_msc.h"
|
|
|
|
#define FLASH_DEFAULT_VALUE 0xFFFFFFFFUL
|
|
|
|
// The entire size of FD_Structure must be the size of a flash page.
|
|
#define FLASH_DATA_BYTE_ARRAY_LENGTH ((uint32_t)FLASH_DATA_PAGE_SIZE \
|
|
- sizeof(uint32_t) \
|
|
- sizeof(uint32_t))
|
|
|
|
// This structure is mapped to flash.
|
|
typedef struct FD_Structure {
|
|
uint32_t prefix;
|
|
uint32_t length;
|
|
uint8_t byteArray[FLASH_DATA_BYTE_ARRAY_LENGTH];
|
|
} FD_Structure_t;
|
|
|
|
/**
|
|
* FLASH_DATA_BASE_ADDR: The base address in flash available for saving
|
|
* application data.
|
|
*
|
|
* Note: USERDATA_BASE can be used from em_device.h, but know that this
|
|
* location may already be used by other software.
|
|
*/
|
|
#ifndef FLASH_DATA_BASE_ADDR
|
|
// Align this array to a flash page boundary.
|
|
__ALIGNED(FLASH_DATA_PAGE_SIZE)
|
|
const FD_Structure_t flash_data_structure =
|
|
{
|
|
FLASH_DATA_PREFIX,
|
|
sizeof(FLASH_DATA_BYTE_ARRAY),
|
|
FLASH_DATA_BYTE_ARRAY
|
|
};
|
|
#define FLASH_DATA_BASE_ADDR (&flash_data_structure)
|
|
#endif
|
|
|
|
/**
|
|
* Flash layout (with a uint32_t pointer pointing to the base flash address):
|
|
* ptr[0] = (uint32_t)FLASH_DATA_PREFIX
|
|
* ptr[1] = (uint32_t)byte_array_length
|
|
* ptr[2] = first word of byte array (i.e. first 4 bytes of the byte array)
|
|
* ...
|
|
* ptr[byte_array_length_rounded / 4] = remaining bytes of the byte array
|
|
*
|
|
* Note: When writing to flash, byte_array_length is rounded up to the nearest
|
|
* multiple of 4 (e.g. byte_array_length_rounded) in order to only write
|
|
* uint32_t word sizes to flash.
|
|
* For example, if byte_array_length = 8, 4 uint32_t flash locations will be used:
|
|
* ptr[0] = (uint32_t)FLASH_DATA_PREFIX
|
|
* ptr[1] = 0x00000008 // length = 8 bytes
|
|
* ptr[2] = 0xXXXXXXXX // bytes 0-3 of the byte array
|
|
* ptr[3] = 0xXXXXXXXX // bytes 4-7 of the byte array
|
|
* For example, if byte_array_length = 9, 5 uint32_t flash locations will be used:
|
|
* ptr[0] = (uint32_t)FLASH_DATA_PREFIX
|
|
* ptr[1] = 0x00000009 // length = 9 bytes
|
|
* ptr[2] = 0xXXXXXXXX // bytes 0-3 of the byte array
|
|
* ptr[3] = 0xXXXXXXXX // bytes 4-7 of the byte array
|
|
* ptr[4] = 0x------XX // byte 8 of the byte array + 3 irrelevant bytes
|
|
*/
|
|
volatile FD_Structure_t *pFlash = (FD_Structure_t *)(FLASH_DATA_BASE_ADDR);
|
|
static const uint32_t flashPrefix = FLASH_DATA_PREFIX;
|
|
|
|
RAIL_Status_t FD_ReadData(uint8_t **data, uint32_t *len)
|
|
{
|
|
if (NULL == data) {
|
|
return RAIL_STATUS_INVALID_PARAMETER; // invalid input pointer
|
|
}
|
|
if (FD_GetLength() == 0UL) {
|
|
return RAIL_STATUS_INVALID_CALL; // no application data exists
|
|
}
|
|
// Return valid data length and address (ignoring flashPrefix).
|
|
if (NULL != len) {
|
|
*len = pFlash->length;
|
|
}
|
|
*data = (uint8_t *)(&(pFlash->byteArray[0]));
|
|
return RAIL_STATUS_NO_ERROR;
|
|
}
|
|
|
|
uint32_t FD_GetLength(void)
|
|
{
|
|
uint32_t result = 0UL;
|
|
if (pFlash->prefix == flashPrefix
|
|
&& pFlash->length != FLASH_DEFAULT_VALUE) {
|
|
result = pFlash->length;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint32_t FD_GetMaxLength(void)
|
|
{
|
|
return FLASH_DATA_BYTE_ARRAY_LENGTH;
|
|
}
|
|
|
|
RAIL_Status_t FD_WriteData(uint8_t *data, uint32_t len)
|
|
{
|
|
RAIL_Status_t status = RAIL_STATUS_INVALID_PARAMETER;
|
|
MSC_Status_TypeDef mscStatus;
|
|
|
|
// Ensure that the data to be saved fits in the flash page size,
|
|
// minus size of prefix (FLASH_DATA_PREFIX),
|
|
// minus size of data length (len),
|
|
// minus 0-3 bytes for uint32_t word alignment.
|
|
if ((NULL == data)
|
|
|| (len > (uint32_t)FLASH_DATA_PAGE_SIZE
|
|
- sizeof(flashPrefix) - sizeof(len) - (len % 4))) {
|
|
return RAIL_STATUS_INVALID_PARAMETER; // data too large
|
|
}
|
|
|
|
// Erase flash page,
|
|
// write data prefix (FLASH_DATA_PREFIX) to flash,
|
|
// write data length (len) to flash,
|
|
// and write the data (data) to flash.
|
|
MSC_Init();
|
|
mscStatus = MSC_ErasePage((uint32_t *)pFlash);
|
|
if (mscReturnOk == mscStatus) {
|
|
mscStatus = MSC_WriteWord((uint32_t *)&(pFlash->prefix),
|
|
&flashPrefix,
|
|
sizeof(flashPrefix));
|
|
if (mscReturnOk == mscStatus) {
|
|
mscStatus = MSC_WriteWord((uint32_t *)&(pFlash->length),
|
|
&len,
|
|
sizeof(len));
|
|
if (mscReturnOk == mscStatus) {
|
|
// Ensure 4-byte alignment; round up.
|
|
uint32_t lenAligned = (len + 0x00000003UL) & 0xFFFFFFFCUL;
|
|
mscStatus = MSC_WriteWord((uint32_t *)(&(pFlash->byteArray[0])),
|
|
data,
|
|
lenAligned);
|
|
if (mscReturnOk == mscStatus) {
|
|
status = RAIL_STATUS_NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MSC_Deinit();
|
|
|
|
// Clear the prefix in case it was written without the data itself.
|
|
if (RAIL_STATUS_NO_ERROR != status) {
|
|
FD_ClearData();
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
RAIL_Status_t FD_ClearData(void)
|
|
{
|
|
RAIL_Status_t status = RAIL_STATUS_INVALID_CALL; // no valid data in flash
|
|
MSC_Status_TypeDef mscStatus;
|
|
|
|
MSC_Init();
|
|
mscStatus = MSC_ErasePage((uint32_t *)pFlash);
|
|
if (mscReturnOk == mscStatus) {
|
|
status = RAIL_STATUS_NO_ERROR;
|
|
}
|
|
MSC_Deinit();
|
|
|
|
return status;
|
|
}
|