프로젝트 정리: 앱 내부 구조 수정

- measurement/hal/system/command
This commit is contained in:
2026-04-15 15:28:09 +09:00
parent e272347664
commit 95894eacd4
66 changed files with 16078 additions and 16089 deletions

View File

@@ -1,11 +0,0 @@
{
"folders": [
{
"path": "../../.."
},
{
"path": "../../../../pc_firm"
}
],
"settings": {}
}

View File

@@ -1,22 +1,22 @@
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
pause

View File

@@ -1,21 +1,21 @@
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
pause

View File

@@ -1,22 +1,22 @@
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
pause

View File

@@ -1,30 +1,30 @@
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --memrd 0x10001208
nrfjprog --family NRF52 --recover
nrfjprog --memrd 0x10001208
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex --verify
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
nrfjprog --memwr 0x10001208 --val 0x00
nrfjprog --memrd 0x10001208
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --memrd 0x10001208
nrfjprog --family NRF52 --recover
nrfjprog --memrd 0x10001208
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --program medithings_bladder_patch_dfu_merged_all.hex --verify
nrfjprog --family NRF52 --reset
nrfjprog --family NRF52 --rbp ALL
nrfjprog --memwr 0x10001208 --val 0x00
nrfjprog --memrd 0x10001208
pause

View File

@@ -1,20 +1,20 @@
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --program medithings_bladder_patch_0001.hex
nrfjprog --family NRF52 --reset
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
copy ..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex medithings_bladder_patch_bootloader.hex
nrfutil settings generate --family NRF52840 --application medithings_bladder_patch_0001.hex --application-version 1 --bootloader-version 1 --bl-settings-version 2 medithings_bladder_patch_bootloader_setting.hex
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex medithings_bladder_patch_0001.hex --output medithings_bladder_patch_merged_1.hex
mergehex.exe --merge medithings_bladder_patch_bootloader.hex medithings_bladder_patch_bootloader_setting.hex --output medithings_bladder_patch_merged_2.hex
mergehex.exe --merge medithings_bladder_patch_merged_1.hex medithings_bladder_patch_merged_2.hex --output medithings_bladder_patch_dfu_merged_all.hex
nrfjprog --family NRF52 --program medithings_bladder_patch_0001.hex
nrfjprog --family NRF52 --reset
pause

View File

@@ -1,137 +1,137 @@
@echo off
setlocal enabledelayedexpansion
echo ==========================================
echo MEDiThings Bladder Patch Programming
echo (mergehex + nrfutil 8.x)
echo ==========================================
REM -----------------------------------------------------
REM Create hex output folder
REM -----------------------------------------------------
if not exist hex mkdir hex
REM -----------------------------------------------------
REM 1. Copy HEX files
REM -----------------------------------------------------
echo [1/7] Copying HEX files...
copy "..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex" hex\app.hex
copy "..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex" hex\boot.hex
if %errorlevel% neq 0 (
echo ERROR: failed copying files.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 2. Generate Bootloader DFU Settings
REM -----------------------------------------------------
echo [2/7] Generating Bootloader DFU settings...
nrfutil settings generate ^
--family NRF52840 ^
--application hex\app.hex ^
--application-version 1 ^
--bootloader-version 1 ^
--bl-settings-version 2 ^
hex\settings.hex
if %errorlevel% neq 0 (
echo ERROR: nrfutil settings failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 3. Merge HEX (SoftDevice + Application)
REM -----------------------------------------------------
echo [3/7] Merging SoftDevice + Application...
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex hex\app.hex --output hex\part1.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part1 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 4. Merge HEX (Bootloader + Settings)
REM -----------------------------------------------------
echo [4/7] Merging Bootloader + Settings...
mergehex.exe --merge hex\boot.hex hex\settings.hex --output hex\part2.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part2 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 5. Final HEX merge (Combine everything)
REM -----------------------------------------------------
echo [5/7] Creating final combined HEX...
mergehex.exe --merge hex\part1.hex hex\part2.hex --output hex\firmware_all.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex final merge failed.
pause
exit /b 1
)
echo Final merged HEX: hex\firmware_all.hex
REM -----------------------------------------------------
REM 6. Detect device SERIAL NUMBER
REM -----------------------------------------------------
echo [6/7] Detecting device serial number...
for /f %%A in ('
powershell -Command "(nrfutil device list --json | Select-String '\"type\":\"info\"' | ConvertFrom-Json).data.devices[0].serialNumber"
') do set SERIALNUMBER=%%A
if "%SERIALNUMBER%"=="" (
echo ERROR: No serial number found.
pause
exit /b 1
)
echo Using Serial Number: %SERIALNUMBER%
echo Flashing: recover → erase → program → reset
REM recover
nrfutil device recover --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM erase
nrfutil device erase --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM program
nrfutil device program --firmware hex\firmware_all.hex --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM reset
nrfutil device reset --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
goto flash_success
:flash_fail
echo ERROR: Flashing failed.
pause
exit /b 1
:flash_success
REM -----------------------------------------------------
REM 7. Set Readback Protection (RBP)
REM -----------------------------------------------------
echo [7/7] Setting Readback Protection (ALL)...
nrfutil device protection-set ALL --serial-number %SERIALNUMBER%
echo ==========================================
echo Programming Complete!
echo %date% %time%
echo ==========================================
pause
endlocal
@echo off
setlocal enabledelayedexpansion
echo ==========================================
echo MEDiThings Bladder Patch Programming
echo (mergehex + nrfutil 8.x)
echo ==========================================
REM -----------------------------------------------------
REM Create hex output folder
REM -----------------------------------------------------
if not exist hex mkdir hex
REM -----------------------------------------------------
REM 1. Copy HEX files
REM -----------------------------------------------------
echo [1/7] Copying HEX files...
copy "..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex" hex\app.hex
copy "..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex" hex\boot.hex
if %errorlevel% neq 0 (
echo ERROR: failed copying files.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 2. Generate Bootloader DFU Settings
REM -----------------------------------------------------
echo [2/7] Generating Bootloader DFU settings...
nrfutil settings generate ^
--family NRF52840 ^
--application hex\app.hex ^
--application-version 1 ^
--bootloader-version 1 ^
--bl-settings-version 2 ^
hex\settings.hex
if %errorlevel% neq 0 (
echo ERROR: nrfutil settings failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 3. Merge HEX (SoftDevice + Application)
REM -----------------------------------------------------
echo [3/7] Merging SoftDevice + Application...
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex hex\app.hex --output hex\part1.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part1 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 4. Merge HEX (Bootloader + Settings)
REM -----------------------------------------------------
echo [4/7] Merging Bootloader + Settings...
mergehex.exe --merge hex\boot.hex hex\settings.hex --output hex\part2.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part2 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 5. Final HEX merge (Combine everything)
REM -----------------------------------------------------
echo [5/7] Creating final combined HEX...
mergehex.exe --merge hex\part1.hex hex\part2.hex --output hex\firmware_all.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex final merge failed.
pause
exit /b 1
)
echo Final merged HEX: hex\firmware_all.hex
REM -----------------------------------------------------
REM 6. Detect device SERIAL NUMBER
REM -----------------------------------------------------
echo [6/7] Detecting device serial number...
for /f %%A in ('
powershell -Command "(nrfutil device list --json | Select-String '\"type\":\"info\"' | ConvertFrom-Json).data.devices[0].serialNumber"
') do set SERIALNUMBER=%%A
if "%SERIALNUMBER%"=="" (
echo ERROR: No serial number found.
pause
exit /b 1
)
echo Using Serial Number: %SERIALNUMBER%
echo Flashing: recover → erase → program → reset
REM recover
nrfutil device recover --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM erase
nrfutil device erase --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM program
nrfutil device program --firmware hex\firmware_all.hex --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
REM reset
nrfutil device reset --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
goto flash_success
:flash_fail
echo ERROR: Flashing failed.
pause
exit /b 1
:flash_success
REM -----------------------------------------------------
REM 7. Set Readback Protection (RBP)
REM -----------------------------------------------------
echo [7/7] Setting Readback Protection (ALL)...
nrfutil device protection-set ALL --serial-number %SERIALNUMBER%
echo ==========================================
echo Programming Complete!
echo %date% %time%
echo ==========================================
pause
endlocal

View File

@@ -1,183 +1,183 @@
@echo off
setlocal enabledelayedexpansion
echo ==========================================
echo MEDiThings Bladder Patch Programming
echo (DEBUG MODE - No Readback Protection)
echo ==========================================
REM -----------------------------------------------------
REM Set script directory as base path
REM -----------------------------------------------------
cd /d "%~dp0"
echo Working directory: %CD%
REM -----------------------------------------------------
REM Create hex output folder
REM -----------------------------------------------------
if not exist hex mkdir hex
REM -----------------------------------------------------
REM 1. Copy HEX files (with verification)
REM -----------------------------------------------------
echo [1/6] Copying HEX files...
set "APP_SRC=..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex"
set "BOOT_SRC=..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex"
REM Check source files exist
if not exist "%APP_SRC%" (
echo ERROR: Application HEX not found: %APP_SRC%
pause
exit /b 1
)
if not exist "%BOOT_SRC%" (
echo ERROR: Bootloader HEX not found: %BOOT_SRC%
pause
exit /b 1
)
REM Copy with /Y to overwrite without prompt
copy /Y "%APP_SRC%" hex\app.hex
if %errorlevel% neq 0 (
echo ERROR: Failed to copy app.hex
pause
exit /b 1
)
echo - app.hex copied OK
copy /Y "%BOOT_SRC%" hex\boot.hex
if %errorlevel% neq 0 (
echo ERROR: Failed to copy boot.hex
pause
exit /b 1
)
echo - boot.hex copied OK
REM -----------------------------------------------------
REM 2. Generate Bootloader DFU Settings
REM -----------------------------------------------------
echo [2/6] Generating Bootloader DFU settings...
nrfutil settings generate ^
--family NRF52840 ^
--application hex\app.hex ^
--application-version 1 ^
--bootloader-version 1 ^
--bl-settings-version 2 ^
hex\settings.hex
if %errorlevel% neq 0 (
echo ERROR: nrfutil settings failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 3. Merge HEX (SoftDevice + Application)
REM -----------------------------------------------------
echo [3/6] Merging SoftDevice + Application...
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex hex\app.hex --output hex\part1.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part1 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 4. Merge HEX (Bootloader + Settings)
REM -----------------------------------------------------
echo [4/6] Merging Bootloader + Settings...
mergehex.exe --merge hex\boot.hex hex\settings.hex --output hex\part2.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part2 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 5. Final HEX merge (Combine everything)
REM -----------------------------------------------------
echo [5/6] Creating final combined HEX...
mergehex.exe --merge hex\part1.hex hex\part2.hex --output hex\firmware_all.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex final merge failed.
pause
exit /b 1
)
echo Final merged HEX: hex\firmware_all.hex
REM -----------------------------------------------------
REM 6. Detect device SERIAL NUMBER and Flash
REM -----------------------------------------------------
echo [6/6] Detecting device serial number...
for /f %%A in ('
powershell -Command "(nrfutil device list --json | Select-String '\"type\":\"info\"' | ConvertFrom-Json).data.devices[0].serialNumber"
') do set SERIALNUMBER=%%A
if "%SERIALNUMBER%"=="" (
echo ERROR: No serial number found.
pause
exit /b 1
)
echo Using Serial Number: %SERIALNUMBER%
echo Flashing: program → reset (NO erase, FDS preserved)
REM recover - SKIP to preserve internal flash data
REM erase - SKIP to preserve FDS/fstorage data
REM program (hex 데이터가 있는 영역만 erase, FDS 보존)
nrfutil device program --firmware hex\firmware_all.hex --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 (
echo.
echo [WARNING] Program failed - device may have Readback Protection enabled.
echo Recover will ERASE ALL flash including FDS data.
echo.
set /p RECOVER_YN="Recover and retry? (Y/N): "
if /i "!RECOVER_YN!"=="Y" (
echo Recovering device...
nrfutil device recover --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
echo Re-programming...
nrfutil device program --firmware hex\firmware_all.hex --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
) else (
goto flash_fail
)
)
REM reset
nrfutil device reset --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
goto flash_success
:flash_fail
echo ERROR: Flashing failed.
pause
exit /b 1
:flash_success
REM -----------------------------------------------------
REM NOTE: Readback Protection SKIPPED for debugging
REM -----------------------------------------------------
echo ==========================================
echo Programming Complete! (DEBUG MODE)
echo No Readback Protection Applied
echo Internal Flash (FDS) Preserved
echo %date% %time%
echo ==========================================
REM -----------------------------------------------------
REM Open J-Link RTT Viewer for RTT debugging
REM -----------------------------------------------------
echo Starting J-Link RTT Viewer...
endlocal
@echo off
setlocal enabledelayedexpansion
echo ==========================================
echo MEDiThings Bladder Patch Programming
echo (DEBUG MODE - No Readback Protection)
echo ==========================================
REM -----------------------------------------------------
REM Set script directory as base path
REM -----------------------------------------------------
cd /d "%~dp0"
echo Working directory: %CD%
REM -----------------------------------------------------
REM Create hex output folder
REM -----------------------------------------------------
if not exist hex mkdir hex
REM -----------------------------------------------------
REM 1. Copy HEX files (with verification)
REM -----------------------------------------------------
echo [1/6] Copying HEX files...
set "APP_SRC=..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex"
set "BOOT_SRC=..\..\..\dfu\secure_bootloader\pca10056_s140_ble\arm5_no_packs\_build\nrf52840_xxaa_s140.hex"
REM Check source files exist
if not exist "%APP_SRC%" (
echo ERROR: Application HEX not found: %APP_SRC%
pause
exit /b 1
)
if not exist "%BOOT_SRC%" (
echo ERROR: Bootloader HEX not found: %BOOT_SRC%
pause
exit /b 1
)
REM Copy with /Y to overwrite without prompt
copy /Y "%APP_SRC%" hex\app.hex
if %errorlevel% neq 0 (
echo ERROR: Failed to copy app.hex
pause
exit /b 1
)
echo - app.hex copied OK
copy /Y "%BOOT_SRC%" hex\boot.hex
if %errorlevel% neq 0 (
echo ERROR: Failed to copy boot.hex
pause
exit /b 1
)
echo - boot.hex copied OK
REM -----------------------------------------------------
REM 2. Generate Bootloader DFU Settings
REM -----------------------------------------------------
echo [2/6] Generating Bootloader DFU settings...
nrfutil settings generate ^
--family NRF52840 ^
--application hex\app.hex ^
--application-version 1 ^
--bootloader-version 1 ^
--bl-settings-version 2 ^
hex\settings.hex
if %errorlevel% neq 0 (
echo ERROR: nrfutil settings failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 3. Merge HEX (SoftDevice + Application)
REM -----------------------------------------------------
echo [3/6] Merging SoftDevice + Application...
mergehex.exe --merge s140_nrf52_7.2.0_softdevice.hex hex\app.hex --output hex\part1.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part1 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 4. Merge HEX (Bootloader + Settings)
REM -----------------------------------------------------
echo [4/6] Merging Bootloader + Settings...
mergehex.exe --merge hex\boot.hex hex\settings.hex --output hex\part2.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex part2 failed.
pause
exit /b 1
)
REM -----------------------------------------------------
REM 5. Final HEX merge (Combine everything)
REM -----------------------------------------------------
echo [5/6] Creating final combined HEX...
mergehex.exe --merge hex\part1.hex hex\part2.hex --output hex\firmware_all.hex
if %errorlevel% neq 0 (
echo ERROR: mergehex final merge failed.
pause
exit /b 1
)
echo Final merged HEX: hex\firmware_all.hex
REM -----------------------------------------------------
REM 6. Detect device SERIAL NUMBER and Flash
REM -----------------------------------------------------
echo [6/6] Detecting device serial number...
for /f %%A in ('
powershell -Command "(nrfutil device list --json | Select-String '\"type\":\"info\"' | ConvertFrom-Json).data.devices[0].serialNumber"
') do set SERIALNUMBER=%%A
if "%SERIALNUMBER%"=="" (
echo ERROR: No serial number found.
pause
exit /b 1
)
echo Using Serial Number: %SERIALNUMBER%
echo Flashing: program → reset (NO erase, FDS preserved)
REM recover - SKIP to preserve internal flash data
REM erase - SKIP to preserve FDS/fstorage data
REM program (hex 데이터가 있는 영역만 erase, FDS 보존)
nrfutil device program --firmware hex\firmware_all.hex --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 (
echo.
echo [WARNING] Program failed - device may have Readback Protection enabled.
echo Recover will ERASE ALL flash including FDS data.
echo.
set /p RECOVER_YN="Recover and retry? (Y/N): "
if /i "!RECOVER_YN!"=="Y" (
echo Recovering device...
nrfutil device recover --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
echo Re-programming...
nrfutil device program --firmware hex\firmware_all.hex --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
) else (
goto flash_fail
)
)
REM reset
nrfutil device reset --serial-number %SERIALNUMBER%
if %errorlevel% neq 0 goto flash_fail
goto flash_success
:flash_fail
echo ERROR: Flashing failed.
pause
exit /b 1
:flash_success
REM -----------------------------------------------------
REM NOTE: Readback Protection SKIPPED for debugging
REM -----------------------------------------------------
echo ==========================================
echo Programming Complete! (DEBUG MODE)
echo No Readback Protection Applied
echo Internal Flash (FDS) Preserved
echo %date% %time%
echo ==========================================
REM -----------------------------------------------------
REM Open J-Link RTT Viewer for RTT debugging
REM -----------------------------------------------------
echo Starting J-Link RTT Viewer...
endlocal

View File

@@ -1,3 +1,3 @@
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --eraseall
pause

View File

@@ -1,3 +1,3 @@
nrfjprog --family NRF52 --rbp ALL
nrfjprog --family NRF52 --pinreset
nrfjprog --family NRF52 --rbp ALL
nrfjprog --family NRF52 --pinreset
pause

View File

@@ -1,2 +1,2 @@
nrfjprog --family NRF52 --recover
nrfjprog --family NRF52 --recover
pause

View File

@@ -1,2 +1,2 @@
nrfjprog --family NRF52 --pinreset
nrfjprog --family NRF52 --pinreset
pause

View File

@@ -1,8 +1,8 @@
chcp 437
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
nrfutil pkg generate --application medithings_bladder_patch_0001.hex --application-version 1 --hw-version 52 --sd-req 0x0100 --sd-id 0x0100 --key-file private.key medithings_bladder_patch_dfu.zip
pause
chcp 437
set CURDIR=%cd%
copy ..\pca10056\s140\arm5_no_packs\_build\nrf52840_xxaa.hex medithings_bladder_patch_0001.hex
nrfutil pkg generate --application medithings_bladder_patch_0001.hex --application-version 1 --hw-version 52 --sd-req 0x0100 --sd-id 0x0100 --key-file private.key medithings_bladder_patch_dfu.zip
pause

View File

@@ -1,3 +1,3 @@
set path=d:\nrfutil\bin;%path%
d:
set path=d:\nrfutil\bin;%path%
d:
cd D:\mt_project\vesiscan\project\ble_peripheral\ble_app_bladder_patch\hex

View File

@@ -1,496 +1,496 @@
/*******************************************************************************
TEST medi50 Dec 23
******************************************************************************/
/**
* @file fstorage.c
* @brief FDS(Flash Data Storage)
*
* EEPROM을 nRF52840 /.
*
* [ ]
* - CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 .
*
* [config_data_t ]
* - magic(4B) : (0x20231226 -> 0x20260318( ))
* - hw_no(12B) : (: "")
* - serial_no(12B) : (: "VB026030000")
* - passkey(6B) : BLE (: "123456")
* - bond_data_delete(1B) : (: 1)
* - reset_status(1B) : (: 99)
* - life_cycle(4B) : (: 0)
* - piezo_freq_option : Piezo (: 1=2.1MHz)
* - piezo_cycles : Piezo (: 7)
* - piezo_averaging : Piezo (: 5)
* - piezo_delay_us : Piezo ADC (us) (: 10)
* - piezo_num_samples : Piezo ADC (: 100)
*
* [ ]
* - magic 0x20231226
* . .
*
* [FDS ]
* - FDS / , :
* OFF (go_device_power_off), (go_sleep_mode_enter),
* (go_NVIC_SystemReset)
*/
#include "sdk_config.h"
#include <string.h>
#include "app_error.h"
#include "boards.h"
#include "nrf_fstorage.h"
#include "nrf_soc.h"
#include "nrf_strerror.h"
#include "sdk_config.h"
#include "nrf_fstorage_sd.h"
#include "nrf_delay.h"
#include "ble_gap.h"
#include "fds.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "fstorage.h"
#include "nrf_pwr_mgmt.h"
#include "main.h"
#include "debug_print.h"
/* FDS 레코드 식별자: 파일 ID와 레코드 키로 단일 설정 레코드를 관리 */
#define CONFIG_FILE (0x8010)
#define CONFIG_REC_KEY (0x7010)
/* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */
#define CONFIG_MAGIC_NUMBER_VALUE (0x20260319)
/* 전역 설정 데이터 구조체 인스턴스 */
config_data_t m_config;
/* FDS 쓰기 완료 후 수행할 후처리 플래그 (main.c에서 선언) */
extern bool go_device_power_off; /* 전원 OFF 요청 */
extern bool go_sleep_mode_enter; /* 슬립 모드 진입 요청 */
extern bool go_NVIC_SystemReset; /* 시스템 리셋 요청 */
/* FDS 초기화 완료 여부 플래그 (fds_evt_handler에서 true로 설정) */
static bool volatile m_fds_initialized;
/* FDS 쓰기 진행 중 플래그: true이면 쓰기 완료 대기 중 */
bool fds_flag_write = false;
/* FDS에 기록할 레코드 템플릿 (m_config 데이터를 가리킴) */
static fds_record_t const m_dummy_record =
{
.file_id = CONFIG_FILE,
.key = CONFIG_REC_KEY,
.data.p_data = (void const *)&m_config,
/* The length of a record is always expressed in 4-byte units (words). */
.data.length_words = (sizeof(m_config) + 3) / sizeof(uint32_t),
};
/* 기본 설정값 상수 */
int8_t reset_status_dflt = 99; /* 리셋 상태 기본값 */
uint8_t static_passkey_dflt[6] = DEFAULT_PASSKEY; /* BLE 패스키 기본값 */
/**
* @brief
*
* m_config .
* .VB0HW0000
*/
void fds_default_value_set(void)
{
/* HW Number - default from HARDWARE_VERSION */
memset(m_config.hw_no, 0, 12);
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
/* Serial Number - default from SERIAL_NUMBER */
memset(m_config.serial_no, 0, 12);
memcpy(m_config.serial_no, SERIAL_NUMBER, strlen(SERIAL_NUMBER));
/* Static Passkey */
memcpy(m_config.static_passkey, static_passkey_dflt, 6);
/* Bond data delete */
m_config.bond_data_delete = 1;
/* Reset status */
m_config.reset_status = reset_status_dflt;
/* Device usage count */
m_config.life_cycle = 0;
/* 피에조 측정 파라미터 기본값 */
m_config.piezo_freq_option = 1; /* 2.1MHz */
m_config.piezo_delay_us = 10; /* 버스트 후 10us */
m_config.piezo_num_samples = 100; /* 100샘플 */
m_config.piezo_cycles = 7; /* 7사이클 */
m_config.piezo_averaging = 3; /* 3회 평균화 */
}
/* 마지막 FDS 이벤트 ID 저장 (디버깅용) */
static volatile uint8_t fds_last_evt = 0xFF;
/**
* @brief FDS
*
* FDS .
* - FDS_EVT_INIT : FDS m_fds_initialized
* - FDS_EVT_WRITE : fds_flag_write
* - FDS_EVT_UPDATE : fds_flag_write
* OFF / /
* - FDS_EVT_DEL_RECORD / FDS_EVT_DEL_FILE / FDS_EVT_GC :
*/
static void fds_evt_handler( fds_evt_t const *p_evt )
{
fds_last_evt = p_evt->id;
switch( p_evt->id )
{
case FDS_EVT_INIT:
if( p_evt->result == NRF_SUCCESS )
{
m_fds_initialized = true;
}
break;
case FDS_EVT_WRITE:
{
fds_flag_write = false;
}
break;
case FDS_EVT_UPDATE:
{
fds_flag_write = false;
if(go_device_power_off == true) {
/* After flash writing completed, System Power Off */
device_power_off();
}
if(go_sleep_mode_enter == true) {
/* After flash writing completed, System go to Sleep Mode */
sleep_mode_enter();
}
if(go_NVIC_SystemReset == true) {
/* After flash writing completed, System Reset */
DBG_PRINTF("Off FDS_EVENT\r\n");
NVIC_SystemReset();
}
}
break;
case FDS_EVT_DEL_RECORD:
break;
case FDS_EVT_DEL_FILE:
break;
case FDS_EVT_GC:
break;
default:
break;
}
}
/**
* @brief FDS
*
* m_fds_initialized true가 .
* 3(3000ms) ,
* .
*/
static void wait_for_fds_ready( void )
{
uint32_t timeout = 0;
while( !m_fds_initialized )
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
timeout++;
if (timeout > 3000) /* 3 second timeout */
{
DBG_PRINTF("[FDS] TIMEOUT!\r\n");
break;
}
}
}
/**
* @brief FDS에서
*
* CONFIG_FILE/CONFIG_REC_KEY m_config에 .
*
* :
* 1. fds_record_find() ( 10 , 100ms )
* 2. :
* - fds_record_open() (CRC )
* - m_config로
* -
* 3. :
* -
*/
void config_load( void )
{
ret_code_t rc;
fds_record_desc_t desc = { 0 };
fds_find_token_t tok = { 0 };
uint8_t cfg_retry = 0;
uint32_t fds_wait_cnt = 0; // FDS write 대기 카운터
cfg_load_start:
memset((char *)&desc, 0, sizeof(desc));
memset((char *)&tok, 0, sizeof(tok));
rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
DBG_PRINTF("[FDS] find rc=%u\r\n", rc);
/* FDS may not be fully ready yet - retry before writing defaults */
if (rc != NRF_SUCCESS && cfg_retry < 10)
{
cfg_retry++;
DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry);
nrf_delay_ms(100);
goto cfg_load_start;
}
if( rc == NRF_SUCCESS )
{
/* A config file is in flash. Let's update it. */
fds_flash_record_t config = { 0 };
/* Open the record and read its contents. */
rc = fds_record_open(&desc, &config);
if (rc != NRF_SUCCESS)
{
/* CRC error or corrupt record - delete and use defaults */
DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc);
(void)fds_record_delete(&desc);
fds_gc();
fds_default_value_set();
goto cfg_load_write_new;
}
/* Copy the configuration from flash into m_config. */
memcpy(&m_config, config.p_data, sizeof(config_data_t));
/* Close the record when done reading. */
rc = fds_record_close(&desc);
APP_ERROR_CHECK(rc);
DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE);
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
{ // first init
DBG_PRINTF("[FDS] FORMAT! overwriting with defaults\r\n");
rc = fds_record_delete(&desc);
APP_ERROR_CHECK(rc);
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
// default....
fds_default_value_set();
/* Write the updated record to flash. */
rc = fds_record_update(&desc, &m_dummy_record);
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
{
rc = fds_gc();
APP_ERROR_CHECK(rc);
}
else
{
APP_ERROR_CHECK(rc);
}
goto cfg_load_start;
}
DBG_PRINTF("[FDS] Loaded OK\r\n");
}
else
{
cfg_load_write_new:
DBG_PRINTF("[FDS] New - writing defaults\r\n");
/* System config not found (or corrupt); write a new one. */
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
// default....
fds_default_value_set();
fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record);
if (rc != NRF_SUCCESS)
{
DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc);
fds_flag_write = false;
}
fds_wait_cnt = 0; //
while(fds_flag_write && fds_wait_cnt < 3000) // FDS write 최대 3초 타임아웃
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
fds_wait_cnt++;
}
if(fds_flag_write) // FDS write 타임아웃 시 플래그 강제 해제
{
DBG_PRINTF("[FDS] write TIMEOUT! forcing flag clear\r\n");
fds_flag_write = false;
}
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
{
rc = fds_gc();
APP_ERROR_CHECK(rc);
}
else
{
APP_ERROR_CHECK(rc);
}
NRF_LOG_FLUSH();
goto cfg_load_start;
}
}
/**
* @brief FDS에
*
* m_config의 .
*
* :
* 1. FDS 3
* 2.
* 3. fds_record_update()
* - GC( )
* 4. fds_record_write()
*
* : fds_evt_handler() ,
* OFF// .
*/
void config_save( void )
{
ret_code_t rc;
fds_record_desc_t desc = { 0 };
fds_find_token_t tok = { 0 };
DBG_PRINTF("[CFG_SAVE] start\r\n");
/* Wait for any previous FDS operation to complete */
if (fds_flag_write)
{
uint32_t wait_cnt = 0;
DBG_PRINTF("[CFG_SAVE] waiting for prev FDS op...\r\n");
while (fds_flag_write && wait_cnt < 3000)
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
wait_cnt++;
}
if (fds_flag_write)
{
DBG_PRINTF("[CFG_SAVE] TIMEOUT! forcing flag clear\r\n");
fds_flag_write = false;
}
}
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
{
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
}
memset((char *)&desc, 0, sizeof(desc));
memset((char *)&tok, 0, sizeof(tok));
rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
DBG_PRINTF("[CFG_SAVE] find rc=%u\r\n", rc);
if( rc == NRF_SUCCESS )
{
fds_flag_write = true;
rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc);
if( rc == FDS_ERR_NO_SPACE_IN_FLASH )
{
fds_flag_write = false;
rc = fds_gc();
DBG_PRINTF("[CFG_SAVE] gc rc=%u, retry\r\n", rc);
fds_flag_write = true;
rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc);
}
if( rc != NRF_SUCCESS )
{
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
fds_flag_write = false;
}
}
else
{
DBG_PRINTF("[CFG_SAVE] not found, writing new\r\n");
fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc);
if( rc != NRF_SUCCESS )
{
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
fds_flag_write = false;
}
}
DBG_PRINTF("[CFG_SAVE] done\r\n");
}
/**
* @brief config_load()
*
* .
*/
void fs_set_value(void)
{
config_load();
}
/**
* @brief FDS
*
* FDS .
* 1. fds_register()
* 2. fds_init() FDS
* 3. wait_for_fds_ready() ( 3)
* 4. fds_stat()
*/
void fs_storage_init(void)
{
ret_code_t rc;
/* Register first to receive an event when initialization is complete. */
rc = fds_register(fds_evt_handler);
APP_ERROR_CHECK(rc);
rc = fds_init();
APP_ERROR_CHECK(rc);
/* Wait for fds to initialize. */
wait_for_fds_ready();
fds_stat_t stat = { 0 };
rc = fds_stat(&stat);
APP_ERROR_CHECK(rc);
DBG_PRINTF("[FDS] OK\r\n");
}
/*******************************************************************************
TEST medi50 Dec 23
******************************************************************************/
/**
* @file fstorage.c
* @brief FDS(Flash Data Storage)
*
* EEPROM을 nRF52840 /.
*
* [ ]
* - CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 .
*
* [config_data_t ]
* - magic(4B) : (0x20231226 -> 0x20260318( ))
* - hw_no(12B) : (: "")
* - serial_no(12B) : (: "VB026030000")
* - passkey(6B) : BLE (: "123456")
* - bond_data_delete(1B) : (: 1)
* - reset_status(1B) : (: 99)
* - life_cycle(4B) : (: 0)
* - piezo_freq_option : Piezo (: 1=2.1MHz)
* - piezo_cycles : Piezo (: 7)
* - piezo_averaging : Piezo (: 5)
* - piezo_delay_us : Piezo ADC (us) (: 10)
* - piezo_num_samples : Piezo ADC (: 100)
*
* [ ]
* - magic 0x20231226
* . .
*
* [FDS ]
* - FDS / , :
* OFF (go_device_power_off), (go_sleep_mode_enter),
* (go_NVIC_SystemReset)
*/
#include "sdk_config.h"
#include <string.h>
#include "app_error.h"
#include "boards.h"
#include "nrf_fstorage.h"
#include "nrf_soc.h"
#include "nrf_strerror.h"
#include "sdk_config.h"
#include "nrf_fstorage_sd.h"
#include "nrf_delay.h"
#include "ble_gap.h"
#include "fds.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "fstorage.h"
#include "nrf_pwr_mgmt.h"
#include "main.h"
#include "debug_print.h"
/* FDS 레코드 식별자: 파일 ID와 레코드 키로 단일 설정 레코드를 관리 */
#define CONFIG_FILE (0x8010)
#define CONFIG_REC_KEY (0x7010)
/* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */
#define CONFIG_MAGIC_NUMBER_VALUE (0x20260319)
/* 전역 설정 데이터 구조체 인스턴스 */
config_data_t m_config;
/* FDS 쓰기 완료 후 수행할 후처리 플래그 (main.c에서 선언) */
extern bool go_device_power_off; /* 전원 OFF 요청 */
extern bool go_sleep_mode_enter; /* 슬립 모드 진입 요청 */
extern bool go_NVIC_SystemReset; /* 시스템 리셋 요청 */
/* FDS 초기화 완료 여부 플래그 (fds_evt_handler에서 true로 설정) */
static bool volatile m_fds_initialized;
/* FDS 쓰기 진행 중 플래그: true이면 쓰기 완료 대기 중 */
bool fds_flag_write = false;
/* FDS에 기록할 레코드 템플릿 (m_config 데이터를 가리킴) */
static fds_record_t const m_dummy_record =
{
.file_id = CONFIG_FILE,
.key = CONFIG_REC_KEY,
.data.p_data = (void const *)&m_config,
/* The length of a record is always expressed in 4-byte units (words). */
.data.length_words = (sizeof(m_config) + 3) / sizeof(uint32_t),
};
/* 기본 설정값 상수 */
int8_t reset_status_dflt = 99; /* 리셋 상태 기본값 */
uint8_t static_passkey_dflt[6] = DEFAULT_PASSKEY; /* BLE 패스키 기본값 */
/**
* @brief
*
* m_config .
* .VB0HW0000
*/
void fds_default_value_set(void)
{
/* HW Number - default from HARDWARE_VERSION */
memset(m_config.hw_no, 0, 12);
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
/* Serial Number - default from SERIAL_NUMBER */
memset(m_config.serial_no, 0, 12);
memcpy(m_config.serial_no, SERIAL_NUMBER, strlen(SERIAL_NUMBER));
/* Static Passkey */
memcpy(m_config.static_passkey, static_passkey_dflt, 6);
/* Bond data delete */
m_config.bond_data_delete = 1;
/* Reset status */
m_config.reset_status = reset_status_dflt;
/* Device usage count */
m_config.life_cycle = 0;
/* 피에조 측정 파라미터 기본값 */
m_config.piezo_freq_option = 1; /* 2.1MHz */
m_config.piezo_delay_us = 10; /* 버스트 후 10us */
m_config.piezo_num_samples = 100; /* 100샘플 */
m_config.piezo_cycles = 7; /* 7사이클 */
m_config.piezo_averaging = 3; /* 3회 평균화 */
}
/* 마지막 FDS 이벤트 ID 저장 (디버깅용) */
static volatile uint8_t fds_last_evt = 0xFF;
/**
* @brief FDS
*
* FDS .
* - FDS_EVT_INIT : FDS m_fds_initialized
* - FDS_EVT_WRITE : fds_flag_write
* - FDS_EVT_UPDATE : fds_flag_write
* OFF / /
* - FDS_EVT_DEL_RECORD / FDS_EVT_DEL_FILE / FDS_EVT_GC :
*/
static void fds_evt_handler( fds_evt_t const *p_evt )
{
fds_last_evt = p_evt->id;
switch( p_evt->id )
{
case FDS_EVT_INIT:
if( p_evt->result == NRF_SUCCESS )
{
m_fds_initialized = true;
}
break;
case FDS_EVT_WRITE:
{
fds_flag_write = false;
}
break;
case FDS_EVT_UPDATE:
{
fds_flag_write = false;
if(go_device_power_off == true) {
/* After flash writing completed, System Power Off */
device_power_off();
}
if(go_sleep_mode_enter == true) {
/* After flash writing completed, System go to Sleep Mode */
sleep_mode_enter();
}
if(go_NVIC_SystemReset == true) {
/* After flash writing completed, System Reset */
DBG_PRINTF("Off FDS_EVENT\r\n");
NVIC_SystemReset();
}
}
break;
case FDS_EVT_DEL_RECORD:
break;
case FDS_EVT_DEL_FILE:
break;
case FDS_EVT_GC:
break;
default:
break;
}
}
/**
* @brief FDS
*
* m_fds_initialized true가 .
* 3(3000ms) ,
* .
*/
static void wait_for_fds_ready( void )
{
uint32_t timeout = 0;
while( !m_fds_initialized )
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
timeout++;
if (timeout > 3000) /* 3 second timeout */
{
DBG_PRINTF("[FDS] TIMEOUT!\r\n");
break;
}
}
}
/**
* @brief FDS에서
*
* CONFIG_FILE/CONFIG_REC_KEY m_config에 .
*
* :
* 1. fds_record_find() ( 10 , 100ms )
* 2. :
* - fds_record_open() (CRC )
* - m_config로
* -
* 3. :
* -
*/
void config_load( void )
{
ret_code_t rc;
fds_record_desc_t desc = { 0 };
fds_find_token_t tok = { 0 };
uint8_t cfg_retry = 0;
uint32_t fds_wait_cnt = 0; // FDS write 대기 카운터
cfg_load_start:
memset((char *)&desc, 0, sizeof(desc));
memset((char *)&tok, 0, sizeof(tok));
rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
DBG_PRINTF("[FDS] find rc=%u\r\n", rc);
/* FDS may not be fully ready yet - retry before writing defaults */
if (rc != NRF_SUCCESS && cfg_retry < 10)
{
cfg_retry++;
DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry);
nrf_delay_ms(100);
goto cfg_load_start;
}
if( rc == NRF_SUCCESS )
{
/* A config file is in flash. Let's update it. */
fds_flash_record_t config = { 0 };
/* Open the record and read its contents. */
rc = fds_record_open(&desc, &config);
if (rc != NRF_SUCCESS)
{
/* CRC error or corrupt record - delete and use defaults */
DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc);
(void)fds_record_delete(&desc);
fds_gc();
fds_default_value_set();
goto cfg_load_write_new;
}
/* Copy the configuration from flash into m_config. */
memcpy(&m_config, config.p_data, sizeof(config_data_t));
/* Close the record when done reading. */
rc = fds_record_close(&desc);
APP_ERROR_CHECK(rc);
DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE);
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
{ // first init
DBG_PRINTF("[FDS] FORMAT! overwriting with defaults\r\n");
rc = fds_record_delete(&desc);
APP_ERROR_CHECK(rc);
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
// default....
fds_default_value_set();
/* Write the updated record to flash. */
rc = fds_record_update(&desc, &m_dummy_record);
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
{
rc = fds_gc();
APP_ERROR_CHECK(rc);
}
else
{
APP_ERROR_CHECK(rc);
}
goto cfg_load_start;
}
DBG_PRINTF("[FDS] Loaded OK\r\n");
}
else
{
cfg_load_write_new:
DBG_PRINTF("[FDS] New - writing defaults\r\n");
/* System config not found (or corrupt); write a new one. */
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
// default....
fds_default_value_set();
fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record);
if (rc != NRF_SUCCESS)
{
DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc);
fds_flag_write = false;
}
fds_wait_cnt = 0; //
while(fds_flag_write && fds_wait_cnt < 3000) // FDS write 최대 3초 타임아웃
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
fds_wait_cnt++;
}
if(fds_flag_write) // FDS write 타임아웃 시 플래그 강제 해제
{
DBG_PRINTF("[FDS] write TIMEOUT! forcing flag clear\r\n");
fds_flag_write = false;
}
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
{
rc = fds_gc();
APP_ERROR_CHECK(rc);
}
else
{
APP_ERROR_CHECK(rc);
}
NRF_LOG_FLUSH();
goto cfg_load_start;
}
}
/**
* @brief FDS에
*
* m_config의 .
*
* :
* 1. FDS 3
* 2.
* 3. fds_record_update()
* - GC( )
* 4. fds_record_write()
*
* : fds_evt_handler() ,
* OFF// .
*/
void config_save( void )
{
ret_code_t rc;
fds_record_desc_t desc = { 0 };
fds_find_token_t tok = { 0 };
DBG_PRINTF("[CFG_SAVE] start\r\n");
/* Wait for any previous FDS operation to complete */
if (fds_flag_write)
{
uint32_t wait_cnt = 0;
DBG_PRINTF("[CFG_SAVE] waiting for prev FDS op...\r\n");
while (fds_flag_write && wait_cnt < 3000)
{
nrf_pwr_mgmt_run();
nrf_delay_ms(1);
wait_cnt++;
}
if (fds_flag_write)
{
DBG_PRINTF("[CFG_SAVE] TIMEOUT! forcing flag clear\r\n");
fds_flag_write = false;
}
}
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
{
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
}
memset((char *)&desc, 0, sizeof(desc));
memset((char *)&tok, 0, sizeof(tok));
rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
DBG_PRINTF("[CFG_SAVE] find rc=%u\r\n", rc);
if( rc == NRF_SUCCESS )
{
fds_flag_write = true;
rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc);
if( rc == FDS_ERR_NO_SPACE_IN_FLASH )
{
fds_flag_write = false;
rc = fds_gc();
DBG_PRINTF("[CFG_SAVE] gc rc=%u, retry\r\n", rc);
fds_flag_write = true;
rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc);
}
if( rc != NRF_SUCCESS )
{
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
fds_flag_write = false;
}
}
else
{
DBG_PRINTF("[CFG_SAVE] not found, writing new\r\n");
fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc);
if( rc != NRF_SUCCESS )
{
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
fds_flag_write = false;
}
}
DBG_PRINTF("[CFG_SAVE] done\r\n");
}
/**
* @brief config_load()
*
* .
*/
void fs_set_value(void)
{
config_load();
}
/**
* @brief FDS
*
* FDS .
* 1. fds_register()
* 2. fds_init() FDS
* 3. wait_for_fds_ready() ( 3)
* 4. fds_stat()
*/
void fs_storage_init(void)
{
ret_code_t rc;
/* Register first to receive an event when initialization is complete. */
rc = fds_register(fds_evt_handler);
APP_ERROR_CHECK(rc);
rc = fds_init();
APP_ERROR_CHECK(rc);
/* Wait for fds to initialize. */
wait_for_fds_ready();
fds_stat_t stat = { 0 };
rc = fds_stat(&stat);
APP_ERROR_CHECK(rc);
DBG_PRINTF("[FDS] OK\r\n");
}

View File

@@ -1,87 +1,87 @@
/*******************************************************************************
* @file fstorage.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief FDS(Flash Data Storage)
*******************************************************************************
*
* [ ]
* nRF52840 / FDS API.
* EEPROM을 , SoftDevice와 .
*
* [config_data_t ] (45, )
* magic_number(4B): (0x20231226)
* hw_no(12B):
* serial_no(12B): (BLE )
* static_passkey(6B): BLE ( 6)
* bond_data_delete(1B):
* reset_status(1B):
* pd_adc_cnt(1B): ADC
* pd_delay_us(2B): PD ()
* life_cycle(4B):
*
* [ API]
* fs_storage_init(): FDS ( 1)
* config_load(): FDS에서 ( )
* config_save(): FDS에
*
******************************************************************************/
#ifndef IHP_FSTORAGE_H_
#define IHP_FSTORAGE_H_
#include "sdk_config.h"
#include "nordic_common.h"
#include <stdint.h>
/* -------------------------------------------------------------------------
* (FDS )
*
*
* - VBTHW0100 = () Ver 1.00
* - VB0HW0100 = Ver 1.00
*
* Firmware
* - VBTFW0100 = () Ver 1.00
* - VB0FW0100 = Ver 1.00
*
*
* - VBT26030001 = () 26 3 1
* - VB026030001 = 26 3 1
------------------------------------------------------------------------- */
#define HARDWARE_VERSION "VBTHW0100"
#define SERIAL_NUMBER "VBT26030001"
#define DEFAULT_PASSKEY "123456"
#pragma pack(1)
typedef struct
{
uint32_t magic_number; /* 4B - 포맷 확인용 매직 넘버 */
char hw_no[12]; /* 12B - HW Version */
char serial_no[12]; /* 12B - Serial Number */
uint8_t static_passkey[6]; /* 6B - BLE Passkey */
uint8_t bond_data_delete; /* 1B - Bond delete flag */
int8_t reset_status; /* 1B - Reset status */
uint32_t life_cycle; /* 4B - Device usage count */
/* Piezo 측정 파라미터 - 8B */
uint8_t piezo_freq_option; /* 1B - Frequency : 송신 펄스 주파수 (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */
uint8_t piezo_cycles; /* 1B - Burst Cycle : 송신 펄스 사이클 수 (3~7) */
uint16_t piezo_averaging; /* 2B - 평균화 수 : 채널당 반복 측정 횟수 (1~10) */
uint16_t piezo_delay_us; /* 2B - 대기 시간(Delay) : 송신 펄스 출력 후 ADC 시작 시까지 대기시간 (us) (0~30) */
uint16_t piezo_num_samples; /* 2B - 측정 ADC 샘플 개수 (80~140) */
} config_data_t; /* Total: 48 bytes - FDS에 저장하는 디바이스 설정 */
extern config_data_t m_config;
void fds_default_value_set(void);
void config_load( void );
void config_save( void );
void fs_set_value(void);
void fs_storage_init(void);
#endif /* IHP_FSTORAGE_H_ */
/*******************************************************************************
* @file fstorage.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief FDS(Flash Data Storage)
*******************************************************************************
*
* [ ]
* nRF52840 / FDS API.
* EEPROM을 , SoftDevice와 .
*
* [config_data_t ] (45, )
* magic_number(4B): (0x20231226)
* hw_no(12B):
* serial_no(12B): (BLE )
* static_passkey(6B): BLE ( 6)
* bond_data_delete(1B):
* reset_status(1B):
* pd_adc_cnt(1B): ADC
* pd_delay_us(2B): PD ()
* life_cycle(4B):
*
* [ API]
* fs_storage_init(): FDS ( 1)
* config_load(): FDS에서 ( )
* config_save(): FDS에
*
******************************************************************************/
#ifndef IHP_FSTORAGE_H_
#define IHP_FSTORAGE_H_
#include "sdk_config.h"
#include "nordic_common.h"
#include <stdint.h>
/* -------------------------------------------------------------------------
* (FDS )
*
*
* - VBTHW0100 = () Ver 1.00
* - VB0HW0100 = Ver 1.00
*
* Firmware
* - VBTFW0100 = () Ver 1.00
* - VB0FW0100 = Ver 1.00
*
*
* - VBT26030001 = () 26 3 1
* - VB026030001 = 26 3 1
------------------------------------------------------------------------- */
#define HARDWARE_VERSION "VBTHW0100"
#define SERIAL_NUMBER "VBT26030001"
#define DEFAULT_PASSKEY "123456"
#pragma pack(1)
typedef struct
{
uint32_t magic_number; /* 4B - 포맷 확인용 매직 넘버 */
char hw_no[12]; /* 12B - HW Version */
char serial_no[12]; /* 12B - Serial Number */
uint8_t static_passkey[6]; /* 6B - BLE Passkey */
uint8_t bond_data_delete; /* 1B - Bond delete flag */
int8_t reset_status; /* 1B - Reset status */
uint32_t life_cycle; /* 4B - Device usage count */
/* Piezo 측정 파라미터 - 8B */
uint8_t piezo_freq_option; /* 1B - Frequency : 송신 펄스 주파수 (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */
uint8_t piezo_cycles; /* 1B - Burst Cycle : 송신 펄스 사이클 수 (3~7) */
uint16_t piezo_averaging; /* 2B - 평균화 수 : 채널당 반복 측정 횟수 (1~10) */
uint16_t piezo_delay_us; /* 2B - 대기 시간(Delay) : 송신 펄스 출력 후 ADC 시작 시까지 대기시간 (us) (0~30) */
uint16_t piezo_num_samples; /* 2B - 측정 ADC 샘플 개수 (80~140) */
} config_data_t; /* Total: 48 bytes - FDS에 저장하는 디바이스 설정 */
extern config_data_t m_config;
void fds_default_value_set(void);
void config_load( void );
void config_save( void );
void fs_set_value(void);
void fs_storage_init(void);
#endif /* IHP_FSTORAGE_H_ */

View File

@@ -1,170 +1,170 @@
/*******************************************************************************
* @file i2c_manager.c
* @brief Reliable HWSW I2C Switching Logic (with Mode Set Logging)
*******************************************************************************
*
* [ ]
* I2C HW( TWI) / SW( ) .
*
* - HW I2C: nRF52840 TWI (ICM42670P IMU , 400kHz)
* - SW I2C: GPIO I2C ( )
*
* [ ]
* SCL = P1.14 (ICM42670_I2C_SCL_PIN)
* SDA = P1.15 (ICM42670_I2C_SDA_PIN)
*
* [ ]
* hw_i2c_init_once() : SWHW HW ( HW )
* sw_i2c_init_once() : HWSW (TWI SW , )
* i2c_reset_state() : I2C (HW/SW false)
*
* [ ]
* HW_I2C_FRQ, SW_I2C_FRQ bool ,
* (mutex) .
* .
*
******************************************************************************/
#include "i2c_manager.h"
#include "debug_print.h"
#include "nrf_delay.h"
#include "nrf_drv_twi.h"
#include "nrfx_twi.h"
#include "boards.h"
#include "system_interface.h"
/* 현재 I2C 모드 상태 플래그 (true = 해당 모드 활성화) */
bool HW_I2C_FRQ = true; /* HW TWI 모드 활성 여부 (기본값: true, 초기 상태는 HW) */
bool SW_I2C_FRQ = false; /* SW 비트뱅 모드 활성 여부 */
/* TWI 인스턴스 번호 (nRF52840은 TWI0, TWI1 두 개 지원) */
#define TWI_INSTANCE 0
/* TWI (I2C) 하드웨어 인스턴스 : IMU 드라이버에서 사용 - jhChun 26.03.16 */
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);
/* TWI (I2C) 해제 - jhChun 26.03.16 */
/* TWI 하드웨어를 비활성화하고 초기화 해제하여 GPIO 핀을 반환한다 */
static void twi_uninitialize(void){
nrfx_twi_disable(&m_twi); /* TWI 주변장치 비활성화 */
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 (핀 리소스 반환) */
}
/* TWI (I2C) 하드웨어 초기화 (SCL/SDA핀, 400kHz) - jhChun 26.03.16 */
/* SCL, SDA 핀을 설정하고 400kHz Fast Mode로 TWI를 초기화 및 활성화한다 */
static void twi_initialize(void){
ret_code_t err_code;
/* TWI 설정 구조체: 핀 번호, 클럭 속도, 인터럽트 우선순위 지정 */
const nrfx_twi_config_t twi_config = {
.scl = ICM42670_I2C_SCL_PIN, /* SCL 핀 (P1.14) */
.sda = ICM42670_I2C_SDA_PIN, /* SDA 핀 (P1.15) */
.frequency = NRF_TWI_FREQ_400K, /* 400kHz Fast Mode */
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, /* 높은 인터럽트 우선순위 */
};
/* TWI 초기화 (이벤트 핸들러 NULL = 블로킹 모드) */
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
nrfx_twi_enable(&m_twi); /* TWI 주변장치 활성화 → I2C 통신 가능 */
}
/* -------------------------------------------------------------------------- */
/* HW (TWI) 초기화 */
/* -------------------------------------------------------------------------- */
/*
* HW I2C .
* - SW SW HW로
* - HW
* - HW twi_initialize() TWI
*/
void hw_i2c_init_once(void)
{
// SW 모드일 경우 강제 해제 후 HW 전환
if (SW_I2C_FRQ)
{
//DBG_PRINTF("[I2C]SW→HW\r\n");
// SW 리소스 해제 (필요 시 추가)
SW_I2C_FRQ = false;
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
}
/* 이미 HW 모드가 활성화되어 있으면 중복 초기화 방지를 위해 즉시 리턴 */
// 이미 HW면 스킵
if (HW_I2C_FRQ)
{
// DBG_PRINTF("[I2C] HW I2C set\r\n");
return;
}
/* HW TWI 하드웨어 초기화 수행 (SCL/SDA 핀 설정, 400kHz, 활성화) */
// 실제 HW 초기화
twi_initialize();
nrf_delay_ms(2); /* 초기화 후 안정화 대기 (2ms) */
/* 모드 플래그 갱신: HW 활성, SW 비활성 */
HW_I2C_FRQ = true;
SW_I2C_FRQ = false;
// DBG_PRINTF("[I2C] HW I2C Mode set!\r\n");
}
/* -------------------------------------------------------------------------- */
/* SW (Port Bang-Bang) 초기화 */
/* -------------------------------------------------------------------------- */
/*
* SW I2C() . ( , )
* - HW TWI를 SW로
* - SW
* - power_control.c의 power_loop() Step 0
*/
void sw_i2c_init_once(void)
{
// HW 모드일 경우 강제 해제 후 SW 전환
if (HW_I2C_FRQ)
{
//DBG_PRINTF("[I2C]HW→SW\r\n");
nrfx_twi_disable(&m_twi); /* TWI 비활성화 */
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 */
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
HW_I2C_FRQ = false;
}
// 이미 SW 모드면 재실행 금지
if (SW_I2C_FRQ)
{
// DBG_PRINTF("[I2C] SWI2C already initialized\r\n");
return;
}
/* TWI 라인 완전 해제 후 SW 비트뱅 모드 진입 */
// 실제 SW 초기화
twi_uninitialize(); // TWI 라인 해제
nrf_delay_ms(1); /* 해제 후 안정화 대기 (1ms) */
/* 모드 플래그 갱신: SW 활성, HW 비활성 */
SW_I2C_FRQ = true;
HW_I2C_FRQ = false;
// DBG_PRINTF("[I2C] SW I2C Mode set!\r\n");
}
/* -------------------------------------------------------------------------- */
/* 전체 리셋 */
/* -------------------------------------------------------------------------- */
/*
* I2C .
* HW/SW , init .
* .
*/
void i2c_reset_state(void)
{
HW_I2C_FRQ = false; /* HW 모드 플래그 초기화 */
SW_I2C_FRQ = false; /* SW 모드 플래그 초기화 */
DBG_PRINTF("Flags reset\r\n");
}
/*******************************************************************************
* @file i2c_manager.c
* @brief Reliable HWSW I2C Switching Logic (with Mode Set Logging)
*******************************************************************************
*
* [ ]
* I2C HW( TWI) / SW( ) .
*
* - HW I2C: nRF52840 TWI (ICM42670P IMU , 400kHz)
* - SW I2C: GPIO I2C ( )
*
* [ ]
* SCL = P1.14 (ICM42670_I2C_SCL_PIN)
* SDA = P1.15 (ICM42670_I2C_SDA_PIN)
*
* [ ]
* hw_i2c_init_once() : SWHW HW ( HW )
* sw_i2c_init_once() : HWSW (TWI SW , )
* i2c_reset_state() : I2C (HW/SW false)
*
* [ ]
* HW_I2C_FRQ, SW_I2C_FRQ bool ,
* (mutex) .
* .
*
******************************************************************************/
#include "i2c_manager.h"
#include "debug_print.h"
#include "nrf_delay.h"
#include "nrf_drv_twi.h"
#include "nrfx_twi.h"
#include "boards.h"
#include "system_interface.h"
/* 현재 I2C 모드 상태 플래그 (true = 해당 모드 활성화) */
bool HW_I2C_FRQ = true; /* HW TWI 모드 활성 여부 (기본값: true, 초기 상태는 HW) */
bool SW_I2C_FRQ = false; /* SW 비트뱅 모드 활성 여부 */
/* TWI 인스턴스 번호 (nRF52840은 TWI0, TWI1 두 개 지원) */
#define TWI_INSTANCE 0
/* TWI (I2C) 하드웨어 인스턴스 : IMU 드라이버에서 사용 - jhChun 26.03.16 */
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);
/* TWI (I2C) 해제 - jhChun 26.03.16 */
/* TWI 하드웨어를 비활성화하고 초기화 해제하여 GPIO 핀을 반환한다 */
static void twi_uninitialize(void){
nrfx_twi_disable(&m_twi); /* TWI 주변장치 비활성화 */
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 (핀 리소스 반환) */
}
/* TWI (I2C) 하드웨어 초기화 (SCL/SDA핀, 400kHz) - jhChun 26.03.16 */
/* SCL, SDA 핀을 설정하고 400kHz Fast Mode로 TWI를 초기화 및 활성화한다 */
static void twi_initialize(void){
ret_code_t err_code;
/* TWI 설정 구조체: 핀 번호, 클럭 속도, 인터럽트 우선순위 지정 */
const nrfx_twi_config_t twi_config = {
.scl = ICM42670_I2C_SCL_PIN, /* SCL 핀 (P1.14) */
.sda = ICM42670_I2C_SDA_PIN, /* SDA 핀 (P1.15) */
.frequency = NRF_TWI_FREQ_400K, /* 400kHz Fast Mode */
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, /* 높은 인터럽트 우선순위 */
};
/* TWI 초기화 (이벤트 핸들러 NULL = 블로킹 모드) */
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
nrfx_twi_enable(&m_twi); /* TWI 주변장치 활성화 → I2C 통신 가능 */
}
/* -------------------------------------------------------------------------- */
/* HW (TWI) 초기화 */
/* -------------------------------------------------------------------------- */
/*
* HW I2C .
* - SW SW HW로
* - HW
* - HW twi_initialize() TWI
*/
void hw_i2c_init_once(void)
{
// SW 모드일 경우 강제 해제 후 HW 전환
if (SW_I2C_FRQ)
{
//DBG_PRINTF("[I2C]SW→HW\r\n");
// SW 리소스 해제 (필요 시 추가)
SW_I2C_FRQ = false;
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
}
/* 이미 HW 모드가 활성화되어 있으면 중복 초기화 방지를 위해 즉시 리턴 */
// 이미 HW면 스킵
if (HW_I2C_FRQ)
{
// DBG_PRINTF("[I2C] HW I2C set\r\n");
return;
}
/* HW TWI 하드웨어 초기화 수행 (SCL/SDA 핀 설정, 400kHz, 활성화) */
// 실제 HW 초기화
twi_initialize();
nrf_delay_ms(2); /* 초기화 후 안정화 대기 (2ms) */
/* 모드 플래그 갱신: HW 활성, SW 비활성 */
HW_I2C_FRQ = true;
SW_I2C_FRQ = false;
// DBG_PRINTF("[I2C] HW I2C Mode set!\r\n");
}
/* -------------------------------------------------------------------------- */
/* SW (Port Bang-Bang) 초기화 */
/* -------------------------------------------------------------------------- */
/*
* SW I2C() . ( , )
* - HW TWI를 SW로
* - SW
* - power_control.c의 power_loop() Step 0
*/
void sw_i2c_init_once(void)
{
// HW 모드일 경우 강제 해제 후 SW 전환
if (HW_I2C_FRQ)
{
//DBG_PRINTF("[I2C]HW→SW\r\n");
nrfx_twi_disable(&m_twi); /* TWI 비활성화 */
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 */
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
HW_I2C_FRQ = false;
}
// 이미 SW 모드면 재실행 금지
if (SW_I2C_FRQ)
{
// DBG_PRINTF("[I2C] SWI2C already initialized\r\n");
return;
}
/* TWI 라인 완전 해제 후 SW 비트뱅 모드 진입 */
// 실제 SW 초기화
twi_uninitialize(); // TWI 라인 해제
nrf_delay_ms(1); /* 해제 후 안정화 대기 (1ms) */
/* 모드 플래그 갱신: SW 활성, HW 비활성 */
SW_I2C_FRQ = true;
HW_I2C_FRQ = false;
// DBG_PRINTF("[I2C] SW I2C Mode set!\r\n");
}
/* -------------------------------------------------------------------------- */
/* 전체 리셋 */
/* -------------------------------------------------------------------------- */
/*
* I2C .
* HW/SW , init .
* .
*/
void i2c_reset_state(void)
{
HW_I2C_FRQ = false; /* HW 모드 플래그 초기화 */
SW_I2C_FRQ = false; /* SW 모드 플래그 초기화 */
DBG_PRINTF("Flags reset\r\n");
}

View File

@@ -1,50 +1,50 @@
/*******************************************************************************
* @file i2c_manager.h
* @brief Common header for HW/SW I2C mutex control
*******************************************************************************
*
* [ ]
* I2C HW/SW .
*
* - HW_I2C_FRQ: HW TWI (true = HW I2C )
* - SW_I2C_FRQ: SW (true = SW I2C )
*
* , true가 .
*
******************************************************************************/
#ifndef __I2C_MANAGER_H__
#define __I2C_MANAGER_H__
#include <stdbool.h>
#include "app_error.h"
/* I2C 모드 상태 플래그 (외부 참조용) */
extern bool HW_I2C_FRQ; /* HW TWI 모드 활성 여부 */
extern bool SW_I2C_FRQ; /* SW 비트뱅 모드 활성 여부 */
/**
* @brief HW I2C(TWI) ( )
*
* SW HW로 .
* HW .
* ICM42670P IMU HW I2C를 .
*/
void hw_i2c_init_once(void);
/**
* @brief SW I2C() (, )
*
* HW TWI를 SW로 .
* SW .
*/
void sw_i2c_init_once(void);
/**
* @brief I2C
*
* HW_I2C_FRQ, SW_I2C_FRQ를 false로 .
* init .
*/
void i2c_reset_state(void);
#endif
/*******************************************************************************
* @file i2c_manager.h
* @brief Common header for HW/SW I2C mutex control
*******************************************************************************
*
* [ ]
* I2C HW/SW .
*
* - HW_I2C_FRQ: HW TWI (true = HW I2C )
* - SW_I2C_FRQ: SW (true = SW I2C )
*
* , true가 .
*
******************************************************************************/
#ifndef __I2C_MANAGER_H__
#define __I2C_MANAGER_H__
#include <stdbool.h>
#include "app_error.h"
/* I2C 모드 상태 플래그 (외부 참조용) */
extern bool HW_I2C_FRQ; /* HW TWI 모드 활성 여부 */
extern bool SW_I2C_FRQ; /* SW 비트뱅 모드 활성 여부 */
/**
* @brief HW I2C(TWI) ( )
*
* SW HW로 .
* HW .
* ICM42670P IMU HW I2C를 .
*/
void hw_i2c_init_once(void);
/**
* @brief SW I2C() (, )
*
* HW TWI를 SW로 .
* SW .
*/
void sw_i2c_init_once(void);
/**
* @brief I2C
*
* HW_I2C_FRQ, SW_I2C_FRQ를 false로 .
* init .
*/
void i2c_reset_state(void);
#endif

View File

@@ -1,297 +1,297 @@
/*******************************************************************************
* @file battery_saadc.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ADC
*
* nRF52840의 SAADC(Successive Approximation ADC) :
* - AIN2 , 10bit
* - 5 (battery_loop)
* - (3500mV ) 10 OFF
* - info4 ( ) info_batt에
*
* :
* (mV) = ADC값 x (600mV / 1023) x 6 x 1.42 ( )
*
* info4 : -> (go_temp) -> IMU(motion_raw_data_enabled)
******************************************************************************/
#include "sdk_common.h"
#include <stdint.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_timer.h"
#include "ble_nus.h"
#include "nrf_log.h"
#include "main.h"
#include "app_timer.h"
//#include "fstorage.h"
#include "battery_saadc.h"
#include "main_timer.h"
#include "main.h"
#include "debug_print.h"
/* SAADC 내부 기준전압 600mV (부동소수점) */
#define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600.0f /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
/* 1/3 프리스케일링 보상 계수 (입력 전압을 1/3로 분압하므로 x3, 추가 x2 = 총 x6) (부동소수점) */
#define BATTERY_PRE_SCALING_COMPENSATION 6.0f /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
/* 12비트 ADC 최대 디지털 값 (부동소수점) */
#define BATTERY_ADC_RES_12BITS 4095.0f /**< Maximum digital value for 12-bit ADC conversion. */
/**@brief Macro to convert the result of ADC conversion in millivolts.
*
* @param[in] ADC_VALUE ADC result.
*
* @retval Result converted to millivolts.
*/
#define BATTERY_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * BATTERY_REF_VOLTAGE_IN_MILLIVOLTS) / BATTERY_ADC_RES_12BITS) * BATTERY_PRE_SCALING_COMPENSATION)
/* 배터리 측정용 싱글 버퍼 (1회 측정 후 uninit하므로 더블 버퍼 불필요) */
static nrf_saadc_value_t adc_buf;
//static nrf_saadc_value_t adc_bufs[2]; // 이전: 더블 버퍼 (연속 측정용)
/* 배터리 모니터링 반복 타이머 정의 */
APP_TIMER_DEF(m_battery_loop_timer_id);
/* 배터리 측정 주기: 5초 (밀리초 단위) */
#define BATTERY_LOOP_INTERVAL 60000
/* 저전압 체크 플래그 — battery_loop에서 true로 설정, 핸들러에서 소비 */
bool low_battery_check = false;
/* SAADC 콜백 완료 플래그 — all_sensors()에서 배터리 측정 완료 대기용 */
volatile bool battery_saadc_done = false;
/* info4: 전체 센서 데이터 수집 모드 플래그 */
extern bool info4; // main.c
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
/* true가 되면 main_timer에서 전원 OFF 시퀀스 실행 */
extern bool go_device_power_off;
/* 다른 작업(IMU 등) 처리 중이면 true — 배터리 측정 스킵용 */
extern volatile bool processing;
/* 현재 명령 소스: CMD_UART 또는 CMD_BLE */
extern which_cmd_t cmd_type_t;
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* info4 모드에서 배터리 전압을 임시 저장 (mV 단위) */
volatile uint16_t info_batt; //48_c
/* info4 순차 측정 제어 플래그: go_batt→ go_temp → motion */
extern bool go_temp; //
extern bool go_batt; //cmd_parse
extern bool motion_raw_data_enabled ;
extern bool ble_got_new_data;
extern bool motion_data_once ;
/**@brief Function for handling the ADC interrupt.
*
* @details This function will fetch the conversion result from the ADC, convert the value into
* percentage and send it to peer.
*/
/**
* @brief ADC
*
* SAADC .
* ADC (mV) , :
* - : 3500mV 10 OFF
* - info4 : info_batt에 (go_temp)
* - : BLE UART로
*
* : ADC값 x (600/1023) x 6 = , x 1.42 =
*/
void battery_event_handler( nrf_drv_saadc_evt_t const * p_event )
{
/* 저전압 연속 감지 카운터 (static으로 호출 간 유지) */
static uint8_t low_battery_cnt = 0;
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_saadc_value_t register_val = 0;
float batt_lvl_in_milli_volt_0 = 0; /* 보정 전 전압 (부동소수점) */
float batt_lvl_in_milli_volt_1 = 0; /* 분압 보정 후 최종 전압 (부동소수점) */
/* ADC 변환 결과 읽기 */
register_val = p_event->data.done.p_buffer[0];
//err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1); // 이전: 다음 변환을 위해 버퍼 재등록
//APP_ERROR_CHECK(err_code);
/* SAADC 해제 — 다른 ADC 측정(온도, 압력)과 하드웨어 공유 */
/* 1회 측정 후 해제이므로 buffer_convert(다음 버퍼 등록) 불필요 */
nrf_drv_saadc_channel_uninit(0);
nrf_drv_saadc_uninit();
/* 콜백 완료 알림 (all_sensors 대기 해제용) */
if (info4) DBG_PRINTF("2");
battery_saadc_done = true;
/* ADC값 → mV 변환 (매크로: ADC x 600/1023 x 6) */
batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val);
/* 분압 저항 보정 계수 1.42 적용 → 실제 배터리 전압 */
batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42f;
/* === 저전압 체크 모드 (battery_loop 타이머에서 설정) === */
if(low_battery_check == true)
{
low_battery_check = false;
/* 배터리 전압이 LOW_BATTERY_VOLTAGE(3500mV) 이하인지 확인 */
if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE)
{
/* 10회 연속 저전압 감지 시 전원 OFF 시퀀스 시작 */
if(low_battery_cnt >= 10)
{
low_battery_cnt = 0;
/*go to power off and fds save */
DBG_PRINTF("Save FDS parameters and then Power OFF\r\n");
go_device_power_off = true;
main_timer_start();
}
else
{
/* 아직 10회 미만 — 카운터 증가 후 경고 출력 */
low_battery_cnt++;
DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, (int)batt_lvl_in_milli_volt_1);
}
}
}
/* === info4 모드: 전체 센서 수집(mbb) 중 배터리 값 저장 === */
else if (info4 == true)
{
info_batt = batt_lvl_in_milli_volt_1;
}
/* === 일반 모드: 단독 배터리 측정 요청(msn)에 대한 응답 전송 === */
else
{
if (cmd_type_t == CMD_UART)
{
DBG_PRINTF("Tn%d\r\n\r\n", (int)batt_lvl_in_milli_volt_1);
}
else if (cmd_type_t == CMD_BLE)
{
/* "rsn:" 헤더와 함께 배터리 전압을 바이너리로 BLE 전송 */
single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1);
dr_binary_tx_safe(ble_bin_buffer,3);
//data_tx_handler(ble_tx_buffer);
}
}
}
}
/**
* @brief SAADC를
*
* AIN2 (SE) , 1/3 .
* (adc_bufs[0], [1]) .
* : battery_event_handler
*/
static void battery_configure(void)
{
/* SAADC 드라이버 초기화 (4x 오버샘플링으로 노이즈 저감) */
nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT; // 10 -> 12bit
saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;
ret_code_t err_code = nrf_drv_saadc_init(&saadc_config, battery_event_handler);
if (err_code != NRF_SUCCESS) {
return; /* SAADC 사용 중 → 이번 측정 스킵, 다음 주기에 재시도 */
}
/* AIN2 채널 설정: 싱글엔드 입력, 1/6 gain, burst + TACQ 20μs */
nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
config.burst = NRF_SAADC_BURST_ENABLED;
config.acq_time = NRF_SAADC_ACQTIME_10US;
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);
/* 싱글 버퍼 등록 (1회 측정 후 uninit) */
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
//err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[0], 1); // 이전: 더블 버퍼
//APP_ERROR_CHECK(err_code);
//err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[1], 1);
//APP_ERROR_CHECK(err_code);
}
/**
* @brief 1
*
* SAADC를 .
* battery_event_handler .
*/
void battery_level_meas(void)
{
ret_code_t err_code;
battery_configure(); /* SAADC 배터리용 초기화 */
err_code = nrf_drv_saadc_sample(); /* ADC 샘플링 트리거 (비동기) */
APP_ERROR_CHECK(err_code);
}
/**
* @brief (5 ) - ( )
*
* .
* (IMU ) .
*/
void battery_loop(void * p_context) /* For 1sec */
{
UNUSED_PARAMETER(p_context);
/* 다른 센서 처리 중 또는 MBB 센서 수집 중이면 배터리 측정 스킵 (SAADC 충돌 방지) */
if (processing == true || info4 == true)
{
processing = false ; // add 20241218
//low_battery_check = true;
return;
}
else
{
low_battery_check = true; /* 저전압 감지 모드로 측정 */
battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */
}
}
/** @brief 배터리 모니터링 타이머 시작 (5초 반복) */
void battery_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_battery_loop_timer_id, APP_TIMER_TICKS(BATTERY_LOOP_INTERVAL), NULL));
}
/** @brief 배터리 모니터링 타이머 정지 */
void battery_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_battery_loop_timer_id));
}
/** @brief 배터리 모니터링 타이머 초기화 (반복 모드, 콜백: battery_loop) */
void battery_timer_init(void)
{
APP_ERROR_CHECK(app_timer_create(&m_battery_loop_timer_id, APP_TIMER_MODE_REPEATED, battery_loop));
}
/*******************************************************************************
* @file battery_saadc.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ADC
*
* nRF52840의 SAADC(Successive Approximation ADC) :
* - AIN2 , 10bit
* - 5 (battery_loop)
* - (3500mV ) 10 OFF
* - info4 ( ) info_batt에
*
* :
* (mV) = ADC값 x (600mV / 1023) x 6 x 1.42 ( )
*
* info4 : -> (go_temp) -> IMU(motion_raw_data_enabled)
******************************************************************************/
#include "sdk_common.h"
#include <stdint.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_timer.h"
#include "ble_nus.h"
#include "nrf_log.h"
#include "main.h"
#include "app_timer.h"
//#include "fstorage.h"
#include "battery_saadc.h"
#include "main_timer.h"
#include "main.h"
#include "debug_print.h"
/* SAADC 내부 기준전압 600mV (부동소수점) */
#define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600.0f /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
/* 1/3 프리스케일링 보상 계수 (입력 전압을 1/3로 분압하므로 x3, 추가 x2 = 총 x6) (부동소수점) */
#define BATTERY_PRE_SCALING_COMPENSATION 6.0f /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
/* 12비트 ADC 최대 디지털 값 (부동소수점) */
#define BATTERY_ADC_RES_12BITS 4095.0f /**< Maximum digital value for 12-bit ADC conversion. */
/**@brief Macro to convert the result of ADC conversion in millivolts.
*
* @param[in] ADC_VALUE ADC result.
*
* @retval Result converted to millivolts.
*/
#define BATTERY_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * BATTERY_REF_VOLTAGE_IN_MILLIVOLTS) / BATTERY_ADC_RES_12BITS) * BATTERY_PRE_SCALING_COMPENSATION)
/* 배터리 측정용 싱글 버퍼 (1회 측정 후 uninit하므로 더블 버퍼 불필요) */
static nrf_saadc_value_t adc_buf;
//static nrf_saadc_value_t adc_bufs[2]; // 이전: 더블 버퍼 (연속 측정용)
/* 배터리 모니터링 반복 타이머 정의 */
APP_TIMER_DEF(m_battery_loop_timer_id);
/* 배터리 측정 주기: 5초 (밀리초 단위) */
#define BATTERY_LOOP_INTERVAL 60000
/* 저전압 체크 플래그 — battery_loop에서 true로 설정, 핸들러에서 소비 */
bool low_battery_check = false;
/* SAADC 콜백 완료 플래그 — all_sensors()에서 배터리 측정 완료 대기용 */
volatile bool battery_saadc_done = false;
/* info4: 전체 센서 데이터 수집 모드 플래그 */
extern bool info4; // main.c
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
/* true가 되면 main_timer에서 전원 OFF 시퀀스 실행 */
extern bool go_device_power_off;
/* 다른 작업(IMU 등) 처리 중이면 true — 배터리 측정 스킵용 */
extern volatile bool processing;
/* 현재 명령 소스: CMD_UART 또는 CMD_BLE */
extern which_cmd_t cmd_type_t;
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* info4 모드에서 배터리 전압을 임시 저장 (mV 단위) */
volatile uint16_t info_batt; //48_c
/* info4 순차 측정 제어 플래그: go_batt→ go_temp → motion */
extern bool go_temp; //
extern bool go_batt; //cmd_parse
extern bool motion_raw_data_enabled ;
extern bool ble_got_new_data;
extern bool motion_data_once ;
/**@brief Function for handling the ADC interrupt.
*
* @details This function will fetch the conversion result from the ADC, convert the value into
* percentage and send it to peer.
*/
/**
* @brief ADC
*
* SAADC .
* ADC (mV) , :
* - : 3500mV 10 OFF
* - info4 : info_batt에 (go_temp)
* - : BLE UART로
*
* : ADC값 x (600/1023) x 6 = , x 1.42 =
*/
void battery_event_handler( nrf_drv_saadc_evt_t const * p_event )
{
/* 저전압 연속 감지 카운터 (static으로 호출 간 유지) */
static uint8_t low_battery_cnt = 0;
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_saadc_value_t register_val = 0;
float batt_lvl_in_milli_volt_0 = 0; /* 보정 전 전압 (부동소수점) */
float batt_lvl_in_milli_volt_1 = 0; /* 분압 보정 후 최종 전압 (부동소수점) */
/* ADC 변환 결과 읽기 */
register_val = p_event->data.done.p_buffer[0];
//err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1); // 이전: 다음 변환을 위해 버퍼 재등록
//APP_ERROR_CHECK(err_code);
/* SAADC 해제 — 다른 ADC 측정(온도, 압력)과 하드웨어 공유 */
/* 1회 측정 후 해제이므로 buffer_convert(다음 버퍼 등록) 불필요 */
nrf_drv_saadc_channel_uninit(0);
nrf_drv_saadc_uninit();
/* 콜백 완료 알림 (all_sensors 대기 해제용) */
if (info4) DBG_PRINTF("2");
battery_saadc_done = true;
/* ADC값 → mV 변환 (매크로: ADC x 600/1023 x 6) */
batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val);
/* 분압 저항 보정 계수 1.42 적용 → 실제 배터리 전압 */
batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42f;
/* === 저전압 체크 모드 (battery_loop 타이머에서 설정) === */
if(low_battery_check == true)
{
low_battery_check = false;
/* 배터리 전압이 LOW_BATTERY_VOLTAGE(3500mV) 이하인지 확인 */
if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE)
{
/* 10회 연속 저전압 감지 시 전원 OFF 시퀀스 시작 */
if(low_battery_cnt >= 10)
{
low_battery_cnt = 0;
/*go to power off and fds save */
DBG_PRINTF("Save FDS parameters and then Power OFF\r\n");
go_device_power_off = true;
main_timer_start();
}
else
{
/* 아직 10회 미만 — 카운터 증가 후 경고 출력 */
low_battery_cnt++;
DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, (int)batt_lvl_in_milli_volt_1);
}
}
}
/* === info4 모드: 전체 센서 수집(mbb) 중 배터리 값 저장 === */
else if (info4 == true)
{
info_batt = batt_lvl_in_milli_volt_1;
}
/* === 일반 모드: 단독 배터리 측정 요청(msn)에 대한 응답 전송 === */
else
{
if (cmd_type_t == CMD_UART)
{
DBG_PRINTF("Tn%d\r\n\r\n", (int)batt_lvl_in_milli_volt_1);
}
else if (cmd_type_t == CMD_BLE)
{
/* "rsn:" 헤더와 함께 배터리 전압을 바이너리로 BLE 전송 */
single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1);
dr_binary_tx_safe(ble_bin_buffer,3);
//data_tx_handler(ble_tx_buffer);
}
}
}
}
/**
* @brief SAADC를
*
* AIN2 (SE) , 1/3 .
* (adc_bufs[0], [1]) .
* : battery_event_handler
*/
static void battery_configure(void)
{
/* SAADC 드라이버 초기화 (4x 오버샘플링으로 노이즈 저감) */
nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT; // 10 -> 12bit
saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;
ret_code_t err_code = nrf_drv_saadc_init(&saadc_config, battery_event_handler);
if (err_code != NRF_SUCCESS) {
return; /* SAADC 사용 중 → 이번 측정 스킵, 다음 주기에 재시도 */
}
/* AIN2 채널 설정: 싱글엔드 입력, 1/6 gain, burst + TACQ 20μs */
nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
config.burst = NRF_SAADC_BURST_ENABLED;
config.acq_time = NRF_SAADC_ACQTIME_10US;
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);
/* 싱글 버퍼 등록 (1회 측정 후 uninit) */
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
//err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[0], 1); // 이전: 더블 버퍼
//APP_ERROR_CHECK(err_code);
//err_code = nrf_drv_saadc_buffer_convert(&adc_bufs[1], 1);
//APP_ERROR_CHECK(err_code);
}
/**
* @brief 1
*
* SAADC를 .
* battery_event_handler .
*/
void battery_level_meas(void)
{
ret_code_t err_code;
battery_configure(); /* SAADC 배터리용 초기화 */
err_code = nrf_drv_saadc_sample(); /* ADC 샘플링 트리거 (비동기) */
APP_ERROR_CHECK(err_code);
}
/**
* @brief (5 ) - ( )
*
* .
* (IMU ) .
*/
void battery_loop(void * p_context) /* For 1sec */
{
UNUSED_PARAMETER(p_context);
/* 다른 센서 처리 중 또는 MBB 센서 수집 중이면 배터리 측정 스킵 (SAADC 충돌 방지) */
if (processing == true || info4 == true)
{
processing = false ; // add 20241218
//low_battery_check = true;
return;
}
else
{
low_battery_check = true; /* 저전압 감지 모드로 측정 */
battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */
}
}
/** @brief 배터리 모니터링 타이머 시작 (5초 반복) */
void battery_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_battery_loop_timer_id, APP_TIMER_TICKS(BATTERY_LOOP_INTERVAL), NULL));
}
/** @brief 배터리 모니터링 타이머 정지 */
void battery_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_battery_loop_timer_id));
}
/** @brief 배터리 모니터링 타이머 초기화 (반복 모드, 콜백: battery_loop) */
void battery_timer_init(void)
{
APP_ERROR_CHECK(app_timer_create(&m_battery_loop_timer_id, APP_TIMER_MODE_REPEATED, battery_loop));
}

View File

@@ -1,41 +1,41 @@
/*******************************************************************************
* @file battery_saadc.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] SAADC
*
* nRF52840 SAADC를 API를 .
*
* API:
* - battery_level_meas() : 1 (AIN2)
* - battery_timer_init/start/stop() : 5
*
* LOW_BATTERY_VOLTAGE(3500mV) 10 OFF
******************************************************************************/
#ifndef _BATTERY_SAADC_H_
#define _BATTERY_SAADC_H_
/* 저전압 판정 임계값 (mV) — 이 값 이하가 10회 연속이면 자동 전원 OFF */
#define LOW_BATTERY_VOLTAGE 3500 /* Low Battery 임계값 */
/** @brief 배터리 SAADC 콜백 완료 플래그 (all_sensors 대기용) */
extern volatile bool battery_saadc_done;
/** @brief 배터리 전압 1회 측정 시작 (비동기, 결과는 콜백에서 처리) */
void battery_level_meas(void);
/** @brief 배터리 모니터링 5초 반복 타이머 시작 */
void battery_timer_start(void);
/** @brief 배터리 모니터링 타이머 정지 */
void battery_timer_stop(void);
/** @brief 배터리 모니터링 타이머 초기화 (앱 시작 시 1회 호출) */
void battery_timer_init(void);
#endif //_BATTERY_SAADC_H_
/*******************************************************************************
* @file battery_saadc.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] SAADC
*
* nRF52840 SAADC를 API를 .
*
* API:
* - battery_level_meas() : 1 (AIN2)
* - battery_timer_init/start/stop() : 5
*
* LOW_BATTERY_VOLTAGE(3500mV) 10 OFF
******************************************************************************/
#ifndef _BATTERY_SAADC_H_
#define _BATTERY_SAADC_H_
/* 저전압 판정 임계값 (mV) — 이 값 이하가 10회 연속이면 자동 전원 OFF */
#define LOW_BATTERY_VOLTAGE 3500 /* Low Battery 임계값 */
/** @brief 배터리 SAADC 콜백 완료 플래그 (all_sensors 대기용) */
extern volatile bool battery_saadc_done;
/** @brief 배터리 전압 1회 측정 시작 (비동기, 결과는 콜백에서 처리) */
void battery_level_meas(void);
/** @brief 배터리 모니터링 5초 반복 타이머 시작 */
void battery_timer_start(void);
/** @brief 배터리 모니터링 타이머 정지 */
void battery_timer_stop(void);
/** @brief 배터리 모니터링 타이머 초기화 (앱 시작 시 1회 호출) */
void battery_timer_init(void);
#endif //_BATTERY_SAADC_H_

View File

@@ -1,103 +1,103 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "DataConverter.h"
uint8_t * inv_dc_int32_to_little8(int32_t x, uint8_t * little8)
{
little8[3] = (uint8_t)((x >> 24) & 0xff);
little8[2] = (uint8_t)((x >> 16) & 0xff);
little8[1] = (uint8_t)((x >> 8) & 0xff);
little8[0] = (uint8_t)(x & 0xff);
return little8;
}
uint8_t * inv_dc_int16_to_little8(int16_t x, uint8_t * little8)
{
little8[0] = (uint8_t)(x & 0xff);
little8[1] = (uint8_t)((x >> 8) & 0xff);
return little8;
}
uint8_t * inv_dc_int32_to_big8(int32_t x, uint8_t * big8)
{
big8[0] = (uint8_t)((x >> 24) & 0xff);
big8[1] = (uint8_t)((x >> 16) & 0xff);
big8[2] = (uint8_t)((x >> 8) & 0xff);
big8[3] = (uint8_t)(x & 0xff);
return big8;
}
int32_t inv_dc_little8_to_int32(const uint8_t * little8)
{
int32_t x = 0;
x |= ((int32_t)little8[3] << 24);
x |= ((int32_t)little8[2] << 16);
x |= ((int32_t)little8[1] << 8);
x |= ((int32_t)little8[0]);
return x;
}
int16_t inv_dc_big16_to_int16(uint8_t * data)
{
int16_t result;
result = (*data << 8);
data++;
result |= *data;
return result;
}
int16_t inv_dc_le_to_int16(const uint8_t * little8)
{
uint16_t x = 0;
x |= ((uint16_t)little8[0]);
x |= ((uint16_t)little8[1] << 8);
return (int16_t)x;
}
void inv_dc_sfix32_to_float(const int32_t * in, uint32_t len, uint8_t qx, float * out)
{
uint8_t i;
for(i = 0; i < len; ++i) {
out[i] = (float)in[i] / (1 << qx);
}
}
void inv_dc_float_to_sfix32(const float * in, uint32_t len, uint8_t qx, int32_t * out)
{
uint8_t i;
for(i = 0; i < len; ++i) {
out[i] = (int32_t)((in[i] * (1 << qx)) + ((in[i] >= 0) - 0.5f));
}
}
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "DataConverter.h"
uint8_t * inv_dc_int32_to_little8(int32_t x, uint8_t * little8)
{
little8[3] = (uint8_t)((x >> 24) & 0xff);
little8[2] = (uint8_t)((x >> 16) & 0xff);
little8[1] = (uint8_t)((x >> 8) & 0xff);
little8[0] = (uint8_t)(x & 0xff);
return little8;
}
uint8_t * inv_dc_int16_to_little8(int16_t x, uint8_t * little8)
{
little8[0] = (uint8_t)(x & 0xff);
little8[1] = (uint8_t)((x >> 8) & 0xff);
return little8;
}
uint8_t * inv_dc_int32_to_big8(int32_t x, uint8_t * big8)
{
big8[0] = (uint8_t)((x >> 24) & 0xff);
big8[1] = (uint8_t)((x >> 16) & 0xff);
big8[2] = (uint8_t)((x >> 8) & 0xff);
big8[3] = (uint8_t)(x & 0xff);
return big8;
}
int32_t inv_dc_little8_to_int32(const uint8_t * little8)
{
int32_t x = 0;
x |= ((int32_t)little8[3] << 24);
x |= ((int32_t)little8[2] << 16);
x |= ((int32_t)little8[1] << 8);
x |= ((int32_t)little8[0]);
return x;
}
int16_t inv_dc_big16_to_int16(uint8_t * data)
{
int16_t result;
result = (*data << 8);
data++;
result |= *data;
return result;
}
int16_t inv_dc_le_to_int16(const uint8_t * little8)
{
uint16_t x = 0;
x |= ((uint16_t)little8[0]);
x |= ((uint16_t)little8[1] << 8);
return (int16_t)x;
}
void inv_dc_sfix32_to_float(const int32_t * in, uint32_t len, uint8_t qx, float * out)
{
uint8_t i;
for(i = 0; i < len; ++i) {
out[i] = (float)in[i] / (1 << qx);
}
}
void inv_dc_float_to_sfix32(const float * in, uint32_t len, uint8_t qx, int32_t * out)
{
uint8_t i;
for(i = 0; i < len; ++i) {
out[i] = (int32_t)((in[i] * (1 << qx)) + ((in[i] >= 0) - 0.5f));
}
}

View File

@@ -1,87 +1,87 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DataConverter Data Converter
* @brief Helper functions to convert integer
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_DATA_CONVERTER_H_
#define _INV_DATA_CONVERTER_H_
#include "InvExport.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/** @brief Converts a 32-bit long to a little endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int32_to_little8(int32_t x, uint8_t * little8);
/** @brief Converts a 16-bit integer to a little endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int16_to_little8(int16_t x, uint8_t * little8);
/** @brief Converts a 32-bit long to a big endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int32_to_big8(int32_t x, uint8_t *big8);
/** @brief Converts a little endian byte stream into a 32-bit integer
*/
int32_t INV_EXPORT inv_dc_little8_to_int32(const uint8_t * little8);
/** @brief Converts a little endian byte stream into a 16-bit integer
*/
int16_t INV_EXPORT inv_dc_le_to_int16(const uint8_t * little8);
/** @brief Converts big endian on 16 bits into an unsigned short
*/
int16_t INV_EXPORT inv_dc_big16_to_int16(uint8_t * data);
/** @brief Converts an array of 32-bit signed fixed-point integers to an array of floats
* @param[in] in Pointer to the first element of the array of 32-bit signed fixed-point integers
* @param[in] len Length of the array
* @param[in] qx Number of bits used to represent the decimal part of the fixed-point integers
* @param[out] out Pointer to the memory area where the output will be stored
*/
void INV_EXPORT inv_dc_sfix32_to_float(const int32_t * in, uint32_t len, uint8_t qx, float * out);
/** @brief Converts an array of floats to an array of 32-bit signed fixed-point integers
* @param[in] in Pointer to the first element of the array of floats
* @param[in] len Length of the array
* @param[in] qx Number of bits used to represent the decimal part of the fixed-point integers
* @param[out] out Pointer to the memory area where the output will be stored
*/
void INV_EXPORT inv_dc_float_to_sfix32(const float * in, uint32_t len, uint8_t qx, int32_t * out);
#ifdef __cplusplus
}
#endif
#endif /* _INV_DATA_CONVERTER_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DataConverter Data Converter
* @brief Helper functions to convert integer
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_DATA_CONVERTER_H_
#define _INV_DATA_CONVERTER_H_
#include "InvExport.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/** @brief Converts a 32-bit long to a little endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int32_to_little8(int32_t x, uint8_t * little8);
/** @brief Converts a 16-bit integer to a little endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int16_to_little8(int16_t x, uint8_t * little8);
/** @brief Converts a 32-bit long to a big endian byte stream
*/
uint8_t INV_EXPORT * inv_dc_int32_to_big8(int32_t x, uint8_t *big8);
/** @brief Converts a little endian byte stream into a 32-bit integer
*/
int32_t INV_EXPORT inv_dc_little8_to_int32(const uint8_t * little8);
/** @brief Converts a little endian byte stream into a 16-bit integer
*/
int16_t INV_EXPORT inv_dc_le_to_int16(const uint8_t * little8);
/** @brief Converts big endian on 16 bits into an unsigned short
*/
int16_t INV_EXPORT inv_dc_big16_to_int16(uint8_t * data);
/** @brief Converts an array of 32-bit signed fixed-point integers to an array of floats
* @param[in] in Pointer to the first element of the array of 32-bit signed fixed-point integers
* @param[in] len Length of the array
* @param[in] qx Number of bits used to represent the decimal part of the fixed-point integers
* @param[out] out Pointer to the memory area where the output will be stored
*/
void INV_EXPORT inv_dc_sfix32_to_float(const int32_t * in, uint32_t len, uint8_t qx, float * out);
/** @brief Converts an array of floats to an array of 32-bit signed fixed-point integers
* @param[in] in Pointer to the first element of the array of floats
* @param[in] len Length of the array
* @param[in] qx Number of bits used to represent the decimal part of the fixed-point integers
* @param[out] out Pointer to the memory area where the output will be stored
*/
void INV_EXPORT inv_dc_float_to_sfix32(const float * in, uint32_t len, uint8_t qx, int32_t * out);
#ifdef __cplusplus
}
#endif
#endif /* _INV_DATA_CONVERTER_H_ */
/** @} */

View File

@@ -1,47 +1,47 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "ErrorHelper.h"
const char * inv_error_str(int error)
{
switch(error) {
case INV_ERROR_SUCCESS: return "Success";
case INV_ERROR: return "Unspecified error";
case INV_ERROR_NIMPL: return "Not implemented";
case INV_ERROR_TRANSPORT: return "Transport error";
case INV_ERROR_TIMEOUT: return "Timeout, action did not complete in time";
case INV_ERROR_SIZE: return "Wrong size error";
case INV_ERROR_OS: return "Operating system failure";
case INV_ERROR_IO: return "Input/Output error";
case INV_ERROR_MEM: return "Bad allocation";
case INV_ERROR_HW: return "Hardware error";
case INV_ERROR_BAD_ARG: return "Invalid arguments";
case INV_ERROR_UNEXPECTED: return "Unexpected error";
case INV_ERROR_FILE: return "Invalid file format";
case INV_ERROR_PATH: return "Invalid file path";
case INV_ERROR_IMAGE_TYPE: return "Unknown image type";
case INV_ERROR_WATCHDOG: return "Watchdog error";
default: return "Unknown error";
}
}
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "ErrorHelper.h"
const char * inv_error_str(int error)
{
switch(error) {
case INV_ERROR_SUCCESS: return "Success";
case INV_ERROR: return "Unspecified error";
case INV_ERROR_NIMPL: return "Not implemented";
case INV_ERROR_TRANSPORT: return "Transport error";
case INV_ERROR_TIMEOUT: return "Timeout, action did not complete in time";
case INV_ERROR_SIZE: return "Wrong size error";
case INV_ERROR_OS: return "Operating system failure";
case INV_ERROR_IO: return "Input/Output error";
case INV_ERROR_MEM: return "Bad allocation";
case INV_ERROR_HW: return "Hardware error";
case INV_ERROR_BAD_ARG: return "Invalid arguments";
case INV_ERROR_UNEXPECTED: return "Unexpected error";
case INV_ERROR_FILE: return "Invalid file format";
case INV_ERROR_PATH: return "Invalid file path";
case INV_ERROR_IMAGE_TYPE: return "Unknown image type";
case INV_ERROR_WATCHDOG: return "Watchdog error";
default: return "Unknown error";
}
}

View File

@@ -1,51 +1,51 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup ErrorHelper Error Helper
* @brief Helper functions related to error code
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_ERROR_HELPER_H_
#define _INV_ERROR_HELPER_H_
#include "InvExport.h"
#include "InvError.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Returns string describing error number
* @sa enum inv_error
*/
const char INV_EXPORT * inv_error_str(int error);
#ifdef __cplusplus
}
#endif
#endif /* _INV_ERROR_HELPER_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup ErrorHelper Error Helper
* @brief Helper functions related to error code
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_ERROR_HELPER_H_
#define _INV_ERROR_HELPER_H_
#include "InvExport.h"
#include "InvError.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Returns string describing error number
* @sa enum inv_error
*/
const char INV_EXPORT * inv_error_str(int error);
#ifdef __cplusplus
}
#endif
#endif /* _INV_ERROR_HELPER_H_ */
/** @} */

View File

@@ -1,82 +1,82 @@
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
#include "InvBasicMath.h"
#include <limits.h>
unsigned int InvBasicMath_log2u(unsigned int val)
{
unsigned int ret = UINT_MAX;
while (val != 0) {
val >>= 1;
ret++;
}
return ret;
}
int InvBasicMath_isAnOrthonormalMatrix(const float matrix[9])
{
// Check if matrix is orthogonal
// Matrix is orthogonal if transpose(Matrix) x Matrix = Identity
float transpose[9];
float mult[9];
int i, j;
// Compute Transpose(matrix)
for (i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
transpose[i*3+j] = matrix[i+j*3];
}
}
// Multiply transpose x matrix
mult[0] = transpose[0]*matrix[0] + transpose[1]*matrix[3] + transpose[2]*matrix[6];
mult[1] = transpose[0]*matrix[1] + transpose[1]*matrix[4] + transpose[2]*matrix[7];
mult[2] = transpose[0]*matrix[2] + transpose[1]*matrix[5] + transpose[2]*matrix[8];
mult[3] = transpose[3]*matrix[0] + transpose[4]*matrix[3] + transpose[5]*matrix[6];
mult[4] = transpose[3]*matrix[1] + transpose[4]*matrix[4] + transpose[5]*matrix[7];
mult[5] = transpose[3]*matrix[2] + transpose[4]*matrix[5] + transpose[5]*matrix[8];
mult[6] = transpose[6]*matrix[0] + transpose[7]*matrix[3] + transpose[8]*matrix[6];
mult[7] = transpose[6]*matrix[1] + transpose[7]*matrix[4] + transpose[8]*matrix[7];
mult[8] = transpose[6]*matrix[2] + transpose[7]*matrix[5] + transpose[8]*matrix[8];
// Check that mult is identity
for (i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
if (i == j) {
if (mult[i+j*3] != 1)
return 0;
}
else {
if (mult[i+j*3] != 0)
return 0;
}
}
}
return 1;
}
float InvBasicMath_computeMatrixDeterminant(const float matrix[9])
{
return matrix[0] * (matrix[4]*matrix[8] - matrix[7]*matrix[5])
-matrix[1] * (matrix[3]*matrix[8] - matrix[6]*matrix[5])
+matrix[2] * (matrix[3]*matrix[7] - matrix[4]*matrix[6]);
}
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
#include "InvBasicMath.h"
#include <limits.h>
unsigned int InvBasicMath_log2u(unsigned int val)
{
unsigned int ret = UINT_MAX;
while (val != 0) {
val >>= 1;
ret++;
}
return ret;
}
int InvBasicMath_isAnOrthonormalMatrix(const float matrix[9])
{
// Check if matrix is orthogonal
// Matrix is orthogonal if transpose(Matrix) x Matrix = Identity
float transpose[9];
float mult[9];
int i, j;
// Compute Transpose(matrix)
for (i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
transpose[i*3+j] = matrix[i+j*3];
}
}
// Multiply transpose x matrix
mult[0] = transpose[0]*matrix[0] + transpose[1]*matrix[3] + transpose[2]*matrix[6];
mult[1] = transpose[0]*matrix[1] + transpose[1]*matrix[4] + transpose[2]*matrix[7];
mult[2] = transpose[0]*matrix[2] + transpose[1]*matrix[5] + transpose[2]*matrix[8];
mult[3] = transpose[3]*matrix[0] + transpose[4]*matrix[3] + transpose[5]*matrix[6];
mult[4] = transpose[3]*matrix[1] + transpose[4]*matrix[4] + transpose[5]*matrix[7];
mult[5] = transpose[3]*matrix[2] + transpose[4]*matrix[5] + transpose[5]*matrix[8];
mult[6] = transpose[6]*matrix[0] + transpose[7]*matrix[3] + transpose[8]*matrix[6];
mult[7] = transpose[6]*matrix[1] + transpose[7]*matrix[4] + transpose[8]*matrix[7];
mult[8] = transpose[6]*matrix[2] + transpose[7]*matrix[5] + transpose[8]*matrix[8];
// Check that mult is identity
for (i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
if (i == j) {
if (mult[i+j*3] != 1)
return 0;
}
else {
if (mult[i+j*3] != 0)
return 0;
}
}
}
return 1;
}
float InvBasicMath_computeMatrixDeterminant(const float matrix[9])
{
return matrix[0] * (matrix[4]*matrix[8] - matrix[7]*matrix[5])
-matrix[1] * (matrix[3]*matrix[8] - matrix[6]*matrix[5])
+matrix[2] * (matrix[3]*matrix[7] - matrix[4]*matrix[6]);
}

View File

@@ -1,94 +1,94 @@
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
/** @defgroup InvBasicMath InvBasicMath
@brief This file contains basic (overloadable) math functions and macros
@ingroup EmbUtils
@{
*/
#ifndef _INV_BASIC_MATH_H_
#define _INV_BASIC_MATH_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Return absolute value of argument
*/
#ifndef INV_ABS
# define INV_ABS(a) ((a) < 0 ? -(a) : (a))
#endif
/** @brief Return minimum of two arguments
*/
#ifndef INV_MIN
# define INV_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/** @brief Return maximum of two arguments
*/
#ifndef INV_MAX
# define INV_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
/** @brief Define value for pi
*/
#ifndef INV_PI
# define INV_PI 3.14159265358979
#endif
#ifndef M_PI
# define M_PI INV_PI
#endif
/** @brief Return saturated integer
*/
#ifndef INV_SATURATE
static inline long InvBasicMath_saturatel(long in, long min, long max)
{
if (in > max)
return max;
else if (in < min)
return min;
else
return in;
}
# define INV_SATURATE(a, min, max) InvBasicMath_saturatel(a, min, max)
#endif
/** @brief Compute log2 from integer
*/
#ifndef INV_LOG2
unsigned int InvBasicMath_log2u(unsigned int val);
# define INV_LOG2(a) InvBasicMath_log2u(a)
#endif
/** @brief Check if matrix is orthonormal
* @param [in] matrix 3x3 Matrix to be checked
* @return 1 if it is an orthonormal matrix, 0 otherwise
*/
int InvBasicMath_isAnOrthonormalMatrix(const float matrix[9]);
/** @brief Compute the determinant of the matrix
* @param [in] matrix 3x3 Matrix to be checked
* @return the determinant value
*/
float InvBasicMath_computeMatrixDeterminant(const float matrix[9]);
#ifdef __cplusplus
}
#endif
#endif /* _INV_BASIC_MATH_H_ */
/** @} */
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
/** @defgroup InvBasicMath InvBasicMath
@brief This file contains basic (overloadable) math functions and macros
@ingroup EmbUtils
@{
*/
#ifndef _INV_BASIC_MATH_H_
#define _INV_BASIC_MATH_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Return absolute value of argument
*/
#ifndef INV_ABS
# define INV_ABS(a) ((a) < 0 ? -(a) : (a))
#endif
/** @brief Return minimum of two arguments
*/
#ifndef INV_MIN
# define INV_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/** @brief Return maximum of two arguments
*/
#ifndef INV_MAX
# define INV_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
/** @brief Define value for pi
*/
#ifndef INV_PI
# define INV_PI 3.14159265358979
#endif
#ifndef M_PI
# define M_PI INV_PI
#endif
/** @brief Return saturated integer
*/
#ifndef INV_SATURATE
static inline long InvBasicMath_saturatel(long in, long min, long max)
{
if (in > max)
return max;
else if (in < min)
return min;
else
return in;
}
# define INV_SATURATE(a, min, max) InvBasicMath_saturatel(a, min, max)
#endif
/** @brief Compute log2 from integer
*/
#ifndef INV_LOG2
unsigned int InvBasicMath_log2u(unsigned int val);
# define INV_LOG2(a) InvBasicMath_log2u(a)
#endif
/** @brief Check if matrix is orthonormal
* @param [in] matrix 3x3 Matrix to be checked
* @return 1 if it is an orthonormal matrix, 0 otherwise
*/
int InvBasicMath_isAnOrthonormalMatrix(const float matrix[9]);
/** @brief Compute the determinant of the matrix
* @param [in] matrix 3x3 Matrix to be checked
* @return the determinant value
*/
float InvBasicMath_computeMatrixDeterminant(const float matrix[9]);
#ifdef __cplusplus
}
#endif
#endif /* _INV_BASIC_MATH_H_ */
/** @} */

View File

@@ -1,389 +1,389 @@
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
/** \defgroup RingBuffer RingBuffer
\brief Macros to manage static circular buffer of any data type
\ingroup EmbUtils
\{
*/
#ifndef _RING_BUFFER_H_
#define _RING_BUFFER_H_
#include <stdint.h>
#include <string.h>
/** \brief Macro to declare a ring buffer
\param[in] type type of item contained in the ring buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
*/
#define RINGBUFFER_DECLARE(type, size) \
struct { \
uint16_t read, write; \
type buffer[size]; \
}
/** \brief Macro to declare a volatile ring buffer, i.e. modified within an interrupt context
\param[in] type type of item contained in the ring buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
*/
#define RINGBUFFER_VOLATILE_DECLARE(type, size) \
struct { \
volatile uint16_t read, write; \
volatile type buffer[size]; \
}
/** \brief Macro to declare a ring buffer
\param[in] name name of the circular buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
\param[in] type type of item contained in the ring buffer
*/
#define RINGBUFFER(name, size, type) RINGBUFFER_DECLARE(type, size) name
/** \brief Macro to declare a volatile ring buffer, i.e. modified within an interrupt context
\param[in] name name of the circular buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
\param[in] type type of item contained in the ring buffer
*/
#define RINGBUFFER_VOLATILE(name, size, type) RINGBUFFER_VOLATILE_DECLARE(type, size) name
/** \brief Macro to get maximum size of a ring buffer
\param[in] rb pointer to the ring buffer
\return maximum number of items that can contain the ringbuffer
*/
#define RINGBUFFER_MAXSIZE(rb) (sizeof((rb)->buffer)/sizeof((rb)->buffer[0]))
/** \brief Macro to get maximum size of a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return maximum number of items that can contain the ringbuffer
*/
#define RINGBUFFER_VOLATILE_MAXSIZE(rb) RINGBUFFER_MAXSIZE(rb)
/** \brief Macro to get current size of a ring buffer
\param[in] rb pointer to the ring buffer
\return current number of items hold in the ringbuffer
*/
#define RINGBUFFER_SIZE(rb) ((uint16_t)((rb)->write - (rb)->read))
static inline uint16_t get_ringbuffer_volatile_size(void * rb)
{
struct { uint16_t read, write; } rb_var;
memcpy(&rb_var, rb, sizeof(rb_var));
return (rb_var.write - rb_var.read);
}
/** \brief Macro to get current size of a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return current number of items hold in the ringbuffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_SIZE(rb) get_ringbuffer_volatile_size(rb)
/** \brief Macro to check if a ring buffer is full
\param[in] rb pointer to the ring buffer
\return 1 if there is no slot left in the ring buffer, 0 otherwise
*/
#define RINGBUFFER_FULL(rb) (RINGBUFFER_SIZE(rb) == RINGBUFFER_MAXSIZE(rb))
/** \brief Macro to check if a volatile ring buffer, i.e. modified within an interrupt context, is full
\param[in] rb pointer to the ring buffer
\return 1 if there is no slot left in the ring buffer, 0 otherwise
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_FULL(rb) (RINGBUFFER_VOLATILE_SIZE(rb) == RINGBUFFER_VOLATILE_MAXSIZE(rb))
/** \brief Macro to check if a ring buffer is empty
\param[in] rb pointer to the ring buffer
\return 1 if there is no item in the ring buffer, 0 otherwise
*/
#define RINGBUFFER_EMPTY(rb) (RINGBUFFER_SIZE(rb) == 0)
/** \brief Macro to check if a volatile ring buffer, i.e. modified within an interrupt context, is empty
\param[in] rb pointer to the ring buffer
\return 1 if there is no item in the ring buffer, 0 otherwise
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_EMPTY(rb) (RINGBUFFER_VOLATILE_SIZE(rb) == 0)
/** \brief Macro to get number of available slot in a ring buffer
\param[in] rb pointer to the ring buffer
\return number of empty slot in the ring buffer
*/
#define RINGBUFFER_AVAILABLE(rb) (RINGBUFFER_MAXSIZE(rb) - RINGBUFFER_SIZE(rb))
/** \brief Macro to get number of available slot in a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return number of empty slot in the ring buffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_AVAILABLE(rb) (RINGBUFFER_VOLATILE_MAXSIZE(rb) - RINGBUFFER_VOLATILE_SIZE(rb))
/** \brief Macro to clear a ring buffer
\param[in] rb pointer to the ring buffer
*/
#define RINGBUFFER_CLEAR(rb) \
do { \
(rb)->read = 0, (rb)->write = 0; \
} while(0)
/** \brief Macro to clear a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_CLEAR(rb) RINGBUFFER_CLEAR(rb)
/** \brief Push item by reference
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
*/
#define RINGBUFFER_PUSHREF(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
++(rb)->write; \
} while(0)
/** \brief Push item by reference
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_PUSHREF(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
++(rb)->write; \
} while(0)
/** \brief Return reference to next available slot
No push is performed
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
*/
#define RINGBUFFER_GETREFNEXT(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to next available slot
No push is performed
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_GETREFNEXT(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Increment write counter
Actually performed a push (assuming data were already copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
*/
#define RINGBUFFER_INCREMENT(rb, refData) \
do { \
++(rb)->write; \
} while(0)
/** \brief Increment write counter
Actually performed a push (assuming data were already copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_INCREMENT(rb, refData) \
do { \
++(rb)->write; \
} while(0)
/** \brief Return reference to youngest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to youngest item
\warning There is no error checking done.
*/
#define RINGBUFFER_BACK(rb, refData) \
do { \
refData = &(rb)->buffer[((rb)->write-1) % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to youngest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to youngest item
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_BACK(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[(wr_ptr-1) % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to push an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to the item to push.
\warning There is no error checking done.
You must check for fullness before pushing data
*/
#define RINGBUFFER_PUSH(rb, ptrData) \
do { \
(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)] = *ptrData; \
++(rb)->write; \
} while(0)
/** \brief Macro to push an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to the item to push.
\warning There is no error checking done.
You must check for fullness before pushing data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_PUSH(rb, ptrData) \
do { \
uint16_t wr_ptr = (rb)->write; \
(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)] = *ptrData; \
++(rb)->write; \
} while(0)
/** \brief Macro to unpush an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to placeholder to hold unpushed item
\warning There is no error checking done.
You must check for emptiness before pushing data
*/
#define RINGBUFFER_UNPUSH(rb, ptrData) \
do { \
--(rb)->write; \
*ptrData = (rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to unpush an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to placeholder to hold unpushed item
\warning There is no error checking done.
You must check for emptiness before pushing data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_UNPUSH(rb, ptrData) \
do { \
--(rb)->write; \
uint16_t wr_ptr = (rb)->write; \
*ptrData = (rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to oldest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to oldest item
\warning There is no error checking done.
*/
#define RINGBUFFER_FRONT(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to oldest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to oldest item
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_FRONT(rb, refData) \
do { \
uint16_t rd_ptr = (rb)->read; \
refData = &(rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to pop an item from a ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to placeholder to hold popped item
\warning There is no error checking done.
You must check for emptiness before popping data
*/
#define RINGBUFFER_POP(rb, ptrData) \
do { \
*ptrData = (rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)]; \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to placeholder to hold popped item
\warning There is no error checking done.
You must check for emptiness before popping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_POP(rb, ptrData) \
do { \
uint16_t rd_ptr = (rb)->read; \
*ptrData = (rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a ring buffer (data is not copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
You must check for emptiness before popping data
*/
#define RINGBUFFER_POPNLOSE(rb) \
do { \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a volatile ring buffer (data is not copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
You must check for emptiness before popping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_POPNLOSE(rb) \
do { \
++(rb)->read; \
} while(0)
/** \brief Macro to unpop an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to to the item to unpop.
\warning There is no error checking done.
You must check for fullness before unpopping data
*/
#define RINGBUFFER_UNPOP(rb, ptrData) \
do { \
--(rb)->read; \
(rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)] = *ptrData; \
} while(0)
/** \brief Macro to unpop an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to to the item to unpop.
\warning There is no error checking done.
You must check for fullness before unpopping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_UNPOP(rb, ptrData) \
do { \
--(rb)->read; \
uint16_t rd_ptr = (rb)->read; \
(rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)] = *ptrData; \
} while(0)
#endif
/** \} */
/*
Copyright (c) 2014-2015 InvenSense Inc. Portions Copyright (c) 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively "Software") is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright and
other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license
agreement from InvenSense is strictly prohibited.
*/
/** \defgroup RingBuffer RingBuffer
\brief Macros to manage static circular buffer of any data type
\ingroup EmbUtils
\{
*/
#ifndef _RING_BUFFER_H_
#define _RING_BUFFER_H_
#include <stdint.h>
#include <string.h>
/** \brief Macro to declare a ring buffer
\param[in] type type of item contained in the ring buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
*/
#define RINGBUFFER_DECLARE(type, size) \
struct { \
uint16_t read, write; \
type buffer[size]; \
}
/** \brief Macro to declare a volatile ring buffer, i.e. modified within an interrupt context
\param[in] type type of item contained in the ring buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
*/
#define RINGBUFFER_VOLATILE_DECLARE(type, size) \
struct { \
volatile uint16_t read, write; \
volatile type buffer[size]; \
}
/** \brief Macro to declare a ring buffer
\param[in] name name of the circular buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
\param[in] type type of item contained in the ring buffer
*/
#define RINGBUFFER(name, size, type) RINGBUFFER_DECLARE(type, size) name
/** \brief Macro to declare a volatile ring buffer, i.e. modified within an interrupt context
\param[in] name name of the circular buffer
\param[in] size number of items that can contain the ring buffer
To improve speed, size should be a power of 2
\param[in] type type of item contained in the ring buffer
*/
#define RINGBUFFER_VOLATILE(name, size, type) RINGBUFFER_VOLATILE_DECLARE(type, size) name
/** \brief Macro to get maximum size of a ring buffer
\param[in] rb pointer to the ring buffer
\return maximum number of items that can contain the ringbuffer
*/
#define RINGBUFFER_MAXSIZE(rb) (sizeof((rb)->buffer)/sizeof((rb)->buffer[0]))
/** \brief Macro to get maximum size of a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return maximum number of items that can contain the ringbuffer
*/
#define RINGBUFFER_VOLATILE_MAXSIZE(rb) RINGBUFFER_MAXSIZE(rb)
/** \brief Macro to get current size of a ring buffer
\param[in] rb pointer to the ring buffer
\return current number of items hold in the ringbuffer
*/
#define RINGBUFFER_SIZE(rb) ((uint16_t)((rb)->write - (rb)->read))
static inline uint16_t get_ringbuffer_volatile_size(void * rb)
{
struct { uint16_t read, write; } rb_var;
memcpy(&rb_var, rb, sizeof(rb_var));
return (rb_var.write - rb_var.read);
}
/** \brief Macro to get current size of a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return current number of items hold in the ringbuffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_SIZE(rb) get_ringbuffer_volatile_size(rb)
/** \brief Macro to check if a ring buffer is full
\param[in] rb pointer to the ring buffer
\return 1 if there is no slot left in the ring buffer, 0 otherwise
*/
#define RINGBUFFER_FULL(rb) (RINGBUFFER_SIZE(rb) == RINGBUFFER_MAXSIZE(rb))
/** \brief Macro to check if a volatile ring buffer, i.e. modified within an interrupt context, is full
\param[in] rb pointer to the ring buffer
\return 1 if there is no slot left in the ring buffer, 0 otherwise
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_FULL(rb) (RINGBUFFER_VOLATILE_SIZE(rb) == RINGBUFFER_VOLATILE_MAXSIZE(rb))
/** \brief Macro to check if a ring buffer is empty
\param[in] rb pointer to the ring buffer
\return 1 if there is no item in the ring buffer, 0 otherwise
*/
#define RINGBUFFER_EMPTY(rb) (RINGBUFFER_SIZE(rb) == 0)
/** \brief Macro to check if a volatile ring buffer, i.e. modified within an interrupt context, is empty
\param[in] rb pointer to the ring buffer
\return 1 if there is no item in the ring buffer, 0 otherwise
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_EMPTY(rb) (RINGBUFFER_VOLATILE_SIZE(rb) == 0)
/** \brief Macro to get number of available slot in a ring buffer
\param[in] rb pointer to the ring buffer
\return number of empty slot in the ring buffer
*/
#define RINGBUFFER_AVAILABLE(rb) (RINGBUFFER_MAXSIZE(rb) - RINGBUFFER_SIZE(rb))
/** \brief Macro to get number of available slot in a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\return number of empty slot in the ring buffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_AVAILABLE(rb) (RINGBUFFER_VOLATILE_MAXSIZE(rb) - RINGBUFFER_VOLATILE_SIZE(rb))
/** \brief Macro to clear a ring buffer
\param[in] rb pointer to the ring buffer
*/
#define RINGBUFFER_CLEAR(rb) \
do { \
(rb)->read = 0, (rb)->write = 0; \
} while(0)
/** \brief Macro to clear a volatile ring buffer, i.e. modified within an interrupt context
\param[in] rb pointer to the ring buffer
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_CLEAR(rb) RINGBUFFER_CLEAR(rb)
/** \brief Push item by reference
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
*/
#define RINGBUFFER_PUSHREF(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
++(rb)->write; \
} while(0)
/** \brief Push item by reference
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_PUSHREF(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
++(rb)->write; \
} while(0)
/** \brief Return reference to next available slot
No push is performed
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
*/
#define RINGBUFFER_GETREFNEXT(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to next available slot
No push is performed
\param[in] rb pointer to the ring buffer
\param[out] refData to available item slot
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_GETREFNEXT(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Increment write counter
Actually performed a push (assuming data were already copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
*/
#define RINGBUFFER_INCREMENT(rb, refData) \
do { \
++(rb)->write; \
} while(0)
/** \brief Increment write counter
Actually performed a push (assuming data were already copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_INCREMENT(rb, refData) \
do { \
++(rb)->write; \
} while(0)
/** \brief Return reference to youngest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to youngest item
\warning There is no error checking done.
*/
#define RINGBUFFER_BACK(rb, refData) \
do { \
refData = &(rb)->buffer[((rb)->write-1) % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to youngest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to youngest item
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_BACK(rb, refData) \
do { \
uint16_t wr_ptr = (rb)->write; \
refData = &(rb)->buffer[(wr_ptr-1) % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to push an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to the item to push.
\warning There is no error checking done.
You must check for fullness before pushing data
*/
#define RINGBUFFER_PUSH(rb, ptrData) \
do { \
(rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)] = *ptrData; \
++(rb)->write; \
} while(0)
/** \brief Macro to push an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to the item to push.
\warning There is no error checking done.
You must check for fullness before pushing data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_PUSH(rb, ptrData) \
do { \
uint16_t wr_ptr = (rb)->write; \
(rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)] = *ptrData; \
++(rb)->write; \
} while(0)
/** \brief Macro to unpush an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to placeholder to hold unpushed item
\warning There is no error checking done.
You must check for emptiness before pushing data
*/
#define RINGBUFFER_UNPUSH(rb, ptrData) \
do { \
--(rb)->write; \
*ptrData = (rb)->buffer[(rb)->write % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to unpush an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[in] ptrData pointer to placeholder to hold unpushed item
\warning There is no error checking done.
You must check for emptiness before pushing data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_UNPUSH(rb, ptrData) \
do { \
--(rb)->write; \
uint16_t wr_ptr = (rb)->write; \
*ptrData = (rb)->buffer[wr_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to oldest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to oldest item
\warning There is no error checking done.
*/
#define RINGBUFFER_FRONT(rb, refData) \
do { \
refData = &(rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)]; \
} while(0)
/** \brief Return reference to oldest item
\param[in] rb pointer to the ring buffer
\param[out] refData reference to oldest item
\warning There is no error checking done.
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_FRONT(rb, refData) \
do { \
uint16_t rd_ptr = (rb)->read; \
refData = &(rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
} while(0)
/** \brief Macro to pop an item from a ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to placeholder to hold popped item
\warning There is no error checking done.
You must check for emptiness before popping data
*/
#define RINGBUFFER_POP(rb, ptrData) \
do { \
*ptrData = (rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)]; \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to placeholder to hold popped item
\warning There is no error checking done.
You must check for emptiness before popping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_POP(rb, ptrData) \
do { \
uint16_t rd_ptr = (rb)->read; \
*ptrData = (rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)]; \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a ring buffer (data is not copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
You must check for emptiness before popping data
*/
#define RINGBUFFER_POPNLOSE(rb) \
do { \
++(rb)->read; \
} while(0)
/** \brief Macro to pop an item from a volatile ring buffer (data is not copied)
\param[in] rb pointer to the ring buffer
\warning There is no error checking done.
You must check for emptiness before popping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_POPNLOSE(rb) \
do { \
++(rb)->read; \
} while(0)
/** \brief Macro to unpop an item to a ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to to the item to unpop.
\warning There is no error checking done.
You must check for fullness before unpopping data
*/
#define RINGBUFFER_UNPOP(rb, ptrData) \
do { \
--(rb)->read; \
(rb)->buffer[(rb)->read % RINGBUFFER_MAXSIZE(rb)] = *ptrData; \
} while(0)
/** \brief Macro to unpop an item to a volatile ring buffer
\param[in] rb pointer to the ring buffer
\param[out] ptrData pointer to to the item to unpop.
\warning There is no error checking done.
You must check for fullness before unpopping data
\warning it is advised to put this in a critical section
*/
#define RINGBUFFER_VOLATILE_UNPOP(rb, ptrData) \
do { \
--(rb)->read; \
uint16_t rd_ptr = (rb)->read; \
(rb)->buffer[rd_ptr % RINGBUFFER_VOLATILE_MAXSIZE(rb)] = *ptrData; \
} while(0)
#endif
/** \} */

View File

@@ -1,47 +1,47 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @brief Custom definition for boolean type to avoid compiler discrepancies
* @{
*/
#ifndef _INV_BOOL_H_
#define _INV_BOOL_H_
typedef int inv_bool_t;
#ifndef __cplusplus
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif /* __cplusplus */
#endif /* _INV_BOOL_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @brief Custom definition for boolean type to avoid compiler discrepancies
* @{
*/
#ifndef _INV_BOOL_H_
#define _INV_BOOL_H_
typedef int inv_bool_t;
#ifndef __cplusplus
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif /* __cplusplus */
#endif /* _INV_BOOL_H_ */
/** @} */

View File

@@ -1,64 +1,64 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup InvError Error code
* @brief Common error code
*
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_ERROR_H_
#define _INV_ERROR_H_
/** @brief Common error code definition
*/
enum inv_error
{
INV_ERROR_SUCCESS = 0, /**< no error */
INV_ERROR = -1, /**< unspecified error */
INV_ERROR_NIMPL = -2, /**< function not implemented for given
arguments */
INV_ERROR_TRANSPORT = -3, /**< error occurred at transport level */
INV_ERROR_TIMEOUT = -4, /**< action did not complete in the expected
time window */
INV_ERROR_SIZE = -5, /**< size/length of given arguments is not
suitable to complete requested action */
INV_ERROR_OS = -6, /**< error related to OS */
INV_ERROR_IO = -7, /**< error related to IO operation */
INV_ERROR_MEM = -9, /**< not enough memory to complete requested
action */
INV_ERROR_HW = -10, /**< error at HW level */
INV_ERROR_BAD_ARG = -11, /**< provided arguments are not good to
perform requested action */
INV_ERROR_UNEXPECTED = -12, /**< something unexpected happened */
INV_ERROR_FILE = -13, /**< cannot access file or unexpected format */
INV_ERROR_PATH = -14, /**< invalid file path */
INV_ERROR_IMAGE_TYPE = -15, /**< error when image type is not managed */
INV_ERROR_WATCHDOG = -16, /**< error when device doesn't respond
to ping */
};
#endif /* _INV_ERROR_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup InvError Error code
* @brief Common error code
*
* @ingroup EmbUtils
* @{
*/
#ifndef _INV_ERROR_H_
#define _INV_ERROR_H_
/** @brief Common error code definition
*/
enum inv_error
{
INV_ERROR_SUCCESS = 0, /**< no error */
INV_ERROR = -1, /**< unspecified error */
INV_ERROR_NIMPL = -2, /**< function not implemented for given
arguments */
INV_ERROR_TRANSPORT = -3, /**< error occurred at transport level */
INV_ERROR_TIMEOUT = -4, /**< action did not complete in the expected
time window */
INV_ERROR_SIZE = -5, /**< size/length of given arguments is not
suitable to complete requested action */
INV_ERROR_OS = -6, /**< error related to OS */
INV_ERROR_IO = -7, /**< error related to IO operation */
INV_ERROR_MEM = -9, /**< not enough memory to complete requested
action */
INV_ERROR_HW = -10, /**< error at HW level */
INV_ERROR_BAD_ARG = -11, /**< provided arguments are not good to
perform requested action */
INV_ERROR_UNEXPECTED = -12, /**< something unexpected happened */
INV_ERROR_FILE = -13, /**< cannot access file or unexpected format */
INV_ERROR_PATH = -14, /**< invalid file path */
INV_ERROR_IMAGE_TYPE = -15, /**< error when image type is not managed */
INV_ERROR_WATCHDOG = -16, /**< error when device doesn't respond
to ping */
};
#endif /* _INV_ERROR_H_ */
/** @} */

View File

@@ -1,39 +1,39 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#ifndef _INV_IDD_EXPORT_H_
#define _INV_IDD_EXPORT_H_
#if defined(_WIN32)
#if !defined(INV_EXPORT) && defined(INV_DO_DLL_EXPORT)
#define INV_EXPORT __declspec(dllexport)
#elif !defined(INV_EXPORT) && defined(INV_DO_DLL_IMPORT)
#define INV_EXPORT __declspec(dllimport)
#endif
#endif
#if !defined(INV_EXPORT)
#define INV_EXPORT
#endif
#endif /* _INV_IDD_EXPORT_H_ */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#ifndef _INV_IDD_EXPORT_H_
#define _INV_IDD_EXPORT_H_
#if defined(_WIN32)
#if !defined(INV_EXPORT) && defined(INV_DO_DLL_EXPORT)
#define INV_EXPORT __declspec(dllexport)
#elif !defined(INV_EXPORT) && defined(INV_DO_DLL_IMPORT)
#define INV_EXPORT __declspec(dllimport)
#endif
#endif
#if !defined(INV_EXPORT)
#define INV_EXPORT
#endif
#endif /* _INV_IDD_EXPORT_H_ */

View File

@@ -1,370 +1,370 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_defs.h"
#include "inv_imu_extfunc.h"
#include "inv_imu_driver.h"
#include "inv_imu_apex.h"
int inv_imu_apex_enable_ff(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_ff(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_smd(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_smd(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs)
{
int status = 0;
(void)s;
/* Default parameters at POR */
apex_inputs->pedo_amp_th = APEX_CONFIG3_PEDO_AMP_TH_62_MG;
apex_inputs->pedo_step_cnt_th = 0x5;
apex_inputs->pedo_step_det_th = 0x2;
apex_inputs->pedo_sb_timer_th = APEX_CONFIG4_PEDO_SB_TIMER_TH_150_SAMPLES;
apex_inputs->pedo_hi_enrgy_th = APEX_CONFIG4_PEDO_HI_ENRGY_TH_104_MG;
apex_inputs->tilt_wait_time = APEX_CONFIG5_TILT_WAIT_TIME_4_S;
apex_inputs->power_save_time = APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_8_S;
apex_inputs->power_save = APEX_CONFIG0_DMP_POWER_SAVE_EN;
apex_inputs->sensitivity_mode = APEX_CONFIG9_SENSITIVITY_MODE_NORMAL;
apex_inputs->low_energy_amp_th = APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_80_MG;
apex_inputs->smd_sensitivity = APEX_CONFIG9_SMD_SENSITIVITY_0;
apex_inputs->ff_debounce_duration = APEX_CONFIG9_FF_DEBOUNCE_DURATION_2000_MS;
apex_inputs->ff_max_duration_cm = APEX_CONFIG12_FF_MAX_DURATION_204_CM;
apex_inputs->ff_min_duration_cm = APEX_CONFIG12_FF_MIN_DURATION_10_CM;
apex_inputs->lowg_peak_th = APEX_CONFIG10_LOWG_PEAK_TH_563_MG;
apex_inputs->lowg_peak_hyst = APEX_CONFIG5_LOWG_PEAK_TH_HYST_156_MG;
apex_inputs->lowg_samples_th = APEX_CONFIG10_LOWG_TIME_TH_1_SAMPLE;
apex_inputs->highg_peak_th = APEX_CONFIG11_HIGHG_PEAK_TH_2500_MG;
apex_inputs->highg_peak_hyst = APEX_CONFIG5_HIGHG_PEAK_TH_HYST_156_MG;
apex_inputs->highg_samples_th = APEX_CONFIG11_HIGHG_TIME_TH_1_SAMPLE;
return status;
}
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs)
{
int status = 0;
uint8_t data;
uint8_t apexConfig[7];
APEX_CONFIG1_PED_ENABLE_t pedo_state;
APEX_CONFIG1_TILT_ENABLE_t tilt_state;
APEX_CONFIG1_FF_ENABLE_t ff_state;
APEX_CONFIG1_SMD_ENABLE_t smd_state;
/* DMP cannot be configured if it is running, hence make sure all APEX algorithms are off */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &data);
pedo_state = (APEX_CONFIG1_PED_ENABLE_t)(data & APEX_CONFIG1_PED_ENABLE_MASK);
tilt_state = (APEX_CONFIG1_TILT_ENABLE_t)(data & APEX_CONFIG1_TILT_ENABLE_MASK);
ff_state = (APEX_CONFIG1_FF_ENABLE_t)(data & APEX_CONFIG1_FF_ENABLE_MASK);
smd_state = (APEX_CONFIG1_SMD_ENABLE_t)(data & APEX_CONFIG1_SMD_ENABLE_MASK);
if (pedo_state == APEX_CONFIG1_PED_ENABLE_EN)
return INV_ERROR;
if (tilt_state == APEX_CONFIG1_TILT_ENABLE_EN)
return INV_ERROR;
if (ff_state == APEX_CONFIG1_FF_ENABLE_EN)
return INV_ERROR;
if (smd_state == APEX_CONFIG1_SMD_ENABLE_EN)
return INV_ERROR;
status |= inv_imu_switch_on_mclk(s);
/* Power Save mode and low energy amplitude threshold (for Pedometer in Slow Walk mode) */
/* APEX_CONFIG2_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->power_save_time
| (uint8_t)apex_inputs->low_energy_amp_th;
/* Pedometer parameters */
/* APEX_CONFIG3_MREG1 */
apexConfig[1] = (uint8_t)apex_inputs->pedo_amp_th
| (apex_inputs->pedo_step_cnt_th & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK);
/* APEX_CONFIG4_MREG1 */
apexConfig[2] = ((apex_inputs->pedo_step_det_th << APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS)
& APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
| (uint8_t)apex_inputs->pedo_sb_timer_th
| (uint8_t)apex_inputs->pedo_hi_enrgy_th;
/* Tilt, Lowg and highg parameters */
/* APEX_CONFIG5_MREG1 */
apexConfig[3] = (uint8_t)apex_inputs->tilt_wait_time
| (uint8_t)apex_inputs->lowg_peak_hyst
| (uint8_t)apex_inputs->highg_peak_hyst;
status |= inv_imu_write_reg(s, APEX_CONFIG2_MREG1, 4, &apexConfig[0]);
/* APEX_CONFIG0 */
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
apexConfig[0] &= ~APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK;
apexConfig[0] |= apex_inputs->power_save;
status |= inv_imu_write_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
/* free fall parameter, SMD parameter and parameters for Pedometer in Slow Walk mode */
/* APEX_CONFIG9_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->ff_debounce_duration
| (uint8_t)apex_inputs->smd_sensitivity
| (uint8_t)apex_inputs->sensitivity_mode;
/* Lowg and highg parameters and free fall parameters */
/* APEX_CONFIG10_MREG1 */
apexConfig[1] = (uint8_t)apex_inputs->lowg_peak_th
| (uint8_t)apex_inputs->lowg_samples_th;
/* APEX_CONFIG11_MREG1 */
apexConfig[2] = (uint8_t)apex_inputs->highg_peak_th
| (uint8_t)apex_inputs->highg_samples_th;
status |= inv_imu_write_reg(s, APEX_CONFIG9_MREG1, 3, &apexConfig[0]);
/* APEX_CONFIG12_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->ff_max_duration_cm
| (uint8_t)apex_inputs->ff_min_duration_cm;
status |= inv_imu_write_reg(s, APEX_CONFIG12_MREG1, 1, &apexConfig[0]);
status |= inv_imu_switch_off_mclk(s);
return status;
}
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params)
{
int status = 0;
uint8_t data[7];
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &value);
apex_params->power_save = (APEX_CONFIG0_DMP_POWER_SAVE_t)(value & APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK);
/* Access continuous config registers (CONFIG2-CONFIG11) */
status |= inv_imu_read_reg(s, APEX_CONFIG2_MREG1, sizeof(data), &data[0]);
/* Get params from apex_config2 : dmp_power_save_time and low_energy_amp_th */
apex_params->power_save_time = (APEX_CONFIG2_DMP_POWER_SAVE_TIME_t)
(data[0] & APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_MASK);
apex_params->low_energy_amp_th = (APEX_CONFIG2_LOW_ENERGY_AMP_TH_t)
(data[0] & APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_MASK);
/* Get params from apex_config3 : pedo_amp_th and pedo_step_cnt_th */
apex_params->pedo_amp_th = (APEX_CONFIG3_PEDO_AMP_TH_t)
(data[1] & APEX_CONFIG3_PED_AMP_TH_SEL_MASK);
apex_params->pedo_step_cnt_th = (data[1] & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK)
>> APEX_CONFIG3_PED_STEP_CNT_TH_SEL_POS;
/* Get params from apex_config4 : pedo_step_det_th, pedo_sb_timer_th and pedo_hi_enrgy_th */
apex_params->pedo_step_det_th = (data[2] & APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
>> APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS;
apex_params->pedo_sb_timer_th = (APEX_CONFIG4_PEDO_SB_TIMER_TH_t)
(data[2] & APEX_CONFIG4_PED_SB_TIMER_TH_SEL_MASK);
apex_params->pedo_hi_enrgy_th = (APEX_CONFIG4_PEDO_HI_ENRGY_TH_t)
(data[2] & APEX_CONFIG4_PED_HI_EN_TH_SEL_MASK);
/* Get params from apex_config5 : tilt_wait_time, lowg_peak_hyst and highg_peak_hyst */
apex_params->tilt_wait_time = (APEX_CONFIG5_TILT_WAIT_TIME_t)
(data[3] & APEX_CONFIG5_TILT_WAIT_TIME_SEL_MASK);
apex_params->lowg_peak_hyst = (APEX_CONFIG5_LOWG_PEAK_TH_HYST_t)
(data[3] & APEX_CONFIG5_LOWG_PEAK_TH_HYST_SEL_MASK);
apex_params->highg_peak_hyst = (APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t)
(data[3] & APEX_CONFIG5_HIGHG_PEAK_TH_HYST_SEL_MASK);
/* Get params from apex_config9 : ff_debounce_duration, smd_sensitivity and sensitivity_mode */
apex_params->ff_debounce_duration = (APEX_CONFIG9_FF_DEBOUNCE_DURATION_t)
(data[4] & APEX_CONFIG9_FF_DEBOUNCE_DURATION_SEL_MASK);
apex_params->smd_sensitivity = (APEX_CONFIG9_SMD_SENSITIVITY_t)
(data[4] & APEX_CONFIG9_SMD_SENSITIVITY_SEL_MASK);
apex_params->sensitivity_mode = (APEX_CONFIG9_SENSITIVITY_MODE_t)
(data[4] & APEX_CONFIG9_SENSITIVITY_MODE_MASK);
/* Get params from apex_config10 : lowg_peak_th and lowg_samples_th */
apex_params->lowg_peak_th = (APEX_CONFIG10_LOWG_PEAK_TH_t)
(data[5] & APEX_CONFIG10_LOWG_PEAK_TH_SEL_MASK);
apex_params->lowg_samples_th = (APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t)
(data[5] & APEX_CONFIG10_LOWG_TIME_TH_SEL_MASK);
/* Get params from apex_config11 : highg_peak_th and highg_samples_th */
apex_params->highg_peak_th = (APEX_CONFIG11_HIGHG_PEAK_TH_t)
(data[6] & APEX_CONFIG11_HIGHG_PEAK_TH_SEL_MASK);
apex_params->highg_samples_th = (APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t)
(data[6] & APEX_CONFIG11_HIGHG_TIME_TH_SEL_MASK);
/* Access apex reg 12 */
status |= inv_imu_read_reg(s, APEX_CONFIG12_MREG1, 1, &data[0]);
/* Get params from apex_config12 : ff_max_duration_cm and ff_min_duration_cm */
apex_params->ff_max_duration_cm = (APEX_CONFIG12_FF_MAX_DURATION_t)
(data[0] & APEX_CONFIG12_FF_MAX_DURATION_SEL_MASK);
apex_params->ff_min_duration_cm = (APEX_CONFIG12_FF_MIN_DURATION_t)
(data[0] & APEX_CONFIG12_FF_MIN_DURATION_SEL_MASK);
return status;
}
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency)
{
uint8_t value;
int status = 0;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_DMP_ODR_MASK;
value |= frequency;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
/* Enable Pedometer */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Disable Pedometer */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_tilt(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
/* Enable Tilt */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_tilt(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Disable Tilt */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity)
{
uint8_t data[4];
int status = inv_imu_read_reg(s, APEX_DATA0, 4, data);
apex_activity->step_cnt = data[1] << 8 | data[0];
apex_activity->step_cadence = data[2];
apex_activity->activity_class = data[3] & APEX_DATA3_ACTIVITY_CLASS_MASK;
return status;
}
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration)
{
uint8_t data[2];
int status = inv_imu_read_reg(s, APEX_DATA4, 2, &data[0]);
*freefall_duration = (data[1] << 8) | data[0];
return status;
}
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_defs.h"
#include "inv_imu_extfunc.h"
#include "inv_imu_driver.h"
#include "inv_imu_apex.h"
int inv_imu_apex_enable_ff(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_ff(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_FF_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_FF_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_smd(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_smd(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_SMD_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_SMD_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs)
{
int status = 0;
(void)s;
/* Default parameters at POR */
apex_inputs->pedo_amp_th = APEX_CONFIG3_PEDO_AMP_TH_62_MG;
apex_inputs->pedo_step_cnt_th = 0x5;
apex_inputs->pedo_step_det_th = 0x2;
apex_inputs->pedo_sb_timer_th = APEX_CONFIG4_PEDO_SB_TIMER_TH_150_SAMPLES;
apex_inputs->pedo_hi_enrgy_th = APEX_CONFIG4_PEDO_HI_ENRGY_TH_104_MG;
apex_inputs->tilt_wait_time = APEX_CONFIG5_TILT_WAIT_TIME_4_S;
apex_inputs->power_save_time = APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_8_S;
apex_inputs->power_save = APEX_CONFIG0_DMP_POWER_SAVE_EN;
apex_inputs->sensitivity_mode = APEX_CONFIG9_SENSITIVITY_MODE_NORMAL;
apex_inputs->low_energy_amp_th = APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_80_MG;
apex_inputs->smd_sensitivity = APEX_CONFIG9_SMD_SENSITIVITY_0;
apex_inputs->ff_debounce_duration = APEX_CONFIG9_FF_DEBOUNCE_DURATION_2000_MS;
apex_inputs->ff_max_duration_cm = APEX_CONFIG12_FF_MAX_DURATION_204_CM;
apex_inputs->ff_min_duration_cm = APEX_CONFIG12_FF_MIN_DURATION_10_CM;
apex_inputs->lowg_peak_th = APEX_CONFIG10_LOWG_PEAK_TH_563_MG;
apex_inputs->lowg_peak_hyst = APEX_CONFIG5_LOWG_PEAK_TH_HYST_156_MG;
apex_inputs->lowg_samples_th = APEX_CONFIG10_LOWG_TIME_TH_1_SAMPLE;
apex_inputs->highg_peak_th = APEX_CONFIG11_HIGHG_PEAK_TH_2500_MG;
apex_inputs->highg_peak_hyst = APEX_CONFIG5_HIGHG_PEAK_TH_HYST_156_MG;
apex_inputs->highg_samples_th = APEX_CONFIG11_HIGHG_TIME_TH_1_SAMPLE;
return status;
}
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs)
{
int status = 0;
uint8_t data;
uint8_t apexConfig[7];
APEX_CONFIG1_PED_ENABLE_t pedo_state;
APEX_CONFIG1_TILT_ENABLE_t tilt_state;
APEX_CONFIG1_FF_ENABLE_t ff_state;
APEX_CONFIG1_SMD_ENABLE_t smd_state;
/* DMP cannot be configured if it is running, hence make sure all APEX algorithms are off */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &data);
pedo_state = (APEX_CONFIG1_PED_ENABLE_t)(data & APEX_CONFIG1_PED_ENABLE_MASK);
tilt_state = (APEX_CONFIG1_TILT_ENABLE_t)(data & APEX_CONFIG1_TILT_ENABLE_MASK);
ff_state = (APEX_CONFIG1_FF_ENABLE_t)(data & APEX_CONFIG1_FF_ENABLE_MASK);
smd_state = (APEX_CONFIG1_SMD_ENABLE_t)(data & APEX_CONFIG1_SMD_ENABLE_MASK);
if (pedo_state == APEX_CONFIG1_PED_ENABLE_EN)
return INV_ERROR;
if (tilt_state == APEX_CONFIG1_TILT_ENABLE_EN)
return INV_ERROR;
if (ff_state == APEX_CONFIG1_FF_ENABLE_EN)
return INV_ERROR;
if (smd_state == APEX_CONFIG1_SMD_ENABLE_EN)
return INV_ERROR;
status |= inv_imu_switch_on_mclk(s);
/* Power Save mode and low energy amplitude threshold (for Pedometer in Slow Walk mode) */
/* APEX_CONFIG2_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->power_save_time
| (uint8_t)apex_inputs->low_energy_amp_th;
/* Pedometer parameters */
/* APEX_CONFIG3_MREG1 */
apexConfig[1] = (uint8_t)apex_inputs->pedo_amp_th
| (apex_inputs->pedo_step_cnt_th & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK);
/* APEX_CONFIG4_MREG1 */
apexConfig[2] = ((apex_inputs->pedo_step_det_th << APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS)
& APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
| (uint8_t)apex_inputs->pedo_sb_timer_th
| (uint8_t)apex_inputs->pedo_hi_enrgy_th;
/* Tilt, Lowg and highg parameters */
/* APEX_CONFIG5_MREG1 */
apexConfig[3] = (uint8_t)apex_inputs->tilt_wait_time
| (uint8_t)apex_inputs->lowg_peak_hyst
| (uint8_t)apex_inputs->highg_peak_hyst;
status |= inv_imu_write_reg(s, APEX_CONFIG2_MREG1, 4, &apexConfig[0]);
/* APEX_CONFIG0 */
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
apexConfig[0] &= ~APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK;
apexConfig[0] |= apex_inputs->power_save;
status |= inv_imu_write_reg(s, APEX_CONFIG0, 1, &apexConfig[0]);
/* free fall parameter, SMD parameter and parameters for Pedometer in Slow Walk mode */
/* APEX_CONFIG9_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->ff_debounce_duration
| (uint8_t)apex_inputs->smd_sensitivity
| (uint8_t)apex_inputs->sensitivity_mode;
/* Lowg and highg parameters and free fall parameters */
/* APEX_CONFIG10_MREG1 */
apexConfig[1] = (uint8_t)apex_inputs->lowg_peak_th
| (uint8_t)apex_inputs->lowg_samples_th;
/* APEX_CONFIG11_MREG1 */
apexConfig[2] = (uint8_t)apex_inputs->highg_peak_th
| (uint8_t)apex_inputs->highg_samples_th;
status |= inv_imu_write_reg(s, APEX_CONFIG9_MREG1, 3, &apexConfig[0]);
/* APEX_CONFIG12_MREG1 */
apexConfig[0] = (uint8_t)apex_inputs->ff_max_duration_cm
| (uint8_t)apex_inputs->ff_min_duration_cm;
status |= inv_imu_write_reg(s, APEX_CONFIG12_MREG1, 1, &apexConfig[0]);
status |= inv_imu_switch_off_mclk(s);
return status;
}
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params)
{
int status = 0;
uint8_t data[7];
uint8_t value;
status |= inv_imu_read_reg(s, APEX_CONFIG0, 1, &value);
apex_params->power_save = (APEX_CONFIG0_DMP_POWER_SAVE_t)(value & APEX_CONFIG0_DMP_POWER_SAVE_EN_MASK);
/* Access continuous config registers (CONFIG2-CONFIG11) */
status |= inv_imu_read_reg(s, APEX_CONFIG2_MREG1, sizeof(data), &data[0]);
/* Get params from apex_config2 : dmp_power_save_time and low_energy_amp_th */
apex_params->power_save_time = (APEX_CONFIG2_DMP_POWER_SAVE_TIME_t)
(data[0] & APEX_CONFIG2_DMP_POWER_SAVE_TIME_SEL_MASK);
apex_params->low_energy_amp_th = (APEX_CONFIG2_LOW_ENERGY_AMP_TH_t)
(data[0] & APEX_CONFIG2_LOW_ENERGY_AMP_TH_SEL_MASK);
/* Get params from apex_config3 : pedo_amp_th and pedo_step_cnt_th */
apex_params->pedo_amp_th = (APEX_CONFIG3_PEDO_AMP_TH_t)
(data[1] & APEX_CONFIG3_PED_AMP_TH_SEL_MASK);
apex_params->pedo_step_cnt_th = (data[1] & APEX_CONFIG3_PED_STEP_CNT_TH_SEL_MASK)
>> APEX_CONFIG3_PED_STEP_CNT_TH_SEL_POS;
/* Get params from apex_config4 : pedo_step_det_th, pedo_sb_timer_th and pedo_hi_enrgy_th */
apex_params->pedo_step_det_th = (data[2] & APEX_CONFIG4_PED_STEP_DET_TH_SEL_MASK)
>> APEX_CONFIG4_PED_STEP_DET_TH_SEL_POS;
apex_params->pedo_sb_timer_th = (APEX_CONFIG4_PEDO_SB_TIMER_TH_t)
(data[2] & APEX_CONFIG4_PED_SB_TIMER_TH_SEL_MASK);
apex_params->pedo_hi_enrgy_th = (APEX_CONFIG4_PEDO_HI_ENRGY_TH_t)
(data[2] & APEX_CONFIG4_PED_HI_EN_TH_SEL_MASK);
/* Get params from apex_config5 : tilt_wait_time, lowg_peak_hyst and highg_peak_hyst */
apex_params->tilt_wait_time = (APEX_CONFIG5_TILT_WAIT_TIME_t)
(data[3] & APEX_CONFIG5_TILT_WAIT_TIME_SEL_MASK);
apex_params->lowg_peak_hyst = (APEX_CONFIG5_LOWG_PEAK_TH_HYST_t)
(data[3] & APEX_CONFIG5_LOWG_PEAK_TH_HYST_SEL_MASK);
apex_params->highg_peak_hyst = (APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t)
(data[3] & APEX_CONFIG5_HIGHG_PEAK_TH_HYST_SEL_MASK);
/* Get params from apex_config9 : ff_debounce_duration, smd_sensitivity and sensitivity_mode */
apex_params->ff_debounce_duration = (APEX_CONFIG9_FF_DEBOUNCE_DURATION_t)
(data[4] & APEX_CONFIG9_FF_DEBOUNCE_DURATION_SEL_MASK);
apex_params->smd_sensitivity = (APEX_CONFIG9_SMD_SENSITIVITY_t)
(data[4] & APEX_CONFIG9_SMD_SENSITIVITY_SEL_MASK);
apex_params->sensitivity_mode = (APEX_CONFIG9_SENSITIVITY_MODE_t)
(data[4] & APEX_CONFIG9_SENSITIVITY_MODE_MASK);
/* Get params from apex_config10 : lowg_peak_th and lowg_samples_th */
apex_params->lowg_peak_th = (APEX_CONFIG10_LOWG_PEAK_TH_t)
(data[5] & APEX_CONFIG10_LOWG_PEAK_TH_SEL_MASK);
apex_params->lowg_samples_th = (APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t)
(data[5] & APEX_CONFIG10_LOWG_TIME_TH_SEL_MASK);
/* Get params from apex_config11 : highg_peak_th and highg_samples_th */
apex_params->highg_peak_th = (APEX_CONFIG11_HIGHG_PEAK_TH_t)
(data[6] & APEX_CONFIG11_HIGHG_PEAK_TH_SEL_MASK);
apex_params->highg_samples_th = (APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t)
(data[6] & APEX_CONFIG11_HIGHG_TIME_TH_SEL_MASK);
/* Access apex reg 12 */
status |= inv_imu_read_reg(s, APEX_CONFIG12_MREG1, 1, &data[0]);
/* Get params from apex_config12 : ff_max_duration_cm and ff_min_duration_cm */
apex_params->ff_max_duration_cm = (APEX_CONFIG12_FF_MAX_DURATION_t)
(data[0] & APEX_CONFIG12_FF_MAX_DURATION_SEL_MASK);
apex_params->ff_min_duration_cm = (APEX_CONFIG12_FF_MIN_DURATION_t)
(data[0] & APEX_CONFIG12_FF_MIN_DURATION_SEL_MASK);
return status;
}
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency)
{
uint8_t value;
int status = 0;
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_DMP_ODR_MASK;
value |= frequency;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
/* Enable Pedometer */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Disable Pedometer */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_PED_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_PED_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_enable_tilt(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
status |= inv_imu_start_dmp(s);
/* Enable Tilt */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_EN;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_disable_tilt(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Disable Tilt */
status |= inv_imu_read_reg(s, APEX_CONFIG1, 1, &value);
value &= ~APEX_CONFIG1_TILT_ENABLE_MASK;
value |= (uint8_t)APEX_CONFIG1_TILT_ENABLE_DIS;
status |= inv_imu_write_reg(s, APEX_CONFIG1, 1, &value);
return status;
}
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity)
{
uint8_t data[4];
int status = inv_imu_read_reg(s, APEX_DATA0, 4, data);
apex_activity->step_cnt = data[1] << 8 | data[0];
apex_activity->step_cadence = data[2];
apex_activity->activity_class = data[3] & APEX_DATA3_ACTIVITY_CLASS_MASK;
return status;
}
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration)
{
uint8_t data[2];
int status = inv_imu_read_reg(s, APEX_DATA4, 2, &data[0]);
*freefall_duration = (data[1] << 8) | data[0];
return status;
}

View File

@@ -1,185 +1,185 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverApex IMU driver high level functions related to APEX and the DMP
* @brief High-level function to setup an IMU device
* @ingroup Driver
* @{
*/
/** @file inv_imu_apex.h
* High-level function to setup an IMU device
*/
#ifndef _INV_IMU_APEX_H_
#define _INV_IMU_APEX_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "inv_imu_defs.h"
#include "InvError.h"
#include <stdint.h>
#include <string.h>
/* Forward declarations */
struct inv_imu_device;
/** @brief IMU APEX inputs parameters definition
*/
typedef struct {
APEX_CONFIG3_PEDO_AMP_TH_t pedo_amp_th;
uint8_t pedo_step_cnt_th;
uint8_t pedo_step_det_th;
APEX_CONFIG4_PEDO_SB_TIMER_TH_t pedo_sb_timer_th;
APEX_CONFIG4_PEDO_HI_ENRGY_TH_t pedo_hi_enrgy_th;
APEX_CONFIG5_TILT_WAIT_TIME_t tilt_wait_time;
APEX_CONFIG2_DMP_POWER_SAVE_TIME_t power_save_time;
APEX_CONFIG0_DMP_POWER_SAVE_t power_save;
APEX_CONFIG9_SENSITIVITY_MODE_t sensitivity_mode;
APEX_CONFIG2_LOW_ENERGY_AMP_TH_t low_energy_amp_th;
APEX_CONFIG9_SMD_SENSITIVITY_t smd_sensitivity;
APEX_CONFIG9_FF_DEBOUNCE_DURATION_t ff_debounce_duration;
APEX_CONFIG12_FF_MAX_DURATION_t ff_max_duration_cm;
APEX_CONFIG12_FF_MIN_DURATION_t ff_min_duration_cm;
APEX_CONFIG10_LOWG_PEAK_TH_t lowg_peak_th;
APEX_CONFIG5_LOWG_PEAK_TH_HYST_t lowg_peak_hyst;
APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t lowg_samples_th;
APEX_CONFIG11_HIGHG_PEAK_TH_t highg_peak_th;
APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t highg_peak_hyst;
APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t highg_samples_th;
} inv_imu_apex_parameters_t;
/** @brief APEX pedometer outputs
*/
typedef struct inv_imu_apex_step_activity {
uint16_t step_cnt; /**< Number of steps taken */
uint8_t step_cadence; /**< Walk/run cadence in number of samples.
Format is u6.2. E.g, At 50Hz and 2Hz walk frequency, if the cadency is 25 samples.
The register will output 100. */
uint8_t activity_class; /**< Detected activity unknown (0), walk (1) or run (2) */
} inv_imu_apex_step_activity_t;
/** @brief Enable Free Fall.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_ff(struct inv_imu_device *s);
/** @brief Disable Free Fall.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_ff(struct inv_imu_device *s);
/** @brief Enable Significant Motion Detection.
* note : SMD requests to have the accelerometer enabled to work.
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
* and the accelerometer in Low Power Mode.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_smd(struct inv_imu_device *s);
/** @brief Disable Significant Motion Detection.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_smd(struct inv_imu_device *s);
/** @brief Fill the APEX parameters structure with all the default parameters for APEX algorithms (pedometer, tilt)
* @param[out] apex_inputs Default input parameters. See @sa inv_imu_apex_parameters_t
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs);
/** @brief Configures DMP parameters for APEX algorithms (pedometer, tilt, lowg, highg).
* This programmable parameters will be decoded and propagate to the SRAM to be executed at DMP start.
* @param[in] apex_inputs The requested input parameters. See @sa inv_imu_apex_parameters_t
* @warning APEX inputs can't change on the fly, this API should be called before enabling any APEX features.
* @warning APEX configuration can't be done too frequently, but only once every 10ms.
* Otherwise it can create unknown behavior.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs);
/** @brief Returns current DMP parameters for APEX algorithms (pedometer, tilt).
* @param[out] apex_params The current parameter, fetched from registers. See @sa inv_imu_apex_parameters_t
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params);
/** @brief Configure DMP Output Data Rate for APEX algorithms (pedometer, tilt)
* @param[in] frequency The requested frequency.
* @sa APEX_CONFIG1_DMP_ODR_t
* @warning DMP_ODR can change on the fly, and the DMP code will accommodate necessary modifications
* @warning The user needs to take care to set Accel frequency >= DMP frequency. This is a hard constraint
since HW will not handle incorrect setting.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency);
/** @brief Enable APEX algorithm Pedometer.
* note : Pedometer request to have the accelerometer enabled to works
* with accelerometer frequency less than dmp frequency.
* @return 0 on success, negative value on error.
* @warning Pedometer must be turned OFF to reconfigure it
*/
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Pedometer.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s);
/** @brief Enable APEX algorithm Tilt.
* note : Tilt request to have the accelerometer enabled to works
* with accelerometer frequency less than dmp frequency.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_tilt(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Tilt.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_tilt(struct inv_imu_device *s);
/** @brief Retrieve APEX pedometer outputs and format them
* @param[out] apex_activity Apex step and activity data value.
* @return 0 in case of success, negative value on error. See enum inv_error
*/
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity);
/** @brief Retrieve APEX free fall outputs and format them
* @param[out] Free fall duration in number of sample.
* @return 0 in case of success, negative value on error. See enum inv_error
*/
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_APEX_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverApex IMU driver high level functions related to APEX and the DMP
* @brief High-level function to setup an IMU device
* @ingroup Driver
* @{
*/
/** @file inv_imu_apex.h
* High-level function to setup an IMU device
*/
#ifndef _INV_IMU_APEX_H_
#define _INV_IMU_APEX_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "inv_imu_defs.h"
#include "InvError.h"
#include <stdint.h>
#include <string.h>
/* Forward declarations */
struct inv_imu_device;
/** @brief IMU APEX inputs parameters definition
*/
typedef struct {
APEX_CONFIG3_PEDO_AMP_TH_t pedo_amp_th;
uint8_t pedo_step_cnt_th;
uint8_t pedo_step_det_th;
APEX_CONFIG4_PEDO_SB_TIMER_TH_t pedo_sb_timer_th;
APEX_CONFIG4_PEDO_HI_ENRGY_TH_t pedo_hi_enrgy_th;
APEX_CONFIG5_TILT_WAIT_TIME_t tilt_wait_time;
APEX_CONFIG2_DMP_POWER_SAVE_TIME_t power_save_time;
APEX_CONFIG0_DMP_POWER_SAVE_t power_save;
APEX_CONFIG9_SENSITIVITY_MODE_t sensitivity_mode;
APEX_CONFIG2_LOW_ENERGY_AMP_TH_t low_energy_amp_th;
APEX_CONFIG9_SMD_SENSITIVITY_t smd_sensitivity;
APEX_CONFIG9_FF_DEBOUNCE_DURATION_t ff_debounce_duration;
APEX_CONFIG12_FF_MAX_DURATION_t ff_max_duration_cm;
APEX_CONFIG12_FF_MIN_DURATION_t ff_min_duration_cm;
APEX_CONFIG10_LOWG_PEAK_TH_t lowg_peak_th;
APEX_CONFIG5_LOWG_PEAK_TH_HYST_t lowg_peak_hyst;
APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t lowg_samples_th;
APEX_CONFIG11_HIGHG_PEAK_TH_t highg_peak_th;
APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t highg_peak_hyst;
APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t highg_samples_th;
} inv_imu_apex_parameters_t;
/** @brief APEX pedometer outputs
*/
typedef struct inv_imu_apex_step_activity {
uint16_t step_cnt; /**< Number of steps taken */
uint8_t step_cadence; /**< Walk/run cadence in number of samples.
Format is u6.2. E.g, At 50Hz and 2Hz walk frequency, if the cadency is 25 samples.
The register will output 100. */
uint8_t activity_class; /**< Detected activity unknown (0), walk (1) or run (2) */
} inv_imu_apex_step_activity_t;
/** @brief Enable Free Fall.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_ff(struct inv_imu_device *s);
/** @brief Disable Free Fall.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_ff(struct inv_imu_device *s);
/** @brief Enable Significant Motion Detection.
* note : SMD requests to have the accelerometer enabled to work.
* To have good performance, it's recommended to set accelerometer ODR (Output Data Rate) to 20ms
* and the accelerometer in Low Power Mode.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_smd(struct inv_imu_device *s);
/** @brief Disable Significant Motion Detection.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_smd(struct inv_imu_device *s);
/** @brief Fill the APEX parameters structure with all the default parameters for APEX algorithms (pedometer, tilt)
* @param[out] apex_inputs Default input parameters. See @sa inv_imu_apex_parameters_t
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_init_parameters_struct(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_inputs);
/** @brief Configures DMP parameters for APEX algorithms (pedometer, tilt, lowg, highg).
* This programmable parameters will be decoded and propagate to the SRAM to be executed at DMP start.
* @param[in] apex_inputs The requested input parameters. See @sa inv_imu_apex_parameters_t
* @warning APEX inputs can't change on the fly, this API should be called before enabling any APEX features.
* @warning APEX configuration can't be done too frequently, but only once every 10ms.
* Otherwise it can create unknown behavior.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_configure_parameters(struct inv_imu_device *s, const inv_imu_apex_parameters_t *apex_inputs);
/** @brief Returns current DMP parameters for APEX algorithms (pedometer, tilt).
* @param[out] apex_params The current parameter, fetched from registers. See @sa inv_imu_apex_parameters_t
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params);
/** @brief Configure DMP Output Data Rate for APEX algorithms (pedometer, tilt)
* @param[in] frequency The requested frequency.
* @sa APEX_CONFIG1_DMP_ODR_t
* @warning DMP_ODR can change on the fly, and the DMP code will accommodate necessary modifications
* @warning The user needs to take care to set Accel frequency >= DMP frequency. This is a hard constraint
since HW will not handle incorrect setting.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency);
/** @brief Enable APEX algorithm Pedometer.
* note : Pedometer request to have the accelerometer enabled to works
* with accelerometer frequency less than dmp frequency.
* @return 0 on success, negative value on error.
* @warning Pedometer must be turned OFF to reconfigure it
*/
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Pedometer.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s);
/** @brief Enable APEX algorithm Tilt.
* note : Tilt request to have the accelerometer enabled to works
* with accelerometer frequency less than dmp frequency.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_tilt(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Tilt.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_tilt(struct inv_imu_device *s);
/** @brief Retrieve APEX pedometer outputs and format them
* @param[out] apex_activity Apex step and activity data value.
* @return 0 in case of success, negative value on error. See enum inv_error
*/
int inv_imu_apex_get_data_activity(struct inv_imu_device *s, inv_imu_apex_step_activity_t *apex_activity);
/** @brief Retrieve APEX free fall outputs and format them
* @param[out] Free fall duration in number of sample.
* @return 0 in case of success, negative value on error. See enum inv_error
*/
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_APEX_H_ */
/** @} */

View File

@@ -1,64 +1,64 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverExt IMU driver extern functions
* @brief Extern functions for IMU devices
* @ingroup Driver
* @{
*/
/** @file inv_imu_extfunc.h
* Extern functions for IMU devices
*/
#ifndef _INV_IMU_EXTFUNC_H_
#define _INV_IMU_EXTFUNC_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Hook for low-level high res system sleep() function to be implemented by upper layer
* ~100us resolution is sufficient
* @param[in] us number of us the calling thread should sleep
*/
extern void inv_imu_sleep_us(uint32_t us);
/** @brief Hook for low-level high res system get_time() function to be implemented by upper layer
* Value shall be on 64bit with a 1 us resolution
* @return The current time in us
*/
extern uint64_t inv_imu_get_time_us(void);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_EXTFUNC_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverExt IMU driver extern functions
* @brief Extern functions for IMU devices
* @ingroup Driver
* @{
*/
/** @file inv_imu_extfunc.h
* Extern functions for IMU devices
*/
#ifndef _INV_IMU_EXTFUNC_H_
#define _INV_IMU_EXTFUNC_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Hook for low-level high res system sleep() function to be implemented by upper layer
* ~100us resolution is sufficient
* @param[in] us number of us the calling thread should sleep
*/
extern void inv_imu_sleep_us(uint32_t us);
/** @brief Hook for low-level high res system get_time() function to be implemented by upper layer
* Value shall be on 64bit with a 1 us resolution
* @return The current time in us
*/
extern uint64_t inv_imu_get_time_us(void);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_EXTFUNC_H_ */
/** @} */

View File

@@ -1,179 +1,179 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_selftest.h"
#include "inv_imu_extfunc.h"
#include "inv_imu_transport.h"
static int configure_selftest_parameters(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params);
int inv_imu_run_selftest(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params,
inv_imu_selftest_output_t *st_output)
{
int status = 0;
uint8_t value;
uint8_t data[2] = {0};
uint8_t st_done = 0;
int polling_timeout_ms = 1000;
/* Disables Gyro/Accel sensors */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &value);
value &= ~(PWR_MGMT0_ACCEL_MODE_MASK | PWR_MGMT0_GYRO_MODE_MASK);
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &value);
/* Enable RC oscillator */
status |= inv_imu_switch_on_mclk(s);
/* Clear DMP SRAM (1 ms wait included in `inv_imu_reset_dmp()`) */
status |= inv_imu_reset_dmp(s, APEX_CONFIG0_DMP_MEM_RESET_APEX_ST_EN);
/* Update `dmp_is_on` since APEX features will have to restart from scratch */
s->dmp_is_on = 0;
/* Load self-test data */
status |= inv_imu_load_selftest_data(s);
/* Set self-test parameters */
status |= configure_selftest_parameters(s, st_params);
/*
* Enable accel and/or gyro self-test.
* If both accel and gyro self-test are enabled,
* they should be set simultaneously in the same write access
*/
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
value &= ~SELFTEST_EN;
value |= (uint8_t)st_params.st_control;
status |= inv_imu_write_reg(s, SELFTEST_MREG1, 1, &value);
/* Poll int_status_st_done bit */
do {
inv_imu_sleep_us(1000);
status |= inv_imu_read_reg(s, INT_STATUS, 1, &st_done);
st_done &= INT_STATUS_ST_INT_MASK;
if (0 == --polling_timeout_ms)
return (status | -1); /* Return error if timeout is reached */
} while ( !st_done /* Exit if ST_DONE */
&& !status /* Or if error is detected */);
/* Read self-test results */
status |= inv_imu_read_reg(s, ST_STATUS1_MREG1, 2, &data[0]);
st_output->accel_status = (data[0] & ST_STATUS1_ACCEL_ST_PASS_MASK) >> ST_STATUS1_ACCEL_ST_PASS_POS;
st_output->ax_status = (data[0] & ST_STATUS1_AX_ST_PASS_MASK) >> ST_STATUS1_AX_ST_PASS_POS;
st_output->ay_status = (data[0] & ST_STATUS1_AY_ST_PASS_MASK) >> ST_STATUS1_AY_ST_PASS_POS;
st_output->az_status = (data[0] & ST_STATUS1_AZ_ST_PASS_MASK) >> ST_STATUS1_AZ_ST_PASS_POS;
st_output->gyro_status = (data[1] & ST_STATUS2_GYRO_ST_PASS_MASK) >> ST_STATUS2_GYRO_ST_PASS_POS;
st_output->gyro_status |= ((data[1] & ST_STATUS2_ST_INCOMPLETE_MASK) >> ST_STATUS2_ST_INCOMPLETE_POS) << 1;
st_output->gx_status = (data[1] & ST_STATUS2_GX_ST_PASS_MASK) >> ST_STATUS2_GX_ST_PASS_POS;
st_output->gy_status = (data[1] & ST_STATUS2_GY_ST_PASS_MASK) >> ST_STATUS2_GY_ST_PASS_POS;
st_output->gz_status = (data[1] & ST_STATUS2_GZ_ST_PASS_MASK) >> ST_STATUS2_GZ_ST_PASS_POS;
/* Disable self-test */
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
value &= ~SELFTEST_EN;
value |= (uint8_t)SELFTEST_DIS;
status |= inv_imu_write_reg(s, SELFTEST_MREG1, 1, &value);
/* Reset FIFO because ST data may have been pushed to it */
status |= inv_imu_reset_fifo(s);
/* Restore idle bit */
status |= inv_imu_switch_off_mclk(s);
return status;
}
int inv_imu_init_selftest_parameters_struct(struct inv_imu_device *s,
inv_imu_selftest_parameters_t *st_params)
{
(void)s;
st_params->st_num_samples = ST_CONFIG_16_SAMPLES;
st_params->st_control = (SELFTEST_ACCEL_GYRO_ST_EN_t)SELFTEST_EN;
return 0;
}
int inv_imu_load_selftest_data(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Enable RC oscillator */
status |= inv_imu_switch_on_mclk(s);
/* Set up OTP controller to reload factory-trimmed self-test response into SRAM */
status |= inv_imu_read_reg(s, OTP_CONFIG_MREG1, 1, &value);
value &= ~OTP_CONFIG_OTP_COPY_MODE_MASK;
value |= (uint8_t)OTP_CONFIG_OTP_COPY_ST_DATA;
status |= inv_imu_write_reg(s, OTP_CONFIG_MREG1, 1, &value);
/* Take the OTP macro out of power-down mode */
status |= inv_imu_read_reg(s, OTP_CTRL7_MREG2, 1, &value);
value &= ~OTP_CTRL7_OTP_PWR_DOWN_MASK;
value |= (uint8_t)OTP_CTRL7_PWR_DOWN_DIS;
status |= inv_imu_write_reg(s, OTP_CTRL7_MREG2, 1, &value);
/* Wait for voltage generator to power on */
inv_imu_sleep_us(100);
/* Host should disable INT function first before kicking off OTP copy operation */
/* Trigger OTP to reload data (this time in self-test mode) */
status |= inv_imu_read_reg(s, OTP_CTRL7_MREG2, 1, &value);
value &= ~OTP_CTRL7_OTP_RELOAD_MASK;
value |= (uint8_t)OTP_CTRL7_OTP_RELOAD_EN;
status |= inv_imu_write_reg(s, OTP_CTRL7_MREG2, 1, &value);
/* Wait for OTP reload */
inv_imu_sleep_us(20);
/* Disable RC oscillator */
status |= inv_imu_switch_off_mclk(s);
return status;
}
static int configure_selftest_parameters(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params)
{
int status = 0;
uint8_t value;
/* Self-test configuration cannot be updated if it already running */
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
if ((value & SELFTEST_EN) != SELFTEST_DIS)
return INV_ERROR_UNEXPECTED;
status |= inv_imu_read_reg(s, ST_CONFIG_MREG1, 1, &value);
value &= ~((uint8_t)ST_CONFIG_ST_NUMBER_SAMPLE_MASK
| (uint8_t)ST_CONFIG_ACCEL_ST_LIM_MASK
| (uint8_t)ST_CONFIG_GYRO_ST_LIM_MASK);
value |= (uint8_t)st_params.st_num_samples
| (uint8_t)ST_CONFIG_ACCEL_ST_LIM_50
| (uint8_t)ST_CONFIG_GYRO_ST_LIM_50;
status |= inv_imu_write_reg(s, ST_CONFIG_MREG1, 1, &value);
return status;
}
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_selftest.h"
#include "inv_imu_extfunc.h"
#include "inv_imu_transport.h"
static int configure_selftest_parameters(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params);
int inv_imu_run_selftest(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params,
inv_imu_selftest_output_t *st_output)
{
int status = 0;
uint8_t value;
uint8_t data[2] = {0};
uint8_t st_done = 0;
int polling_timeout_ms = 1000;
/* Disables Gyro/Accel sensors */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &value);
value &= ~(PWR_MGMT0_ACCEL_MODE_MASK | PWR_MGMT0_GYRO_MODE_MASK);
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &value);
/* Enable RC oscillator */
status |= inv_imu_switch_on_mclk(s);
/* Clear DMP SRAM (1 ms wait included in `inv_imu_reset_dmp()`) */
status |= inv_imu_reset_dmp(s, APEX_CONFIG0_DMP_MEM_RESET_APEX_ST_EN);
/* Update `dmp_is_on` since APEX features will have to restart from scratch */
s->dmp_is_on = 0;
/* Load self-test data */
status |= inv_imu_load_selftest_data(s);
/* Set self-test parameters */
status |= configure_selftest_parameters(s, st_params);
/*
* Enable accel and/or gyro self-test.
* If both accel and gyro self-test are enabled,
* they should be set simultaneously in the same write access
*/
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
value &= ~SELFTEST_EN;
value |= (uint8_t)st_params.st_control;
status |= inv_imu_write_reg(s, SELFTEST_MREG1, 1, &value);
/* Poll int_status_st_done bit */
do {
inv_imu_sleep_us(1000);
status |= inv_imu_read_reg(s, INT_STATUS, 1, &st_done);
st_done &= INT_STATUS_ST_INT_MASK;
if (0 == --polling_timeout_ms)
return (status | -1); /* Return error if timeout is reached */
} while ( !st_done /* Exit if ST_DONE */
&& !status /* Or if error is detected */);
/* Read self-test results */
status |= inv_imu_read_reg(s, ST_STATUS1_MREG1, 2, &data[0]);
st_output->accel_status = (data[0] & ST_STATUS1_ACCEL_ST_PASS_MASK) >> ST_STATUS1_ACCEL_ST_PASS_POS;
st_output->ax_status = (data[0] & ST_STATUS1_AX_ST_PASS_MASK) >> ST_STATUS1_AX_ST_PASS_POS;
st_output->ay_status = (data[0] & ST_STATUS1_AY_ST_PASS_MASK) >> ST_STATUS1_AY_ST_PASS_POS;
st_output->az_status = (data[0] & ST_STATUS1_AZ_ST_PASS_MASK) >> ST_STATUS1_AZ_ST_PASS_POS;
st_output->gyro_status = (data[1] & ST_STATUS2_GYRO_ST_PASS_MASK) >> ST_STATUS2_GYRO_ST_PASS_POS;
st_output->gyro_status |= ((data[1] & ST_STATUS2_ST_INCOMPLETE_MASK) >> ST_STATUS2_ST_INCOMPLETE_POS) << 1;
st_output->gx_status = (data[1] & ST_STATUS2_GX_ST_PASS_MASK) >> ST_STATUS2_GX_ST_PASS_POS;
st_output->gy_status = (data[1] & ST_STATUS2_GY_ST_PASS_MASK) >> ST_STATUS2_GY_ST_PASS_POS;
st_output->gz_status = (data[1] & ST_STATUS2_GZ_ST_PASS_MASK) >> ST_STATUS2_GZ_ST_PASS_POS;
/* Disable self-test */
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
value &= ~SELFTEST_EN;
value |= (uint8_t)SELFTEST_DIS;
status |= inv_imu_write_reg(s, SELFTEST_MREG1, 1, &value);
/* Reset FIFO because ST data may have been pushed to it */
status |= inv_imu_reset_fifo(s);
/* Restore idle bit */
status |= inv_imu_switch_off_mclk(s);
return status;
}
int inv_imu_init_selftest_parameters_struct(struct inv_imu_device *s,
inv_imu_selftest_parameters_t *st_params)
{
(void)s;
st_params->st_num_samples = ST_CONFIG_16_SAMPLES;
st_params->st_control = (SELFTEST_ACCEL_GYRO_ST_EN_t)SELFTEST_EN;
return 0;
}
int inv_imu_load_selftest_data(struct inv_imu_device *s)
{
int status = 0;
uint8_t value;
/* Enable RC oscillator */
status |= inv_imu_switch_on_mclk(s);
/* Set up OTP controller to reload factory-trimmed self-test response into SRAM */
status |= inv_imu_read_reg(s, OTP_CONFIG_MREG1, 1, &value);
value &= ~OTP_CONFIG_OTP_COPY_MODE_MASK;
value |= (uint8_t)OTP_CONFIG_OTP_COPY_ST_DATA;
status |= inv_imu_write_reg(s, OTP_CONFIG_MREG1, 1, &value);
/* Take the OTP macro out of power-down mode */
status |= inv_imu_read_reg(s, OTP_CTRL7_MREG2, 1, &value);
value &= ~OTP_CTRL7_OTP_PWR_DOWN_MASK;
value |= (uint8_t)OTP_CTRL7_PWR_DOWN_DIS;
status |= inv_imu_write_reg(s, OTP_CTRL7_MREG2, 1, &value);
/* Wait for voltage generator to power on */
inv_imu_sleep_us(100);
/* Host should disable INT function first before kicking off OTP copy operation */
/* Trigger OTP to reload data (this time in self-test mode) */
status |= inv_imu_read_reg(s, OTP_CTRL7_MREG2, 1, &value);
value &= ~OTP_CTRL7_OTP_RELOAD_MASK;
value |= (uint8_t)OTP_CTRL7_OTP_RELOAD_EN;
status |= inv_imu_write_reg(s, OTP_CTRL7_MREG2, 1, &value);
/* Wait for OTP reload */
inv_imu_sleep_us(20);
/* Disable RC oscillator */
status |= inv_imu_switch_off_mclk(s);
return status;
}
static int configure_selftest_parameters(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params)
{
int status = 0;
uint8_t value;
/* Self-test configuration cannot be updated if it already running */
status |= inv_imu_read_reg(s, SELFTEST_MREG1, 1, &value);
if ((value & SELFTEST_EN) != SELFTEST_DIS)
return INV_ERROR_UNEXPECTED;
status |= inv_imu_read_reg(s, ST_CONFIG_MREG1, 1, &value);
value &= ~((uint8_t)ST_CONFIG_ST_NUMBER_SAMPLE_MASK
| (uint8_t)ST_CONFIG_ACCEL_ST_LIM_MASK
| (uint8_t)ST_CONFIG_GYRO_ST_LIM_MASK);
value |= (uint8_t)st_params.st_num_samples
| (uint8_t)ST_CONFIG_ACCEL_ST_LIM_50
| (uint8_t)ST_CONFIG_GYRO_ST_LIM_50;
status |= inv_imu_write_reg(s, ST_CONFIG_MREG1, 1, &value);
return status;
}

View File

@@ -1,101 +1,101 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverST SelfTest IMU selftest
* @brief Low-level function to run selftest on a IMU device
* @ingroup Driver
* @{
*/
/** @file inv_imu_selftest.h
* Low-level function to run selftest on a IMU device
*/
#ifndef _INV_IMU_SELFTEST_H_
#define _INV_IMU_SELFTEST_H_
#include <stdint.h>
#include "InvExport.h"
#include "inv_imu_defs.h"
#include "inv_imu_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
/* forward declaration */
struct inv_imu_device;
/** @brief Self-test input parameters
*/
typedef struct {
ST_CONFIG_NUM_SAMPLES_t st_num_samples; /**< Number of samples used to perform self-test */
SELFTEST_ACCEL_GYRO_ST_EN_t st_control; /**< Define which sensor is under self-test */
} inv_imu_selftest_parameters_t;
/** @brief Self-test routine outputs
*/
typedef struct {
int8_t accel_status; /**< global accelerometer self-test passed */
int8_t gyro_status; /**< global gyroscope self-test status: st_pass (bit0), st_incomplete (bit1) */
int8_t ax_status; /**< AX self-test status */
int8_t ay_status; /**< AY self-test status */
int8_t az_status; /**< AZ self-test status */
int8_t gx_status; /**< GX self-test status */
int8_t gy_status; /**< GY self-test status */
int8_t gz_status; /**< GZ self-test status */
} inv_imu_selftest_output_t;
/**
* @brief Perform hardware self-test for Accel and Gyro
* @param[in] Self-test parameters (see inv_imu_selftest_parameters_t)
* @param[out] Self-test results (see inv_imu_selftest_output_t)
* @return 0 on completion, negative number if intermediate errors occurred
*/
int inv_imu_run_selftest(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params,
inv_imu_selftest_output_t *st_output);
/** @brief Fill the self-test configuration structure with default configuration
* @param[in] selftest_params self-test parameters to be initialized
* @return 0 on success, negative return code otherwise
*/
int inv_imu_init_selftest_parameters_struct(struct inv_imu_device *s,
inv_imu_selftest_parameters_t *selftest_params);
/** @brief Load self-test data
* @return 0 on success, negative return code otherwise
*/
int inv_imu_load_selftest_data(struct inv_imu_device *s);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_SELFTEST_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup DriverST SelfTest IMU selftest
* @brief Low-level function to run selftest on a IMU device
* @ingroup Driver
* @{
*/
/** @file inv_imu_selftest.h
* Low-level function to run selftest on a IMU device
*/
#ifndef _INV_IMU_SELFTEST_H_
#define _INV_IMU_SELFTEST_H_
#include <stdint.h>
#include "InvExport.h"
#include "inv_imu_defs.h"
#include "inv_imu_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
/* forward declaration */
struct inv_imu_device;
/** @brief Self-test input parameters
*/
typedef struct {
ST_CONFIG_NUM_SAMPLES_t st_num_samples; /**< Number of samples used to perform self-test */
SELFTEST_ACCEL_GYRO_ST_EN_t st_control; /**< Define which sensor is under self-test */
} inv_imu_selftest_parameters_t;
/** @brief Self-test routine outputs
*/
typedef struct {
int8_t accel_status; /**< global accelerometer self-test passed */
int8_t gyro_status; /**< global gyroscope self-test status: st_pass (bit0), st_incomplete (bit1) */
int8_t ax_status; /**< AX self-test status */
int8_t ay_status; /**< AY self-test status */
int8_t az_status; /**< AZ self-test status */
int8_t gx_status; /**< GX self-test status */
int8_t gy_status; /**< GY self-test status */
int8_t gz_status; /**< GZ self-test status */
} inv_imu_selftest_output_t;
/**
* @brief Perform hardware self-test for Accel and Gyro
* @param[in] Self-test parameters (see inv_imu_selftest_parameters_t)
* @param[out] Self-test results (see inv_imu_selftest_output_t)
* @return 0 on completion, negative number if intermediate errors occurred
*/
int inv_imu_run_selftest(struct inv_imu_device *s,
const inv_imu_selftest_parameters_t st_params,
inv_imu_selftest_output_t *st_output);
/** @brief Fill the self-test configuration structure with default configuration
* @param[in] selftest_params self-test parameters to be initialized
* @return 0 on success, negative return code otherwise
*/
int inv_imu_init_selftest_parameters_struct(struct inv_imu_device *s,
inv_imu_selftest_parameters_t *selftest_params);
/** @brief Load self-test data
* @return 0 on success, negative return code otherwise
*/
int inv_imu_load_selftest_data(struct inv_imu_device *s);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_SELFTEST_H_ */
/** @} */

View File

@@ -1,257 +1,257 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_extfunc.h"
#include "inv_imu_transport.h"
#include "inv_imu_regmap.h"
#include "InvError.h"
/* Function definition */
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg);
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf);
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf);
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf);
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf);
int inv_imu_init_transport(struct inv_imu_device *s)
{
int status = 0;
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
status |= read_sreg(s, (uint8_t)PWR_MGMT0, 1, &(t->register_cache.pwr_mgmt0_reg));
status |= read_sreg(s, (uint8_t)GYRO_CONFIG0, 1, &(t->register_cache.gyro_config0_reg));
status |= read_sreg(s, (uint8_t)ACCEL_CONFIG0, 1, &(t->register_cache.accel_config0_reg));
status |= read_mclk_reg(s, (TMST_CONFIG1_MREG1 & 0xFFFF), 1, &(t->register_cache.tmst_config1_reg));
t->need_mclk_cnt = 0;
return status;
}
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf)
{
uint32_t i;
int rc = 0;
for (i = 0; i < len; i++) {
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
if (cache_addr) {
buf[i] = *cache_addr;
} else {
if (!(reg & 0x10000)) {
rc |= read_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
} else {
rc |= read_sreg(s, (uint8_t)reg + i, len - i, &buf[i]);
break;
}
}
}
return rc;
}
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf)
{
uint32_t i;
int rc = 0;
for (i = 0; i < len; i++) {
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
if (cache_addr)
*cache_addr = buf[i];
if (!(reg & 0x10000))
rc |= write_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
}
if (reg & 0x10000)
rc |= write_sreg(s, (uint8_t)reg, len, buf);
return rc;
}
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;
/* set IDLE bit only if it is not set yet */
if (t->need_mclk_cnt == 0) {
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
data |= PWR_MGMT0_IDLE_MASK;
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
if (status)
return status;
/* Check if MCLK is ready */
do {
status = inv_imu_read_reg(s, MCLK_RDY, 1, &data);
} while ((status != 0) || !(data & MCLK_RDY_MCLK_RDY_MASK));
} else {
/* Make sure it is already on */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
if (0 == (data &= PWR_MGMT0_IDLE_MASK))
status |= INV_ERROR;
}
/* Increment the counter to keep track of number of MCLK requesters */
t->need_mclk_cnt++;
return status;
}
int inv_imu_switch_off_mclk(struct inv_imu_device *s)
{
int status = 0;
uint8_t data;
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
/* Reset the IDLE but only if there is one requester left */
if (t->need_mclk_cnt == 1) {
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
data &= ~PWR_MGMT0_IDLE_MASK;
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
} else {
/* Make sure it is still on */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
if (0 == (data &= PWR_MGMT0_IDLE_MASK))
status |= INV_ERROR;
}
/* Decrement the counter */
t->need_mclk_cnt--;
return status;
}
/* Static function */
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg)
{
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
switch(reg) {
case PWR_MGMT0: return &(t->register_cache.pwr_mgmt0_reg);
case GYRO_CONFIG0: return &(t->register_cache.gyro_config0_reg);
case ACCEL_CONFIG0: return &(t->register_cache.accel_config0_reg);
case TMST_CONFIG1_MREG1: return &(t->register_cache.tmst_config1_reg);
default: return (uint8_t *)0; // Not found
}
}
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf)
{
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
if (len > serif->max_read)
return INV_ERROR_SIZE;
if (serif->read_reg(serif, reg, buf, len) != 0)
return INV_ERROR_TRANSPORT;
return 0;
}
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf)
{
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
if (len > serif->max_write)
return INV_ERROR_SIZE;
if (serif->write_reg(serif, reg, buf, len) != 0)
return INV_ERROR_TRANSPORT;
return 0;
}
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf)
{
uint8_t data;
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
int status = 0;
// Have IMU not in IDLE mode to access MCLK domain
status |= inv_imu_switch_on_mclk(s);
// optimize by changing BLK_SEL only if not NULL
if (blk_sel)
status |= write_sreg(s, (uint8_t)BLK_SEL_R & 0xff, 1, &blk_sel);
data = (regaddr & 0x00FF);
status |= write_sreg(s, (uint8_t)MADDR_R, 1, &data);
inv_imu_sleep_us(10);
status |= read_sreg(s, (uint8_t)M_R, rd_cnt, buf);
inv_imu_sleep_us(10);
if (blk_sel) {
data = 0;
status |= write_sreg(s, (uint8_t)BLK_SEL_R, 1, &data);
}
// switch OFF MCLK if needed
status |= inv_imu_switch_off_mclk(s);
return status;
}
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf)
{
uint8_t data;
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
int status = 0;
// Have IMU not in IDLE mode to access MCLK domain
status |= inv_imu_switch_on_mclk(s);
// optimize by changing BLK_SEL only if not NULL
if (blk_sel)
status |= write_sreg(s, (uint8_t)BLK_SEL_W, 1, &blk_sel);
data = (regaddr & 0x00FF);
status |= write_sreg(s, (uint8_t)MADDR_W, 1, &data);
for (uint8_t i = 0; i < wr_cnt; i++) {
status |= write_sreg(s, (uint8_t)M_W, 1, &buf[i]);
inv_imu_sleep_us(10);
}
if (blk_sel) {
data = 0;
status = write_sreg(s, (uint8_t)BLK_SEL_W, 1, &data);
}
status |= inv_imu_switch_off_mclk(s);
return status;
}
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#include "inv_imu_extfunc.h"
#include "inv_imu_transport.h"
#include "inv_imu_regmap.h"
#include "InvError.h"
/* Function definition */
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg);
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf);
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf);
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf);
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf);
int inv_imu_init_transport(struct inv_imu_device *s)
{
int status = 0;
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
status |= read_sreg(s, (uint8_t)PWR_MGMT0, 1, &(t->register_cache.pwr_mgmt0_reg));
status |= read_sreg(s, (uint8_t)GYRO_CONFIG0, 1, &(t->register_cache.gyro_config0_reg));
status |= read_sreg(s, (uint8_t)ACCEL_CONFIG0, 1, &(t->register_cache.accel_config0_reg));
status |= read_mclk_reg(s, (TMST_CONFIG1_MREG1 & 0xFFFF), 1, &(t->register_cache.tmst_config1_reg));
t->need_mclk_cnt = 0;
return status;
}
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf)
{
uint32_t i;
int rc = 0;
for (i = 0; i < len; i++) {
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
if (cache_addr) {
buf[i] = *cache_addr;
} else {
if (!(reg & 0x10000)) {
rc |= read_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
} else {
rc |= read_sreg(s, (uint8_t)reg + i, len - i, &buf[i]);
break;
}
}
}
return rc;
}
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf)
{
uint32_t i;
int rc = 0;
for (i = 0; i < len; i++) {
uint8_t *cache_addr = get_register_cache_addr(s, reg + i);
if (cache_addr)
*cache_addr = buf[i];
if (!(reg & 0x10000))
rc |= write_mclk_reg(s, ((reg + i) & 0xFFFF), 1, &buf[i]);
}
if (reg & 0x10000)
rc |= write_sreg(s, (uint8_t)reg, len, buf);
return rc;
}
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;
/* set IDLE bit only if it is not set yet */
if (t->need_mclk_cnt == 0) {
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
data |= PWR_MGMT0_IDLE_MASK;
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
if (status)
return status;
/* Check if MCLK is ready */
do {
status = inv_imu_read_reg(s, MCLK_RDY, 1, &data);
} while ((status != 0) || !(data & MCLK_RDY_MCLK_RDY_MASK));
} else {
/* Make sure it is already on */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
if (0 == (data &= PWR_MGMT0_IDLE_MASK))
status |= INV_ERROR;
}
/* Increment the counter to keep track of number of MCLK requesters */
t->need_mclk_cnt++;
return status;
}
int inv_imu_switch_off_mclk(struct inv_imu_device *s)
{
int status = 0;
uint8_t data;
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
/* Reset the IDLE but only if there is one requester left */
if (t->need_mclk_cnt == 1) {
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
data &= ~PWR_MGMT0_IDLE_MASK;
status |= inv_imu_write_reg(s, PWR_MGMT0, 1, &data);
} else {
/* Make sure it is still on */
status |= inv_imu_read_reg(s, PWR_MGMT0, 1, &data);
if (0 == (data &= PWR_MGMT0_IDLE_MASK))
status |= INV_ERROR;
}
/* Decrement the counter */
t->need_mclk_cnt--;
return status;
}
/* Static function */
static uint8_t *get_register_cache_addr(struct inv_imu_device *s, uint32_t reg)
{
struct inv_imu_transport *t = (struct inv_imu_transport *)s;
switch(reg) {
case PWR_MGMT0: return &(t->register_cache.pwr_mgmt0_reg);
case GYRO_CONFIG0: return &(t->register_cache.gyro_config0_reg);
case ACCEL_CONFIG0: return &(t->register_cache.accel_config0_reg);
case TMST_CONFIG1_MREG1: return &(t->register_cache.tmst_config1_reg);
default: return (uint8_t *)0; // Not found
}
}
static int read_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, uint8_t *buf)
{
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
if (len > serif->max_read)
return INV_ERROR_SIZE;
if (serif->read_reg(serif, reg, buf, len) != 0)
return INV_ERROR_TRANSPORT;
return 0;
}
static int write_sreg(struct inv_imu_device *s, uint8_t reg, uint32_t len, const uint8_t *buf)
{
struct inv_imu_serif *serif = (struct inv_imu_serif *)s;
if (len > serif->max_write)
return INV_ERROR_SIZE;
if (serif->write_reg(serif, reg, buf, len) != 0)
return INV_ERROR_TRANSPORT;
return 0;
}
static int read_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t rd_cnt, uint8_t *buf)
{
uint8_t data;
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
int status = 0;
// Have IMU not in IDLE mode to access MCLK domain
status |= inv_imu_switch_on_mclk(s);
// optimize by changing BLK_SEL only if not NULL
if (blk_sel)
status |= write_sreg(s, (uint8_t)BLK_SEL_R & 0xff, 1, &blk_sel);
data = (regaddr & 0x00FF);
status |= write_sreg(s, (uint8_t)MADDR_R, 1, &data);
inv_imu_sleep_us(10);
status |= read_sreg(s, (uint8_t)M_R, rd_cnt, buf);
inv_imu_sleep_us(10);
if (blk_sel) {
data = 0;
status |= write_sreg(s, (uint8_t)BLK_SEL_R, 1, &data);
}
// switch OFF MCLK if needed
status |= inv_imu_switch_off_mclk(s);
return status;
}
static int write_mclk_reg(struct inv_imu_device *s, uint16_t regaddr, uint8_t wr_cnt, const uint8_t *buf)
{
uint8_t data;
uint8_t blk_sel = (regaddr & 0xFF00) >> 8;
int status = 0;
// Have IMU not in IDLE mode to access MCLK domain
status |= inv_imu_switch_on_mclk(s);
// optimize by changing BLK_SEL only if not NULL
if (blk_sel)
status |= write_sreg(s, (uint8_t)BLK_SEL_W, 1, &blk_sel);
data = (regaddr & 0x00FF);
status |= write_sreg(s, (uint8_t)MADDR_W, 1, &data);
for (uint8_t i = 0; i < wr_cnt; i++) {
status |= write_sreg(s, (uint8_t)M_W, 1, &buf[i]);
inv_imu_sleep_us(10);
}
if (blk_sel) {
data = 0;
status = write_sreg(s, (uint8_t)BLK_SEL_W, 1, &data);
}
status |= inv_imu_switch_off_mclk(s);
return status;
}

View File

@@ -1,122 +1,122 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup Transport IMU transport
* @brief Low-level IMU SCLK register access
* @ingroup Driver
* @{
*/
/** @file inv_imu_transport.h
* Low-level IMU SCLK register access
*/
#ifndef _INV_IMU_TRANSPORT_H_
#define _INV_IMU_TRANSPORT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* forward declaration */
struct inv_imu_device;
/** @brief enumeration of serial interfaces available on IMU */
typedef enum
{
UI_I2C,
UI_SPI4,
UI_SPI3
} SERIAL_IF_TYPE_t;
/** @brief basesensor serial interface
*/
struct inv_imu_serif {
void *context;
int (*read_reg)(struct inv_imu_serif *serif, uint8_t reg, uint8_t *buf, uint32_t len);
int (*write_reg)(struct inv_imu_serif *serif, uint8_t reg, const uint8_t *buf, uint32_t len);
int (*configure)(struct inv_imu_serif *serif);
uint32_t max_read;
uint32_t max_write;
SERIAL_IF_TYPE_t serif_type;
};
/** @brief transport interface
*/
struct inv_imu_transport {
struct inv_imu_serif serif; /**< Warning : this field MUST be the first one of struct inv_imu_transport */
/** @brief Contains mirrored values of some IP registers */
struct register_cache {
uint8_t pwr_mgmt0_reg; /**< PWR_MGMT0, Bank: 0 */
uint8_t gyro_config0_reg; /**< GYRO_CONFIG0, Bank: 0 */
uint8_t accel_config0_reg; /**< ACCEL_CONFIG0, Bank: 0 */
uint8_t tmst_config1_reg; /**< TMST_CONFIG1, Bank: MREG_TOP1 */
} register_cache; /**< Store mostly used register values on SRAM */
uint8_t need_mclk_cnt; /**< internal counter to keep track of everyone that needs MCLK */
};
/** @brief Init cache variable.
* @return 0 in case of success, -1 for any error
*/
int inv_imu_init_transport(struct inv_imu_device *s);
/** @brief Reads data from a register on IMU.
* @param[in] reg register address to be read
* @param[in] len number of byte to be read
* @param[out] buf output data from the register
* @return 0 in case of success, -1 for any error
*/
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf);
/** @brief Writes data to a register on IMU.
* @param[in] reg register address to be written
* @param[in] len number of byte to be written
* @param[in] buf input data to write
* @return 0 in case of success, -1 for any error
*/
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf);
/** @brief Enable MCLK so that MREG are clocked and system beyond SOI can be safely accessed
* @return 0 in case of success, -1 for any error
*/
int inv_imu_switch_on_mclk(struct inv_imu_device *s);
/** @brief Disable MCLK so that MREG are not clocked anymore, hence reducing power consumption
* @return 0 in case of success, -1 for any error
*/
int inv_imu_switch_off_mclk(struct inv_imu_device *s);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_TRANSPORT_H_ */
/** @} */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup Transport IMU transport
* @brief Low-level IMU SCLK register access
* @ingroup Driver
* @{
*/
/** @file inv_imu_transport.h
* Low-level IMU SCLK register access
*/
#ifndef _INV_IMU_TRANSPORT_H_
#define _INV_IMU_TRANSPORT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* forward declaration */
struct inv_imu_device;
/** @brief enumeration of serial interfaces available on IMU */
typedef enum
{
UI_I2C,
UI_SPI4,
UI_SPI3
} SERIAL_IF_TYPE_t;
/** @brief basesensor serial interface
*/
struct inv_imu_serif {
void *context;
int (*read_reg)(struct inv_imu_serif *serif, uint8_t reg, uint8_t *buf, uint32_t len);
int (*write_reg)(struct inv_imu_serif *serif, uint8_t reg, const uint8_t *buf, uint32_t len);
int (*configure)(struct inv_imu_serif *serif);
uint32_t max_read;
uint32_t max_write;
SERIAL_IF_TYPE_t serif_type;
};
/** @brief transport interface
*/
struct inv_imu_transport {
struct inv_imu_serif serif; /**< Warning : this field MUST be the first one of struct inv_imu_transport */
/** @brief Contains mirrored values of some IP registers */
struct register_cache {
uint8_t pwr_mgmt0_reg; /**< PWR_MGMT0, Bank: 0 */
uint8_t gyro_config0_reg; /**< GYRO_CONFIG0, Bank: 0 */
uint8_t accel_config0_reg; /**< ACCEL_CONFIG0, Bank: 0 */
uint8_t tmst_config1_reg; /**< TMST_CONFIG1, Bank: MREG_TOP1 */
} register_cache; /**< Store mostly used register values on SRAM */
uint8_t need_mclk_cnt; /**< internal counter to keep track of everyone that needs MCLK */
};
/** @brief Init cache variable.
* @return 0 in case of success, -1 for any error
*/
int inv_imu_init_transport(struct inv_imu_device *s);
/** @brief Reads data from a register on IMU.
* @param[in] reg register address to be read
* @param[in] len number of byte to be read
* @param[out] buf output data from the register
* @return 0 in case of success, -1 for any error
*/
int inv_imu_read_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf);
/** @brief Writes data to a register on IMU.
* @param[in] reg register address to be written
* @param[in] len number of byte to be written
* @param[in] buf input data to write
* @return 0 in case of success, -1 for any error
*/
int inv_imu_write_reg(struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf);
/** @brief Enable MCLK so that MREG are clocked and system beyond SOI can be safely accessed
* @return 0 in case of success, -1 for any error
*/
int inv_imu_switch_on_mclk(struct inv_imu_device *s);
/** @brief Disable MCLK so that MREG are not clocked anymore, hence reducing power consumption
* @return 0 in case of success, -1 for any error
*/
int inv_imu_switch_off_mclk(struct inv_imu_device *s);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_TRANSPORT_H_ */
/** @} */

View File

@@ -1,37 +1,37 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2019 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#ifndef _INV_IMU_VERSION_H_
#define _INV_IMU_VERSION_H_
#ifdef __cplusplus
extern "C" {
#endif
#define INV_IMU_VERSION_STRING "2.0.4"
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_VERSION_H_ */
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2019 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively Software) is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
#ifndef _INV_IMU_VERSION_H_
#define _INV_IMU_VERSION_H_
#ifdef __cplusplus
extern "C" {
#endif
#define INV_IMU_VERSION_STRING "2.0.4"
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_VERSION_H_ */

View File

@@ -1,153 +1,153 @@
//-----------------------------------------------------------------------------
/*
Copyright © 2014-2015 InvenSense Inc. Portions Copyright © 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively Software) is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
and other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license agreement
from InvenSense is strictly prohibited.
*/
//-----------------------------------------------------------------------------
#ifndef INVN_COMMON_INVN_TYPES_H_
#define INVN_COMMON_INVN_TYPES_H_
/**
* @defgroup invn_types Types
* @brief Motion Library - Type definitions.
* \details Definition of codes and error codes used within the MPL and
* returned to the user.
* Every function tries to return a meaningful error code basing
* on the occuring error condition. The error code is numeric.
*
* The available error codes and their associated values are:
* - (0) INV_SUCCESS
* - (32) INV_ERROR
* - (22 / EINVAL) INV_ERROR_INVALID_PARAMETER
* - (1 / EPERM) INV_ERROR_FEATURE_NOT_ENABLED
* - (36) INV_ERROR_FEATURE_NOT_IMPLEMENTED
* - (64) INV_ERROR_FIFO_READ_COUNT
* \todo Clean up the details documentation in order to use only the \\def one.
* \todo Add documentation to all the definitions
* \ingroup Common
* @file invn_types.h
*/
//=======================================//
//========= Integer Definition =========//
//=======================================//
#ifdef _MSC_VER
# include "inttypes.h"
#else
# include <stdint.h>
#endif
//=======================================//
//======= Fixed Point Conversion =======//
//=======================================//
//! \def INVN_FLT_TO_FXP
//! Convert the \a value from float to QN value. \ingroup invn_macro
#define INVN_FLT_TO_FXP(value, shift) ( (int32_t) ((float)(value)*(1ULL << (shift)) + ( (value>=0)-0.5f )) )
//! \def INVN_DBL_TO_FXP
//! Convert the \a value from double to QN value. \ingroup invn_macro
#define INVN_DBL_TO_FXP(value, shift) ( (int32_t) ((double)(value)*(1ULL << (shift)) + ( (value>=0)-0.5 )) )
//! \def INVN_FLT_TO_UFXP
//! Convert the \a value from float to unsigned QN value. \ingroup invn_macro
#define INVN_FLT_TO_UFXP(value, shift) ( (uint32_t) ((float)(value)*(1ULL << (shift)) + 0.5f) )
//! \def INVN_DBL_TO_UFXP
//! Convert the \a value from double to unsigned QN value. \ingroup invn_macro
#define INVN_DBL_TO_UFXP(value, shift) ( (uint32_t) ((double)(value)*(1ULL << (shift)) + 0.5) )
//! \def INVN_FXP_TO_FLT
//! Convert the \a value from QN value to float. \ingroup invn_macro
#define INVN_FXP_TO_FLT(value, shift) ( (float) (int32_t)(value) / (float)(1ULL << (shift)) )
//! \def INVN_FXP_TO_DBL
//! Convert the \a value from QN value to double. \ingroup invn_macro
#define INVN_FXP_TO_DBL(value, shift) ( (double) (int32_t)(value) / (double)(1ULL << (shift)) )
//! \def INVN_UFXP_TO_FLT
//! Convert the \a value from unsigned QN value to float. \ingroup invn_macro
#define INVN_UFXP_TO_FLT(value, shift) ( (float) (uint32_t)(value) / (float)(1ULL << (shift)) )
//! \def INVN_UFXP_TO_DBL
//! Convert the \a value from unsigned QN value to double. \ingroup invn_macro
#define INVN_UFXP_TO_DBL(value, shift) ( (double) (uint32_t)(value) / (double)(1ULL << (shift)) )
//! \def INVN_CONVERT_FLT_TO_FXP
//! Macro to convert float values from an address into QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FLT_TO_FXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_FLT_TO_FXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_FLT_TO_UFXP
//! Macro to convert float values from an address into unsigned QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FLT_TO_UFXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_FLT_TO_UFXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_DBL_TO_FXP
//! Macro to convert double values from an address into QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_DBL_TO_FXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_DBL_TO_FXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_DBL_TO_UFXP
//! Macro to convert double values from an address into unsigned QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_DBL_TO_UFXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_DBL_TO_UFXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_FXP_TO_FLT
//! Macro to convert QN values from an address into float values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FXP_TO_FLT(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_FXP_TO_FLT((fixptr)[i], shift); }
//! \def INVN_CONVERT_UFXP_TO_FLT
//! Macro to convert unsigned QN values from an address into float values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_UFXP_TO_FLT(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_UFXP_TO_FLT((fixptr)[i], shift); }
//! \def INVN_CONVERT_FXP_TO_DBL
//! Macro to convert QN values from an address into double values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FXP_TO_DBL(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_FXP_TO_DBL((fixptr)[i], shift); }
//! \def INVN_CONVERT_UFXP_TO_DBL
//! \brief Macro to convert unsigned QN values from an address into double values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_UFXP_TO_DBL(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_UFXP_TO_DBL((fixptr)[i], shift); }
//=====================================//
//========= Error Definition =========//
//=====================================//
#ifndef REMOVE_INV_ERROR_T
typedef int32_t inv_error_t; /*!< Type used for error definitions. \ingroup invn_types */
#endif
//typedef int32_t mpu_error_t;
typedef int64_t mpu_time_t; /*!< Type used for mpu time. \ingroup invn_types */
// Typically I2C addresses are 8-bit, but some specifications allow for a 10-bit address
// This definition allows the length to be optimally defined for the platform
typedef uint8_t inv_i2c_addr_t; /*!< Type used for I2C addresses. \ingroup invn_types */
#ifdef __IAR_SYSTEMS_ICC__
// These are defined in standard C errno.h
#define EINVAL (22)
#define EPERM (1)
#define ENOMEM (12)
#else
#include "errno.h"
#endif
#define INVN_SUCCESS (0) /*!< Constant definition for success. \ingroup invn_types */
#define INVN_ERROR_BASE (0x20) /*!< Constant definition for basic error. Value is \b 32 \ingroup invn_types */
#define INVN_ERROR (INVN_ERROR_BASE) /*!< Constant definition for error. Value is \b 32 \ingroup invn_types */
#define INVN_ERROR_FEATURE_NOT_ENABLED (EPERM) /*!< Constant definition for feature not enabled error. \ingroup invn_types */
#define INVN_ERROR_FEATURE_NOT_IMPLEMENTED (INVN_ERROR_BASE + 4) /*!< Constant definition for feature not implemented error. \ingroup invn_types */
#define INVN_ERROR_INVALID_PARAMETER (EINVAL) /*!< Constant definition for invalid parameter error. \ingroup invn_types */
#define INVN_ERROR_FILE_OPEN (INVN_ERROR_BASE + 14) /*!< Constant definition for opening file error. \ingroup invn_types */
#define INVN_ERROR_FILE_READ (INVN_ERROR_BASE + 15) /*!< Constant definition for reading file error. \ingroup invn_types */
#define INVN_ERROR_FILE_WRITE (INVN_ERROR_BASE + 16) /*!< Constant definition for writing file error. \ingroup invn_types */
#define INVN_ERROR_INVALID_CONFIGURATION (INVN_ERROR_BASE + 17) /*!< Constant definition for invalid configuration error. \ingroup invn_types */
/* Serial Communication */
#define INVN_ERROR_SERIAL_OPEN_ERROR (INVN_ERROR_BASE + 21) /*!< Constant definition for serial open error. \ingroup invn_types */
#define INVN_ERROR_SERIAL_READ (INVN_ERROR_BASE + 22) /*!< Constant definition for serial read error. \ingroup invn_types */
#define INVN_ERROR_SERIAL_WRITE (INVN_ERROR_BASE + 23) /*!< Constant definition for serial write error. \ingroup invn_types */
/* Fifo */
#define INVN_ERROR_FIFO_OVERFLOW (INVN_ERROR_BASE + 30) /*!< Constant definition for fifo overflow error. \ingroup invn_types */
#define INVN_ERROR_FIFO_FOOTER (INVN_ERROR_BASE + 31) /*!< Constant definition for fifo footer error. \ingroup invn_types */
#define INVN_ERROR_FIFO_READ_COUNT (INVN_ERROR_BASE + 32) /*!< Constant definition for fifo read count error. \ingroup invn_types */
#define INVN_ERROR_FIFO_READ_DATA (INVN_ERROR_BASE + 33) /*!< Constant definition for fifo read data error. \ingroup invn_types */
/* OS interface errors */
#define INVN_ERROR_OS_BAD_HANDLE (INVN_ERROR_BASE + 61) /*!< Constant definition for OS bad handle error. \ingroup invn_types */
#define INVN_ERROR_OS_CREATE_FAILED (INVN_ERROR_BASE + 62) /*!< Constant definition for OS create failed error. \ingroup invn_types */
#define INVN_ERROR_OS_LOCK_FAILED (INVN_ERROR_BASE + 63) /*!< Constant definition for OS lock failed error. \ingroup invn_types */
/* Warning */
#define INVN_WARNING_SEMAPHORE_TIMEOUT (INVN_ERROR_BASE + 86) /*!< Constant definition for semaphore timeout warning. \ingroup invn_types */
#endif // INVN_COMMON_INVN_TYPES_H_
//-----------------------------------------------------------------------------
/*
Copyright © 2014-2015 InvenSense Inc. Portions Copyright © 2014-2015 Movea. All rights reserved.
This software, related documentation and any modifications thereto (collectively Software) is subject
to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
and other intellectual property rights laws.
InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
and any use, reproduction, disclosure or distribution of the Software without an express license agreement
from InvenSense is strictly prohibited.
*/
//-----------------------------------------------------------------------------
#ifndef INVN_COMMON_INVN_TYPES_H_
#define INVN_COMMON_INVN_TYPES_H_
/**
* @defgroup invn_types Types
* @brief Motion Library - Type definitions.
* \details Definition of codes and error codes used within the MPL and
* returned to the user.
* Every function tries to return a meaningful error code basing
* on the occuring error condition. The error code is numeric.
*
* The available error codes and their associated values are:
* - (0) INV_SUCCESS
* - (32) INV_ERROR
* - (22 / EINVAL) INV_ERROR_INVALID_PARAMETER
* - (1 / EPERM) INV_ERROR_FEATURE_NOT_ENABLED
* - (36) INV_ERROR_FEATURE_NOT_IMPLEMENTED
* - (64) INV_ERROR_FIFO_READ_COUNT
* \todo Clean up the details documentation in order to use only the \\def one.
* \todo Add documentation to all the definitions
* \ingroup Common
* @file invn_types.h
*/
//=======================================//
//========= Integer Definition =========//
//=======================================//
#ifdef _MSC_VER
# include "inttypes.h"
#else
# include <stdint.h>
#endif
//=======================================//
//======= Fixed Point Conversion =======//
//=======================================//
//! \def INVN_FLT_TO_FXP
//! Convert the \a value from float to QN value. \ingroup invn_macro
#define INVN_FLT_TO_FXP(value, shift) ( (int32_t) ((float)(value)*(1ULL << (shift)) + ( (value>=0)-0.5f )) )
//! \def INVN_DBL_TO_FXP
//! Convert the \a value from double to QN value. \ingroup invn_macro
#define INVN_DBL_TO_FXP(value, shift) ( (int32_t) ((double)(value)*(1ULL << (shift)) + ( (value>=0)-0.5 )) )
//! \def INVN_FLT_TO_UFXP
//! Convert the \a value from float to unsigned QN value. \ingroup invn_macro
#define INVN_FLT_TO_UFXP(value, shift) ( (uint32_t) ((float)(value)*(1ULL << (shift)) + 0.5f) )
//! \def INVN_DBL_TO_UFXP
//! Convert the \a value from double to unsigned QN value. \ingroup invn_macro
#define INVN_DBL_TO_UFXP(value, shift) ( (uint32_t) ((double)(value)*(1ULL << (shift)) + 0.5) )
//! \def INVN_FXP_TO_FLT
//! Convert the \a value from QN value to float. \ingroup invn_macro
#define INVN_FXP_TO_FLT(value, shift) ( (float) (int32_t)(value) / (float)(1ULL << (shift)) )
//! \def INVN_FXP_TO_DBL
//! Convert the \a value from QN value to double. \ingroup invn_macro
#define INVN_FXP_TO_DBL(value, shift) ( (double) (int32_t)(value) / (double)(1ULL << (shift)) )
//! \def INVN_UFXP_TO_FLT
//! Convert the \a value from unsigned QN value to float. \ingroup invn_macro
#define INVN_UFXP_TO_FLT(value, shift) ( (float) (uint32_t)(value) / (float)(1ULL << (shift)) )
//! \def INVN_UFXP_TO_DBL
//! Convert the \a value from unsigned QN value to double. \ingroup invn_macro
#define INVN_UFXP_TO_DBL(value, shift) ( (double) (uint32_t)(value) / (double)(1ULL << (shift)) )
//! \def INVN_CONVERT_FLT_TO_FXP
//! Macro to convert float values from an address into QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FLT_TO_FXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_FLT_TO_FXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_FLT_TO_UFXP
//! Macro to convert float values from an address into unsigned QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FLT_TO_UFXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_FLT_TO_UFXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_DBL_TO_FXP
//! Macro to convert double values from an address into QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_DBL_TO_FXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_DBL_TO_FXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_DBL_TO_UFXP
//! Macro to convert double values from an address into unsigned QN values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_DBL_TO_UFXP(fltptr, fixptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fixptr)[i] = INVN_DBL_TO_UFXP((fltptr)[i], shift); }
//! \def INVN_CONVERT_FXP_TO_FLT
//! Macro to convert QN values from an address into float values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FXP_TO_FLT(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_FXP_TO_FLT((fixptr)[i], shift); }
//! \def INVN_CONVERT_UFXP_TO_FLT
//! Macro to convert unsigned QN values from an address into float values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_UFXP_TO_FLT(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_UFXP_TO_FLT((fixptr)[i], shift); }
//! \def INVN_CONVERT_FXP_TO_DBL
//! Macro to convert QN values from an address into double values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_FXP_TO_DBL(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_FXP_TO_DBL((fixptr)[i], shift); }
//! \def INVN_CONVERT_UFXP_TO_DBL
//! \brief Macro to convert unsigned QN values from an address into double values, and copy them to another address. \ingroup invn_macro
#define INVN_CONVERT_UFXP_TO_DBL(fixptr, fltptr, length, shift) { int32_t i; for(i=0; i<(length); ++i) (fltptr)[i] = INVN_UFXP_TO_DBL((fixptr)[i], shift); }
//=====================================//
//========= Error Definition =========//
//=====================================//
#ifndef REMOVE_INV_ERROR_T
typedef int32_t inv_error_t; /*!< Type used for error definitions. \ingroup invn_types */
#endif
//typedef int32_t mpu_error_t;
typedef int64_t mpu_time_t; /*!< Type used for mpu time. \ingroup invn_types */
// Typically I2C addresses are 8-bit, but some specifications allow for a 10-bit address
// This definition allows the length to be optimally defined for the platform
typedef uint8_t inv_i2c_addr_t; /*!< Type used for I2C addresses. \ingroup invn_types */
#ifdef __IAR_SYSTEMS_ICC__
// These are defined in standard C errno.h
#define EINVAL (22)
#define EPERM (1)
#define ENOMEM (12)
#else
#include "errno.h"
#endif
#define INVN_SUCCESS (0) /*!< Constant definition for success. \ingroup invn_types */
#define INVN_ERROR_BASE (0x20) /*!< Constant definition for basic error. Value is \b 32 \ingroup invn_types */
#define INVN_ERROR (INVN_ERROR_BASE) /*!< Constant definition for error. Value is \b 32 \ingroup invn_types */
#define INVN_ERROR_FEATURE_NOT_ENABLED (EPERM) /*!< Constant definition for feature not enabled error. \ingroup invn_types */
#define INVN_ERROR_FEATURE_NOT_IMPLEMENTED (INVN_ERROR_BASE + 4) /*!< Constant definition for feature not implemented error. \ingroup invn_types */
#define INVN_ERROR_INVALID_PARAMETER (EINVAL) /*!< Constant definition for invalid parameter error. \ingroup invn_types */
#define INVN_ERROR_FILE_OPEN (INVN_ERROR_BASE + 14) /*!< Constant definition for opening file error. \ingroup invn_types */
#define INVN_ERROR_FILE_READ (INVN_ERROR_BASE + 15) /*!< Constant definition for reading file error. \ingroup invn_types */
#define INVN_ERROR_FILE_WRITE (INVN_ERROR_BASE + 16) /*!< Constant definition for writing file error. \ingroup invn_types */
#define INVN_ERROR_INVALID_CONFIGURATION (INVN_ERROR_BASE + 17) /*!< Constant definition for invalid configuration error. \ingroup invn_types */
/* Serial Communication */
#define INVN_ERROR_SERIAL_OPEN_ERROR (INVN_ERROR_BASE + 21) /*!< Constant definition for serial open error. \ingroup invn_types */
#define INVN_ERROR_SERIAL_READ (INVN_ERROR_BASE + 22) /*!< Constant definition for serial read error. \ingroup invn_types */
#define INVN_ERROR_SERIAL_WRITE (INVN_ERROR_BASE + 23) /*!< Constant definition for serial write error. \ingroup invn_types */
/* Fifo */
#define INVN_ERROR_FIFO_OVERFLOW (INVN_ERROR_BASE + 30) /*!< Constant definition for fifo overflow error. \ingroup invn_types */
#define INVN_ERROR_FIFO_FOOTER (INVN_ERROR_BASE + 31) /*!< Constant definition for fifo footer error. \ingroup invn_types */
#define INVN_ERROR_FIFO_READ_COUNT (INVN_ERROR_BASE + 32) /*!< Constant definition for fifo read count error. \ingroup invn_types */
#define INVN_ERROR_FIFO_READ_DATA (INVN_ERROR_BASE + 33) /*!< Constant definition for fifo read data error. \ingroup invn_types */
/* OS interface errors */
#define INVN_ERROR_OS_BAD_HANDLE (INVN_ERROR_BASE + 61) /*!< Constant definition for OS bad handle error. \ingroup invn_types */
#define INVN_ERROR_OS_CREATE_FAILED (INVN_ERROR_BASE + 62) /*!< Constant definition for OS create failed error. \ingroup invn_types */
#define INVN_ERROR_OS_LOCK_FAILED (INVN_ERROR_BASE + 63) /*!< Constant definition for OS lock failed error. \ingroup invn_types */
/* Warning */
#define INVN_WARNING_SEMAPHORE_TIMEOUT (INVN_ERROR_BASE + 86) /*!< Constant definition for semaphore timeout warning. \ingroup invn_types */
#endif // INVN_COMMON_INVN_TYPES_H_

View File

@@ -1,156 +1,156 @@
/*
$License:
Copyright (C) 2018 InvenSense Corporation, All Rights Reserved.
$
*/
#ifndef _INVN_ALGO_AGM_H_
#define _INVN_ALGO_AGM_H_
#include "invn_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup AGM AGM
* \brief Algorithm that provides device orientation. Algorithm inputs are raw Accelerometer, Gyroscope and Magnetometer data.
* Algorithm outputs: calibrated sensor and 9-axis sensor fusion.
* \warning supported sampling frequency [50 Hz-1000 Hz]
* \warning supported gyroscope FSR [250 dps, 500 dps, 1000 dps, 2000 dps, 4000 dps]
* \warning supported accelerometer FSR [1 g, 2 g, 4 g, 8 g, 16 g]
*/
#define INVN_ALGO_AGM_INPUT_MASK_ACC 1 ///< Raw Accel update mask
#define INVN_ALGO_AGM_INPUT_MASK_GYR 2 ///< Raw Gyro update mask
#define INVN_ALGO_AGM_INPUT_MASK_MAG 4 ///< Raw Mag update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_ACCEL_CAL 1 ///< Accel cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_GYRO_CAL 2 ///< Gyro cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_MAG_CAL 4 ///< Mag cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_QUAT_AG 8 ///< Game Rotation Vector (Accel and Gyro Fusion) output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_QUAT_AGM 16 ///< Rotation Vector (Accel, Gyro and Magnetometer Fusion) output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_GRAVITY 32 ///< Gravity vector output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_LINEARACC 64 ///< Linear acceleration vector output update mask
/* Forward declarations */
struct inv_icm426xx;
/*! \struct InvnAlgoAGMInput
* AGM input structure (raw data) \ingroup AGM
*/
typedef struct
{
int32_t mask; /*!< mask to specify updated inputs. */
int64_t sRimu_time_us; /*!< timestamp \f$ [\mu s]\f$ of raw accel and gyro */
int32_t sRacc_data[3]; /*!< raw accelerometer in high resolution mode. Expect Full Scale Value coded on 20 bit (i.e. +/- FSR g = 1<<19 LSB) */
int32_t sRgyr_data[3]; /*!< raw gyroscope in high resolution mode. Expect Full Scale Value coded on 20 bit (i.e. +/- FSR dps = 1<<19 LSB) */
int16_t sRtemp_data; /*!< raw temperature */
int64_t sRmag_time_us; /*!< timestamp of raw mag */
int32_t sRmag_data[3]; /*!< raw mag */
} InvnAlgoAGMInput;
/*! \struct InvnAlgoAGMOutput
* AGM output structure (calibrated sensors and fusion output) \ingroup AGM
*/
typedef struct
{
int32_t mask; /*!< mask to specify updated outputs */
int32_t acc_uncal_q16[3]; /*!< uncalibrated accelerometer (1 g = 1<<16) */
int32_t acc_cal_q16[3]; /*!< calibrated accelerometer (1 g = 1<<16) */
int32_t acc_bias_q16[3]; /*!< accelerometer bias (1 g = 1<<16)*/
int8_t acc_accuracy_flag; /*!< accelerometer accuracy from 0(non calibrated) to 3(well calibrated) */
int32_t gyr_uncal_q16[3]; /*!< uncalibrated gyroscope (1 dps = 1<<16) */
int32_t gyr_cal_q16[3]; /*!< calibrated gyroscope (1 dps = 1<<16) */
int32_t gyr_bias_q16[3]; /*!< gyro bias (1 dps = 1<<16)*/
int8_t gyr_accuracy_flag; /*!< gyro accuracy, from 0(non calibrated) to 3(well calibrated) */
int32_t mag_uncal_q16[3]; /*!< uncalibrated magnetometer (1uT = 1<<16) */
int32_t mag_cal_q16[3]; /*!< calibrated magnetometer (1uT = 1<<16) */
int32_t mag_bias_q16[3]; /*!< magnetometer bias (1uT = 1<<16) */
int8_t mag_accuracy_flag; /*!< magnetometer accuracy, from 0(non calibrated) to 3(well calibrated) */
int32_t grv_quat_q30[4]; /*!< 6-axis (accel and gyro fusion) quaternion */
int32_t rv_quat_q30[4]; /*!< 9-axis (accel, gyro and magnetometer fusion) quaternion */
int32_t rv_accuracy_q27; /*!< 9-axis (accel, gyro and magnetometer fusion) 3\sigma accuracy in rad */
int32_t gravity_q16[3]; /*!< gravity estimation in sensor frame */
int32_t linear_acc_q16[3]; /*!< linear acceleration estimation in sensor frame */
int32_t temp_degC_q16; /*!< temperature (1 \f$ [^{\circ}C]\f$ = 1<<16)*/
} InvnAlgoAGMOutput;
/*! \struct InvnAlgoAGMConfig
* AGM configuration structure (sensor related settings) \ingroup AGM
*/
typedef struct
{
int32_t * acc_bias_q16; /*!< Previously stored accel bias pointer. If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int32_t * gyr_bias_q16; /*!< Previously stored gyro bias pointer. If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int32_t * mag_bias_q16; /*!< mag_bias_q16 Previously stored mag bias pointer If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int8_t acc_accuracy; /*!< Previously stored accelerometer bias accuracy (0 to 3) */
int8_t gyr_accuracy; /*!< Previously stored gyroscope bias accuracy (0 to 3) */
int8_t mag_accuracy; /*!< Previously stored magnetometer bias accuracy (0 to 3) */
int32_t acc_fsr; /*!< accelerometer full scale range [g] */
int32_t gyr_fsr; /*!< gyroscope full scale range [dps] */
uint32_t acc_odr_us; /*!< accelerometer output data rate in \f$ [\mu s]\f$ */
uint32_t gyr_odr_us; /*!< gyroscope output data rate \f$ [\mu s]\f$ */
int32_t mag_sc_q16; /*!< magnetometer sensitivity (uT/LSB, e.g. mag_uT = (mag_sc_q16 * raw_mag_LSB)/65536) */
uint32_t mag_odr_us; /*!< magnetometer output data rate \f$ [\mu s]\f$ */
int32_t temp_sensitivity; /*!< temperature sensitivity in q30 (if temperature(\f$ ^{\circ}C \f$) = LSB * k + z, then temp_sensitivity = k) */
int32_t temp_offset; /*!< temperature offset in q16 (if temperature(\f$ ^{\circ}C \f$) = LSB * k + z, then temp_offset = z) */
} InvnAlgoAGMConfig;
/*!
* \brief Return library version x.y.z-suffix as a char array
* \retval library version a char array "x.y.z-suffix"
* \ingroup AGM
*/
const char * invn_algo_agm_version(void);
/*!
* \brief Initializes algorithms with default parameters and reset states.
* (\icm_device[in] Invensense ICM426XX device pointer. Only when gyro assisted is enabled.)
* \config[in] algo init parameters structure.
* \return initialization success indicator.
* \retval 0 Success
* \retval 1 Fail
* \ingroup AGM
*/
#ifdef WITH_GYRO_ASSIST
uint8_t invn_algo_agm_init_a(struct inv_icm426xx * icm_device, const InvnAlgoAGMConfig * config);
#else
uint8_t invn_algo_agm_init(const InvnAlgoAGMConfig * config);
#endif
/*!
* \brief Sets algo config structure.
* \config[in] config structure of the algo.
* \ingroup AGM
*/
void invn_algo_agm_set_config(const InvnAlgoAGMConfig * config);
/*!
* \brief Performs algorithm computation.
* \in inputs algorithm input. Input mask (inputs->mask) should be set with respect to new sensor data in InvnAlgoAGMInput.
* \out outputs algorithm output. Output mask (outputs->mask) reports updated outputs in InvnAlgoAGMOutput.
* \ingroup AGM
*/
void invn_algo_agm_process(const InvnAlgoAGMInput *inputs, InvnAlgoAGMOutput *outputs);
#ifdef __cplusplus
}
#endif
#endif
/*
$License:
Copyright (C) 2018 InvenSense Corporation, All Rights Reserved.
$
*/
#ifndef _INVN_ALGO_AGM_H_
#define _INVN_ALGO_AGM_H_
#include "invn_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup AGM AGM
* \brief Algorithm that provides device orientation. Algorithm inputs are raw Accelerometer, Gyroscope and Magnetometer data.
* Algorithm outputs: calibrated sensor and 9-axis sensor fusion.
* \warning supported sampling frequency [50 Hz-1000 Hz]
* \warning supported gyroscope FSR [250 dps, 500 dps, 1000 dps, 2000 dps, 4000 dps]
* \warning supported accelerometer FSR [1 g, 2 g, 4 g, 8 g, 16 g]
*/
#define INVN_ALGO_AGM_INPUT_MASK_ACC 1 ///< Raw Accel update mask
#define INVN_ALGO_AGM_INPUT_MASK_GYR 2 ///< Raw Gyro update mask
#define INVN_ALGO_AGM_INPUT_MASK_MAG 4 ///< Raw Mag update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_ACCEL_CAL 1 ///< Accel cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_GYRO_CAL 2 ///< Gyro cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_MAG_CAL 4 ///< Mag cal output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_QUAT_AG 8 ///< Game Rotation Vector (Accel and Gyro Fusion) output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_QUAT_AGM 16 ///< Rotation Vector (Accel, Gyro and Magnetometer Fusion) output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_GRAVITY 32 ///< Gravity vector output update mask
#define INVN_ALGO_AGM_OUTPUT_MASK_LINEARACC 64 ///< Linear acceleration vector output update mask
/* Forward declarations */
struct inv_icm426xx;
/*! \struct InvnAlgoAGMInput
* AGM input structure (raw data) \ingroup AGM
*/
typedef struct
{
int32_t mask; /*!< mask to specify updated inputs. */
int64_t sRimu_time_us; /*!< timestamp \f$ [\mu s]\f$ of raw accel and gyro */
int32_t sRacc_data[3]; /*!< raw accelerometer in high resolution mode. Expect Full Scale Value coded on 20 bit (i.e. +/- FSR g = 1<<19 LSB) */
int32_t sRgyr_data[3]; /*!< raw gyroscope in high resolution mode. Expect Full Scale Value coded on 20 bit (i.e. +/- FSR dps = 1<<19 LSB) */
int16_t sRtemp_data; /*!< raw temperature */
int64_t sRmag_time_us; /*!< timestamp of raw mag */
int32_t sRmag_data[3]; /*!< raw mag */
} InvnAlgoAGMInput;
/*! \struct InvnAlgoAGMOutput
* AGM output structure (calibrated sensors and fusion output) \ingroup AGM
*/
typedef struct
{
int32_t mask; /*!< mask to specify updated outputs */
int32_t acc_uncal_q16[3]; /*!< uncalibrated accelerometer (1 g = 1<<16) */
int32_t acc_cal_q16[3]; /*!< calibrated accelerometer (1 g = 1<<16) */
int32_t acc_bias_q16[3]; /*!< accelerometer bias (1 g = 1<<16)*/
int8_t acc_accuracy_flag; /*!< accelerometer accuracy from 0(non calibrated) to 3(well calibrated) */
int32_t gyr_uncal_q16[3]; /*!< uncalibrated gyroscope (1 dps = 1<<16) */
int32_t gyr_cal_q16[3]; /*!< calibrated gyroscope (1 dps = 1<<16) */
int32_t gyr_bias_q16[3]; /*!< gyro bias (1 dps = 1<<16)*/
int8_t gyr_accuracy_flag; /*!< gyro accuracy, from 0(non calibrated) to 3(well calibrated) */
int32_t mag_uncal_q16[3]; /*!< uncalibrated magnetometer (1uT = 1<<16) */
int32_t mag_cal_q16[3]; /*!< calibrated magnetometer (1uT = 1<<16) */
int32_t mag_bias_q16[3]; /*!< magnetometer bias (1uT = 1<<16) */
int8_t mag_accuracy_flag; /*!< magnetometer accuracy, from 0(non calibrated) to 3(well calibrated) */
int32_t grv_quat_q30[4]; /*!< 6-axis (accel and gyro fusion) quaternion */
int32_t rv_quat_q30[4]; /*!< 9-axis (accel, gyro and magnetometer fusion) quaternion */
int32_t rv_accuracy_q27; /*!< 9-axis (accel, gyro and magnetometer fusion) 3\sigma accuracy in rad */
int32_t gravity_q16[3]; /*!< gravity estimation in sensor frame */
int32_t linear_acc_q16[3]; /*!< linear acceleration estimation in sensor frame */
int32_t temp_degC_q16; /*!< temperature (1 \f$ [^{\circ}C]\f$ = 1<<16)*/
} InvnAlgoAGMOutput;
/*! \struct InvnAlgoAGMConfig
* AGM configuration structure (sensor related settings) \ingroup AGM
*/
typedef struct
{
int32_t * acc_bias_q16; /*!< Previously stored accel bias pointer. If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int32_t * gyr_bias_q16; /*!< Previously stored gyro bias pointer. If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int32_t * mag_bias_q16; /*!< mag_bias_q16 Previously stored mag bias pointer If pointer is NULL or 0, offset will be set to { 0, 0, 0} */
int8_t acc_accuracy; /*!< Previously stored accelerometer bias accuracy (0 to 3) */
int8_t gyr_accuracy; /*!< Previously stored gyroscope bias accuracy (0 to 3) */
int8_t mag_accuracy; /*!< Previously stored magnetometer bias accuracy (0 to 3) */
int32_t acc_fsr; /*!< accelerometer full scale range [g] */
int32_t gyr_fsr; /*!< gyroscope full scale range [dps] */
uint32_t acc_odr_us; /*!< accelerometer output data rate in \f$ [\mu s]\f$ */
uint32_t gyr_odr_us; /*!< gyroscope output data rate \f$ [\mu s]\f$ */
int32_t mag_sc_q16; /*!< magnetometer sensitivity (uT/LSB, e.g. mag_uT = (mag_sc_q16 * raw_mag_LSB)/65536) */
uint32_t mag_odr_us; /*!< magnetometer output data rate \f$ [\mu s]\f$ */
int32_t temp_sensitivity; /*!< temperature sensitivity in q30 (if temperature(\f$ ^{\circ}C \f$) = LSB * k + z, then temp_sensitivity = k) */
int32_t temp_offset; /*!< temperature offset in q16 (if temperature(\f$ ^{\circ}C \f$) = LSB * k + z, then temp_offset = z) */
} InvnAlgoAGMConfig;
/*!
* \brief Return library version x.y.z-suffix as a char array
* \retval library version a char array "x.y.z-suffix"
* \ingroup AGM
*/
const char * invn_algo_agm_version(void);
/*!
* \brief Initializes algorithms with default parameters and reset states.
* (\icm_device[in] Invensense ICM426XX device pointer. Only when gyro assisted is enabled.)
* \config[in] algo init parameters structure.
* \return initialization success indicator.
* \retval 0 Success
* \retval 1 Fail
* \ingroup AGM
*/
#ifdef WITH_GYRO_ASSIST
uint8_t invn_algo_agm_init_a(struct inv_icm426xx * icm_device, const InvnAlgoAGMConfig * config);
#else
uint8_t invn_algo_agm_init(const InvnAlgoAGMConfig * config);
#endif
/*!
* \brief Sets algo config structure.
* \config[in] config structure of the algo.
* \ingroup AGM
*/
void invn_algo_agm_set_config(const InvnAlgoAGMConfig * config);
/*!
* \brief Performs algorithm computation.
* \in inputs algorithm input. Input mask (inputs->mask) should be set with respect to new sensor data in InvnAlgoAGMInput.
* \out outputs algorithm output. Output mask (outputs->mask) reports updated outputs in InvnAlgoAGMOutput.
* \ingroup AGM
*/
void invn_algo_agm_process(const InvnAlgoAGMInput *inputs, InvnAlgoAGMOutput *outputs);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,101 +1,101 @@
/*******************************************************************************
* @file app_raw.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P IMU
*
* IMU , ,
* .
*
* :
* SERIF_TYPE - (UI_I2C)
* USE_LOW_NOISE_MODE - 1:(800Hz), 0:(100Hz)
* USE_HIGH_RES_MODE - 1:20 , 0:16
* USE_FIFO - 1:FIFO , 0:
******************************************************************************/
#ifndef _APP_RAW_H_
#define _APP_RAW_H_
#include "sdk_config.h"
#include <stdint.h>
#include "inv_imu_transport.h"
#include "inv_imu_defs.h"
#include "inv_imu_driver.h"
/*** 설정 매크로 ***/
/*
* MCU와 IMU
* UI_I2C: I2C ()
*/
#define SERIF_TYPE UI_I2C
/*
*
* 1: 800Hz ODR, ,
* 0: 100Hz ODR,
* : 12.5Hz ODR에서는
*/
#define USE_LOW_NOISE_MODE 1
/*
* FIFO
* 0: 16 ()
* 1: 20 (FSR이 16g/2000dps로 )
*/
#define USE_HIGH_RES_MODE 0
/*
*
* 0: ( )
* 1: FIFO에서
*/
#define USE_FIFO 0
/**
* \brief IMU . WHOAMI .
* IMU .
*
* \return 0=, =
*/
int setup_imu_device(struct inv_imu_serif *icm_serif);
/**
* \brief .
* FSR, ODR, , FIFO .
* \return 0=, =
*/
int configure_imu_device(void);
/**
* \brief FIFO IMU .
* imu_callback() .
* \return 0=, =
*/
int get_imu_data(void);
/**
* \brief .
* info4/BLE/UART .
* \param[in] event
*/
void imu_callback(inv_imu_sensor_event_t *event);
/**
* \brief API를 I2C .
* DRDY BLE로 .
* IMU를 .
* \return 0=, =
*/
int imu_read_direct(void);
#endif /* !_APP_RAW_H_ */
/*******************************************************************************
* @file app_raw.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P IMU
*
* IMU , ,
* .
*
* :
* SERIF_TYPE - (UI_I2C)
* USE_LOW_NOISE_MODE - 1:(800Hz), 0:(100Hz)
* USE_HIGH_RES_MODE - 1:20 , 0:16
* USE_FIFO - 1:FIFO , 0:
******************************************************************************/
#ifndef _APP_RAW_H_
#define _APP_RAW_H_
#include "sdk_config.h"
#include <stdint.h>
#include "inv_imu_transport.h"
#include "inv_imu_defs.h"
#include "inv_imu_driver.h"
/*** 설정 매크로 ***/
/*
* MCU와 IMU
* UI_I2C: I2C ()
*/
#define SERIF_TYPE UI_I2C
/*
*
* 1: 800Hz ODR, ,
* 0: 100Hz ODR,
* : 12.5Hz ODR에서는
*/
#define USE_LOW_NOISE_MODE 1
/*
* FIFO
* 0: 16 ()
* 1: 20 (FSR이 16g/2000dps로 )
*/
#define USE_HIGH_RES_MODE 0
/*
*
* 0: ( )
* 1: FIFO에서
*/
#define USE_FIFO 0
/**
* \brief IMU . WHOAMI .
* IMU .
*
* \return 0=, =
*/
int setup_imu_device(struct inv_imu_serif *icm_serif);
/**
* \brief .
* FSR, ODR, , FIFO .
* \return 0=, =
*/
int configure_imu_device(void);
/**
* \brief FIFO IMU .
* imu_callback() .
* \return 0=, =
*/
int get_imu_data(void);
/**
* \brief .
* info4/BLE/UART .
* \param[in] event
*/
void imu_callback(inv_imu_sensor_event_t *event);
/**
* \brief API를 I2C .
* DRDY BLE로 .
* IMU를 .
* \return 0=, =
*/
int imu_read_direct(void);
#endif /* !_APP_RAW_H_ */

View File

@@ -1,290 +1,290 @@
/*******************************************************************************
* @file app_raw_main.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* 2026.03.26 jhChun
*
* app_raw.c imu_read_direct()
*
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P
*
* ICM42670P IMU 퀀 .
*
* (icm42670_init):
* 1) setup_mcu() - I2C TWI
* 2) setup_imu_device() - IMU + WHOAMI
* 3) configure_imu_device() - (FSR, ODR, )
* 4) inv_gpio_sensor_irq_init() - INT1(P1.13) GPIO
*
* (icm42670_main):
* - INT1 irq_from_device
* - ,
* - (HITOLO) (INT1 )
*
* :
* - inv_imu_sleep_us() - nrf_delay_us (IMU )
* - inv_imu_get_time_us() - RTC1
******************************************************************************/
#include "sdk_config.h"
#include "app_raw.h"
#include "app_raw_main.h"
#include "RingBuffer.h"
#include "inv_imu_driver.h"
#include "system_interface.h"
/* std */
#include <stdio.h>
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */
#include "i2c_manager.h"
/* --------------------------------------------------------------------------------------
* Global variables
* -------------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------------
* Static variables
* -------------------------------------------------------------------------------------- */
/*
* IMU
* INT1 1 .
* 0 .
* volatile: ISR에서
*/
static volatile int irq_from_device;
/* --------------------------------------------------------------------------------------
* Forward declaration
* -------------------------------------------------------------------------------------- */
static int setup_mcu(struct inv_imu_serif *icm_serif);
/*!
* @brief Sensor general interrupt handler, calls specific handlers.
*
* This function is called when an external interrupt is triggered by the sensor,
* checks interrupt registers of InvenSense Sensor to determine the source and type of interrupt
* and calls the specific interrupt handler accordingly.
*
* @param[in] NULL
*
* @param[out] NULL
*
* @return NULL
*
*/
/*
* inv_gpio_sensor_interrupt_handler()
* INT1 (ISR).
* , .
* (icm42670_main) .
*/
static void inv_gpio_sensor_interrupt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
irq_from_device = 1;
}
/*
* inv_gpio_sensor_irq_init()
* INT1(P1.13) GPIO .
*
* :
* - : (HITOLO) INT를 Low로
* - :
* - : inv_gpio_sensor_interrupt_handler
* - GPIOTE
*/
void inv_gpio_sensor_irq_init(void)
{
ret_code_t err_code;
/* GPIOTE 모듈 초기화 (이미 초기화되어 있으면 건너뜀) */
if (!nrfx_gpiote_is_init())
{
err_code = nrfx_gpiote_init();
APP_ERROR_CHECK(err_code);
}
/* 하강 에지 인터럽트 설정: High→Low 전환 시 트리거, 내부 풀업 사용 */
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
in_config.pull = NRF_GPIO_PIN_PULLUP;
/* INT1 핀에 인터럽트 핸들러 등록 */
err_code = nrfx_gpiote_in_init(ICM42670_INT1_PIN, &in_config, inv_gpio_sensor_interrupt_handler);
APP_ERROR_CHECK(err_code);
/* 인터럽트 이벤트 활성화 */
nrfx_gpiote_in_event_enable(ICM42670_INT1_PIN, true);
}
/*
* inv_gpio_sensor_irq_uninit()
* INT1 GPIO .
* .
*/
void inv_gpio_sensor_irq_uninit(void)
{
/* 인터럽트 이벤트 비활성화 */
nrfx_gpiote_in_event_disable(ICM42670_INT1_PIN);
/* INT1 핀 인터럽트 설정 해제 */
nrfx_gpiote_in_uninit(ICM42670_INT1_PIN);
/* GPIOTE 모듈 해제 (초기화된 경우에만) */
if (nrfx_gpiote_is_init())
{
nrfx_gpiote_uninit();
}
}
/* --------------------------------------------------------------------------------------
* Main
* -------------------------------------------------------------------------------------- */
/*
* icm42670_init()
* ICM42670P 퀀 .
*
* :
* 1) setup_mcu() - I2C TWI
* 2) setup_imu_device() - IMU , WHOAMI(0x67)
* 3) configure_imu_device() - FSR, ODR,
* 4) inv_gpio_sensor_irq_init() - INT1 ( )
*
* : 0=, -1=
*/
int icm42670_init(void)
{
int rc = 0;
struct inv_imu_serif icm_serif;
rc |= setup_mcu(&icm_serif);
rc |= setup_imu_device(&icm_serif);
rc |= configure_imu_device();
if(rc != 0){
printf("!!!error during initialization\r\n");
return -1;
}
/* 초기화 성공 후 INT1 인터럽트 활성화 — 이후 데이터 준비 시 ISR이 호출됨 */
inv_gpio_sensor_irq_init();
return rc;
}
/*
* icm42670_main()
* ICM42670P .
* .
*
* :
* 1) I2C (hw_i2c_init_once)
* 2) irq_from_device (ISR에서 )
* 3) (get_imu_data)
* 4)
*
* : , ISR에서는 I2C .
*/
void icm42670_main(void)
{
int rc = 0;
hw_i2c_init_once();
/* 인터럽트 발생 여부 확인 후 데이터 읽기 */
if (irq_from_device) {
rc = get_imu_data();
if(rc < 0) {
printf("error while getting data\r\n");
}
/* 플래그 클리어 — 다음 인터럽트까지 대기 */
irq_from_device = 0;
}
}
/* --------------------------------------------------------------------------------------
* Functions definitions
* -------------------------------------------------------------------------------------- */
/*
* setup_mcu()
* MCU .
*
* inv_imu_serif :
* - read_reg / write_reg : I2C / (system_interface.c에서 )
* - max_read / max_write : (32KB)
* - serif_type : (UI_I2C)
*
* inv_io_hal_init() TWI .
*/
static int setup_mcu(struct inv_imu_serif *icm_serif)
{
int rc = 0;
/* IMU 드라이버용 시리얼 인터페이스 구조체 설정 */
icm_serif->context = 0; /* 컨텍스트 미사용 */
icm_serif->read_reg = inv_io_hal_read_reg; /* 레지스터 읽기 콜백 */
icm_serif->write_reg = inv_io_hal_write_reg; /* 레지스터 쓰기 콜백 */
icm_serif->max_read = 1024*32; /* 1회 읽기 최대 바이트 수 */
icm_serif->max_write = 1024*32; /* 1회 쓰기 최대 바이트 수 */
icm_serif->serif_type = SERIF_TYPE; /* UI_I2C (app_raw.h에서 정의) */
/* TWI 하드웨어 초기화 */
rc |= inv_io_hal_init(icm_serif);
return rc;
}
/* --------------------------------------------------------------------------------------
* Extern functions definition
* -------------------------------------------------------------------------------------- */
/*
* inv_imu_sleep_us()
* IMU .
* nrf_delay_us() .
* : (GYR_STARTUP_TIME_US)
*/
void inv_imu_sleep_us(uint32_t us)
{
nrf_delay_us(us);
}
/*
* inv_imu_get_time_us()
* IMU .
* nRF52840의 RTC1 .
*
* : RTC1은 32.768kHz로 ,
* RTC ( 30.5us/tick).
* .
*/
uint64_t inv_imu_get_time_us(void)
{
return NRF_RTC1->COUNTER;
}
/*******************************************************************************
* @file app_raw_main.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* 2026.03.26 jhChun
*
* app_raw.c imu_read_direct()
*
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P
*
* ICM42670P IMU 퀀 .
*
* (icm42670_init):
* 1) setup_mcu() - I2C TWI
* 2) setup_imu_device() - IMU + WHOAMI
* 3) configure_imu_device() - (FSR, ODR, )
* 4) inv_gpio_sensor_irq_init() - INT1(P1.13) GPIO
*
* (icm42670_main):
* - INT1 irq_from_device
* - ,
* - (HITOLO) (INT1 )
*
* :
* - inv_imu_sleep_us() - nrf_delay_us (IMU )
* - inv_imu_get_time_us() - RTC1
******************************************************************************/
#include "sdk_config.h"
#include "app_raw.h"
#include "app_raw_main.h"
#include "RingBuffer.h"
#include "inv_imu_driver.h"
#include "system_interface.h"
/* std */
#include <stdio.h>
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */
#include "i2c_manager.h"
/* --------------------------------------------------------------------------------------
* Global variables
* -------------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------------
* Static variables
* -------------------------------------------------------------------------------------- */
/*
* IMU
* INT1 1 .
* 0 .
* volatile: ISR에서
*/
static volatile int irq_from_device;
/* --------------------------------------------------------------------------------------
* Forward declaration
* -------------------------------------------------------------------------------------- */
static int setup_mcu(struct inv_imu_serif *icm_serif);
/*!
* @brief Sensor general interrupt handler, calls specific handlers.
*
* This function is called when an external interrupt is triggered by the sensor,
* checks interrupt registers of InvenSense Sensor to determine the source and type of interrupt
* and calls the specific interrupt handler accordingly.
*
* @param[in] NULL
*
* @param[out] NULL
*
* @return NULL
*
*/
/*
* inv_gpio_sensor_interrupt_handler()
* INT1 (ISR).
* , .
* (icm42670_main) .
*/
static void inv_gpio_sensor_interrupt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
irq_from_device = 1;
}
/*
* inv_gpio_sensor_irq_init()
* INT1(P1.13) GPIO .
*
* :
* - : (HITOLO) INT를 Low로
* - :
* - : inv_gpio_sensor_interrupt_handler
* - GPIOTE
*/
void inv_gpio_sensor_irq_init(void)
{
ret_code_t err_code;
/* GPIOTE 모듈 초기화 (이미 초기화되어 있으면 건너뜀) */
if (!nrfx_gpiote_is_init())
{
err_code = nrfx_gpiote_init();
APP_ERROR_CHECK(err_code);
}
/* 하강 에지 인터럽트 설정: High→Low 전환 시 트리거, 내부 풀업 사용 */
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
in_config.pull = NRF_GPIO_PIN_PULLUP;
/* INT1 핀에 인터럽트 핸들러 등록 */
err_code = nrfx_gpiote_in_init(ICM42670_INT1_PIN, &in_config, inv_gpio_sensor_interrupt_handler);
APP_ERROR_CHECK(err_code);
/* 인터럽트 이벤트 활성화 */
nrfx_gpiote_in_event_enable(ICM42670_INT1_PIN, true);
}
/*
* inv_gpio_sensor_irq_uninit()
* INT1 GPIO .
* .
*/
void inv_gpio_sensor_irq_uninit(void)
{
/* 인터럽트 이벤트 비활성화 */
nrfx_gpiote_in_event_disable(ICM42670_INT1_PIN);
/* INT1 핀 인터럽트 설정 해제 */
nrfx_gpiote_in_uninit(ICM42670_INT1_PIN);
/* GPIOTE 모듈 해제 (초기화된 경우에만) */
if (nrfx_gpiote_is_init())
{
nrfx_gpiote_uninit();
}
}
/* --------------------------------------------------------------------------------------
* Main
* -------------------------------------------------------------------------------------- */
/*
* icm42670_init()
* ICM42670P 퀀 .
*
* :
* 1) setup_mcu() - I2C TWI
* 2) setup_imu_device() - IMU , WHOAMI(0x67)
* 3) configure_imu_device() - FSR, ODR,
* 4) inv_gpio_sensor_irq_init() - INT1 ( )
*
* : 0=, -1=
*/
int icm42670_init(void)
{
int rc = 0;
struct inv_imu_serif icm_serif;
rc |= setup_mcu(&icm_serif);
rc |= setup_imu_device(&icm_serif);
rc |= configure_imu_device();
if(rc != 0){
printf("!!!error during initialization\r\n");
return -1;
}
/* 초기화 성공 후 INT1 인터럽트 활성화 — 이후 데이터 준비 시 ISR이 호출됨 */
inv_gpio_sensor_irq_init();
return rc;
}
/*
* icm42670_main()
* ICM42670P .
* .
*
* :
* 1) I2C (hw_i2c_init_once)
* 2) irq_from_device (ISR에서 )
* 3) (get_imu_data)
* 4)
*
* : , ISR에서는 I2C .
*/
void icm42670_main(void)
{
int rc = 0;
hw_i2c_init_once();
/* 인터럽트 발생 여부 확인 후 데이터 읽기 */
if (irq_from_device) {
rc = get_imu_data();
if(rc < 0) {
printf("error while getting data\r\n");
}
/* 플래그 클리어 — 다음 인터럽트까지 대기 */
irq_from_device = 0;
}
}
/* --------------------------------------------------------------------------------------
* Functions definitions
* -------------------------------------------------------------------------------------- */
/*
* setup_mcu()
* MCU .
*
* inv_imu_serif :
* - read_reg / write_reg : I2C / (system_interface.c에서 )
* - max_read / max_write : (32KB)
* - serif_type : (UI_I2C)
*
* inv_io_hal_init() TWI .
*/
static int setup_mcu(struct inv_imu_serif *icm_serif)
{
int rc = 0;
/* IMU 드라이버용 시리얼 인터페이스 구조체 설정 */
icm_serif->context = 0; /* 컨텍스트 미사용 */
icm_serif->read_reg = inv_io_hal_read_reg; /* 레지스터 읽기 콜백 */
icm_serif->write_reg = inv_io_hal_write_reg; /* 레지스터 쓰기 콜백 */
icm_serif->max_read = 1024*32; /* 1회 읽기 최대 바이트 수 */
icm_serif->max_write = 1024*32; /* 1회 쓰기 최대 바이트 수 */
icm_serif->serif_type = SERIF_TYPE; /* UI_I2C (app_raw.h에서 정의) */
/* TWI 하드웨어 초기화 */
rc |= inv_io_hal_init(icm_serif);
return rc;
}
/* --------------------------------------------------------------------------------------
* Extern functions definition
* -------------------------------------------------------------------------------------- */
/*
* inv_imu_sleep_us()
* IMU .
* nrf_delay_us() .
* : (GYR_STARTUP_TIME_US)
*/
void inv_imu_sleep_us(uint32_t us)
{
nrf_delay_us(us);
}
/*
* inv_imu_get_time_us()
* IMU .
* nRF52840의 RTC1 .
*
* : RTC1은 32.768kHz로 ,
* RTC ( 30.5us/tick).
* .
*/
uint64_t inv_imu_get_time_us(void)
{
return NRF_RTC1->COUNTER;
}

View File

@@ -1,31 +1,31 @@
/*******************************************************************************
* @file app_raw_main.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P /
*
* ICM42670P IMU .
* - icm42670_init() : (MCU설정 IMU초기화 )
* - icm42670_main() : (INT1 )
* - icm42670_uninit() : ( , )
******************************************************************************/
#ifndef _APP_RAW_MAIN_H_
#define _APP_RAW_MAIN_H_
#include "sdk_config.h"
/* ICM42670P 전체 초기화 — MCU I2C 설정 → IMU 드라이버 초기화 → 센서 설정 → 인터럽트 활성화 */
int icm42670_init(void);
/* ICM42670P 메인 폴링 루프 — INT1 인터럽트 플래그 확인 후 센서 데이터 읽기 */
void icm42670_main(void);
/* ICM42670P 해제 (프로토타입 선언) */
int icm42670_uninit(void);
#endif /* !_APP_RAW_MAIN_H_ */
/*******************************************************************************
* @file app_raw_main.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P /
*
* ICM42670P IMU .
* - icm42670_init() : (MCU설정 IMU초기화 )
* - icm42670_main() : (INT1 )
* - icm42670_uninit() : ( , )
******************************************************************************/
#ifndef _APP_RAW_MAIN_H_
#define _APP_RAW_MAIN_H_
#include "sdk_config.h"
/* ICM42670P 전체 초기화 — MCU I2C 설정 → IMU 드라이버 초기화 → 센서 설정 → 인터럽트 활성화 */
int icm42670_init(void);
/* ICM42670P 메인 폴링 루프 — INT1 인터럽트 플래그 확인 후 센서 데이터 읽기 */
void icm42670_main(void);
/* ICM42670P 해제 (프로토타입 선언) */
int icm42670_uninit(void);
#endif /* !_APP_RAW_MAIN_H_ */

View File

@@ -1,334 +1,334 @@
/*******************************************************************************
* @file system_interface.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P IMU I2C
*
* nRF52840의 TWI(I2C) ICM42670P IMU
* .
*
* - I2C : 0x68 (ICM42670P )
* - I2C : SCL=P1.14, SDA=P1.15 (system_interface.h에서 )
* - TWI : NRFX_TWI_INSTANCE(0)
* - : 100kHz (NRF_TWI_FREQ_100K)
*
* :
* inv_io_hal_init() I2C SPI ( I2C만 )
* inv_io_hal_read_reg() (TX로 RX로 )
* inv_io_hal_write_reg() (+ TX)
*
* : I2C / 1
*
* : SPI4 ,
* I2C(UI_I2C) .
******************************************************************************/
/* board driver */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"
#include "nrfx_twi.h"
#include "system_interface.h"
#include "nrf_delay.h"
/* ICM42670P I2C 슬레이브 주소 및 직렬 쓰기 최대 바이트 수 */
#define ICM_I2C_ADDR 0x68
#define INV_MAX_SERIAL_WRITE 16
/* TWI(I2C) 인스턴스 생성 — system_interface.h의 ICM42670_I2C_INSTANCE(0)을 사용 */
const nrfx_twi_t m_twi_icm42670 = NRFX_TWI_INSTANCE(ICM42670_I2C_INSTANCE);
/*
* inv_i2c_master_uninitialize()
* I2C TWI .
* .
*/
void inv_i2c_master_uninitialize(void){
nrfx_twi_disable(&m_twi_icm42670);
nrfx_twi_uninit(&m_twi_icm42670);
}
/*
* inv_i2c_master_initialize()
* nRF52840 TWI .
* - SCL: P1.14, SDA: P1.15
* - : 100kHz
* - : (APP_IRQ_PRIORITY_HIGH)
* - ( )
*/
void inv_i2c_master_initialize(void){
ret_code_t err_code;
const nrfx_twi_config_t twi_icm42670_config = {
.scl = ICM42670_I2C_SCL_PIN,
.sda = ICM42670_I2C_SDA_PIN,
.frequency = NRF_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
};
/* TWI 드라이버 초기화 (이벤트 핸들러=NULL → 블로킹 모드) */
err_code = nrfx_twi_init(&m_twi_icm42670, &twi_icm42670_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
/* TWI 하드웨어 활성화 — 이후 tx/rx 가능 */
nrfx_twi_enable(&m_twi_icm42670);
}
/*
* icm42670_twi_tx()
* I2C . nrfx_twi_tx를 .
* no_stop=true이면 STOP (Repeated START를 )
*/
uint32_t icm42670_twi_tx( uint8_t device_id,
uint8_t const * p_data,
uint8_t length,
bool no_stop)
{
ret_code_t ret;
ret = nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
return ret;
}
/*
* icm42670_twi_rx()
* I2C . nrfx_twi_rx를 .
*/
uint32_t icm42670_twi_rx( uint8_t device_id,
uint8_t * p_data,
uint8_t length)
{
ret_code_t ret;
ret = nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
return ret;
}
/*
* inv_i2c_master_read_register()
* ICM42670P의 .
*
* :
* 1) TX: 1 (no_stop=true Repeated START )
* 2) RX:
*
* : TX, RX 1 .
*/
static unsigned long inv_i2c_master_read_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, unsigned char *RegisterValue){
//ret_code_t ret;
uint32_t ret;
uint8_t addr8 = (uint8_t)RegisterAddr;
/* 1단계: 읽을 레지스터 주소를 전송 (STOP 없이 → Repeated START 사용) */
ret = icm42670_twi_tx(Address, &addr8, 1, true);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_tx(Address, &addr8, 1, true);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c read-1\r\n");
}
}
/* 2단계: 해당 레지스터에서 데이터 수신 */
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c read-2\r\n");
}
}
return ret;
}
/*
* inv_i2c_master_write_register()
* ICM42670P의 .
*
* :
* 1) [0] , [1~N]
* 2) TX: + (no_stop=false STOP )
*
* : 1 .
*/
static unsigned long inv_i2c_master_write_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, const unsigned char *RegisterValue){
uint32_t ret;
uint8_t buffer[1 + INV_MAX_SERIAL_WRITE]; /* 레지스터 주소(1) + 데이터(최대 16바이트) */
/* 버퍼 구성: [레지스터 주소][데이터 바이트들] */
buffer[0] = (uint8_t)RegisterAddr;
memcpy(buffer+1, RegisterValue, RegisterLen);
/* 주소+데이터를 한번에 전송 */
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c write\r\n");
}
}
return ret;
}
/*
* inv_io_hal_init()
* IMU (I2C SPI) .
* serif->serif_type에 , I2C만 .
* : 0=, -1=
*/
int inv_io_hal_init(struct inv_imu_serif *serif)
{
switch (serif->serif_type) {
case UI_SPI4:
{
/* SPI4 초기화 — 현재 미구현 (I2C만 사용) */
break;
}
case UI_I2C:
inv_i2c_master_initialize();
break;
default:
return -1;
}
return 0;
}
/*
* inv_io_hal_read_reg()
* IMU : .
* I2C SPI .
*/
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
{
switch (serif->serif_type) {
case UI_SPI4:
return 0;
case UI_I2C:
return inv_i2c_master_read_register(ICM_I2C_ADDR, reg, rlen, rbuffer);
default:
return -1;
}
}
/*
* inv_io_hal_write_reg()
* IMU : .
* I2C SPI .
*/
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
{
switch (serif->serif_type) {
case UI_SPI4:
return 0;
case UI_I2C:
return inv_i2c_master_write_register(ICM_I2C_ADDR, reg, wlen, wbuffer);
default:
return -1;
}
}
/*
* cat_read()
* I2C (/).
* 8 , .
* : , .
*/
uint8_t cat_read(uint8_t device_id, uint8_t address, uint8_t *data)
{
uint8_t read_data = 0;
char adata[8];
ret_code_t err_code;
//address = 1|(address<<1);
address = (address & 0xFF);
/* 레지스터 주소 전송 (STOP 없이, Repeated START 준비) */
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, &address, 1, true);
if (err_code != NRF_SUCCESS) {
// Handle error
// return;
}
/* 8바이트 데이터 수신 */
err_code = nrfx_twi_rx(&m_twi_icm42670, device_id, data, 8);
if (err_code != NRF_SUCCESS) {
// Handle error
return 0;
}
read_data = data[0];
memcpy(adata,data,8);
printf("Data %s . \r\n", adata);
return read_data;
}
/*
* cat_write()
* I2C (/).
* 1 + 1 .
* : buffer에 6 , 2 .
*/
void cat_write(uint8_t device_id, uint8_t address, uint8_t *data){
uint8_t buffer[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
address = (address & 0xFF);
buffer[0] = (address);
//buffer[1] =(data & 0xFF);
memcpy(buffer+1,data,6);
ret_code_t err_code;
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, 0x00, 1, false);
/* 주소(1바이트) + 데이터(1바이트) = 2바이트 전송 */
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, buffer, 2, false);
// err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 2, false);
// nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
// nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
printf("Data %x %x %x %x. \r\n", buffer[0], buffer[1], buffer[2], buffer[3]);
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 6, false);
if (err_code != NRF_SUCCESS) {
printf("TWI Error.");
}
}
/*******************************************************************************
* @file system_interface.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P IMU I2C
*
* nRF52840의 TWI(I2C) ICM42670P IMU
* .
*
* - I2C : 0x68 (ICM42670P )
* - I2C : SCL=P1.14, SDA=P1.15 (system_interface.h에서 )
* - TWI : NRFX_TWI_INSTANCE(0)
* - : 100kHz (NRF_TWI_FREQ_100K)
*
* :
* inv_io_hal_init() I2C SPI ( I2C만 )
* inv_io_hal_read_reg() (TX로 RX로 )
* inv_io_hal_write_reg() (+ TX)
*
* : I2C / 1
*
* : SPI4 ,
* I2C(UI_I2C) .
******************************************************************************/
/* board driver */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"
#include "nrfx_twi.h"
#include "system_interface.h"
#include "nrf_delay.h"
/* ICM42670P I2C 슬레이브 주소 및 직렬 쓰기 최대 바이트 수 */
#define ICM_I2C_ADDR 0x68
#define INV_MAX_SERIAL_WRITE 16
/* TWI(I2C) 인스턴스 생성 — system_interface.h의 ICM42670_I2C_INSTANCE(0)을 사용 */
const nrfx_twi_t m_twi_icm42670 = NRFX_TWI_INSTANCE(ICM42670_I2C_INSTANCE);
/*
* inv_i2c_master_uninitialize()
* I2C TWI .
* .
*/
void inv_i2c_master_uninitialize(void){
nrfx_twi_disable(&m_twi_icm42670);
nrfx_twi_uninit(&m_twi_icm42670);
}
/*
* inv_i2c_master_initialize()
* nRF52840 TWI .
* - SCL: P1.14, SDA: P1.15
* - : 100kHz
* - : (APP_IRQ_PRIORITY_HIGH)
* - ( )
*/
void inv_i2c_master_initialize(void){
ret_code_t err_code;
const nrfx_twi_config_t twi_icm42670_config = {
.scl = ICM42670_I2C_SCL_PIN,
.sda = ICM42670_I2C_SDA_PIN,
.frequency = NRF_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
};
/* TWI 드라이버 초기화 (이벤트 핸들러=NULL → 블로킹 모드) */
err_code = nrfx_twi_init(&m_twi_icm42670, &twi_icm42670_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
/* TWI 하드웨어 활성화 — 이후 tx/rx 가능 */
nrfx_twi_enable(&m_twi_icm42670);
}
/*
* icm42670_twi_tx()
* I2C . nrfx_twi_tx를 .
* no_stop=true이면 STOP (Repeated START를 )
*/
uint32_t icm42670_twi_tx( uint8_t device_id,
uint8_t const * p_data,
uint8_t length,
bool no_stop)
{
ret_code_t ret;
ret = nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
return ret;
}
/*
* icm42670_twi_rx()
* I2C . nrfx_twi_rx를 .
*/
uint32_t icm42670_twi_rx( uint8_t device_id,
uint8_t * p_data,
uint8_t length)
{
ret_code_t ret;
ret = nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
return ret;
}
/*
* inv_i2c_master_read_register()
* ICM42670P의 .
*
* :
* 1) TX: 1 (no_stop=true Repeated START )
* 2) RX:
*
* : TX, RX 1 .
*/
static unsigned long inv_i2c_master_read_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, unsigned char *RegisterValue){
//ret_code_t ret;
uint32_t ret;
uint8_t addr8 = (uint8_t)RegisterAddr;
/* 1단계: 읽을 레지스터 주소를 전송 (STOP 없이 → Repeated START 사용) */
ret = icm42670_twi_tx(Address, &addr8, 1, true);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_tx(Address, &addr8, 1, true);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c read-1\r\n");
}
}
/* 2단계: 해당 레지스터에서 데이터 수신 */
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c read-2\r\n");
}
}
return ret;
}
/*
* inv_i2c_master_write_register()
* ICM42670P의 .
*
* :
* 1) [0] , [1~N]
* 2) TX: + (no_stop=false STOP )
*
* : 1 .
*/
static unsigned long inv_i2c_master_write_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, const unsigned char *RegisterValue){
uint32_t ret;
uint8_t buffer[1 + INV_MAX_SERIAL_WRITE]; /* 레지스터 주소(1) + 데이터(최대 16바이트) */
/* 버퍼 구성: [레지스터 주소][데이터 바이트들] */
buffer[0] = (uint8_t)RegisterAddr;
memcpy(buffer+1, RegisterValue, RegisterLen);
/* 주소+데이터를 한번에 전송 */
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
if(ret != NRF_SUCCESS) {
/* 실패 시 1회 재시도 */
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
if(ret != NRF_SUCCESS) {
printf("ERR! i2c write\r\n");
}
}
return ret;
}
/*
* inv_io_hal_init()
* IMU (I2C SPI) .
* serif->serif_type에 , I2C만 .
* : 0=, -1=
*/
int inv_io_hal_init(struct inv_imu_serif *serif)
{
switch (serif->serif_type) {
case UI_SPI4:
{
/* SPI4 초기화 — 현재 미구현 (I2C만 사용) */
break;
}
case UI_I2C:
inv_i2c_master_initialize();
break;
default:
return -1;
}
return 0;
}
/*
* inv_io_hal_read_reg()
* IMU : .
* I2C SPI .
*/
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
{
switch (serif->serif_type) {
case UI_SPI4:
return 0;
case UI_I2C:
return inv_i2c_master_read_register(ICM_I2C_ADDR, reg, rlen, rbuffer);
default:
return -1;
}
}
/*
* inv_io_hal_write_reg()
* IMU : .
* I2C SPI .
*/
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
{
switch (serif->serif_type) {
case UI_SPI4:
return 0;
case UI_I2C:
return inv_i2c_master_write_register(ICM_I2C_ADDR, reg, wlen, wbuffer);
default:
return -1;
}
}
/*
* cat_read()
* I2C (/).
* 8 , .
* : , .
*/
uint8_t cat_read(uint8_t device_id, uint8_t address, uint8_t *data)
{
uint8_t read_data = 0;
char adata[8];
ret_code_t err_code;
//address = 1|(address<<1);
address = (address & 0xFF);
/* 레지스터 주소 전송 (STOP 없이, Repeated START 준비) */
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, &address, 1, true);
if (err_code != NRF_SUCCESS) {
// Handle error
// return;
}
/* 8바이트 데이터 수신 */
err_code = nrfx_twi_rx(&m_twi_icm42670, device_id, data, 8);
if (err_code != NRF_SUCCESS) {
// Handle error
return 0;
}
read_data = data[0];
memcpy(adata,data,8);
printf("Data %s . \r\n", adata);
return read_data;
}
/*
* cat_write()
* I2C (/).
* 1 + 1 .
* : buffer에 6 , 2 .
*/
void cat_write(uint8_t device_id, uint8_t address, uint8_t *data){
uint8_t buffer[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
address = (address & 0xFF);
buffer[0] = (address);
//buffer[1] =(data & 0xFF);
memcpy(buffer+1,data,6);
ret_code_t err_code;
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, 0x00, 1, false);
/* 주소(1바이트) + 데이터(1바이트) = 2바이트 전송 */
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, buffer, 2, false);
// err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 2, false);
// nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
// nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
printf("Data %x %x %x %x. \r\n", buffer[0], buffer[1], buffer[2], buffer[3]);
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 6, false);
if (err_code != NRF_SUCCESS) {
printf("TWI Error.");
}
}

View File

@@ -1,72 +1,72 @@
/*******************************************************************************
* @file system_interface.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P I2C
*
* nRF52840 TWI ICM42670P IMU ,
*
* :
* - I2C SCL : P1.14
* - I2C SDA : P1.15
* - INT1 : P1.13 ( )
* - INT2 : P0.26 ( , )
*
* TWI : 0
******************************************************************************/
#ifndef _SYSTEM_INTERFACE_H_
#define _SYSTEM_INTERFACE_H_
#include "inv_imu_transport.h"
#include <stdbool.h>
/* TODO: Move that somewhere else */
#ifndef TO_MASK
#define TO_MASK(a) (1U << (unsigned)(a))
#endif
#define ICM42670_I2C_INSTANCE 0 /**< I2C(TWI) 인스턴스 인덱스 */
#define ICM42670_I2C_SDA_PIN NRF_GPIO_PIN_MAP(1,15) /**< SDA 핀: P1.15 */
#define ICM42670_I2C_SCL_PIN NRF_GPIO_PIN_MAP(1,14) /**< SCL 핀: P1.14 */
#define ICM42670_INT1_PIN NRF_GPIO_PIN_MAP(1,13) /**< INT1 핀: P1.13 (데이터 준비 인터럽트) */
#define ICM42670_INT2_PIN NRF_GPIO_PIN_MAP(0,26) /**< INT2 핀: P0.26 (보조, 현재 미사용) */
/* I2C 전송 래퍼 — no_stop=true이면 Repeated START를 위해 STOP 컨디션 생략 */
uint32_t icm42670_twi_tx( uint8_t device_id,
uint8_t const * p_data,
uint8_t length,
bool no_stop);
/* I2C 수신 래퍼 */
uint32_t icm42670_twi_rx( uint8_t device_id,
uint8_t * p_data,
uint8_t length);
/* 범용 I2C 읽기 (디버그/레거시용) — 8바이트를 읽어 첫 바이트 반환 */
uint8_t cat_read (uint8_t device_id, uint8_t address, uint8_t *data);
/* 범용 I2C 쓰기 (디버그/레거시용) — 주소+데이터 2바이트 전송 */
void cat_write (uint8_t device_id, uint8_t address, uint8_t *data);
/* I2C 하드웨어 해제 (슬립 또는 재초기화 전 호출) */
void inv_i2c_master_uninitialize(void);
/* I2C 하드웨어 초기화 (100kHz, 블로킹 모드) */
void inv_i2c_master_initialize(void);
/* IMU 드라이버용 시리얼 인터페이스 초기화 (I2C/SPI 분기) */
int inv_io_hal_init(struct inv_imu_serif *serif);
/* IMU 드라이버 콜백: 레지스터 읽기 */
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen);
/* IMU 드라이버 콜백: 레지스터 쓰기 */
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen);
#endif /* !_SYSTEM_INTERFACE_H_ */
/*******************************************************************************
* @file system_interface.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] ICM42670P I2C
*
* nRF52840 TWI ICM42670P IMU ,
*
* :
* - I2C SCL : P1.14
* - I2C SDA : P1.15
* - INT1 : P1.13 ( )
* - INT2 : P0.26 ( , )
*
* TWI : 0
******************************************************************************/
#ifndef _SYSTEM_INTERFACE_H_
#define _SYSTEM_INTERFACE_H_
#include "inv_imu_transport.h"
#include <stdbool.h>
/* TODO: Move that somewhere else */
#ifndef TO_MASK
#define TO_MASK(a) (1U << (unsigned)(a))
#endif
#define ICM42670_I2C_INSTANCE 0 /**< I2C(TWI) 인스턴스 인덱스 */
#define ICM42670_I2C_SDA_PIN NRF_GPIO_PIN_MAP(1,15) /**< SDA 핀: P1.15 */
#define ICM42670_I2C_SCL_PIN NRF_GPIO_PIN_MAP(1,14) /**< SCL 핀: P1.14 */
#define ICM42670_INT1_PIN NRF_GPIO_PIN_MAP(1,13) /**< INT1 핀: P1.13 (데이터 준비 인터럽트) */
#define ICM42670_INT2_PIN NRF_GPIO_PIN_MAP(0,26) /**< INT2 핀: P0.26 (보조, 현재 미사용) */
/* I2C 전송 래퍼 — no_stop=true이면 Repeated START를 위해 STOP 컨디션 생략 */
uint32_t icm42670_twi_tx( uint8_t device_id,
uint8_t const * p_data,
uint8_t length,
bool no_stop);
/* I2C 수신 래퍼 */
uint32_t icm42670_twi_rx( uint8_t device_id,
uint8_t * p_data,
uint8_t length);
/* 범용 I2C 읽기 (디버그/레거시용) — 8바이트를 읽어 첫 바이트 반환 */
uint8_t cat_read (uint8_t device_id, uint8_t address, uint8_t *data);
/* 범용 I2C 쓰기 (디버그/레거시용) — 주소+데이터 2바이트 전송 */
void cat_write (uint8_t device_id, uint8_t address, uint8_t *data);
/* I2C 하드웨어 해제 (슬립 또는 재초기화 전 호출) */
void inv_i2c_master_uninitialize(void);
/* I2C 하드웨어 초기화 (100kHz, 블로킹 모드) */
void inv_i2c_master_initialize(void);
/* IMU 드라이버용 시리얼 인터페이스 초기화 (I2C/SPI 분기) */
int inv_io_hal_init(struct inv_imu_serif *serif);
/* IMU 드라이버 콜백: 레지스터 읽기 */
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen);
/* IMU 드라이버 콜백: 레지스터 쓰기 */
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen);
#endif /* !_SYSTEM_INTERFACE_H_ */

View File

@@ -1,217 +1,217 @@
/*******************************************************************************
* @file tmp235_q1.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] TMP235-Q1
*
* TMP235-Q1은 (Vout)
* nRF52840 SAADC의 AIN3 Vout을 , mV로 (°C)
*
* ( ):
* - Vout <= 1500mV (0~100°C): Ta = (Vout - 500) / 10.0
* - Vout <= 1750mV (100~125°C): Ta = (Vout - 1500) / 10.1 + 100
* - Vout <= 2000mV (125~150°C): Ta = (Vout - 1752.5) / 10.6 + 125
* - Vout > 2000mV: (150°C )
*
* info4 ( ) :
* (go_batt) (go_temp) IMU(motion_raw_data_enabled)
* go_temp=false, motion_raw_data_enabled=true
******************************************************************************/
#include "sdk_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "ble_nus.h"
#include "tmp235_q1.h"
#include "main.h"
/* 2026-03-17: cmd_parse.h 삭제 — main.h는 이미 포함됨 */
#include "main_timer.h"
#include "debug_print.h"
/* SAADC 내부 기준전압 600mV (부동소수점) */
#define TMP235_REF_VOLTAGE_IN_MILLIVOLTS 600.0f /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
/* 1/3 프리스케일링 보상 계수 x6 (부동소수점) */
#define TMP235_PRE_SCALING_COMPENSATION 6.0f /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
/* 12비트 ADC 최대값 4096 (부동소수점, 분해능 기준) */
#define TMP235_ADC_RES_12BITS 4096.0f /**< Maximum digital value for 12-bit ADC conversion. */
/**@brief Macro to convert the result of ADC conversion in millivolts.
*
* @param[in] ADC_VALUE ADC result.
*
* @retval Result converted to millivolts.
*/
/* ADC 원시값 → TMP235 출력전압(mV) 변환 매크로: ADC x (600/4096) x 6 */
#define TMP235_VOUT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * TMP235_REF_VOLTAGE_IN_MILLIVOLTS) / TMP235_ADC_RES_12BITS) * TMP235_PRE_SCALING_COMPENSATION)
/* SAADC 변환 결과 저장 버퍼 (1채널) */
static nrf_saadc_value_t adc_buf;
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* 현재 명령 소스: CMD_UART 또는 CMD_BLE */
extern which_cmd_t cmd_type_t;
/* info4: 전체 센서 데이터 수집 모드 플래그 */
extern bool info4; // main.c
/* 온도 측정 순서 제어 플래그 */
extern bool go_temp; // main_timer.c
/* info4 모드에서 온도값 임시 저장 (°C x 100, 정수 표현) */
volatile uint16_t info_temp; //48_C
extern bool motion_raw_data_enabled;
/* SAADC 완료 플래그 — all_sensors()에서 콜백 완료 대기용 */
volatile bool tmp235_saadc_done = false;
/**@brief Function for handling the ADC interrupt.
*
* @details This function will fetch the conversion result from the ADC, convert the value into
* percentage and send it to peer.
*/
/**
* @brief TMP235 ADC
*
* SAADC .
* ADC값 Vout(mV) (°C) , :
* - info4 : info_temp에 (°C x 100 ), IMU
* - : BLE("rso:" ) UART로
*/
void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout reading */
{
float led_temp; /* 계산된 온도 (°C, 부동소수점) */
float led_temp_16; /* BLE 전송용 온도 (°C x 100, 부동소수점) */
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_saadc_value_t adc_result;
float tmp235_voltage_in_milli_volts = 0;
/* ADC 변환 결과 읽기 */
adc_result = p_event->data.done.p_buffer[0];
//DBG_PRINTF("[TMP] adc=%d\r\n", adc_result);
/* SAADC 해제 — 배터리/압력센서 측정과 하드웨어 공유 */
nrf_drv_saadc_channel_uninit(0); // 채널 먼저 해제
nrf_drv_saadc_uninit();
//nrf_drv_saadc_uninit(); // 이전: 드라이버 먼저 해제
//nrf_drv_saadc_channel_uninit(0);
/* ADC값 → TMP235 출력전압(mV) 변환 */
tmp235_voltage_in_milli_volts = TMP235_VOUT_IN_MILLI_VOLTS(adc_result);
/*
* Vout (°C) ( )
* TMP235 :
* 0~100°C : 10.0 mV/°C, 500mV
* 100~125°C : 10.1 mV/°C
* 125~150°C : 10.6 mV/°C
*/
if(tmp235_voltage_in_milli_volts <= 1500)
{
/* 0~100°C: Ta = (Vout - 500mV) / 10.0 mV/°C */
led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f;
}
else if(tmp235_voltage_in_milli_volts <= 1750)
{
/* 100~125°C: 기울기가 10.1로 약간 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f;
}
else if(tmp235_voltage_in_milli_volts <= 2000)
{
/* 125~150°C: 기울기가 10.6으로 더 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f;
}
else
{
/* 150°C 초과 — 센서 측정 범위 벗어남 */
DBG_PRINTF("ERR!!! Temprature is over 150c\r\n");
}
/* info4 모드: 온도값을 정수(°C x 100)로 저장 (예: 36.50°C → 3650) */
if (info4 == true)
{
info_temp = (uint16_t)(led_temp * 100);
}
/* UART 모드: 소수점 2자리까지 텍스트로 출력 */
else if(cmd_type_t == CMD_UART)
{
DBG_PRINTF("To%.2f\r\n\r\n",led_temp);
}
/* BLE 모드: °C x 100 정수를 "rso:" 헤더로 바이너리 전송 */
else if(cmd_type_t == CMD_BLE)
{
led_temp_16 = led_temp * 100;
single_format_data(ble_bin_buffer, "rso:", (uint16_t)led_temp_16);
dr_binary_tx_safe(ble_bin_buffer,3);
// sprintf(ble_tx_buffer, "To%.2f\r\n",led_temp);
// data_tx_handler(ble_tx_buffer);
}
DBG_PRINTF("7");
tmp235_saadc_done = true;
}
}
/**
* @brief TMP235 SAADC
*
* AIN3 .
* tmp235_voltage_handler .
*/
void tmp235_init(void)
{
/* SAADC 드라이버 초기화 (4x 오버샘플링으로 노이즈 저감) */
nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;
saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;
ret_code_t err_code = nrf_drv_saadc_init(&saadc_config, tmp235_voltage_handler);
APP_ERROR_CHECK(err_code);
/* AIN3 채널 설정: TMP235-Q1 Vout 핀 (싱글엔드 입력, burst 활성화) */
nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
config.burst = NRF_SAADC_BURST_ENABLED;
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);
/* ADC 버퍼 등록 (1채널, 1샘플) */
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
/* 즉시 ADC 샘플링 시작 (비동기) */
err_code = nrf_drv_saadc_sample();
APP_ERROR_CHECK(err_code);
}
/* Ta = (Vout Voffs ) / Tc + Tinfl */
/**
* @brief
*
* tmp235_init() SAADC + .
* init sample .
*/
void tmp235_voltage_level_meas(void)
{
tmp235_init(); // init 함수에 있는 걸 그냥 여기 넣어도
//tmp235_uninit();
}
/*******************************************************************************
* @file tmp235_q1.c
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] TMP235-Q1
*
* TMP235-Q1은 (Vout)
* nRF52840 SAADC의 AIN3 Vout을 , mV로 (°C)
*
* ( ):
* - Vout <= 1500mV (0~100°C): Ta = (Vout - 500) / 10.0
* - Vout <= 1750mV (100~125°C): Ta = (Vout - 1500) / 10.1 + 100
* - Vout <= 2000mV (125~150°C): Ta = (Vout - 1752.5) / 10.6 + 125
* - Vout > 2000mV: (150°C )
*
* info4 ( ) :
* (go_batt) (go_temp) IMU(motion_raw_data_enabled)
* go_temp=false, motion_raw_data_enabled=true
******************************************************************************/
#include "sdk_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_drv_saadc.h"
#include "ble_nus.h"
#include "tmp235_q1.h"
#include "main.h"
/* 2026-03-17: cmd_parse.h 삭제 — main.h는 이미 포함됨 */
#include "main_timer.h"
#include "debug_print.h"
/* SAADC 내부 기준전압 600mV (부동소수점) */
#define TMP235_REF_VOLTAGE_IN_MILLIVOLTS 600.0f /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
/* 1/3 프리스케일링 보상 계수 x6 (부동소수점) */
#define TMP235_PRE_SCALING_COMPENSATION 6.0f /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
/* 12비트 ADC 최대값 4096 (부동소수점, 분해능 기준) */
#define TMP235_ADC_RES_12BITS 4096.0f /**< Maximum digital value for 12-bit ADC conversion. */
/**@brief Macro to convert the result of ADC conversion in millivolts.
*
* @param[in] ADC_VALUE ADC result.
*
* @retval Result converted to millivolts.
*/
/* ADC 원시값 → TMP235 출력전압(mV) 변환 매크로: ADC x (600/4096) x 6 */
#define TMP235_VOUT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * TMP235_REF_VOLTAGE_IN_MILLIVOLTS) / TMP235_ADC_RES_12BITS) * TMP235_PRE_SCALING_COMPENSATION)
/* SAADC 변환 결과 저장 버퍼 (1채널) */
static nrf_saadc_value_t adc_buf;
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* 현재 명령 소스: CMD_UART 또는 CMD_BLE */
extern which_cmd_t cmd_type_t;
/* info4: 전체 센서 데이터 수집 모드 플래그 */
extern bool info4; // main.c
/* 온도 측정 순서 제어 플래그 */
extern bool go_temp; // main_timer.c
/* info4 모드에서 온도값 임시 저장 (°C x 100, 정수 표현) */
volatile uint16_t info_temp; //48_C
extern bool motion_raw_data_enabled;
/* SAADC 완료 플래그 — all_sensors()에서 콜백 완료 대기용 */
volatile bool tmp235_saadc_done = false;
/**@brief Function for handling the ADC interrupt.
*
* @details This function will fetch the conversion result from the ADC, convert the value into
* percentage and send it to peer.
*/
/**
* @brief TMP235 ADC
*
* SAADC .
* ADC값 Vout(mV) (°C) , :
* - info4 : info_temp에 (°C x 100 ), IMU
* - : BLE("rso:" ) UART로
*/
void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout reading */
{
float led_temp; /* 계산된 온도 (°C, 부동소수점) */
float led_temp_16; /* BLE 전송용 온도 (°C x 100, 부동소수점) */
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
nrf_saadc_value_t adc_result;
float tmp235_voltage_in_milli_volts = 0;
/* ADC 변환 결과 읽기 */
adc_result = p_event->data.done.p_buffer[0];
//DBG_PRINTF("[TMP] adc=%d\r\n", adc_result);
/* SAADC 해제 — 배터리/압력센서 측정과 하드웨어 공유 */
nrf_drv_saadc_channel_uninit(0); // 채널 먼저 해제
nrf_drv_saadc_uninit();
//nrf_drv_saadc_uninit(); // 이전: 드라이버 먼저 해제
//nrf_drv_saadc_channel_uninit(0);
/* ADC값 → TMP235 출력전압(mV) 변환 */
tmp235_voltage_in_milli_volts = TMP235_VOUT_IN_MILLI_VOLTS(adc_result);
/*
* Vout (°C) ( )
* TMP235 :
* 0~100°C : 10.0 mV/°C, 500mV
* 100~125°C : 10.1 mV/°C
* 125~150°C : 10.6 mV/°C
*/
if(tmp235_voltage_in_milli_volts <= 1500)
{
/* 0~100°C: Ta = (Vout - 500mV) / 10.0 mV/°C */
led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f;
}
else if(tmp235_voltage_in_milli_volts <= 1750)
{
/* 100~125°C: 기울기가 10.1로 약간 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f;
}
else if(tmp235_voltage_in_milli_volts <= 2000)
{
/* 125~150°C: 기울기가 10.6으로 더 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f;
}
else
{
/* 150°C 초과 — 센서 측정 범위 벗어남 */
DBG_PRINTF("ERR!!! Temprature is over 150c\r\n");
}
/* info4 모드: 온도값을 정수(°C x 100)로 저장 (예: 36.50°C → 3650) */
if (info4 == true)
{
info_temp = (uint16_t)(led_temp * 100);
}
/* UART 모드: 소수점 2자리까지 텍스트로 출력 */
else if(cmd_type_t == CMD_UART)
{
DBG_PRINTF("To%.2f\r\n\r\n",led_temp);
}
/* BLE 모드: °C x 100 정수를 "rso:" 헤더로 바이너리 전송 */
else if(cmd_type_t == CMD_BLE)
{
led_temp_16 = led_temp * 100;
single_format_data(ble_bin_buffer, "rso:", (uint16_t)led_temp_16);
dr_binary_tx_safe(ble_bin_buffer,3);
// sprintf(ble_tx_buffer, "To%.2f\r\n",led_temp);
// data_tx_handler(ble_tx_buffer);
}
DBG_PRINTF("7");
tmp235_saadc_done = true;
}
}
/**
* @brief TMP235 SAADC
*
* AIN3 .
* tmp235_voltage_handler .
*/
void tmp235_init(void)
{
/* SAADC 드라이버 초기화 (4x 오버샘플링으로 노이즈 저감) */
nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;
saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;
ret_code_t err_code = nrf_drv_saadc_init(&saadc_config, tmp235_voltage_handler);
APP_ERROR_CHECK(err_code);
/* AIN3 채널 설정: TMP235-Q1 Vout 핀 (싱글엔드 입력, burst 활성화) */
nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
config.burst = NRF_SAADC_BURST_ENABLED;
err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);
/* ADC 버퍼 등록 (1채널, 1샘플) */
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
APP_ERROR_CHECK(err_code);
/* 즉시 ADC 샘플링 시작 (비동기) */
err_code = nrf_drv_saadc_sample();
APP_ERROR_CHECK(err_code);
}
/* Ta = (Vout Voffs ) / Tc + Tinfl */
/**
* @brief
*
* tmp235_init() SAADC + .
* init sample .
*/
void tmp235_voltage_level_meas(void)
{
tmp235_init(); // init 함수에 있는 걸 그냥 여기 넣어도
//tmp235_uninit();
}

View File

@@ -1,31 +1,31 @@
/*******************************************************************************
* @file tmp235_q1.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] TMP235-Q1
*
* TMP235-Q1의 SAADC(AIN3)
* (°C) API를 .
*
* API:
* - tmp235_init() : SAADC + ( )
* - tmp235_voltage_level_meas() : 1 ( )
*
* : Vout(mV) Ta(°C) = (Vout - 500) / 10.0 (0~100°C )
******************************************************************************/
#ifndef _TMP235_Q1_H_
#define _TMP235_Q1_H_
/** @brief TMP235 SAADC 초기화 및 측정 시작 (AIN3 채널) */
void tmp235_init(void);
/** @brief 온도 1회 측정 외부 호출 함수 (내부적으로 tmp235_init 호출) */
void tmp235_voltage_level_meas(void);
#endif /* !_TMP235_Q1_H_ */
/*******************************************************************************
* @file tmp235_q1.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
******************************************************************************/
/*******************************************************************************
* [ ] TMP235-Q1
*
* TMP235-Q1의 SAADC(AIN3)
* (°C) API를 .
*
* API:
* - tmp235_init() : SAADC + ( )
* - tmp235_voltage_level_meas() : 1 ( )
*
* : Vout(mV) Ta(°C) = (Vout - 500) / 10.0 (0~100°C )
******************************************************************************/
#ifndef _TMP235_Q1_H_
#define _TMP235_Q1_H_
/** @brief TMP235 SAADC 초기화 및 측정 시작 (AIN3 채널) */
void tmp235_init(void);
/** @brief 온도 1회 측정 외부 호출 함수 (내부적으로 tmp235_init 호출) */
void tmp235_voltage_level_meas(void);
#endif /* !_TMP235_Q1_H_ */

View File

@@ -209,7 +209,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -225,7 +225,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -545,7 +545,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -561,7 +561,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -609,7 +609,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -721,7 +721,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -737,7 +737,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -753,7 +753,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -769,7 +769,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -785,7 +785,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\power_control.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\power_control.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -929,7 +929,7 @@
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\..\..\fstorage.c</Filename>
<Filename>C:\jhChun\VesiScan-Basic\project\ble_peripheral\ble_app_bladder_patch\fstorage.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
@@ -1183,7 +1183,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\main_timer.c</PathWithFileName>
<PathWithFileName>..\..\..\system\main_timer.c</PathWithFileName>
<FilenameWithoutPath>main_timer.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1195,7 +1195,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\battery_saadc.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\battery\battery_saadc.c</PathWithFileName>
<FilenameWithoutPath>battery_saadc.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1207,7 +1207,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\power_control.c</PathWithFileName>
<PathWithFileName>..\..\..\io\power\power_control.c</PathWithFileName>
<FilenameWithoutPath>power_control.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1219,7 +1219,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\tmp235_q1.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\temperature\tmp235_q1.c</PathWithFileName>
<FilenameWithoutPath>tmp235_q1.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1231,7 +1231,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\fstorage.c</PathWithFileName>
<PathWithFileName>..\..\..\hal\fds\fstorage.c</PathWithFileName>
<FilenameWithoutPath>fstorage.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1243,7 +1243,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\debug_print.h</PathWithFileName>
<PathWithFileName>..\..\..\system\debug_print.h</PathWithFileName>
<FilenameWithoutPath>debug_print.h</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1255,7 +1255,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\i2c_manager.c</PathWithFileName>
<PathWithFileName>..\..\..\hal\i2c\i2c_manager.c</PathWithFileName>
<FilenameWithoutPath>i2c_manager.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -1375,7 +1375,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\led_control.c</PathWithFileName>
<PathWithFileName>..\..\..\io\led\led_control.c</PathWithFileName>
<FilenameWithoutPath>led_control.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3111,7 +3111,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\system_interface.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\system_interface.c</PathWithFileName>
<FilenameWithoutPath>system_interface.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3123,7 +3123,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\EmbUtils\DataConverter.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\EmbUtils\DataConverter.c</PathWithFileName>
<FilenameWithoutPath>DataConverter.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3135,7 +3135,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\EmbUtils\ErrorHelper.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\EmbUtils\ErrorHelper.c</PathWithFileName>
<FilenameWithoutPath>ErrorHelper.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3147,7 +3147,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\EmbUtils\InvBasicMath.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\EmbUtils\InvBasicMath.c</PathWithFileName>
<FilenameWithoutPath>InvBasicMath.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3159,7 +3159,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\imu\inv_imu_apex.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\imu\inv_imu_apex.c</PathWithFileName>
<FilenameWithoutPath>inv_imu_apex.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3171,7 +3171,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\imu\inv_imu_driver.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\imu\inv_imu_driver.c</PathWithFileName>
<FilenameWithoutPath>inv_imu_driver.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3183,7 +3183,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\imu\inv_imu_selftest.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\imu\inv_imu_selftest.c</PathWithFileName>
<FilenameWithoutPath>inv_imu_selftest.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3195,7 +3195,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\Invn\imu\inv_imu_transport.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\Invn\imu\inv_imu_transport.c</PathWithFileName>
<FilenameWithoutPath>inv_imu_transport.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3207,7 +3207,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\app_raw\app_raw.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\app_raw\app_raw.c</PathWithFileName>
<FilenameWithoutPath>app_raw.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
@@ -3219,7 +3219,7 @@
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\icm42670p\app_raw\app_raw_main.c</PathWithFileName>
<PathWithFileName>..\..\..\sensors\imu\app_raw\app_raw_main.c</PathWithFileName>
<FilenameWithoutPath>app_raw_main.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>

View File

@@ -1,33 +1,33 @@
// file: debug_print.h
/*******************************************************************************
* [ ] ( )
*
* SEGGER RTT(Real Time Transfer) .
* J-Link PC에 .
* UART를 .
*
* === ===
* ENABLE_PRINTF = 1: DBG_PRINTF가 SEGGER_RTT_printf(0)
* -> ( )
* ENABLE_PRINTF = 0: DBG_PRINTF가
* -> ( )
*
* === ===
* DBG_PRINTF("값: %d\r\n", value); // printf와 동일한 포맷 문자열
* SEGGER RTT Viewer J-Link RTT Client에서 .
******************************************************************************/
#ifndef DEBUG_PRINT_H
#define DEBUG_PRINT_H
#define ENABLE_PRINTF 1 /* 1=디버그 출력 활성화, 0=전역 비활성화 */
#if ENABLE_PRINTF
#include "SEGGER_RTT.h"
/* SEGGER RTT 채널 0으로 포맷 문자열 출력 */
#define DBG_PRINTF(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
/* 빈 매크로: 컴파일러가 호출 코드를 완전히 제거 */
#define DBG_PRINTF(...) // Do nothing
#endif
#endif // DEBUG_PRINT_H
// file: debug_print.h
/*******************************************************************************
* [ ] ( )
*
* SEGGER RTT(Real Time Transfer) .
* J-Link PC에 .
* UART를 .
*
* === ===
* ENABLE_PRINTF = 1: DBG_PRINTF가 SEGGER_RTT_printf(0)
* -> ( )
* ENABLE_PRINTF = 0: DBG_PRINTF가
* -> ( )
*
* === ===
* DBG_PRINTF("값: %d\r\n", value); // printf와 동일한 포맷 문자열
* SEGGER RTT Viewer J-Link RTT Client에서 .
******************************************************************************/
#ifndef DEBUG_PRINT_H
#define DEBUG_PRINT_H
#define ENABLE_PRINTF 1 /* 1=디버그 출력 활성화, 0=전역 비활성화 */
#if ENABLE_PRINTF
#include "SEGGER_RTT.h"
/* SEGGER RTT 채널 0으로 포맷 문자열 출력 */
#define DBG_PRINTF(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
/* 빈 매크로: 컴파일러가 호출 코드를 완전히 제거 */
#define DBG_PRINTF(...) // Do nothing
#endif
#endif // DEBUG_PRINT_H

View File

@@ -1,280 +1,280 @@
/*******************************************************************************
TEST medi50 Dec 23
*******************************************************************************
*
* [ ]
* (10ms , ).
*
* .
* app_timer ,
* main_timer_start() .
*
* [ ]
* motion_raw_data_enabled IMU (icm42670_main )
* - motion_data_once == true: (HW I2C 1)
* - motion_data_once == false: (BLE )
* go_batt (battery_level_meas)
* go_temp (tmp235_voltage_level_meas)
* go_device_power_off OFF (device_power_off)
* go_sleep_mode_enter (sleep_mode_enter)
* go_NVIC_SystemReset NVIC
*
* [info4 ]
* IMU go_batt() go_temp() motion_data_once(IMU )
* motion_data_once=true로 IMU로 .
*
* [ ]
* - : 10ms (MAIN_LOOP_INTERVAL)
* - FEATURE_DETAIL_VALUE_FULL : 80ms ( )
*
******************************************************************************/
#include "sdk_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_drv_gpiote.h"
#include "battery_saadc.h"
#include "app_timer.h"
#include "main.h"
#include "app_raw_main.h"
#include "main_timer.h"
#include "tmp235_q1.h"
//#include "fstorage.h"
#include "power_control.h"
#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */
#include "debug_print.h"
#include "i2c_manager.h" //add cj
/* 메인 루프 싱글샷 타이머 인스턴스 */
APP_TIMER_DEF(m_main_loop_timer_id);
#if FEATURE_DETAIL_VALUE_FULL
/* 디테일 프린트아웃 모드: 80ms 간격으로 메인 루프 실행 */
#define MAIN_LOOP_INTERVAL 80 /* 디테일 프린트아웃이 있을경우 Full_Mode Main Prosessing 수행하는 타이머 */
//extern bool pd_adc_full_a_start;
//extern bool pd_adc_full_b_start;
//extern bool pd_adc_full_c_start;
//extern bool pd_adc_full_d_start;
//extern bool pd_adc_full_end;
extern which_cmd_t cmd_type_t;
#else
/* 일반 모드: 10ms 간격으로 메인 루프 실행 */
#define MAIN_LOOP_INTERVAL 10
#endif
/* ========================================================================== */
/* 이벤트 플래그 (외부 모듈에서 설정, main_loop에서 처리) */
/* ========================================================================== */
bool go_batt= false; /* 배터리 측정 요청 플래그 */
bool go_temp= false; /* 온도 측정 요청 플래그 */
bool go_device_power_off = false; /* 디바이스 전원 OFF 요청 플래그 */
bool go_sleep_mode_enter = false; /* 슬립 모드 진입 요청 플래그 */
bool go_NVIC_SystemReset = false; /* 시스템 리셋 요청 플래그 */
bool motion_raw_data_enabled = false; /* IMU 모션 데이터 읽기 활성화 플래그 */
bool ble_got_new_data = false; /* BLE로 새 데이터 전송 완료 여부 */
bool motion_data_once = false; /* IMU 단발성 읽기 모드 (true: 1회만 읽기) */
/**
* @brief ( )
*
* , .
* main_timer_start()
* .
*
* [ ] ( )
* 1. IMU (motion_raw_data_enabled)
* 2. (go_batt)
* 3. (go_temp)
* 4. OFF (go_device_power_off)
* 5. (go_sleep_mode_enter)
* 6. (go_NVIC_SystemReset)
*/
void main_loop(void * p_context) /* For x ms */
{
UNUSED_PARAMETER(p_context);
#if FEATURE_DETAIL_VALUE_FULL
// if(pd_adc_full_a_start == true) { // A mode
// main_timer_stop();
// printf("main_loop_A\r\n");
// full_adc_start();
// }else if(pd_adc_full_b_start == true) { // B mode
// main_timer_stop();
// printf("main_loop_B\r\n");
// full_adc_start();
// }else if(pd_adc_full_c_start == true) { // C mode
// main_timer_stop();
// printf("main_loop_C\r\n");
// full_adc_start();
// }else if(pd_adc_full_d_start == true) { // D mode
// main_timer_stop();
// printf("main_loop_D\r\n");
// full_adc_start();
// }else if(pd_adc_full_end == true) { // Completed
// pd_adc_full_end = false;
// main_timer_stop();
// printf("main_loop_END\r\n");
// if(cmd_type_t == CMD_BLE) {
// full_send_timer_start();
// }
// }
#endif
// For Motion Data Sampling
/* ---- IMU 모션 데이터 읽기 ---- */
/*
* motion_raw_data_enabled가 true이면 IMU(ICM42670P) .
*
* motion_data_once == true:
* . HW I2C를 icm42670_main() 1 .
* info4 / IMU로 .
*
* motion_data_once == false:
* . BLE (ble_got_new_data==false)
* icm42670_main() 10ms .
*/
if(motion_raw_data_enabled == true) {
main_timer_stop(); /* 타이머 정지 (재진입 방지) */
if(motion_data_once == true)
{
/* 단발성 모드: HW I2C 초기화 후 IMU 데이터 1회 읽기 */
hw_i2c_init_once(); /* HW TWI 모드로 전환 (400kHz) */
icm42670_main(); /* IMU 데이터 읽기 및 처리 */
}
else{
/* 연속 모드: BLE 전송 대기 중이 아니면 반복 읽기 */
if(ble_got_new_data==false){
//for(uint16_t i=0 ; i<60 ;i++)
//{
DBG_PRINTF("IMU \r\n");
icm42670_main(); /* IMU 데이터 읽기 */
motion_raw_data_enabled = true; /* 플래그 유지 (연속 읽기) */
main_timer_start_ms(1000); /* 1초 후 다음 IMU 읽기 */
}
// else if(ble_got_new_data==true){
// motion_data_once = true;
// }
}
}
/* ---- 배터리 전압 측정 ---- */
/*
* go_batt true이면 .
* info4 IMU .
* .
*/
if(go_batt == true) {
DBG_PRINTF("IMU BATT\r\n");
main_timer_stop(); /* 타이머 정지 */
go_batt = false; /* 플래그 소비 (1회 실행) */
// go_temp = true;
battery_level_meas(); /* SAADC를 이용한 배터리 전압 측정 */
// nrf_delay_ms(20);
// m48_adc_start_init();
// main_timer_start();
}
/* ---- 온도 측정 ---- */
/*
* go_temp true이면 TMP235-Q1 .
* info4 .
* motion_data_once=true로
* IMU (HW I2C ) .
*/
if(go_temp == true) {
DBG_PRINTF("IMU Temp\r\n");
main_timer_stop(); /* 타이머 정지 */
// go_batt = false;
go_temp = false; /* 플래그 소비 (1회 실행) */
motion_data_once = true; /* 다음 IMU 읽기를 단발성 모드로 전환 */
tmp235_voltage_level_meas(); /* TMP235-Q1 온도 센서 전압 측정 */
// motion_raw_data_enabled = true;
// main_timer_start();
}
/* ---- 시스템 제어 이벤트 처리 ---- */
/* 디바이스 전원 OFF 처리 */
if(go_device_power_off == true){
main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("Off main_timer\r\n");
device_power_off(); /* 디바이스 전원 OFF 실행 */
}
/* 슬립 모드 진입 처리 */
if(go_sleep_mode_enter == true){
main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("sleep main timer\r\n");
sleep_mode_enter(); /* 슬립 모드 진입 실행 */
}
/* NVIC 시스템 리셋 처리 */
if(go_NVIC_SystemReset == true) {
main_timer_stop(); /* 타이머 정지 */
NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */
}
}
/**
* @brief
*
* MAIN_LOOP_INTERVAL(10ms 80ms) main_loop()
*/
void main_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(MAIN_LOOP_INTERVAL), NULL));
}
/**
* @brief (ms)
*
* IMU
*/
void main_timer_start_ms(uint32_t interval_ms)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(interval_ms), NULL));
}
/**
* @brief
*/
void main_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_main_loop_timer_id));
}
/**
* @brief ( 1 )
*
* , main_loop()
* main_timer_start()
*/
void main_timer_init(void)
{
APP_ERROR_CHECK(app_timer_create(&m_main_loop_timer_id, APP_TIMER_MODE_SINGLE_SHOT, main_loop));
}
/*******************************************************************************
TEST medi50 Dec 23
*******************************************************************************
*
* [ ]
* (10ms , ).
*
* .
* app_timer ,
* main_timer_start() .
*
* [ ]
* motion_raw_data_enabled IMU (icm42670_main )
* - motion_data_once == true: (HW I2C 1)
* - motion_data_once == false: (BLE )
* go_batt (battery_level_meas)
* go_temp (tmp235_voltage_level_meas)
* go_device_power_off OFF (device_power_off)
* go_sleep_mode_enter (sleep_mode_enter)
* go_NVIC_SystemReset NVIC
*
* [info4 ]
* IMU go_batt() go_temp() motion_data_once(IMU )
* motion_data_once=true로 IMU로 .
*
* [ ]
* - : 10ms (MAIN_LOOP_INTERVAL)
* - FEATURE_DETAIL_VALUE_FULL : 80ms ( )
*
******************************************************************************/
#include "sdk_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_drv_gpiote.h"
#include "battery_saadc.h"
#include "app_timer.h"
#include "main.h"
#include "app_raw_main.h"
#include "main_timer.h"
#include "tmp235_q1.h"
//#include "fstorage.h"
#include "power_control.h"
#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */
#include "debug_print.h"
#include "i2c_manager.h" //add cj
/* 메인 루프 싱글샷 타이머 인스턴스 */
APP_TIMER_DEF(m_main_loop_timer_id);
#if FEATURE_DETAIL_VALUE_FULL
/* 디테일 프린트아웃 모드: 80ms 간격으로 메인 루프 실행 */
#define MAIN_LOOP_INTERVAL 80 /* 디테일 프린트아웃이 있을경우 Full_Mode Main Prosessing 수행하는 타이머 */
//extern bool pd_adc_full_a_start;
//extern bool pd_adc_full_b_start;
//extern bool pd_adc_full_c_start;
//extern bool pd_adc_full_d_start;
//extern bool pd_adc_full_end;
extern which_cmd_t cmd_type_t;
#else
/* 일반 모드: 10ms 간격으로 메인 루프 실행 */
#define MAIN_LOOP_INTERVAL 10
#endif
/* ========================================================================== */
/* 이벤트 플래그 (외부 모듈에서 설정, main_loop에서 처리) */
/* ========================================================================== */
bool go_batt= false; /* 배터리 측정 요청 플래그 */
bool go_temp= false; /* 온도 측정 요청 플래그 */
bool go_device_power_off = false; /* 디바이스 전원 OFF 요청 플래그 */
bool go_sleep_mode_enter = false; /* 슬립 모드 진입 요청 플래그 */
bool go_NVIC_SystemReset = false; /* 시스템 리셋 요청 플래그 */
bool motion_raw_data_enabled = false; /* IMU 모션 데이터 읽기 활성화 플래그 */
bool ble_got_new_data = false; /* BLE로 새 데이터 전송 완료 여부 */
bool motion_data_once = false; /* IMU 단발성 읽기 모드 (true: 1회만 읽기) */
/**
* @brief ( )
*
* , .
* main_timer_start()
* .
*
* [ ] ( )
* 1. IMU (motion_raw_data_enabled)
* 2. (go_batt)
* 3. (go_temp)
* 4. OFF (go_device_power_off)
* 5. (go_sleep_mode_enter)
* 6. (go_NVIC_SystemReset)
*/
void main_loop(void * p_context) /* For x ms */
{
UNUSED_PARAMETER(p_context);
#if FEATURE_DETAIL_VALUE_FULL
// if(pd_adc_full_a_start == true) { // A mode
// main_timer_stop();
// printf("main_loop_A\r\n");
// full_adc_start();
// }else if(pd_adc_full_b_start == true) { // B mode
// main_timer_stop();
// printf("main_loop_B\r\n");
// full_adc_start();
// }else if(pd_adc_full_c_start == true) { // C mode
// main_timer_stop();
// printf("main_loop_C\r\n");
// full_adc_start();
// }else if(pd_adc_full_d_start == true) { // D mode
// main_timer_stop();
// printf("main_loop_D\r\n");
// full_adc_start();
// }else if(pd_adc_full_end == true) { // Completed
// pd_adc_full_end = false;
// main_timer_stop();
// printf("main_loop_END\r\n");
// if(cmd_type_t == CMD_BLE) {
// full_send_timer_start();
// }
// }
#endif
// For Motion Data Sampling
/* ---- IMU 모션 데이터 읽기 ---- */
/*
* motion_raw_data_enabled가 true이면 IMU(ICM42670P) .
*
* motion_data_once == true:
* . HW I2C를 icm42670_main() 1 .
* info4 / IMU로 .
*
* motion_data_once == false:
* . BLE (ble_got_new_data==false)
* icm42670_main() 10ms .
*/
if(motion_raw_data_enabled == true) {
main_timer_stop(); /* 타이머 정지 (재진입 방지) */
if(motion_data_once == true)
{
/* 단발성 모드: HW I2C 초기화 후 IMU 데이터 1회 읽기 */
hw_i2c_init_once(); /* HW TWI 모드로 전환 (400kHz) */
icm42670_main(); /* IMU 데이터 읽기 및 처리 */
}
else{
/* 연속 모드: BLE 전송 대기 중이 아니면 반복 읽기 */
if(ble_got_new_data==false){
//for(uint16_t i=0 ; i<60 ;i++)
//{
DBG_PRINTF("IMU \r\n");
icm42670_main(); /* IMU 데이터 읽기 */
motion_raw_data_enabled = true; /* 플래그 유지 (연속 읽기) */
main_timer_start_ms(1000); /* 1초 후 다음 IMU 읽기 */
}
// else if(ble_got_new_data==true){
// motion_data_once = true;
// }
}
}
/* ---- 배터리 전압 측정 ---- */
/*
* go_batt true이면 .
* info4 IMU .
* .
*/
if(go_batt == true) {
DBG_PRINTF("IMU BATT\r\n");
main_timer_stop(); /* 타이머 정지 */
go_batt = false; /* 플래그 소비 (1회 실행) */
// go_temp = true;
battery_level_meas(); /* SAADC를 이용한 배터리 전압 측정 */
// nrf_delay_ms(20);
// m48_adc_start_init();
// main_timer_start();
}
/* ---- 온도 측정 ---- */
/*
* go_temp true이면 TMP235-Q1 .
* info4 .
* motion_data_once=true로
* IMU (HW I2C ) .
*/
if(go_temp == true) {
DBG_PRINTF("IMU Temp\r\n");
main_timer_stop(); /* 타이머 정지 */
// go_batt = false;
go_temp = false; /* 플래그 소비 (1회 실행) */
motion_data_once = true; /* 다음 IMU 읽기를 단발성 모드로 전환 */
tmp235_voltage_level_meas(); /* TMP235-Q1 온도 센서 전압 측정 */
// motion_raw_data_enabled = true;
// main_timer_start();
}
/* ---- 시스템 제어 이벤트 처리 ---- */
/* 디바이스 전원 OFF 처리 */
if(go_device_power_off == true){
main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("Off main_timer\r\n");
device_power_off(); /* 디바이스 전원 OFF 실행 */
}
/* 슬립 모드 진입 처리 */
if(go_sleep_mode_enter == true){
main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("sleep main timer\r\n");
sleep_mode_enter(); /* 슬립 모드 진입 실행 */
}
/* NVIC 시스템 리셋 처리 */
if(go_NVIC_SystemReset == true) {
main_timer_stop(); /* 타이머 정지 */
NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */
}
}
/**
* @brief
*
* MAIN_LOOP_INTERVAL(10ms 80ms) main_loop()
*/
void main_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(MAIN_LOOP_INTERVAL), NULL));
}
/**
* @brief (ms)
*
* IMU
*/
void main_timer_start_ms(uint32_t interval_ms)
{
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(interval_ms), NULL));
}
/**
* @brief
*/
void main_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_main_loop_timer_id));
}
/**
* @brief ( 1 )
*
* , main_loop()
* main_timer_start()
*/
void main_timer_init(void)
{
APP_ERROR_CHECK(app_timer_create(&m_main_loop_timer_id, APP_TIMER_MODE_SINGLE_SHOT, main_loop));
}

View File

@@ -1,37 +1,37 @@
/*******************************************************************************
* @file timer_routine.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [ ]
* .
*
* 10ms() 80ms()
* main_loop() .
*
* [ ]
* main_timer_start() : (, )
* main_timer_stop() :
* main_timer_init() : ( 1 )
*
******************************************************************************/
#ifndef TIMER_ROUTINE_H__
#define TIMER_ROUTINE_H__
/** @brief 메인 루프 타이머 시작 (싱글샷, MAIN_LOOP_INTERVAL 후 main_loop 호출) */
void main_timer_start(void);
/** @brief 지정된 간격(ms)으로 메인 루프 타이머 시작 */
void main_timer_start_ms(uint32_t interval_ms);
/** @brief 메인 루프 타이머 정지 */
void main_timer_stop(void);
/** @brief 메인 루프 타이머 초기화 (앱 시작 시 1회, 싱글샷 모드로 생성) */
void main_timer_init(void);
#endif //TIMER_ROUTINE_H__
/*******************************************************************************
* @file timer_routine.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [ ]
* .
*
* 10ms() 80ms()
* main_loop() .
*
* [ ]
* main_timer_start() : (, )
* main_timer_stop() :
* main_timer_init() : ( 1 )
*
******************************************************************************/
#ifndef TIMER_ROUTINE_H__
#define TIMER_ROUTINE_H__
/** @brief 메인 루프 타이머 시작 (싱글샷, MAIN_LOOP_INTERVAL 후 main_loop 호출) */
void main_timer_start(void);
/** @brief 지정된 간격(ms)으로 메인 루프 타이머 시작 */
void main_timer_start_ms(uint32_t interval_ms);
/** @brief 메인 루프 타이머 정지 */
void main_timer_stop(void);
/** @brief 메인 루프 타이머 초기화 (앱 시작 시 1회, 싱글샷 모드로 생성) */
void main_timer_init(void);
#endif //TIMER_ROUTINE_H__

View File

@@ -1,189 +1,189 @@
/*******************************************************************************
TEST medi50 Dec 23
//=========power_control.c====================
*******************************************************************************
*
* [ ]
* 퀀 ( / / ).
*
* [ ]
* device_activated()
* power_loop ( )
* (IMU) imu_read_direct()
*
* [ ]
* device_sleep_mode()
* processing
*
* []
* device_reactivated()
* I2C 퀀
*
* []
* app_timer, 20ms power_loop
*
******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "power_control.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "app_timer.h"
#include "debug_print.h"
#include "i2c_manager.h"
/* 전원 시퀀스용 싱글샷 타이머 인스턴스 */
APP_TIMER_DEF(m_power_timer_id);
/* 전원 시퀀스 상태머신의 타이머 간격 (20ms) */
// 2025-12-08 change to #define POWER_LOOP_INTERVAL 30 -> 20
#define POWER_LOOP_INTERVAL 20
/* 전원 시퀀스 현재 단계 (0: I2C 초기화, 1: 예약, 2: 완료) */
static uint8_t p_order;
/* 데이터 처리 중 플래그 (외부 모듈에서 선언) */
extern volatile bool processing;
/* 전원 시퀀스 잠금 플래그 (true = 전원 시퀀스 진행 중) */
bool lock_check = false;
/**
* @brief
*
* (processing)
* .
*
* @return 0 ( )
*/
int device_sleep_mode(void){
int rc = 0;
nrf_delay_ms(2);
DBG_PRINTF("Device_Sleep_Mode OK!\r\n");
nrf_delay_ms(10);
processing = false; /* 데이터 처리 플래그 해제 → 센서 처리 중단 */
return rc;
}
/**
* @brief ( 퀀 )
*
* 퀀 0 ,
* power_loop() .
*
* @return 0 ( )
*/
int device_activated(void){
int rc = 0;
p_order = 0; /* 상태머신 시작 단계 (Step 0: I2C 초기화) */
lock_check =true; /* 전원 시퀀스 진행 중 잠금 */
power_timer_start(); /* 20ms 후 power_loop() 첫 호출 */
return rc;
}
/**
* @brief Power-up sequence state machine
*
* Executes hardware initialization steps
* Called by app_timer at POWER_LOOP_INTERVAL (20ms)
*
* Sequence:
* 0: I2C init
* 1: (reserved)
* 2: Complete
*/
/*
* 퀀 (20ms ).
*
* [ ]
* 1) ()
* 2) p_order에
* 3) p_order < 2
* 4) p_order == 2 퀀
*
* imu_read_direct()
*/
void power_loop(void *p_context)
{
UNUSED_PARAMETER(p_context);
power_timer_stop(); /* 현재 타이머 정지 (싱글샷 → 수동 재시작 필요) */
/* 센서 초기화 불필요 — imu_read_direct()가 매 측정 시 자체 처리 */
/* 추후 전원 시퀀스 단계가 필요하면 여기에 switch(p_order) 추가 */
p_order = 2;
/* Advance to next step or finish */
/* 다음 단계로 진행하거나, 시퀀스 완료 처리 */
if (p_order < 2) {
p_order++; /* 다음 단계로 이동 */
power_timer_start(); /* 20ms 후 다음 단계 실행 */
} else {
/* 전원 시퀀스 전체 완료 */
DBG_PRINTF("[PWR] Device Activated OK!\r\n");
}
}
/**
* @brief ( )
*
* I2C를 , 퀀 .
* .
*
* @return 0 ( )
*/
int device_reactivated(void){
int rc = 0;
sw_i2c_init_once(); /* I2C 버스 재초기화 */
nrf_delay_ms(10); /* 안정화 대기 */
lock_check = true; /* 전원 시퀀스 진행 중 잠금 */
p_order = 0; /* 상태머신을 Step 0부터 재시작 */
power_timer_start(); /* 20ms 후 power_loop() 시작 */
return rc;
}
/**
* @brief 퀀
*
* POWER_LOOP_INTERVAL(20ms) power_loop() .
*/
void power_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_power_timer_id, APP_TIMER_TICKS(POWER_LOOP_INTERVAL), NULL));
}
/**
* @brief 퀀
*/
void power_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_power_timer_id));
}
/**
* @brief 퀀 ( 1 )
*
* , power_loop() .
* power_timer_start() .
*/
void power_timer_init(void) //active start
{
APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_SINGLE_SHOT, power_loop));
// 2025-12-08 change to APP_TIMER_MODE_REPEATED mode
//APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_REPEATED, power_loop));
}
/*******************************************************************************
TEST medi50 Dec 23
//=========power_control.c====================
*******************************************************************************
*
* [ ]
* 퀀 ( / / ).
*
* [ ]
* device_activated()
* power_loop ( )
* (IMU) imu_read_direct()
*
* [ ]
* device_sleep_mode()
* processing
*
* []
* device_reactivated()
* I2C 퀀
*
* []
* app_timer, 20ms power_loop
*
******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "power_control.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "app_timer.h"
#include "debug_print.h"
#include "i2c_manager.h"
/* 전원 시퀀스용 싱글샷 타이머 인스턴스 */
APP_TIMER_DEF(m_power_timer_id);
/* 전원 시퀀스 상태머신의 타이머 간격 (20ms) */
// 2025-12-08 change to #define POWER_LOOP_INTERVAL 30 -> 20
#define POWER_LOOP_INTERVAL 20
/* 전원 시퀀스 현재 단계 (0: I2C 초기화, 1: 예약, 2: 완료) */
static uint8_t p_order;
/* 데이터 처리 중 플래그 (외부 모듈에서 선언) */
extern volatile bool processing;
/* 전원 시퀀스 잠금 플래그 (true = 전원 시퀀스 진행 중) */
bool lock_check = false;
/**
* @brief
*
* (processing)
* .
*
* @return 0 ( )
*/
int device_sleep_mode(void){
int rc = 0;
nrf_delay_ms(2);
DBG_PRINTF("Device_Sleep_Mode OK!\r\n");
nrf_delay_ms(10);
processing = false; /* 데이터 처리 플래그 해제 → 센서 처리 중단 */
return rc;
}
/**
* @brief ( 퀀 )
*
* 퀀 0 ,
* power_loop() .
*
* @return 0 ( )
*/
int device_activated(void){
int rc = 0;
p_order = 0; /* 상태머신 시작 단계 (Step 0: I2C 초기화) */
lock_check =true; /* 전원 시퀀스 진행 중 잠금 */
power_timer_start(); /* 20ms 후 power_loop() 첫 호출 */
return rc;
}
/**
* @brief Power-up sequence state machine
*
* Executes hardware initialization steps
* Called by app_timer at POWER_LOOP_INTERVAL (20ms)
*
* Sequence:
* 0: I2C init
* 1: (reserved)
* 2: Complete
*/
/*
* 퀀 (20ms ).
*
* [ ]
* 1) ()
* 2) p_order에
* 3) p_order < 2
* 4) p_order == 2 퀀
*
* imu_read_direct()
*/
void power_loop(void *p_context)
{
UNUSED_PARAMETER(p_context);
power_timer_stop(); /* 현재 타이머 정지 (싱글샷 → 수동 재시작 필요) */
/* 센서 초기화 불필요 — imu_read_direct()가 매 측정 시 자체 처리 */
/* 추후 전원 시퀀스 단계가 필요하면 여기에 switch(p_order) 추가 */
p_order = 2;
/* Advance to next step or finish */
/* 다음 단계로 진행하거나, 시퀀스 완료 처리 */
if (p_order < 2) {
p_order++; /* 다음 단계로 이동 */
power_timer_start(); /* 20ms 후 다음 단계 실행 */
} else {
/* 전원 시퀀스 전체 완료 */
DBG_PRINTF("[PWR] Device Activated OK!\r\n");
}
}
/**
* @brief ( )
*
* I2C를 , 퀀 .
* .
*
* @return 0 ( )
*/
int device_reactivated(void){
int rc = 0;
sw_i2c_init_once(); /* I2C 버스 재초기화 */
nrf_delay_ms(10); /* 안정화 대기 */
lock_check = true; /* 전원 시퀀스 진행 중 잠금 */
p_order = 0; /* 상태머신을 Step 0부터 재시작 */
power_timer_start(); /* 20ms 후 power_loop() 시작 */
return rc;
}
/**
* @brief 퀀
*
* POWER_LOOP_INTERVAL(20ms) power_loop() .
*/
void power_timer_start(void)
{
APP_ERROR_CHECK(app_timer_start(m_power_timer_id, APP_TIMER_TICKS(POWER_LOOP_INTERVAL), NULL));
}
/**
* @brief 퀀
*/
void power_timer_stop(void)
{
APP_ERROR_CHECK(app_timer_stop(m_power_timer_id));
}
/**
* @brief 퀀 ( 1 )
*
* , power_loop() .
* power_timer_start() .
*/
void power_timer_init(void) //active start
{
APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_SINGLE_SHOT, power_loop));
// 2025-12-08 change to APP_TIMER_MODE_REPEATED mode
//APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_REPEATED, power_loop));
}

View File

@@ -1,48 +1,48 @@
/*******************************************************************************
* @file power_control.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [ ]
* 퀀 .
*
* [ ]
* device_activated() : power_loop
* device_sleep_mode() : ( )
* device_reactivated() : 퀀
* power_loop() : 20ms 퀀
* power_timer_start/stop : 퀀
* power_timer_init() : 퀀 ( 1)
*
******************************************************************************/
#ifndef _POWER_CONTROL_H_
#define _POWER_CONTROL_H_
#include "main.h"
/** @brief 디바이스 슬립 모드 진입 (processing 해제) */
int device_sleep_mode(void);
/** @brief 디바이스 전원 켜기 (전원 시퀀스 상태머신 시작) */
int device_activated(void);
/** @brief 디바이스 재활성화 (슬립 복귀 시 I2C 재초기화 후 시퀀스 재시작) */
int device_reactivated(void);
/** @brief 전원 시퀀스 상태머신 (20ms 타이머 콜백, Step 0→1→2) */
void power_loop(void * p_context); /* For x ms */
/** @brief 전원 시퀀스 타이머 시작 (20ms 싱글샷) */
void power_timer_start(void);
/** @brief 전원 시퀀스 타이머 정지 */
void power_timer_stop(void);;
/** @brief 전원 시퀀스 타이머 초기화 (앱 시작 시 1회 호출) */
void power_timer_init(void);
#endif //_POWER_CONTROL_H_
/*******************************************************************************
* @file power_control.h
* @author CandyPops Co.
* @version V1.0.0
* @date 2022-09-05
* @brief
*******************************************************************************
*
* [ ]
* 퀀 .
*
* [ ]
* device_activated() : power_loop
* device_sleep_mode() : ( )
* device_reactivated() : 퀀
* power_loop() : 20ms 퀀
* power_timer_start/stop : 퀀
* power_timer_init() : 퀀 ( 1)
*
******************************************************************************/
#ifndef _POWER_CONTROL_H_
#define _POWER_CONTROL_H_
#include "main.h"
/** @brief 디바이스 슬립 모드 진입 (processing 해제) */
int device_sleep_mode(void);
/** @brief 디바이스 전원 켜기 (전원 시퀀스 상태머신 시작) */
int device_activated(void);
/** @brief 디바이스 재활성화 (슬립 복귀 시 I2C 재초기화 후 시퀀스 재시작) */
int device_reactivated(void);
/** @brief 전원 시퀀스 상태머신 (20ms 타이머 콜백, Step 0→1→2) */
void power_loop(void * p_context); /* For x ms */
/** @brief 전원 시퀀스 타이머 시작 (20ms 싱글샷) */
void power_timer_start(void);
/** @brief 전원 시퀀스 타이머 정지 */
void power_timer_stop(void);;
/** @brief 전원 시퀀스 타이머 초기화 (앱 시작 시 1회 호출) */
void power_timer_init(void);
#endif //_POWER_CONTROL_H_