14. System Memory¶
14.1. Random Access Memory¶
14.1.1. Code Location¶
The complete BLE stack (both the Controller and Host) is in the system’s Read Only Memory (ROM) and it is executed from there as well.
Application code on the other hand may reside either in on-chip OTP or in external QSPI Flash. It can be executed either in place (cached mode) or be copied into RAM and then executed from there (mirrored mode).
14.1.1.1. Execution Modes¶
There are two execution modes for the application code:
(a) Cached Mode, where the application code is in the OTP or Flash and is executed in place using the 16KB cache RAM.
(b) Mirrored mode, where the entire application code is copied into the RAM from where it is executed.
Depending on the execution mode, the available RAM size for Application Data varies.
- In Cached Mode, code is executed in place from either OTP or Flash memory. There is 128KB of RAM available for data and any code that is moved there
- In Mirrored Mode, both application code and data are eventually located in the platform’s 144KB RAM. In this mode the 16KB cache RAM is added to the 128KB of normal RAM
Warning
The SDK has been developed to support only cached mode from flash.
14.1.2. Data Heaps¶
All data variables are allocated from one of two memory heaps.
Application Heap
The Application Heap is used to allocate memory for every RTOS task including the OS itself. Its size is dependent on the actual application and must be configured together with the RTOS configuration.
The retained variables that need to be maintained when the system is sleeping should be clearly declared using the PRIVILEGED_DATA
or INITIALISED_PRIVILEGED_DATA
attributes, which inform the linker that these elements must be placed in the data sections that will be retained when the system goes to sleep.
BLE Stack Heap
The BLE Stack has its own dedicated Data Heap. Its size and retention scheme is pre-configured in the SmartSnippets™ DA1468x SDK and should not be changed by the application developer.
14.1.3. Optimal Memory Size¶
The Application heap and retained memory configuration is application-dependent and so must be optimized by the developer.
Optimizing Heap size is done empirically by configuring the system with a big heap and then measuring Heap ratio usage while executing final application. FreeRTOS provides some advanced methods of monitoring RTOS Heap usage during the development phase. Refer to section 17.2 for more details about the optimization of the Heap size.
14.2. Non Volatile Memory Storage¶
The SmartSnippets™ DA1468x SDK defines a set of storage classification rules that enable the good design of memory storage requirements and memory budget estimation. It is essential for the developer to have a clear understanding of their requirements for the following elements that could use non-volatile storage:
- System Parameters that need to be stored in NVM (e.g. device address)
- Firmware upgrade (dual images)
- App-specific binaries (e.g. pre-recorded audio messages)
- Logging (e.g. event logs)
- Application data (e.g. sensor values, statistics, authentication keys)
For each storage type a corresponding, dedicated region is mapped in the Flash partition. Each region is identified by a partition ID. When the NVMS Adapter makes read/write accesses to storage it uses the partition ID and an offset. Additional details can be found in the NVMS Adapter section, 16.4.
The SmartSnippets™ DA1468x SDK defines the following memory partitions (in a non-SUOTA build) to manage the storage:
- (FW) Firmware Image Region
- (PARAMS) Parameters Region
- (BIN) Binaries Region
- (LOG) Logging of events or values
- (DATA) Generic data Region, Statistics etc.
The exact Memory mapping depends on the actual Flash device (i.e. size, sector size) used on the board. It needs to be specified during compilation in <sdk_root_directory>/config/1M/partition_table.h
. A default partition table is provided with the SmartSnippetsTM DA1468x SDK which fits in DK QSPI Flash (1Mbytes with sectors of 4KB), the actual definition of which is shown in Code 22:
PARTITION2( 0x000000 , 0x07F000 , NVMS_FIRMWARE_PART , 0 )
PARTITION2( 0x07F000 , 0x001000 , NVMS_PARTITION_TABLE , PARTITION_FLAG_READ_ONLY )
PARTITION2( 0x080000 , 0x010000 , NVMS_PARAM_PART , 0 )
PARTITION2( 0x090000 , 0x030000 , NVMS_BIN_PART , 0 )
PARTITION2( 0x0C0000 , 0x020000 , NVMS_LOG_PART , 0 )
PARTITION2( 0x0E0000 , 0x020000 , NVMS_GENERIC_PART , PARTITION_FLAG_VES )
14.2.1. QSPI Flash Support¶
This section describes the QSPI Flash support in SmartSnippets™ DA1468x SDK and the steps the user need to follow in order to add support for new Flash types.
The SDK supports by default three different flash types:
- Winbond: W25Q80EW, 8Mbit
- Gigadevice: GD25LQ80B, 8Mbit
- Macronix: MX25U51245G, 512 Mbit
These three devices have been tested with the SDK release using the modes of operation listed below. The default device is the Winbond W25Q80EW because this is the flash type that is mounted on the Pro and Basic DK boards. Another device can be selected by changing the macros shown in section 14.2.1.4.
Section 14.2.1.7 explains how to add other flash devices that have the same boot sequence as the three supported devices. The user will need to check carefully the Flash command set and verify correct read/write/erase operation at the desired clock speed.
Flash types with a different boot sequence can be used on the DA14681-SDK by modifying the QSPI Flash Initialization Section (QFIS) in the OTP of the DA1468x. This method is explained in [Ref_10].
14.2.1.1. Modes of operation and configuration¶
The SmartSnippets™ DA1468x SDK supports two modes of operation: Autodetect mode and Manual mode. The Autodetect mode can detect the flash type at runtime, while the Manual mode involves explicitly declaring the flash used in the project at compile time.
Note
The Manual Mode is the default and recommended mode. The Autodetect Mode will greatly increase code size and Retained RAM usage, and may prevent the project fitting in RAM.
14.2.1.2. Autodetect Mode¶
The Autodetect mode detects the flash that is used in runtime, and selects the proper flash driver to use. The Autodetect mode can only detect among the flash devices officially supported by the SmartSnippetsTM DA1468x SDK. If no match is found, a default driver will be used (which may or may not work).
Since the Autodetect mode needs to select the driver to use in runtime, it has the code for all the drivers in the binary. It also keeps the selected driver’s configuration parameters in Retained RAM. Therefore, the Autodetect mode is NOT recommended for production builds.
14.2.1.3. Manual Mode¶
The Manual mode simply consists of a hardcoded declaration of the flash driver to use. Therefore, only the code of the selected driver needs to be compiled in the binary, and there is no need to retain the driver parameters in Retained RAM, since the compiler optimizes them out. This mode is suitable for Production builds.
14.2.1.4. Flash Configuration¶
The Flash subsystem is configured using the macros shown in Table 39, which must be defined in the config/custom_config_qspi.h
file of the project:
qspi_flash_config_t field | Description |
---|---|
dg_configFLASH_AUTODETECT | Default: 0. This macro, if set, enables the Autodetect Mode. Please note, that the use of this macro is NOT recommended. |
dg_configFLASH_HEADER_FILE | This macro must be defined as a string named after the header file to use for the specific flash driver. E.g. qspi_w25q80ew.h, qspi_gd25lq80b.h, qspi_mx25u51245.h.This header file must be either one of the qspi_<part_nr>.h header files found in <sdk_root_directory>/sdk/bsp/memory/include , or a header file under the project’s folder, as long as this path is in the compiler’s include path (see the document section 10.2.1.7 about adding support for new flash devices). |
dg_configFLASH_MANUFACTURER_ID | This macro must be defined to the Flash manufacturer ID, as defined in the respective driver header file (e.g. WINBOND_ID , GIGADEVICE_ID , MACRONIX_ID ). |
dg_configFLASH_DEVICE_TYPE | This macro must be defined to the corresponding device type macro, as defined in the driver header file (e.g. W25Q80EW , GD25LQ_SERIES , MX25U_MX66U_SERIES ). |
dg_configFLASH_DENSITY | This macro must be defined to the corresponding device density macro, as defined in the driver header file (e.g. W25Q_8Mb_SIZE , GD25LQ80B_SIZE , MX25U51245_SIZE ). |
When the system is in Manual Mode (dg_configFLASH_AUTODETECT == 0
), which is the default, all the three macros above are defined in sdk/config/bsp_defaults.h
to enable the default flash used, which is the Winbond W25Q80EW
.
14.2.1.5. Code Structure¶
The QSPI Flash access functionality is implemented in qspi_automode.c
and qspi_automode.h
file. Common command definitions and functions needed for all devices are declared in qspi_common.h
. Device specific code is defined in header files named as qspi_<flash device name>.h
.
The code in qspi_automode.c
(and in some other parts of the SmartSnippets™ DA1468x SDK, as well), calls device-specific functions and uses device-specific values to properly initialize the flash device. Each driver header file provides an instance of the structure qspi_flash_config_t
to the main driver, containing all the device-specific function pointers and variables.
14.2.1.6. The flash configuration structure qspi_flash_config_t¶
Each driver header file must provide its own instance of qspi_flash_config_t
. Please note that this instance must be named with a unique name, like flash_<device name>_config
, since all the device header files are included in the qspi_automode.c
file. Therefore, there is a single global namespace. Also, please note that the struct instance must be declared as const so that the compiler can optimize references to it.
The qspi_flash_config_t structure
, as shown in Table 40, has the following fields (see <sdk_root_directory>/sdk/memory/include qspi_common.h
for more information):
qspi_flash_config_t field | Description |
---|---|
initialize | Pointer to the flash-specific initialization function. |
is_suspended | Pointer to a flash-specific function that checks if flash is in erase/program suspend state. |
deactivate_command_entry_mode | Pointer to a flash-specific function that performs extra steps needed when command entry mode is deactivated. |
sys_clk_cfg | Pointer to a flash-specific function that performs Flash configuration when system clock is changed (e.g. change dummy bytes or QSPIC clock divider). |
get_dummy_bytes | Pointer to a flash-specific function that returns the number of dummy bytes currently needed (it may change when the clock changes). |
manufacturer_id | The Flash JEDEC vendor ID (Cmd 0x9F , 1st byte). This and the device_type and device_density are needed for flash autodetection, when on Autodetect mode. |
device_type | The Flash JEDEC device type (Cmd 0x9F , 2nd byte). |
device_density | The Flash JEDEC device type (Cmd 0x9F , 3rd byte). |
erase_opcode | The Flash erase opcode to use. |
erase_suspend_opcode | The Flash erase suspend opcode to use. |
erase_resume_opcode | The Flash erase resume opcode to use. |
page_program_opcode | The Flash page program opcode to use. |
quad_page_program_address | If true, the address will be transmitted in QUAD mode when writing a page. Otherwise, it will be transmitted in serial mode. |
read_erase_progress_opcode | The opcode to use to check if erase is in progress (Usually the Read Status Reg opcode (0x5 ). |
erase_in_progress_bit | The bit to check when reading the erase progress. |
erase_in_progress_bit_high_level | The active state (true: high, false: low) of the bit above. |
send_once | If set to 1, the “Performance mode” (or “burst”, or “continuous”; differs per vendor) will be used for read accesses. In this mode, the read opcode is only sent once, and subsequent accesses only transfer the address. |
extra_byte | The extra byte to transmit, when in “Performance mode” (send once is 1), that tells the flash that it should stay in this continuous, performance mode. |
address_size | Whether the flash works in 24- or 32-bit addressing mode. |
break_seq_size | Whether the break sequence, that puts flash out of the continuous mode, is one or two bytes long (the break byte is 0xFF ). |
ucode_wakeup | The QSPIC microcode to use to setup the flash on wakeup. This is automatically used by the QSPI Controller after wakeup, and before CPU starts code execution. This is different based on whether flash was active, in deep power down or completely off while the system was sleeping. |
power_down_delay | This is the time, in usec, needed for the flash to go to power down, after the Power Down command is issued. |
release_power_down_delay | This is the time, in usec, needed for the flash to exit the power down mode, after the Release Power Down command is issued. |
In Autodetect mode, these structures reside in the .rodata
section of the code. As soon as the flash subsystem is initialized, it reads the flash JEDEC ID
(command 0x9F
) to find out which is the actual flash device that is used. It then uses the JEDEC ID
to select the corresponding flash_<flash device>_config structure
, and copies it in the Retained RAM. It then uses it for all the flash operations that need it.
When in Manual mode, no JEDED ID
is read and no copy is performed to the Retained RAM. Instead, the constant pointer flash_config
is directly initialized (inside the flash-specific driver file) to the specific (and constant) flash_<device name>_config
structure. The compiler then optimizes out the entire structure.
14.2.1.7. Adding support for a new flash device¶
The SmartSnippets™ DA1468x SDK driver subsystem currently supports a specific set of QSPI flash devices. It provides, however, the capability to add support for other flash devices as well.
Each device driver must have its own header file that should be named qspi_<device name>.h
. The programmer can either use the qspi_XXX_template.h
, or start from an existing driver file.
Warning
The new flash driver file should be placed inside the project’s path, in a folder that is in the compiler’s include path (an obvious choice is the ``config/`` folder, but others can be used as well). This is recommended so that potential SDK upgrades will not interfere with the project-specific flash driver implementation.
Common code among flash families or vendors can be factored out in common header file per family/vendor. There are currently such common header files, like qspi_macronix.h
and qspi_winbond.h
. However, this is NOT necessary; moreover, it is the responsibility of the device driver header file to include the common header file, if needed.
Note
A custom flash driver can ONLY be used in Manual mode, which means that the macros described in Table 39 MUST be defined in config/custom_config_qspi.h
.
The following steps are usually needed to create the new flash driver:
- Copy and rename the template header file, or an existing driver file.
- Rename all the functions and variables appropriately. It is important to remember that all the drivers reside in the same namespace and so all function and variable names must be unique.
- Define the proper
JEDEC ID
values for the Manufacturer code, the device type and the device density - Verify that the
suspend
,resume
,exit power-down
,enter power-down
,fast read
,write enable
,read
status register are valid for the new device type. - Guard the header file using an
#if
preprocessor macro that checks for the specific driver selection. - Define any other driver-specific macros that are needed (like timings etc).
- Define the constant wakeup microcode arrays that will be needed, per
configuration mode that will be supported
(
dg_configFLASH_POWER_OFF
,dg_configFLASH_POWER_DOWN
or none of them). The microcode will be copied during the driver initialization in a special memory in the QSPI controller, and will be used after system wakeup to initialize the QSPI (since the CPU isn’t yet running code at this time). Please see [Ref_01] for theuCode
format. - Declare the constant struct instance of type
qspi_flash_config_t
, namedflash_<device name>_config
, and initialize it with proper values. Please note that this must be declared as const. - Extend the function flash
<device name>_initialize()
if needed, e.g. to write some special QSPI configuration registers or the QUAD enable bit. Otherwise, leave empty. - Extend the function
flash_<device name>_sys_clock_cfg()
if needed. This can include modifying the dummy bytes when the system (and hence the QSPI) clock changes, or changing the QSPI clock divider (if, for example, the flash device cannot cope with 96MHz). Otherwise, leave empty. - The function
is_suspended()
should read the flash Status Register and return true if Erase or Write is suspended on the device. - If Continuous Read Mode (sometimes referred to as Performance or Burst Mode) is used, make sure to set
send_once
to 1, and setextra_byte
to a proper value for the flash to keep working in this mode. This is flash-specific. - If the flash supports 32-bit addressing (e.g. the Macronix
MX25U51245G
Flash), make sure to use the proper uCode for wakeup. Also setpage_program_opcode
,erase_opcode
,break_seq_size
(this should also take into consideration whether the device will be working in Continuous Read mode as well) andaddress_size
. - If the address, during write, will be provided in QUAD mode, set
quad_page_program_address
to true.
Note
The SmartSnippets™ DA1468x SDK supports reading in QUAD I/O mode (where the address and data are read in QUAD mode, and only the command is transferred in serial mode), both in Continuous Read and normal mode.
To test the flash driver, use the PXP Reporter demo application, and configure the new flash driver in its custom_config_qspi.h
and custom_config_qspi_suota.h
files. Do the following tests:
- Verify that the application boots by using SmartSnippets™ Studio Power Profiler and a cell phone to connect to the device
- Verify that the application continues working after the system starts going to sleep (after ~8 seconds), that the cell phone can connect to the device and that it can maintain the connection for a while.
- Repeat steps 1 and 2 by changing the application clock to 96 MHz
(change
sysclk_XTAL16M
inmain.c
tosysclk_PLL96
) - Repeat steps 1, 2 and 3 and change
dg_configPOWER_1V8_SLEEP
to 0 (in flashes where this makes sense) and (separately),dg_configFLASH_POWER_DOWN
to 1, to test the supported wake up sequence driver modes. - Repeat steps 1 through 4 using the SUOTA Configuration of the PXP Reporter application. This will test the write/erase functionality of the driver.
14.2.1.8. Working with a new flash device¶
Read/Erase/Program of new QSPI flash devices should be done using SmartSnippets™ Studio standard procedure (check “General Installation and Debugging Procedure” in SDK’s Doxygen documentation).
Before working with new QSPI flash devices the following steps are required:
- Support for the new flash is added to the SDK as described in “Adding support for a new flash device” paragraph.
- SDK uartboot project (the secondary bootloader used by SDK flash programming tools) is built with support for the new QSPI flash as described in “Flash configuration” paragraph.
- SDK cli_programmer project (the tool used in the SDK for accessing flash) is re-built in
Release_static
(if working in Linux) orRelease_static_win
(if working in Windows) configuration, as described in SDK’s Doxygen documentation “CLI programmer application” paragraph.
Note
SmartSnippets™ Toolbox only supports read/erase/programming
of the default supported QSPI flash devices. Therefore, it is not recommended to be used with new flash devices.