Compare commits

..

6 Commits

Author SHA1 Message Date
jh.chun ab74582568 IMU FIFO 동시 진입 방지 및 MCLK ready timeout 추가
- IMU FIFO capture가 이미 활성화되어 있는 상태에서 msp?/mim? 등이 들어오는 경우 요청 무시
- MCLK_RDY 대기에 timeout 추가해 IMU/I2C 상태가 꼬였을 때 메인 루프가 멈추지 않도록 함
2026-07-08 14:51:29 +09:00
jh.chun b75c99b125 IMU FIFO 커맨드 mim? 추가 2026-07-06 12:04:44 +09:00
jh.chun 763abb0fcc Piezo 측정 파라미터 공용 헤더 추가 및 최대 샘플 수 118개로 변경
- reb: 패킷에 채널 정보 2바이트가 추가되어 단일 패킷 최대 샘플 수를 119개에서 118개로 조정
2026-06-26 17:40:05 +09:00
jh.chun 80d7086d09 bootloader DFU 배치 파일
- DFU를 통한 bootloader 반영을 위해 생성
- 현재 nrfutil 버전에서는 App + bootloader를 한 zip 파일에 넣을 수 없어 개별 생성
2026-06-26 17:34:40 +09:00
jh.chun 39cf6068f7 주석 정리 2026-06-26 17:28:52 +09:00
jh.chun 0d719751c4 DFU activation 후 App 부팅 시 전원 OFF 처리 추가 2026-06-26 17:22:56 +09:00
11 changed files with 201 additions and 19 deletions
@@ -50,6 +50,8 @@ extern int imu_read_direct(void);
extern int imu_read_temperature_x100(uint16_t *temp_x100, float *temp_c);
extern int imu_fifo_capture_start(void);
extern int imu_fifo_capture_stop_and_send_rim(void);
extern int imu_fifo_capture_wait_samples_and_send_rim(uint16_t target_samples, uint32_t timeout_ms);
extern void imu_fifo_capture_disable(void);
extern void battery_timer_stop(void);
extern void main_timer_start(void);
extern void hw_i2c_init_once(void);
@@ -41,6 +41,7 @@ static const CmdEntry m_cmd_table[] = {
{ "msn?", true, Cmd_msn },
{ "mst?", true, Cmd_mst },
{ "msp?", true, Cmd_msp },
{ "mim?", true, Cmd_mim },
/* D. Piezo ultrasound */
{ "mpa?", true, Cmd_mpa },
@@ -4,11 +4,13 @@
* msn? -> rsn: battery ADC measurement
* mst? -> rso: IMU die temperature reading
* msp? -> rsp: IMU 6-axis single read
* mim? -> rim: IMU FIFO 15-sample read
* all_sensors() bulk-measurement helper used by the mbb? handler
*============================================================================*/
#include "cmd_common.h"
#include "cmd_sensor.h"
#include "app_raw.h"
/*==============================================================================
* msn? -> rsn: Battery level ADC measurement
@@ -47,6 +49,7 @@ int Cmd_mst(const ParsedCmd *cmd)
/*==============================================================================
* msp? -> rsp: IMU 6-axis single read
* mim? -> rim: IMU FIFO 15-sample read
*
* Request: [TAG 4B "msp?"] [CRC 2B]
* Response: rsp: + accel(xyz) + gyro(xyz) (transmitted inside imu_read_direct)
@@ -56,11 +59,49 @@ int Cmd_mst(const ParsedCmd *cmd)
int Cmd_msp(const ParsedCmd *cmd)
{
(void)cmd;
if (imu_fifo_capture_is_active())
{
return 1; // already owned by mtb?/mim?, ignore duplicate request
}
hw_i2c_init_once();
imu_read_direct();
return 1;
}
/*==============================================================================
* mim? -> rim: IMU FIFO-only capture
*
* Request: [TAG 4B "mim?"] [CRC 2B]
* Response: rim: [total_sample_count u16 BE]
* [samples: 12B each ax,ay,az,gx,gy,gz ...]
*
* Uses the same FIFO/rim path as mtb? but without piezo reb:/raa: packets.
* At 50 Hz, 15 samples are about 300 ms; timeout leaves margin for startup.
*============================================================================*/
int Cmd_mim(const ParsedCmd *cmd)
{
int rc;
(void)cmd;
if (imu_fifo_capture_is_active())
{
return 1; // already owned by mtb?/mim?, ignore duplicate request
}
rc = imu_fifo_capture_start();
if (rc != 0)
{
(void)imu_fifo_capture_stop_and_send_rim();
imu_fifo_capture_disable();
return 1;
}
(void)imu_fifo_capture_wait_samples_and_send_rim(15, 500);
return 1;
}
/*==============================================================================
* all_sensors() - Bulk-measurement helper for the mbb? handler
*
@@ -9,6 +9,7 @@
int Cmd_msn(const ParsedCmd *cmd); /* msn? -> rsn: battery ADC measurement */
int Cmd_mst(const ParsedCmd *cmd); /* mst? -> rso: IMU die temperature */
int Cmd_msp(const ParsedCmd *cmd); /* msp? -> rsp: IMU 6-axis single read */
int Cmd_mim(const ParsedCmd *cmd); /* mim? -> rim: IMU FIFO 15 samples */
/* Helper for the mbb? handler: sequentially measures battery / IMU / temperature, then emits a single rbb: response.
* Called from Cmd_mbb() in cmd_piezo.c. */
void all_sensors(void);
@@ -0,0 +1,66 @@
@echo off
chcp 437
setlocal EnableExtensions
cd /d "%~dp0"
set "APP_HEX=medithings_bladder_patch_0001.hex"
set "BOOT_HEX=medithings_bladder_patch_bootloader.hex"
set "OUT_APP_ZIP=medithings_bladder_patch_dfu.zip"
set "OUT_BOOT_ZIP=medithings_bladder_patch_bootloader_dfu.zip"
REM Bootloader DFU requires a version greater than the currently installed bootloader_version.
REM cpd/cpd_eraseALL currently install bootloader-version 1, so use 2 for this update.
set "APP_VERSION=1"
set "BOOTLOADER_VERSION=2"
set "HW_VERSION=52"
set "SD_REQ=0x0100"
set "SD_ID=0x0100"
echo [1/4] Copying application HEX...
copy /Y "..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex" "%APP_HEX%"
if errorlevel 1 goto fail
echo [2/4] Copying bootloader HEX...
copy /Y "..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex" "%BOOT_HEX%"
if errorlevel 1 goto fail
echo [3/4] Generating application DFU package...
nrfutil pkg generate ^
--application "%APP_HEX%" ^
--application-version %APP_VERSION% ^
--hw-version %HW_VERSION% ^
--sd-req %SD_REQ% ^
--sd-id %SD_ID% ^
--key-file private.key ^
"%OUT_APP_ZIP%"
if errorlevel 1 goto fail
echo [4/4] Generating bootloader DFU package...
nrfutil pkg generate ^
--bootloader "%BOOT_HEX%" ^
--bootloader-version %BOOTLOADER_VERSION% ^
--hw-version %HW_VERSION% ^
--sd-req %SD_REQ% ^
--key-file private.key ^
"%OUT_BOOT_ZIP%"
if errorlevel 1 goto fail
echo.
echo Done:
echo %OUT_APP_ZIP%
echo %OUT_BOOT_ZIP%
echo Bootloader version: %BOOTLOADER_VERSION%
echo.
echo Update order for both app and bootloader changes:
echo 1. Send %OUT_BOOT_ZIP%
echo 2. Power on again if the device powers off
echo 3. Send %OUT_APP_ZIP%
pause
exit /b 0
:fail
echo.
echo ERROR: Failed to generate DFU package(s).
pause
exit /b 1
@@ -231,7 +231,7 @@ static char * roles_str[] = {"INVALID_ROLE", "CENTRAL", "PERIPHERAL"};
/*==============================================================================
* Global Variables
* IEC 62304 §5.5.3: all global buffers zero-initialized for deterministic startup
* IEC 62304 5.5.3: all global buffers zero-initialized for deterministic startup
*============================================================================*/
volatile uint8_t Sj_type; /* Command type identifier */
bool power_off_duble_prohibit = false; /* Power-off double prevention flag */
@@ -1546,7 +1546,7 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
DBG_PRINTF("[BLE] Connected\r\n");
#if BLE_DEV_MODE
/* Dev: no passkey/SEC allow NUS TX/RX as soon as GAP is up (prod uses PM_EVT_CONN_SEC_SUCCEEDED). */
/* Dev: no passkey/SEC - allow NUS TX/RX as soon as GAP is up (prod uses PM_EVT_CONN_SEC_SUCCEEDED). */
ble_connection_st = BLE_CONNECTED_ST;
battery_timer_start();
#endif
@@ -2077,6 +2077,7 @@ static void main_s(void * p_context)
bool button_released = nrf_gpio_pin_read(POWER_BUTTON);
/* ---- Running phase: post-boot button polling ---- */
if (booted)
{
@@ -2121,7 +2122,7 @@ static void main_s(void * p_context)
go_device_power_off = true;
main_timer_start();
}
else if (cnt_s > 250 || (m_reset_status == 2)) /* 250 x 5ms = 1.25s + α */
else if (cnt_s > 250 || (m_reset_status == 2)) /* 250 x 5ms = 1.25s + ¥á */
{
DBG_PRINTF("[BTN] Boot (cnt=%d)\r\n", cnt_s);
device_reset = false;
@@ -2150,7 +2151,7 @@ static void main_s(void * p_context)
cnt_s++;
device_reset = false;
if (cnt_s == 250) /* 250 x 5ms = 1.25s + α */
if (cnt_s == 250) /* 250 x 5ms = 1.25s + ¥á */
{
led_set_state(LED_STATE_POWER_ON);
DBG_PRINTF("[BTN] 2.0s\r\n");
@@ -2171,7 +2172,7 @@ int main(void)
{
bool erase_bonds_local = false;
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Phase 1: Basic hardware init (BLE-independent)
*
* - Power self-latch (P0.8 HIGH)
@@ -2180,7 +2181,7 @@ int main(void)
* - App timers (power polling, battery, main loop)
* - Default config (serial number, passkey)
* - Buttons/LEDs
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
power_hold_init();
if ((NRF_POWER->GPREGRET2 & POST_DFU_APP_BOOT_GPREGRET2_MASK) != 0)
@@ -2203,7 +2204,7 @@ int main(void)
log_init();
DBG_PRINTF("\r\n========================================\r\n");
DBG_PRINTF(" Medithings v1.17\r\n");
DBG_PRINTF(" Medithings VesiScan-Basic\r\n");
DBG_PRINTF("========================================\r\n");
DBG_PRINTF("[1] HW Init\r\n");
@@ -2217,33 +2218,33 @@ int main(void)
#endif
DBG_PRINTF(" gpio/timer/config/btn OK\r\n");
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Phase 2: BLE stack init
*
* - Power management module (WFE/sleep when idle)
* - SoftDevice S140 (BLE 5.0 protocol stack)
* - DC-DC converter enable (required after SoftDevice)
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
DBG_PRINTF("[2] BLE Stack\r\n");
power_management_init();
ble_stack_init();
APP_ERROR_CHECK(sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE));
DBG_PRINTF(" pwr/stack/dcdc OK\r\n");
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Phase 3: Internal flash config (must init after BLE stack)
*
* - FDS (Flash Data Storage) init
* - Read stored config from flash (serial, passkey, piezo, etc.)
* - Overwrite defaults with flash values
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
DBG_PRINTF("[3] FDS\r\n");
fs_storage_init();
config_load();
load_flash_config();
DBG_PRINTF(" fds OK\r\n");
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Phase 4: BLE protocol setup
*
* - GAP: device name (serial number), connection params, passkey
@@ -2252,7 +2253,7 @@ int main(void)
* - Advertising: advertising data (name, UUID)
* - Connection parameter negotiation module
* - Security: Peer Manager (bonding/passkey)
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
DBG_PRINTF("[4] BLE Protocol\r\n");
gap_params_init();
gatt_init();
@@ -2287,14 +2288,14 @@ int main(void)
DBG_PRINTF(" fds defaults saved\r\n");
}
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Phase 5: Application init
*
* - Command parser: process BLE received commands (log, BLE TX, CRC)
* - Piezo driver: GPIO/Timer/PPI setup for ultrasound measurement
* - IMU (ICM42670P) is NOT initialized here
* -> imu_read_direct() self-configures/reads/sleeps on each msp? command
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
DBG_PRINTF("[5] App\r\n");
g_plat.log = log_printf;
g_plat.tx_bin = dr_binary_tx_safe;
@@ -2304,9 +2305,9 @@ int main(void)
dr_piezo_init();
DBG_PRINTF(" parser/piezo OK\r\n");
/*──────────────────────────────────────────────────────────────
/*--------------------------------------------------------------------------
* Boot complete -> start power button state machine
*────────────────────────────────────────────────────────────*/
*--------------------------------------------------------------------------*/
DBG_PRINTF("\r\n========================================\r\n");
DBG_PRINTF(" READY [%s]\r\n", SERIAL_NO);
DBG_PRINTF("========================================\r\n\r\n");
@@ -51,9 +51,12 @@
* - VBTFW0119 260615 jhChun
* : Replaced all TMP235 temperature paths with IMU register direct-read temperature and removed legacy TMP235 build references.
* : Unify both IMU direct-read and FIFO outputs as raw data in datasheet axis convention.
* : Added mim? command (rim:, IMU FIFO-only 15 samples at 50 Hz).
* - VBTFW0120 260615 jhChun : Add EMC mitigation logic for BLE link stability: extended supervision timeout and dynamic TX power control based on RSSI, RSSI silence, HVN latency, and TX queue congestion.
* - VBTFW0121 260703 jhChun : Add mim? cammand.
* - VBTFW0122 260708 jhChun : Prevent IMU FIFO reentry and add MCLK ready timeout.
------------------------------------------------------------------------- */
#define FIRMWARE_VERSION "VBTFW0129"
#define FIRMWARE_VERSION "VBTFW0122"
/*==============================================================================
* Data Length Constants
@@ -101,6 +101,7 @@ int inv_imu_switch_on_mclk(struct inv_imu_device *s)
int status = 0;
uint8_t data;
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
uint64_t start;
/* set IDLE bit only if it is not set yet */
if (t->need_mclk_cnt == 0) {
@@ -112,9 +113,23 @@ int inv_imu_switch_on_mclk(struct inv_imu_device *s)
if (status)
return status;
start = inv_imu_get_time_us();
/* Check if MCLK is ready */
do {
status = inv_imu_read_reg(s, MCLK_RDY, 1, &data);
/* Bound the MCLK wait so a bad IMU/I2C state cannot hang the main loop. */
if ((inv_imu_get_time_us() - start) >= 50000U)
{
status = 0;
if (inv_imu_read_reg(s, PWR_MGMT0, 1, &data) == 0)
{
data &= ~PWR_MGMT0_IDLE_MASK;
(void)inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
}
return INV_ERROR_TIMEOUT;
}
} while ((status != 0) || !(data & MCLK_RDY_MCLK_RDY_MASK));
} else {
@@ -986,3 +986,48 @@ int imu_fifo_capture_stop_and_send_rim(void)
imu_fifo_send_rim_packets(packet_count);
return 0;
}
int imu_fifo_capture_wait_samples_and_send_rim(uint16_t target_samples, uint32_t timeout_ms)
{
int rc = 0;
uint8_t count_raw[2] = {0};
uint16_t packet_count = 0;
uint32_t waited_ms = 0;
const uint32_t poll_ms = 10U;
if (target_samples == 0U)
{
return imu_fifo_capture_stop_and_send_rim();
}
if (!s_fifo_capture_active)
{
imu_fifo_send_rim_packets(0);
return -1;
}
while (waited_ms <= timeout_ms)
{
rc = inv_imu_read_reg(&icm_driver, FIFO_COUNTH, 2, count_raw);
if (rc != 0)
{
DBG_PRINTF("[IMU FIFO] count read fail %d\r\n", rc);
imu_fifo_send_rim_packets(0);
imu_fifo_power_off();
return rc;
}
packet_count = (uint16_t)count_raw[0] | ((uint16_t)count_raw[1] << 8);
if (packet_count > target_samples)
{
break;
}
dr_sd_delay_ms(poll_ms);
waited_ms += poll_ms;
}
rc = imu_fifo_capture_stop_and_send_rim();
imu_fifo_capture_disable();
return rc;
}
@@ -122,6 +122,13 @@ int imu_fifo_capture_start(void);
*/
int imu_fifo_capture_stop_and_send_rim(void);
/**
* \brief Wait until at least target_samples FIFO records are available, then drain
* FIFO and send rim: packets.
* \return 0=success, negative=error
*/
int imu_fifo_capture_wait_samples_and_send_rim(uint16_t target_samples, uint32_t timeout_ms);
/**
* \brief Stop IMU FIFO capture without sending rim: packets.
*/
@@ -22,7 +22,7 @@
#define PIEZO_CONFIG_DELAY_US_DEFAULT 10U
#define PIEZO_CONFIG_NUM_SAMPLES_MIN 80U
#define PIEZO_CONFIG_NUM_SAMPLES_MAX 117U
#define PIEZO_CONFIG_NUM_SAMPLES_MAX 118U
#define PIEZO_CONFIG_NUM_SAMPLES_DEFAULT 100U