fix: BLE TX 먹통 해결 및 메모리 안전성 개선

- binary_tx_handler를 dr_binary_tx_safe로 전체 교체 (APP_ERROR_CHECK 제거)
- data_tx_handler APP_ERROR_CHECK → DBG_PRINTF 교체
- memset/memcpy 하드코딩 크기를 define 상수로 교체 (버퍼 오버런 수정)
- SERIAL_NO_LENGTH, HW_NO_LENGTH, PASSKEY_LENGTH를 main.h로 통합
- 미사용 HW 드라이버/EEPROM 코드 삭제, TWI를 i2c_manager.c로 통합
- EEPROM → FDS 전환, 코드 리뷰 현황 문서 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 16:39:26 +09:00
parent a77919b4d3
commit 831dbc2844
76 changed files with 43253 additions and 16370 deletions

View File

@@ -0,0 +1,245 @@
/*******************************************************************************
* @file dr_w25q32.h
* @brief W25Q32 SPI Flash Driver for nRF52840
* 32Mbit (4MB) Serial NOR Flash Memory
* @date 2026-03-12
*
* @details Software SPI (bit-bang) driver for W25Q32RVXHJQ.
* Shares SPI bus (SCK/MISO/MOSI) with ADC121S051.
* Only CS pin is unique (P0.24).
*
* Pin connections:
* nRF52840 W25Q32 (U16)
* P0.24 -----> /CS (pin 1)
* P0.15 <----- DO (pin 2, MISO)
* P0.16 -----> DI (pin 5, MOSI)
* P0.14 -----> CLK (pin 6)
*
* @note WP (pin 3) and HOLD (pin 7) are pulled HIGH via 10k resistors.
******************************************************************************/
#ifndef DR_W25Q32_H
#define DR_W25Q32_H
#include <stdint.h>
#include <stdbool.h>
#include "nrf_gpio.h"
/*==============================================================================
* PIN CONFIGURATION
*============================================================================*/
#define DR_FLASH_PIN_CS NRF_GPIO_PIN_MAP(0, 24) /* Chip Select - SPI_CS_FLASH(P0.24) */
#define DR_FLASH_PIN_SCLK NRF_GPIO_PIN_MAP(0, 14) /* Serial Clock(shared) - SPI_SCK(P0.14) */
#define DR_FLASH_PIN_MISO NRF_GPIO_PIN_MAP(0, 15) /* DI_(IO0)(shared) - SPI_MOSI(P0.15) */
#define DR_FLASH_PIN_MOSI NRF_GPIO_PIN_MAP(0, 16) /* DO_(IO1)(shared) - SPI_MISO(P0.16) */
/*==============================================================================
* W25Q32 SPECIFICATIONS
*============================================================================*/
#define DR_FLASH_PAGE_SIZE 256 /**< Page size (bytes) */
#define DR_FLASH_SECTOR_SIZE 4096 /**< Sector size (bytes, 4KB) */
#define DR_FLASH_BLOCK_32K (32*1024) /**< 32KB block */
#define DR_FLASH_BLOCK_64K (64*1024) /**< 64KB block */
#define DR_FLASH_TOTAL_SIZE (4*1024*1024) /**< 4MB total */
#define DR_FLASH_UID_LENGTH 8 /**< Unique ID length (bytes) */
/*==============================================================================
* W25Q32 COMMAND OPCODES
*============================================================================*/
#define DR_FLASH_CMD_WRITE_ENABLE 0x06
#define DR_FLASH_CMD_WRITE_DISABLE 0x04
#define DR_FLASH_CMD_READ_STATUS1 0x05
#define DR_FLASH_CMD_READ_STATUS2 0x35
#define DR_FLASH_CMD_WRITE_STATUS 0x01
#define DR_FLASH_CMD_READ_DATA 0x03
#define DR_FLASH_CMD_PAGE_PROGRAM 0x02
#define DR_FLASH_CMD_SECTOR_ERASE 0x20 /**< 4KB erase */
#define DR_FLASH_CMD_BLOCK_ERASE_32K 0x52 /**< 32KB erase */
#define DR_FLASH_CMD_BLOCK_ERASE_64K 0xD8 /**< 64KB erase */
#define DR_FLASH_CMD_CHIP_ERASE 0xC7 /**< Full chip erase */
#define DR_FLASH_CMD_POWER_DOWN 0xB9 /**< Deep power-down */
#define DR_FLASH_CMD_RELEASE_PD 0xAB /**< Release from deep power-down */
#define DR_FLASH_CMD_READ_UID 0x4B /**< Read unique ID */
#define DR_FLASH_CMD_READ_JEDEC_ID 0x9F /**< Read JEDEC ID */
#define DR_FLASH_CMD_READ_MFR_ID 0x90 /**< Read manufacturer/device ID */
/* Status Register 1 bits */
#define DR_FLASH_SR1_BUSY 0x01 /**< Erase/Write in progress */
#define DR_FLASH_SR1_WEL 0x02 /**< Write enable latch */
/*==============================================================================
* ERROR CODES
*============================================================================*/
typedef enum {
DR_FLASH_OK = 0,
DR_FLASH_ERR_NOT_INIT,
DR_FLASH_ERR_INVALID_PARAM,
DR_FLASH_ERR_TIMEOUT,
DR_FLASH_ERR_WRITE_FAILED,
DR_FLASH_ERR_JEDEC_MISMATCH
} dr_flash_err_t;
/*==============================================================================
* DATA STRUCTURES
*============================================================================*/
/** @brief JEDEC ID structure */
typedef struct {
uint8_t manufacturer_id; /**< 0xEF = Winbond */
uint8_t memory_type; /**< 0x40 = SPI */
uint8_t capacity; /**< 0x16 = 32Mbit */
} dr_flash_jedec_t;
/*==============================================================================
* INITIALIZATION
*============================================================================*/
/**
* @brief Initialize W25Q32 Flash driver
* @return dr_flash_err_t Error code
* @note Sets up GPIO pins. Does NOT wake chip from deep power-down.
*/
dr_flash_err_t dr_w25q32_init(void);
/**
* @brief Uninitialize driver, release GPIO pins
*/
void dr_w25q32_uninit(void);
/**
* @brief Check if driver is initialized
*/
bool dr_w25q32_is_initialized(void);
/*==============================================================================
* IDENTIFICATION
*============================================================================*/
/**
* @brief Read JEDEC ID (manufacturer, type, capacity)
* @param jedec Pointer to JEDEC ID structure
* @return dr_flash_err_t Error code
* @note Expected: manufacturer=0xEF, type=0x40, capacity=0x16
*/
dr_flash_err_t dr_w25q32_read_jedec_id(dr_flash_jedec_t *jedec);
/**
* @brief Read 8-byte unique ID
* @param uid Buffer to store 8-byte UID (must be >= 8 bytes)
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_read_uid(uint8_t *uid);
/*==============================================================================
* READ
*============================================================================*/
/**
* @brief Read data from flash
* @param addr 24-bit start address (0x000000 ~ 0x3FFFFF)
* @param buf Buffer to store read data
* @param len Number of bytes to read
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_read(uint32_t addr, uint8_t *buf, uint32_t len);
/*==============================================================================
* WRITE
*============================================================================*/
/**
* @brief Write data to flash (page program, max 256 bytes)
* @param addr 24-bit start address (must be page-aligned for best results)
* @param data Data to write
* @param len Number of bytes (1~256, must not cross page boundary)
* @return dr_flash_err_t Error code
* @note Automatically sends Write Enable before programming.
* Waits for completion (BUSY flag).
*/
dr_flash_err_t dr_w25q32_write(uint32_t addr, const uint8_t *data, uint32_t len);
/*==============================================================================
* ERASE
*============================================================================*/
/**
* @brief Erase 4KB sector
* @param addr Any address within the sector to erase
* @return dr_flash_err_t Error code
* @note Typical 45ms, max 400ms. Waits for completion.
*/
dr_flash_err_t dr_w25q32_erase_sector(uint32_t addr);
/**
* @brief Erase 32KB block
* @param addr Any address within the block
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_erase_block_32k(uint32_t addr);
/**
* @brief Erase 64KB block
* @param addr Any address within the block
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_erase_block_64k(uint32_t addr);
/**
* @brief Erase entire chip
* @return dr_flash_err_t Error code
* @note Takes 6~50 seconds. Use with caution.
*/
dr_flash_err_t dr_w25q32_chip_erase(void);
/*==============================================================================
* POWER MANAGEMENT
*============================================================================*/
/**
* @brief Enter deep power-down mode (~1uA)
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_deep_powerdown(void);
/**
* @brief Release from deep power-down
* @return dr_flash_err_t Error code
* @note Requires ~3us recovery time (handled internally)
*/
dr_flash_err_t dr_w25q32_wakeup(void);
/*==============================================================================
* STATUS
*============================================================================*/
/**
* @brief Read Status Register 1
* @param status Pointer to store status byte
* @return dr_flash_err_t Error code
*/
dr_flash_err_t dr_w25q32_read_status(uint8_t *status);
/**
* @brief Check if flash is busy (erase/write in progress)
* @return true if busy
*/
bool dr_w25q32_is_busy(void);
/**
* @brief Wait until flash is not busy
* @param timeout_ms Maximum wait time in milliseconds
* @return dr_flash_err_t DR_FLASH_OK or DR_FLASH_ERR_TIMEOUT
*/
dr_flash_err_t dr_w25q32_wait_busy(uint32_t timeout_ms);
/*==============================================================================
* DEBUG / TEST
*============================================================================*/
/**
* @brief Test flash communication by reading JEDEC ID
* @return true if JEDEC ID matches W25Q32 (0xEF, 0x40, 0x16)
*/
bool dr_w25q32_test(void);
#endif /* DR_W25Q32_H */