initial commit
This commit is contained in:
226
project/ble_peripheral/ble_app_vivaMayo/storage/dr_mem.c
Normal file
226
project/ble_peripheral/ble_app_vivaMayo/storage/dr_mem.c
Normal file
@@ -0,0 +1,226 @@
|
||||
/*******************************************************************************
|
||||
* @file dr_mem.c
|
||||
* @brief Name-based Memory API Implementation
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2026-02-19
|
||||
* @copyright (c) 2026 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details Routes name-based read/write to FDS or W25Q32 backend.
|
||||
*
|
||||
* dr_memWrite("serial_no", data, 12)
|
||||
* |
|
||||
* v
|
||||
* [Lookup Table] --> FDS (config_data_t memcpy + config_save)
|
||||
* --> W25Q32 (w25q32_write at physical address)
|
||||
******************************************************************************/
|
||||
|
||||
#include "dr_mem.h"
|
||||
#include "fstorage.h"
|
||||
#include "drivers/w25q32/w25q32.h"
|
||||
#include "debug_print.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*==============================================================================
|
||||
* DEFAULT VALUES
|
||||
*============================================================================*/
|
||||
|
||||
static const char dflt_hw_no[12] = "123456789012";
|
||||
static const char dflt_serial[12] = "2025AAAAT001";
|
||||
static const uint8_t dflt_passkey[6] = {'1','2','3','4','5','6'};
|
||||
static const uint8_t dflt_bond_del = 1;
|
||||
static const int8_t dflt_reset_st = 99;
|
||||
static const uint8_t dflt_adc_cnt = 8;
|
||||
static const uint16_t dflt_pd_delay = 8000;
|
||||
static const uint16_t dflt_agc[48] = {
|
||||
2048,2048,2048,2048,2048,2048,2048,2048,
|
||||
2048,2048,2048,2048,2048,2048,2048,2048,
|
||||
2048,2048,2048,2048,2048,2048,2048,2048,
|
||||
2048,2048,2048,2048,2048,2048,2048,2048,
|
||||
2048,2048,2048,2048,2048,2048,2048,2048,
|
||||
2048,2048,2048,2048,2048,2048,2048,2048
|
||||
};
|
||||
static const uint32_t dflt_life_cycle = 0;
|
||||
|
||||
/*==============================================================================
|
||||
* LOOKUP TABLE
|
||||
*
|
||||
* FDS entries: plaintext in config_data_t (internal flash, RBP protected)
|
||||
* W25Q32 entries: direct physical address access
|
||||
*============================================================================*/
|
||||
|
||||
static const dr_mem_entry_t mem_table[] = {
|
||||
/* FDS entries (device config - internal flash, plaintext) */
|
||||
{ "hw_no", MEM_BACKEND_FDS, offsetof(config_data_t, hw_no), 12, false, dflt_hw_no },
|
||||
{ "serial_no", MEM_BACKEND_FDS, offsetof(config_data_t, serial_no), 12, false, dflt_serial },
|
||||
{ "passkey", MEM_BACKEND_FDS, offsetof(config_data_t, static_passkey), 6, false, dflt_passkey },
|
||||
{ "bond_delete", MEM_BACKEND_FDS, offsetof(config_data_t, bond_data_delete), 1, false, &dflt_bond_del },
|
||||
{ "reset_status", MEM_BACKEND_FDS, offsetof(config_data_t, reset_status), 1, false, &dflt_reset_st },
|
||||
{ "pd_adc_cnt", MEM_BACKEND_FDS, offsetof(config_data_t, pd_adc_cnt), 1, false, &dflt_adc_cnt },
|
||||
{ "pd_delay", MEM_BACKEND_FDS, offsetof(config_data_t, pd_delay_us), 2, false, &dflt_pd_delay },
|
||||
|
||||
/* W25Q32 entries (calibration + data - external flash) */
|
||||
{ "agc_gain", MEM_BACKEND_W25Q32, 0x000000, 96, false, dflt_agc },
|
||||
{ "life_cycle", MEM_BACKEND_W25Q32, 0x000060, 4, false, &dflt_life_cycle },
|
||||
};
|
||||
|
||||
#define MEM_TABLE_COUNT (sizeof(mem_table) / sizeof(mem_table[0]))
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Find entry by key name
|
||||
*/
|
||||
static const dr_mem_entry_t *find_entry(const char *key)
|
||||
{
|
||||
for (uint32_t i = 0; i < MEM_TABLE_COUNT; i++) {
|
||||
if (strcmp(mem_table[i].key, key) == 0) {
|
||||
return &mem_table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write to FDS backend (config_data_t field + config_save)
|
||||
* FDS stores plaintext - internal flash is RBP protected
|
||||
*/
|
||||
static ret_code_t fds_backend_write(const dr_mem_entry_t *entry,
|
||||
const void *data, uint16_t len)
|
||||
{
|
||||
uint16_t copy_len = (len < entry->size) ? len : entry->size;
|
||||
uint8_t *dst = (uint8_t *)&m_config + entry->offset;
|
||||
|
||||
DBG_PRINTF("[FDS_W] '%s' %uB offset=%u\r\n", entry->key, copy_len, entry->offset);
|
||||
memcpy(dst, data, copy_len);
|
||||
DBG_PRINTF("[FDS_W] memcpy OK, calling config_save\r\n");
|
||||
config_save();
|
||||
DBG_PRINTF("[FDS_W] config_save returned\r\n");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read from FDS backend (config_data_t field)
|
||||
*/
|
||||
static ret_code_t fds_backend_read(const dr_mem_entry_t *entry,
|
||||
void *data, uint16_t len)
|
||||
{
|
||||
uint16_t copy_len = (len < entry->size) ? len : entry->size;
|
||||
uint8_t *src = (uint8_t *)&m_config + entry->offset;
|
||||
|
||||
memcpy(data, src, copy_len);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write to W25Q32 backend
|
||||
*/
|
||||
static ret_code_t w25q_backend_write(const dr_mem_entry_t *entry,
|
||||
const void *data, uint16_t len)
|
||||
{
|
||||
uint16_t copy_len = (len < entry->size) ? len : entry->size;
|
||||
w25q32_write(entry->offset, (const uint8_t *)data, copy_len);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read from W25Q32 backend
|
||||
*/
|
||||
static ret_code_t w25q_backend_read(const dr_mem_entry_t *entry,
|
||||
void *data, uint16_t len)
|
||||
{
|
||||
uint16_t copy_len = (len < entry->size) ? len : entry->size;
|
||||
w25q32_read(entry->offset, (uint8_t *)data, copy_len);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC API
|
||||
*============================================================================*/
|
||||
|
||||
ret_code_t dr_memInit(void)
|
||||
{
|
||||
/* FDS is initialized in fs_storage_init() + config_load() (main.c) */
|
||||
/* W25Q32 is initialized in w25q32_power_on() + w25q32_init() (main.c) */
|
||||
printf("[DR_MEM] Init OK (FDS + W25Q32)\r\n");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t dr_memWrite(const char *key, const void *data, uint16_t len)
|
||||
{
|
||||
const dr_mem_entry_t *entry = find_entry(key);
|
||||
if (entry == NULL) {
|
||||
printf("[DR_MEM] Write ERR: key '%s' not found\r\n", key);
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (len > entry->size) {
|
||||
printf("[DR_MEM] Write WARN: len %u > size %u for '%s'\r\n",
|
||||
len, entry->size, key);
|
||||
}
|
||||
|
||||
printf("[DR_MEM] W '%s' %uB -> %s\r\n", key, len,
|
||||
entry->backend == MEM_BACKEND_FDS ? "FDS" : "W25Q32");
|
||||
|
||||
switch (entry->backend) {
|
||||
case MEM_BACKEND_FDS:
|
||||
return fds_backend_write(entry, data, len);
|
||||
case MEM_BACKEND_W25Q32:
|
||||
return w25q_backend_write(entry, data, len);
|
||||
default:
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t dr_memRead(const char *key, void *data, uint16_t len)
|
||||
{
|
||||
const dr_mem_entry_t *entry = find_entry(key);
|
||||
if (entry == NULL) {
|
||||
printf("[DR_MEM] Read ERR: key '%s' not found\r\n", key);
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (len > entry->size) {
|
||||
printf("[DR_MEM] Read WARN: len %u > size %u for '%s'\r\n",
|
||||
len, entry->size, key);
|
||||
}
|
||||
|
||||
switch (entry->backend) {
|
||||
case MEM_BACKEND_FDS:
|
||||
return fds_backend_read(entry, data, len);
|
||||
case MEM_BACKEND_W25Q32:
|
||||
return w25q_backend_read(entry, data, len);
|
||||
default:
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
const dr_mem_entry_t *dr_memFind(const char *key)
|
||||
{
|
||||
return find_entry(key);
|
||||
}
|
||||
|
||||
ret_code_t dr_memSetDefaults(void)
|
||||
{
|
||||
printf("[DR_MEM] Setting defaults (RAM only)\r\n");
|
||||
|
||||
/* FDS entries: write to m_config RAM only (no config_save)
|
||||
* FDS flash defaults are handled by config_load() -> fds_default_value_set()
|
||||
* W25Q32 is not initialized during boot */
|
||||
for (uint32_t i = 0; i < MEM_TABLE_COUNT; i++) {
|
||||
const dr_mem_entry_t *e = &mem_table[i];
|
||||
if (e->default_val == NULL) continue;
|
||||
|
||||
if (e->backend == MEM_BACKEND_FDS) {
|
||||
uint8_t *dst = (uint8_t *)&m_config + e->offset;
|
||||
memcpy(dst, e->default_val, e->size);
|
||||
}
|
||||
printf("[DR_MEM] D '%s' %uB\r\n", e->key, e->size);
|
||||
}
|
||||
|
||||
printf("[DR_MEM] Defaults applied (%u entries, RAM)\r\n", MEM_TABLE_COUNT);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
88
project/ble_peripheral/ble_app_vivaMayo/storage/dr_mem.h
Normal file
88
project/ble_peripheral/ble_app_vivaMayo/storage/dr_mem.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*******************************************************************************
|
||||
* @file dr_mem.h
|
||||
* @brief Name-based Memory API (dr_memWrite / dr_memRead)
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2026-02-19
|
||||
* @copyright (c) 2026 Medithings Inc. All rights reserved.
|
||||
*
|
||||
* @details Provides name-based memory access that automatically routes to
|
||||
* the correct backend storage:
|
||||
* - FDS (internal flash) for device config
|
||||
* - W25Q32 (external flash) for calibration & data
|
||||
*
|
||||
* Usage:
|
||||
* dr_memWrite("serial_no", data, 12);
|
||||
* dr_memRead("serial_no", buf, 12);
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DR_MEM_H
|
||||
#define DR_MEM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_errors.h"
|
||||
|
||||
/*==============================================================================
|
||||
* BACKEND TYPES
|
||||
*============================================================================*/
|
||||
|
||||
typedef enum {
|
||||
MEM_BACKEND_FDS, /**< Internal Flash (FDS) - device config */
|
||||
MEM_BACKEND_W25Q32 /**< External Flash (W25Q32RV) - calibration/data */
|
||||
} mem_backend_t;
|
||||
|
||||
/*==============================================================================
|
||||
* LOOKUP TABLE ENTRY
|
||||
*============================================================================*/
|
||||
|
||||
typedef struct {
|
||||
const char *key; /**< Name key (e.g., "hw_no", "agc_gain") */
|
||||
mem_backend_t backend; /**< Storage backend */
|
||||
uint32_t offset; /**< FDS: offsetof in config_data_t, W25Q32: address */
|
||||
uint16_t size; /**< Data size in bytes */
|
||||
bool encrypted; /**< AES-128 CBC encryption */
|
||||
const void *default_val; /**< Default value (NULL = no default) */
|
||||
} dr_mem_entry_t;
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize memory subsystem (FDS + W25Q32)
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t dr_memInit(void);
|
||||
|
||||
/**
|
||||
* @brief Write data by name
|
||||
* @param key Name key (e.g., "serial_no", "agc_gain")
|
||||
* @param data Data to write
|
||||
* @param len Data length in bytes
|
||||
* @return NRF_SUCCESS on success, NRF_ERROR_NOT_FOUND if key unknown
|
||||
*/
|
||||
ret_code_t dr_memWrite(const char *key, const void *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Read data by name
|
||||
* @param key Name key (e.g., "serial_no", "agc_gain")
|
||||
* @param data Output buffer
|
||||
* @param len Buffer length in bytes
|
||||
* @return NRF_SUCCESS on success, NRF_ERROR_NOT_FOUND if key unknown
|
||||
*/
|
||||
ret_code_t dr_memRead(const char *key, void *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Get entry info by name (for debugging)
|
||||
* @param key Name key
|
||||
* @return Pointer to entry, or NULL if not found
|
||||
*/
|
||||
const dr_mem_entry_t *dr_memFind(const char *key);
|
||||
|
||||
/**
|
||||
* @brief Write default values to all entries (when hw_no is uninitialized)
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t dr_memSetDefaults(void);
|
||||
|
||||
#endif /* DR_MEM_H */
|
||||
69
project/ble_peripheral/ble_app_vivaMayo/storage/mem_config.h
Normal file
69
project/ble_peripheral/ble_app_vivaMayo/storage/mem_config.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*******************************************************************************
|
||||
* @file mem_config.h
|
||||
* @brief Memory Configuration - Select memory type
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-02-03
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MEM_CONFIG_H
|
||||
#define MEM_CONFIG_H
|
||||
|
||||
/*==============================================================================
|
||||
* MEMORY TYPE SELECTION
|
||||
* Enable only ONE option
|
||||
*============================================================================*/
|
||||
|
||||
#define MEM_USE_EEPROM 0 /* I2C EEPROM (24LC64) */
|
||||
#define MEM_USE_W25Q_FLASH 1 /* W25Q32RV SPI Flash */
|
||||
#define MEM_USE_INTERNAL_FDS 0 /* Internal Flash (FDS) - for testing */
|
||||
|
||||
/*==============================================================================
|
||||
* W25Q32RV SPI PIN CONFIGURATION
|
||||
*============================================================================*/
|
||||
|
||||
#if MEM_USE_W25Q_FLASH
|
||||
|
||||
/* SPI Instance - use SPI2 (shared with ADC) */
|
||||
#define MEM_SPI_INSTANCE 2
|
||||
|
||||
/* SPI Pins (shared bus) */
|
||||
#define MEM_SPI_SCK_PIN 14 /* P0.14 */
|
||||
#define MEM_SPI_MISO_PIN 15 /* P0.15 */
|
||||
#define MEM_SPI_MOSI_PIN 16 /* P0.16 */
|
||||
#define MEM_SPI_CS_PIN 24 /* P0.24 - Flash dedicated */
|
||||
|
||||
#endif /* MEM_USE_W25Q_FLASH */
|
||||
|
||||
/*==============================================================================
|
||||
* MEMORY PARAMETERS
|
||||
*============================================================================*/
|
||||
|
||||
#if MEM_USE_EEPROM
|
||||
#define MEM_PAGE_SIZE 64
|
||||
#define MEM_SECTOR_SIZE 64 /* EEPROM has no sector concept */
|
||||
#define MEM_TOTAL_SIZE (8*1024) /* 8KB - 24LC64 */
|
||||
#elif MEM_USE_W25Q_FLASH
|
||||
#define MEM_PAGE_SIZE 256
|
||||
#define MEM_SECTOR_SIZE 4096 /* 4KB */
|
||||
#define MEM_TOTAL_SIZE (4*1024*1024) /* 4MB */
|
||||
#elif MEM_USE_INTERNAL_FDS
|
||||
#define MEM_PAGE_SIZE 256
|
||||
#define MEM_SECTOR_SIZE 4096
|
||||
#define MEM_TOTAL_SIZE (32*1024) /* ~32KB available */
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* ADDRESS MAP (same for all memory types)
|
||||
*============================================================================*/
|
||||
|
||||
#define MEM_ADDR_HW_NO 0x0010 /* 12 bytes - HW Number */
|
||||
#define MEM_ADDR_PASSKEY 0x0020 /* 6 bytes - BLE Passkey */
|
||||
#define MEM_ADDR_SERIAL_NO 0x0030 /* 12 bytes - Serial Number */
|
||||
#define MEM_ADDR_BOND_DELETE 0x0060 /* 1 byte - Bond delete flag */
|
||||
#define MEM_ADDR_RESET_STATUS 0x0065 /* 1 byte - Reset status */
|
||||
#define MEM_ADDR_PD_ADC_CNT 0x0070 /* 1 byte - ADC count */
|
||||
#define MEM_ADDR_PD_DELAY 0x0080 /* 2 bytes - PD delay */
|
||||
#define MEM_ADDR_LIFE_CYCLE 0x0090 /* 4 bytes - Life cycle counter */
|
||||
#define MEM_ADDR_AGC_GAIN 0x0480 /* 96 bytes - AGC gain array */
|
||||
|
||||
#endif /* MEM_CONFIG_H */
|
||||
429
project/ble_peripheral/ble_app_vivaMayo/storage/mem_flash.c
Normal file
429
project/ble_peripheral/ble_app_vivaMayo/storage/mem_flash.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/*******************************************************************************
|
||||
* @file mem_flash.c
|
||||
* @brief W25Q32RV SPI Flash Driver Implementation
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-02-03
|
||||
*
|
||||
* @details W25Q32RV: 4MB Serial NOR Flash
|
||||
* - SPI Mode 0/3
|
||||
* - Page size: 256 bytes
|
||||
* - Sector size: 4KB
|
||||
* - Erase before write required
|
||||
******************************************************************************/
|
||||
|
||||
#include "mem_hal.h"
|
||||
#include "mem_config.h"
|
||||
|
||||
#if MEM_USE_W25Q_FLASH
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "app_error.h"
|
||||
#include "../spi2_bus.h" /* Shared SPI2 bus */
|
||||
|
||||
/*==============================================================================
|
||||
* W25Q32RV COMMANDS
|
||||
*============================================================================*/
|
||||
|
||||
#define W25Q_CMD_WRITE_ENABLE 0x06
|
||||
#define W25Q_CMD_WRITE_DISABLE 0x04
|
||||
#define W25Q_CMD_READ_STATUS1 0x05
|
||||
#define W25Q_CMD_READ_STATUS2 0x35
|
||||
#define W25Q_CMD_WRITE_STATUS 0x01
|
||||
#define W25Q_CMD_READ_DATA 0x03
|
||||
#define W25Q_CMD_FAST_READ 0x0B
|
||||
#define W25Q_CMD_PAGE_PROGRAM 0x02
|
||||
#define W25Q_CMD_SECTOR_ERASE 0x20 /* 4KB */
|
||||
#define W25Q_CMD_BLOCK_ERASE_32K 0x52 /* 32KB */
|
||||
#define W25Q_CMD_BLOCK_ERASE_64K 0xD8 /* 64KB */
|
||||
#define W25Q_CMD_CHIP_ERASE 0xC7
|
||||
#define W25Q_CMD_POWER_DOWN 0xB9
|
||||
#define W25Q_CMD_RELEASE_PD 0xAB
|
||||
#define W25Q_CMD_DEVICE_ID 0x90
|
||||
#define W25Q_CMD_JEDEC_ID 0x9F
|
||||
#define W25Q_CMD_ENABLE_RESET 0x66
|
||||
#define W25Q_CMD_RESET_DEVICE 0x99
|
||||
|
||||
/* Status Register-1 Bits */
|
||||
#define W25Q_STATUS_BUSY 0x01
|
||||
#define W25Q_STATUS_WEL 0x02
|
||||
|
||||
/* Device ID */
|
||||
#define W25Q_MANUFACTURER_WINBOND 0xEF
|
||||
#define W25Q_DEVICE_ID_32RV 0x4016
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
static bool m_initialized = false;
|
||||
|
||||
/* 4KB sector buffer for Read-Modify-Write */
|
||||
static uint8_t m_sector_buffer[MEM_SECTOR_SIZE];
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Assert CS (active low) - Flash CS from shared bus
|
||||
*/
|
||||
static inline void cs_low(void)
|
||||
{
|
||||
nrf_gpio_pin_clear(SPI2_CS_FLASH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deassert CS
|
||||
*/
|
||||
static inline void cs_high(void)
|
||||
{
|
||||
nrf_gpio_pin_set(SPI2_CS_FLASH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI transfer with CS control (blocking mode via shared bus)
|
||||
*/
|
||||
static ret_code_t spi_transfer(const uint8_t *tx_buf, uint8_t tx_len,
|
||||
uint8_t *rx_buf, uint8_t rx_len)
|
||||
{
|
||||
printf("[FLASH] xfer tx=%d rx=%d...", tx_len, rx_len);
|
||||
cs_low();
|
||||
ret_code_t err = spi2_bus_transfer(tx_buf, tx_len, rx_buf, rx_len);
|
||||
cs_high();
|
||||
printf("done(%d)\r\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read Status Register-1
|
||||
*/
|
||||
static uint8_t w25q_read_status(void)
|
||||
{
|
||||
uint8_t cmd = W25Q_CMD_READ_STATUS1;
|
||||
uint8_t rx[2];
|
||||
|
||||
cs_low();
|
||||
spi2_bus_transfer(&cmd, 1, rx, 2);
|
||||
cs_high();
|
||||
|
||||
return rx[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for BUSY flag to clear
|
||||
*/
|
||||
static void w25q_wait_busy(void)
|
||||
{
|
||||
uint32_t timeout = 100000; /* ~seconds */
|
||||
while ((w25q_read_status() & W25Q_STATUS_BUSY) && timeout--)
|
||||
{
|
||||
nrf_delay_us(10);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send Write Enable command
|
||||
*/
|
||||
static void w25q_write_enable(void)
|
||||
{
|
||||
uint8_t cmd = W25Q_CMD_WRITE_ENABLE;
|
||||
spi_transfer(&cmd, 1, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data from flash (blocking mode via shared bus)
|
||||
*/
|
||||
static ret_code_t w25q_read(uint32_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
uint8_t cmd[4];
|
||||
cmd[0] = W25Q_CMD_READ_DATA;
|
||||
cmd[1] = (addr >> 16) & 0xFF;
|
||||
cmd[2] = (addr >> 8) & 0xFF;
|
||||
cmd[3] = addr & 0xFF;
|
||||
|
||||
cs_low();
|
||||
|
||||
/* Send command */
|
||||
ret_code_t err = spi2_bus_transfer(cmd, 4, NULL, 0);
|
||||
if (err != NRF_SUCCESS) { cs_high(); return err; }
|
||||
|
||||
/* Read data */
|
||||
err = spi2_bus_transfer(NULL, 0, buf, len);
|
||||
cs_high();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program a page (max 256 bytes, must not cross page boundary)
|
||||
*/
|
||||
static ret_code_t w25q_page_program(uint32_t addr, const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if (len > MEM_PAGE_SIZE) len = MEM_PAGE_SIZE;
|
||||
|
||||
w25q_write_enable();
|
||||
|
||||
uint8_t cmd[4];
|
||||
cmd[0] = W25Q_CMD_PAGE_PROGRAM;
|
||||
cmd[1] = (addr >> 16) & 0xFF;
|
||||
cmd[2] = (addr >> 8) & 0xFF;
|
||||
cmd[3] = addr & 0xFF;
|
||||
|
||||
cs_low();
|
||||
|
||||
/* Send command */
|
||||
ret_code_t err = spi2_bus_transfer(cmd, 4, NULL, 0);
|
||||
if (err != NRF_SUCCESS) { cs_high(); return err; }
|
||||
|
||||
/* Send data */
|
||||
err = spi2_bus_transfer(buf, len, NULL, 0);
|
||||
cs_high();
|
||||
|
||||
if (err == NRF_SUCCESS)
|
||||
{
|
||||
w25q_wait_busy(); /* Wait for program complete (~0.25ms typ) */
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erase a 4KB sector
|
||||
*/
|
||||
static ret_code_t w25q_sector_erase(uint32_t addr)
|
||||
{
|
||||
uint32_t sector_addr = addr & ~(MEM_SECTOR_SIZE - 1);
|
||||
|
||||
w25q_write_enable();
|
||||
|
||||
uint8_t cmd[4];
|
||||
cmd[0] = W25Q_CMD_SECTOR_ERASE;
|
||||
cmd[1] = (sector_addr >> 16) & 0xFF;
|
||||
cmd[2] = (sector_addr >> 8) & 0xFF;
|
||||
cmd[3] = sector_addr & 0xFF;
|
||||
|
||||
spi_transfer(cmd, 4, NULL, 0);
|
||||
|
||||
w25q_wait_busy(); /* Wait for erase complete (~30ms typ, 240ms max) */
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PUBLIC FUNCTIONS - mem_hal.h IMPLEMENTATION
|
||||
*============================================================================*/
|
||||
|
||||
ret_code_t mem_init(void)
|
||||
{
|
||||
ret_code_t err;
|
||||
|
||||
printf("[FLASH] Init start\r\n");
|
||||
|
||||
/* Ensure shared SPI2 bus is initialized */
|
||||
if (!spi2_bus_is_initialized())
|
||||
{
|
||||
err = spi2_bus_init();
|
||||
if (err != NRF_SUCCESS)
|
||||
{
|
||||
printf("[FLASH] SPI2 init FAIL: %d\r\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check MISO pin state (should be high when idle) */
|
||||
uint32_t miso_state = nrf_gpio_pin_read(SPI2_MISO_PIN);
|
||||
printf("[FLASH] MISO(P0.%d)=%d\r\n", SPI2_MISO_PIN, miso_state);
|
||||
|
||||
cs_high(); /* Ensure Flash is deselected */
|
||||
|
||||
/* Release from power-down - try multiple times with longer delay */
|
||||
printf("[FLASH] Wake up...\r\n");
|
||||
uint8_t cmd = W25Q_CMD_RELEASE_PD;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
spi_transfer(&cmd, 1, NULL, 0);
|
||||
nrf_delay_ms(1); /* Longer delay - 1ms */
|
||||
}
|
||||
|
||||
/* Check MISO again after wake */
|
||||
miso_state = nrf_gpio_pin_read(SPI2_MISO_PIN);
|
||||
printf("[FLASH] MISO after wake=%d\r\n", miso_state);
|
||||
|
||||
m_initialized = true;
|
||||
printf("[FLASH] Init OK\r\n");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
void mem_uninit(void)
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
/* Enter power-down mode */
|
||||
uint8_t cmd = W25Q_CMD_POWER_DOWN;
|
||||
spi_transfer(&cmd, 1, NULL, 0);
|
||||
|
||||
/* Note: Don't uninit shared bus - other devices may still use it */
|
||||
m_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool mem_is_ready(void)
|
||||
{
|
||||
return m_initialized && !(w25q_read_status() & W25Q_STATUS_BUSY);
|
||||
}
|
||||
|
||||
ret_code_t mem_read_byte(uint32_t addr, uint8_t *out)
|
||||
{
|
||||
return w25q_read(addr, out, 1);
|
||||
}
|
||||
|
||||
ret_code_t mem_write_byte(uint32_t addr, uint8_t data)
|
||||
{
|
||||
return mem_write_bytes(addr, &data, 1);
|
||||
}
|
||||
|
||||
ret_code_t mem_read_bytes(uint32_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
return w25q_read(addr, buf, len);
|
||||
}
|
||||
|
||||
ret_code_t mem_write_bytes(uint32_t addr, const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
/*
|
||||
* Flash write requires Read-Modify-Write:
|
||||
* 1. Read entire sector
|
||||
* 2. Modify data in buffer
|
||||
* 3. Erase sector
|
||||
* 4. Write back entire sector
|
||||
*/
|
||||
|
||||
uint32_t sector_addr = addr & ~(MEM_SECTOR_SIZE - 1);
|
||||
uint32_t offset = addr - sector_addr;
|
||||
|
||||
/* Check if data fits in one sector */
|
||||
if (offset + len > MEM_SECTOR_SIZE)
|
||||
{
|
||||
/* TODO: Handle cross-sector writes */
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
/* 1. Read entire sector */
|
||||
ret_code_t err = w25q_read(sector_addr, m_sector_buffer, MEM_SECTOR_SIZE);
|
||||
if (err != NRF_SUCCESS) return err;
|
||||
|
||||
/* 2. Modify data */
|
||||
memcpy(&m_sector_buffer[offset], buf, len);
|
||||
|
||||
/* 3. Erase sector */
|
||||
err = w25q_sector_erase(sector_addr);
|
||||
if (err != NRF_SUCCESS) return err;
|
||||
|
||||
/* 4. Write back page by page */
|
||||
for (uint16_t i = 0; i < MEM_SECTOR_SIZE; i += MEM_PAGE_SIZE)
|
||||
{
|
||||
err = w25q_page_program(sector_addr + i, &m_sector_buffer[i], MEM_PAGE_SIZE);
|
||||
if (err != NRF_SUCCESS) return err;
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t mem_read_word(uint32_t addr, uint16_t *out)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
ret_code_t err = w25q_read(addr, buf, 2);
|
||||
if (err == NRF_SUCCESS)
|
||||
{
|
||||
*out = buf[0] | (buf[1] << 8);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
ret_code_t mem_write_word(uint32_t addr, uint16_t data)
|
||||
{
|
||||
uint8_t buf[2] = { data & 0xFF, (data >> 8) & 0xFF };
|
||||
return mem_write_bytes(addr, buf, 2);
|
||||
}
|
||||
|
||||
ret_code_t mem_read_uint32(uint32_t addr, uint32_t *out)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
ret_code_t err = w25q_read(addr, buf, 4);
|
||||
if (err == NRF_SUCCESS)
|
||||
{
|
||||
*out = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
ret_code_t mem_write_uint32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
uint8_t buf[4] = {
|
||||
data & 0xFF,
|
||||
(data >> 8) & 0xFF,
|
||||
(data >> 16) & 0xFF,
|
||||
(data >> 24) & 0xFF
|
||||
};
|
||||
return mem_write_bytes(addr, buf, 4);
|
||||
}
|
||||
|
||||
ret_code_t mem_read_uint16_array(uint32_t addr, uint16_t *arr, uint16_t count)
|
||||
{
|
||||
return w25q_read(addr, (uint8_t *)arr, count * 2);
|
||||
}
|
||||
|
||||
ret_code_t mem_write_uint16_array(uint32_t addr, const uint16_t *arr, uint16_t count)
|
||||
{
|
||||
return mem_write_bytes(addr, (const uint8_t *)arr, count * 2);
|
||||
}
|
||||
|
||||
ret_code_t mem_read_decrypted(uint32_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
/* TODO: Implement AES-128 CBC decryption */
|
||||
/* For now, just read raw data */
|
||||
return w25q_read(addr, buf, len);
|
||||
}
|
||||
|
||||
ret_code_t mem_write_encrypted(uint32_t addr, const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
/* TODO: Implement AES-128 CBC encryption */
|
||||
/* For now, just write raw data */
|
||||
return mem_write_bytes(addr, buf, len);
|
||||
}
|
||||
|
||||
ret_code_t mem_erase_sector(uint32_t addr)
|
||||
{
|
||||
return w25q_sector_erase(addr);
|
||||
}
|
||||
|
||||
ret_code_t mem_get_device_id(uint8_t *manufacturer_id, uint16_t *device_id)
|
||||
{
|
||||
uint8_t cmd = W25Q_CMD_JEDEC_ID;
|
||||
uint8_t rx[4] = {0};
|
||||
|
||||
printf("[FLASH] Reading JEDEC ID...\r\n");
|
||||
|
||||
cs_low();
|
||||
ret_code_t err = spi2_bus_transfer(&cmd, 1, rx, 4);
|
||||
cs_high();
|
||||
|
||||
if (err != NRF_SUCCESS)
|
||||
{
|
||||
printf("[FLASH] JEDEC xfer err: %d\r\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* rx[1] = Manufacturer ID (0xEF for Winbond) */
|
||||
/* rx[2:3] = Device ID (0x4016 for W25Q32RV) */
|
||||
*manufacturer_id = rx[1];
|
||||
*device_id = (rx[2] << 8) | rx[3];
|
||||
|
||||
printf("[FLASH] JEDEC: MFR=0x%02X DEV=0x%04X\r\n", rx[1], (rx[2]<<8)|rx[3]);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* MEM_USE_W25Q_FLASH */
|
||||
137
project/ble_peripheral/ble_app_vivaMayo/storage/mem_hal.c
Normal file
137
project/ble_peripheral/ble_app_vivaMayo/storage/mem_hal.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*******************************************************************************
|
||||
* @file mem_hal.c
|
||||
* @brief Memory HAL - Common functions and driver selection
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-02-03
|
||||
*
|
||||
* @details This file provides common functionality that applies to all
|
||||
* memory backends. Specific implementations are in:
|
||||
* - mem_flash.c (W25Q32RV SPI Flash)
|
||||
* - mem_eeprom.c (I2C EEPROM) - not yet implemented
|
||||
******************************************************************************/
|
||||
|
||||
#include "mem_hal.h"
|
||||
#include "mem_config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*==============================================================================
|
||||
* DEBUG MACROS
|
||||
*============================================================================*/
|
||||
|
||||
#define MEM_DEBUG 1
|
||||
|
||||
#if MEM_DEBUG
|
||||
#define MEM_LOG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define MEM_LOG(...)
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* MEMORY TEST FUNCTION
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Test memory read/write functionality
|
||||
* @return NRF_SUCCESS if all tests pass
|
||||
*/
|
||||
ret_code_t mem_test(void)
|
||||
{
|
||||
ret_code_t err;
|
||||
uint8_t manufacturer_id;
|
||||
uint16_t device_id;
|
||||
|
||||
MEM_LOG("[MEM] Testing memory...\r\n");
|
||||
|
||||
#if MEM_USE_W25Q_FLASH
|
||||
/* Read device ID */
|
||||
err = mem_get_device_id(&manufacturer_id, &device_id);
|
||||
if (err != NRF_SUCCESS)
|
||||
{
|
||||
MEM_LOG("[MEM] Failed to read device ID\r\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
MEM_LOG("[MEM] Manufacturer: 0x%02X, Device: 0x%04X\r\n",
|
||||
manufacturer_id, device_id);
|
||||
|
||||
/* Verify it's W25Q32RV */
|
||||
if (manufacturer_id != 0xEF || device_id != 0x4016)
|
||||
{
|
||||
MEM_LOG("[MEM] WARNING: Unexpected device ID!\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Test read/write at address 0x0000 */
|
||||
uint8_t test_data[4] = { 0x12, 0x34, 0x56, 0x78 };
|
||||
uint8_t read_data[4] = { 0 };
|
||||
|
||||
MEM_LOG("[MEM] Writing test data...\r\n");
|
||||
err = mem_write_bytes(0x0000, test_data, 4);
|
||||
if (err != NRF_SUCCESS)
|
||||
{
|
||||
MEM_LOG("[MEM] Write failed: %d\r\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
MEM_LOG("[MEM] Reading back...\r\n");
|
||||
err = mem_read_bytes(0x0000, read_data, 4);
|
||||
if (err != NRF_SUCCESS)
|
||||
{
|
||||
MEM_LOG("[MEM] Read failed: %d\r\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
bool match = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (test_data[i] != read_data[i])
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
MEM_LOG("[MEM] Test PASSED\r\n");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
MEM_LOG("[MEM] Test FAILED: data mismatch\r\n");
|
||||
MEM_LOG("[MEM] Wrote: %02X %02X %02X %02X\r\n",
|
||||
test_data[0], test_data[1], test_data[2], test_data[3]);
|
||||
MEM_LOG("[MEM] Read: %02X %02X %02X %02X\r\n",
|
||||
read_data[0], read_data[1], read_data[2], read_data[3]);
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* STUB IMPLEMENTATIONS (when memory type not selected)
|
||||
*============================================================================*/
|
||||
|
||||
#if !MEM_USE_W25Q_FLASH && !MEM_USE_EEPROM && !MEM_USE_INTERNAL_FDS
|
||||
|
||||
/* No memory backend selected - provide stub implementations */
|
||||
|
||||
ret_code_t mem_init(void) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
void mem_uninit(void) { }
|
||||
bool mem_is_ready(void) { return false; }
|
||||
ret_code_t mem_read_byte(uint32_t addr, uint8_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_byte(uint32_t addr, uint8_t data) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_read_bytes(uint32_t addr, uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_bytes(uint32_t addr, const uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_read_word(uint32_t addr, uint16_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_word(uint32_t addr, uint16_t data) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_read_uint32(uint32_t addr, uint32_t *out) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_uint32(uint32_t addr, uint32_t data) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_read_uint16_array(uint32_t addr, uint16_t *arr, uint16_t count) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_uint16_array(uint32_t addr, const uint16_t *arr, uint16_t count) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_read_decrypted(uint32_t addr, uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_write_encrypted(uint32_t addr, const uint8_t *buf, uint16_t len) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_erase_sector(uint32_t addr) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
ret_code_t mem_get_device_id(uint8_t *manufacturer_id, uint16_t *device_id) { return NRF_ERROR_NOT_SUPPORTED; }
|
||||
|
||||
#endif
|
||||
151
project/ble_peripheral/ble_app_vivaMayo/storage/mem_hal.h
Normal file
151
project/ble_peripheral/ble_app_vivaMayo/storage/mem_hal.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*******************************************************************************
|
||||
* @file mem_hal.h
|
||||
* @brief Memory Hardware Abstraction Layer Interface
|
||||
* @author Charles KWON <charleskwon@medithings.co.kr>
|
||||
* @date 2025-02-03
|
||||
*
|
||||
* @details Provides unified API for different memory types:
|
||||
* - EEPROM (I2C)
|
||||
* - W25Q32RV Flash (SPI)
|
||||
* - Internal Flash (FDS)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MEM_HAL_H
|
||||
#define MEM_HAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdk_errors.h"
|
||||
#include "mem_config.h"
|
||||
|
||||
/*==============================================================================
|
||||
* INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize memory subsystem
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_init(void);
|
||||
|
||||
/**
|
||||
* @brief Uninitialize memory subsystem
|
||||
*/
|
||||
void mem_uninit(void);
|
||||
|
||||
/**
|
||||
* @brief Check if memory is ready
|
||||
* @return true if ready
|
||||
*/
|
||||
bool mem_is_ready(void);
|
||||
|
||||
/*==============================================================================
|
||||
* BASIC READ/WRITE OPERATIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read single byte
|
||||
* @param addr Memory address
|
||||
* @param out Output buffer
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_read_byte(uint32_t addr, uint8_t *out);
|
||||
|
||||
/**
|
||||
* @brief Write single byte
|
||||
* @param addr Memory address
|
||||
* @param data Byte to write
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_write_byte(uint32_t addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Read multiple bytes
|
||||
* @param addr Start address
|
||||
* @param buf Output buffer
|
||||
* @param len Number of bytes
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_read_bytes(uint32_t addr, uint8_t *buf, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Write multiple bytes
|
||||
* @param addr Start address
|
||||
* @param buf Data buffer
|
||||
* @param len Number of bytes
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_write_bytes(uint32_t addr, const uint8_t *buf, uint16_t len);
|
||||
|
||||
/*==============================================================================
|
||||
* WORD/DWORD OPERATIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read 16-bit word
|
||||
*/
|
||||
ret_code_t mem_read_word(uint32_t addr, uint16_t *out);
|
||||
|
||||
/**
|
||||
* @brief Write 16-bit word
|
||||
*/
|
||||
ret_code_t mem_write_word(uint32_t addr, uint16_t data);
|
||||
|
||||
/**
|
||||
* @brief Read 32-bit value
|
||||
*/
|
||||
ret_code_t mem_read_uint32(uint32_t addr, uint32_t *out);
|
||||
|
||||
/**
|
||||
* @brief Write 32-bit value
|
||||
*/
|
||||
ret_code_t mem_write_uint32(uint32_t addr, uint32_t data);
|
||||
|
||||
/*==============================================================================
|
||||
* ARRAY OPERATIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read array of 16-bit values
|
||||
*/
|
||||
ret_code_t mem_read_uint16_array(uint32_t addr, uint16_t *arr, uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief Write array of 16-bit values
|
||||
*/
|
||||
ret_code_t mem_write_uint16_array(uint32_t addr, const uint16_t *arr, uint16_t count);
|
||||
|
||||
/*==============================================================================
|
||||
* ENCRYPTED OPERATIONS (AES-128 CBC)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read and decrypt data
|
||||
*/
|
||||
ret_code_t mem_read_decrypted(uint32_t addr, uint8_t *buf, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Encrypt and write data
|
||||
*/
|
||||
ret_code_t mem_write_encrypted(uint32_t addr, const uint8_t *buf, uint16_t len);
|
||||
|
||||
/*==============================================================================
|
||||
* FLASH-SPECIFIC OPERATIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Erase sector (Flash only, NOP for EEPROM)
|
||||
* @param addr Any address within the sector
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_erase_sector(uint32_t addr);
|
||||
|
||||
/**
|
||||
* @brief Get device ID (Flash only)
|
||||
* @param manufacturer_id Output: Manufacturer ID
|
||||
* @param device_id Output: Device ID
|
||||
* @return NRF_SUCCESS on success
|
||||
*/
|
||||
ret_code_t mem_get_device_id(uint8_t *manufacturer_id, uint16_t *device_id);
|
||||
|
||||
#endif /* MEM_HAL_H */
|
||||
Reference in New Issue
Block a user