add flash ASF4 driver
this is imported from the Atmel Start website Change-Id: I5eccb37da64c7def7b99418773d09b6d98664432
This commit is contained in:
parent
2257c6c32a
commit
9bebe583ae
|
@ -0,0 +1,36 @@
|
|||
/* Auto-generated config file hpl_nvmctrl_config.h */
|
||||
#ifndef HPL_NVMCTRL_CONFIG_H
|
||||
#define HPL_NVMCTRL_CONFIG_H
|
||||
|
||||
// <<< Use Configuration Wizard in Context Menu >>>
|
||||
|
||||
// <h> Basic Settings
|
||||
|
||||
// <o> Power Reduction Mode During Sleep
|
||||
// <0x00=> Wake On Access
|
||||
// <0x01=> Wake Up Instant
|
||||
// <0x03=> Disabled
|
||||
// <id> nvm_arch_sleepprm
|
||||
#ifndef CONF_NVM_SLEEPPRM
|
||||
#define CONF_NVM_SLEEPPRM 0
|
||||
#endif
|
||||
|
||||
// <q> AHB0 Cache Disable
|
||||
// <i> Indicate whether AHB0 cache is disable or not
|
||||
// <id> nvm_arch_cache0
|
||||
#ifndef CONF_NVM_CACHE0
|
||||
#define CONF_NVM_CACHE0 0
|
||||
#endif
|
||||
|
||||
// <q> AHB1 Cache Disable
|
||||
// <i> Indicate whether AHB1 cache is disable or not
|
||||
// <id> nvm_arch_cache1
|
||||
#ifndef CONF_NVM_CACHE1
|
||||
#define CONF_NVM_CACHE1 0
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// <<< end of configuration section >>>
|
||||
|
||||
#endif // HPL_NVMCTRL_CONFIG_H
|
14
gcc/Makefile
14
gcc/Makefile
|
@ -41,6 +41,7 @@ hpl/gclk \
|
|||
usb/device \
|
||||
hpl/oscctrl \
|
||||
gcc/gcc \
|
||||
hpl/nvmctrl \
|
||||
hpl/usb \
|
||||
hpl/core \
|
||||
hpl/cmcc
|
||||
|
@ -52,6 +53,7 @@ hpl/core/hpl_core_m4.o \
|
|||
usb/class/dfu/device/dfudf.o \
|
||||
hal/utils/src/utils_syscalls.o \
|
||||
hpl/dmac/hpl_dmac.o \
|
||||
hpl/nvmctrl/hpl_nvmctrl.o \
|
||||
gcc/system_same54.o \
|
||||
hpl/usb/hpl_usb.o \
|
||||
hal/src/hal_delay.o \
|
||||
|
@ -65,6 +67,7 @@ hpl/oscctrl/hpl_oscctrl.o \
|
|||
hpl/mclk/hpl_mclk.o \
|
||||
hpl/ramecc/hpl_ramecc.o \
|
||||
usb/usb_protocol.o \
|
||||
hal/src/hal_flash.o \
|
||||
hal/src/hal_init.o \
|
||||
gcc/gcc/startup_same54.o \
|
||||
hal/src/hal_usb_device.o \
|
||||
|
@ -81,12 +84,14 @@ usb_dfu_main.o \
|
|||
usb/device/usbdc.o \
|
||||
hal/src/hal_atomic.o
|
||||
|
||||
|
||||
OBJS_AS_ARGS += \
|
||||
"hal/src/hal_io.o" \
|
||||
"hpl/core/hpl_core_m4.o" \
|
||||
"usb/class/dfu/device/dfudf.o" \
|
||||
"hal/utils/src/utils_syscalls.o" \
|
||||
"hpl/dmac/hpl_dmac.o" \
|
||||
"hpl/nvmctrl/hpl_nvmctrl.o" \
|
||||
"gcc/system_same54.o" \
|
||||
"hpl/usb/hpl_usb.o" \
|
||||
"hal/src/hal_delay.o" \
|
||||
|
@ -100,6 +105,7 @@ OBJS_AS_ARGS += \
|
|||
"hpl/mclk/hpl_mclk.o" \
|
||||
"hpl/ramecc/hpl_ramecc.o" \
|
||||
"usb/usb_protocol.o" \
|
||||
"hal/src/hal_flash.o" \
|
||||
"hal/src/hal_init.o" \
|
||||
"gcc/gcc/startup_same54.o" \
|
||||
"hal/src/hal_usb_device.o" \
|
||||
|
@ -125,6 +131,7 @@ DEPS_AS_ARGS += \
|
|||
"hpl/ramecc/hpl_ramecc.d" \
|
||||
"hpl/core/hpl_core_m4.d" \
|
||||
"hal/utils/src/utils_syscalls.d" \
|
||||
"hpl/nvmctrl/hpl_nvmctrl.d" \
|
||||
"usb/class/dfu/device/dfudf.d" \
|
||||
"gcc/gcc/startup_same54.d" \
|
||||
"hpl/usb/hpl_usb.d" \
|
||||
|
@ -136,6 +143,7 @@ DEPS_AS_ARGS += \
|
|||
"hpl/core/hpl_init.d" \
|
||||
"hpl/pm/hpl_pm.d" \
|
||||
"usb/usb_protocol.d" \
|
||||
"hal/src/hal_flash.d" \
|
||||
"hpl/gclk/hpl_gclk.d" \
|
||||
"hal/src/hal_usb_device.d" \
|
||||
"hpl/dmac/hpl_dmac.d" \
|
||||
|
@ -199,7 +207,7 @@ $(OUTPUT_FILE_PATH): $(OBJS)
|
|||
@echo ARM/GNU C Compiler
|
||||
$(QUOTE)arm-none-eabi-gcc$(QUOTE) -x c -mthumb -DDEBUG -Os -ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
|
||||
-D__SAME54P20A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/nvmctrl" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -o "$@" "$<"
|
||||
@echo Finished building: $<
|
||||
|
||||
|
@ -208,7 +216,7 @@ $(OUTPUT_FILE_PATH): $(OBJS)
|
|||
@echo ARM/GNU Assembler
|
||||
$(QUOTE)arm-none-eabi-as$(QUOTE) -x c -mthumb -DDEBUG -Os -ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
|
||||
-D__SAME54P20A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/nvmctrl" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -o "$@" "$<"
|
||||
@echo Finished building: $<
|
||||
|
||||
|
@ -217,7 +225,7 @@ $(OUTPUT_FILE_PATH): $(OBJS)
|
|||
@echo ARM/GNU Preprocessing Assembler
|
||||
$(QUOTE)arm-none-eabi-gcc$(QUOTE) -x c -mthumb -DDEBUG -Os -ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
|
||||
-D__SAME54P20A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-I"../" -I"../config" -I"../examples" -I"../hal/include" -I"../hal/utils/include" -I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" -I"../hpl/nvmctrl" -I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" -I"../hpl/ramecc" -I"../hpl/usb" -I"../hri" -I"../" -I"../config" -I"../usb" -I"../usb/class/dfu" -I"../usb/class/dfu/device" -I"../usb/device" -I"../" -I"../CMSIS/Include" -I"../include" \
|
||||
-MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -o "$@" "$<"
|
||||
@echo Finished building: $<
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
The Flash Driver
|
||||
================
|
||||
|
||||
Flash is a re-programmable memory that retains program and data
|
||||
storage even with power off.
|
||||
|
||||
User can write or read several bytes from any valid address in a flash.
|
||||
|
||||
As to the erase/lock/unlock command, the input parameter of address should
|
||||
be a bytes address aligned with the page start, otherwise, the command will fail
|
||||
to be executed. At the meantime, the number of pages that can be locked or unlocked
|
||||
at once depends on region size of the flash. User can get the real number
|
||||
from the function return value which could be different for the different devices.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Initialization/de-initialization
|
||||
* Writing/Reading bytes
|
||||
* Locking/Unlocking/Erasing pages
|
||||
* Notifications about errors or being ready for a new command
|
||||
|
||||
Applications
|
||||
------------
|
||||
|
||||
* Mini disk which can retain program and data storage
|
||||
* Boot loader
|
||||
* Non volatile storage
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The peripheral which controls a re-programmable flash memory.
|
||||
|
||||
Concurrency
|
||||
-----------
|
||||
|
||||
N/A
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
User should pay attention to set a proper stack size in their application,
|
||||
since the driver manages a temporary buffer in stack to cache unchanged data
|
||||
when calling flash write and erase function.
|
||||
Due to flash memory architecture of SAMD21/D20/L21/L22/C20/C21/D09/D10/D11/R21,
|
||||
write operation erazes row content before each write.
|
||||
|
||||
Known issues and workarounds
|
||||
----------------------------
|
||||
|
||||
N/A
|
|
@ -0,0 +1,209 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Flash related functionality declaration.
|
||||
*
|
||||
* Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip
|
||||
* software and any derivatives exclusively with Microchip products.
|
||||
* It is your responsibility to comply with third party license terms applicable
|
||||
* to your use of third party software (including open source software) that
|
||||
* may accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
||||
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
||||
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
||||
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
||||
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
||||
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
||||
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
||||
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAL_FLASH_H_INCLUDED
|
||||
#define _HAL_FLASH_H_INCLUDED
|
||||
|
||||
#include <hpl_flash.h>
|
||||
|
||||
/**
|
||||
* \addtogroup doc_driver_hal_flash
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forward declaration of flash_descriptor. */
|
||||
struct flash_descriptor;
|
||||
|
||||
/** The callback types */
|
||||
enum flash_cb_type {
|
||||
/** Callback type for ready to accept a new command */
|
||||
FLASH_CB_READY,
|
||||
/** Callback type for error */
|
||||
FLASH_CB_ERROR,
|
||||
FLASH_CB_N
|
||||
};
|
||||
|
||||
/** \brief Prototype of callback on FLASH
|
||||
*
|
||||
*/
|
||||
typedef void (*flash_cb_t)(struct flash_descriptor *const descr);
|
||||
|
||||
/** \brief FLASH HAL callbacks
|
||||
*
|
||||
*/
|
||||
struct flash_callbacks {
|
||||
/** Callback invoked when ready to accept a new command */
|
||||
flash_cb_t cb_ready;
|
||||
/** Callback invoked when error occurs */
|
||||
flash_cb_t cb_error;
|
||||
};
|
||||
|
||||
/** \brief FLASH HAL driver struct for asynchronous access
|
||||
*/
|
||||
struct flash_descriptor {
|
||||
/** Pointer to FLASH device instance */
|
||||
struct _flash_device dev;
|
||||
/** Callbacks for asynchronous transfer */
|
||||
struct flash_callbacks callbacks;
|
||||
};
|
||||
|
||||
/** \brief Initialize the FLASH HAL instance and hardware for callback mode
|
||||
*
|
||||
* Initialize FLASH HAL with interrupt mode (uses callbacks).
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] hw Pointer to the hardware base.
|
||||
* \return Initialize status.
|
||||
*/
|
||||
int32_t flash_init(struct flash_descriptor *flash, void *const hw);
|
||||
|
||||
/** \brief Deinitialize the FLASH HAL instance
|
||||
*
|
||||
* Abort transfer, disable and reset FLASH, and deinitialize software.
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \return Deinitialze status.
|
||||
*/
|
||||
int32_t flash_deinit(struct flash_descriptor *flash);
|
||||
|
||||
/** \brief Writes a number of bytes to a page in the internal Flash
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] dst_addr Destination bytes address to write into flash
|
||||
* \param[in] buffer Pointer to a buffer where the content
|
||||
* will be written to the flash
|
||||
* \param[in] length Number of bytes to write
|
||||
* \return Write status.
|
||||
*/
|
||||
int32_t flash_write(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/** \brief Appends a number of bytes to a page in the internal Flash
|
||||
*
|
||||
* This functions never erases the flash before writing.
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] dst_addr Destination bytes address to write to flash
|
||||
* \param[in] buffer Pointer to a buffer with data to write to flash
|
||||
* \param[in] length Number of bytes to append
|
||||
* \return Append status.
|
||||
*/
|
||||
int32_t flash_append(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/** \brief Reads a number of bytes to a page in the internal Flash
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] src_addr Source bytes address to read from flash
|
||||
* \param[out] buffer Pointer to a buffer where the content
|
||||
* of the read pages will be stored
|
||||
* \param[in] length Number of bytes to read
|
||||
* \return Read status.
|
||||
*/
|
||||
int32_t flash_read(struct flash_descriptor *flash, uint32_t src_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/** \brief Register a function as FLASH transfer completion callback
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] type Callback type (\ref flash_cb_type).
|
||||
* \param[in] func Pointer to callback function.
|
||||
* \retval 0 Success
|
||||
* \retval -1 Error
|
||||
*/
|
||||
int32_t flash_register_callback(struct flash_descriptor *flash, const enum flash_cb_type type, flash_cb_t func);
|
||||
|
||||
/** \brief Execute lock in the internal flash
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be locked
|
||||
* \param[in] page_nums Number of pages to be locked
|
||||
*
|
||||
* \return Real locked numbers of pages.
|
||||
*/
|
||||
int32_t flash_lock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums);
|
||||
|
||||
/** \brief Execute unlock in the internal flash
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be unlocked
|
||||
* \param[in] page_nums Number of pages to be unlocked
|
||||
*
|
||||
* \return Real unlocked numbers of pages.
|
||||
*/
|
||||
int32_t flash_unlock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums);
|
||||
|
||||
/** \brief Execute erase in the internal flash
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be erased
|
||||
* \param[in] page_nums Number of pages to be erased
|
||||
* \retval 0 Success
|
||||
* \retval -1 Error
|
||||
*/
|
||||
int32_t flash_erase(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums);
|
||||
|
||||
/**
|
||||
* \brief Get the flash page size
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance
|
||||
*
|
||||
* \return The flash page size
|
||||
*/
|
||||
uint32_t flash_get_page_size(struct flash_descriptor *flash);
|
||||
|
||||
/**
|
||||
* \brief Get the number of flash page
|
||||
*
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
*
|
||||
* \return The flash total page numbers
|
||||
*/
|
||||
uint32_t flash_get_total_pages(struct flash_descriptor *flash);
|
||||
|
||||
/** \brief Retrieve the current driver version
|
||||
*
|
||||
* \return Current driver version.
|
||||
*/
|
||||
uint32_t flash_get_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**@}*/
|
||||
#endif /* ifndef _HAL_FLASH_H_INCLUDED */
|
|
@ -0,0 +1,265 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief FLASH related functionality declaration.
|
||||
*
|
||||
* Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip
|
||||
* software and any derivatives exclusively with Microchip products.
|
||||
* It is your responsibility to comply with third party license terms applicable
|
||||
* to your use of third party software (including open source software) that
|
||||
* may accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
||||
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
||||
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
||||
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
||||
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
||||
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
||||
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
||||
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
#ifndef _HPL_FLASH_H_INCLUDED
|
||||
#define _HPL_FLASH_H_INCLUDED
|
||||
|
||||
/**
|
||||
* \addtogroup hpl__flash__group FLASH HPL APIs
|
||||
*
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include "hpl_irq.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief FLASH device structure
|
||||
*
|
||||
* The FLASH device structure forward declaration.
|
||||
*/
|
||||
struct _flash_device;
|
||||
|
||||
/** The callback types */
|
||||
enum _flash_cb_type { FLASH_DEVICE_CB_READY, FLASH_DEVICE_CB_ERROR, FLASH_DEVICE_CB_N };
|
||||
|
||||
/**
|
||||
* \brief FLASH interrupt handlers structure
|
||||
*/
|
||||
struct _flash_callback {
|
||||
/** Ready to accept new command handler */
|
||||
void (*ready_cb)(struct _flash_device *device);
|
||||
/** Error handler */
|
||||
void (*error_cb)(struct _flash_device *device);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief FLASH descriptor device structure.
|
||||
*/
|
||||
struct _flash_device {
|
||||
struct _flash_callback flash_cb; /*!< Interrupt handers */
|
||||
struct _irq_descriptor irq; /*!< Interrupt descriptor */
|
||||
void * hw; /*!< Hardware module instance handler */
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Initialize FLASH.
|
||||
*
|
||||
* This function does low level FLASH configuration.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] hw The pointer to hardware instance
|
||||
*
|
||||
* \return Initialize status.
|
||||
*/
|
||||
int32_t _flash_init(struct _flash_device *const device, void *const hw);
|
||||
|
||||
/**
|
||||
* \brief Deinitialize FLASH.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*/
|
||||
void _flash_deinit(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Reads a number of bytes in the internal Flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] src_addr Source bytes address to read from flash
|
||||
* \param[out] buffer Pointer to a buffer where the content
|
||||
* of the read page will be stored
|
||||
* \param[in] length Number of bytes to read
|
||||
*/
|
||||
void _flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/**
|
||||
* \brief Writes a number of bytes in the internal Flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address to write into flash
|
||||
* \param[in] buffer Pointer to buffer where the data to
|
||||
* write is stored
|
||||
* \param[in] length Number of bytes to write
|
||||
*/
|
||||
void _flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/**
|
||||
* \brief Appends a number of bytes in the internal Flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address to write into flash
|
||||
* \param[in] buffer Pointer to buffer with data to write to flash
|
||||
* \param[in] length Number of bytes to write
|
||||
*/
|
||||
void _flash_append(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/** \brief Execute lock in the internal flash
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be locked
|
||||
* \param[in] page_nums Number of pages to be locked
|
||||
*
|
||||
* \return Real locked numbers of pages.
|
||||
*/
|
||||
int32_t _flash_lock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums);
|
||||
|
||||
/** \brief Execute unlock in the internal flash
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be unlocked
|
||||
* \param[in] page_nums Number of pages to be unlocked
|
||||
*
|
||||
* \return Real unlocked numbers of pages.
|
||||
*/
|
||||
int32_t _flash_unlock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums);
|
||||
|
||||
/** \brief check whether the region which is pointed by address
|
||||
* is locked
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address to check
|
||||
*
|
||||
* \return The lock status of assigned address.
|
||||
*/
|
||||
bool _flash_is_locked(struct _flash_device *const device, const uint32_t dst_addr);
|
||||
|
||||
/** \brief Execute erase in the internal flash
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address aligned with page
|
||||
* start to be erased
|
||||
* \param[in] page_nums Number of pages to be erased
|
||||
*/
|
||||
void _flash_erase(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums);
|
||||
|
||||
/**
|
||||
* \brief Get the flash page size.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*
|
||||
* \return The flash page size
|
||||
*/
|
||||
uint32_t _flash_get_page_size(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Get the numbers of flash page.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*
|
||||
* \return The flash total page numbers
|
||||
*/
|
||||
uint32_t _flash_get_total_pages(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Get the number of wait states for read and write operations.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*
|
||||
* \return The number of wait states for read and write operations
|
||||
*/
|
||||
uint8_t _flash_get_wait_state(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Set the number of wait states for read and write operations.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] state The number of wait states
|
||||
*
|
||||
*/
|
||||
void _flash_set_wait_state(struct _flash_device *const device, uint8_t state);
|
||||
|
||||
/**
|
||||
* \brief Enable/disable Flash interrupt
|
||||
*
|
||||
* param[in] device The pointer to Flash device instance
|
||||
* param[in] type The type of interrupt to disable/enable if applicable
|
||||
* param[in] state Enable or disable
|
||||
*/
|
||||
void _flash_set_irq_state(struct _flash_device *const device, const enum _flash_cb_type type, const bool state);
|
||||
|
||||
/*
|
||||
* Below RWW flash APIs are only available for device which has RWWEE
|
||||
* flash array, such as SAM C20/C21/D21/L21/L22/R30/DA1/HA1 etc.
|
||||
*/
|
||||
/**
|
||||
* \brief Get the RWWEE flash page size.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*
|
||||
* \return The flash page size
|
||||
*/
|
||||
uint32_t _rww_flash_get_page_size(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Get the total page numbers of RWWEE flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
*
|
||||
* \return The flash total page numbers
|
||||
*/
|
||||
uint32_t _rww_flash_get_total_pages(struct _flash_device *const device);
|
||||
|
||||
/**
|
||||
* \brief Reads a number of bytes in the internal RWWEE Flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] src_addr Source bytes address to read from flash
|
||||
* \param[out] buffer Pointer to a buffer where the content
|
||||
* of the read page will be stored
|
||||
* \param[in] length Number of bytes to read
|
||||
*
|
||||
* \return Read status, ERR_NONE for successful read.
|
||||
*/
|
||||
int32_t _rww_flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length);
|
||||
|
||||
/**
|
||||
* \brief Writes a number of bytes in the internal RWWEE Flash.
|
||||
*
|
||||
* \param[in] device The pointer to FLASH device instance
|
||||
* \param[in] dst_addr Destination bytes address to write into flash
|
||||
* \param[in] buffer Pointer to buffer where the data to
|
||||
* write is stored
|
||||
* \param[in] length Number of bytes to write
|
||||
*
|
||||
* \return Write status, ERR_NONE for successful write.
|
||||
*/
|
||||
int32_t _rww_flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* _HPL_FLASH_H_INCLUDED */
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Special user data area access
|
||||
*
|
||||
* Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip
|
||||
* software and any derivatives exclusively with Microchip products.
|
||||
* It is your responsibility to comply with third party license terms applicable
|
||||
* to your use of third party software (including open source software) that
|
||||
* may accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
||||
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
||||
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
||||
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
||||
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
||||
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
||||
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
||||
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HPL_USER_DATA_H_INCLUDED
|
||||
#define _HPL_USER_DATA_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Read data from user data area
|
||||
*
|
||||
* The user data area could be the area that stores user data that is not erased
|
||||
* with the flash contents, e.g.,
|
||||
* - NVM Software Calibration Area of SAM D/L/C family
|
||||
* - User Signature of SAM E/S/V 70
|
||||
*
|
||||
* \param[in] base The base address of the user area
|
||||
* \param[in] offset The byte offset of the data to be read inside the area
|
||||
* \param[out] buf Pointer to buffer to place the read data
|
||||
* \param[in] size Size of data in number of bytes
|
||||
*
|
||||
* \return Operation status or bytes read.
|
||||
* \retval ERR_NONE Data read successfully
|
||||
* \retval ERR_UNSUPPORTED_OP base address not in any supported user area
|
||||
* \retval ERR_BAD_ADDRESS offset not in right area
|
||||
* \retval ERR_INVALID_ARG offset and size exceeds the right area
|
||||
*/
|
||||
int32_t _user_area_read(const void *base, const uint32_t offset, uint8_t *buf, const uint32_t size);
|
||||
|
||||
/**
|
||||
* \brief Read no more than 32 bits data from user data area
|
||||
*
|
||||
* When reading bits, the bitfield can cross 32-bis boundaries.
|
||||
*
|
||||
* \param[in] base The base address of the user area
|
||||
* \param[in] bit_offset Offset in number of bits
|
||||
* \param[in] n_bits Number of bits to read
|
||||
* \return data read, assert if anything wrong (address not in user area
|
||||
* offset, size error, etc.).
|
||||
*/
|
||||
uint32_t _user_area_read_bits(const void *base, const uint32_t bit_offset, const uint8_t n_bits);
|
||||
|
||||
/**
|
||||
* \brief Write data to user data area
|
||||
*
|
||||
* The user data area could be the area that stores user data that is not erased
|
||||
* with the flash contents, e.g.,
|
||||
* - NVM Software Calibration Area of SAM D/L/C family
|
||||
* - User Signature of SAM E/S/V 70
|
||||
*
|
||||
* When assigned offset and size exceeds the data area, error is reported.
|
||||
*
|
||||
* \param[out] base The base address of the user area
|
||||
* \param[in] offset The offset of the data to be written inside the area
|
||||
* \param[in] buf Pointer to buffer to place the written data
|
||||
* \param[in] size Size of data in number of bytes
|
||||
*
|
||||
* \return Operation status or bytes writting.
|
||||
* \retval ERR_NONE Data written successfully
|
||||
* \retval ERR_UNSUPPORTED_OP base address not in any supported user area
|
||||
* \retval ERR_DENIED Security bit is set
|
||||
* \retval ERR_BAD_ADDRESS offset not in right area
|
||||
* \retval ERR_INVALID_ARG offset and size exceeds the right area
|
||||
*/
|
||||
int32_t _user_area_write(void *base, const uint32_t offset, const uint8_t *buf, const uint32_t size);
|
||||
|
||||
/**
|
||||
* \brief Write no more than 32 bits data to user data area
|
||||
*
|
||||
* When writting bits, the bitfield can cross 32-bis boundaries.
|
||||
*
|
||||
* \param[out] base The base address of the user area
|
||||
* \param[in] bit_offset Offset in number of bits
|
||||
* \param[in] bits The data content
|
||||
* \param[in] n_bits Number of bits to write
|
||||
* \return Operation result
|
||||
* \retval ERR_NONE Data written successfully
|
||||
* \retval ERR_UNSUPPORTED_OP base address not in any supported user area
|
||||
* \retval ERR_DENIED Security bit is set
|
||||
* \retval ERR_BAD_ADDRESS offset not in right area
|
||||
* \retval ERR_INVALID_ARG offset and size exceeds the right area
|
||||
*/
|
||||
int32_t _user_area_write_bits(void *base, const uint32_t bit_offset, const uint32_t bits, const uint8_t n_bits);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HPL_USER_DATA_H_INCLUDED */
|
|
@ -0,0 +1,314 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Flash functionality implementation.
|
||||
*
|
||||
* Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip
|
||||
* software and any derivatives exclusively with Microchip products.
|
||||
* It is your responsibility to comply with third party license terms applicable
|
||||
* to your use of third party software (including open source software) that
|
||||
* may accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
||||
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
||||
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
||||
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
||||
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
||||
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
||||
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
||||
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hal_flash.h"
|
||||
#include <utils_assert.h>
|
||||
#include <utils.h>
|
||||
#include <hal_atomic.h>
|
||||
|
||||
/**
|
||||
* \brief Driver version
|
||||
*/
|
||||
#define DRIVER_VERSION 0x00000001u
|
||||
|
||||
static void flash_ready(struct _flash_device *device);
|
||||
static void flash_error(struct _flash_device *device);
|
||||
|
||||
static int32_t flash_is_address_aligned(struct flash_descriptor *flash, const uint32_t flash_addr);
|
||||
|
||||
/**
|
||||
* \brief Initialize the FLASH HAL instance and hardware for callback mode.
|
||||
*/
|
||||
int32_t flash_init(struct flash_descriptor *flash, void *const hw)
|
||||
{
|
||||
int32_t rc;
|
||||
|
||||
ASSERT(flash && hw);
|
||||
|
||||
rc = _flash_init(&flash->dev, hw);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
flash->dev.flash_cb.ready_cb = flash_ready;
|
||||
flash->dev.flash_cb.error_cb = flash_error;
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Deinitialize the FLASH HAL instance.
|
||||
*/
|
||||
int32_t flash_deinit(struct flash_descriptor *flash)
|
||||
{
|
||||
ASSERT(flash);
|
||||
|
||||
_flash_deinit(&flash->dev);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads a number of bytes to a page in the internal Flash
|
||||
*/
|
||||
int32_t flash_read(struct flash_descriptor *flash, uint32_t src_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
ASSERT(flash && buffer && length);
|
||||
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
|
||||
/* Check if the address is valid */
|
||||
if ((src_addr > page_size * total_pages) || (src_addr + length > page_size * total_pages)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
_flash_read(&flash->dev, src_addr, buffer, length);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Updates several bytes to the internal Flash
|
||||
*/
|
||||
int32_t flash_write(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
ASSERT(flash && buffer && length);
|
||||
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
|
||||
/* Check if the address is valid */
|
||||
if ((dst_addr > page_size * total_pages) || (dst_addr + length > page_size * total_pages)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (_flash_is_locked(&flash->dev, dst_addr)) {
|
||||
return ERR_DENIED;
|
||||
}
|
||||
|
||||
_flash_write(&flash->dev, dst_addr, buffer, length);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Appends a number of bytes to a page in the internal Flash
|
||||
*/
|
||||
int32_t flash_append(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
ASSERT(flash && buffer && length);
|
||||
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
|
||||
/* Check if the address is valid */
|
||||
if ((dst_addr > page_size * total_pages) || (dst_addr + length > page_size * total_pages)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (_flash_is_locked(&flash->dev, dst_addr)) {
|
||||
return ERR_DENIED;
|
||||
}
|
||||
|
||||
_flash_append(&flash->dev, dst_addr, buffer, length);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute erase in the internal flash
|
||||
*/
|
||||
int32_t flash_erase(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)
|
||||
{
|
||||
ASSERT(flash && page_nums);
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
int32_t rc;
|
||||
|
||||
rc = flash_is_address_aligned(flash, dst_addr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
_flash_erase(&flash->dev, dst_addr, page_nums);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Register a function as FLASH transfer completion callback
|
||||
*/
|
||||
int32_t flash_register_callback(struct flash_descriptor *flash, const enum flash_cb_type type, flash_cb_t func)
|
||||
{
|
||||
ASSERT(flash);
|
||||
|
||||
switch (type) {
|
||||
case FLASH_CB_READY:
|
||||
flash->callbacks.cb_ready = func;
|
||||
break;
|
||||
|
||||
case FLASH_CB_ERROR:
|
||||
flash->callbacks.cb_error = func;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
_flash_set_irq_state(&flash->dev, (enum _flash_cb_type)type, NULL != func);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute lock in the internal flash
|
||||
*/
|
||||
int32_t flash_lock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)
|
||||
{
|
||||
ASSERT(flash && page_nums);
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
int32_t rc;
|
||||
|
||||
rc = flash_is_address_aligned(flash, dst_addr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return _flash_lock(&flash->dev, dst_addr, page_nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute unlock in the internal flash
|
||||
*/
|
||||
int32_t flash_unlock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)
|
||||
{
|
||||
ASSERT(flash && page_nums);
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
uint32_t total_pages = _flash_get_total_pages(&flash->dev);
|
||||
int32_t rc;
|
||||
|
||||
rc = flash_is_address_aligned(flash, dst_addr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return _flash_unlock(&flash->dev, dst_addr, page_nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the flash page size.
|
||||
*/
|
||||
uint32_t flash_get_page_size(struct flash_descriptor *flash)
|
||||
{
|
||||
ASSERT(flash);
|
||||
return _flash_get_page_size(&flash->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the numbers of flash page.
|
||||
*/
|
||||
uint32_t flash_get_total_pages(struct flash_descriptor *flash)
|
||||
{
|
||||
ASSERT(flash);
|
||||
return _flash_get_total_pages(&flash->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieve the current driver version
|
||||
*/
|
||||
uint32_t flash_get_version(void)
|
||||
{
|
||||
return DRIVER_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal check the address whether it is aligned
|
||||
* \param[in, out] flash Pointer to the HAL FLASH instance.
|
||||
* \param[in] flash_addr address to be check in flash
|
||||
*
|
||||
* \return whether it is valid
|
||||
* \retval 0 Valid.
|
||||
* \retval -1 Error, invalid.
|
||||
*/
|
||||
static int32_t flash_is_address_aligned(struct flash_descriptor *flash, const uint32_t flash_addr)
|
||||
{
|
||||
ASSERT(flash);
|
||||
|
||||
uint32_t page_size = _flash_get_page_size(&flash->dev);
|
||||
|
||||
/* Check if the read address not aligned to the start of a page */
|
||||
if (flash_addr & (page_size - 1)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal Ready for a new flash command
|
||||
*
|
||||
* \param[in] device The pointer to flash device structure
|
||||
*/
|
||||
static void flash_ready(struct _flash_device *device)
|
||||
{
|
||||
struct flash_descriptor *const descr = CONTAINER_OF(device, struct flash_descriptor, dev);
|
||||
if (descr->callbacks.cb_ready) {
|
||||
descr->callbacks.cb_ready(descr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal Error occurs in flash command
|
||||
*
|
||||
* \param[in] device The pointer to flash device structure
|
||||
*/
|
||||
static void flash_error(struct _flash_device *device)
|
||||
{
|
||||
struct flash_descriptor *const descr = CONTAINER_OF(device, struct flash_descriptor, dev);
|
||||
if (descr->callbacks.cb_error) {
|
||||
descr->callbacks.cb_error(descr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,695 @@
|
|||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Non-Volatile Memory Controller
|
||||
*
|
||||
* Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip
|
||||
* software and any derivatives exclusively with Microchip products.
|
||||
* It is your responsibility to comply with third party license terms applicable
|
||||
* to your use of third party software (including open source software) that
|
||||
* may accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
||||
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
||||
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
||||
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
||||
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
||||
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
||||
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
||||
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
||||
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hpl_flash.h>
|
||||
#include <hpl_user_area.h>
|
||||
#include <string.h>
|
||||
#include <utils_assert.h>
|
||||
#include <utils.h>
|
||||
#include <hpl_nvmctrl_config.h>
|
||||
|
||||
#define NVM_MEMORY ((volatile uint32_t *)FLASH_ADDR)
|
||||
#define NVMCTRL_BLOCK_PAGES (NVMCTRL_BLOCK_SIZE / NVMCTRL_PAGE_SIZE)
|
||||
#define NVMCTRL_REGIONS_NUM 32
|
||||
#define NVMCTRL_INTFLAG_ERR \
|
||||
(NVMCTRL_INTFLAG_ADDRE | NVMCTRL_INTFLAG_PROGE | NVMCTRL_INTFLAG_LOCKE | NVMCTRL_INTFLAG_ECCSE \
|
||||
| NVMCTRL_INTFLAG_NVME | NVMCTRL_INTFLAG_SEESOVF)
|
||||
/**
|
||||
* \brief NVM configuration type
|
||||
*/
|
||||
struct nvm_configuration {
|
||||
hri_nvmctrl_ctrlb_reg_t ctrla; /*!< Control B Register */
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Array of NVM configurations
|
||||
*/
|
||||
static struct nvm_configuration _nvm
|
||||
= {(CONF_NVM_CACHE0 << NVMCTRL_CTRLA_CACHEDIS0_Pos) | (CONF_NVM_CACHE1 << NVMCTRL_CTRLA_CACHEDIS1_Pos)
|
||||
| (NVMCTRL_CTRLA_PRM(CONF_NVM_SLEEPPRM))};
|
||||
|
||||
/*!< Pointer to hpl device */
|
||||
static struct _flash_device *_nvm_dev = NULL;
|
||||
|
||||
static void _flash_erase_block(void *const hw, const uint32_t dst_addr);
|
||||
static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size);
|
||||
|
||||
/**
|
||||
* \brief Initialize NVM
|
||||
*/
|
||||
int32_t _flash_init(struct _flash_device *const device, void *const hw)
|
||||
{
|
||||
uint32_t ctrla;
|
||||
|
||||
ASSERT(device && (hw == NVMCTRL));
|
||||
|
||||
device->hw = hw;
|
||||
ctrla = hri_nvmctrl_read_CTRLA_reg(hw);
|
||||
ctrla &= ~(NVMCTRL_CTRLA_CACHEDIS0 | NVMCTRL_CTRLA_CACHEDIS1 | NVMCTRL_CTRLA_PRM_Msk);
|
||||
ctrla |= _nvm.ctrla;
|
||||
hri_nvmctrl_write_CTRLA_reg(hw, ctrla);
|
||||
|
||||
_nvm_dev = device;
|
||||
NVIC_DisableIRQ(NVMCTRL_0_IRQn);
|
||||
NVIC_DisableIRQ(NVMCTRL_1_IRQn);
|
||||
NVIC_ClearPendingIRQ(NVMCTRL_0_IRQn);
|
||||
NVIC_ClearPendingIRQ(NVMCTRL_1_IRQn);
|
||||
NVIC_EnableIRQ(NVMCTRL_0_IRQn);
|
||||
NVIC_EnableIRQ(NVMCTRL_1_IRQn);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief De-initialize NVM
|
||||
*/
|
||||
void _flash_deinit(struct _flash_device *const device)
|
||||
{
|
||||
device->hw = NULL;
|
||||
NVIC_DisableIRQ(NVMCTRL_0_IRQn);
|
||||
NVIC_DisableIRQ(NVMCTRL_1_IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the flash page size.
|
||||
*/
|
||||
uint32_t _flash_get_page_size(struct _flash_device *const device)
|
||||
{
|
||||
(void)device;
|
||||
return (uint32_t)NVMCTRL_PAGE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the numbers of flash page.
|
||||
*/
|
||||
uint32_t _flash_get_total_pages(struct _flash_device *const device)
|
||||
{
|
||||
(void)device;
|
||||
return (uint32_t)hri_nvmctrl_read_PARAM_NVMP_bf(device->hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the number of wait states for read and write operations.
|
||||
*/
|
||||
uint8_t _flash_get_wait_state(struct _flash_device *const device)
|
||||
{
|
||||
return hri_nvmctrl_get_CTRLA_reg(device->hw, NVMCTRL_CTRLA_RWS_Msk);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the number of wait states for read and write operations.
|
||||
*/
|
||||
void _flash_set_wait_state(struct _flash_device *const device, uint8_t state)
|
||||
{
|
||||
hri_nvmctrl_write_CTRLA_RWS_bf(device->hw, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads a number of bytes to a page in the internal Flash.
|
||||
*/
|
||||
void _flash_read(struct _flash_device *const device, const uint32_t src_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
uint8_t *nvm_addr = (uint8_t *)NVM_MEMORY;
|
||||
uint32_t i;
|
||||
|
||||
/* Check if the module is busy */
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(device->hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
buffer[i] = nvm_addr[src_addr + i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes a number of bytes to a page in the internal Flash.
|
||||
*/
|
||||
void _flash_write(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
uint8_t tmp_buffer[NVMCTRL_BLOCK_PAGES][NVMCTRL_PAGE_SIZE];
|
||||
uint32_t block_start_addr, block_end_addr;
|
||||
uint32_t i, j, k;
|
||||
uint32_t wr_start_addr = dst_addr;
|
||||
|
||||
do {
|
||||
block_start_addr = wr_start_addr & ~(NVMCTRL_BLOCK_SIZE - 1);
|
||||
block_end_addr = block_start_addr + NVMCTRL_BLOCK_SIZE - 1;
|
||||
|
||||
/* store the erase data into temp buffer before write */
|
||||
for (i = 0; i < NVMCTRL_BLOCK_PAGES; i++) {
|
||||
_flash_read(device, block_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* temp buffer update */
|
||||
j = (wr_start_addr - block_start_addr) / NVMCTRL_PAGE_SIZE;
|
||||
k = wr_start_addr - block_start_addr - j * NVMCTRL_PAGE_SIZE;
|
||||
while ((wr_start_addr <= block_end_addr) && (length > 0)) {
|
||||
tmp_buffer[j][k] = *buffer;
|
||||
k = (k + 1) % NVMCTRL_PAGE_SIZE;
|
||||
|
||||
if (0 == k) {
|
||||
j++;
|
||||
}
|
||||
|
||||
wr_start_addr++;
|
||||
buffer++;
|
||||
length--;
|
||||
}
|
||||
|
||||
/* erase row before write */
|
||||
_flash_erase_block(device->hw, block_start_addr);
|
||||
|
||||
/* write buffer to flash */
|
||||
for (i = 0; i < NVMCTRL_BLOCK_PAGES; i++) {
|
||||
_flash_program(device->hw, block_start_addr + i * NVMCTRL_PAGE_SIZE, tmp_buffer[i], NVMCTRL_PAGE_SIZE);
|
||||
}
|
||||
} while (block_end_addr < (wr_start_addr + length - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Appends a number of bytes in the internal Flash.
|
||||
*/
|
||||
void _flash_append(struct _flash_device *const device, const uint32_t dst_addr, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
uint32_t page_start_addr = dst_addr & ~(NVMCTRL_PAGE_SIZE - 1);
|
||||
uint32_t size;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (dst_addr != page_start_addr) {
|
||||
/* Need to write some data to the end of a page */
|
||||
size = min(length, NVMCTRL_PAGE_SIZE - (dst_addr - page_start_addr));
|
||||
_flash_program(device->hw, dst_addr, buffer, size);
|
||||
page_start_addr += NVMCTRL_PAGE_SIZE;
|
||||
offset += size;
|
||||
}
|
||||
|
||||
while (offset < length) {
|
||||
size = min(length - offset, NVMCTRL_PAGE_SIZE);
|
||||
_flash_program(device->hw, page_start_addr, buffer + offset, size);
|
||||
page_start_addr += NVMCTRL_PAGE_SIZE;
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute erase in the internal flash
|
||||
*/
|
||||
void _flash_erase(struct _flash_device *const device, uint32_t dst_addr, uint32_t page_nums)
|
||||
{
|
||||
uint8_t tmp_buffer[NVMCTRL_PAGE_SIZE];
|
||||
uint32_t block_start_addr;
|
||||
uint32_t i;
|
||||
|
||||
block_start_addr = dst_addr & ~(NVMCTRL_BLOCK_SIZE - 1);
|
||||
|
||||
memset(tmp_buffer, 0xFF, NVMCTRL_PAGE_SIZE);
|
||||
|
||||
/* when address is not aligned with block start address */
|
||||
if (dst_addr != block_start_addr) {
|
||||
block_start_addr += NVMCTRL_BLOCK_SIZE;
|
||||
for (i = 0; i < NVMCTRL_BLOCK_PAGES - 1; i++) {
|
||||
_flash_write(device, dst_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
|
||||
|
||||
if (--page_nums == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dst_addr += NVMCTRL_PAGE_SIZE;
|
||||
|
||||
if (dst_addr == block_start_addr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (page_nums >= NVMCTRL_BLOCK_PAGES) {
|
||||
_flash_erase_block(device->hw, block_start_addr);
|
||||
block_start_addr += NVMCTRL_BLOCK_SIZE;
|
||||
page_nums -= NVMCTRL_BLOCK_PAGES;
|
||||
}
|
||||
|
||||
if (page_nums != 0) {
|
||||
for (i = 0; i < page_nums; i++) {
|
||||
_flash_write(device, block_start_addr, tmp_buffer, NVMCTRL_PAGE_SIZE);
|
||||
block_start_addr += NVMCTRL_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute lock in the internal flash
|
||||
*/
|
||||
int32_t _flash_lock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
|
||||
{
|
||||
uint32_t region_pages;
|
||||
uint32_t block_start_addr;
|
||||
|
||||
region_pages = (uint32_t)FLASH_SIZE / (NVMCTRL_REGIONS_NUM * NVMCTRL_PAGE_SIZE);
|
||||
block_start_addr = dst_addr & ~(NVMCTRL_BLOCK_SIZE - 1);
|
||||
|
||||
if ((page_nums != region_pages) || (dst_addr != block_start_addr)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(device->hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr);
|
||||
hri_nvmctrl_write_CTRLB_reg(device->hw, NVMCTRL_CTRLB_CMD_LR | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
|
||||
return (int32_t)FLASH_SIZE / (NVMCTRL_REGIONS_NUM * NVMCTRL_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute unlock in the internal flash
|
||||
*/
|
||||
int32_t _flash_unlock(struct _flash_device *const device, const uint32_t dst_addr, uint32_t page_nums)
|
||||
{
|
||||
uint32_t region_pages;
|
||||
uint32_t block_start_addr;
|
||||
|
||||
region_pages = (uint32_t)FLASH_SIZE / (NVMCTRL_REGIONS_NUM * NVMCTRL_PAGE_SIZE);
|
||||
block_start_addr = dst_addr & ~(NVMCTRL_BLOCK_SIZE - 1);
|
||||
|
||||
if ((page_nums != region_pages) || (dst_addr != block_start_addr)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(device->hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
hri_nvmctrl_write_ADDR_reg(device->hw, dst_addr);
|
||||
hri_nvmctrl_write_CTRLB_reg(device->hw, NVMCTRL_CTRLB_CMD_UR | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
|
||||
return (int32_t)FLASH_SIZE / (NVMCTRL_REGIONS_NUM * NVMCTRL_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check whether the region which is pointed by address
|
||||
*/
|
||||
bool _flash_is_locked(struct _flash_device *const device, const uint32_t dst_addr)
|
||||
{
|
||||
uint16_t region_id;
|
||||
|
||||
/* Get region for given page */
|
||||
region_id = dst_addr / (FLASH_SIZE / NVMCTRL_REGIONS_NUM);
|
||||
|
||||
return !(hri_nvmctrl_get_RUNLOCK_reg(device->hw, 1 << region_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable/disable Flash interrupt
|
||||
*/
|
||||
void _flash_set_irq_state(struct _flash_device *const device, const enum _flash_cb_type type, const bool state)
|
||||
{
|
||||
ASSERT(device);
|
||||
|
||||
if (FLASH_DEVICE_CB_READY == type) {
|
||||
hri_nvmctrl_write_INTEN_DONE_bit(device->hw, state);
|
||||
} else if (FLASH_DEVICE_CB_ERROR == type) {
|
||||
if (state) {
|
||||
hri_nvmctrl_write_INTEN_reg(device->hw, NVMCTRL_INTFLAG_ERR);
|
||||
} else {
|
||||
hri_nvmctrl_clear_INTEN_reg(device->hw, NVMCTRL_INTFLAG_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal erase a row in flash
|
||||
* \param[in] hw The pointer to hardware instance
|
||||
* \param[in] dst_addr Destination page address to erase
|
||||
*/
|
||||
static void _flash_erase_block(void *const hw, const uint32_t dst_addr)
|
||||
{
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
/* Set address and command */
|
||||
hri_nvmctrl_write_ADDR_reg(hw, dst_addr);
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_EB | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal write a page in flash
|
||||
* \param[in] hw The pointer to hardware instance
|
||||
* \param[in] dst_addr Destination page address to write
|
||||
* \param[in] buffer Pointer to buffer where the data to
|
||||
* write is stored
|
||||
* \param[in] size The size of data to write to a page
|
||||
*/
|
||||
static void _flash_program(void *const hw, const uint32_t dst_addr, const uint8_t *buffer, const uint16_t size)
|
||||
{
|
||||
uint32_t *ptr_read = (uint32_t *)buffer;
|
||||
uint32_t nvm_address = dst_addr / 4;
|
||||
uint16_t i;
|
||||
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_PBC | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
/* Writes to the page buffer must be 32 bits, perform manual copy
|
||||
* to ensure alignment */
|
||||
for (i = 0; i < size; i += 4) {
|
||||
NVM_MEMORY[nvm_address++] = *ptr_read;
|
||||
ptr_read++;
|
||||
}
|
||||
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
hri_nvmctrl_write_ADDR_reg(hw, dst_addr);
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_WP | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal NVM interrupt handler
|
||||
*
|
||||
* \param[in] p The pointer to interrupt parameter
|
||||
*/
|
||||
static void _nvm_interrupt_handler(struct _flash_device *device)
|
||||
{
|
||||
void *const hw = device->hw;
|
||||
|
||||
if (hri_nvmctrl_get_INTFLAG_DONE_bit(hw)) {
|
||||
hri_nvmctrl_clear_INTFLAG_DONE_bit(hw);
|
||||
|
||||
if (NULL != device->flash_cb.ready_cb) {
|
||||
device->flash_cb.ready_cb(device);
|
||||
}
|
||||
} else if (hri_nvmctrl_read_INTFLAG_reg(hw) && ~NVMCTRL_INTFLAG_ERR) {
|
||||
hri_nvmctrl_clear_INTFLAG_reg(hw, NVMCTRL_INTFLAG_ERR);
|
||||
|
||||
if (NULL != device->flash_cb.error_cb) {
|
||||
device->flash_cb.error_cb(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal NVM 0 interrupt handler
|
||||
*/
|
||||
void NVMCTRL_0_Handler(void)
|
||||
{
|
||||
_nvm_interrupt_handler(_nvm_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal NVM 1 interrupt handler
|
||||
*/
|
||||
void NVMCTRL_1_Handler(void)
|
||||
{
|
||||
_nvm_interrupt_handler(_nvm_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
The NVM User Row contains calibration data that are automatically read at device
|
||||
power on.
|
||||
The NVM User Row can be read at address 0x804000.
|
||||
|
||||
The first eight 32-bit words (32 Bytes) of the Non Volatile Memory (NVM) User
|
||||
Page contain calibration data that are automatically read at device power-on.
|
||||
The remaining 480 Bytes can be used for storing custom parameters.
|
||||
*/
|
||||
#ifndef _NVM_USER_ROW_BASE
|
||||
#define _NVM_USER_ROW_BASE 0x804000
|
||||
#endif
|
||||
#define _NVM_USER_ROW_N_BITS 4096
|
||||
#define _NVM_USER_ROW_N_BYTES (_NVM_USER_ROW_N_BITS / 8)
|
||||
#define _NVM_USER_ROW_END (((uint8_t *)_NVM_USER_ROW_BASE) + _NVM_USER_ROW_N_BYTES - 1)
|
||||
#define _IS_NVM_USER_ROW(b) \
|
||||
(((uint8_t *)(b) >= (uint8_t *)(_NVM_USER_ROW_BASE)) && ((uint8_t *)(b) <= (uint8_t *)(_NVM_USER_ROW_END)))
|
||||
#define _IN_NVM_USER_ROW(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_USER_ROW_END))
|
||||
|
||||
/*
|
||||
The NVM Software Calibration Area can be read at address 0x00800080.
|
||||
The NVM Software Calibration Area can not be written.
|
||||
*/
|
||||
#ifndef _NVM_SW_CALIB_AREA_BASE
|
||||
#define _NVM_SW_CALIB_AREA_BASE 0x00800080
|
||||
#endif
|
||||
#define _NVM_SW_CALIB_AREA_N_BITS 45
|
||||
#define _NVM_SW_CALIB_AREA_N_BYTES (_NVM_SW_CALIB_AREA_N_BITS / 8)
|
||||
#define _NVM_SW_CALIB_AREA_END (((uint8_t *)_NVM_SW_CALIB_AREA_BASE) + _NVM_SW_CALIB_AREA_N_BYTES - 1)
|
||||
#define _IS_NVM_SW_CALIB_AREA(b) \
|
||||
(((uint8_t *)(b) >= (uint8_t *)_NVM_SW_CALIB_AREA_BASE) && ((uint8_t *)(b) <= (uint8_t *)_NVM_SW_CALIB_AREA_END))
|
||||
#define _IN_NVM_SW_CALIB_AREA(b, o) (((uint8_t *)(b) + (o)) <= (uint8_t *)(_NVM_SW_CALIB_AREA_END))
|
||||
|
||||
/**
|
||||
* \internal Read left aligned data bits
|
||||
* \param[in] base Base address for the data
|
||||
* \param[in] bit_offset Offset for the bitfield start
|
||||
* \param[in] n_bits Number of bits in the bitfield
|
||||
*/
|
||||
static inline uint32_t _user_area_read_l32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
|
||||
const uint8_t n_bits)
|
||||
{
|
||||
return base[bit_offset >> 5] & ((1 << n_bits) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal Read right aligned data bits
|
||||
* \param[in] base Base address for the data
|
||||
* \param[in] bit_offset Offset for the bitfield start
|
||||
* \param[in] n_bits Number of bits in the bitfield
|
||||
*/
|
||||
static inline uint32_t _user_area_read_r32_bits(const volatile uint32_t *base, const uint32_t bit_offset,
|
||||
const uint8_t n_bits)
|
||||
{
|
||||
return (base[bit_offset >> 5] >> (bit_offset & 0x1F)) & ((1 << n_bits) - 1);
|
||||
}
|
||||
|
||||
int32_t _user_area_read(const void *base, const uint32_t offset, uint8_t *buf, uint32_t size)
|
||||
{
|
||||
ASSERT(buf);
|
||||
|
||||
/** Parameter check. */
|
||||
if (_IS_NVM_USER_ROW(base)) {
|
||||
if (!_IN_NVM_USER_ROW(base, offset)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
/* Cut off if request too many bytes */
|
||||
if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (_IS_NVM_SW_CALIB_AREA(base)) {
|
||||
if (!_IN_NVM_SW_CALIB_AREA(base, offset)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
/* Cut off if request too many bytes */
|
||||
if (!_IN_NVM_SW_CALIB_AREA(base, offset + size - 1)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
} else {
|
||||
return ERR_UNSUPPORTED_OP;
|
||||
}
|
||||
|
||||
/* Copy data */
|
||||
memcpy(buf, ((uint8_t *)base) + offset, size);
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
uint32_t _user_area_read_bits(const void *base, const uint32_t bit_offset, const uint8_t n_bits)
|
||||
{
|
||||
volatile uint32_t *mem_base = (volatile uint32_t *)base;
|
||||
uint32_t l_off, l_bits;
|
||||
uint32_t r_off, r_bits;
|
||||
|
||||
/** Parameter check. */
|
||||
if (_IS_NVM_USER_ROW(base)) {
|
||||
ASSERT(_IN_NVM_USER_ROW(base, bit_offset >> 3) && _IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3));
|
||||
} else if (_IS_NVM_SW_CALIB_AREA(base)) {
|
||||
ASSERT(_IN_NVM_SW_CALIB_AREA(base, bit_offset >> 3)
|
||||
&& _IN_NVM_SW_CALIB_AREA(base, (bit_offset + n_bits - 1) >> 3));
|
||||
} else {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
/* Since the bitfield can cross 32-bits boundaries,
|
||||
* left and right bits are read from 32-bit aligned address
|
||||
* and then combined together. */
|
||||
l_off = bit_offset & (~(32 - 1));
|
||||
r_off = l_off + 32;
|
||||
l_bits = 32 - (bit_offset & (32 - 1));
|
||||
|
||||
if (n_bits > l_bits) {
|
||||
r_bits = n_bits - l_bits;
|
||||
} else {
|
||||
l_bits = n_bits;
|
||||
r_bits = 0;
|
||||
}
|
||||
|
||||
return _user_area_read_r32_bits(mem_base, bit_offset, l_bits)
|
||||
+ (_user_area_read_l32_bits(mem_base, r_off, r_bits) << l_bits);
|
||||
}
|
||||
|
||||
/** \internal Write 4096-bit user row
|
||||
* \param[in] _row Pointer to 4096-bit user row data.
|
||||
*/
|
||||
static int32_t _user_row_write_exec(const uint32_t *_row)
|
||||
{
|
||||
Nvmctrl *hw = NVMCTRL;
|
||||
uint32_t ctrla = hri_nvmctrl_read_CTRLA_reg(NVMCTRL);
|
||||
uint32_t i;
|
||||
|
||||
/* Denied if Security Bit is set */
|
||||
if (DSU->STATUSB.bit.PROT) {
|
||||
return ERR_DENIED;
|
||||
}
|
||||
|
||||
/* Do Save */
|
||||
|
||||
/* - Prepare. */
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
hri_nvmctrl_clear_CTRLA_WMODE_bf(NVMCTRL, NVMCTRL_CTRLA_WMODE_Msk);
|
||||
|
||||
/* - Erase AUX row. */
|
||||
hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)_NVM_USER_ROW_BASE);
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_EP | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) { /* 32 Quad words for User row: 32 * (4 bytes * 4) = 512 bytes */
|
||||
/* - Page buffer clear & write. */
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_PBC | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
*(((uint32_t *)NVMCTRL_USER) + i * 4) = _row[i * 4];
|
||||
*(((uint32_t *)NVMCTRL_USER) + i * 4 + 1) = _row[i * 4 + 1];
|
||||
*(((uint32_t *)NVMCTRL_USER) + i * 4 + 2) = _row[i * 4 + 2];
|
||||
*(((uint32_t *)NVMCTRL_USER) + i * 4 + 3) = _row[i * 4 + 3];
|
||||
|
||||
/* - Write AUX row. */
|
||||
hri_nvmctrl_write_ADDR_reg(hw, (hri_nvmctrl_addr_reg_t)(_NVM_USER_ROW_BASE + i * 16));
|
||||
hri_nvmctrl_write_CTRLB_reg(hw, NVMCTRL_CTRLB_CMD_WQW | NVMCTRL_CTRLB_CMDEX_KEY);
|
||||
while (!hri_nvmctrl_get_STATUS_READY_bit(hw)) {
|
||||
/* Wait until this module isn't busy */
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore CTRLA */
|
||||
hri_nvmctrl_write_CTRLA_reg(NVMCTRL, ctrla);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
int32_t _user_area_write(void *base, const uint32_t offset, const uint8_t *buf, const uint32_t size)
|
||||
{
|
||||
uint32_t _row[NVMCTRL_PAGE_SIZE / 4]; /* Copy of user row. */
|
||||
|
||||
/** Parameter check. */
|
||||
if (_IS_NVM_USER_ROW(base)) {
|
||||
if (!_IN_NVM_USER_ROW(base, offset)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
} else if (!_IN_NVM_USER_ROW(base, offset + size - 1)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (_IS_NVM_SW_CALIB_AREA(base)) {
|
||||
return ERR_DENIED;
|
||||
} else {
|
||||
return ERR_UNSUPPORTED_OP;
|
||||
}
|
||||
|
||||
memcpy(_row, base, NVMCTRL_PAGE_SIZE); /* Store previous data. */
|
||||
memcpy((uint8_t *)_row + offset, buf, size); /* Modify with buf data. */
|
||||
|
||||
return _user_row_write_exec(_row);
|
||||
}
|
||||
|
||||
int32_t _user_area_write_bits(void *base, const uint32_t bit_offset, const uint32_t bits, const uint8_t n_bits)
|
||||
{
|
||||
uint32_t _row[NVMCTRL_PAGE_SIZE / 4]; /* Copy of user row. */
|
||||
uint32_t l_off, l_bits;
|
||||
uint32_t r_off, r_bits;
|
||||
|
||||
/** Parameter check. */
|
||||
if (_IS_NVM_USER_ROW(base)) {
|
||||
if (!_IN_NVM_USER_ROW(base, bit_offset >> 3)) {
|
||||
return ERR_BAD_ADDRESS;
|
||||
} else if (!_IN_NVM_USER_ROW(base, (bit_offset + n_bits - 1) >> 3)) {
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (_IS_NVM_SW_CALIB_AREA(base)) {
|
||||
return ERR_DENIED;
|
||||
} else {
|
||||
return ERR_UNSUPPORTED_OP;
|
||||
}
|
||||
|
||||
/* Since the bitfield can cross 32-bits boundaries,
|
||||
* left and right bits are splitted for 32-bit aligned address
|
||||
* and then saved. */
|
||||
l_off = bit_offset & (~(32 - 1));
|
||||
r_off = l_off + 32;
|
||||
l_bits = 32 - (bit_offset & (32 - 1));
|
||||
|
||||
if (n_bits > l_bits) {
|
||||
r_bits = n_bits - l_bits;
|
||||
} else {
|
||||
l_bits = n_bits;
|
||||
r_bits = 0;
|
||||
}
|
||||
|
||||
memcpy(_row, base, NVMCTRL_PAGE_SIZE); /* Store previous data. */
|
||||
|
||||
if (l_bits) {
|
||||
uint32_t l_mask = ((1 << l_bits) - 1) << (bit_offset & (32 - 1));
|
||||
_row[bit_offset >> 5] &= ~l_mask;
|
||||
_row[bit_offset >> 5] |= (bits << (bit_offset & (32 - 1))) & l_mask;
|
||||
}
|
||||
|
||||
if (r_bits) {
|
||||
uint32_t r_mask = (1 << r_bits) - 1;
|
||||
_row[r_off >> 5] &= ~r_mask;
|
||||
_row[r_off >> 5] |= bits >> l_bits;
|
||||
}
|
||||
|
||||
return _user_row_write_exec(_row);
|
||||
}
|
Loading…
Reference in New Issue