Initial commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*==============================================================================
|
||||
* cmd_common.h - Shared header for command handlers
|
||||
*
|
||||
* Bundles every include / extern declaration / macro used in common across
|
||||
* the cmd_*.c modules. A handler module only needs this header plus its own
|
||||
* area-specific driver headers.
|
||||
*============================================================================*/
|
||||
#ifndef CMD_COMMON_H
|
||||
#define CMD_COMMON_H
|
||||
|
||||
#include "parser.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "debug_print.h"
|
||||
#include "dr_util.h"
|
||||
#include "main.h"
|
||||
#include "app_timer.h"
|
||||
#include "fstorage.h" /* config_data_t */
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* BLE transmission / formatting (defined in main.c)
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern uint8_t ble_bin_buffer[];
|
||||
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
|
||||
extern void ascii_format_data(uint8_t *buffer, const char *tag, const char *ascii, size_t length);
|
||||
extern void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length);
|
||||
extern void dr_binary_tx_safe(const uint8_t *buffer, uint16_t length); /* length: word count */
|
||||
extern void dr_sd_delay_ms(uint32_t ms);
|
||||
extern volatile bool data_tx_in_progress;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Device state / flags
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern bool device_status;
|
||||
extern bool con_single;
|
||||
extern bool lock_check;
|
||||
extern uint8_t resetCount;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Measurement functions (defined elsewhere)
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern void battery_level_meas(void);
|
||||
extern void pressure_all_level_meas(void);
|
||||
extern void tmp235_voltage_level_meas(void);
|
||||
extern int imu_read_direct(void);
|
||||
extern void battery_timer_stop(void);
|
||||
extern void main_timer_start(void);
|
||||
extern void hw_i2c_init_once(void);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* info4 mode sensor cache (used to assemble the rbb: response in mbb?)
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern bool info4;
|
||||
extern bool ble_got_new_data;
|
||||
extern bool go_batt;
|
||||
extern bool motion_data_once;
|
||||
extern bool motion_raw_data_enabled;
|
||||
extern volatile uint16_t info_batt;
|
||||
extern volatile uint16_t info_temp;
|
||||
extern volatile uint16_t info_imu[6];
|
||||
extern volatile bool tmp235_saadc_done;
|
||||
extern volatile bool battery_saadc_done;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Device identifiers / passkey (FDS-backed)
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern char SERIAL_NO[12];
|
||||
extern char HW_NO[12];
|
||||
extern char m_static_passkey[6];
|
||||
extern uint32_t m_life_cycle;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Power / reset / bonding control
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern bool go_device_power_off;
|
||||
extern bool go_NVIC_SystemReset;
|
||||
extern bool bond_data_delete;
|
||||
extern uint8_t m_reset_status;
|
||||
extern void config_save(void);
|
||||
extern config_data_t m_config;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* AGC gain switch (P0.20)
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define GAIN_SW_PIN NRF_GPIO_PIN_MAP(0, 20)
|
||||
#define AGC_GAIN_SW(x) do { if(x) nrf_gpio_pin_set(GAIN_SW_PIN); else nrf_gpio_pin_clear(GAIN_SW_PIN); } while(0)
|
||||
|
||||
#endif /* CMD_COMMON_H */
|
||||
@@ -0,0 +1,62 @@
|
||||
/*==============================================================================
|
||||
* cmd_table.c - Command table definition
|
||||
*
|
||||
* This file is the only linkage point between parser.c and the cmd_*.c handler modules.
|
||||
* It pulls in every cmd_*.h to gather handler prototypes,
|
||||
* builds the CmdEntry array, and injects the table into the parser via dr_parser_init() inside cmd_table_init().
|
||||
*
|
||||
* Adding a new command:
|
||||
* 1) Implement the handler in the appropriate cmd_*.c
|
||||
* 2) Add the prototype to the matching cmd_*.h
|
||||
* 3) Append { "tag?", true, Cmd_xxx } to m_cmd_table[] below
|
||||
*============================================================================*/
|
||||
|
||||
#include "parser.h"
|
||||
#include "cmd_table.h"
|
||||
#include "cmd_device.h"
|
||||
#include "cmd_info.h"
|
||||
#include "cmd_sensor.h"
|
||||
#include "cmd_piezo.h"
|
||||
|
||||
static const CmdEntry m_cmd_table[] = {
|
||||
/* A. Device state control */
|
||||
{ "msq?", true, Cmd_msq },
|
||||
{ "mss?", true, Cmd_mss },
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
{ "msr?", true, Cmd_msr },
|
||||
#endif
|
||||
{ "cmd?", true, Cmd_cmd },
|
||||
|
||||
/* B. Device information */
|
||||
{ "mfv?", true, Cmd_mfv },
|
||||
{ "mid?", true, Cmd_mid },
|
||||
{ "mwh?", true, Cmd_mwh },
|
||||
{ "mws?", true, Cmd_mws },
|
||||
{ "mrh?", true, Cmd_mrh },
|
||||
{ "mrs?", true, Cmd_mrs },
|
||||
{ "mpz?", true, Cmd_mpz },
|
||||
{ "mqz?", true, Cmd_mqz },
|
||||
|
||||
/* C. Sensor measurement */
|
||||
{ "msn?", true, Cmd_msn },
|
||||
{ "mst?", true, Cmd_mst },
|
||||
{ "msp?", true, Cmd_msp },
|
||||
|
||||
/* D. Piezo ultrasound */
|
||||
{ "mpa?", true, Cmd_mpa },
|
||||
{ "mpb?", true, Cmd_mpb },
|
||||
{ "mpc?", true, Cmd_mpc },
|
||||
{ "mec?", true, Cmd_mec },
|
||||
{ "maa?", true, Cmd_maa },
|
||||
{ "mbb?", true, Cmd_mbb },
|
||||
{ "mcf?", true, Cmd_mcf },
|
||||
{ "mcs?", true, Cmd_mcs },
|
||||
|
||||
/* E. LED control (handler in cmd_device.c) */
|
||||
{ "mls?", true, Cmd_mls },
|
||||
};
|
||||
|
||||
void cmd_table_init(void)
|
||||
{
|
||||
dr_parser_init(m_cmd_table, sizeof(m_cmd_table) / sizeof(m_cmd_table[0]));
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*==============================================================================
|
||||
* cmd_table.h - Command table registration entry point
|
||||
*
|
||||
* main.c calls cmd_table_init() at boot to inject the command table into
|
||||
* the parser.
|
||||
*============================================================================*/
|
||||
#ifndef CMD_TABLE_H
|
||||
#define CMD_TABLE_H
|
||||
|
||||
void cmd_table_init(void);
|
||||
|
||||
#endif /* CMD_TABLE_H */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*==============================================================================
|
||||
* dr_util.c - BLE response formatting helpers
|
||||
*
|
||||
* Convenience wrappers used by command handlers to assemble and transmit
|
||||
* short BLE responses. Each helper prepends a 4-char TAG and writes the
|
||||
* supplied uint16 values in Big-Endian order.
|
||||
*============================================================================*/
|
||||
|
||||
#include "dr_util.h"
|
||||
#include "parser.h"
|
||||
|
||||
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
|
||||
extern void format_data(uint8_t *buffer, const char *tag, uint16_t *data, uint8_t length);
|
||||
extern uint8_t ble_bin_buffer[];
|
||||
extern void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
|
||||
void dr_ble_return_1(const char *tag, uint16_t value)
|
||||
{
|
||||
single_format_data(ble_bin_buffer, tag, value);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3); /* Use safe TX with retry */
|
||||
}
|
||||
|
||||
void dr_ble_return_2(const char *tag, uint16_t v1, uint16_t v2)
|
||||
{
|
||||
ble_bin_buffer[0] = tag[0];
|
||||
ble_bin_buffer[1] = tag[1];
|
||||
ble_bin_buffer[2] = tag[2];
|
||||
ble_bin_buffer[3] = tag[3];
|
||||
|
||||
ble_bin_buffer[4] = (uint8_t)(v1 >> 8);
|
||||
ble_bin_buffer[5] = (uint8_t)(v1 & 0xFF);
|
||||
ble_bin_buffer[6] = (uint8_t)(v2 >> 8);
|
||||
ble_bin_buffer[7] = (uint8_t)(v2 & 0xFF);
|
||||
|
||||
dr_binary_tx_safe(ble_bin_buffer, 4); /* Use safe TX with retry */
|
||||
}
|
||||
|
||||
void dr_ble_return_3(const char *tag, uint16_t v1, uint16_t v2, uint16_t v3)
|
||||
{
|
||||
ble_bin_buffer[0] = tag[0];
|
||||
ble_bin_buffer[1] = tag[1];
|
||||
ble_bin_buffer[2] = tag[2];
|
||||
ble_bin_buffer[3] = tag[3];
|
||||
|
||||
ble_bin_buffer[4] = (uint8_t)(v1 >> 8);
|
||||
ble_bin_buffer[5] = (uint8_t)(v1 & 0xFF);
|
||||
ble_bin_buffer[6] = (uint8_t)(v2 >> 8);
|
||||
ble_bin_buffer[7] = (uint8_t)(v2 & 0xFF);
|
||||
ble_bin_buffer[8] = (uint8_t)(v3 >> 8);
|
||||
ble_bin_buffer[9] = (uint8_t)(v3 & 0xFF);
|
||||
|
||||
dr_binary_tx_safe(ble_bin_buffer, 5); /* Use safe TX with retry */
|
||||
}
|
||||
|
||||
void dr_ble_debug(uint16_t point_id, uint16_t value)
|
||||
{
|
||||
/* Use dedicated buffer to avoid conflicts with ble_bin_buffer */
|
||||
static uint8_t dbg_buffer[8] = {0};
|
||||
|
||||
dbg_buffer[0] = 'd';
|
||||
dbg_buffer[1] = 'b';
|
||||
dbg_buffer[2] = 'g';
|
||||
dbg_buffer[3] = ':';
|
||||
|
||||
dbg_buffer[4] = (uint8_t)(point_id >> 8);
|
||||
dbg_buffer[5] = (uint8_t)(point_id & 0xFF);
|
||||
dbg_buffer[6] = (uint8_t)(value >> 8);
|
||||
dbg_buffer[7] = (uint8_t)(value & 0xFF);
|
||||
|
||||
dr_binary_tx_safe(dbg_buffer, 4);
|
||||
}
|
||||
|
||||
void dr_ble_return_piezo_1(const char *tag, uint16_t value)
|
||||
{
|
||||
/* Use dedicated buffer for piezo responses to avoid conflicts with ble_bin_buffer */
|
||||
static uint8_t piezo_buffer[8] = {0};
|
||||
|
||||
piezo_buffer[0] = tag[0];
|
||||
piezo_buffer[1] = tag[1];
|
||||
piezo_buffer[2] = tag[2];
|
||||
piezo_buffer[3] = tag[3];
|
||||
|
||||
piezo_buffer[4] = (uint8_t)(value >> 8);
|
||||
piezo_buffer[5] = (uint8_t)(value & 0xFF);
|
||||
|
||||
dr_binary_tx_safe(piezo_buffer, 3); /* 6 bytes = 3 words */
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*==============================================================================
|
||||
* dr_util.h - BLE response helper API
|
||||
*============================================================================*/
|
||||
#ifndef DR_UTIL_H
|
||||
#define DR_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void dr_ble_return_1(const char *tag, uint16_t value);
|
||||
void dr_ble_return_2(const char *tag, uint16_t v1, uint16_t v2);
|
||||
void dr_ble_return_3(const char *tag, uint16_t v1, uint16_t v2, uint16_t v3);
|
||||
void dr_ble_return_3_be(const char *tag, uint16_t v1, uint16_t v2, uint16_t v3);
|
||||
|
||||
/* Piezo dedicated BLE return - uses a separate buffer to avoid conflicts. */
|
||||
void dr_ble_return_piezo_1(const char *tag, uint16_t value);
|
||||
|
||||
/* BLE debug output - sends "dbg:" + point_id + value. */
|
||||
void dr_ble_debug(uint16_t point_id, uint16_t value);
|
||||
|
||||
#endif /* DR_UTIL_H */
|
||||
@@ -0,0 +1,177 @@
|
||||
/*==============================================================================
|
||||
* cmd_device.c - Device state control handlers
|
||||
*
|
||||
* A. msq? -> rsq: device power OFF
|
||||
* B. mss? -> rss: device soft reset
|
||||
* C. msr? -> rsr: BLE bond delete + reset (FEATURE_SECURE_CONNECTION)
|
||||
* D. cmd? -> rmd: direct GPIO pin control (debug / test only)
|
||||
* E. mls? -> rls: set LED state
|
||||
*============================================================================*/
|
||||
|
||||
#include "cmd_common.h"
|
||||
#include "cmd_device.h"
|
||||
#include "fstorage.h"
|
||||
#include "led_control.h"
|
||||
|
||||
/*==============================================================================
|
||||
* msq? -> rsq: Device power OFF
|
||||
*
|
||||
* Request: [TAG 4B "msq?"] [val 2B BE] [CRC 2B]
|
||||
* Response: [TAG 4B "rsq:"] [val 2B BE] [CRC 2B]
|
||||
*
|
||||
* Sends BLE response first; the actual power-off is performed from the main loop.
|
||||
* Powering off immediately would prevent the response from reaching the host, so a flag + timer pattern is used instead.
|
||||
*============================================================================*/
|
||||
int Cmd_msq(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
dr_get_u16(cmd, 0, &val);
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[Cmd_msq] Power off val=%u\r\n", val);
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "rsq:", val);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
go_device_power_off = true;
|
||||
main_timer_start();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mss? -> rss: Device soft reset
|
||||
*
|
||||
* Request: [TAG 4B "mss?"] [val 2B BE] [CRC 2B]
|
||||
* Response: [TAG 4B "rss:"] [val 2B BE] [CRC 2B]
|
||||
*
|
||||
* Resets without erasing bond information. Reset status code is persisted to FDS so the boot path can identify the cause.
|
||||
*============================================================================*/
|
||||
int Cmd_mss(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
dr_get_u16(cmd, 0, &val);
|
||||
single_format_data(ble_bin_buffer, "rss:", val);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
|
||||
m_reset_status = 2;
|
||||
m_config.reset_status = m_reset_status;
|
||||
config_save();
|
||||
nrf_delay_ms(5);
|
||||
go_NVIC_SystemReset = true;
|
||||
main_timer_start();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* msr? -> rsr: Delete BLE bonding info + system reset
|
||||
*
|
||||
* Request: [TAG 4B "msr?"] [val 2B BE] [CRC 2B]
|
||||
* Response: [TAG 4B "rsr:"] [val 2B BE] [CRC 2B]
|
||||
*
|
||||
* 1. Send BLE response
|
||||
* 2. Persist bond-delete flag and reset status to FDS
|
||||
* 3. Wait 5 ms for FDS write completion
|
||||
* 4. Set NVIC system reset flag
|
||||
*============================================================================*/
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
int Cmd_msr(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
dr_get_u16(cmd, 0, &val);
|
||||
single_format_data(ble_bin_buffer, "rsr:", val);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 2);
|
||||
|
||||
bond_data_delete = true;
|
||||
m_config.bond_data_delete = (uint8_t)bond_data_delete;
|
||||
m_reset_status = 2;
|
||||
m_config.reset_status = m_reset_status;
|
||||
config_save();
|
||||
nrf_delay_ms(5);
|
||||
go_NVIC_SystemReset = true;
|
||||
main_timer_start();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* cmd? -> rmd: Direct GPIO pin control (debug / test)
|
||||
*
|
||||
* Request: [TAG 4B "cmd?"] [port 2B BE] [pin 2B BE] [state 2B BE] [CRC 2B]
|
||||
* Response: [TAG 4B "rmd:"] [port 2B BE] [pin 2B BE] [state 2B BE] [CRC 2B]
|
||||
* Error: rmd: + 0 (insufficient data)
|
||||
*
|
||||
* port : GPIO port (0 or 1)
|
||||
* pin : pin number (0..31)
|
||||
* state: 1=HIGH, 0=LOW
|
||||
*
|
||||
* Misuse can damage hardware - intended for debug only.
|
||||
*============================================================================*/
|
||||
int Cmd_cmd(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t v1, v2, v3;
|
||||
uint32_t pin_number;
|
||||
|
||||
if (cmd->data_len < 6)
|
||||
{
|
||||
dr_ble_return_1("rmd:", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dr_get_u16(cmd, 0, &v1))
|
||||
{
|
||||
v1 = 0;
|
||||
}
|
||||
if (!dr_get_u16(cmd, 1, &v2))
|
||||
{
|
||||
v2 = 0;
|
||||
}
|
||||
if (!dr_get_u16(cmd, 2, &v3))
|
||||
{
|
||||
v3 = 0;
|
||||
}
|
||||
|
||||
pin_number = NRF_GPIO_PIN_MAP(v1, v2);
|
||||
nrf_gpio_cfg_output(pin_number);
|
||||
|
||||
if (v3 == 1)
|
||||
{
|
||||
nrf_gpio_pin_set(pin_number);
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_gpio_pin_clear(pin_number);
|
||||
}
|
||||
|
||||
dr_ble_return_3("rmd:", v1, v2, v3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mls? -> rls: Set LED state (app -> device)
|
||||
*
|
||||
* Request: [TAG 4B "mls?"] [state 2B BE] [CRC 2B]
|
||||
* state: led_state_t enum value: 0=OFF, 4=DETACH_WARNING, 5=ALIGN_SEARCHING, 6=ALIGN_COMPLETE
|
||||
* Response: [TAG 4B "rls:"] [state 2B] [CRC 2B]
|
||||
* Error: rls: + 0xFFFF (insufficient data)
|
||||
* rls: + 0xFFFE (state out of range)
|
||||
*============================================================================*/
|
||||
int Cmd_mls(const ParsedCmd *cmd)
|
||||
{
|
||||
if (cmd->data_len < 2)
|
||||
{
|
||||
dr_ble_return_1("rls:", 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t state;
|
||||
dr_get_u16(cmd, 0, &state);
|
||||
|
||||
if (state > LED_STATE_ERROR)
|
||||
{
|
||||
dr_ble_return_1("rls:", 0xFFFE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
led_set_state((led_state_t)state);
|
||||
dr_ble_return_1("rls:", state);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*==============================================================================
|
||||
* cmd_device.h - Device state control handlers (power / reset / GPIO / LED)
|
||||
*============================================================================*/
|
||||
#ifndef CMD_DEVICE_H
|
||||
#define CMD_DEVICE_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
int Cmd_msq(const ParsedCmd *cmd); /* msq? -> rsq: device power OFF */
|
||||
int Cmd_mss(const ParsedCmd *cmd); /* mss? -> rss: device soft reset */
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
int Cmd_msr(const ParsedCmd *cmd); /* msr? -> rsr: bond delete + reset */
|
||||
#endif
|
||||
int Cmd_cmd(const ParsedCmd *cmd); /* cmd? -> rmd: direct GPIO control */
|
||||
int Cmd_mls(const ParsedCmd *cmd); /* mls? -> rls: set LED state */
|
||||
|
||||
#endif /* CMD_DEVICE_H */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*==============================================================================
|
||||
* cmd_info.c - Device information read/write handlers
|
||||
*
|
||||
* Commands that read or write FDS-persisted data: firmware version, hardware version, serial number, BLE passkey.
|
||||
* Typically written once at the factory and read back later for identification.
|
||||
*============================================================================*/
|
||||
|
||||
#include "cmd_common.h"
|
||||
#include "cmd_info.h"
|
||||
#include "fstorage.h"
|
||||
|
||||
/*==============================================================================
|
||||
* mfv? -> rfv: Read firmware version
|
||||
*
|
||||
* Request: [TAG 4B "mfv?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rfv:"] [FW_VER 12B ASCII] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mfv(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
ascii_format_data(ble_bin_buffer, "rfv:", FIRMWARE_VERSION, 12);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8); /* 16 bytes = 8 words */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mid? -> rid: Read HW number + serial number + FW version together
|
||||
*
|
||||
* Request: [TAG 4B "mid?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rid:"] [HW 12B] [SN 12B] [FW 12B] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mid(const ParsedCmd *cmd)
|
||||
{
|
||||
uint8_t *buf = ble_bin_buffer;
|
||||
(void)cmd;
|
||||
|
||||
memcpy(HW_NO, m_config.hw_no, 12);
|
||||
memcpy(SERIAL_NO, m_config.serial_no, 12);
|
||||
|
||||
buf[0] = 'r'; buf[1] = 'i'; buf[2] = 'd'; buf[3] = ':';
|
||||
memcpy(&buf[4], HW_NO, 12);
|
||||
memcpy(&buf[16], SERIAL_NO, 12);
|
||||
memcpy(&buf[28], FIRMWARE_VERSION, 12);
|
||||
|
||||
dr_binary_tx_safe(buf, 20); /* 40 bytes = 20 words */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mwh? -> rwh: Write HW number to FDS
|
||||
*
|
||||
* Request: [TAG 4B "mwh?"] [HW 12B ASCII] [CRC 2B]
|
||||
* Response: [TAG 4B "rwh:"] [HW 12B ASCII] [CRC 2B]
|
||||
* Error: rwh: + 0xFFFF (insufficient data)
|
||||
*============================================================================*/
|
||||
int Cmd_mwh(const ParsedCmd *cmd)
|
||||
{
|
||||
char buf[13];
|
||||
|
||||
if (cmd->data_len < 12)
|
||||
{
|
||||
dr_ble_return_1("rwh:", 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dr_get_ascii(cmd, 0, buf, 12);
|
||||
memcpy(HW_NO, buf, 12);
|
||||
memcpy(m_config.hw_no, buf, 12);
|
||||
config_save();
|
||||
|
||||
ascii_format_data(ble_bin_buffer, "rwh:", buf, 12);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mws? -> rws: Write serial number to FDS
|
||||
*
|
||||
* Request: [TAG 4B "mws?"] [SN 12B ASCII] [CRC 2B]
|
||||
* Response: [TAG 4B "rws:"] [SN 12B ASCII] [CRC 2B]
|
||||
* Error: rws: + 0xFFFF (insufficient data)
|
||||
*============================================================================*/
|
||||
int Cmd_mws(const ParsedCmd *cmd)
|
||||
{
|
||||
char buf[13];
|
||||
|
||||
if (cmd->data_len < 12)
|
||||
{
|
||||
dr_ble_return_1("rws:", 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dr_get_ascii(cmd, 0, buf, 12);
|
||||
memcpy(SERIAL_NO, buf, 12);
|
||||
memcpy(m_config.serial_no, buf, 12);
|
||||
config_save();
|
||||
|
||||
ascii_format_data(ble_bin_buffer, "rws:", buf, 12);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mrh? -> rrh: Read HW number from FDS
|
||||
*
|
||||
* Request: [TAG 4B "mrh?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rrh:"] [HW 12B ASCII] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mrh(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
memcpy(HW_NO, m_config.hw_no, 12);
|
||||
ascii_format_data(ble_bin_buffer, "rrh:", HW_NO, 12);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mrs? -> rrs: Read serial number from FDS
|
||||
*
|
||||
* Request: [TAG 4B "mrs?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rrs:"] [SN 12B ASCII] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mrs(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
memcpy(SERIAL_NO, m_config.serial_no, 12);
|
||||
ascii_format_data(ble_bin_buffer, "rrs:", SERIAL_NO, 12);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mpz? -> rpz: Write BLE passkey to FDS
|
||||
*
|
||||
* Request: [TAG 4B "mpz?"] [passkey 6B ASCII] [CRC 2B]
|
||||
* Response: [TAG 4B "rpz:"] [passkey 6B ASCII] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mpz(const ParsedCmd *cmd)
|
||||
{
|
||||
if (m_config.factory_provisioned != 0)
|
||||
{
|
||||
dr_ble_return_1("rpz:", 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char passkey[7] = {0};
|
||||
dr_get_ascii(cmd, 0, passkey, 6);
|
||||
|
||||
memcpy(m_static_passkey, passkey, 6);
|
||||
memcpy(m_config.static_passkey, m_static_passkey, 6);
|
||||
m_config.factory_provisioned = 1;
|
||||
config_save();
|
||||
|
||||
ascii_format_data(ble_bin_buffer, "rpz:", passkey, 6);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 5);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mqz? -> rqz: Read BLE passkey from FDS
|
||||
*
|
||||
* Request: [TAG 4B "mqz?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rqz:"] [passkey 6B ASCII] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mqz(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
memcpy(m_static_passkey, m_config.static_passkey, 6);
|
||||
ascii_format_data(ble_bin_buffer, "rqz:", m_static_passkey, 6);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 5);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*==============================================================================
|
||||
* cmd_info.h - Device information read/write handlers
|
||||
*============================================================================*/
|
||||
#ifndef CMD_INFO_H
|
||||
#define CMD_INFO_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
int Cmd_mfv(const ParsedCmd *cmd); /* mfv? -> rfv: read firmware version */
|
||||
int Cmd_mid(const ParsedCmd *cmd); /* mid? -> rid: read HW + SN + FW together */
|
||||
int Cmd_mwh(const ParsedCmd *cmd); /* mwh? -> rwh: write HW number */
|
||||
int Cmd_mws(const ParsedCmd *cmd); /* mws? -> rws: write serial number */
|
||||
int Cmd_mrh(const ParsedCmd *cmd); /* mrh? -> rrh: read HW number */
|
||||
int Cmd_mrs(const ParsedCmd *cmd); /* mrs? -> rrs: read serial number */
|
||||
int Cmd_mpz(const ParsedCmd *cmd); /* mpz? -> rpz: write BLE passkey */
|
||||
int Cmd_mqz(const ParsedCmd *cmd); /* mqz? -> rqz: read BLE passkey */
|
||||
|
||||
#endif /* CMD_INFO_H */
|
||||
@@ -0,0 +1,343 @@
|
||||
/*==============================================================================
|
||||
* cmd_piezo.c - Piezo ultrasound measurement handlers
|
||||
*
|
||||
* mpa? -> rpa: TX/RX power ON
|
||||
* mpb? -> rpb: TX/RX power OFF
|
||||
* mpc? -> rpc: burst generation (test)
|
||||
* mec? -> reb:+raa: single-channel burst + echo capture
|
||||
* maa? -> reb:+raa: 6-channel asynchronous capture
|
||||
* mbb? -> rbb:+reb:+raa: bulk sensor measurement + 6-channel capture
|
||||
* mcf? -> rcf: read piezo parameters
|
||||
* mcs? -> rcs: write piezo parameters
|
||||
*============================================================================*/
|
||||
|
||||
#include "cmd_common.h"
|
||||
#include "cmd_piezo.h"
|
||||
#include "cmd_sensor.h" /* all_sensors() */
|
||||
#include "dr_piezo.h"
|
||||
#include "dr_adc121s051.h"
|
||||
|
||||
/*==============================================================================
|
||||
* mpa? -> rpa: Enable piezo TX/RX circuit
|
||||
*
|
||||
* Request: [TAG 4B "mpa?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rpa:"] [1 2B] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mpa(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
dr_piezo_power_on();
|
||||
|
||||
if (g_plat.tx_bin)
|
||||
{
|
||||
single_format_data(ble_bin_buffer, "rpa:", 1);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mpb? -> rpb: Disable piezo TX/RX circuit
|
||||
*
|
||||
* Request: [TAG 4B "mpb?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rpb:"] [1 2B] [CRC 2B]
|
||||
*
|
||||
* Power saving once measurement is complete.
|
||||
*============================================================================*/
|
||||
int Cmd_mpb(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
dr_piezo_power_off();
|
||||
|
||||
if (g_plat.tx_bin)
|
||||
{
|
||||
single_format_data(ble_bin_buffer, "rpb:", 1);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mpc? -> rpc: Piezo burst generation (test / debug)
|
||||
*
|
||||
* Request: [TAG 4B "mpc?"] [cycles 2B] [freq_option 2B] [piezo_ch 2B] [CRC 2B]
|
||||
* cycles : 3..7 (default 5)
|
||||
* freq_option : 0=1.8MHz, 1=2.1MHz(default), 2=2.0MHz, 3=1.7MHz, 4=2.2MHz
|
||||
* piezo_ch : 0..7
|
||||
* Response: [TAG 4B "rpc:"] [cycles 2B] [CRC 2B]
|
||||
* Error: rpc: + 2 (cycles out of range)
|
||||
*
|
||||
* Generates the burst only - no echo capture.
|
||||
*============================================================================*/
|
||||
int Cmd_mpc(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t cycles = 5;
|
||||
uint16_t freq_option = 1;
|
||||
uint16_t piezo_ch = 0;
|
||||
|
||||
(void)dr_get_u16(cmd, 0, &cycles);
|
||||
(void)dr_get_u16(cmd, 1, &freq_option);
|
||||
(void)dr_get_u16(cmd, 2, &piezo_ch);
|
||||
|
||||
if (piezo_ch >= MAA_NUM_CHANNELS)
|
||||
{
|
||||
piezo_ch = 0;
|
||||
}
|
||||
|
||||
if (cycles < 3 || cycles > 7)
|
||||
{
|
||||
dr_ble_return_1("rpc:", 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dr_piezo_select_channel((uint8_t)piezo_ch);
|
||||
|
||||
switch (freq_option)
|
||||
{
|
||||
case 0:
|
||||
dr_piezo_burst_sw_18mhz((uint8_t)cycles);
|
||||
break;
|
||||
case 2:
|
||||
dr_piezo_burst_sw_20mhz((uint8_t)cycles);
|
||||
break;
|
||||
case 3:
|
||||
dr_piezo_burst_sw_17mhz((uint8_t)cycles);
|
||||
break;
|
||||
case 4:
|
||||
dr_piezo_burst_sw_22mhz((uint8_t)cycles);
|
||||
break;
|
||||
default:
|
||||
dr_piezo_burst_sw((uint8_t)cycles);
|
||||
break;
|
||||
}
|
||||
|
||||
dr_ble_return_1("rpc:", (uint8_t)cycles);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mec? -> reb:+raa: Piezo burst + echo capture (16-bit raw)
|
||||
*
|
||||
* Request: [TAG 4B "mec?"] [freq 2B] [delay_us 2B] [num_samples 2B]
|
||||
* [cycles 2B] [averaging 2B] [piezo_ch 2B] [CRC 2B]
|
||||
* Response: reb: [num_samples 2B] [raw_data up to 238B] (red: follow-up if needed)
|
||||
* raa: [status 2B]
|
||||
* Error: rer: + (0xEE00|err) + num_samples
|
||||
*
|
||||
* Sends raw 16-bit ADC values directly. Suited for short-range (~25cm).
|
||||
*============================================================================*/
|
||||
int Cmd_mec(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t freq_option = 0;
|
||||
uint16_t delay_us = 20;
|
||||
uint16_t num_samples = 140;
|
||||
uint16_t cycles = 5;
|
||||
uint16_t averaging = 1;
|
||||
uint16_t piezo_ch = 0;
|
||||
|
||||
if (!dr_piezo_is_power_on())
|
||||
{
|
||||
dr_piezo_power_on();
|
||||
}
|
||||
|
||||
(void)dr_get_u16(cmd, 0, &freq_option);
|
||||
(void)dr_get_u16(cmd, 1, &delay_us);
|
||||
(void)dr_get_u16(cmd, 2, &num_samples);
|
||||
(void)dr_get_u16(cmd, 3, &cycles);
|
||||
(void)dr_get_u16(cmd, 4, &averaging);
|
||||
(void)dr_get_u16(cmd, 5, &piezo_ch);
|
||||
|
||||
if (averaging == 0)
|
||||
{
|
||||
averaging = 1;
|
||||
}
|
||||
if (averaging > 1000)
|
||||
{
|
||||
averaging = 1000;
|
||||
}
|
||||
if (piezo_ch >= MAA_NUM_CHANNELS)
|
||||
{
|
||||
piezo_ch = 0;
|
||||
}
|
||||
|
||||
dr_adc_err_t err = dr_adc_burst_capture_transmit(
|
||||
(uint8_t)freq_option, delay_us, num_samples, (uint8_t)cycles,
|
||||
(uint16_t)averaging, (uint8_t)piezo_ch, ble_bin_buffer, 0);
|
||||
|
||||
if (err != DR_ADC_OK)
|
||||
{
|
||||
dr_ble_return_2("rer:", 0xEE00 | (uint16_t)err, num_samples);
|
||||
}
|
||||
|
||||
dr_piezo_power_off();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* maa? -> reb:+raa: 6-channel asynchronous full capture
|
||||
*
|
||||
* Request: [TAG 4B "maa?"] [CRC 2B]
|
||||
* Response: per channel reb: [num_samples 2B] [raw_data...]
|
||||
* final raa: [status 2B]
|
||||
* Error: raa: + 0xFFFE (previous capture in progress)
|
||||
* raa: + (0xFF00|err) (start failed)
|
||||
*
|
||||
* Asynchronous state machine - the BLE_NUS_EVT_TX_RDY callback drives the
|
||||
* follow-up packet transmissions. Parameters are loaded from m_config (FDS).
|
||||
*============================================================================*/
|
||||
int Cmd_maa(const ParsedCmd *cmd)
|
||||
{
|
||||
dr_adc_err_t err;
|
||||
(void)cmd;
|
||||
|
||||
if (maa_async_is_busy())
|
||||
{
|
||||
dr_ble_return_1("raa:", 0xFFFE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dr_piezo_is_power_on())
|
||||
{
|
||||
dr_piezo_power_on();
|
||||
}
|
||||
|
||||
err = maa_async_start(
|
||||
m_config.piezo_freq_option,
|
||||
m_config.piezo_delay_us,
|
||||
m_config.piezo_num_samples,
|
||||
m_config.piezo_cycles,
|
||||
m_config.piezo_averaging,
|
||||
ble_bin_buffer
|
||||
);
|
||||
|
||||
if (err != DR_ADC_OK)
|
||||
{
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[Cmd_maa] start failed err=%d\r\n", err);
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err));
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
dr_piezo_power_off();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mbb? -> rbb:+reb:+raa: Bulk sensor measurement + 6-channel full capture
|
||||
*
|
||||
* Request: [TAG 4B "mbb?"] [CRC 2B]
|
||||
* Response: rbb: [batt 2B] [IMU 12B] [temp 2B]
|
||||
* reb: [num_samples 2B] [raw_data...] (per channel)
|
||||
* raa: [status 2B]
|
||||
* Error: raa: + 0xFFFE (previous capture in progress)
|
||||
* raa: + (0xFF00|err) (start failed)
|
||||
*
|
||||
* 1) all_sensors() measures battery / IMU / temperature and emits rbb:
|
||||
* 2) Starts 6-channel capture in pre-capture-all mode
|
||||
*============================================================================*/
|
||||
int Cmd_mbb(const ParsedCmd *cmd)
|
||||
{
|
||||
dr_adc_err_t err;
|
||||
(void)cmd;
|
||||
|
||||
all_sensors();
|
||||
|
||||
if (maa_async_is_busy())
|
||||
{
|
||||
dr_ble_return_1("raa:", 0xFFFE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
maa_async_set_pre_capture_all(true);
|
||||
|
||||
err = maa_async_start(
|
||||
m_config.piezo_freq_option,
|
||||
m_config.piezo_delay_us,
|
||||
m_config.piezo_num_samples,
|
||||
m_config.piezo_cycles,
|
||||
m_config.piezo_averaging,
|
||||
ble_bin_buffer
|
||||
);
|
||||
|
||||
if (err != DR_ADC_OK)
|
||||
{
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[Cmd_mbb] start failed err=%d\r\n", err);
|
||||
}
|
||||
single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err));
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
dr_piezo_power_off();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mcf? -> rcf: Read piezo parameters from FDS
|
||||
*
|
||||
* Request: [TAG 4B "mcf?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rcf:"] [freq 2B] [cycles 2B] [avg 2B] [delay_us 2B] [num_samples 2B] [CRC 2B]
|
||||
*============================================================================*/
|
||||
int Cmd_mcf(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
|
||||
uint8_t *buf = ble_bin_buffer;
|
||||
buf[0] = 'r'; buf[1] = 'c'; buf[2] = 'f'; buf[3] = ':';
|
||||
buf[4] = 0; buf[5] = m_config.piezo_freq_option;
|
||||
buf[6] = 0; buf[7] = m_config.piezo_cycles;
|
||||
buf[8] = (uint8_t)(m_config.piezo_averaging >> 8); buf[9] = (uint8_t)(m_config.piezo_averaging & 0xFF);
|
||||
buf[10] = (uint8_t)(m_config.piezo_delay_us >> 8); buf[11] = (uint8_t)(m_config.piezo_delay_us & 0xFF);
|
||||
buf[12] = (uint8_t)(m_config.piezo_num_samples >> 8); buf[13] = (uint8_t)(m_config.piezo_num_samples & 0xFF);
|
||||
dr_binary_tx_safe(buf, 7); /* 14 bytes = 7 words */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mcs? -> rcs: Write piezo parameters to FDS
|
||||
*
|
||||
* Request: [TAG 4B "mcs?"] [freq 2B] [cycles 2B] [avg 2B] [delay_us 2B] [num_samples 2B] [CRC 2B]
|
||||
* Response: [TAG 4B "rcs:"] [stored 5 values] [CRC 2B]
|
||||
* Error: rcs: + 0xFFFF (insufficient data)
|
||||
*============================================================================*/
|
||||
int Cmd_mcs(const ParsedCmd *cmd)
|
||||
{
|
||||
if (cmd->data_len < 10)
|
||||
{
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[Cmd_mcs] missing params (data_len=%u)\r\n", cmd->data_len);
|
||||
}
|
||||
dr_ble_return_1("rcs:", 0xFFFF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t freq, cycles, averaging, delay_us, num_samples;
|
||||
dr_get_u16(cmd, 0, &freq);
|
||||
dr_get_u16(cmd, 1, &cycles);
|
||||
dr_get_u16(cmd, 2, &averaging);
|
||||
dr_get_u16(cmd, 3, &delay_us);
|
||||
dr_get_u16(cmd, 4, &num_samples);
|
||||
|
||||
m_config.piezo_freq_option = (uint8_t)freq;
|
||||
m_config.piezo_cycles = (uint8_t)cycles;
|
||||
m_config.piezo_averaging = averaging;
|
||||
m_config.piezo_delay_us = delay_us;
|
||||
m_config.piezo_num_samples = num_samples;
|
||||
config_save();
|
||||
|
||||
uint8_t *buf = ble_bin_buffer;
|
||||
buf[0] = 'r'; buf[1] = 'c'; buf[2] = 's'; buf[3] = ':';
|
||||
buf[4] = 0; buf[5] = m_config.piezo_freq_option;
|
||||
buf[6] = 0; buf[7] = m_config.piezo_cycles;
|
||||
buf[8] = (uint8_t)(m_config.piezo_averaging >> 8); buf[9] = (uint8_t)(m_config.piezo_averaging & 0xFF);
|
||||
buf[10] = (uint8_t)(m_config.piezo_delay_us >> 8); buf[11] = (uint8_t)(m_config.piezo_delay_us & 0xFF);
|
||||
buf[12] = (uint8_t)(m_config.piezo_num_samples >> 8); buf[13] = (uint8_t)(m_config.piezo_num_samples & 0xFF);
|
||||
dr_binary_tx_safe(buf, 7);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*==============================================================================
|
||||
* cmd_piezo.h - Piezo ultrasound measurement handlers
|
||||
*============================================================================*/
|
||||
#ifndef CMD_PIEZO_H
|
||||
#define CMD_PIEZO_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
int Cmd_mpa(const ParsedCmd *cmd); /* mpa? -> rpa: TX/RX power ON */
|
||||
int Cmd_mpb(const ParsedCmd *cmd); /* mpb? -> rpb: TX/RX power OFF */
|
||||
int Cmd_mpc(const ParsedCmd *cmd); /* mpc? -> rpc: burst generation */
|
||||
int Cmd_mec(const ParsedCmd *cmd); /* mec? -> reb:+raa: single-channel capture */
|
||||
int Cmd_maa(const ParsedCmd *cmd); /* maa? -> reb:+raa: 6-channel async capture */
|
||||
int Cmd_mbb(const ParsedCmd *cmd); /* mbb? -> rbb:+reb:+raa: sensors + capture */
|
||||
int Cmd_mcf(const ParsedCmd *cmd); /* mcf? -> rcf: read piezo parameters */
|
||||
int Cmd_mcs(const ParsedCmd *cmd); /* mcs? -> rcs: write piezo parameters */
|
||||
|
||||
#endif /* CMD_PIEZO_H */
|
||||
@@ -0,0 +1,138 @@
|
||||
/*==============================================================================
|
||||
* cmd_sensor.c - Sensor measurement handlers
|
||||
*
|
||||
* msn? -> rsn: battery ADC measurement
|
||||
* mso? -> rso: TMP235 temperature reading
|
||||
* msp? -> rsp: IMU 6-axis single read
|
||||
* all_sensors() bulk-measurement helper used by the mbb? handler
|
||||
*============================================================================*/
|
||||
|
||||
#include "cmd_common.h"
|
||||
#include "cmd_sensor.h"
|
||||
#include "dr_piezo.h"
|
||||
|
||||
/*==============================================================================
|
||||
* msn? -> rsn: Battery level ADC measurement
|
||||
*
|
||||
* Request: [TAG 4B "msn?"] [CRC 2B]
|
||||
* Response: rsn: + battery voltage in mV (sent from battery_saadc.c callback)
|
||||
*============================================================================*/
|
||||
int Cmd_msn(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
battery_level_meas();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* mst? -> rso: Temperature with piezo power cycle
|
||||
*
|
||||
* Request: [TAG 4B "mst?"] [CRC 2B]
|
||||
* Response: [TAG 4B "rso:"] [temp_x100 2B BE] [CRC 2B]
|
||||
*
|
||||
* TMP235 shares the piezo TX/RX power rail. This command handles the full
|
||||
* sequence: power ON -> measure -> power OFF, so the caller doesn't need
|
||||
* to send mpa?/mpb? separately.
|
||||
* Response is sent from the TMP235 SAADC callback (tmp235_voltage_handler).
|
||||
*============================================================================*/
|
||||
int Cmd_mst(const ParsedCmd *cmd)
|
||||
{
|
||||
uint32_t timeout_cnt;
|
||||
(void)cmd;
|
||||
|
||||
if (!dr_piezo_is_power_on())
|
||||
{
|
||||
dr_piezo_power_on();
|
||||
}
|
||||
|
||||
tmp235_saadc_done = false;
|
||||
tmp235_voltage_level_meas();
|
||||
for (timeout_cnt = 0; !tmp235_saadc_done && timeout_cnt < 100; timeout_cnt++)
|
||||
{
|
||||
dr_sd_delay_ms(1);
|
||||
}
|
||||
|
||||
dr_piezo_power_off();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* msp? -> rsp: IMU 6-axis single read
|
||||
*
|
||||
* Request: [TAG 4B "msp?"] [CRC 2B]
|
||||
* Response: rsp: + accel(xyz) + gyro(xyz) (transmitted inside imu_read_direct)
|
||||
*
|
||||
* Reads IMU registers directly over I2C and transmits over BLE. Synchronous.
|
||||
*============================================================================*/
|
||||
int Cmd_msp(const ParsedCmd *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
hw_i2c_init_once();
|
||||
imu_read_direct();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* all_sensors() - Bulk-measurement helper for the mbb? handler
|
||||
*
|
||||
* Stores sensor values into globals via info4 mode, then transmits them as a
|
||||
* single rbb: packet. SAADC measurements run asynchronously (callback), so
|
||||
* dr_sd_delay_ms() is used to wait for completion.
|
||||
*
|
||||
* Order: battery -> IMU -> (Piezo TX/RX ON) -> temperature
|
||||
* Response: rbb: [batt 2B] [IMU 6x2B] [temp 2B] = 20 bytes = 10 words
|
||||
*============================================================================*/
|
||||
void all_sensors(void)
|
||||
{
|
||||
uint8_t *buf;
|
||||
uint32_t timeout_cnt;
|
||||
|
||||
info4 = true;
|
||||
|
||||
/* 1. Battery voltage -> info_batt */
|
||||
battery_saadc_done = false;
|
||||
battery_level_meas();
|
||||
for (timeout_cnt = 0; !battery_saadc_done && timeout_cnt < 100; timeout_cnt++)
|
||||
{
|
||||
dr_sd_delay_ms(1);
|
||||
}
|
||||
|
||||
/* 2. IMU 6-axis single read -> info_imu[6] */
|
||||
hw_i2c_init_once();
|
||||
imu_read_direct();
|
||||
|
||||
/* 3. Temperature -> info_temp (TMP235 needs Piezo TX/RX power) */
|
||||
if (!dr_piezo_is_power_on())
|
||||
{
|
||||
dr_piezo_power_on();
|
||||
}
|
||||
|
||||
tmp235_saadc_done = false;
|
||||
tmp235_voltage_level_meas();
|
||||
for (timeout_cnt = 0; !tmp235_saadc_done && timeout_cnt < 100; timeout_cnt++)
|
||||
{
|
||||
dr_sd_delay_ms(1);
|
||||
}
|
||||
|
||||
info4 = false;
|
||||
|
||||
/* Assemble and transmit the rbb: packet (dedicated buffer to avoid
|
||||
collision with ble_bin_buffer used by the async ADC state machine) */
|
||||
static uint8_t rbb_buf[20];
|
||||
buf = rbb_buf;
|
||||
buf[0] = 'r'; buf[1] = 'b'; buf[2] = 'b'; buf[3] = ':';
|
||||
buf[4] = (uint8_t)(info_batt >> 8);
|
||||
buf[5] = (uint8_t)(info_batt & 0xFF);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
buf[6 + i * 2] = (uint8_t)(info_imu[i] >> 8);
|
||||
buf[6 + i * 2 + 1] = (uint8_t)(info_imu[i] & 0xFF);
|
||||
}
|
||||
|
||||
buf[18] = (uint8_t)(info_temp >> 8);
|
||||
buf[19] = (uint8_t)(info_temp & 0xFF);
|
||||
|
||||
dr_binary_tx_safe(buf, 10); /* 20 bytes = 10 words */
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*==============================================================================
|
||||
* cmd_sensor.h - Sensor measurement handlers (battery / temperature / IMU)
|
||||
*============================================================================*/
|
||||
#ifndef CMD_SENSOR_H
|
||||
#define CMD_SENSOR_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
int Cmd_msn(const ParsedCmd *cmd); /* msn? -> rsn: battery ADC measurement */
|
||||
int Cmd_mst(const ParsedCmd *cmd); /* mst? -> rso: TMP235 with piezo power cycle */
|
||||
int Cmd_msp(const ParsedCmd *cmd); /* msp? -> rsp: IMU 6-axis single read */
|
||||
/* Helper for the mbb? handler: sequentially measures battery / IMU / temperature, then emits a single rbb: response.
|
||||
* Called from Cmd_mbb() in cmd_piezo.c. */
|
||||
void all_sensors(void);
|
||||
|
||||
#endif /* CMD_SENSOR_H */
|
||||
@@ -0,0 +1,336 @@
|
||||
/*==============================================================================
|
||||
* parser.c - BLE command parser / dispatcher
|
||||
*
|
||||
* Common module that parses binary command packets received over BLE and
|
||||
* dispatches them to the appropriate handler from the command table.
|
||||
*
|
||||
* Key point: this file does not know which Cmd_* functions exist.
|
||||
* cmd_table.c injects the table pointer at boot via dr_parser_init().
|
||||
*
|
||||
* Packet layout: [TAG 4B] [data N] [CRC16 2B (optional)]
|
||||
* - TAG : 4-char ASCII identifier (e.g. "mid?")
|
||||
* - data : Big-Endian uint16 or ASCII
|
||||
* - CRC16: present when g_plat.crc_check is true; trailing 2 bytes (LE)
|
||||
*
|
||||
* Flow:
|
||||
* 1) dr_cmd_parser() - external entry point
|
||||
* 2) dr_parse_cmd() - length / CRC verification + TAG/data split
|
||||
* 3) dr_cmd_dispatch() - walks the command table -> calls handler
|
||||
*
|
||||
* Error responses (all formatted as [err_tag 4B] [echo cmd_tag 4B] = 8 bytes):
|
||||
* - rxs: Too short (< 4B, or < 7B with CRC enabled)
|
||||
* - rxc: CRC fail
|
||||
* - rxd: Disabled command
|
||||
* - rxn: NULL handler
|
||||
* - rxx: Unknown command
|
||||
*============================================================================*/
|
||||
|
||||
#include "parser.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Globals (declared extern in header)
|
||||
*----------------------------------------------------------------------------*/
|
||||
dr_platform_if_t g_plat = { 0, 0, 0 };
|
||||
bool g_log_enable = false;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal state - command table pointer injected via dr_parser_init()
|
||||
*----------------------------------------------------------------------------*/
|
||||
static const CmdEntry *m_cmd_table = NULL;
|
||||
static uint16_t m_cmd_count = 0;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Internal utilities (static)
|
||||
*============================================================================*/
|
||||
|
||||
/* Copy first 4 bytes of buffer into a null-terminated TAG string. */
|
||||
static void dr_copy_tag(const uint8_t *buf, char *tag_out)
|
||||
{
|
||||
tag_out[0] = (char)buf[0];
|
||||
tag_out[1] = (char)buf[1];
|
||||
tag_out[2] = (char)buf[2];
|
||||
tag_out[3] = (char)buf[3];
|
||||
tag_out[4] = '\0';
|
||||
}
|
||||
|
||||
/* Compare two 4-char TAGs (byte-by-byte, faster than memcmp here). */
|
||||
static bool dr_tag_eq(const char *tag, const char *key4)
|
||||
{
|
||||
return (tag[0] == key4[0] &&
|
||||
tag[1] == key4[1] &&
|
||||
tag[2] == key4[2] &&
|
||||
tag[3] == key4[3]);
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Public utilities - used by handlers
|
||||
*============================================================================*/
|
||||
|
||||
bool dr_get_u16(const ParsedCmd *cmd, uint8_t word_index, uint16_t *out)
|
||||
{
|
||||
uint8_t pos = (uint8_t)(word_index * 2);
|
||||
if (cmd->data_len < (uint8_t)(pos + 2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*out = (uint16_t)((uint16_t)cmd->data[pos] << 8) | (uint16_t)cmd->data[pos + 1];
|
||||
return true;
|
||||
}
|
||||
|
||||
void dr_get_ascii(const ParsedCmd *cmd, uint8_t offset, char *out, uint8_t max_len)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t remain;
|
||||
|
||||
if (offset >= cmd->data_len)
|
||||
{
|
||||
out[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
remain = (uint8_t)(cmd->data_len - offset);
|
||||
if (remain > max_len)
|
||||
{
|
||||
remain = max_len;
|
||||
}
|
||||
|
||||
for (i = 0; i < remain; i++)
|
||||
{
|
||||
out[i] = (char)cmd->data[offset + i];
|
||||
}
|
||||
out[remain] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* CRC16 (Nordic SDK CRC-CCITT variant)
|
||||
*============================================================================*/
|
||||
|
||||
uint16_t dr_crc16_compute(const uint8_t *p_data, uint32_t size, const uint16_t *p_crc)
|
||||
{
|
||||
uint32_t i;
|
||||
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
crc = (uint8_t)(crc >> 8) | (crc << 8);
|
||||
crc ^= p_data[i];
|
||||
crc ^= (uint8_t)(crc & 0xFF) >> 4;
|
||||
crc ^= (crc << 8) << 4;
|
||||
crc ^= ((crc & 0xFF) << 4) << 1;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static bool dr_crc16_check(const uint8_t *p_data, uint32_t data_len, uint16_t expected_crc)
|
||||
{
|
||||
return (dr_crc16_compute(p_data, data_len, NULL) == expected_crc);
|
||||
}
|
||||
|
||||
/* Extract trailing 2 bytes (Little-Endian) as expected CRC and verify. */
|
||||
static bool dr_crc16_check_packet(const uint8_t *packet, uint32_t packet_len)
|
||||
{
|
||||
uint16_t expected_crc;
|
||||
uint32_t data_len;
|
||||
|
||||
if (packet_len < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data_len = packet_len - 2;
|
||||
expected_crc = (uint16_t)packet[packet_len - 2]
|
||||
| ((uint16_t)packet[packet_len - 1] << 8);
|
||||
|
||||
return dr_crc16_check(packet, data_len, expected_crc);
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Error response helper
|
||||
*
|
||||
* Packet: [err_tag 4B] [echo cmd_tag 4B] = 8 bytes = 4 words
|
||||
* CRC16 is appended automatically by the tx_bin layer.
|
||||
*============================================================================*/
|
||||
static void dr_send_error(const char *err_tag, const char *cmd_tag)
|
||||
{
|
||||
if (g_plat.tx_bin)
|
||||
{
|
||||
uint8_t err_buf[8];
|
||||
memcpy(&err_buf[0], err_tag, 4);
|
||||
memcpy(&err_buf[4], cmd_tag, 4);
|
||||
g_plat.tx_bin(err_buf, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Packet parser - raw buffer -> ParsedCmd
|
||||
*
|
||||
* Error responses (rxs: / rxc:) are emitted directly from this function.
|
||||
*============================================================================*/
|
||||
static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
|
||||
{
|
||||
uint8_t data_len;
|
||||
|
||||
/* Less than 4 bytes -> TAG cannot be identified */
|
||||
if (length < 4)
|
||||
{
|
||||
dr_send_error("rxs:", "????");
|
||||
if (g_plat.log && g_log_enable)
|
||||
{
|
||||
g_plat.log("[parser] too short (%u bytes) -> rxs:\r\n", length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Extract TAG first (used in error echoes below) */
|
||||
dr_copy_tag(buffer, out->tag);
|
||||
|
||||
/* CRC verification */
|
||||
if (g_plat.crc_check)
|
||||
{
|
||||
if (length < 7)
|
||||
{
|
||||
dr_send_error("rxs:", out->tag);
|
||||
if (g_plat.log && g_log_enable)
|
||||
{
|
||||
g_plat.log("[parser] CRC enabled but too short (%u) -> rxs:\r\n", length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dr_crc16_check_packet(buffer, length))
|
||||
{
|
||||
dr_send_error("rxc:", out->tag);
|
||||
if (g_plat.log && g_log_enable)
|
||||
{
|
||||
g_plat.log("[parser] CRC mismatch '%s' -> rxc:\r\n", out->tag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
data_len = (uint8_t)(length - 4 - 2); /* strip TAG and CRC */
|
||||
}
|
||||
else
|
||||
{
|
||||
data_len = (uint8_t)(length - 4);
|
||||
}
|
||||
|
||||
if (data_len > DR_MAX_DATA)
|
||||
{
|
||||
data_len = DR_MAX_DATA;
|
||||
}
|
||||
|
||||
if (data_len > 0)
|
||||
{
|
||||
memcpy(out->data, buffer + 4, data_len);
|
||||
}
|
||||
out->data_len = data_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Command dispatcher
|
||||
*
|
||||
* Lower-cases the parsed TAG and walks the command table to find a matching
|
||||
* handler. Emits the matching error response on miss / disabled / NULL handler.
|
||||
*============================================================================*/
|
||||
static int dr_cmd_dispatch(const ParsedCmd *cmd)
|
||||
{
|
||||
uint16_t i;
|
||||
char tag_lower[5];
|
||||
|
||||
if (m_cmd_table == NULL)
|
||||
{
|
||||
dr_send_error("rxn:", cmd->tag);
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[parser] table not initialized -> rxn:\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Case-insensitive matching */
|
||||
for (i = 0; i < 4 && cmd->tag[i]; i++)
|
||||
{
|
||||
tag_lower[i] = (cmd->tag[i] >= 'A' && cmd->tag[i] <= 'Z') ? (cmd->tag[i] + 32) : cmd->tag[i];
|
||||
}
|
||||
tag_lower[i] = '\0';
|
||||
|
||||
for (i = 0; i < m_cmd_count; i++)
|
||||
{
|
||||
if (dr_tag_eq(tag_lower, m_cmd_table[i].tag))
|
||||
{
|
||||
|
||||
if (!m_cmd_table[i].enabled)
|
||||
{
|
||||
dr_send_error("rxd:", cmd->tag);
|
||||
if (g_plat.log && g_log_enable)
|
||||
{
|
||||
g_plat.log("Command '%s' disabled -> rxd:\n", cmd->tag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_cmd_table[i].handler == NULL)
|
||||
{
|
||||
dr_send_error("rxn:", cmd->tag);
|
||||
if (g_plat.log)
|
||||
{
|
||||
g_plat.log("[parser] NULL handler for '%s' -> rxn:\n", cmd->tag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_cmd_table[i].handler(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* TAG not found in table */
|
||||
dr_send_error("rxx:", cmd->tag);
|
||||
if (g_plat.log && g_log_enable)
|
||||
{
|
||||
g_plat.log("Unknown TAG '%s' -> rxx:\n", cmd->tag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Public API
|
||||
*============================================================================*/
|
||||
|
||||
/* Called by cmd_table.c at boot to inject the command table. */
|
||||
void dr_parser_init(const CmdEntry *table, uint16_t count)
|
||||
{
|
||||
m_cmd_table = table;
|
||||
m_cmd_count = count;
|
||||
}
|
||||
|
||||
/* Entry point - called from BLE NUS / UART receive callbacks.
|
||||
*
|
||||
* Returns:
|
||||
* 1 = command processed successfully
|
||||
* 0 = unknown TAG / disabled command (error response already sent)
|
||||
* -1 = parse failure (rxs: / rxc: error response already sent)
|
||||
*/
|
||||
int dr_cmd_parser(const uint8_t *buf, uint8_t len)
|
||||
{
|
||||
ParsedCmd cmd;
|
||||
|
||||
if (!dr_parse_cmd(buf, len, &cmd))
|
||||
{
|
||||
if (g_plat.log) g_plat.log("[PARSER] PARSE FAIL\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dr_cmd_dispatch(&cmd);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*==============================================================================
|
||||
* parser.h - BLE command parser public API
|
||||
*
|
||||
* Parser infrastructure (parsing/CRC/dispatch) and command handlers are
|
||||
* decoupled:
|
||||
* - Parser: parser.c (defines the functions here)
|
||||
* - Handlers: handlers/cmd_device.c / cmd_info.c / ...
|
||||
* - Table: cmd_table.c (injected via cmd_table_init)
|
||||
*
|
||||
* Boot sequence: main.c calls cmd_table_init() -> dr_parser_init() to inject
|
||||
* the command table pointer into the parser.
|
||||
*============================================================================*/
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Maximum payload length (excludes TAG) */
|
||||
#define DR_MAX_DATA 128
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Platform interface
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
void (*log)(const char *fmt, ...);
|
||||
void (*tx_bin)(const uint8_t *buf, uint16_t len); /* len: word (uint16) count */
|
||||
bool crc_check;
|
||||
} dr_platform_if_t;
|
||||
|
||||
extern dr_platform_if_t g_plat;
|
||||
extern bool g_log_enable;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Parsed command - input passed to handlers
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
char tag[5]; /* Command TAG (e.g. "mid?") + '\0' */
|
||||
uint8_t data[DR_MAX_DATA]; /* Payload bytes following the TAG */
|
||||
uint8_t data_len; /* Valid length of data[] */
|
||||
} ParsedCmd;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Command table entry - defined in cmd_table.c
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
char tag[5]; /* TAG: 4 chars + '\0' */
|
||||
bool enabled; /* false -> rxd: response */
|
||||
int (*handler)(const ParsedCmd *cmd); /* 1=success, 0=failure */
|
||||
} CmdEntry;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Parser API
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Inject command table (called once at boot). */
|
||||
void dr_parser_init(const CmdEntry *table, uint16_t count);
|
||||
|
||||
/* Entry point: invoked from BLE NUS / UART receive callbacks. */
|
||||
int dr_cmd_parser(const uint8_t *buf, uint8_t len);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Public utilities for handlers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Extract Big-Endian uint16. Returns false if not enough data. */
|
||||
bool dr_get_u16(const ParsedCmd *cmd, uint8_t word_index, uint16_t *out);
|
||||
|
||||
/* Extract null-terminated ASCII string. out must hold at least max_len+1. */
|
||||
void dr_get_ascii(const ParsedCmd *cmd, uint8_t offset, char *out, uint8_t max_len);
|
||||
|
||||
/* CRC16 (Nordic SDK CRC-CCITT variant). p_crc=NULL -> initial 0xFFFF. */
|
||||
uint16_t dr_crc16_compute(const uint8_t *p_data, uint32_t size, const uint16_t *p_crc);
|
||||
|
||||
#endif /* PARSER_H */
|
||||
@@ -0,0 +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
|
||||
|
||||
pause
|
||||
@@ -0,0 +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
|
||||
@@ -0,0 +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
|
||||
@@ -0,0 +1,176 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo ==========================================
|
||||
echo MEDiThings Bladder Patch Programming
|
||||
echo (DEBUG MODE - ERASE ALL, FDS Reset)
|
||||
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: ERASE ALL + program + reset (FDS will be reset!)
|
||||
|
||||
REM program (ERASE_ALL: chip erase -> FDS/bond data all cleared)
|
||||
nrfutil device program --firmware hex\firmware_all.hex --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 --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! (ERASE ALL)
|
||||
echo No Readback Protection Applied
|
||||
echo FDS/Bond data cleared (factory default)
|
||||
echo %date% %time%
|
||||
echo ==========================================
|
||||
pause
|
||||
|
||||
endlocal
|
||||
@@ -0,0 +1,3 @@
|
||||
nrfjprog --family NRF52 --recover
|
||||
nrfjprog --family NRF52 --eraseall
|
||||
pause
|
||||
@@ -0,0 +1,3 @@
|
||||
nrfjprog --family NRF52 --rbp ALL
|
||||
nrfjprog --family NRF52 --pinreset
|
||||
pause
|
||||
@@ -0,0 +1,2 @@
|
||||
nrfjprog --family NRF52 --recover
|
||||
pause
|
||||
@@ -0,0 +1,2 @@
|
||||
nrfjprog --family NRF52 --pinreset
|
||||
pause
|
||||
@@ -0,0 +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
|
||||
@@ -0,0 +1,413 @@
|
||||
[2025-Dec-02 21:41:39] [debug] --------------------------------------------------------------------------------
|
||||
[2025-Dec-02 21:41:39] [debug] nrfjprog --recover -s 682580999 --log
|
||||
[2025-Dec-02 21:41:39] [debug] nrfjprog version 10.19.0 external
|
||||
[2025-Dec-02 21:41:39] [debug] --------------------------------------------------------------------------------
|
||||
[2025-Dec-02 21:41:39] [ info] Load library at d:\nrfutil\bin\nrfjprog.dll.
|
||||
[2025-Dec-02 21:41:39] [ info] Library loaded, loading member functions.
|
||||
[2025-Dec-02 21:41:39] [ info] Member functions succesfully loaded.
|
||||
[2025-Dec-02 21:41:39] [debug] [ Client] - open
|
||||
[2025-Dec-02 21:41:39] [debug] [ Client] - start
|
||||
[2025-Dec-02 21:41:39] [ info] [ Client] - stdout: Jlinkarm nRF Worker ready. Handling sequence 9216d55f-e6c3-46dc-87a3-92d9ff8623b1.
|
||||
|
||||
[2025-Dec-02 21:41:39] [trace] [ Client] - Command open executed for 36 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - Logger sink registered in Segger backend logger
|
||||
[2025-Dec-02 21:41:39] [debug] [ Client] - config
|
||||
[2025-Dec-02 21:41:39] [debug] [ JLink] - Logger sink registered in JLink logger
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - open
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - just_check_family
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - open_dll
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - No J-Link DLL path was provided. Attempting to auto detect.
|
||||
[2025-Dec-02 21:41:39] [ info] [SeggerBackend] - Load library at C:\Program Files\SEGGER\JLink_V818\JLinkARM.dll.
|
||||
[2025-Dec-02 21:41:39] [ info] [SeggerBackend] - Library loaded, loading member functions.
|
||||
[2025-Dec-02 21:41:39] [ info] [SeggerBackend] - Member functions succesfully loaded.
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - Set batch mode
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - dll_version
|
||||
[2025-Dec-02 21:41:39] [ info] [SeggerBackend] - Segger dll version 8.18. loaded.
|
||||
[2025-Dec-02 21:41:39] [trace] [ Worker] - Command open executed for 4 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [trace] [ Client] - Command config executed for 15 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [debug] [ Client] - enum_emu_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - config
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - enum_emu_snr
|
||||
[2025-Dec-02 21:41:39] [trace] [ Worker] - Command config executed for 2 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [trace] [ Client] - Command enum_emu_con_info executed for 15 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [debug] [ Client] - connect_to_emu_with_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - enum_emu_con_info
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - enum_emu_con_info
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:39] [trace] [ Worker] - Command enum_emu_con_info executed for 3 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - connect_to_emu_with_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - connect_to_emu_with_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - ---just_enum_emu_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - ---just_get_num_emus
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - ---just_connect_to_emu_with_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - ---just_connect_to_emu_without_snr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - Segger logging enabled.
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Jul 8 2025 10:14:41
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Jul 8 2025 10:14:41
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Hardware: V1.00
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - S/N: 682580999
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - OEM: SEGGER
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Feature(s): RDI, FlashBP, FlashDL, JFlash, GDB
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Bootloader: 2014 Sep 11
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - USB speed mode: High speed (480 MBit/s)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - TELNET listener socket opened on port 19021
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - WEBSRV WEBSRV_Init(): Starting webserver thread(s)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - WEBSRV Webserver running on local port 19080
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Looking for J-Link GUI Server exe at: C:\Program Files\SEGGER\JLink_V818\JLinkGUIServer.exe
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - Forking J-Link GUI Server: C:\Program Files\SEGGER\JLink_V818\JLinkGUIServer.exe
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - J-Link GUI Server info: "J-Link GUI server V8.18 "
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 37.124ms returns "O.K."
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_Lock()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_ExecCommand("SetRestartOnClose = 0", ...).
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.001ms returns 0x01
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_ExecCommand("DisableFlashDL", ...).
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.000ms returns 0x00
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_ExecCommand("ExcludeFlashCacheRange 0x0-0xFFFFFFFF", ...).
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.002ms returns 0x00
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_SetHookUnsecureDialog
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_SetHookUnsecureDialog(...)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.010ms returns 0
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_TIF_Select(JLINKARM_TIF_SWD)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.479ms returns 0x00
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_GetSpeedInfo()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - 10000000 Hz / n, n >= 10
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.007ms
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - Connected emulator supports SWD speeds up to 1000kHz
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - Requested speed 2000kHz is higher than the emulator max speed of 1000kHz
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_SetSpeed(2000)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.046ms
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_GetSpeed()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.003ms returns 1000
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - SWD speed was reported as 1000kHz after requesting 2000kHz. Check the capabilities of the selected emulator.
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_GetSN()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.003ms returns 682580999
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.004ms
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - read_device_family
|
||||
[2025-Dec-02 21:41:39] [debug] [ nRFXX] - read_device_family
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_IsOpen()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.003ms returns 0x01
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_Lock()
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - read_debug_port_idr
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - read_debug_port_register
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - ---just_read_debug_port_register
|
||||
[2025-Dec-02 21:41:39] [debug] [SeggerBackend] - coresight_configure
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_GetHWStatus(...)
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - - 0.137ms returns 0
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:39] [trace] [ JLink] - JLINK_CORESIGHT_Configure()
|
||||
[2025-Dec-02 21:41:40] [trace] [ Client] - Command connect_to_emu_with_snr executed for 188 milliseconds with result -102
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 104.594ms returns 0
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - read_debug_port_idr
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - read_debug_port_register
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_read_debug_port_register
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_select_debug_port_register
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Select AP 255, DP Bank 0, AP Bank 255
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.793ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.780ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.970ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.732ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.740ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.736ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.698ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.741ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.721ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.726ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.707ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.703ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.716ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.728ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.727ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.760ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.765ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.722ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.723ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.734ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.711ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.715ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.714ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.710ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.716ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.750ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.718ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.849ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.744ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.761ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.040ms
|
||||
[2025-Dec-02 21:41:40] [trace] [ Worker] - Command connect_to_emu_with_snr executed for 187 milliseconds with result -102
|
||||
[2025-Dec-02 21:41:40] [debug] [ nRFXX] - close
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - is_connected_to_emu
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_IsOpen()
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.005ms returns 0x01
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_Lock()
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - close
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - disconnect_from_emu
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_disconnect_from_emu
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - is_connected_to_device
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_IsConnected()
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.003ms returns FALSE
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_is_debug_region_powered
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_read_debug_port_register
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_select_debug_port_register
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Select AP 255, DP Bank 0, AP Bank 255
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.733ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.759ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.720ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.772ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.740ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.725ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.734ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.746ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.738ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.735ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.746ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.723ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.717ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.753ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.737ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.741ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.818ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.725ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.717ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.704ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.727ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.711ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.686ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.719ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x02, 0x00000000)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.721ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - ---just_abort_debug_action
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Attempting to clear any configuration errors in debug port before closing connection.
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.760ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.786ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.739ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.764ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_CORESIGHT_WriteAPDPReg(DP reg 0x00, 0x0000001F)
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.793ms returns -1
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_HasError()
|
||||
[2025-Dec-02 21:41:40] [error] [SeggerBackend] - JLinkARM.dll reported "-1", "An unknown error.".
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - - 0.028ms
|
||||
[2025-Dec-02 21:41:40] [trace] [ JLink] - JLINK_Close()
|
||||
[2025-Dec-02 21:41:40] [debug] [SeggerBackend] - Segger Backend closed.
|
||||
[2025-Dec-02 21:41:40] [debug] [ nRFXX] - nRF family DLL closed
|
||||
[2025-Dec-02 21:41:40] [trace] [ Worker] - Command close executed for 60 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:40] [trace] [ Client] - Command close executed for 61 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:40] [debug] [ Client] - terminate
|
||||
[2025-Dec-02 21:41:40] [trace] [ Client] - Command terminate executed for 0 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:40] [trace] [ Worker] - Command terminate executed for 0 milliseconds with result 0
|
||||
[2025-Dec-02 21:41:40] [trace] [ Worker] - Executed 6 commands for 256 milliseconds
|
||||
[2025-Dec-02 21:41:40] [debug] [ Client] - Worker process exited with code: 0
|
||||
[2025-Dec-02 21:41:40] [debug] [ Client] - Worker process exited with code: 0
|
||||
[2025-Dec-02 21:41:40] [debug] [ Client] - Child process terminated with result 0
|
||||
[2025-Dec-02 21:41:40] [trace] [ Client] - Executed 6 commands for 315 milliseconds
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIHf/LPF4rHM8BNLwocN5rRNXA7nxqMZytmagH4csLaBUoAoGCCqGSM49
|
||||
AwEHoUQDQgAE1ZAavjWbKjEoGnKJm65rdtwnIIG8F15sg2pw5QPLW2f6iAh24ig+
|
||||
A8fY5qAD1vbELamAp4bYO9daX3m1OSRL7A==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -0,0 +1,456 @@
|
||||
/*==============================================================================
|
||||
* fstorage.c - FDS (Flash Data Storage) configuration module
|
||||
*
|
||||
* Stores and loads device configuration to/from nRF52840 internal flash,
|
||||
* replacing external EEPROM. Coexists safely with the SoftDevice.
|
||||
*
|
||||
* Record management:
|
||||
* CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 (single record)
|
||||
*
|
||||
* Magic number validation:
|
||||
* Data loaded from flash is checked against CONFIG_MAGIC_NUMBER_VALUE.
|
||||
* Mismatch -> reinitialise with factory defaults.
|
||||
*
|
||||
* FDS event post-processing:
|
||||
* After a write/update completes, pending actions are executed:
|
||||
* power-off (go_device_power_off), sleep (go_sleep_mode_enter),
|
||||
* system reset (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 record identifiers */
|
||||
#define CONFIG_FILE (0x8010)
|
||||
#define CONFIG_REC_KEY (0x7010)
|
||||
|
||||
/* Magic number used to validate stored data */
|
||||
#define CONFIG_MAGIC_NUMBER_VALUE (0x20260319)
|
||||
|
||||
/* Global configuration instance */
|
||||
config_data_t m_config;
|
||||
|
||||
/* Post-processing flags (declared in main.c) */
|
||||
extern bool go_device_power_off;
|
||||
extern bool go_sleep_mode_enter;
|
||||
extern bool go_NVIC_SystemReset;
|
||||
|
||||
/* FDS initialisation complete flag (set in fds_evt_handler) */
|
||||
static bool volatile m_fds_initialized;
|
||||
|
||||
/* FDS write-in-progress flag */
|
||||
bool fds_flag_write = false;
|
||||
|
||||
/* FDS record template pointing to 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),
|
||||
};
|
||||
|
||||
|
||||
/* Default values */
|
||||
int8_t reset_status_dflt = 99;
|
||||
uint8_t static_passkey_dflt[6] = DEFAULT_PASSKEY;
|
||||
|
||||
/*==============================================================================
|
||||
* fds_default_value_set - Initialise m_config with factory defaults
|
||||
*
|
||||
* Called when flash contains no valid configuration or the magic number
|
||||
* does not match.
|
||||
*============================================================================*/
|
||||
void fds_default_value_set(void)
|
||||
{
|
||||
/* HW number */
|
||||
memset(m_config.hw_no, 0, 12);
|
||||
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
|
||||
|
||||
/* 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 delete — default: no pending delete */
|
||||
m_config.bond_data_delete = 0;
|
||||
|
||||
/* Reset status */
|
||||
m_config.reset_status = reset_status_dflt;
|
||||
|
||||
/* Device usage count */
|
||||
m_config.life_cycle = 0;
|
||||
|
||||
/* Piezo measurement parameter defaults */
|
||||
m_config.piezo_freq_option = 1; /* 2.1 MHz */
|
||||
m_config.piezo_delay_us = 10; /* 10 us after burst */
|
||||
m_config.piezo_num_samples = 100; /* 100 samples */
|
||||
m_config.piezo_cycles = 3; /* 7 cycles */
|
||||
m_config.piezo_averaging = 3; /* 3x averaging */
|
||||
|
||||
/* Factory provisioning — default: not provisioned */
|
||||
m_config.factory_provisioned = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Last FDS event ID (for debugging) */
|
||||
static volatile uint8_t fds_last_evt = 0xFF;
|
||||
|
||||
/*==============================================================================
|
||||
* fds_evt_handler - FDS event callback
|
||||
*
|
||||
* FDS_EVT_INIT : initialisation complete -> set m_fds_initialized
|
||||
* FDS_EVT_WRITE : new record written -> clear fds_flag_write
|
||||
* FDS_EVT_UPDATE : record updated -> clear flag, then execute any
|
||||
* pending power-off / sleep / system reset
|
||||
*============================================================================*/
|
||||
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)
|
||||
{
|
||||
device_power_off();
|
||||
}
|
||||
if (go_sleep_mode_enter == true)
|
||||
{
|
||||
sleep_mode_enter();
|
||||
}
|
||||
if (go_NVIC_SystemReset == true)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* wait_for_fds_ready - Block until FDS initialisation completes
|
||||
*
|
||||
* Times out after 3 seconds with an error log.
|
||||
*============================================================================*/
|
||||
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)
|
||||
{
|
||||
DBG_PRINTF("[FDS] TIMEOUT!\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* config_load - Load configuration from FDS
|
||||
*
|
||||
* Flow:
|
||||
* 1. Search for CONFIG_FILE / CONFIG_REC_KEY (retry up to 10x, 100 ms apart)
|
||||
* 2. If found:
|
||||
* - Open the record (on CRC error: delete and regenerate defaults)
|
||||
* - Copy into m_config
|
||||
* - Validate magic number; on mismatch: delete -> defaults -> rewrite
|
||||
* 3. If not found:
|
||||
* - Write factory defaults as a new record, then reload
|
||||
*============================================================================*/
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
fds_flash_record_t config = { 0 };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy(&m_config, config.p_data, sizeof(config_data_t));
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
fds_default_value_set();
|
||||
|
||||
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");
|
||||
m_config.magic_number = CONFIG_MAGIC_NUMBER_VALUE;
|
||||
|
||||
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) /* 3 second timeout */
|
||||
{
|
||||
nrf_pwr_mgmt_run();
|
||||
nrf_delay_ms(1);
|
||||
fds_wait_cnt++;
|
||||
}
|
||||
|
||||
if (fds_flag_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* config_save - Persist current configuration to FDS
|
||||
*
|
||||
* Flow:
|
||||
* 1. If a previous FDS write is in progress, wait up to 3 seconds
|
||||
* 2. Fix magic number if needed
|
||||
* 3. If existing record found: fds_record_update()
|
||||
* - On no-space: GC then retry
|
||||
* 4. If not found: fds_record_write() (new record)
|
||||
*
|
||||
* Write completion is asynchronous (fds_evt_handler). Post-processing
|
||||
* (power-off / sleep / reset) may follow.
|
||||
*============================================================================*/
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* fs_set_value - Wrapper for config_load()
|
||||
*============================================================================*/
|
||||
void fs_set_value(void)
|
||||
{
|
||||
config_load();
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* fs_storage_init - Initialise FDS
|
||||
*
|
||||
* Called once at boot:
|
||||
* 1. Register event handler
|
||||
* 2. Start FDS initialisation
|
||||
* 3. Wait for completion (up to 3 seconds)
|
||||
* 4. Verify flash stats
|
||||
*============================================================================*/
|
||||
void fs_storage_init(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
rc = fds_register(fds_evt_handler);
|
||||
APP_ERROR_CHECK(rc);
|
||||
|
||||
rc = fds_init();
|
||||
APP_ERROR_CHECK(rc);
|
||||
|
||||
wait_for_fds_ready();
|
||||
|
||||
fds_stat_t stat = { 0 };
|
||||
rc = fds_stat(&stat);
|
||||
APP_ERROR_CHECK(rc);
|
||||
|
||||
DBG_PRINTF("[FDS] OK\r\n");
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*==============================================================================
|
||||
* fstorage.h - FDS (Flash Data Storage) configuration module interface
|
||||
*
|
||||
* Stores and loads device configuration to/from the nRF52840 internal flash
|
||||
* via the Nordic FDS library. Replaces external EEPROM and coexists safely
|
||||
* with the SoftDevice.
|
||||
*
|
||||
* config_data_t (49 bytes, packed):
|
||||
* magic_number (4B) : format validation (0x20231226)
|
||||
* hw_no (12B): hardware version string
|
||||
* serial_no (12B): serial number (also used as BLE device name)
|
||||
* static_passkey(6B) : BLE pairing passkey (6-digit numeric)
|
||||
* bond_data_delete(1B): bond-delete flag
|
||||
* reset_status (1B) : reset cause code
|
||||
* life_cycle (4B) : device usage count
|
||||
* piezo_* (8B) : piezo measurement parameters
|
||||
* factory_provisioned(1B): passkey provisioning lock flag
|
||||
*
|
||||
* API:
|
||||
* fs_storage_init() : initialise FDS (once at boot)
|
||||
* config_load() : load config from FDS (creates defaults if absent)
|
||||
* config_save() : persist current config to FDS
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef IHP_FSTORAGE_H_
|
||||
#define IHP_FSTORAGE_H_
|
||||
|
||||
#include "sdk_config.h"
|
||||
|
||||
#include "nordic_common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Default version identifiers (used for FDS defaults / empty field recovery)
|
||||
*
|
||||
* Hardware ID:
|
||||
* VBTHW0100 = development / test Ver 1.00
|
||||
* VB0HW0100 = production Ver 1.00
|
||||
*
|
||||
* Firmware ID:
|
||||
* VBTFW0100 = development / test Ver 1.00
|
||||
* VB0FW0100 = production Ver 1.00
|
||||
*
|
||||
* Serial number:
|
||||
* VBT26030001 = dev/test, manufactured Mar 2026, unit #1
|
||||
* VB026030001 = production, Mar 2026, unit #1
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define HARDWARE_VERSION "VBTHW0100"
|
||||
#define SERIAL_NUMBER "VBT26030001"
|
||||
#define DEFAULT_PASSKEY "123456"
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic_number; /* 4B - format validation magic */
|
||||
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 measurement parameters - 8B */
|
||||
uint8_t piezo_freq_option; /* 1B - TX pulse frequency (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */
|
||||
uint8_t piezo_cycles; /* 1B - burst pulse cycle count (3..7) */
|
||||
uint16_t piezo_averaging; /* 2B - averages per channel (1..10) */
|
||||
uint16_t piezo_delay_us; /* 2B - delay from TX pulse to ADC start (us) (0..30) */
|
||||
uint16_t piezo_num_samples; /* 2B - ADC sample count (80..140) */
|
||||
|
||||
/* Factory provisioning lock */
|
||||
uint8_t factory_provisioned; /* 1B - 0=passkey not set, 1=passkey set (locked) */
|
||||
} config_data_t; /* Total: 49 bytes */
|
||||
|
||||
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_ */
|
||||
@@ -0,0 +1,125 @@
|
||||
/*==============================================================================
|
||||
* i2c_manager.c - HW / SW I2C mutex switching logic
|
||||
*
|
||||
* Manages mutually-exclusive HW (TWI peripheral) and SW (bit-bang) I2C modes.
|
||||
*
|
||||
* HW I2C : nRF52840 TWI hardware, 400 kHz Fast Mode (ICM42670P IMU)
|
||||
* SW I2C : GPIO bit-bang (legacy, currently unused)
|
||||
*
|
||||
* Pins:
|
||||
* SCL = P1.14 (ICM42670_I2C_SCL_PIN)
|
||||
* SDA = P1.15 (ICM42670_I2C_SDA_PIN)
|
||||
*
|
||||
* The two bool flags HW_I2C_FRQ and SW_I2C_FRQ track the current mode.
|
||||
* Switching releases the old mode's resources before initialising the new one.
|
||||
*============================================================================*/
|
||||
|
||||
#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"
|
||||
|
||||
/* Current I2C mode flags */
|
||||
bool HW_I2C_FRQ = true;
|
||||
bool SW_I2C_FRQ = false;
|
||||
|
||||
/* TWI instance (nRF52840 supports TWI0 and TWI1) */
|
||||
#define TWI_INSTANCE 0
|
||||
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);
|
||||
|
||||
/* Disable and uninitialise the TWI peripheral, releasing GPIO pins. */
|
||||
static void twi_uninitialize(void)
|
||||
{
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
}
|
||||
|
||||
/* Initialise the TWI peripheral (SCL/SDA pins, 400 kHz, blocking mode). */
|
||||
static void twi_initialize(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
const nrfx_twi_config_t twi_config =
|
||||
{
|
||||
.scl = ICM42670_I2C_SCL_PIN,
|
||||
.sda = ICM42670_I2C_SDA_PIN,
|
||||
.frequency = NRF_TWI_FREQ_400K,
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
|
||||
};
|
||||
|
||||
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrfx_twi_enable(&m_twi);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* hw_i2c_init_once - Switch to or initialise HW TWI mode
|
||||
*
|
||||
* If SW mode is active, its flag is cleared first.
|
||||
* If HW mode is already active, returns immediately (no re-init).
|
||||
*============================================================================*/
|
||||
void hw_i2c_init_once(void)
|
||||
{
|
||||
if (SW_I2C_FRQ)
|
||||
{
|
||||
SW_I2C_FRQ = false;
|
||||
nrf_delay_ms(2); /* mode-switch settling */
|
||||
}
|
||||
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
twi_initialize();
|
||||
nrf_delay_ms(2);
|
||||
|
||||
HW_I2C_FRQ = true;
|
||||
SW_I2C_FRQ = false;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* sw_i2c_init_once - Switch to SW bit-bang mode (legacy, unused)
|
||||
*
|
||||
* If HW mode is active, TWI is released first.
|
||||
* If SW mode is already active, returns immediately.
|
||||
*============================================================================*/
|
||||
void sw_i2c_init_once(void)
|
||||
{
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
nrf_delay_ms(2);
|
||||
HW_I2C_FRQ = false;
|
||||
}
|
||||
|
||||
if (SW_I2C_FRQ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
twi_uninitialize();
|
||||
nrf_delay_ms(1);
|
||||
|
||||
SW_I2C_FRQ = true;
|
||||
HW_I2C_FRQ = false;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* i2c_reset_state - Clear all mode flags
|
||||
*
|
||||
* Forces re-initialisation on the next init call. Used for system reset
|
||||
* or error recovery.
|
||||
*============================================================================*/
|
||||
void i2c_reset_state(void)
|
||||
{
|
||||
HW_I2C_FRQ = false;
|
||||
SW_I2C_FRQ = false;
|
||||
DBG_PRINTF("Flags reset\r\n");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*==============================================================================
|
||||
* i2c_manager.h - HW / SW I2C mutex control
|
||||
*
|
||||
* Manages the mutually-exclusive HW TWI and SW bit-bang I2C modes.
|
||||
* Only one mode may be active at a time.
|
||||
*
|
||||
* Flags:
|
||||
* HW_I2C_FRQ : true when HW TWI mode is active
|
||||
* SW_I2C_FRQ : true when SW bit-bang mode is active
|
||||
*============================================================================*/
|
||||
#ifndef __I2C_MANAGER_H__
|
||||
#define __I2C_MANAGER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "app_error.h"
|
||||
|
||||
extern bool HW_I2C_FRQ;
|
||||
extern bool SW_I2C_FRQ;
|
||||
|
||||
/* Initialise HW I2C (TWI) mode. If SW mode is active it is released first.
|
||||
* No-op if HW mode is already active. Call before ICM42670P IMU access. */
|
||||
void hw_i2c_init_once(void);
|
||||
|
||||
/* Initialise SW I2C (bit-bang) mode (legacy, currently unused).
|
||||
* If HW mode is active it is released first. */
|
||||
void sw_i2c_init_once(void);
|
||||
|
||||
/* Reset both mode flags to false, forcing re-initialisation on next call. */
|
||||
void i2c_reset_state(void);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,182 @@
|
||||
/*******************************************************************************
|
||||
* @file main.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief VesiScan BASIC main header file
|
||||
*
|
||||
* [System Overview]
|
||||
* VesiScan BASIC is an nRF52840-based BLE bladder monitoring patch device.
|
||||
* This header defines enums, function declarations, and global variables used system-wide.
|
||||
*
|
||||
* [Communication]
|
||||
* - BLE NUS (Nordic UART Service): binary protocol with smartphone app
|
||||
* - Physical UART (1Mbps): debug and factory testing
|
||||
*
|
||||
* [Data Transmission Flow]
|
||||
* 1. Receive command from app/UART -> received_command_process()
|
||||
* 2. Collect sensor data (battery, temperature, IMU, pressure)
|
||||
* 3. Build binary packets via format_data() family
|
||||
* 4. Transmit over BLE with CRC16 appended via dr_binary_tx_safe()
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MAIN_H__
|
||||
#define MAIN_H__
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Firmware Identification Code
|
||||
* - VBTFW0100 = Development (test) build Ver 1.00
|
||||
* - VB0FW0100 = Production build Ver 1.00
|
||||
*
|
||||
* Firmware Version Update History
|
||||
* - VBTFW0101 : Merged reb+red packets (single packet per channel), 260330 jhChun
|
||||
* - VBTFW0102 : Added LED state command (msl) and re-pairing support, 260331 jhChun
|
||||
* - VBTFW0103 260416 jhChun
|
||||
* : Stabilized ADC measurement by clearing buffers before sampling.
|
||||
* : Improved low-battery detection and automatic power-off handling.
|
||||
* : Updated BLE security, bonding, and advertising timeout behavior.
|
||||
* : Cleaned up command parsing and removed unused project files.
|
||||
* - VBTFW0111 260422 jhChun : Updated firmware version for test.
|
||||
------------------------------------------------------------------------- */
|
||||
#define FIRMWARE_VERSION "VBTFW0111"
|
||||
|
||||
/*==============================================================================
|
||||
* Data Length Constants
|
||||
*============================================================================*/
|
||||
#define SERIAL_NO_LENGTH 12 /* Serial number length (e.g. "VB026030000") */
|
||||
#define HW_NO_LENGTH 12 /* Hardware number (version) length */
|
||||
#define PASSKEY_LENGTH 6 /* BLE pairing passkey length (6 digits) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include "boards.h"
|
||||
|
||||
/*==============================================================================
|
||||
* Enum Definitions
|
||||
*============================================================================*/
|
||||
|
||||
/* Device ON/OFF control enum (EEPROM, power, etc.) */
|
||||
typedef enum
|
||||
{
|
||||
OFF = 0, /* Off */
|
||||
ON = 1 /* On */
|
||||
}on_off_cont_t;
|
||||
|
||||
/* Command source identifier (BLE or UART) */
|
||||
typedef enum
|
||||
{
|
||||
CMD_BLE = 0, /* Command received via BLE NUS */
|
||||
CMD_UART = 1 /* Command received via physical UART */
|
||||
}which_cmd_t;
|
||||
|
||||
/* Chamber auto-test mode (when FEATURE_CHAMBER_AUTO_TEST enabled) */
|
||||
#if FEATURE_CHAMBER_AUTO_TEST
|
||||
typedef enum
|
||||
{
|
||||
SIMPLE_AUTO_MODE = 0, /* Simple auto mode */
|
||||
HALF_AUTO_MODE = 1, /* Semi-auto mode */
|
||||
FULL_AUTO_MODE = 2, /* Full auto mode */
|
||||
NONE_AUTO_MODE = 3 /* No auto mode */
|
||||
}auto_meas_mode_t;
|
||||
#endif
|
||||
|
||||
/* BLE connection state */
|
||||
typedef enum
|
||||
{
|
||||
BLE_DISCONNECTED_ST = 0, /* BLE disconnected */
|
||||
BLE_CONNECTED_ST = 1 /* BLE connected */
|
||||
}ble_status_t;
|
||||
|
||||
/*==============================================================================
|
||||
* Function Declarations
|
||||
*============================================================================*/
|
||||
|
||||
#if FEATURE_SECURE_CONNECTION
|
||||
/* Start BLE advertising (if erase_bonds=true, delete bond info first) */
|
||||
static void advertising_start(bool erase_bonds);
|
||||
#endif
|
||||
|
||||
/* Enter sleep mode: show LED, then power off after POWER_OFF_DELAY (3s) */
|
||||
void sleep_mode_enter(void);
|
||||
|
||||
/* Power-off timer callback: physically cut power after POWER_OFF_DELAY */
|
||||
static void t_power_off_timeout_handler(void * p_context);
|
||||
|
||||
/* Device power off: show LED, then delayed power cut via timer */
|
||||
void device_power_off(void);
|
||||
|
||||
/* Power control handler: physical power ON/OFF via POWER_HOLD pin */
|
||||
static void power_control_handler(on_off_cont_t device_power_st);
|
||||
|
||||
/* Power button state machine (timer callback, 5ms interval):
|
||||
* - Short press (<1.5s): power OFF
|
||||
* - Medium press (1.5s~10s): start boot sequence
|
||||
* - Long press (>10s): factory reset (passkey reset + power OFF) */
|
||||
static void main_s(void * p_context);
|
||||
|
||||
/* Peer Manager timer callback: force BLE disconnect if reset_status==5 */
|
||||
static void PM_s(void * p_context);
|
||||
|
||||
//static void main_re(void * p_context);
|
||||
|
||||
/* Main routine handler (legacy, currently unused) */
|
||||
static void main_routine_handler(void * p_context);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Data Transmission Functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Send ASCII text over BLE (up to '\r', CRC16 appended automatically) */
|
||||
void data_tx_handler(char const *p_data_to_send);
|
||||
|
||||
/* Safe binary data BLE transmission (CRC16 appended, with retry logic)
|
||||
* @param ble_bin_buff Binary buffer to transmit
|
||||
* @param length Data length in uint16_t words (actual bytes = length x 2) */
|
||||
void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length);
|
||||
|
||||
/* SoftDevice-compatible delay (nrf_delay_ms wrapper) */
|
||||
void dr_sd_delay_ms(uint32_t ms);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Binary Packet Format Functions
|
||||
* Packet structure: [4-byte tag][data][2-byte CRC16]
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/* Format single uint16_t value: [tag 4B][value 2B] */
|
||||
void single_format_data(uint8_t *buffer, const char *tag, const uint16_t value) ;
|
||||
|
||||
/* Format uint16_t array: [tag 4B][data0 2B][data1 2B]... */
|
||||
void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length);
|
||||
|
||||
/* Format uint8_t byte array: [tag 4B][byte0][byte1]... */
|
||||
void format_data_byte(uint8_t *buffer, const char *tag, const uint8_t *data_array, size_t length);
|
||||
|
||||
/* Format ASCII string: [tag 4B][char0][char1]... */
|
||||
void ascii_format_data(uint8_t *buffer, const char *tag, const char *data_ascii, size_t length);
|
||||
|
||||
/*==============================================================================
|
||||
* Global Variables (extern)
|
||||
*============================================================================*/
|
||||
extern volatile bool data_tx_in_progress; /* BLE TX in progress flag */
|
||||
extern volatile bool ble_connection_st; /* BLE connection state (0=disconnected, 1=connected) */
|
||||
|
||||
/* 2026-03-17: Global variables moved from cmd_parse.c to main.c */
|
||||
extern char SERIAL_NO[SERIAL_NO_LENGTH]; /* Serial number */
|
||||
extern char HW_NO[HW_NO_LENGTH]; /* Hardware number */
|
||||
extern char m_static_passkey[PASSKEY_LENGTH]; /* BLE static passkey */
|
||||
extern bool bond_data_delete; /* Bond data delete request flag */
|
||||
extern uint32_t m_life_cycle; /* Device life cycle counter */
|
||||
extern uint8_t resetCount; /* Communication timeout counter */
|
||||
extern bool info4; /* Measurement with extra info flag */
|
||||
extern uint8_t m_reset_status; /* Reset status code */
|
||||
|
||||
extern uint8_t ble_bin_buffer[]; /* BLE binary response buffer */
|
||||
|
||||
/* Send error response */
|
||||
void param_error(const char *cmd);
|
||||
|
||||
#endif //MAIN_H__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,502 @@
|
||||
/*******************************************************************************
|
||||
* @file dr_adc121s051.h
|
||||
* @brief ADC121S051 12-bit ADC Driver for nRF52840
|
||||
* For 1.2MHz Piezo Echo Envelope Detection
|
||||
* @author Charles KWON
|
||||
* @date 2025-12-15
|
||||
*
|
||||
* @details This driver reads the envelope-detected DC level from piezo echo.
|
||||
*
|
||||
* Signal Flow:
|
||||
*
|
||||
* [Piezo TX] [Echo RX] [Envelope] [ADC] [MCU]
|
||||
* 1.2MHz --> Reflect --> Detector --> DC Level --> Digital
|
||||
* burst signal (hardware) reading value
|
||||
*
|
||||
* The envelope detector circuit converts the 1.2MHz echo burst
|
||||
* into a DC voltage proportional to the echo amplitude.
|
||||
* ADC samples this DC level for amplitude measurement.
|
||||
*
|
||||
* @note Hardware: Texas Instruments ADC121S051
|
||||
* - 12-bit resolution (0-4095)
|
||||
* - Sample rate: 200-500 ksps
|
||||
* - Input range: 0V to VA
|
||||
* - SPI interface (software bit-bang)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef DR_ADC121S051_H
|
||||
#define DR_ADC121S051_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_gpio.h"
|
||||
|
||||
/*==============================================================================
|
||||
* PIN CONFIGURATION
|
||||
*
|
||||
* WARNING: Never hardcode pin numbers!
|
||||
* Hardcoding may save a developer's time momentarily,
|
||||
* but it will also shorten their lifespan.
|
||||
*============================================================================*/
|
||||
#define DR_ADC_PIN_SCLK NRF_GPIO_PIN_MAP(0, 14) /**< Serial Clock */
|
||||
#define DR_ADC_PIN_SDATA NRF_GPIO_PIN_MAP(0, 15) /**< Serial Data (MISO) */
|
||||
#define DR_ADC_PIN_CS NRF_GPIO_PIN_MAP(0, 19) /**< Chip Select P0.13 -> P0.19 */
|
||||
|
||||
/*==============================================================================
|
||||
* ADC SPECIFICATIONS
|
||||
*============================================================================*/
|
||||
#define DR_ADC_RESOLUTION 12 /**< Bits */
|
||||
#define DR_ADC_MAX_VALUE 4095 /**< 2^12 - 1 */
|
||||
#define DR_ADC_VREF_MV 3300 /**< Reference voltage (mV) */
|
||||
|
||||
/*==============================================================================
|
||||
* ECHO DETECTION CONFIGURATION
|
||||
*
|
||||
* Bladder Measurement Requirements:
|
||||
* - Target measurement range: 20cm (200mm)
|
||||
* - SCLK frequency: 8.6MHz (bit-bang SPI)
|
||||
* - ADC121S051 requires 16 SCLK cycles per sample
|
||||
* - Actual sample rate: 8.6MHz / 16 = 0.5375MHz = 537.5kHz
|
||||
* - Actual sample interval: 16 / 8.6MHz = 1.86us
|
||||
* - Sound speed in tissue: 1540m/s = 1.54mm/us
|
||||
*
|
||||
* Formula: samples = distance(mm) * 2 / (1.86us * 1.54mm/us)
|
||||
* = distance(mm) * 2 / 2.86
|
||||
* = distance(mm) * 0.7
|
||||
*
|
||||
* 10cm = 100mm -> 100 * 0.7 = 70 samples (round-trip 130us)
|
||||
* 17cm = 170mm -> 170 * 0.7 = 119 samples (round-trip 221us)
|
||||
* 20cm = 200mm -> 200 * 0.7 = 140 samples (round-trip 260us)
|
||||
*
|
||||
* Buffer size: 200 samples * 2 bytes = 400 bytes (RAM 256KB, OK)
|
||||
* BLE transmission: 140 samples * 2 bytes = 280 bytes (16-bit raw, no packing)
|
||||
*============================================================================*/
|
||||
#define DR_ADC_SCLK_MHZ 8.6f /**< SPI bit-bang SCLK frequency */
|
||||
#define DR_ADC_CLOCKS_PER_SAMPLE 16 /**< ADC121S051: 16 SCLK per sample */
|
||||
#define DR_ADC_ECHO_SAMPLES_MAX 119 /**< Maximum samples */
|
||||
#define DR_ADC_ECHO_SAMPLES_DEFAULT 100 /**< Default samples */
|
||||
#define DR_ADC_SAMPLE_INTERVAL_US 1.86f /**< 16 / 8.6MHz = 1.86us per sample */
|
||||
#define DR_ADC_SOUND_SPEED_MM_US 1.54f /**< Sound speed in tissue (mm/us) */
|
||||
|
||||
/*==============================================================================
|
||||
* ERROR CODES
|
||||
*============================================================================*/
|
||||
typedef enum {
|
||||
DR_ADC_OK = 0,
|
||||
DR_ADC_ERR_NOT_INIT,
|
||||
DR_ADC_ERR_INVALID_PARAM,
|
||||
DR_ADC_ERR_NO_ECHO
|
||||
} dr_adc_err_t;
|
||||
|
||||
/*==============================================================================
|
||||
* DATA STRUCTURES
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Single ADC reading result
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t raw; /**< Raw 12-bit value (0-4095) */
|
||||
uint32_t voltage_mv; /**< Voltage in millivolts */
|
||||
} dr_adc_result_t;
|
||||
|
||||
/**
|
||||
* @brief Echo measurement result
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t peak_raw; /**< Peak amplitude (raw) */
|
||||
uint32_t peak_mv; /**< Peak amplitude (mV) */
|
||||
uint16_t peak_index; /**< Sample index of peak */
|
||||
uint32_t peak_time_us; /**< Time to peak (us) */
|
||||
uint16_t baseline_raw; /**< Baseline level before echo */
|
||||
uint16_t num_samples; /**< Number of samples captured */
|
||||
} dr_adc_echo_t;
|
||||
|
||||
/**
|
||||
* @brief Echo capture configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t num_samples; /**< Samples to capture (1-200) */
|
||||
uint16_t threshold_raw; /**< Minimum peak threshold */
|
||||
uint16_t delay_us; /**< Delay before capture starts */
|
||||
} dr_adc_echo_config_t;
|
||||
|
||||
/*==============================================================================
|
||||
* INITIALIZATION
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initialize ADC driver
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_init(void);
|
||||
|
||||
/**
|
||||
* @brief Uninitialize ADC driver
|
||||
*/
|
||||
void dr_adc_uninit(void);
|
||||
|
||||
/**
|
||||
* @brief Check if initialized
|
||||
*/
|
||||
bool dr_adc_is_initialized(void);
|
||||
|
||||
/*==============================================================================
|
||||
* BASIC READ FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Read single ADC value
|
||||
* @param result Pointer to result structure
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_read(dr_adc_result_t *result);
|
||||
|
||||
/**
|
||||
* @brief Read raw 12-bit value only
|
||||
* @param raw_value Pointer to store value
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value);
|
||||
|
||||
/**
|
||||
* @brief Read averaged value
|
||||
* @param result Pointer to result structure
|
||||
* @param num_samples Number of samples to average (1-256)
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_read_averaged(dr_adc_result_t *result, uint16_t num_samples);
|
||||
|
||||
/*==============================================================================
|
||||
* ECHO DETECTION FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Capture echo envelope after piezo burst
|
||||
* @param buffer Array to store samples (must be pre-allocated)
|
||||
* @param num_samples Number of samples to capture
|
||||
* @return dr_adc_err_t Error code
|
||||
*
|
||||
* @note Call this immediately after dr_piezo_burst_sw()
|
||||
*/
|
||||
dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples);
|
||||
|
||||
/**
|
||||
* @brief Capture and analyze echo in one call
|
||||
* @param echo Pointer to echo result structure
|
||||
* @param config Pointer to capture configuration (NULL for defaults)
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Piezo burst + Echo capture in one call
|
||||
* @param cycles Number of burst cycles (3~7)
|
||||
* @param delay_us Delay before capture (us)
|
||||
* @param num_samples Number of samples to capture
|
||||
* @param echo Pointer to echo result structure
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
|
||||
uint16_t num_samples, dr_adc_echo_t *echo);
|
||||
|
||||
/**
|
||||
* @brief Get pointer to last captured echo buffer
|
||||
* @return Pointer to internal buffer (valid until next capture)
|
||||
* @note Buffer contains num_samples values from last burst_and_capture call
|
||||
*/
|
||||
const uint16_t* dr_adc_get_echo_buffer(void);
|
||||
|
||||
/**
|
||||
* @brief Analyze captured echo buffer
|
||||
* @param buffer Sample buffer
|
||||
* @param num_samples Number of samples in buffer
|
||||
* @param echo Pointer to echo result structure
|
||||
* @param threshold Minimum threshold for valid peak
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
|
||||
dr_adc_echo_t *echo, uint16_t threshold);
|
||||
|
||||
/**
|
||||
* @brief Find peak in buffer
|
||||
* @param buffer Sample buffer
|
||||
* @param num_samples Number of samples
|
||||
* @param peak_value Pointer to store peak value
|
||||
* @param peak_index Pointer to store peak index (can be NULL)
|
||||
*/
|
||||
void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
|
||||
uint16_t *peak_value, uint16_t *peak_index);
|
||||
|
||||
/**
|
||||
* @brief Calculate baseline (average of first N samples)
|
||||
* @param buffer Sample buffer
|
||||
* @param num_samples Number of samples to average for baseline
|
||||
* @return Baseline value
|
||||
*/
|
||||
uint16_t dr_adc_calc_baseline(const uint16_t *buffer, uint16_t num_samples);
|
||||
|
||||
/*==============================================================================
|
||||
* UTILITY FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Convert raw value to millivolts
|
||||
* @param raw_value Raw 12-bit value
|
||||
* @return Voltage in millivolts
|
||||
*/
|
||||
uint32_t dr_adc_raw_to_mv(uint16_t raw_value);
|
||||
|
||||
/**
|
||||
* @brief Set reference voltage
|
||||
* @param vref_mv Reference voltage in millivolts
|
||||
*/
|
||||
void dr_adc_set_vref(uint32_t vref_mv);
|
||||
|
||||
/**
|
||||
* @brief Get reference voltage
|
||||
* @return Reference voltage in millivolts
|
||||
*/
|
||||
uint32_t dr_adc_get_vref(void);
|
||||
|
||||
/*==============================================================================
|
||||
* DEBUG FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
/*==============================================================================
|
||||
* POWER CONTROL
|
||||
*============================================================================*/
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* BLE TRANSMISSION CALLBACK
|
||||
*============================================================================*/
|
||||
|
||||
/*==============================================================================
|
||||
* INTEGRATED BURST + CAPTURE + TRANSMIT
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Piezo burst + ADC capture + BLE transmission (all-in-one)
|
||||
*
|
||||
* This function performs the complete measurement cycle internally:
|
||||
* 1. Power on ADC
|
||||
* 2. Select piezo channel (0~7)
|
||||
* 3. Execute piezo burst (frequency based on freq_option)
|
||||
* 4. Capture echo samples (after delay_us) - repeated 'averaging' times
|
||||
* 5. Average the captured samples (firmware-level noise reduction)
|
||||
* 6. Analyze peak/baseline
|
||||
* 7. Transmit data via BLE with proper packet timing
|
||||
*
|
||||
* @param freq_option Frequency option: 0=1.8MHz (default), 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
|
||||
* @param delay_us Delay before capture (us), default 20
|
||||
* @param num_samples Number of samples to capture (1~200)
|
||||
* @param cycles Number of burst cycles (3~7), default 5
|
||||
* @param averaging Number of measurements to average (1~1000), default 1
|
||||
* @param piezo_ch Piezo channel to use (0~7), default 0
|
||||
* @param ble_buffer Working buffer for BLE packets (must be >= 240 bytes)
|
||||
* @return dr_adc_err_t Error code
|
||||
*
|
||||
* @note Must call dr_adc_register_ble_tx() before using this function
|
||||
* @note BLE packets: reb: (header+data merged), red: (continuation, >119 samples only)
|
||||
* @note Higher averaging reduces noise but increases measurement time (~0.3ms per avg)
|
||||
*/
|
||||
dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_us,
|
||||
uint16_t num_samples, uint8_t cycles,
|
||||
uint16_t averaging, uint8_t piezo_ch,
|
||||
uint8_t *ble_buffer, uint8_t skip_raa);
|
||||
|
||||
/**
|
||||
* @brief Select piezo channel (0~7)
|
||||
* @param channel Piezo channel number (0~7)
|
||||
*
|
||||
* @note Hardware-dependent: requires MUX or individual GPIO control
|
||||
* Currently uses placeholder - implement based on actual hardware
|
||||
*/
|
||||
void dr_piezo_select_channel(uint8_t channel);
|
||||
|
||||
/*==============================================================================
|
||||
* 4-CHANNEL CAPTURE (maa? command support)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 8-channel echo buffer for maa? command
|
||||
* Memory: 140 samples × 2 bytes × 8 channels = 2,240 bytes
|
||||
*/
|
||||
#define MAA_NUM_CHANNELS 6 /* 4 -> 8 -> 6 jhChun 26.03.17*/
|
||||
#define MAA_SAMPLES_MAX 200
|
||||
|
||||
/**
|
||||
* @brief Echo data for one channel
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t samples[MAA_SAMPLES_MAX]; /**< Raw sample data */
|
||||
uint16_t num_samples; /**< Actual sample count */
|
||||
} dr_maa_channel_t;
|
||||
|
||||
/**
|
||||
* @brief Capture echo from one channel (no BLE transmission)
|
||||
*
|
||||
* Captures averaged echo data for a single channel and stores
|
||||
* in the provided channel buffer. Does NOT transmit via BLE.
|
||||
*
|
||||
* @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
|
||||
* @param delay_us Delay before capture (us)
|
||||
* @param num_samples Number of samples (1~200)
|
||||
* @param cycles Burst cycles (3~7)
|
||||
* @param averaging Number of averages (1~1000)
|
||||
* @param piezo_ch Piezo channel (0~7)
|
||||
* @param out_channel Output channel data structure
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
|
||||
uint16_t num_samples, uint8_t cycles,
|
||||
uint16_t averaging, uint8_t piezo_ch,
|
||||
dr_maa_channel_t *out_channel);
|
||||
|
||||
/**
|
||||
* @brief Transmit captured channel data via BLE
|
||||
*
|
||||
* Sends previously captured channel data using reb+red merged protocol.
|
||||
* reb: tag(4) + num_samples(2) + data(up to 238B). red: only if > 119 samples.
|
||||
*
|
||||
* @param ch_data Pointer to captured channel data
|
||||
* @param ble_buffer Working buffer for BLE packets (>= 244 bytes)
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
|
||||
uint8_t *ble_buffer);
|
||||
|
||||
/*==============================================================================
|
||||
* DELTA COMPRESSION (maa? mode=1)
|
||||
*
|
||||
* Format:
|
||||
* Byte 0-1: First sample (16-bit, little endian)
|
||||
* Byte 2+: Delta values (8-bit signed)
|
||||
* If delta > 127 or < -127: escape (0x80) + 16-bit value
|
||||
*
|
||||
* Expected compression: ~50% (280 bytes -> ~140 bytes)
|
||||
*============================================================================*/
|
||||
|
||||
#define DELTA_ESCAPE_BYTE 0x80 /**< Escape marker for out-of-range delta */
|
||||
|
||||
/**
|
||||
* @brief Compress sample data using delta encoding
|
||||
*
|
||||
* @param samples Input sample array (16-bit values)
|
||||
* @param num_samples Number of samples
|
||||
* @param out_buffer Output buffer for compressed data
|
||||
* @param out_size Output: number of bytes written
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples,
|
||||
uint8_t *out_buffer, uint16_t *out_size);
|
||||
|
||||
/**
|
||||
* @brief Transmit captured channel data via BLE with delta compression
|
||||
*
|
||||
* Uses rdb+rdd merged protocol (delta variant of reb+red merged)
|
||||
*
|
||||
* @param ch_data Pointer to captured channel data
|
||||
* @param ble_buffer Working buffer for BLE packets (>= 240 bytes)
|
||||
* @return dr_adc_err_t Error code
|
||||
*/
|
||||
dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
|
||||
uint8_t *ble_buffer);
|
||||
|
||||
/*==============================================================================
|
||||
* ASYNC MAA - Non-blocking 8-channel capture
|
||||
*
|
||||
* Design: State machine driven by BLE TX complete events
|
||||
* Flow:
|
||||
* maa? cmd -> maa_async_start() -> capture all CH -> TX reb:(header+data) -> TX red: (if needed)
|
||||
* BLE_NUS_EVT_TX_RDY -> maa_async_on_tx_ready() -> TX next packet or next channel
|
||||
* All done -> TX raa: -> state=IDLE
|
||||
*============================================================================*/
|
||||
|
||||
/** @brief MAA async state machine states */
|
||||
typedef enum {
|
||||
MAA_ASYNC_IDLE = 0, /**< Not active */
|
||||
MAA_ASYNC_CAPTURING, /**< ADC capture in progress */
|
||||
MAA_ASYNC_TX_HEADER, /**< Sending reb: header+data merged */
|
||||
MAA_ASYNC_TX_DATA, /**< Sending red: data packets */
|
||||
MAA_ASYNC_NEXT_CHANNEL, /**< Preparing next channel */
|
||||
MAA_ASYNC_COMPLETE /**< Sending raa: and finishing */
|
||||
} maa_async_state_t;
|
||||
|
||||
/** @brief MAA async context */
|
||||
typedef struct {
|
||||
maa_async_state_t state; /**< Current state */
|
||||
uint8_t current_ch; /**< Current channel (0~7) */
|
||||
uint8_t current_pkt; /**< Current packet index */
|
||||
uint16_t data_offset; /**< Bytes sent so far for current channel */
|
||||
uint8_t freq_option; /**< Frequency option */
|
||||
uint16_t delay_us; /**< Capture delay */
|
||||
uint16_t num_samples; /**< Samples per channel */
|
||||
uint8_t cycles; /**< Burst cycles */
|
||||
uint16_t averaging; /**< Averaging count */
|
||||
uint8_t *ble_buffer; /**< Working buffer for BLE packets */
|
||||
dr_maa_channel_t channels[MAA_NUM_CHANNELS]; /**< Captured data for each channel */
|
||||
bool pre_capture_all; /**< true: capture all channels before transmitting (mbb) */
|
||||
void (*on_complete_cb)(void); /**< callback after async capture completes (NULL = none) */
|
||||
} maa_async_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief Start async MAA 8-channel capture
|
||||
*
|
||||
* Initiates the async state machine. Captures CH0 and begins transmission.
|
||||
* Subsequent packets are sent when maa_async_on_tx_ready() is called.
|
||||
*
|
||||
* @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
|
||||
* @param delay_us Capture delay (us)
|
||||
* @param num_samples Samples per channel (1~200)
|
||||
* @param cycles Burst cycles (3~7)
|
||||
* @param averaging Averaging count (1~1000)
|
||||
* @param ble_buffer Working buffer (>= 244 bytes)
|
||||
* @return dr_adc_err_t DR_ADC_OK if started successfully
|
||||
*/
|
||||
dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us,
|
||||
uint16_t num_samples, uint8_t cycles,
|
||||
uint16_t averaging, uint8_t *ble_buffer);
|
||||
|
||||
/**
|
||||
* @brief Handle BLE TX ready event
|
||||
*
|
||||
* Called from BLE_NUS_EVT_TX_RDY handler. Sends next packet or
|
||||
* transitions to next state.
|
||||
*
|
||||
* @return true if more work pending, false if complete or idle
|
||||
*/
|
||||
bool maa_async_on_tx_ready(void);
|
||||
|
||||
/**
|
||||
* @brief Check if async MAA is active
|
||||
* @return true if state != IDLE
|
||||
*/
|
||||
bool maa_async_is_busy(void);
|
||||
|
||||
/**
|
||||
* @brief Get current async state (for debugging)
|
||||
* @return Current state
|
||||
*/
|
||||
maa_async_state_t maa_async_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Abort async MAA operation
|
||||
*/
|
||||
void maa_async_abort(void);
|
||||
|
||||
/**
|
||||
* @brief Set auto power-off flag (power off after completion)
|
||||
*/
|
||||
void maa_async_set_auto_power(bool on);
|
||||
void maa_async_set_pre_capture_all(bool on);
|
||||
|
||||
/**
|
||||
* @brief Set async capture completion callback
|
||||
* Called after raa: is transmitted and power-off. NULL = no callback.
|
||||
*/
|
||||
void maa_async_set_on_complete(void (*cb)(void));
|
||||
|
||||
#endif /* DR_ADC121S051_H */
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/*==============================================================================
|
||||
* battery_saadc.c - Battery voltage ADC measurement
|
||||
*
|
||||
* Measures battery voltage via nRF52840 SAADC on AIN2:
|
||||
* - 12-bit resolution, 4x oversampling
|
||||
* - Periodic safety check via battery_loop timer (60 s interval)
|
||||
* - Sequential: battery -> temperature measurement
|
||||
* - Auto power-off after 5 consecutive readings below 3500 mV or above 40 C
|
||||
* - In info4 mode (bulk sensor collection): stores to info_batt
|
||||
*
|
||||
* Voltage conversion:
|
||||
* mV = ADC_VALUE * (600 / 4095) * 6 * 1.42 (resistor divider correction)
|
||||
*============================================================================*/
|
||||
|
||||
#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 "battery_saadc.h"
|
||||
#include "main_timer.h"
|
||||
#include "tmp235_q1.h"
|
||||
#include "dr_piezo.h"
|
||||
#include "debug_print.h"
|
||||
|
||||
/* SAADC internal reference voltage (mV, float) */
|
||||
#define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600.0f
|
||||
|
||||
/* 1/3 prescaling compensation (input divided by 3, then x2 = total x6) */
|
||||
#define BATTERY_PRE_SCALING_COMPENSATION 6.0f
|
||||
|
||||
/* 12-bit ADC maximum digital value */
|
||||
#define BATTERY_ADC_RES_12BITS 4095.0f
|
||||
|
||||
/* Convert raw ADC value 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)
|
||||
|
||||
/* Single ADC buffer (uninit after each measurement, no double-buffer needed) */
|
||||
static nrf_saadc_value_t adc_buf;
|
||||
|
||||
/* Battery monitoring repeat timer */
|
||||
APP_TIMER_DEF(m_battery_loop_timer_id);
|
||||
|
||||
/* Battery monitoring interval (ms) */
|
||||
#define BATTERY_LOOP_INTERVAL 60000
|
||||
|
||||
/* Safety check consecutive count threshold */
|
||||
#define SAFETY_CHECK_COUNT 5
|
||||
|
||||
/* Low-battery check flag — set by battery_loop, consumed by handler */
|
||||
bool low_battery_check = false;
|
||||
|
||||
/* Safety check mode flag — set by battery handler, consumed by tmp235 handler */
|
||||
bool safety_check_mode = false;
|
||||
|
||||
/* SAADC callback completion flag — used by all_sensors() to wait */
|
||||
volatile bool battery_saadc_done = false;
|
||||
|
||||
/* Safety check: cached battery voltage for use in safety_check_complete() */
|
||||
static float safety_batt_mv = 0;
|
||||
|
||||
/* Safety check: consecutive counters */
|
||||
static uint8_t low_battery_cnt = 0;
|
||||
static uint8_t over_temp_cnt = 0;
|
||||
|
||||
/* info4: bulk sensor collection mode flag */
|
||||
extern bool info4;
|
||||
|
||||
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
|
||||
extern bool go_device_power_off;
|
||||
extern which_cmd_t cmd_type_t;
|
||||
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN];
|
||||
|
||||
/* info4 mode: cached battery voltage (mV) */
|
||||
volatile uint16_t info_batt;
|
||||
|
||||
/* info4 sequential measurement control flags */
|
||||
extern bool go_temp;
|
||||
extern bool go_batt;
|
||||
|
||||
extern bool motion_raw_data_enabled;
|
||||
extern bool ble_got_new_data;
|
||||
extern bool motion_data_once;
|
||||
|
||||
/*==============================================================================
|
||||
* safety_check_complete - Called by tmp235 handler after temperature measurement
|
||||
*
|
||||
* Checks both battery voltage and temperature against thresholds.
|
||||
* 5 consecutive readings exceeding either threshold triggers power OFF.
|
||||
*============================================================================*/
|
||||
void safety_check_complete(float temp_c)
|
||||
{
|
||||
//DBG_PRINTF("[SAFETY] Batt=%d mV, Temp=%d.%d C\r\n",
|
||||
// (int)safety_batt_mv, (int)temp_c, ((int)(temp_c * 10)) % 10);
|
||||
|
||||
/* Battery check */
|
||||
if (safety_batt_mv <= LOW_BATTERY_VOLTAGE)
|
||||
{
|
||||
low_battery_cnt++;
|
||||
DBG_PRINTF("[SAFETY] Low batt cnt=%d\r\n", low_battery_cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
low_battery_cnt = 0;
|
||||
}
|
||||
|
||||
/* Temperature check */
|
||||
if (temp_c >= OVER_TEMPERATURE_THRESHOLD)
|
||||
{
|
||||
over_temp_cnt++;
|
||||
DBG_PRINTF("[SAFETY] Over temp cnt=%d\r\n", over_temp_cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
over_temp_cnt = 0;
|
||||
}
|
||||
|
||||
/* Power OFF if either threshold exceeded 5 consecutive times */
|
||||
if (low_battery_cnt >= SAFETY_CHECK_COUNT)
|
||||
{
|
||||
low_battery_cnt = 0;
|
||||
DBG_PRINTF("[SAFETY] Low battery -> Power OFF\r\n");
|
||||
go_device_power_off = true;
|
||||
main_timer_start();
|
||||
}
|
||||
else if (over_temp_cnt >= SAFETY_CHECK_COUNT)
|
||||
{
|
||||
over_temp_cnt = 0;
|
||||
DBG_PRINTF("[SAFETY] Over temperature -> Power OFF\r\n");
|
||||
go_device_power_off = true;
|
||||
main_timer_start();
|
||||
}
|
||||
|
||||
dr_piezo_power_off();
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* battery_event_handler - SAADC conversion complete callback
|
||||
*
|
||||
* Converts the raw ADC value to battery voltage (mV) and then:
|
||||
* - Low-battery check mode: store voltage, chain temperature measurement
|
||||
* - info4 mode: store to info_batt (no BLE send)
|
||||
* - Normal mode: send rsn: response over BLE or UART
|
||||
*============================================================================*/
|
||||
void battery_event_handler(nrf_drv_saadc_evt_t const * p_event)
|
||||
{
|
||||
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;
|
||||
|
||||
register_val = p_event->data.done.p_buffer[0];
|
||||
|
||||
/* Release SAADC — shared with temperature / pressure ADC */
|
||||
nrf_drv_saadc_channel_uninit(0);
|
||||
nrf_drv_saadc_uninit();
|
||||
|
||||
battery_saadc_done = true;
|
||||
|
||||
/* ADC -> mV conversion */
|
||||
batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val);
|
||||
|
||||
/* Resistor divider correction factor 1.42 */
|
||||
batt_lvl_in_milli_volt_1 = batt_lvl_in_milli_volt_0 * 1.42f;
|
||||
|
||||
/* --- Safety check mode: store voltage, chain temperature measurement --- */
|
||||
if (low_battery_check == true)
|
||||
{
|
||||
low_battery_check = false;
|
||||
safety_batt_mv = batt_lvl_in_milli_volt_1;
|
||||
safety_check_mode = true;
|
||||
|
||||
/* TMP235 shares piezo TX/RX power rail */
|
||||
if (!dr_piezo_is_power_on())
|
||||
{
|
||||
dr_piezo_power_on();
|
||||
}
|
||||
tmp235_voltage_level_meas();
|
||||
}
|
||||
|
||||
/* --- info4 mode: store value for mbb? bulk response --- */
|
||||
else if (info4 == true)
|
||||
{
|
||||
info_batt = batt_lvl_in_milli_volt_1;
|
||||
}
|
||||
|
||||
/* --- Normal mode: send rsn: BLE response --- */
|
||||
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)
|
||||
{
|
||||
single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1);
|
||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* battery_configure - Set up SAADC for battery voltage measurement
|
||||
*
|
||||
* AIN2, single-ended, 1/6 gain, 12-bit, 4x oversampling, burst enabled.
|
||||
* Registers a single buffer (uninit after one conversion).
|
||||
*============================================================================*/
|
||||
static void battery_configure(void)
|
||||
{
|
||||
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, battery_event_handler);
|
||||
if (err_code != NRF_SUCCESS)
|
||||
{
|
||||
return; /* SAADC busy — skip this cycle, retry next */
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* battery_level_meas - Start a single battery voltage measurement
|
||||
*
|
||||
* Configures SAADC and triggers sampling. Result arrives asynchronously
|
||||
* via battery_event_handler.
|
||||
*============================================================================*/
|
||||
void battery_level_meas(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
battery_configure();
|
||||
err_code = nrf_drv_saadc_sample();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* battery_loop - Periodic battery monitoring timer callback
|
||||
*
|
||||
* Sets the low-battery check flag and starts a measurement.
|
||||
* Skips if info4 mode is active (SAADC conflict).
|
||||
*============================================================================*/
|
||||
void battery_loop(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
if (info4 == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
low_battery_check = true;
|
||||
battery_level_meas();
|
||||
}
|
||||
|
||||
/* Start the periodic battery monitoring timer. */
|
||||
void battery_timer_start(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_start(m_battery_loop_timer_id, APP_TIMER_TICKS(BATTERY_LOOP_INTERVAL), NULL));
|
||||
}
|
||||
|
||||
/* Stop the battery monitoring timer. */
|
||||
void battery_timer_stop(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_stop(m_battery_loop_timer_id));
|
||||
}
|
||||
|
||||
/* Initialise the battery monitoring timer (repeated mode). */
|
||||
void battery_timer_init(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_create(&m_battery_loop_timer_id, APP_TIMER_MODE_REPEATED, battery_loop));
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*==============================================================================
|
||||
* battery_saadc.h - Battery voltage SAADC measurement interface
|
||||
*
|
||||
* Uses the nRF52840 SAADC to measure battery voltage on AIN2.
|
||||
*
|
||||
* API:
|
||||
* battery_level_meas() : one-shot measurement (async, result via callback)
|
||||
* battery_timer_init/start/stop() : 60-second periodic monitoring timer
|
||||
*
|
||||
* Periodic safety check (every 60 s):
|
||||
* Battery -> Temperature sequential measurement via SAADC.
|
||||
* Auto power-off after 5 consecutive readings below LOW_BATTERY_VOLTAGE (3500 mV)
|
||||
* or above OVER_TEMPERATURE_THRESHOLD (40 C).
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef _BATTERY_SAADC_H_
|
||||
#define _BATTERY_SAADC_H_
|
||||
|
||||
/* Low-battery threshold (mV) — 5 consecutive readings below this -> power OFF */
|
||||
#define LOW_BATTERY_VOLTAGE 3500
|
||||
|
||||
/* Over-temperature threshold (deg C) — 5 consecutive readings above this -> power OFF */
|
||||
#define OVER_TEMPERATURE_THRESHOLD 40.0f
|
||||
|
||||
/* SAADC callback completion flag (used by all_sensors() to wait) */
|
||||
extern volatile bool battery_saadc_done;
|
||||
|
||||
/* Safety check mode flag — set by battery_loop, consumed by tmp235 handler */
|
||||
extern bool safety_check_mode;
|
||||
|
||||
/* Called by tmp235 handler when safety check temperature measurement completes */
|
||||
void safety_check_complete(float temp_c);
|
||||
|
||||
/* Start a single async battery measurement. Result handled in callback. */
|
||||
void battery_level_meas(void);
|
||||
/* Start the 60-second periodic battery monitoring timer. */
|
||||
void battery_timer_start(void);
|
||||
/* Stop the battery monitoring timer. */
|
||||
void battery_timer_stop(void);
|
||||
/* Initialise the battery monitoring timer (call once at app start). */
|
||||
void battery_timer_init(void);
|
||||
|
||||
#endif //_BATTERY_SAADC_H_
|
||||
+103
@@ -0,0 +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));
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+47
@@ -0,0 +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";
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+82
@@ -0,0 +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]);
|
||||
}
|
||||
|
||||
|
||||
+94
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
|
||||
+389
@@ -0,0 +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
|
||||
|
||||
/** \} */
|
||||
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +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_ */
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
|
||||
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+1011
File diff suppressed because it is too large
Load Diff
+1619
File diff suppressed because it is too large
Load Diff
+520
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* ________________________________________________________________________________________________________
|
||||
* 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 Driver IMU driver high level functions
|
||||
* @brief High-level function to setup an IMU device
|
||||
* @ingroup DriverIcm
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file inv_imu_driver.h
|
||||
* High-level function to setup an IMU device
|
||||
*/
|
||||
|
||||
#ifndef _INV_IMU_DRIVER_H_
|
||||
#define _INV_IMU_DRIVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "inv_imu_defs.h"
|
||||
#include "inv_imu_transport.h"
|
||||
|
||||
#include "InvError.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/** @brief IMU max FSR values for accel and gyro
|
||||
* Dependent on chip
|
||||
*/
|
||||
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_16g
|
||||
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_2000dps
|
||||
|
||||
#define ACCEL_OFFUSER_MAX_MG 1000
|
||||
#define GYRO_OFFUSER_MAX_DPS 64
|
||||
|
||||
/** @brief IMU maximum buffer size mirrored from FIFO at polling time
|
||||
* @warning fifo_idx type variable must be large enough to parse the FIFO_MIRRORING_SIZE
|
||||
*/
|
||||
#define FIFO_MIRRORING_SIZE 16 * 258 // packet size * max_count = 4kB
|
||||
|
||||
/** @brief IMU Accelerometer start-up time before having correct data
|
||||
*/
|
||||
#define ACC_STARTUP_TIME_US 10000
|
||||
|
||||
/** @brief IMU Gyroscope start-up time before having correct data
|
||||
*/
|
||||
#define GYR_STARTUP_TIME_US 70000
|
||||
|
||||
/** @brief IMU Gyroscope power off to power on duration
|
||||
*/
|
||||
#define GYR_POWER_OFF_DUR_US 20000
|
||||
|
||||
/** @brief Sensor identifier for UI control function
|
||||
*/
|
||||
enum inv_imu_sensor {
|
||||
INV_SENSOR_ACCEL, /**< Accelerometer */
|
||||
INV_SENSOR_GYRO, /**< Gyroscope */
|
||||
INV_SENSOR_FSYNC_EVENT, /**< FSYNC */
|
||||
INV_SENSOR_TEMPERATURE, /**< Chip temperature */
|
||||
INV_SENSOR_DMP_PEDOMETER_EVENT, /**< Pedometer: step detected */
|
||||
INV_SENSOR_DMP_PEDOMETER_COUNT, /**< Pedometer: step counter */
|
||||
INV_SENSOR_DMP_TILT, /**< Tilt */
|
||||
INV_SENSOR_DMP_FF, /**< FreeFall */
|
||||
INV_SENSOR_DMP_LOWG, /**< Low G */
|
||||
INV_SENSOR_DMP_SMD, /**< Significant Motion Detection */
|
||||
INV_SENSOR_MAX
|
||||
};
|
||||
|
||||
/** @brief Configure Fifo usage
|
||||
*/
|
||||
typedef enum {
|
||||
INV_IMU_FIFO_DISABLED = 0, /**< Fifo is disabled and data source is sensors registers */
|
||||
INV_IMU_FIFO_ENABLED = 1, /**< Fifo is used as data source */
|
||||
}INV_IMU_FIFO_CONFIG_t;
|
||||
|
||||
/** @brief Sensor event structure definition
|
||||
*/
|
||||
typedef struct {
|
||||
int sensor_mask;
|
||||
uint16_t timestamp_fsync;
|
||||
int16_t accel[3];
|
||||
int16_t gyro[3];
|
||||
int16_t temperature;
|
||||
int8_t accel_high_res[3];
|
||||
int8_t gyro_high_res[3];
|
||||
} inv_imu_sensor_event_t;
|
||||
|
||||
/** @brief IMU driver states definition
|
||||
*/
|
||||
struct inv_imu_device {
|
||||
struct inv_imu_transport transport; /**< Transport layer
|
||||
Must be the first one of struct inv_imu_device */
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event); /**< callback executed by:
|
||||
inv_imu_get_data_from_fifo (if FIFO is used)
|
||||
inv_imu_get_data_from_registers (if FIFO isn't used)
|
||||
May be NULL if above API are not used by application */
|
||||
uint8_t fifo_data[FIFO_MIRRORING_SIZE]; /**< FIFO mirroring memory area */
|
||||
uint8_t dmp_is_on; /**< DMP started status */
|
||||
uint8_t endianness_data; /**< Data endianness configuration */
|
||||
uint8_t fifo_highres_enabled; /**< Highres mode configuration */
|
||||
INV_IMU_FIFO_CONFIG_t fifo_is_used; /**< FIFO configuration */
|
||||
uint64_t gyro_start_time_us; /**< Gyro start time used to discard first samples */
|
||||
uint64_t accel_start_time_us; /**< Accel start time used to discard first samples */
|
||||
uint64_t gyro_power_off_tmst; /**< Gyro power off time */
|
||||
};
|
||||
|
||||
|
||||
/* Interrupt enum state for INT1, INT2, and IBI */
|
||||
typedef enum {
|
||||
INV_IMU_DISABLE = 0,
|
||||
INV_IMU_ENABLE
|
||||
} inv_imu_interrupt_value;
|
||||
|
||||
/** @brief Interrupt definition
|
||||
*/
|
||||
typedef struct {
|
||||
inv_imu_interrupt_value INV_UI_FSYNC;
|
||||
inv_imu_interrupt_value INV_UI_DRDY;
|
||||
inv_imu_interrupt_value INV_FIFO_THS;
|
||||
inv_imu_interrupt_value INV_FIFO_FULL;
|
||||
inv_imu_interrupt_value INV_SMD;
|
||||
inv_imu_interrupt_value INV_WOM_X;
|
||||
inv_imu_interrupt_value INV_WOM_Y;
|
||||
inv_imu_interrupt_value INV_WOM_Z;
|
||||
inv_imu_interrupt_value INV_FF;
|
||||
inv_imu_interrupt_value INV_LOWG;
|
||||
inv_imu_interrupt_value INV_STEP_DET;
|
||||
inv_imu_interrupt_value INV_STEP_CNT_OVFL;
|
||||
inv_imu_interrupt_value INV_TILT_DET;
|
||||
} inv_imu_interrupt_parameter_t;
|
||||
|
||||
|
||||
/** @brief Configure the serial interface used to access the device and execute hardware initialization.
|
||||
*
|
||||
* This functions first configures serial interface passed in parameter to make sure device
|
||||
* is accessible both in read and write. Thus no serial access should be done before
|
||||
* successfully executing the present function.
|
||||
*
|
||||
* Then if requested serial interface is a primary interface (aka UI interface or AP
|
||||
* interface), this function initializes the device using the following hardware settings:
|
||||
* - set timestamp resolution to 16us
|
||||
* - enable FIFO mechanism with the following configuration:
|
||||
* - FIFO record mode i.e FIFO count unit is packet
|
||||
* - FIFO snapshot mode i.e drop the data when the FIFO overflows
|
||||
* - Timestamp is logged in FIFO
|
||||
* - Little Endian fifo_count and fifo_data
|
||||
* - generate FIFO threshold interrupt when packet count reaches FIFO watermark
|
||||
* - set FIFO watermark to 1 packet
|
||||
* - enable temperature and timestamp data to go to FIFO
|
||||
*
|
||||
*
|
||||
* @param[in] s driver structure. Note that first field of this structure MUST be a struct
|
||||
* inv_imu_serif.
|
||||
*
|
||||
* @param[in] serif pointer on serial interface structure to be used to access inv_device.
|
||||
*
|
||||
* @param[in] sensor_event_cb callback executed by inv_imu_get_data_from_fifo function
|
||||
* each time it extracts some valid data from fifo. Or inv_imu_get_data_from_registers read data
|
||||
* from register. Thus this parameter is optional as long
|
||||
* as inv_imu_get_data_from_fifo/inv_imu_get_data_from_registers function is not used.
|
||||
*
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_init(struct inv_imu_device *s,
|
||||
struct inv_imu_serif *serif,
|
||||
void (*sensor_event_cb)(inv_imu_sensor_event_t *event));
|
||||
|
||||
/** @brief Perform a soft reset of the device
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_device_reset(struct inv_imu_device *s);
|
||||
|
||||
/** @brief return WHOAMI value
|
||||
* @param[out] who_am_i WHOAMI for device
|
||||
* @return 0 on success, negative value on error
|
||||
*/
|
||||
int inv_imu_get_who_am_i(struct inv_imu_device *s, uint8_t *who_am_i);
|
||||
|
||||
/** @brief Enable/put accel in low power mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_power_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put accel in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables accel and gyro data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_accel_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of accel
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_accel(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable/put gyro in low noise mode
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* It enables gyro and accel data in the FIFO (so
|
||||
* the packet format is 16 bytes). If called first,
|
||||
* the configuration will be applied, otherwise it
|
||||
* will be ignored if the FIFO is not empty (but since
|
||||
* the new configuration is identical it is not a issue).
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_enable_gyro_low_noise_mode(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable all 3 axes of gyro
|
||||
* @return 0 on success, negative value on error.
|
||||
* @details
|
||||
* If both accel and gyro are turned off as a result of this
|
||||
* function, they will also be removed from the FIFO and a
|
||||
* FIFO reset will be performed (to guarantee no side effects
|
||||
* until the next enable sensor call)
|
||||
* @warning inv_device::register_cache::pwr_mgmt0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_disable_gyro(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - enables fsync
|
||||
* - enables timestamp to registers. Once fsync is enabled fsync counter is pushed to
|
||||
* fifo instead of timestamp. So timestamp is made available in registers. Note that
|
||||
* this increase power consumption.
|
||||
* - enables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_enable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable fsync tagging functionality.
|
||||
* In details it:
|
||||
* - disables fsync
|
||||
* - disables timestamp to registers. Once fsync is disabled timestamp is pushed to fifo
|
||||
* instead of fsync counter. So in order to decrease power consumption, timestamp is no
|
||||
* more available in registers.
|
||||
* - disables fsync related interrupt
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_fsync(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT1.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT1.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int1(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Configure which interrupt source can trigger INT2.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Retrieve interrupts configuration.
|
||||
* @param[in] interrupt_to_configure structure with the corresponding state to manage INT2.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_config_int2(struct inv_imu_device *s,
|
||||
inv_imu_interrupt_parameter_t *interrupt_to_configure);
|
||||
|
||||
/** @brief Read all registers containing data (temperature, accelerometer and gyroscope). Then it calls
|
||||
* sensor_event_cb function passed in parameter of inv_imu_init function for each packet
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_registers(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Read all available packets from the FIFO. For each packet function builds a
|
||||
* sensor event containing packet data and validity information. Then it calls
|
||||
* sensor_event_cb funtion passed in parameter of inv_imu_init function for each
|
||||
* packet.
|
||||
* @return number of valid packets read on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_data_from_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Converts ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enums to period expressed in us
|
||||
* @param[in] odr_bitfield An ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enum
|
||||
* @return The corresponding period expressed in us
|
||||
*/
|
||||
uint32_t inv_imu_convert_odr_bitfield_to_us(uint32_t odr_bitfield);
|
||||
|
||||
/** @brief Configure accel Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa ACCEL_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_frequency(struct inv_imu_device *s,
|
||||
const ACCEL_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Configure gyro Output Data Rate
|
||||
* @param[in] frequency The requested frequency.
|
||||
* @sa GYRO_CONFIG0_ODR_t
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_frequency(struct inv_imu_device *s,
|
||||
const GYRO_CONFIG0_ODR_t frequency);
|
||||
|
||||
/** @brief Set accel full scale range
|
||||
* @param[in] accel_fsr_g requested full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t accel_fsr_g);
|
||||
|
||||
/** @brief Access accel full scale range
|
||||
* @param[out] accel_fsr_g current full scale range.
|
||||
* @sa ACCEL_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::accel_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_accel_fsr(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG0_FS_SEL_t *accel_fsr_g);
|
||||
|
||||
/** @brief Set gyro full scale range
|
||||
* @param[in] gyro_fsr_dps requested full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is modified by this function
|
||||
*/
|
||||
int inv_imu_set_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t gyro_fsr_dps);
|
||||
|
||||
/** @brief Access gyro full scale range
|
||||
* @param[out] gyro_fsr_dps current full scale range.
|
||||
* @sa GYRO_CONFIG0_FS_SEL_t.
|
||||
* @return 0 on success, negative value on error.
|
||||
* @warning inv_device::register_cache::gyro_config0_reg is relied upon by this function
|
||||
*/
|
||||
int inv_imu_get_gyro_fsr(struct inv_imu_device *s,
|
||||
GYRO_CONFIG0_FS_SEL_t *gyro_fsr_dps);
|
||||
|
||||
/** @brief Set accel Low-Power averaging value
|
||||
* @param[in] acc_avg requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_AVG_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_lp_avg(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_AVG_t acc_avg);
|
||||
|
||||
/** @brief Set accel Low-Noise bandwidth value
|
||||
* @param[in] acc_bw requested averaging value
|
||||
* @sa ACCEL_CONFIG1_ACCEL_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_accel_ln_bw(struct inv_imu_device *s,
|
||||
ACCEL_CONFIG1_ACCEL_FILT_BW_t acc_bw);
|
||||
|
||||
/** @brief Set gyro Low-Noise bandwidth value
|
||||
* @param[in] gyr_bw requested averaging value
|
||||
* @sa GYRO_CONFIG1_GYRO_FILT_BW_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_gyro_ln_bw(struct inv_imu_device *s,
|
||||
GYRO_CONFIG1_GYRO_FILT_BW_t gyr_bw);
|
||||
|
||||
/** @brief Set timestamp resolution
|
||||
* @param[in] timestamp_resol requested timestamp resolution
|
||||
* @sa TMST_CONFIG1_RESOL_t
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_timestamp_resolution(struct inv_imu_device *s,
|
||||
const TMST_CONFIG1_RESOL_t timestamp_resol);
|
||||
|
||||
/** @brief reset IMU fifo
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_enable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable 20 bits raw acc and raw gyr data in fifo.
|
||||
* @return 0 on success, negative return code otherwise
|
||||
*/
|
||||
int inv_imu_disable_high_resolution_fifo(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo
|
||||
* @param[in] fifo_config Fifo configuration method :
|
||||
* if FIFO is enabled, data are pushed to FIFO and FIFO THS interrupt is set
|
||||
* if FIFO is disabled, data are not pused to FIFO and DRDY interrupt is set
|
||||
* @sa INV_IMU_FIFO_CONFIG_t
|
||||
*/
|
||||
int inv_imu_configure_fifo(struct inv_imu_device *s,
|
||||
INV_IMU_FIFO_CONFIG_t fifo_config);
|
||||
|
||||
/** @brief Get FIFO timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
int32_t inv_imu_get_fifo_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Get register timestamp resolution
|
||||
* @return the timestamp resolution in us as a q24 or 0 in case of error
|
||||
*/
|
||||
uint32_t inv_imu_get_reg_timestamp_resolution_us_q24(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* @param[in] wom_x_th threshold value for the Wake on Motion Interrupt for X-axis accelerometer.
|
||||
* @param[in] wom_y_th threshold value for the Wake on Motion Interrupt for Y-axis accelerometer.
|
||||
* @param[in] wom_z_th threshold value for the Wake on Motion Interrupt for Z-axis accelerometer.
|
||||
* @param[in] wom_int select which mode between AND/OR is used to generate interrupt.
|
||||
* @param[in] wom_dur select the number of overthreshold event to wait before generating interrupt.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_wom(struct inv_imu_device *s,
|
||||
const uint8_t wom_x_th,
|
||||
const uint8_t wom_y_th,
|
||||
const uint8_t wom_z_th,
|
||||
WOM_CONFIG_WOM_INT_MODE_t wom_int,
|
||||
WOM_CONFIG_WOM_INT_DUR_t wom_dur);
|
||||
|
||||
/** @brief Enable Wake On Motion.
|
||||
* note : WoM requests to have the accelerometer enabled to work.
|
||||
* As a consequence Fifo water-mark interrupt is disabled to only trigger WoM interrupts.
|
||||
* 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_enable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Disable Wake On Motion.
|
||||
* note : Fifo water-mark interrupt is re-enabled when WoM is disabled.
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_disable_wom(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Start DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_start_dmp(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Reset DMP for APEX algorithms and selftest
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_reset_dmp(struct inv_imu_device *s,
|
||||
const APEX_CONFIG0_DMP_MEM_RESET_t sram_reset);
|
||||
|
||||
/** @breif Set the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_set_endianness(struct inv_imu_device *s,
|
||||
INTF_CONFIG0_DATA_ENDIAN_t endianness);
|
||||
|
||||
/** @breif Read the UI endianness and set the inv_device endianness field
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_get_endianness(struct inv_imu_device *s);
|
||||
|
||||
/** @brief Configure Fifo decimation
|
||||
* @param[in] requested decimation factor value from 2 to 256
|
||||
* @return 0 on success, negative value on error.
|
||||
*/
|
||||
int inv_imu_configure_fifo_data_rate(struct inv_imu_device *s,
|
||||
FDR_CONFIG_FDR_SEL_t dec_factor);
|
||||
|
||||
/** @brief Return driver version x.y.z-suffix as a char array
|
||||
* @retval driver version a char array "x.y.z-suffix"
|
||||
*/
|
||||
const char * inv_imu_get_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _INV_IMU_DRIVER_H_ */
|
||||
|
||||
/** @} */
|
||||
+64
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+3391
File diff suppressed because it is too large
Load Diff
+179
@@ -0,0 +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;
|
||||
}
|
||||
+101
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+257
@@ -0,0 +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;
|
||||
}
|
||||
+122
@@ -0,0 +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_ */
|
||||
|
||||
/** @} */
|
||||
+37
@@ -0,0 +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_ */
|
||||
+153
@@ -0,0 +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_
|
||||
+156
@@ -0,0 +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
|
||||
BIN
Binary file not shown.
+3012
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,582 @@
|
||||
/*******************************************************************************
|
||||
* @file app_raw.c
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Module overview] ICM42670P IMU driver application layer
|
||||
*
|
||||
* Application layer module responsible for initialization, configuration,
|
||||
* and data reading of the ICM42670P IMU sensor. Wraps InvenSense driver API.
|
||||
*
|
||||
* Key functions:
|
||||
* 1) setup_imu_device() - IMU init and WHOAMI verification (0x67 = ICM42670P)
|
||||
* 2) configure_imu_device() - Sensor parameter configuration
|
||||
* - Accelerometer: +/-4g FSR, 100Hz (low-power) or 800Hz (low-noise)
|
||||
* - Gyroscope: +/-2000dps FSR, 100Hz or 800Hz
|
||||
* - FIFO disabled (direct register read mode)
|
||||
* 3) get_imu_data() - Read sensor data from FIFO or registers
|
||||
* 4) imu_callback() - Sensor data receive callback
|
||||
* - Applies mounting matrix (board orientation correction)
|
||||
* - info4 mode: stores data in info_imu[6]
|
||||
* - BLE mode: sends 6-axis data via BLE with "rsp:" tag
|
||||
* - UART mode: outputs text format to serial
|
||||
* 5) imu_read_direct() - Direct I2C register read bypassing driver API
|
||||
* - Configure sensor -> power ON -> wait 80ms -> read 12 bytes -> sleep
|
||||
*
|
||||
* Mounting matrix:
|
||||
* 3x3 rotation matrix in Q30 fixed-point format, correcting the sensor's
|
||||
* physical mounting orientation to match the software coordinate system.
|
||||
******************************************************************************/
|
||||
|
||||
#include "sdk_config.h"
|
||||
#include "app_raw.h"
|
||||
#include "inv_imu_extfunc.h"
|
||||
#include "inv_imu_driver.h"
|
||||
#include "ble_nus.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
|
||||
#include "app_util_platform.h"
|
||||
#include "main.h"
|
||||
#include "debug_print.h"
|
||||
#include "nrf_delay.h"
|
||||
|
||||
|
||||
/*
|
||||
* Data output format selection
|
||||
* 0 : Raw data output (raw accel, gyro, temp)
|
||||
* 1 : Scaled data output (g, dps, Celsius)
|
||||
*/
|
||||
#define SCALED_DATA_G_DPS 0
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Static and extern variables
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/* IMU driver object — always passed to driver API calls */
|
||||
static struct inv_imu_device icm_driver;
|
||||
|
||||
/* Binary buffer for BLE transmission */
|
||||
uint8_t imu_bin_buffer[BLE_NUS_MAX_DATA_LEN] = {0};
|
||||
|
||||
/*
|
||||
* ICM42670P mounting matrix (Q30 fixed-point)
|
||||
*
|
||||
* Coordinate transform based on the sensor's physical mounting orientation.
|
||||
* Q30 format: 1.0 = (1 << 30) = 0x40000000
|
||||
*
|
||||
* SM_REVB_DB (dev board): X->-Y, Y->X transform (90-degree rotation)
|
||||
* Default (SmartMotion): identity matrix (no transform)
|
||||
*/
|
||||
#if (SM_BOARD_REV == SM_REVB_DB) /* when DB or EVB are used */
|
||||
static int32_t icm_mounting_matrix[9] = { 0, -(1<<30), 0,
|
||||
(1<<30), 0, 0,
|
||||
0, 0, (1<<30) };
|
||||
#else /* For SmartMotion */
|
||||
static int32_t icm_mounting_matrix[9] = {(1<<30), 0, 0,
|
||||
0, (1<<30), 0,
|
||||
0, 0, (1<<30)};
|
||||
#endif
|
||||
|
||||
bool custom_add_data; /* Custom data append flag (BLE transmission control) */
|
||||
extern bool motion_raw_data_enabled; /* Flag requesting raw data read from external module */
|
||||
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; /* BLE text transmit buffer */
|
||||
extern which_cmd_t cmd_type_t; /* Current command source (BLE or UART) */
|
||||
uint16_t ssp_data[6]={0,}; /* 6-axis data array for BLE (accel XYZ + gyro XYZ) */
|
||||
extern bool info4; /* info4 mode flag (set by cmd_parse) */
|
||||
volatile uint16_t info_imu[6]; /* Global array storing IMU data in info4 mode */
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* static function declaration
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
static void apply_mounting_matrix(const int32_t matrix[9], int32_t raw[3]);
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Functions definition
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* setup_imu_device()
|
||||
* IMU device initialization and identification verification.
|
||||
*
|
||||
* Flow:
|
||||
* 1) Initialize driver via inv_imu_init() (serial interface + callback registration)
|
||||
* 2) Read WHOAMI register for device identification
|
||||
* 3) Verify WHOAMI value matches ICM_WHOAMI (0x67)
|
||||
*
|
||||
* Returns: 0=success, negative=error
|
||||
*/
|
||||
int setup_imu_device(struct inv_imu_serif *icm_serif)
|
||||
{
|
||||
int rc = 0;
|
||||
uint8_t who_am_i;
|
||||
|
||||
/* Initialize IMU driver — connect serial interface and register callback */
|
||||
rc = inv_imu_init(&icm_driver, icm_serif, imu_callback);
|
||||
if (rc != INV_ERROR_SUCCESS) {
|
||||
DBG_PRINTF("!!! ERROR : Failed to initialize IMU!\r\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Read WHOAMI register — verify device presence and communication */
|
||||
rc = inv_imu_get_who_am_i(&icm_driver, &who_am_i);
|
||||
if (rc != INV_ERROR_SUCCESS) {
|
||||
DBG_PRINTF("!!! ERROR : Failed to read whoami!\r\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Verify WHOAMI value — must be 0x67 for ICM42670P */
|
||||
if (who_am_i != ICM_WHOAMI) {
|
||||
DBG_PRINTF("!!! ERROR : Bad WHOAMI value! Read 0x%02x, expected 0x%02x\r\n", who_am_i, ICM_WHOAMI);
|
||||
return INV_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* configure_imu_device()
|
||||
* Configures IMU sensor operating parameters.
|
||||
*
|
||||
* Settings:
|
||||
* - FIFO: disabled (when USE_FIFO=0, direct register read mode)
|
||||
* - Accel FSR: +/-4g (when USE_HIGH_RES_MODE=0)
|
||||
* - Gyro FSR: +/-2000dps
|
||||
* - ODR (output data rate):
|
||||
* - Low-noise mode (USE_LOW_NOISE_MODE=1): 800Hz
|
||||
* - Low-power mode (USE_LOW_NOISE_MODE=0): 100Hz
|
||||
* - Gyro always operates in low-noise mode
|
||||
* - Waits for gyro startup time when FIFO is not used
|
||||
*
|
||||
* Returns: 0=success, negative=error
|
||||
*/
|
||||
int configure_imu_device(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Disable FIFO — read data directly from registers */
|
||||
if (!USE_FIFO)
|
||||
rc |= inv_imu_configure_fifo(&icm_driver, INV_IMU_FIFO_DISABLED);
|
||||
|
||||
if (USE_HIGH_RES_MODE) {
|
||||
/* High-resolution FIFO mode: 20-bit data, FSR locked to 16g/2000dps */
|
||||
rc |= inv_imu_enable_high_resolution_fifo(&icm_driver);
|
||||
} else {
|
||||
/* Standard mode: accel +/-4g, gyro +/-2000dps FSR */
|
||||
rc |= inv_imu_set_accel_fsr(&icm_driver, ACCEL_CONFIG0_FS_SEL_4g);
|
||||
rc |= inv_imu_set_gyro_fsr(&icm_driver, GYRO_CONFIG0_FS_SEL_2000dps);
|
||||
}
|
||||
|
||||
if (USE_LOW_NOISE_MODE) {
|
||||
/* Low-noise mode: 800Hz ODR, enable accel low-noise mode */
|
||||
rc |= inv_imu_set_accel_frequency(&icm_driver, ACCEL_CONFIG0_ODR_800_HZ);
|
||||
rc |= inv_imu_set_gyro_frequency(&icm_driver, GYRO_CONFIG0_ODR_800_HZ);
|
||||
rc |= inv_imu_enable_accel_low_noise_mode(&icm_driver);
|
||||
} else {
|
||||
/* Low-power mode: 100Hz ODR, enable accel low-power mode */
|
||||
rc |= inv_imu_set_accel_frequency(&icm_driver, ACCEL_CONFIG0_ODR_100_HZ);
|
||||
rc |= inv_imu_set_gyro_frequency(&icm_driver, GYRO_CONFIG0_ODR_100_HZ);
|
||||
rc |= inv_imu_enable_accel_low_power_mode(&icm_driver);
|
||||
}
|
||||
|
||||
/* Gyro always operates in low-noise mode regardless of setting */
|
||||
rc |= inv_imu_enable_gyro_low_noise_mode(&icm_driver);
|
||||
|
||||
/* When FIFO is not used, wait for gyro startup time (delay until first valid data) */
|
||||
if (!USE_FIFO)
|
||||
inv_imu_sleep_us(GYR_STARTUP_TIME_US);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_imu_data()
|
||||
* Reads sensor data from the IMU.
|
||||
* Fetches data from FIFO or registers depending on USE_FIFO setting.
|
||||
* Read data is processed via imu_callback().
|
||||
*/
|
||||
int get_imu_data(void)
|
||||
{
|
||||
#if USE_FIFO
|
||||
return inv_imu_get_data_from_fifo(&icm_driver);
|
||||
#else
|
||||
|
||||
return inv_imu_get_data_from_registers(&icm_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SCALED_DATA_G_DPS
|
||||
/*
|
||||
* get_accel_and_gyr_fsr()
|
||||
* Retrieves the currently configured FSR (Full Scale Range) for accel and gyro.
|
||||
* Used for converting to scaled data (g, dps).
|
||||
*/
|
||||
static void get_accel_and_gyr_fsr(int16_t * accel_fsr_g, int16_t * gyro_fsr_dps)
|
||||
{
|
||||
ACCEL_CONFIG0_FS_SEL_t accel_fsr_bitfield;
|
||||
GYRO_CONFIG0_FS_SEL_t gyro_fsr_bitfield;
|
||||
|
||||
inv_imu_get_accel_fsr(&icm_driver, &accel_fsr_bitfield);
|
||||
switch(accel_fsr_bitfield) {
|
||||
case ACCEL_CONFIG0_FS_SEL_2g: *accel_fsr_g = 2;
|
||||
break;
|
||||
case ACCEL_CONFIG0_FS_SEL_4g: *accel_fsr_g = 4;
|
||||
break;
|
||||
case ACCEL_CONFIG0_FS_SEL_8g: *accel_fsr_g = 8;
|
||||
break;
|
||||
case ACCEL_CONFIG0_FS_SEL_16g: *accel_fsr_g = 16;
|
||||
break;
|
||||
default: *accel_fsr_g = -1;
|
||||
}
|
||||
|
||||
inv_imu_get_gyro_fsr(&icm_driver, &gyro_fsr_bitfield);
|
||||
switch(gyro_fsr_bitfield) {
|
||||
case GYRO_CONFIG0_FS_SEL_250dps: *gyro_fsr_dps = 250;
|
||||
break;
|
||||
case GYRO_CONFIG0_FS_SEL_500dps: *gyro_fsr_dps = 500;
|
||||
break;
|
||||
case GYRO_CONFIG0_FS_SEL_1000dps: *gyro_fsr_dps = 1000;
|
||||
break;
|
||||
case GYRO_CONFIG0_FS_SEL_2000dps: *gyro_fsr_dps = 2000;
|
||||
break;
|
||||
default: *gyro_fsr_dps = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* imu_callback()
|
||||
* Callback invoked each time the IMU driver reads new sensor data.
|
||||
*
|
||||
* Flow:
|
||||
* 1) Extract raw accel/gyro data from event
|
||||
* - FIFO mode: handles timestamp rollover, supports high-res (20-bit)
|
||||
* - Register mode: uses 16-bit data directly
|
||||
* 2) Apply mounting matrix (board orientation correction)
|
||||
* 3) Output data (branches by mode):
|
||||
* - info4 mode: stores in info_imu[6] global array (polled externally)
|
||||
* - UART mode: text output with "Tp" prefix for 6-axis data
|
||||
* - BLE mode: binary packet with "rsp:" tag + simultaneous UART output
|
||||
*/
|
||||
void imu_callback(inv_imu_sensor_event_t *event)
|
||||
{
|
||||
int32_t accel[3], gyro[3];
|
||||
|
||||
#if SCALED_DATA_G_DPS
|
||||
float accel_g[3];
|
||||
float gyro_dps[3];
|
||||
float temp_degc;
|
||||
int16_t accel_fsr_g, gyro_fsr_dps;
|
||||
#endif
|
||||
|
||||
#if USE_FIFO
|
||||
static uint64_t last_fifo_timestamp = 0;
|
||||
static uint32_t rollover_num = 0;
|
||||
|
||||
/* FIFO timestamp rollover handling (16-bit -> 64-bit extension) */
|
||||
if (last_fifo_timestamp > event->timestamp_fsync)
|
||||
rollover_num++;
|
||||
last_fifo_timestamp = event->timestamp_fsync;
|
||||
|
||||
/* Convert timestamp to microseconds (apply Q24 resolution) */
|
||||
timestamp = event->timestamp_fsync + rollover_num * UINT16_MAX;
|
||||
timestamp *= inv_imu_get_fifo_timestamp_resolution_us_q24(&icm_driver);
|
||||
timestamp /= (1UL << 24);
|
||||
|
||||
if (icm_driver.fifo_highres_enabled) {
|
||||
/* High-res mode: left-shift 16-bit data by 4 + add lower 4 bits -> 20-bit */
|
||||
accel[0] = (((int32_t)event->accel[0] << 4)) | event->accel_high_res[0];
|
||||
accel[1] = (((int32_t)event->accel[1] << 4)) | event->accel_high_res[1];
|
||||
accel[2] = (((int32_t)event->accel[2] << 4)) | event->accel_high_res[2];
|
||||
|
||||
gyro[0] = (((int32_t)event->gyro[0] << 4)) | event->gyro_high_res[0];
|
||||
gyro[1] = (((int32_t)event->gyro[1] << 4)) | event->gyro_high_res[1];
|
||||
gyro[2] = (((int32_t)event->gyro[2] << 4)) | event->gyro_high_res[2];
|
||||
|
||||
} else {
|
||||
/* Standard resolution: use 16-bit data as-is */
|
||||
accel[0] = event->accel[0];
|
||||
accel[1] = event->accel[1];
|
||||
accel[2] = event->accel[2];
|
||||
|
||||
gyro[0] = event->gyro[0];
|
||||
gyro[1] = event->gyro[1];
|
||||
gyro[2] = event->gyro[2];
|
||||
}
|
||||
#else
|
||||
|
||||
/* Direct register read mode: extract 16-bit raw data */
|
||||
accel[0] = event->accel[0];
|
||||
accel[1] = event->accel[1];
|
||||
accel[2] = event->accel[2];
|
||||
|
||||
gyro[0] = event->gyro[0];
|
||||
gyro[1] = event->gyro[1];
|
||||
gyro[2] = event->gyro[2];
|
||||
|
||||
/* In register mode, force sensor mask so the output logic below works */
|
||||
event->sensor_mask |= (1 << INV_SENSOR_TEMPERATURE);
|
||||
event->sensor_mask |= (1 << INV_SENSOR_ACCEL);
|
||||
event->sensor_mask |= (1 << INV_SENSOR_GYRO);
|
||||
#endif
|
||||
|
||||
/* Apply mounting matrix — correct sensor physical orientation to software coordinates */
|
||||
apply_mounting_matrix(icm_mounting_matrix, accel);
|
||||
apply_mounting_matrix(icm_mounting_matrix, gyro);
|
||||
|
||||
#if SCALED_DATA_G_DPS
|
||||
/*
|
||||
* Convert raw data to physical units (g, dps)
|
||||
* Formula: physical_value = raw_value * FSR / INT16_MAX
|
||||
*/
|
||||
get_accel_and_gyr_fsr(&accel_fsr_g, &gyro_fsr_dps);
|
||||
accel_g[0] = (float)(accel[0] * accel_fsr_g) / INT16_MAX;
|
||||
accel_g[1] = (float)(accel[1] * accel_fsr_g) / INT16_MAX;
|
||||
accel_g[2] = (float)(accel[2] * accel_fsr_g) / INT16_MAX;
|
||||
gyro_dps[0] = (float)(gyro[0] * gyro_fsr_dps) / INT16_MAX;
|
||||
gyro_dps[1] = (float)(gyro[1] * gyro_fsr_dps) / INT16_MAX;
|
||||
gyro_dps[2] = (float)(gyro[2] * gyro_fsr_dps) / INT16_MAX;
|
||||
|
||||
/* Temperature conversion: high-res/register mode uses /128, FIFO standard mode uses /2 */
|
||||
if (USE_HIGH_RES_MODE || !USE_FIFO)
|
||||
temp_degc = 25 + ((float)event->temperature / 128);
|
||||
else
|
||||
temp_degc = 25 + ((float)event->temperature / 2);
|
||||
|
||||
/*
|
||||
* Output scaled data via UART
|
||||
*/
|
||||
if (event->sensor_mask & (1 << INV_SENSOR_ACCEL) && event->sensor_mask & (1 << INV_SENSOR_GYRO))
|
||||
DBG_PRINTF("%u: %.3f, \t%.3f, \t%.3f, \t%.3f, \t%.3f, \t%.3f, \t%.3f\r\n",
|
||||
(uint32_t)timestamp,
|
||||
accel_g[0], accel_g[1], accel_g[2],
|
||||
temp_degc,
|
||||
gyro_dps[0], gyro_dps[1], gyro_dps[2]);
|
||||
#else
|
||||
|
||||
/*
|
||||
* Raw data output — branches by command source (info4/UART/BLE)
|
||||
*/
|
||||
if (event->sensor_mask & (1 << INV_SENSOR_ACCEL) && event->sensor_mask & (1 << INV_SENSOR_GYRO) || motion_raw_data_enabled)
|
||||
{
|
||||
motion_raw_data_enabled = false;
|
||||
|
||||
/* info4 mode: store data in global array info_imu[6], polled by external modules */
|
||||
if (info4 == true)
|
||||
{
|
||||
info_imu[0] = (uint16_t)accel[0];
|
||||
info_imu[1] = (uint16_t)accel[1];
|
||||
info_imu[2] = (uint16_t)accel[2];
|
||||
info_imu[3] = (uint16_t)gyro[0];
|
||||
info_imu[4] = (uint16_t)gyro[1];
|
||||
info_imu[5] = (uint16_t)gyro[2];
|
||||
}
|
||||
|
||||
/* UART mode: output 6-axis data in text format with "Tp" prefix */
|
||||
else if(cmd_type_t == CMD_UART) {
|
||||
//DBG_PRINTF("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* BLE mode: send 6-axis data as binary packet via BLE
|
||||
* ssp_data[0..2] = accel XYZ, ssp_data[3..5] = gyro XYZ
|
||||
* format_data() packs "rsp:" tag + 12-byte data
|
||||
* dr_binary_tx_safe() sends 8 bytes via BLE
|
||||
*/
|
||||
else if(cmd_type_t == CMD_BLE) {
|
||||
ssp_data[0] = (uint16_t)accel[0];
|
||||
ssp_data[1] = (uint16_t)accel[1];
|
||||
ssp_data[2] = (uint16_t)accel[2];
|
||||
ssp_data[3] = (uint16_t)gyro[0];
|
||||
ssp_data[4] = (uint16_t)gyro[1];
|
||||
ssp_data[5] = (uint16_t)gyro[2];
|
||||
|
||||
format_data(imu_bin_buffer, "rsp:", ssp_data,12);
|
||||
//DBG_PRINTF("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
|
||||
dr_binary_tx_safe(imu_bin_buffer,8);
|
||||
|
||||
if(custom_add_data==true) {
|
||||
custom_add_data = false;
|
||||
}
|
||||
else {
|
||||
//data_tx_handler(ble_tx_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Static functions definition
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* apply_mounting_matrix()
|
||||
* Applies a Q30 fixed-point rotation matrix to a 3-axis vector.
|
||||
*
|
||||
* Calculation:
|
||||
* result[i] = matrix[i*3+0]*raw[0] + matrix[i*3+1]*raw[1] + matrix[i*3+2]*raw[2]
|
||||
* Right-shift result by 30 bits for Q30 -> integer conversion.
|
||||
*
|
||||
* Ensures a consistent coordinate system regardless of physical sensor orientation.
|
||||
*/
|
||||
static void apply_mounting_matrix(const int32_t matrix[9], int32_t raw[3])
|
||||
{
|
||||
unsigned i;
|
||||
int64_t data_q30[3];
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
data_q30[i] = ((int64_t)matrix[3*i+0] * raw[0]);
|
||||
data_q30[i] += ((int64_t)matrix[3*i+1] * raw[1]);
|
||||
data_q30[i] += ((int64_t)matrix[3*i+2] * raw[2]);
|
||||
}
|
||||
/* Q30 -> integer conversion: right-shift by 30 bits */
|
||||
raw[0] = (int32_t)(data_q30[0]>>30);
|
||||
raw[1] = (int32_t)(data_q30[1]>>30);
|
||||
raw[2] = (int32_t)(data_q30[2]>>30);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* imu_read_direct()
|
||||
* Reads IMU registers directly via I2C, bypassing the driver API.
|
||||
* Reads data immediately without waiting for DRDY interrupt.
|
||||
*
|
||||
* Flow:
|
||||
* 1) Check TWI initialization (first call only)
|
||||
* 2) Gyro config: +/-2000dps, 100Hz ODR (GYRO_CONFIG0 = 0x09)
|
||||
* 3) Accel config: +/-4g, 100Hz ODR (ACCEL_CONFIG0 = 0x29)
|
||||
* 4) Power ON: accel+gyro low-noise mode (PWR_MGMT0 = 0x0F)
|
||||
* 5) Wait 80ms (gyro startup: min 45ms + margin)
|
||||
* 6) Read 12 consecutive bytes from ACCEL_DATA_X1 (0x0B) (accel 6 + gyro 6)
|
||||
* 7) Big-endian -> int16_t conversion
|
||||
* 8) Apply mounting matrix
|
||||
* 9) Send via BLE with "rsp:" tag
|
||||
* 10) Switch IMU to sleep mode (power saving)
|
||||
*
|
||||
* Returns: 0=success, -1=TX failure, -2=RX failure
|
||||
*/
|
||||
/* Raw I2C read from ICM42670P — bypasses driver API entirely */
|
||||
#include "system_interface.h"
|
||||
#include "nrfx_twi.h"
|
||||
|
||||
extern const nrfx_twi_t m_twi_icm42670;
|
||||
|
||||
#define IMU_I2C_ADDR 0x68
|
||||
#define REG_ACCEL_X1 0x0B /* ACCEL_DATA_X1 — accel X-axis upper byte register */
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Direct IMU register read — raw I2C, no DRDY, sends rsp: via BLE
|
||||
* Direct I2C register read (no interrupt, no IMU driver API)
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
int imu_read_direct(void)
|
||||
{
|
||||
uint8_t raw[12]; /* accel 6 bytes + gyro 6 bytes */
|
||||
int32_t accel[3], gyro[3];
|
||||
uint8_t reg;
|
||||
uint32_t ret;
|
||||
|
||||
static bool twi_ready = false;
|
||||
|
||||
/* TWI (I2C) init — performed only once (re-init ensures clean state) */
|
||||
if (!twi_ready) {
|
||||
inv_i2c_master_uninitialize();
|
||||
inv_i2c_master_initialize();
|
||||
twi_ready = true;
|
||||
}
|
||||
|
||||
/* Gyro config: GYRO_CONFIG0(0x20) = 0x09 -> +/-2000dps FSR, 100Hz ODR */
|
||||
{
|
||||
uint8_t gyro_cfg[2] = { 0x20, 0x09 };
|
||||
icm42670_twi_tx(IMU_I2C_ADDR, gyro_cfg, 2, false);
|
||||
}
|
||||
|
||||
/* Accel config: ACCEL_CONFIG0(0x21) = 0x29 -> +/-4g FSR, 100Hz ODR */
|
||||
{
|
||||
uint8_t accel_cfg[2] = { 0x21, 0x29 };
|
||||
icm42670_twi_tx(IMU_I2C_ADDR, accel_cfg, 2, false);
|
||||
}
|
||||
|
||||
/* Power ON: PWR_MGMT0(0x1F) = 0x0F -> accel (low-noise) + gyro (low-noise) enabled */
|
||||
{
|
||||
uint8_t pwr_cmd[2] = { 0x1F, 0x0F }; /* reg=0x1F, val=0x0F */
|
||||
icm42670_twi_tx(IMU_I2C_ADDR, pwr_cmd, 2, false);
|
||||
//nrf_delay_ms(80); /* Gyro startup: min 45ms + safety margin */
|
||||
dr_sd_delay_ms(80);
|
||||
}
|
||||
|
||||
/* Read 12 consecutive bytes from ACCEL_DATA_X1 (0x0B~0x16) */
|
||||
reg = REG_ACCEL_X1;
|
||||
ret = icm42670_twi_tx(IMU_I2C_ADDR, ®, 1, true); /* Send register address (no STOP) */
|
||||
|
||||
if (ret)
|
||||
{
|
||||
DBG_PRINTF("[IMU] tx FAIL %u\r\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = icm42670_twi_rx(IMU_I2C_ADDR, raw, 12); /* Receive 12 bytes of data */
|
||||
|
||||
if (ret)
|
||||
{
|
||||
DBG_PRINTF("[IMU] rx FAIL %u\r\n", ret);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert big-endian register layout to int16_t
|
||||
* raw[0..5] = accel X,Y,Z (2 bytes each, MSB first)
|
||||
* raw[6..11] = gyro X,Y,Z (2 bytes each, MSB first)
|
||||
*/
|
||||
accel[0] = (int16_t)((raw[0] << 8) | raw[1]);
|
||||
accel[1] = (int16_t)((raw[2] << 8) | raw[3]);
|
||||
accel[2] = (int16_t)((raw[4] << 8) | raw[5]);
|
||||
gyro[0] = (int16_t)((raw[6] << 8) | raw[7]);
|
||||
gyro[1] = (int16_t)((raw[8] << 8) | raw[9]);
|
||||
gyro[2] = (int16_t)((raw[10] << 8) | raw[11]);
|
||||
|
||||
/* Apply mounting matrix — board orientation correction */
|
||||
apply_mounting_matrix(icm_mounting_matrix, accel);
|
||||
apply_mounting_matrix(icm_mounting_matrix, gyro);
|
||||
|
||||
/* Pack data */
|
||||
ssp_data[0] = (uint16_t)accel[0];
|
||||
ssp_data[1] = (uint16_t)accel[1];
|
||||
ssp_data[2] = (uint16_t)accel[2];
|
||||
ssp_data[3] = (uint16_t)gyro[0];
|
||||
ssp_data[4] = (uint16_t)gyro[1];
|
||||
ssp_data[5] = (uint16_t)gyro[2];
|
||||
|
||||
if (info4 == true)
|
||||
{
|
||||
/* info4 mode: store in global array (sent as rbb: packet by mbb?) */
|
||||
info_imu[0] = ssp_data[0];
|
||||
info_imu[1] = ssp_data[1];
|
||||
info_imu[2] = ssp_data[2];
|
||||
info_imu[3] = ssp_data[3];
|
||||
info_imu[4] = ssp_data[4];
|
||||
info_imu[5] = ssp_data[5];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal mode: send immediately via BLE with "rsp:" tag */
|
||||
format_data(imu_bin_buffer, "rsp:", ssp_data, 12);
|
||||
dr_binary_tx_safe(imu_bin_buffer, 8);
|
||||
}
|
||||
|
||||
/* IMU sleep mode: PWR_MGMT0 = 0x00 -> accel/gyro both OFF (power saving) */
|
||||
{
|
||||
uint8_t pwr_off[2] = { 0x1F, 0x00 }; /* reg=PWR_MGMT0, val=0x00 */
|
||||
icm42670_twi_tx(IMU_I2C_ADDR, pwr_off, 2, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*******************************************************************************
|
||||
* @file app_raw.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Header overview] ICM42670P IMU driver application layer declarations
|
||||
*
|
||||
* Function prototypes and operating mode configuration macros for
|
||||
* IMU sensor initialization, configuration, and data reading.
|
||||
*
|
||||
* Key configuration macros:
|
||||
* SERIF_TYPE - Communication interface (UI_I2C)
|
||||
* USE_LOW_NOISE_MODE - 1: low-noise (800Hz), 0: low-power (100Hz)
|
||||
* USE_HIGH_RES_MODE - 1: 20-bit high-res, 0: 16-bit standard
|
||||
* USE_FIFO - 1: use FIFO, 0: direct register read
|
||||
******************************************************************************/
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
/*** Configuration macros ***/
|
||||
|
||||
/*
|
||||
* MCU-IMU communication interface selection
|
||||
* UI_I2C: use I2C communication (default)
|
||||
*/
|
||||
#define SERIF_TYPE UI_I2C
|
||||
|
||||
/*
|
||||
* Power mode selection
|
||||
* 1: Low-noise mode — 800Hz ODR, high precision, higher power consumption
|
||||
* 0: Low-power mode — 100Hz ODR, lower power consumption
|
||||
* Note: Low-noise mode cannot be used with ODR below 12.5Hz
|
||||
*/
|
||||
#define USE_LOW_NOISE_MODE 1
|
||||
|
||||
/*
|
||||
* FIFO resolution mode selection
|
||||
* 0: Low resolution — 16-bit data (default)
|
||||
* 1: High resolution — 20-bit data (FSR locked to 16g/2000dps)
|
||||
*/
|
||||
#define USE_HIGH_RES_MODE 0
|
||||
|
||||
/*
|
||||
* Data read method selection
|
||||
* 0: Direct register read (currently in use)
|
||||
* 1: Read from FIFO
|
||||
*/
|
||||
#define USE_FIFO 0
|
||||
|
||||
|
||||
/**
|
||||
* \brief Resets and initializes the IMU device. Includes WHOAMI verification.
|
||||
* Must complete successfully before calling any other IMU access functions.
|
||||
*
|
||||
* \return 0=success, negative=error
|
||||
*/
|
||||
int setup_imu_device(struct inv_imu_serif *icm_serif);
|
||||
|
||||
/**
|
||||
* \brief Configures the device for gyro and accel output.
|
||||
* Applies FSR, ODR, power mode, and FIFO settings.
|
||||
* \return 0=success, negative=error
|
||||
*/
|
||||
int configure_imu_device(void);
|
||||
|
||||
/**
|
||||
* \brief Retrieves IMU data from FIFO or registers.
|
||||
* Internally triggers imu_callback() for data processing.
|
||||
* \return 0=success, negative=error
|
||||
*/
|
||||
int get_imu_data(void);
|
||||
|
||||
/**
|
||||
* \brief Sensor data receive callback. Applies mounting matrix then
|
||||
* outputs data according to info4/BLE/UART mode.
|
||||
* \param[in] event Structure containing one sensor data packet
|
||||
*/
|
||||
void imu_callback(inv_imu_sensor_event_t *event);
|
||||
|
||||
/**
|
||||
* \brief Direct I2C register read bypassing the driver API.
|
||||
* Reads sensor data immediately without DRDY interrupt and sends via BLE.
|
||||
* Switches IMU to sleep mode after reading to save power.
|
||||
* \return 0=success, negative=error
|
||||
*/
|
||||
int imu_read_direct(void);
|
||||
|
||||
|
||||
#endif /* !_APP_RAW_H_ */
|
||||
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* @file app_raw_main.c
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* 2026.03.26 jhChun
|
||||
* This file is currently not executed at runtime.
|
||||
* Instead of interrupt-driven reads, imu_read_direct() in app_raw.c
|
||||
* reads registers directly. May be cleaned up later as needed.
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Module overview] ICM42670P main initialization and polling loop
|
||||
*
|
||||
* Handles the full initialization sequence and main loop for the ICM42670P
|
||||
* IMU sensor.
|
||||
*
|
||||
* Init flow (icm42670_init):
|
||||
* 1) setup_mcu() - Configure I2C serial interface struct and TWI init
|
||||
* 2) setup_imu_device() - IMU driver init + WHOAMI verification
|
||||
* 3) configure_imu_device() - Sensor parameter config (FSR, ODR, power mode)
|
||||
* 4) inv_gpio_sensor_irq_init() - INT1 (P1.13) GPIO interrupt setup
|
||||
*
|
||||
* Main loop (icm42670_main):
|
||||
* - irq_from_device flag is set when INT1 interrupt fires
|
||||
* - Main loop checks the flag and reads sensor data when set
|
||||
* - Interrupt triggers on falling edge (HITOLO) with INT1 pin pulled up
|
||||
*
|
||||
* Helper functions:
|
||||
* - inv_imu_sleep_us() - nrf_delay_us wrapper (used by IMU driver)
|
||||
* - inv_imu_get_time_us() - Provides timestamp via RTC1 counter
|
||||
******************************************************************************/
|
||||
#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: removed cmd_parse.h, using main.h */
|
||||
#include "i2c_manager.h"
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Global variables
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Static variables
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* IMU interrupt flag
|
||||
* Set to 1 on falling-edge interrupt of INT1 pin.
|
||||
* Main loop checks this flag, reads data, and clears it to 0.
|
||||
* volatile: modified by ISR, prevents compiler optimization.
|
||||
*/
|
||||
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 pin interrupt handler (ISR).
|
||||
* Called when the sensor has new data ready; sets a flag and returns immediately.
|
||||
* Actual data processing is done in the main loop (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()
|
||||
* Initializes INT1 (P1.13) GPIO interrupt.
|
||||
*
|
||||
* Configuration:
|
||||
* - Trigger: falling edge (HITOLO) — when the sensor pulls INT low
|
||||
* - Pull-up: internal pull-up enabled
|
||||
* - Handler: inv_gpio_sensor_interrupt_handler
|
||||
* - Initializes GPIOTE module first if not already initialized
|
||||
*/
|
||||
void inv_gpio_sensor_irq_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
/* Initialize GPIOTE module (skip if already initialized) */
|
||||
if (!nrfx_gpiote_is_init())
|
||||
{
|
||||
err_code = nrfx_gpiote_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/* Falling-edge interrupt: trigger on High->Low transition, internal pull-up */
|
||||
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
|
||||
in_config.pull = NRF_GPIO_PIN_PULLUP;
|
||||
|
||||
/* Register interrupt handler for INT1 pin */
|
||||
err_code = nrfx_gpiote_in_init(ICM42670_INT1_PIN, &in_config, inv_gpio_sensor_interrupt_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Enable interrupt event */
|
||||
nrfx_gpiote_in_event_enable(ICM42670_INT1_PIN, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inv_gpio_sensor_irq_uninit()
|
||||
* Disables and releases the INT1 GPIO interrupt.
|
||||
* Called when deactivating the sensor or before re-initialization.
|
||||
*/
|
||||
void inv_gpio_sensor_irq_uninit(void)
|
||||
{
|
||||
/* Disable interrupt event */
|
||||
nrfx_gpiote_in_event_disable(ICM42670_INT1_PIN);
|
||||
|
||||
/* Release INT1 pin interrupt configuration */
|
||||
nrfx_gpiote_in_uninit(ICM42670_INT1_PIN);
|
||||
|
||||
/* Release GPIOTE module (only if initialized) */
|
||||
if (nrfx_gpiote_is_init())
|
||||
{
|
||||
nrfx_gpiote_uninit();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Main
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* icm42670_init()
|
||||
* Performs the full ICM42670P initialization sequence.
|
||||
*
|
||||
* Init order:
|
||||
* 1) setup_mcu() - Configure I2C interface struct and TWI hardware init
|
||||
* 2) setup_imu_device() - IMU driver init, WHOAMI (0x67) verification
|
||||
* 3) configure_imu_device() - FSR, ODR, power mode configuration
|
||||
* 4) inv_gpio_sensor_irq_init() - Enable INT1 interrupt (data-ready notification)
|
||||
*
|
||||
* Returns: 0=success, -1=initialization failure
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* Enable INT1 interrupt after successful init — ISR fires on data ready */
|
||||
inv_gpio_sensor_irq_init();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icm42670_main()
|
||||
* ICM42670P main polling loop.
|
||||
* Must be called periodically from the main application loop.
|
||||
*
|
||||
* Operation:
|
||||
* 1) Check if I2C hardware is initialized (hw_i2c_init_once)
|
||||
* 2) Check irq_from_device flag (set by ISR)
|
||||
* 3) If flag is set, read sensor data (get_imu_data)
|
||||
* 4) Clear flag after data read completes
|
||||
*
|
||||
* Note: Interrupt-based polling — ISR only sets the flag; actual I2C
|
||||
* communication is done in the main context.
|
||||
*/
|
||||
void icm42670_main(void)
|
||||
{
|
||||
int rc = 0;
|
||||
hw_i2c_init_once();
|
||||
/* Check for interrupt and read data */
|
||||
|
||||
if (irq_from_device) {
|
||||
rc = get_imu_data();
|
||||
|
||||
if(rc < 0) {
|
||||
printf("error while getting data\r\n");
|
||||
}
|
||||
|
||||
/* Clear flag — wait for next interrupt */
|
||||
irq_from_device = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Functions definitions
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* setup_mcu()
|
||||
* Configures the MCU-side serial interface.
|
||||
*
|
||||
* Registers the following in the inv_imu_serif struct:
|
||||
* - read_reg / write_reg : I2C read/write callbacks (implemented in system_interface.c)
|
||||
* - max_read / max_write : Max transfer size (32KB)
|
||||
* - serif_type : Communication type (UI_I2C)
|
||||
*
|
||||
* After configuration, calls inv_io_hal_init() to initialize the TWI hardware.
|
||||
*/
|
||||
static int setup_mcu(struct inv_imu_serif *icm_serif)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Configure serial interface struct for IMU driver */
|
||||
icm_serif->context = 0; /* Context unused */
|
||||
icm_serif->read_reg = inv_io_hal_read_reg; /* Register read callback */
|
||||
icm_serif->write_reg = inv_io_hal_write_reg; /* Register write callback */
|
||||
icm_serif->max_read = 1024*32; /* Max bytes per read */
|
||||
icm_serif->max_write = 1024*32; /* Max bytes per write */
|
||||
icm_serif->serif_type = SERIF_TYPE; /* UI_I2C (defined in app_raw.h) */
|
||||
|
||||
/* Initialize TWI hardware */
|
||||
rc |= inv_io_hal_init(icm_serif);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------
|
||||
* Extern functions definition
|
||||
* -------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* inv_imu_sleep_us()
|
||||
* Microsecond sleep function used by the IMU driver.
|
||||
* Wraps nrf_delay_us() to provide a platform-independent interface.
|
||||
* Example: used for gyro startup delay (GYR_STARTUP_TIME_US).
|
||||
*/
|
||||
void inv_imu_sleep_us(uint32_t us)
|
||||
{
|
||||
nrf_delay_us(us);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inv_imu_get_time_us()
|
||||
* Timestamp function used by the IMU driver.
|
||||
* Returns the nRF52840 RTC1 counter value.
|
||||
*
|
||||
* Note: RTC1 runs at 32.768kHz, so the returned value is technically
|
||||
* in RTC ticks (~30.5us/tick), not microseconds.
|
||||
* Used for relative time comparisons within the driver.
|
||||
*/
|
||||
uint64_t inv_imu_get_time_us(void)
|
||||
{
|
||||
return NRF_RTC1->COUNTER;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* @file app_raw_main.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Header overview] ICM42670P main initialization/polling loop declarations
|
||||
*
|
||||
* Declares the full initialization and main loop functions for the
|
||||
* ICM42670P IMU sensor.
|
||||
* - icm42670_init() : Full init (MCU config -> IMU init -> sensor config -> enable IRQ)
|
||||
* - icm42670_main() : Main polling loop (check INT1 interrupt -> read data)
|
||||
* - icm42670_uninit() : Release (prototype only, implementation elsewhere)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _APP_RAW_MAIN_H_
|
||||
#define _APP_RAW_MAIN_H_
|
||||
#include "sdk_config.h"
|
||||
|
||||
/* ICM42670P full init — MCU I2C config -> IMU driver init -> sensor config -> enable IRQ */
|
||||
int icm42670_init(void);
|
||||
|
||||
/* ICM42670P main polling loop — check INT1 interrupt flag, then read sensor data */
|
||||
void icm42670_main(void);
|
||||
|
||||
/* ICM42670P release (prototype declaration) */
|
||||
int icm42670_uninit(void);
|
||||
|
||||
#endif /* !_APP_RAW_MAIN_H_ */
|
||||
@@ -0,0 +1,334 @@
|
||||
/*******************************************************************************
|
||||
* @file system_interface.c
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Module overview] ICM42670P IMU sensor I2C communication interface
|
||||
*
|
||||
* Low-level interface module for communicating with the ICM42670P IMU sensor
|
||||
* via the nRF52840 TWI (I2C) hardware.
|
||||
*
|
||||
* - I2C slave address: 0x68 (ICM42670P default)
|
||||
* - I2C pin config: SCL=P1.14, SDA=P1.15 (defined in system_interface.h)
|
||||
* - TWI instance: NRFX_TWI_INSTANCE(0)
|
||||
* - Bus speed: 100kHz (NRF_TWI_FREQ_100K)
|
||||
*
|
||||
* Main function flow:
|
||||
* inv_io_hal_init() -> Initialize I2C or SPI (only I2C implemented)
|
||||
* inv_io_hal_read_reg() -> Register read (TX address -> RX data)
|
||||
* inv_io_hal_write_reg() -> Register write (TX address+data at once)
|
||||
*
|
||||
* Error handling: All I2C read/write operations retry once on failure
|
||||
*
|
||||
* Note: SPI4 code path exists but is not implemented;
|
||||
* only I2C (UI_I2C) is used in production.
|
||||
******************************************************************************/
|
||||
|
||||
/* 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 slave address and max serial write byte count */
|
||||
#define ICM_I2C_ADDR 0x68
|
||||
#define INV_MAX_SERIAL_WRITE 16
|
||||
|
||||
/* TWI (I2C) instance — uses ICM42670_I2C_INSTANCE(0) from system_interface.h */
|
||||
const nrfx_twi_t m_twi_icm42670 = NRFX_TWI_INSTANCE(ICM42670_I2C_INSTANCE);
|
||||
|
||||
/*
|
||||
* inv_i2c_master_uninitialize()
|
||||
* Disables the I2C bus and releases the TWI instance.
|
||||
* Called before entering sleep mode or before re-initialization.
|
||||
*/
|
||||
void inv_i2c_master_uninitialize(void){
|
||||
nrfx_twi_disable(&m_twi_icm42670);
|
||||
nrfx_twi_uninit(&m_twi_icm42670);
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_i2c_master_initialize()
|
||||
* Initializes and enables the nRF52840 TWI hardware.
|
||||
* - SCL: P1.14, SDA: P1.15
|
||||
* - Speed: 100kHz
|
||||
* - Interrupt priority: highest (APP_IRQ_PRIORITY_HIGH)
|
||||
* - No event handler (blocking mode)
|
||||
*/
|
||||
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,
|
||||
};
|
||||
|
||||
/* Initialize TWI driver (event handler=NULL -> blocking mode) */
|
||||
err_code = nrfx_twi_init(&m_twi_icm42670, &twi_icm42670_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* Enable TWI hardware — tx/rx available after this */
|
||||
nrfx_twi_enable(&m_twi_icm42670);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icm42670_twi_tx()
|
||||
* I2C transmit wrapper. Calls nrfx_twi_tx to send data.
|
||||
* If no_stop=true, STOP condition is omitted (used for 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 receive wrapper. Calls nrfx_twi_rx to receive data.
|
||||
*/
|
||||
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()
|
||||
* Reads data from a specific ICM42670P register.
|
||||
*
|
||||
* Sequence:
|
||||
* 1) TX: Send 1-byte register address (no_stop=true -> prepare Repeated START)
|
||||
* 2) RX: Receive data of specified length
|
||||
*
|
||||
* Error handling: Retries once on TX or RX failure.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Step 1: Send register address to read (no STOP -> uses Repeated START) */
|
||||
ret = icm42670_twi_tx(Address, &addr8, 1, true);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
/* Retry once on failure */
|
||||
ret = icm42670_twi_tx(Address, &addr8, 1, true);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
printf("ERR! i2c read-1\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 2: Receive data from the register */
|
||||
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
/* Retry once on failure */
|
||||
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()
|
||||
* Writes data to a specific ICM42670P register.
|
||||
*
|
||||
* Sequence:
|
||||
* 1) Place register address in buffer[0], data in buffer[1..N]
|
||||
* 2) TX: Send address+data at once (no_stop=false -> includes STOP condition)
|
||||
*
|
||||
* Error handling: Retries once on failure.
|
||||
*/
|
||||
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]; /* register address (1) + data (max 16 bytes) */
|
||||
|
||||
/* Buffer layout: [register address][data bytes] */
|
||||
buffer[0] = (uint8_t)RegisterAddr;
|
||||
memcpy(buffer+1, RegisterValue, RegisterLen);
|
||||
|
||||
/* Send address+data at once */
|
||||
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
/* Retry once on failure */
|
||||
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()
|
||||
* Initializes the serial interface (I2C or SPI) used by the IMU driver.
|
||||
* Branches based on serif->serif_type; only I2C is currently implemented.
|
||||
* Returns: 0=success, -1=unsupported interface type
|
||||
*/
|
||||
|
||||
int inv_io_hal_init(struct inv_imu_serif *serif)
|
||||
{
|
||||
|
||||
switch (serif->serif_type) {
|
||||
case UI_SPI4:
|
||||
{
|
||||
/* SPI4 init — not implemented (only I2C is used) */
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_I2C:
|
||||
inv_i2c_master_initialize();
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inv_io_hal_read_reg()
|
||||
* IMU driver callback: reads data from the specified register.
|
||||
* Performs I2C or SPI read depending on the serial type.
|
||||
*/
|
||||
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 driver callback: writes data to the specified register.
|
||||
* Performs I2C or SPI write depending on the serial type.
|
||||
*/
|
||||
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()
|
||||
* Generic I2C read function (debug/legacy).
|
||||
* Reads 8 bytes, returns the first byte, and prints the data to console.
|
||||
* Note: Not used in production; kept for debug purposes.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Send register address (no STOP, prepare Repeated START) */
|
||||
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, &address, 1, true);
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
// Handle error
|
||||
// return;
|
||||
}
|
||||
|
||||
/* Receive 8 bytes of data */
|
||||
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()
|
||||
* Generic I2C write function (debug/legacy).
|
||||
* Sends 1 byte address + 1 byte data.
|
||||
* Note: Copies 6 bytes into buffer, but only transmits 2 bytes.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Address (1 byte) + data (1 byte) = 2 bytes transmitted */
|
||||
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.");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* @file system_interface.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [Header overview] ICM42670P I2C communication interface declarations
|
||||
*
|
||||
* Pin definitions and function prototypes for communicating with the
|
||||
* ICM42670P IMU sensor via nRF52840 TWI hardware.
|
||||
*
|
||||
* Pin assignment:
|
||||
* - I2C SCL : P1.14
|
||||
* - I2C SDA : P1.15
|
||||
* - INT1 : P1.13 (data-ready interrupt)
|
||||
* - INT2 : P0.26 (auxiliary interrupt, currently unused)
|
||||
*
|
||||
* TWI instance: 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) instance index */
|
||||
#define ICM42670_I2C_SDA_PIN NRF_GPIO_PIN_MAP(1,15) /**< SDA pin: P1.15 */
|
||||
#define ICM42670_I2C_SCL_PIN NRF_GPIO_PIN_MAP(1,14) /**< SCL pin: P1.14 */
|
||||
#define ICM42670_INT1_PIN NRF_GPIO_PIN_MAP(1,13) /**< INT1 pin: P1.13 (data-ready interrupt) */
|
||||
#define ICM42670_INT2_PIN NRF_GPIO_PIN_MAP(0,26) /**< INT2 pin: P0.26 (auxiliary, currently unused) */
|
||||
|
||||
/* I2C transmit wrapper — if no_stop=true, STOP condition is omitted for Repeated START */
|
||||
uint32_t icm42670_twi_tx( uint8_t device_id,
|
||||
uint8_t const * p_data,
|
||||
uint8_t length,
|
||||
bool no_stop);
|
||||
|
||||
/* I2C receive wrapper */
|
||||
uint32_t icm42670_twi_rx( uint8_t device_id,
|
||||
uint8_t * p_data,
|
||||
uint8_t length);
|
||||
|
||||
/* Generic I2C read (debug/legacy) — reads 8 bytes and returns the first byte */
|
||||
uint8_t cat_read (uint8_t device_id, uint8_t address, uint8_t *data);
|
||||
|
||||
/* Generic I2C write (debug/legacy) — sends address+data 2 bytes */
|
||||
void cat_write (uint8_t device_id, uint8_t address, uint8_t *data);
|
||||
|
||||
/* Release I2C hardware (called before sleep or re-initialization) */
|
||||
void inv_i2c_master_uninitialize(void);
|
||||
|
||||
/* Initialize I2C hardware (100kHz, blocking mode) */
|
||||
void inv_i2c_master_initialize(void);
|
||||
|
||||
/* Initialize serial interface for IMU driver (I2C/SPI branch) */
|
||||
int inv_io_hal_init(struct inv_imu_serif *serif);
|
||||
|
||||
/* IMU driver callback: register read */
|
||||
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen);
|
||||
|
||||
/* IMU driver callback: register write */
|
||||
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 diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
/*==============================================================================
|
||||
* dr_piezo.h - Piezo Transducer Driver (2 MHz Signal Generator)
|
||||
*
|
||||
* Hardware: nRF52840 + MD1822K6-G MOSFET Driver + TC7920K6-G MOSFET
|
||||
* Output: +/-20V at 2 MHz, 3..7 cycles burst
|
||||
*
|
||||
* Timing Sequence:
|
||||
* 1. PE = HIGH (enable)
|
||||
* 2. P_OUT/N_OUT = 2 MHz pulses (3..7 cycles)
|
||||
* 3. DMP = HIGH (dump residual energy)
|
||||
* 4. DMP = LOW
|
||||
* 5. PE = LOW (disable)
|
||||
*
|
||||
* Pin assignment:
|
||||
* Power: DR_PIEZO_PWR_EN (P1.9) — DC/DC +/-20V enable
|
||||
* TX: PE (P0.25), DMP (P1.0), P_OUT (P1.7), N_OUT (P1.6)
|
||||
* MUX: EN_MUXA (P0.21), EN_MUXB (P0.23), SEL0 (P1.10), SEL1 (P0.28)
|
||||
*
|
||||
* MUX channel mapping (8ch):
|
||||
* CH0=A0(1,0,0,0) CH1=A2(1,0,1,0) CH2=A1(1,0,0,1) CH3=A3(1,0,1,1)
|
||||
* CH4=B0(0,1,1,1) CH5=B1(0,1,0,1) CH6=B2(0,1,1,0) CH7=B3(0,1,0,0)
|
||||
*
|
||||
* Two burst modes:
|
||||
* 1) HW burst (dr_piezo_burst): Timer2 + PPI + GPIOTE, CPU-independent
|
||||
* 2) SW burst (dr_piezo_burst_sw_XXmhz): CPU NOP-based precise timing
|
||||
* Per-frequency functions: 1.7 / 1.8 / 1.9 / 2.0 / 2.1 / 2.2 MHz
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef DR_PIEZO_H
|
||||
#define DR_PIEZO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_gpio.h"
|
||||
|
||||
/*==============================================================================
|
||||
* Power control pin (+/-20V DC/DC converter)
|
||||
*============================================================================*/
|
||||
#define DR_PIEZO_PWR_EN NRF_GPIO_PIN_MAP(1, 9)
|
||||
|
||||
/*==============================================================================
|
||||
* TX signal pins (MOSFET driver)
|
||||
* PE: Pulse Enable — activates the entire TX sequence
|
||||
* DMP: Dump — discharges residual piezo energy after burst
|
||||
* P_OUT: Positive output — drives piezo positive terminal
|
||||
* N_OUT: Negative output — drives piezo negative terminal (inverted P_OUT)
|
||||
*============================================================================*/
|
||||
#define DR_PIEZO_PIN_PE NRF_GPIO_PIN_MAP(0, 25) /**< Pulse Enable */
|
||||
#define DR_PIEZO_PIN_DMP NRF_GPIO_PIN_MAP(1, 0) /**< Dump control */
|
||||
#define DR_PIEZO_PIN_P_OUT NRF_GPIO_PIN_MAP(1, 7) /**< Positive output */
|
||||
#define DR_PIEZO_PIN_N_OUT NRF_GPIO_PIN_MAP(1, 6) /**< Negative output */
|
||||
|
||||
/*==============================================================================
|
||||
* MUX control pins (echo signal path selection, 8 channels)
|
||||
* MUXA handles CH0..CH3, MUXB handles CH4..CH7.
|
||||
* Only one MUX is enabled at a time.
|
||||
*============================================================================*/
|
||||
#define DR_PIEZO_EN_MUXA NRF_GPIO_PIN_MAP(0, 21) /**< MUXA Enable */
|
||||
#define DR_PIEZO_EN_MUXB NRF_GPIO_PIN_MAP(0, 23) /**< MUXB Enable */
|
||||
#define DR_PIEZO_MUX_SEL0 NRF_GPIO_PIN_MAP(1, 10) /**< MUX Select 0 */
|
||||
#define DR_PIEZO_MUX_SEL1 NRF_GPIO_PIN_MAP(0, 28) /**< MUX Select 1 */
|
||||
|
||||
/*==============================================================================
|
||||
* Configuration
|
||||
*============================================================================*/
|
||||
#define DR_PIEZO_FREQ_HZ 2100000 /**< Target frequency (set PIEZO_FREQ_MHZ in .c) */
|
||||
#define DR_PIEZO_DEFAULT_CYCLES 5 /**< Default burst cycles */
|
||||
#define DR_PIEZO_MIN_CYCLES 3
|
||||
#define DR_PIEZO_MAX_CYCLES 7
|
||||
#define DR_PIEZO_MUX_SETTLING_US 1300 /**< MUX settling delay (us) */
|
||||
|
||||
/*==============================================================================
|
||||
* Power control
|
||||
*============================================================================*/
|
||||
|
||||
void dr_piezo_power_on(void);
|
||||
void dr_piezo_power_off(void);
|
||||
|
||||
/** @return true if power is ON */
|
||||
bool dr_piezo_is_power_on(void);
|
||||
|
||||
/*==============================================================================
|
||||
* TX driver
|
||||
*============================================================================*/
|
||||
|
||||
void dr_piezo_init(void);
|
||||
void dr_piezo_uninit(void);
|
||||
void dr_piezo_burst(uint8_t cycles);
|
||||
void dr_piezo_pulse(void);
|
||||
void dr_piezo_enable(void);
|
||||
void dr_piezo_disable(void);
|
||||
bool dr_piezo_is_busy(void);
|
||||
void dr_piezo_set_frequency(uint32_t freq_hz);
|
||||
void dr_piezo_test_pins(void);
|
||||
void dr_piezo_mux_init(void);
|
||||
|
||||
/**
|
||||
* @brief Select piezo channel (0..7) via 8ch MUX
|
||||
* @note MUX settling time: ~1.3 ms delay after switching
|
||||
*/
|
||||
void dr_piezo_select_channel(uint8_t channel);
|
||||
|
||||
/*==============================================================================
|
||||
* System functions (power + TX combined)
|
||||
*============================================================================*/
|
||||
|
||||
void dr_piezo_system_init(void);
|
||||
void dr_piezo_system_uninit(void);
|
||||
void dr_piezo_transmit(uint8_t cycles);
|
||||
|
||||
/*==============================================================================
|
||||
* Software burst — CPU NOP-based precise timing, no Timer/PPI
|
||||
*
|
||||
* Interrupts are disabled during burst for timing accuracy.
|
||||
* Per-frequency functions (NOP count varies):
|
||||
*============================================================================*/
|
||||
|
||||
void dr_piezo_burst_sw(uint8_t cycles); /**< 2.1 MHz (default) */
|
||||
void dr_piezo_burst_sw_18mhz(uint8_t cycles); /**< 1.8 MHz */
|
||||
void dr_piezo_burst_sw_20mhz(uint8_t cycles); /**< 2.0 MHz */
|
||||
void dr_piezo_burst_sw_22mhz(uint8_t cycles); /**< 2.2 MHz */
|
||||
void dr_piezo_burst_sw_17mhz(uint8_t cycles); /**< 1.7 MHz */
|
||||
void dr_piezo_burst_sw_19mhz(uint8_t cycles); /**< 1.9 MHz */
|
||||
|
||||
#endif /* DR_PIEZO_H */
|
||||
@@ -0,0 +1,168 @@
|
||||
/*==============================================================================
|
||||
* tmp235_q1.c - TMP235-Q1 analogue temperature sensor driver
|
||||
*
|
||||
* Reads the TMP235-Q1 analogue output via SAADC AIN3 and converts to deg C.
|
||||
*
|
||||
* Temperature conversion (piecewise linear, per datasheet):
|
||||
* Vout <= 1500 mV (0..100 C) : Ta = (Vout - 500) / 10.0
|
||||
* Vout <= 1750 mV (100..125 C): Ta = (Vout - 1500) / 10.1 + 100
|
||||
* Vout <= 2000 mV (125..150 C): Ta = (Vout - 1752.5) / 10.6 + 125
|
||||
* Vout > 2000 mV : out of sensor range
|
||||
*============================================================================*/
|
||||
|
||||
#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"
|
||||
#include "main_timer.h"
|
||||
#include "battery_saadc.h"
|
||||
#include "debug_print.h"
|
||||
|
||||
/* SAADC internal reference (mV) */
|
||||
#define TMP235_REF_VOLTAGE_IN_MILLIVOLTS 600.0f
|
||||
/* 1/3 prescaling compensation (x6) */
|
||||
#define TMP235_PRE_SCALING_COMPENSATION 6.0f
|
||||
/* 12-bit ADC full scale */
|
||||
#define TMP235_ADC_RES_12BITS 4096.0f
|
||||
|
||||
/* Convert raw ADC value to TMP235 output voltage (mV) */
|
||||
#define TMP235_VOUT_IN_MILLI_VOLTS(ADC_VALUE)\
|
||||
((((ADC_VALUE) * TMP235_REF_VOLTAGE_IN_MILLIVOLTS) / TMP235_ADC_RES_12BITS) * TMP235_PRE_SCALING_COMPENSATION)
|
||||
|
||||
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];
|
||||
|
||||
extern which_cmd_t cmd_type_t;
|
||||
extern bool info4;
|
||||
extern bool go_temp;
|
||||
|
||||
/* info4 mode: cached temperature (deg C x 100, integer) */
|
||||
volatile uint16_t info_temp;
|
||||
extern bool motion_raw_data_enabled;
|
||||
|
||||
/* SAADC completion flag — used by all_sensors() to wait */
|
||||
volatile bool tmp235_saadc_done = false;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* tmp235_voltage_handler - SAADC conversion complete callback
|
||||
*
|
||||
* ADC value -> Vout (mV) -> temperature (deg C), then:
|
||||
* - info4 mode: store to info_temp (C x 100 integer)
|
||||
* - Normal mode: send rso: response over BLE or UART
|
||||
*============================================================================*/
|
||||
void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event)
|
||||
{
|
||||
float led_temp;
|
||||
float led_temp_16;
|
||||
|
||||
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
|
||||
{
|
||||
nrf_saadc_value_t adc_result;
|
||||
float tmp235_voltage_in_milli_volts = 0;
|
||||
|
||||
adc_result = p_event->data.done.p_buffer[0];
|
||||
|
||||
/* Release SAADC — shared with battery / pressure ADC */
|
||||
nrf_drv_saadc_channel_uninit(0);
|
||||
nrf_drv_saadc_uninit();
|
||||
|
||||
/* ADC -> TMP235 output voltage (mV) */
|
||||
tmp235_voltage_in_milli_volts = TMP235_VOUT_IN_MILLI_VOLTS(adc_result);
|
||||
|
||||
/* Vout -> temperature (piecewise linear per datasheet) */
|
||||
if(tmp235_voltage_in_milli_volts <= 1500)
|
||||
{
|
||||
/* 0..100 C: slope 10.0 mV/C, offset 500 mV */
|
||||
led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f;
|
||||
}
|
||||
else if(tmp235_voltage_in_milli_volts <= 1750)
|
||||
{
|
||||
/* 100..125 C: slope 10.1 mV/C */
|
||||
led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f;
|
||||
}
|
||||
else if(tmp235_voltage_in_milli_volts <= 2000)
|
||||
{
|
||||
/* 125..150 C: slope 10.6 mV/C */
|
||||
led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Out of sensor range (>150 C) */
|
||||
DBG_PRINTF("ERR!!! Temperature is over 150c\r\n");
|
||||
}
|
||||
|
||||
/* --- Safety check mode: pass temperature to battery module for judgment --- */
|
||||
if (safety_check_mode == true)
|
||||
{
|
||||
safety_check_mode = false;
|
||||
safety_check_complete(led_temp);
|
||||
}
|
||||
|
||||
/* --- info4 mode: store value for mbb? bulk response --- */
|
||||
else if (info4 == true)
|
||||
{
|
||||
info_temp = (uint16_t)(led_temp * 100);
|
||||
}
|
||||
else if (cmd_type_t == CMD_UART)
|
||||
{
|
||||
DBG_PRINTF("To%.2f\r\n\r\n", led_temp);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
tmp235_saadc_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* tmp235_init - Initialise SAADC for TMP235 and start measurement
|
||||
*
|
||||
* AIN3, single-ended, 12-bit, 4x oversampling, burst enabled.
|
||||
* Triggers sampling immediately; result arrives via tmp235_voltage_handler.
|
||||
*============================================================================*/
|
||||
void tmp235_init(void)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
err_code = nrf_drv_saadc_sample();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* tmp235_voltage_level_meas - External entry point for one-shot reading
|
||||
*
|
||||
* Calls tmp235_init() which both initialises and triggers sampling.
|
||||
*============================================================================*/
|
||||
void tmp235_voltage_level_meas(void)
|
||||
{
|
||||
tmp235_init();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*==============================================================================
|
||||
* tmp235_q1.h - TMP235-Q1 analogue temperature sensor driver interface
|
||||
*
|
||||
* Reads the TMP235-Q1 analogue voltage output via SAADC (AIN3) and converts
|
||||
* it to temperature (deg C).
|
||||
*
|
||||
* Conversion: Ta(C) = (Vout_mV - 500) / 10.0 (valid 0..100 C)
|
||||
*
|
||||
* API:
|
||||
* tmp235_init() : initialise SAADC + start measurement (internal)
|
||||
* tmp235_voltage_level_meas() : one-shot temperature reading (external wrapper)
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef _TMP235_Q1_H_
|
||||
#define _TMP235_Q1_H_
|
||||
|
||||
/* Initialise SAADC for TMP235 and start measurement (AIN3). */
|
||||
void tmp235_init(void);
|
||||
/* External entry point for a single temperature reading. */
|
||||
void tmp235_voltage_level_meas(void);
|
||||
|
||||
#endif /* !_TMP235_Q1_H_ */
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
..\..\..\..\..\..\..\pc_firm\dr_adc121s051\dr_adc121s051.c,
|
||||
..\..\..\..\..\..\..\pc_firm\dr_adc121s051\dr_adc121s051.h
|
||||
TO nrf52840_xxaa.hex RTE NOPRINT
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
|
||||
|
||||
<component name="EventRecorderStub" version="1.0.0"/> <!--name and version of the component-->
|
||||
<events>
|
||||
</events>
|
||||
|
||||
</component_viewer>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
[BREAKPOINTS]
|
||||
ForceImpTypeAny = 0
|
||||
ShowInfoWin = 1
|
||||
EnableFlashBP = 2
|
||||
BPDuringExecution = 0
|
||||
[CFI]
|
||||
CFISize = 0x00
|
||||
CFIAddr = 0x00
|
||||
[CPU]
|
||||
MonModeVTableAddr = 0xFFFFFFFF
|
||||
MonModeDebug = 0
|
||||
MaxNumAPs = 0
|
||||
LowPowerHandlingMode = 0
|
||||
OverrideMemMap = 0
|
||||
AllowSimulation = 1
|
||||
ScriptFile=""
|
||||
[FLASH]
|
||||
RMWThreshold = 0x400
|
||||
Loaders=""
|
||||
EraseType = 0x00
|
||||
CacheExcludeSize = 0x00
|
||||
CacheExcludeAddr = 0x00
|
||||
MinNumBytesFlashDL = 0
|
||||
SkipProgOnCRCMatch = 1
|
||||
VerifyDownload = 1
|
||||
AllowCaching = 1
|
||||
EnableFlashDL = 2
|
||||
Override = 0
|
||||
Device="ARM7"
|
||||
[GENERAL]
|
||||
WorkRAMSize = 0x00
|
||||
WorkRAMAddr = 0x00
|
||||
RAMUsageLimit = 0x00
|
||||
[SWO]
|
||||
SWOLogFile=""
|
||||
[MEM]
|
||||
RdOverrideOrMask = 0x00
|
||||
RdOverrideAndMask = 0xFFFFFFFF
|
||||
RdOverrideAddr = 0xFFFFFFFF
|
||||
WrOverrideOrMask = 0x00
|
||||
WrOverrideAndMask = 0xFFFFFFFF
|
||||
WrOverrideAddr = 0xFFFFFFFF
|
||||
[RAM]
|
||||
VerifyDownload = 0x00
|
||||
[DYN_MEM_MAP]
|
||||
NumUserRegion = 0x00
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
; Copyright (c) 2009-2021 ARM Limited. All rights reserved.
|
||||
;
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
;
|
||||
; Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; not use this file except in compliance with the License.
|
||||
; You may obtain a copy of the License at
|
||||
;
|
||||
; www.apache.org/licenses/LICENSE-2.0
|
||||
;
|
||||
; Unless required by applicable law or agreed to in writing, software
|
||||
; distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; See the License for the specific language governing permissions and
|
||||
; limitations under the License.
|
||||
;
|
||||
; NOTICE: This file has been modified by Nordic Semiconductor ASA.
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
#ifdef __STARTUP_CONFIG
|
||||
#include "startup_config.h"
|
||||
#ifndef __STARTUP_CONFIG_STACK_ALIGNEMENT
|
||||
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3
|
||||
#endif
|
||||
#endif
|
||||
ENDIF
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Stack_Size EQU __STARTUP_CONFIG_STACK_SIZE
|
||||
ELIF :DEF: __STACK_SIZE
|
||||
Stack_Size EQU __STACK_SIZE
|
||||
ELSE
|
||||
Stack_Size EQU 16384
|
||||
ENDIF
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Stack_Align EQU __STARTUP_CONFIG_STACK_ALIGNEMENT
|
||||
ELSE
|
||||
Stack_Align EQU 3
|
||||
ENDIF
|
||||
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=Stack_Align
|
||||
Stack_Mem SPACE Stack_Size
|
||||
__initial_sp
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Heap_Size EQU __STARTUP_CONFIG_HEAP_SIZE
|
||||
ELIF :DEF: __HEAP_SIZE
|
||||
Heap_Size EQU __HEAP_SIZE
|
||||
ELSE
|
||||
Heap_Size EQU 16384
|
||||
ENDIF
|
||||
|
||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
; Vector Table Mapped to Address 0 at Reset
|
||||
|
||||
AREA RESET, DATA, READONLY
|
||||
EXPORT __Vectors
|
||||
EXPORT __Vectors_End
|
||||
EXPORT __Vectors_Size
|
||||
|
||||
__Vectors DCD __initial_sp ; Top of Stack
|
||||
DCD Reset_Handler
|
||||
DCD NMI_Handler
|
||||
DCD HardFault_Handler
|
||||
DCD MemoryManagement_Handler
|
||||
DCD BusFault_Handler
|
||||
DCD UsageFault_Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD SVC_Handler
|
||||
DCD DebugMon_Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD PendSV_Handler
|
||||
DCD SysTick_Handler
|
||||
|
||||
; External Interrupts
|
||||
DCD POWER_CLOCK_IRQHandler
|
||||
DCD RADIO_IRQHandler
|
||||
DCD UARTE0_UART0_IRQHandler
|
||||
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
|
||||
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
|
||||
DCD NFCT_IRQHandler
|
||||
DCD GPIOTE_IRQHandler
|
||||
DCD SAADC_IRQHandler
|
||||
DCD TIMER0_IRQHandler
|
||||
DCD TIMER1_IRQHandler
|
||||
DCD TIMER2_IRQHandler
|
||||
DCD RTC0_IRQHandler
|
||||
DCD TEMP_IRQHandler
|
||||
DCD RNG_IRQHandler
|
||||
DCD ECB_IRQHandler
|
||||
DCD CCM_AAR_IRQHandler
|
||||
DCD WDT_IRQHandler
|
||||
DCD RTC1_IRQHandler
|
||||
DCD QDEC_IRQHandler
|
||||
DCD COMP_LPCOMP_IRQHandler
|
||||
DCD SWI0_EGU0_IRQHandler
|
||||
DCD SWI1_EGU1_IRQHandler
|
||||
DCD SWI2_EGU2_IRQHandler
|
||||
DCD SWI3_EGU3_IRQHandler
|
||||
DCD SWI4_EGU4_IRQHandler
|
||||
DCD SWI5_EGU5_IRQHandler
|
||||
DCD TIMER3_IRQHandler
|
||||
DCD TIMER4_IRQHandler
|
||||
DCD PWM0_IRQHandler
|
||||
DCD PDM_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD MWU_IRQHandler
|
||||
DCD PWM1_IRQHandler
|
||||
DCD PWM2_IRQHandler
|
||||
DCD SPIM2_SPIS2_SPI2_IRQHandler
|
||||
DCD RTC2_IRQHandler
|
||||
DCD I2S_IRQHandler
|
||||
DCD FPU_IRQHandler
|
||||
DCD USBD_IRQHandler
|
||||
DCD UARTE1_IRQHandler
|
||||
DCD QSPI_IRQHandler
|
||||
DCD CRYPTOCELL_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD PWM3_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD SPIM3_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
|
||||
__Vectors_End
|
||||
|
||||
__Vectors_Size EQU __Vectors_End - __Vectors
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
; Reset Handler
|
||||
|
||||
|
||||
Reset_Handler PROC
|
||||
EXPORT Reset_Handler [WEAK]
|
||||
IMPORT SystemInit
|
||||
IMPORT __main
|
||||
|
||||
|
||||
LDR R0, =SystemInit
|
||||
BLX R0
|
||||
LDR R0, =__main
|
||||
BX R0
|
||||
ENDP
|
||||
|
||||
; Dummy Exception Handlers (infinite loops which can be modified)
|
||||
|
||||
NMI_Handler PROC
|
||||
EXPORT NMI_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
HardFault_Handler\
|
||||
PROC
|
||||
EXPORT HardFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
MemoryManagement_Handler\
|
||||
PROC
|
||||
EXPORT MemoryManagement_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
BusFault_Handler\
|
||||
PROC
|
||||
EXPORT BusFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
UsageFault_Handler\
|
||||
PROC
|
||||
EXPORT UsageFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
DebugMon_Handler\
|
||||
PROC
|
||||
EXPORT DebugMon_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
|
||||
Default_Handler PROC
|
||||
|
||||
EXPORT POWER_CLOCK_IRQHandler [WEAK]
|
||||
EXPORT RADIO_IRQHandler [WEAK]
|
||||
EXPORT UARTE0_UART0_IRQHandler [WEAK]
|
||||
EXPORT SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler [WEAK]
|
||||
EXPORT SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler [WEAK]
|
||||
EXPORT NFCT_IRQHandler [WEAK]
|
||||
EXPORT GPIOTE_IRQHandler [WEAK]
|
||||
EXPORT SAADC_IRQHandler [WEAK]
|
||||
EXPORT TIMER0_IRQHandler [WEAK]
|
||||
EXPORT TIMER1_IRQHandler [WEAK]
|
||||
EXPORT TIMER2_IRQHandler [WEAK]
|
||||
EXPORT RTC0_IRQHandler [WEAK]
|
||||
EXPORT TEMP_IRQHandler [WEAK]
|
||||
EXPORT RNG_IRQHandler [WEAK]
|
||||
EXPORT ECB_IRQHandler [WEAK]
|
||||
EXPORT CCM_AAR_IRQHandler [WEAK]
|
||||
EXPORT WDT_IRQHandler [WEAK]
|
||||
EXPORT RTC1_IRQHandler [WEAK]
|
||||
EXPORT QDEC_IRQHandler [WEAK]
|
||||
EXPORT COMP_LPCOMP_IRQHandler [WEAK]
|
||||
EXPORT SWI0_EGU0_IRQHandler [WEAK]
|
||||
EXPORT SWI1_EGU1_IRQHandler [WEAK]
|
||||
EXPORT SWI2_EGU2_IRQHandler [WEAK]
|
||||
EXPORT SWI3_EGU3_IRQHandler [WEAK]
|
||||
EXPORT SWI4_EGU4_IRQHandler [WEAK]
|
||||
EXPORT SWI5_EGU5_IRQHandler [WEAK]
|
||||
EXPORT TIMER3_IRQHandler [WEAK]
|
||||
EXPORT TIMER4_IRQHandler [WEAK]
|
||||
EXPORT PWM0_IRQHandler [WEAK]
|
||||
EXPORT PDM_IRQHandler [WEAK]
|
||||
EXPORT MWU_IRQHandler [WEAK]
|
||||
EXPORT PWM1_IRQHandler [WEAK]
|
||||
EXPORT PWM2_IRQHandler [WEAK]
|
||||
EXPORT SPIM2_SPIS2_SPI2_IRQHandler [WEAK]
|
||||
EXPORT RTC2_IRQHandler [WEAK]
|
||||
EXPORT I2S_IRQHandler [WEAK]
|
||||
EXPORT FPU_IRQHandler [WEAK]
|
||||
EXPORT USBD_IRQHandler [WEAK]
|
||||
EXPORT UARTE1_IRQHandler [WEAK]
|
||||
EXPORT QSPI_IRQHandler [WEAK]
|
||||
EXPORT CRYPTOCELL_IRQHandler [WEAK]
|
||||
EXPORT PWM3_IRQHandler [WEAK]
|
||||
EXPORT SPIM3_IRQHandler [WEAK]
|
||||
POWER_CLOCK_IRQHandler
|
||||
RADIO_IRQHandler
|
||||
UARTE0_UART0_IRQHandler
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
|
||||
NFCT_IRQHandler
|
||||
GPIOTE_IRQHandler
|
||||
SAADC_IRQHandler
|
||||
TIMER0_IRQHandler
|
||||
TIMER1_IRQHandler
|
||||
TIMER2_IRQHandler
|
||||
RTC0_IRQHandler
|
||||
TEMP_IRQHandler
|
||||
RNG_IRQHandler
|
||||
ECB_IRQHandler
|
||||
CCM_AAR_IRQHandler
|
||||
WDT_IRQHandler
|
||||
RTC1_IRQHandler
|
||||
QDEC_IRQHandler
|
||||
COMP_LPCOMP_IRQHandler
|
||||
SWI0_EGU0_IRQHandler
|
||||
SWI1_EGU1_IRQHandler
|
||||
SWI2_EGU2_IRQHandler
|
||||
SWI3_EGU3_IRQHandler
|
||||
SWI4_EGU4_IRQHandler
|
||||
SWI5_EGU5_IRQHandler
|
||||
TIMER3_IRQHandler
|
||||
TIMER4_IRQHandler
|
||||
PWM0_IRQHandler
|
||||
PDM_IRQHandler
|
||||
MWU_IRQHandler
|
||||
PWM1_IRQHandler
|
||||
PWM2_IRQHandler
|
||||
SPIM2_SPIS2_SPI2_IRQHandler
|
||||
RTC2_IRQHandler
|
||||
I2S_IRQHandler
|
||||
FPU_IRQHandler
|
||||
USBD_IRQHandler
|
||||
UARTE1_IRQHandler
|
||||
QSPI_IRQHandler
|
||||
CRYPTOCELL_IRQHandler
|
||||
PWM3_IRQHandler
|
||||
SPIM3_IRQHandler
|
||||
B .
|
||||
ENDP
|
||||
ALIGN
|
||||
|
||||
; User Initial Stack & Heap
|
||||
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
|
||||
__user_initial_stackheap PROC
|
||||
|
||||
LDR R0, = Heap_Mem
|
||||
LDR R1, = (Stack_Mem + Stack_Size)
|
||||
LDR R2, = (Heap_Mem + Heap_Size)
|
||||
LDR R3, = Stack_Mem
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
ALIGN
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2009-2021 ARM Limited. All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NOTICE: This file has been modified by Nordic Semiconductor ASA.
|
||||
|
||||
*/
|
||||
|
||||
/* NOTE: Template files (including this one) are application specific and therefore expected to
|
||||
be copied into the application project folder prior to its use! */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_peripherals.h"
|
||||
#include "nrf52_erratas.h"
|
||||
#include "system_nrf52.h"
|
||||
#include "system_nrf52_approtect.h"
|
||||
|
||||
#define __SYSTEM_CLOCK_64M (64000000UL)
|
||||
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __ICCARM__ )
|
||||
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __GNUC__ )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#endif
|
||||
|
||||
/* Select correct reset pin */
|
||||
/* Handle DEVELOP_IN-targets first as they take precedence over the later macros */
|
||||
#if defined (DEVELOP_IN_NRF52805) \
|
||||
|| defined (DEVELOP_IN_NRF52810) \
|
||||
|| defined (DEVELOP_IN_NRF52811) \
|
||||
|| defined (DEVELOP_IN_NRF52832)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (DEVELOP_IN_NRF52820) \
|
||||
|| defined (DEVELOP_IN_NRF52833) \
|
||||
|| defined (DEVELOP_IN_NRF52840)
|
||||
#define RESET_PIN 18
|
||||
#elif defined (NRF52805_XXAA) \
|
||||
|| defined (NRF52810_XXAA) \
|
||||
|| defined (NRF52811_XXAA) \
|
||||
|| defined (NRF52832_XXAA) \
|
||||
|| defined (NRF52832_XXAB)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (NRF52820_XXAA) \
|
||||
|| defined (NRF52833_XXAA) \
|
||||
|| defined (NRF52840_XXAA)
|
||||
#define RESET_PIN 18
|
||||
#else
|
||||
#error "A supported device macro must be defined."
|
||||
#endif
|
||||
|
||||
/* -- NVMC utility functions -- */
|
||||
/* Waits until NVMC is done with the current pending action */
|
||||
void nvmc_wait(void)
|
||||
{
|
||||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||
}
|
||||
|
||||
/* Configure the NVMC to "mode".
|
||||
Mode must be an enumerator of field NVMC_CONFIG_WEN */
|
||||
void nvmc_config(uint32_t mode)
|
||||
{
|
||||
NRF_NVMC->CONFIG = mode << NVMC_CONFIG_WEN_Pos;
|
||||
nvmc_wait();
|
||||
}
|
||||
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
}
|
||||
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
|
||||
Specification to see which one). */
|
||||
#if defined (ENABLE_SWO) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
|
||||
Specification to see which ones). */
|
||||
#if defined (ENABLE_TRACE) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_12_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 12 "COMP: Reference ladder not correctly calibrated" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_12()){
|
||||
*(volatile uint32_t *)0x40013540 = (*(uint32_t *)0x10000324 & 0x00001F00) >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_16_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_16()){
|
||||
*(volatile uint32_t *)0x4007C074 = 3131961357ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_31_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_31()){
|
||||
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_32_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_32()){
|
||||
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_36_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_36()){
|
||||
NRF_CLOCK->EVENTS_DONE = 0;
|
||||
NRF_CLOCK->EVENTS_CTTO = 0;
|
||||
NRF_CLOCK->CTIV = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_37_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_37()){
|
||||
*(volatile uint32_t *)0x400005A0 = 0x3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_57_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_57()){
|
||||
*(volatile uint32_t *)0x40005610 = 0x00000005;
|
||||
*(volatile uint32_t *)0x40005688 = 0x00000001;
|
||||
*(volatile uint32_t *)0x40005618 = 0x00000000;
|
||||
*(volatile uint32_t *)0x40005614 = 0x0000003F;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_66_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_66()){
|
||||
NRF_TEMP->A0 = NRF_FICR->TEMP.A0;
|
||||
NRF_TEMP->A1 = NRF_FICR->TEMP.A1;
|
||||
NRF_TEMP->A2 = NRF_FICR->TEMP.A2;
|
||||
NRF_TEMP->A3 = NRF_FICR->TEMP.A3;
|
||||
NRF_TEMP->A4 = NRF_FICR->TEMP.A4;
|
||||
NRF_TEMP->A5 = NRF_FICR->TEMP.A5;
|
||||
NRF_TEMP->B0 = NRF_FICR->TEMP.B0;
|
||||
NRF_TEMP->B1 = NRF_FICR->TEMP.B1;
|
||||
NRF_TEMP->B2 = NRF_FICR->TEMP.B2;
|
||||
NRF_TEMP->B3 = NRF_FICR->TEMP.B3;
|
||||
NRF_TEMP->B4 = NRF_FICR->TEMP.B4;
|
||||
NRF_TEMP->B5 = NRF_FICR->TEMP.B5;
|
||||
NRF_TEMP->T0 = NRF_FICR->TEMP.T0;
|
||||
NRF_TEMP->T1 = NRF_FICR->TEMP.T1;
|
||||
NRF_TEMP->T2 = NRF_FICR->TEMP.T2;
|
||||
NRF_TEMP->T3 = NRF_FICR->TEMP.T3;
|
||||
NRF_TEMP->T4 = NRF_FICR->TEMP.T4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_98_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 98 "NFCT: Not able to communicate with the peer" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_98()){
|
||||
*(volatile uint32_t *)0x4000568Cul = 0x00038148ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_103_ENABLE_WORKAROUND && defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos)
|
||||
/* Workaround for Errata 103 "CCM: Wrong reset value of CCM MAXPACKETSIZE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_103()){
|
||||
NRF_CCM->MAXPACKETSIZE = 0xFBul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_108_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 108 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_108()){
|
||||
*(volatile uint32_t *)0x40000EE4ul = *(volatile uint32_t *)0x10000258ul & 0x0000004Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_115_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 115 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_115()){
|
||||
*(volatile uint32_t *)0x40000EE4 = (*(volatile uint32_t *)0x40000EE4 & 0xFFFFFFF0) | (*(uint32_t *)0x10000258 & 0x0000000F);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_120_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 120 "QSPI: Data read or written is corrupted" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_120()){
|
||||
*(volatile uint32_t *)0x40029640ul = 0x200ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_136_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 136 "System: Bits in RESETREAS are set when they should not be" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_136()){
|
||||
if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk){
|
||||
NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_182_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 182 "RADIO: Fixes for anomalies #102, #106, and #107 do not take effect" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_182()){
|
||||
*(volatile uint32_t *) 0x4000173C |= (0x1 << 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_217_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 217 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_217()){
|
||||
*(volatile uint32_t *)0x40000EE4ul |= 0x0000000Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
|
||||
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
|
||||
* operations are not used in your code. */
|
||||
#if (__FPU_USED == 1)
|
||||
SCB->CPACR |= (3UL << 20) | (3UL << 22);
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
|
||||
nrf52_handle_approtect();
|
||||
|
||||
#if NRF52_CONFIGURATION_249_ENABLE && (defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA))
|
||||
if (nrf52_configuration_249() && (NRF_UICR->NRFMDK[0] == 0xFFFFFFFF || NRF_UICR->NRFMDK[1] == 0xFFFFFFFF))
|
||||
{
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->NRFMDK[0] = 0;
|
||||
nvmc_wait();
|
||||
NRF_UICR->NRFMDK[1] = 0;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
|
||||
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
|
||||
normal GPIOs. */
|
||||
#if defined (CONFIG_NFCT_PINS_AS_GPIOS) && defined(NFCT_PRESENT)
|
||||
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
|
||||
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
|
||||
reserved for PinReset and not available as normal GPIO. */
|
||||
#if defined (CONFIG_GPIO_AS_PINRESET)
|
||||
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
|
||||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->PSELRESET[0] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
NRF_UICR->PSELRESET[1] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* When developing for nRF52810 on an nRF52832, or nRF52811 on an nRF52840,
|
||||
make sure NFC pins are mapped as GPIO. */
|
||||
#if defined (DEVELOP_IN_NRF52832) && defined(NRF52810_XXAA) \
|
||||
|| defined (DEVELOP_IN_NRF52840) && defined(NRF52811_XXAA)
|
||||
if ((*((uint32_t *)0x1000120C) & (1 << 0)) != 0){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
*((uint32_t *)0x1000120C) = 0;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2009-2021 ARM Limited. All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NOTICE: This file has been modified by Nordic Semiconductor ASA.
|
||||
|
||||
*/
|
||||
|
||||
/* NOTE: Template files (including this one) are application specific and therefore expected to
|
||||
be copied into the application project folder prior to its use! */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_peripherals.h"
|
||||
#include "nrf52_erratas.h"
|
||||
#include "system_nrf52.h"
|
||||
#include "system_nrf52_approtect.h"
|
||||
|
||||
#define __SYSTEM_CLOCK_64M (64000000UL)
|
||||
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __ICCARM__ )
|
||||
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __GNUC__ )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#endif
|
||||
|
||||
/* Select correct reset pin */
|
||||
/* Handle DEVELOP_IN-targets first as they take precedence over the later macros */
|
||||
#if defined (DEVELOP_IN_NRF52805) \
|
||||
|| defined (DEVELOP_IN_NRF52810) \
|
||||
|| defined (DEVELOP_IN_NRF52811) \
|
||||
|| defined (DEVELOP_IN_NRF52832)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (DEVELOP_IN_NRF52820) \
|
||||
|| defined (DEVELOP_IN_NRF52833) \
|
||||
|| defined (DEVELOP_IN_NRF52840)
|
||||
#define RESET_PIN 18
|
||||
#elif defined (NRF52805_XXAA) \
|
||||
|| defined (NRF52810_XXAA) \
|
||||
|| defined (NRF52811_XXAA) \
|
||||
|| defined (NRF52832_XXAA) \
|
||||
|| defined (NRF52832_XXAB)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (NRF52820_XXAA) \
|
||||
|| defined (NRF52833_XXAA) \
|
||||
|| defined (NRF52840_XXAA)
|
||||
#define RESET_PIN 18
|
||||
#else
|
||||
#error "A supported device macro must be defined."
|
||||
#endif
|
||||
|
||||
/* -- NVMC utility functions -- */
|
||||
/* Waits until NVMC is done with the current pending action */
|
||||
void nvmc_wait(void)
|
||||
{
|
||||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||
}
|
||||
|
||||
/* Configure the NVMC to "mode".
|
||||
Mode must be an enumerator of field NVMC_CONFIG_WEN */
|
||||
void nvmc_config(uint32_t mode)
|
||||
{
|
||||
NRF_NVMC->CONFIG = mode << NVMC_CONFIG_WEN_Pos;
|
||||
nvmc_wait();
|
||||
}
|
||||
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
}
|
||||
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
|
||||
Specification to see which one). */
|
||||
#if defined (ENABLE_SWO) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
|
||||
Specification to see which ones). */
|
||||
#if defined (ENABLE_TRACE) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_12_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 12 "COMP: Reference ladder not correctly calibrated" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_12()){
|
||||
*(volatile uint32_t *)0x40013540 = (*(uint32_t *)0x10000324 & 0x00001F00) >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_16_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_16()){
|
||||
*(volatile uint32_t *)0x4007C074 = 3131961357ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_31_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_31()){
|
||||
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_32_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_32()){
|
||||
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_36_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_36()){
|
||||
NRF_CLOCK->EVENTS_DONE = 0;
|
||||
NRF_CLOCK->EVENTS_CTTO = 0;
|
||||
NRF_CLOCK->CTIV = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_37_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_37()){
|
||||
*(volatile uint32_t *)0x400005A0 = 0x3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_57_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_57()){
|
||||
*(volatile uint32_t *)0x40005610 = 0x00000005;
|
||||
*(volatile uint32_t *)0x40005688 = 0x00000001;
|
||||
*(volatile uint32_t *)0x40005618 = 0x00000000;
|
||||
*(volatile uint32_t *)0x40005614 = 0x0000003F;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_66_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_66()){
|
||||
NRF_TEMP->A0 = NRF_FICR->TEMP.A0;
|
||||
NRF_TEMP->A1 = NRF_FICR->TEMP.A1;
|
||||
NRF_TEMP->A2 = NRF_FICR->TEMP.A2;
|
||||
NRF_TEMP->A3 = NRF_FICR->TEMP.A3;
|
||||
NRF_TEMP->A4 = NRF_FICR->TEMP.A4;
|
||||
NRF_TEMP->A5 = NRF_FICR->TEMP.A5;
|
||||
NRF_TEMP->B0 = NRF_FICR->TEMP.B0;
|
||||
NRF_TEMP->B1 = NRF_FICR->TEMP.B1;
|
||||
NRF_TEMP->B2 = NRF_FICR->TEMP.B2;
|
||||
NRF_TEMP->B3 = NRF_FICR->TEMP.B3;
|
||||
NRF_TEMP->B4 = NRF_FICR->TEMP.B4;
|
||||
NRF_TEMP->B5 = NRF_FICR->TEMP.B5;
|
||||
NRF_TEMP->T0 = NRF_FICR->TEMP.T0;
|
||||
NRF_TEMP->T1 = NRF_FICR->TEMP.T1;
|
||||
NRF_TEMP->T2 = NRF_FICR->TEMP.T2;
|
||||
NRF_TEMP->T3 = NRF_FICR->TEMP.T3;
|
||||
NRF_TEMP->T4 = NRF_FICR->TEMP.T4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_98_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 98 "NFCT: Not able to communicate with the peer" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_98()){
|
||||
*(volatile uint32_t *)0x4000568Cul = 0x00038148ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_103_ENABLE_WORKAROUND && defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos)
|
||||
/* Workaround for Errata 103 "CCM: Wrong reset value of CCM MAXPACKETSIZE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_103()){
|
||||
NRF_CCM->MAXPACKETSIZE = 0xFBul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_108_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 108 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_108()){
|
||||
*(volatile uint32_t *)0x40000EE4ul = *(volatile uint32_t *)0x10000258ul & 0x0000004Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_115_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 115 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_115()){
|
||||
*(volatile uint32_t *)0x40000EE4 = (*(volatile uint32_t *)0x40000EE4 & 0xFFFFFFF0) | (*(uint32_t *)0x10000258 & 0x0000000F);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_120_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 120 "QSPI: Data read or written is corrupted" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_120()){
|
||||
*(volatile uint32_t *)0x40029640ul = 0x200ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_136_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 136 "System: Bits in RESETREAS are set when they should not be" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_136()){
|
||||
if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk){
|
||||
NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_182_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 182 "RADIO: Fixes for anomalies #102, #106, and #107 do not take effect" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_182()){
|
||||
*(volatile uint32_t *) 0x4000173C |= (0x1 << 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_217_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 217 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_217()){
|
||||
*(volatile uint32_t *)0x40000EE4ul |= 0x0000000Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
|
||||
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
|
||||
* operations are not used in your code. */
|
||||
#if (__FPU_USED == 1)
|
||||
SCB->CPACR |= (3UL << 20) | (3UL << 22);
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
|
||||
nrf52_handle_approtect();
|
||||
|
||||
#if NRF52_CONFIGURATION_249_ENABLE && (defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA))
|
||||
if (nrf52_configuration_249() && (NRF_UICR->NRFMDK[0] == 0xFFFFFFFF || NRF_UICR->NRFMDK[1] == 0xFFFFFFFF))
|
||||
{
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->NRFMDK[0] = 0;
|
||||
nvmc_wait();
|
||||
NRF_UICR->NRFMDK[1] = 0;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
|
||||
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
|
||||
normal GPIOs. */
|
||||
#if defined (CONFIG_NFCT_PINS_AS_GPIOS) && defined(NFCT_PRESENT)
|
||||
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
|
||||
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
|
||||
reserved for PinReset and not available as normal GPIO. */
|
||||
#if defined (CONFIG_GPIO_AS_PINRESET)
|
||||
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
|
||||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->PSELRESET[0] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
NRF_UICR->PSELRESET[1] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* When developing for nRF52810 on an nRF52832, or nRF52811 on an nRF52840,
|
||||
make sure NFC pins are mapped as GPIO. */
|
||||
#if defined (DEVELOP_IN_NRF52832) && defined(NRF52810_XXAA) \
|
||||
|| defined (DEVELOP_IN_NRF52840) && defined(NRF52811_XXAA)
|
||||
if ((*((uint32_t *)0x1000120C) & (1 << 0)) != 0){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
*((uint32_t *)0x1000120C) = 0;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2009-2021 ARM Limited. All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
NOTICE: This file has been modified by Nordic Semiconductor ASA.
|
||||
|
||||
*/
|
||||
|
||||
/* NOTE: Template files (including this one) are application specific and therefore expected to
|
||||
be copied into the application project folder prior to its use! */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf.h"
|
||||
#include "nrf_peripherals.h"
|
||||
#include "nrf_erratas.h"
|
||||
#include "system_nrf52.h"
|
||||
#include "system_nrf52_approtect.h"
|
||||
|
||||
#define __SYSTEM_CLOCK_64M (64000000UL)
|
||||
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __ICCARM__ )
|
||||
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
#elif defined ( __GNUC__ )
|
||||
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
|
||||
#endif
|
||||
|
||||
/* Select correct reset pin */
|
||||
/* Handle DEVELOP_IN-targets first as they take precedence over the later macros */
|
||||
#if defined (DEVELOP_IN_NRF52805) \
|
||||
|| defined (DEVELOP_IN_NRF52810) \
|
||||
|| defined (DEVELOP_IN_NRF52811) \
|
||||
|| defined (DEVELOP_IN_NRF52832)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (DEVELOP_IN_NRF52820) \
|
||||
|| defined (DEVELOP_IN_NRF52833) \
|
||||
|| defined (DEVELOP_IN_NRF52840)
|
||||
#define RESET_PIN 18
|
||||
#elif defined (NRF52805_XXAA) \
|
||||
|| defined (NRF52810_XXAA) \
|
||||
|| defined (NRF52811_XXAA) \
|
||||
|| defined (NRF52832_XXAA) \
|
||||
|| defined (NRF52832_XXAB)
|
||||
#define RESET_PIN 21
|
||||
#elif defined (NRF52820_XXAA) \
|
||||
|| defined (NRF52833_XXAA) \
|
||||
|| defined (NRF52840_XXAA)
|
||||
#define RESET_PIN 18
|
||||
#else
|
||||
#error "A supported device macro must be defined."
|
||||
#endif
|
||||
|
||||
/* -- NVMC utility functions -- */
|
||||
/* Waits until NVMC is done with the current pending action */
|
||||
void nvmc_wait(void)
|
||||
{
|
||||
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||
}
|
||||
|
||||
/* Configure the NVMC to "mode".
|
||||
Mode must be an enumerator of field NVMC_CONFIG_WEN */
|
||||
void nvmc_config(uint32_t mode)
|
||||
{
|
||||
NRF_NVMC->CONFIG = mode << NVMC_CONFIG_WEN_Pos;
|
||||
nvmc_wait();
|
||||
}
|
||||
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
SystemCoreClock = __SYSTEM_CLOCK_64M;
|
||||
}
|
||||
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
|
||||
Specification to see which one). */
|
||||
#if defined (ENABLE_SWO) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
|
||||
Specification to see which ones). */
|
||||
#if defined (ENABLE_TRACE) && defined(CLOCK_TRACECONFIG_TRACEMUX_Pos)
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;
|
||||
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_12_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 12 "COMP: Reference ladder not correctly calibrated" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_12()){
|
||||
*(volatile uint32_t *)0x40013540 = (*(uint32_t *)0x10000324 & 0x00001F00) >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_16_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_16()){
|
||||
*(volatile uint32_t *)0x4007C074 = 3131961357ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_31_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_31()){
|
||||
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_32_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_32()){
|
||||
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_36_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_36()){
|
||||
NRF_CLOCK->EVENTS_DONE = 0;
|
||||
NRF_CLOCK->EVENTS_CTTO = 0;
|
||||
NRF_CLOCK->CTIV = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_37_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_37()){
|
||||
*(volatile uint32_t *)0x400005A0 = 0x3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_57_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_57()){
|
||||
*(volatile uint32_t *)0x40005610 = 0x00000005;
|
||||
*(volatile uint32_t *)0x40005688 = 0x00000001;
|
||||
*(volatile uint32_t *)0x40005618 = 0x00000000;
|
||||
*(volatile uint32_t *)0x40005614 = 0x0000003F;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_66_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_66()){
|
||||
NRF_TEMP->A0 = NRF_FICR->TEMP.A0;
|
||||
NRF_TEMP->A1 = NRF_FICR->TEMP.A1;
|
||||
NRF_TEMP->A2 = NRF_FICR->TEMP.A2;
|
||||
NRF_TEMP->A3 = NRF_FICR->TEMP.A3;
|
||||
NRF_TEMP->A4 = NRF_FICR->TEMP.A4;
|
||||
NRF_TEMP->A5 = NRF_FICR->TEMP.A5;
|
||||
NRF_TEMP->B0 = NRF_FICR->TEMP.B0;
|
||||
NRF_TEMP->B1 = NRF_FICR->TEMP.B1;
|
||||
NRF_TEMP->B2 = NRF_FICR->TEMP.B2;
|
||||
NRF_TEMP->B3 = NRF_FICR->TEMP.B3;
|
||||
NRF_TEMP->B4 = NRF_FICR->TEMP.B4;
|
||||
NRF_TEMP->B5 = NRF_FICR->TEMP.B5;
|
||||
NRF_TEMP->T0 = NRF_FICR->TEMP.T0;
|
||||
NRF_TEMP->T1 = NRF_FICR->TEMP.T1;
|
||||
NRF_TEMP->T2 = NRF_FICR->TEMP.T2;
|
||||
NRF_TEMP->T3 = NRF_FICR->TEMP.T3;
|
||||
NRF_TEMP->T4 = NRF_FICR->TEMP.T4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_98_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 98 "NFCT: Not able to communicate with the peer" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_98()){
|
||||
*(volatile uint32_t *)0x4000568Cul = 0x00038148ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_103_ENABLE_WORKAROUND && defined(CCM_MAXPACKETSIZE_MAXPACKETSIZE_Pos)
|
||||
/* Workaround for Errata 103 "CCM: Wrong reset value of CCM MAXPACKETSIZE" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_103()){
|
||||
NRF_CCM->MAXPACKETSIZE = 0xFBul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_108_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 108 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_108()){
|
||||
*(volatile uint32_t *)0x40000EE4ul = *(volatile uint32_t *)0x10000258ul & 0x0000004Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_115_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 115 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_115()){
|
||||
*(volatile uint32_t *)0x40000EE4 = (*(volatile uint32_t *)0x40000EE4 & 0xFFFFFFF0) | (*(uint32_t *)0x10000258 & 0x0000000F);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_120_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 120 "QSPI: Data read or written is corrupted" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_120()){
|
||||
*(volatile uint32_t *)0x40029640ul = 0x200ul;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_136_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 136 "System: Bits in RESETREAS are set when they should not be" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_136()){
|
||||
if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk){
|
||||
NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_182_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 182 "RADIO: Fixes for anomalies #102, #106, and #107 do not take effect" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_182()){
|
||||
*(volatile uint32_t *) 0x4000173C |= (0x1 << 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF52_ERRATA_217_ENABLE_WORKAROUND
|
||||
/* Workaround for Errata 217 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
|
||||
for your device located at https://infocenter.nordicsemi.com/index.jsp */
|
||||
if (nrf52_errata_217()){
|
||||
*(volatile uint32_t *)0x40000EE4ul |= 0x0000000Ful;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
|
||||
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
|
||||
* operations are not used in your code. */
|
||||
#if (__FPU_USED == 1)
|
||||
SCB->CPACR |= (3UL << 20) | (3UL << 22);
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
|
||||
nrf52_handle_approtect();
|
||||
|
||||
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
|
||||
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
|
||||
normal GPIOs. */
|
||||
#if defined (CONFIG_NFCT_PINS_AS_GPIOS) && defined(NFCT_PRESENT)
|
||||
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
|
||||
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
|
||||
reserved for PinReset and not available as normal GPIO. */
|
||||
#if defined (CONFIG_GPIO_AS_PINRESET)
|
||||
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
|
||||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
NRF_UICR->PSELRESET[0] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
NRF_UICR->PSELRESET[1] = RESET_PIN;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* When developing for nRF52810 on an nRF52832, or nRF52811 on an nRF52840,
|
||||
make sure NFC pins are mapped as GPIO. */
|
||||
#if defined (DEVELOP_IN_NRF52832) && defined(NRF52810_XXAA) \
|
||||
|| defined (DEVELOP_IN_NRF52840) && defined(NRF52811_XXAA)
|
||||
if ((*((uint32_t *)0x1000120C) & (1 << 0)) != 0){
|
||||
nvmc_config(NVMC_CONFIG_WEN_Wen);
|
||||
*((uint32_t *)0x1000120C) = 0;
|
||||
nvmc_wait();
|
||||
nvmc_config(NVMC_CONFIG_WEN_Ren);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
* Auto generated Run-Time-Environment Configuration File
|
||||
* *** Do not modify ! ***
|
||||
*
|
||||
* Project: 'ble_app_bladder_patch_s140'
|
||||
* Target: 'flash_s140_nrf52_7.2.0_softdevice'
|
||||
*/
|
||||
|
||||
#ifndef RTE_COMPONENTS_H
|
||||
#define RTE_COMPONENTS_H
|
||||
|
||||
|
||||
/*
|
||||
* Define the Device Header File:
|
||||
*/
|
||||
#define CMSIS_device_header "nrf.h"
|
||||
|
||||
|
||||
|
||||
#endif /* RTE_COMPONENTS_H */
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
* Auto generated Run-Time-Environment Configuration File
|
||||
* *** Do not modify ! ***
|
||||
*
|
||||
* Project: 'ble_app_bladder_patch_s140'
|
||||
* Target: 'nrf52840_xxaa'
|
||||
*/
|
||||
|
||||
#ifndef RTE_COMPONENTS_H
|
||||
#define RTE_COMPONENTS_H
|
||||
|
||||
|
||||
/*
|
||||
* Define the Device Header File:
|
||||
*/
|
||||
#define CMSIS_device_header "nrf.h"
|
||||
|
||||
|
||||
|
||||
#endif /* RTE_COMPONENTS_H */
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
SET PATH=C:\Keil_v5\ARM\ARMCC\Bin;C:\Program Files\Common Files\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Oracle\Java\java8path;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\dotnet\;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;D:\go\bin;C:\Program Files\Git\cmd;d:\nrfutil\bin;D:\nrfutil\bin\;C:\Program Files\eProsima\fastdds 3.2.2\bin;C:\Program Files\eProsima\fastdds 3.2.2\bin\x64Win64VS2019;C:\Users\CharlesKWON\AppData\Local\Microsoft\WindowsApps;C:\Users\CharlesKWON\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\CharlesKWON\.dotnet\tools;C:\Users\CharlesKWON\go\bin;C:\Users\CharlesKWON\AppData\Local\PowerToys\
|
||||
SET CPU_TYPE=nRF52840_xxAA
|
||||
SET CPU_VENDOR=Nordic Semiconductor
|
||||
SET UV2_TARGET=nrf52840_xxaa
|
||||
SET CPU_CLOCK=0x03D09000
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\main.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\main_timer.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ada2200_spi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ad5272_i2c.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\battery_saadc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\mcp4725_i2c.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\power_control.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\tmp235_q1.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\measurements.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\fstorage.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\mcp4725_adc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\meas_pd_voltage_simple.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\full_agc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ir_i2c.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\led_parse.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cat_interface.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cmd_parse.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\meas_pd_imm.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\meas_pd_48.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\pulse_gen.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\i2c_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\parser.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_quick_security.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\dr_piezo.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\dr_util.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\dr_adc121s051.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\boards.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\bsp.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\bsp_btn_ble.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\utf.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_advdata.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_advertising.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_conn_params.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_conn_state.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_link_ctx_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_srv_common.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_ble_gatt.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_ble_qwr.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\peer_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\peer_manager_handler.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\pm_buffer.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\peer_data_storage.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\peer_database.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\peer_id.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\security_dispatcher.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\security_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\gatt_cache_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\id_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\gatts_cache_manager.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_ble_lesc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_nus.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_drv_clock.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_drv_uart.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_atomic.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_clock.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_gpiote.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_prs.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_uart.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_uarte.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_twi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_saadc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_timer.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_ppi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_drv_ppi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_drv_spi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_spi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_spim.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_drv_twi.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_twim.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrfx_pwm.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_button.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_error.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_error_handler_keil.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_error_weak.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_fifo.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_scheduler.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_timer2.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_uart_fifo.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_util_platform.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\drv_rtc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\hardfault_implementation.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_assert.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_atfifo.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_atflags.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_atomic.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_balloc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_fprintf.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_fprintf_format.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_memobj.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_pwr_mgmt.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_ringbuf.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_section_iter.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_sortlist.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_strerror.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\retarget.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\crc16.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_fstorage.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_fstorage_sd.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\fds.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_log_backend_rtt.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_log_backend_serial.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_log_default_backends.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_log_frontend.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_log_str_formatter.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\segger_rtt.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\segger_rtt_syscalls_keil.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\segger_rtt_printf.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_sdh.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_sdh_ble.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_sdh_soc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_dfu.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_dfu_bonded.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ble_dfu_unbonded.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_dfu_svci.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_aead.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_aes.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_aes_shared.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_ecc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_ecdh.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_ecdsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_eddsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_error.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_hash.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_hkdf.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_hmac.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_init.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_rng.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_crypto_shared.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_aes.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_aes_aead.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_chacha_poly_aead.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_ecc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_ecdh.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_ecdsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_eddsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_hash.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_hmac.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_init.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_mutex.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_rng.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\cc310_backend_shared.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_chacha_poly_aead.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_ecc.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_ecdh.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_ecdsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_eddsa.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_hash.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\oberon_backend_hmac.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_hw_backend_init.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_hw_backend_rng.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\nrf_hw_backend_rng_mbedtls.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\aes.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\ctr_drbg.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\platform_util.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\system_interface.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\dataconverter.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\errorhelper.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\invbasicmath.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\inv_imu_apex.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\inv_imu_driver.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\inv_imu_selftest.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\inv_imu_transport.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_raw.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\app_raw_main.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmAsm" --Via ".\_build\arm_startup_nrf52840._ia"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --Via ".\_build\system_nrf52.__i"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\ArmLink" --Via ".\_build\nrf52840_xxaa.lnp"
|
||||
"C:\Keil_v5\ARM\ARMCC\Bin\fromelf.exe" ".\_build\nrf52840_xxaa.axf" --i32combined --output ".\_build\nrf52840_xxaa.hex"
|
||||
+3293
File diff suppressed because it is too large
Load Diff
+8630
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.h
|
||||
* @brief Common header for HW/SW I2C mutex control
|
||||
******************************************************************************/
|
||||
#ifndef __I2C_MANAGER_H__
|
||||
#define __I2C_MANAGER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "app_error.h"
|
||||
|
||||
extern bool HW_I2C_FRQ;
|
||||
extern bool SW_I2C_FRQ;
|
||||
|
||||
void hw_i2c_init_once(void);
|
||||
void sw_i2c_init_once(void);
|
||||
void i2c_reset_state(void);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.c
|
||||
* @brief Robust HW/SW I2C switching logic with mutual exclusion
|
||||
******************************************************************************/
|
||||
|
||||
#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"
|
||||
|
||||
bool HW_I2C_FRQ = false;
|
||||
bool SW_I2C_FRQ = false;
|
||||
|
||||
#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 */
|
||||
static void twi_uninitialize(void){
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
}
|
||||
|
||||
/* TWI (I2C) 하드웨어 초기화 (SCL/SDA핀, 400kHz) - jhChun 26.03.16 */
|
||||
static void twi_initialize(void){
|
||||
ret_code_t err_code;
|
||||
|
||||
const nrfx_twi_config_t twi_config = {
|
||||
.scl = ICM42670_I2C_SCL_PIN,
|
||||
.sda = ICM42670_I2C_SDA_PIN,
|
||||
.frequency = NRF_TWI_FREQ_400K,
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
|
||||
};
|
||||
|
||||
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrfx_twi_enable(&m_twi);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* HW (TWI) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void hw_i2c_init_once(void)
|
||||
{
|
||||
if (SW_I2C_FRQ)
|
||||
{
|
||||
DBG_PRINTF("[I2C] SW I2C active - forcing HW switch\r\n");
|
||||
// SW 비활성화 후 전환
|
||||
SW_I2C_FRQ = false;
|
||||
}
|
||||
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
DBG_PRINTF("[I2C] HW I2C already initialized\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_PRINTF("[I2C] Initializing HW (TWI) I2C...\r\n");
|
||||
twi_initialize();
|
||||
nrf_delay_ms(2);
|
||||
|
||||
HW_I2C_FRQ = true;
|
||||
SW_I2C_FRQ = false;
|
||||
|
||||
DBG_PRINTF("[I2C] HW I2C initialized\r\n");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* SW (Port-Bang) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void sw_i2c_init_once(void)
|
||||
{
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
DBG_PRINTF("[I2C] HW I2C active -> switching to SW I2C\r\n");
|
||||
|
||||
// HW 완전 종료
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
nrf_delay_ms(3);
|
||||
|
||||
HW_I2C_FRQ = false; // 반드시 false로 갱신
|
||||
}
|
||||
|
||||
// HW 모드가 종료되었으니 SW 시작 가능
|
||||
if (!SW_I2C_FRQ)
|
||||
{
|
||||
DBG_PRINTF("[I2C] Initializing SW (Port Bang-Bang) I2C...\r\n");
|
||||
|
||||
twi_uninitialize(); // SDA/SCL 해제
|
||||
nrf_delay_ms(1);
|
||||
|
||||
SW_I2C_FRQ = true;
|
||||
HW_I2C_FRQ = false;
|
||||
|
||||
DBG_PRINTF("[I2C] SW I2C initialized\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_PRINTF("[I2C] SW I2C already active\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* RESET STATE */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void i2c_reset_state(void)
|
||||
{
|
||||
HW_I2C_FRQ = false;
|
||||
SW_I2C_FRQ = false;
|
||||
DBG_PRINTF("[I2C] Flags reset\r\n");
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// file: debug_print.h
|
||||
/*******************************************************************************
|
||||
* Debug print macros (conditional compilation)
|
||||
*
|
||||
* Debug output macros using SEGGER RTT (Real Time Transfer).
|
||||
* Sends logs to the PC in real time via J-Link debugger.
|
||||
* Minimal impact on system timing since UART is not used.
|
||||
*
|
||||
* === Conditional compilation ===
|
||||
* ENABLE_PRINTF = 1: DBG_PRINTF maps to SEGGER_RTT_printf (channel 0)
|
||||
* -> Actual log output (for debugging)
|
||||
* ENABLE_PRINTF = 0: DBG_PRINTF maps to an empty macro
|
||||
* -> Completely removed from code (for release builds)
|
||||
*
|
||||
* === Usage ===
|
||||
* DBG_PRINTF("val: %d\r\n", value); // Same format string as printf
|
||||
* View output in SEGGER RTT Viewer or J-Link RTT Client.
|
||||
******************************************************************************/
|
||||
#ifndef DEBUG_PRINT_H
|
||||
#define DEBUG_PRINT_H
|
||||
|
||||
#define ENABLE_PRINTF 1 /* 1=Enable debug output, 0=Disable globally */
|
||||
|
||||
#if ENABLE_PRINTF
|
||||
#include "SEGGER_RTT.h"
|
||||
/* Print formatted string to SEGGER RTT channel 0 */
|
||||
#define DBG_PRINTF(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
/* Empty macro: compiler removes all call-site code */
|
||||
#define DBG_PRINTF(...) // Do nothing
|
||||
#endif
|
||||
|
||||
#endif // DEBUG_PRINT_H
|
||||
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* @file led_control.c
|
||||
* @brief Direct LED control driver
|
||||
* @date 2026-03-30
|
||||
*
|
||||
* Implements dual-color LED (green/orange) blink patterns with a single app_timer.
|
||||
* Simple on/off states use immediate GPIO control without a timer.
|
||||
* Complex patterns (e.g. error) are handled by a phase-based state machine.
|
||||
******************************************************************************/
|
||||
|
||||
#include "led_control.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "app_timer.h"
|
||||
|
||||
/*==============================================================================
|
||||
* Internal constants
|
||||
*============================================================================*/
|
||||
#define MS_TO_TICKS(ms) APP_TIMER_TICKS(ms)
|
||||
|
||||
/*==============================================================================
|
||||
* Colors
|
||||
*============================================================================*/
|
||||
#define COLOR_NONE 0
|
||||
#define COLOR_GREEN 1
|
||||
#define COLOR_ORANGE 2
|
||||
|
||||
/*==============================================================================
|
||||
* Error pattern constants (No.7)
|
||||
* 3Hz blink x3 = 166ms on + 166ms off x 3 = ~1s, then off for 1s
|
||||
*============================================================================*/
|
||||
#define ERROR_BLINK_ON_MS 166
|
||||
#define ERROR_BLINK_OFF_MS 166
|
||||
#define ERROR_BLINK_COUNT 3
|
||||
#define ERROR_PAUSE_MS 1000
|
||||
|
||||
/*==============================================================================
|
||||
* Pattern table (for simple blink)
|
||||
*============================================================================*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t on_ms; /* LED on duration (ms) */
|
||||
uint32_t off_ms; /* LED off duration (ms) */
|
||||
uint8_t color; /* COLOR_GREEN or COLOR_ORANGE */
|
||||
bool repeat; /* true: repeat forever, false: once then OFF */
|
||||
} led_pattern_t;
|
||||
|
||||
static const led_pattern_t m_patterns[LED_STATE_COUNT] =
|
||||
{
|
||||
[LED_STATE_OFF] = { 0, 0, COLOR_NONE, false },
|
||||
[LED_STATE_POWER_ON] = { 2000, 0, COLOR_GREEN, false }, /* Green on 2s, stay on */
|
||||
[LED_STATE_POWER_OFF] = { 2000, 0, COLOR_GREEN, false }, /* Green on 2s, then OFF */
|
||||
[LED_STATE_ADVERTISING] = { 500, 500, COLOR_GREEN, true }, /* Green blink 1s interval */
|
||||
[LED_STATE_DETACH_WARNING] = { 1000, 3000, COLOR_GREEN, true }, /* Green 1s on / 3s off */
|
||||
[LED_STATE_ALIGN_SEARCHING] = { 1000, 1000, COLOR_ORANGE, true }, /* Orange blink 1s interval */
|
||||
[LED_STATE_ALIGN_COMPLETE] = { 3000, 1000, COLOR_GREEN, true }, /* Green 3s on / 1s off */
|
||||
[LED_STATE_ERROR] = { 0, 0, COLOR_ORANGE, true } /* Separate state machine */
|
||||
};
|
||||
|
||||
/*==============================================================================
|
||||
* Module variables
|
||||
*============================================================================*/
|
||||
APP_TIMER_DEF(m_led_timer);
|
||||
|
||||
static led_state_t m_current_state = LED_STATE_OFF;
|
||||
static bool m_phase_on; /* true: LED on phase, false: off phase */
|
||||
|
||||
/* Error pattern only */
|
||||
static uint8_t m_error_blink_cnt; /* Blink count so far */
|
||||
static uint8_t m_error_phase; /* 0: blink-on, 1: blink-off, 2: pause */
|
||||
|
||||
/*==============================================================================
|
||||
* GPIO helpers
|
||||
*============================================================================*/
|
||||
|
||||
static inline void led_green_on(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_clear(LED_PIN_GREEN);
|
||||
#else
|
||||
nrf_gpio_pin_set(LED_PIN_GREEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_green_off(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_set(LED_PIN_GREEN);
|
||||
#else
|
||||
nrf_gpio_pin_clear(LED_PIN_GREEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_orange_on(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_clear(LED_PIN_ORANGE);
|
||||
#else
|
||||
nrf_gpio_pin_set(LED_PIN_ORANGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void led_orange_off(void)
|
||||
{
|
||||
#if LED_ACTIVE_LOW
|
||||
nrf_gpio_pin_set(LED_PIN_ORANGE);
|
||||
#else
|
||||
nrf_gpio_pin_clear(LED_PIN_ORANGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void led_all_off(void)
|
||||
{
|
||||
led_green_off();
|
||||
led_orange_off();
|
||||
}
|
||||
|
||||
static void led_color_on(uint8_t color)
|
||||
{
|
||||
led_all_off();
|
||||
if (color == COLOR_GREEN) led_green_on();
|
||||
else if (color == COLOR_ORANGE) led_orange_on();
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Timer start helper
|
||||
*============================================================================*/
|
||||
static void timer_start_ms(uint32_t ms)
|
||||
{
|
||||
if (ms == 0) return;
|
||||
app_timer_start(m_led_timer, MS_TO_TICKS(ms), NULL);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Error pattern state machine (No.7)
|
||||
* phase 0: LED ON (166ms) → phase 1
|
||||
* phase 1: LED OFF (166ms) → cnt++ → cnt<3 ? phase 0 : phase 2
|
||||
* phase 2: PAUSE (1000ms) → cnt=0, phase 0
|
||||
*============================================================================*/
|
||||
static void error_pattern_start(void)
|
||||
{
|
||||
m_error_blink_cnt = 0;
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
}
|
||||
|
||||
static void error_pattern_tick(void)
|
||||
{
|
||||
switch (m_error_phase)
|
||||
{
|
||||
case 0: /* ON phase done -> OFF */
|
||||
led_all_off();
|
||||
m_error_phase = 1;
|
||||
timer_start_ms(ERROR_BLINK_OFF_MS);
|
||||
break;
|
||||
|
||||
case 1: /* OFF phase done */
|
||||
m_error_blink_cnt++;
|
||||
if (m_error_blink_cnt < ERROR_BLINK_COUNT)
|
||||
{
|
||||
/* Back to ON */
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3 blinks done -> pause */
|
||||
m_error_phase = 2;
|
||||
timer_start_ms(ERROR_PAUSE_MS);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* Pause done -> restart */
|
||||
m_error_blink_cnt = 0;
|
||||
m_error_phase = 0;
|
||||
led_color_on(COLOR_ORANGE);
|
||||
timer_start_ms(ERROR_BLINK_ON_MS);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Timer callback
|
||||
*============================================================================*/
|
||||
static void led_timer_handler(void * p_context)
|
||||
{
|
||||
(void)p_context;
|
||||
|
||||
/* Error state handled separately */
|
||||
if (m_current_state == LED_STATE_ERROR)
|
||||
{
|
||||
error_pattern_tick();
|
||||
return;
|
||||
}
|
||||
|
||||
const led_pattern_t * p = &m_patterns[m_current_state];
|
||||
|
||||
if (m_phase_on)
|
||||
{
|
||||
/* ON -> OFF transition */
|
||||
led_all_off();
|
||||
m_phase_on = false;
|
||||
|
||||
if (p->off_ms > 0)
|
||||
{
|
||||
timer_start_ms(p->off_ms);
|
||||
}
|
||||
else if (!p->repeat)
|
||||
{
|
||||
/* One-shot: if off_ms == 0, stay on (POWER_ON) or turn off (POWER_OFF) */
|
||||
if (m_current_state == LED_STATE_POWER_OFF)
|
||||
{
|
||||
led_all_off();
|
||||
m_current_state = LED_STATE_OFF;
|
||||
}
|
||||
/* POWER_ON: stay lit, no timer */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OFF -> ON transition */
|
||||
if (p->repeat)
|
||||
{
|
||||
led_color_on(p->color);
|
||||
m_phase_on = true;
|
||||
timer_start_ms(p->on_ms);
|
||||
}
|
||||
/* No current case where repeat == false && off_ms > 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Public functions
|
||||
*============================================================================*/
|
||||
|
||||
void led_init(void)
|
||||
{
|
||||
/* Configure GPIO outputs */
|
||||
nrf_gpio_cfg_output(LED_PIN_GREEN);
|
||||
nrf_gpio_cfg_output(LED_PIN_ORANGE);
|
||||
led_all_off();
|
||||
|
||||
/* Create timer (single-shot) */
|
||||
app_timer_create(&m_led_timer, APP_TIMER_MODE_SINGLE_SHOT, led_timer_handler);
|
||||
|
||||
m_current_state = LED_STATE_OFF;
|
||||
}
|
||||
|
||||
void led_set_state(led_state_t state)
|
||||
{
|
||||
if (state >= LED_STATE_COUNT) return;
|
||||
|
||||
/* Stop previous pattern */
|
||||
app_timer_stop(m_led_timer);
|
||||
led_all_off();
|
||||
|
||||
m_current_state = state;
|
||||
m_phase_on = false;
|
||||
|
||||
const led_pattern_t * p = &m_patterns[state];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case LED_STATE_OFF:
|
||||
/* Already all off */
|
||||
break;
|
||||
|
||||
/* Error pattern: separate state machine */
|
||||
case LED_STATE_ERROR:
|
||||
error_pattern_start();
|
||||
break;
|
||||
|
||||
/* All others: start from ON phase */
|
||||
default:
|
||||
led_color_on(p->color);
|
||||
m_phase_on = true;
|
||||
if (p->on_ms > 0)
|
||||
{
|
||||
timer_start_ms(p->on_ms);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
led_state_t led_get_state(void)
|
||||
{
|
||||
return m_current_state;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* @file led_control.h
|
||||
* @brief Direct LED control driver
|
||||
* @date 2026-03-30
|
||||
*
|
||||
* Controls dual-color LED green(P0.12) + orange(P0.29) via app_timer.
|
||||
* On/off timing, color, and repeat pattern managed per state in a table.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LED_CONTROL_H__
|
||||
#define LED_CONTROL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*==============================================================================
|
||||
* LED pin definitions
|
||||
*============================================================================*/
|
||||
#define LED_PIN_GREEN NRF_GPIO_PIN_MAP(0, 12) /* Green LED */
|
||||
#define LED_PIN_ORANGE NRF_GPIO_PIN_MAP(0, 29) /* Orange LED */
|
||||
#define LED_ACTIVE_LOW 1 /* 1 = Active Low (LED on when GPIO LOW) */
|
||||
|
||||
/*==============================================================================
|
||||
* LED state enumeration
|
||||
*============================================================================*/
|
||||
typedef enum
|
||||
{
|
||||
LED_STATE_OFF = 0, /* All LEDs off */
|
||||
LED_STATE_POWER_ON, /* 1: Power ON - green on 2s */
|
||||
LED_STATE_POWER_OFF, /* 2: Power OFF - green on 2s then off */
|
||||
LED_STATE_ADVERTISING, /* 3: BLE advertising - green blink 1s interval (repeat) */
|
||||
LED_STATE_DETACH_WARNING, /* 4: Normal operation (detached) - green 1s on / 3s off (repeat) */
|
||||
LED_STATE_ALIGN_SEARCHING, /* 5: Alignment mode (searching) - orange blink 1s interval (repeat) */
|
||||
LED_STATE_ALIGN_COMPLETE, /* 6: Alignment mode (complete) - green 3s on / 1s off */
|
||||
LED_STATE_ERROR, /* 7: Error - orange 3Hz blink x3 / off 1s (repeat) */
|
||||
LED_STATE_COUNT /* Array size */
|
||||
} led_state_t;
|
||||
|
||||
/*==============================================================================
|
||||
* Public functions
|
||||
*============================================================================*/
|
||||
|
||||
/** @brief Initialize LED GPIO + create timer - call once from main() */
|
||||
void led_init(void);
|
||||
|
||||
/** @brief Change LED state - immediately stops previous pattern and starts new one */
|
||||
void led_set_state(led_state_t state);
|
||||
|
||||
/** @brief Get current LED state */
|
||||
led_state_t led_get_state(void);
|
||||
|
||||
#endif /* LED_CONTROL_H__ */
|
||||
@@ -0,0 +1,288 @@
|
||||
/*******************************************************************************
|
||||
TEST medi50 Dec 23
|
||||
*******************************************************************************
|
||||
*
|
||||
* [Module overview]
|
||||
* Main event loop timer module (10ms interval, single-shot mode).
|
||||
*
|
||||
* Dispatches sensor data collection and system control events via flags.
|
||||
* Uses app_timer single-shot mode; after processing, call main_timer_start()
|
||||
* manually to restart if needed.
|
||||
*
|
||||
* [Event flags and processing order]
|
||||
* motion_raw_data_enabled -> IMU data read (calls icm42670_main)
|
||||
* - motion_data_once == true: one-shot read (after HW I2C init)
|
||||
* - motion_data_once == false: continuous read (when not waiting for BLE TX)
|
||||
* go_batt -> Battery voltage measurement (battery_level_meas)
|
||||
* go_temp -> Temperature measurement (tmp235_voltage_level_meas)
|
||||
* go_device_power_off -> Device power OFF (device_power_off)
|
||||
* go_sleep_mode_enter -> Enter sleep mode (sleep_mode_enter)
|
||||
* go_NVIC_SystemReset -> NVIC system reset
|
||||
*
|
||||
* [info4 mode measurement order]
|
||||
* IMU continuous read -> go_batt (battery) -> go_temp (temp) -> motion_data_once (IMU one-shot)
|
||||
* After temperature measurement, motion_data_once=true to return to IMU.
|
||||
*
|
||||
* [Timer settings]
|
||||
* - Normal mode: 10ms interval (MAIN_LOOP_INTERVAL)
|
||||
* - FEATURE_DETAIL_VALUE_FULL mode: 80ms interval (for detail printout)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#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 removed, use main.h */
|
||||
#include "debug_print.h"
|
||||
#include "i2c_manager.h" //add cj
|
||||
|
||||
/* Main loop single-shot timer instance */
|
||||
APP_TIMER_DEF(m_main_loop_timer_id);
|
||||
|
||||
#if FEATURE_DETAIL_VALUE_FULL
|
||||
/* Detail printout mode: run main loop at 80ms interval */
|
||||
#define MAIN_LOOP_INTERVAL 80 /* Timer for Full_Mode main processing when detail printout is enabled */
|
||||
|
||||
//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
|
||||
/* Normal mode: run main loop at 10ms interval */
|
||||
#define MAIN_LOOP_INTERVAL 10
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* Event flags (set by external modules, processed in main_loop) */
|
||||
/* ========================================================================== */
|
||||
bool go_batt= false; /* Battery measurement request flag */
|
||||
bool go_temp= false; /* Temperature measurement request flag */
|
||||
bool go_device_power_off = false; /* Device power OFF request flag */
|
||||
bool go_sleep_mode_enter = false; /* Sleep mode entry request flag */
|
||||
bool go_NVIC_SystemReset = false; /* System reset request flag */
|
||||
bool motion_raw_data_enabled = false; /* IMU motion data read enable flag */
|
||||
bool ble_got_new_data = false; /* BLE new data transmission complete */
|
||||
bool motion_data_once = false; /* IMU one-shot read mode (true: read once) */
|
||||
|
||||
/**
|
||||
* @brief Main event loop (single-shot timer callback)
|
||||
*
|
||||
* Flag-based event dispatcher; processes actions based on set flags.
|
||||
* Since the timer is single-shot, call main_timer_start() again from
|
||||
* within the handler to continue execution.
|
||||
*
|
||||
* [Processing priority] (checked in code order)
|
||||
* 1. IMU motion data (motion_raw_data_enabled)
|
||||
* 2. Battery measurement (go_batt)
|
||||
* 3. Temperature measurement (go_temp)
|
||||
* 4. Power OFF (go_device_power_off)
|
||||
* 5. Sleep mode (go_sleep_mode_enter)
|
||||
* 6. System reset (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 data read ---- */
|
||||
/*
|
||||
* If motion_raw_data_enabled is true, read IMU (ICM42670P) data.
|
||||
*
|
||||
* motion_data_once == true:
|
||||
* One-shot read mode. Initialize HW I2C then call icm42670_main() once.
|
||||
* Used in info4 mode to return to IMU after battery/temp measurement.
|
||||
*
|
||||
* motion_data_once == false:
|
||||
* Continuous read mode. If not waiting for BLE TX (ble_got_new_data==false),
|
||||
* call icm42670_main() and restart timer after 10ms for repeated execution.
|
||||
*/
|
||||
if (motion_raw_data_enabled == true)
|
||||
{
|
||||
main_timer_stop(); /* Stop timer (prevent re-entry) */
|
||||
if (motion_data_once == true)
|
||||
{
|
||||
/* One-shot mode: init HW I2C then read IMU data once */
|
||||
hw_i2c_init_once(); /* Switch to HW TWI mode (400kHz) */
|
||||
icm42670_main(); /* Read and process IMU data */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Continuous mode: repeat read if not waiting for BLE TX */
|
||||
if (ble_got_new_data==false)
|
||||
{
|
||||
//for(uint16_t i=0 ; i<60 ;i++)
|
||||
//{
|
||||
DBG_PRINTF("IMU \r\n");
|
||||
|
||||
icm42670_main(); /* Read IMU data */
|
||||
motion_raw_data_enabled = true; /* Keep flag set (continuous read) */
|
||||
main_timer_start_ms(1000); /* Next IMU read after 1s */
|
||||
}
|
||||
// else if(ble_got_new_data==true){
|
||||
// motion_data_once = true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---- Battery voltage measurement ---- */
|
||||
/*
|
||||
* If go_batt is true, measure battery level.
|
||||
* Called after IMU continuous read in info4 mode.
|
||||
* Timer remains stopped after measurement.
|
||||
*/
|
||||
if (go_batt == true)
|
||||
{
|
||||
DBG_PRINTF("IMU BATT\r\n");
|
||||
main_timer_stop(); /* Stop timer */
|
||||
go_batt = false; /* Consume flag (one-shot) */
|
||||
// go_temp = true;
|
||||
battery_level_meas(); /* Measure battery voltage via SAADC */
|
||||
// nrf_delay_ms(20);
|
||||
// m48_adc_start_init();
|
||||
// main_timer_start();
|
||||
}
|
||||
|
||||
|
||||
/* ---- Temperature measurement ---- */
|
||||
/*
|
||||
* If go_temp is true, measure temperature via TMP235-Q1 sensor.
|
||||
* Called after battery measurement in info4 mode.
|
||||
* After completion, sets motion_data_once=true so the next IMU read
|
||||
* uses one-shot mode (with HW I2C re-init).
|
||||
*/
|
||||
if (go_temp == true)
|
||||
{
|
||||
DBG_PRINTF("IMU Temp\r\n");
|
||||
main_timer_stop(); /* Stop timer */
|
||||
// go_batt = false;
|
||||
go_temp = false; /* Consume flag (one-shot) */
|
||||
motion_data_once = true; /* Switch next IMU read to one-shot mode */
|
||||
tmp235_voltage_level_meas(); /* Measure TMP235-Q1 temperature sensor voltage */
|
||||
// motion_raw_data_enabled = true;
|
||||
// main_timer_start();
|
||||
|
||||
}
|
||||
|
||||
/* ---- System control event handling ---- */
|
||||
|
||||
/* Device power OFF handling */
|
||||
if (go_device_power_off == true)
|
||||
{
|
||||
main_timer_stop(); /* Stop timer */
|
||||
DBG_PRINTF("Off main_timer\r\n");
|
||||
device_power_off(); /* Execute device power OFF */
|
||||
}
|
||||
|
||||
/* Sleep mode entry handling */
|
||||
if (go_sleep_mode_enter == true)
|
||||
{
|
||||
main_timer_stop(); /* Stop timer */
|
||||
DBG_PRINTF("sleep main timer\r\n");
|
||||
sleep_mode_enter(); /* Execute sleep mode entry */
|
||||
}
|
||||
|
||||
/* NVIC system reset handling */
|
||||
if (go_NVIC_SystemReset == true)
|
||||
{
|
||||
main_timer_stop(); /* Stop timer */
|
||||
NVIC_SystemReset(); /* ARM Cortex-M4 system reset */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start main loop timer
|
||||
*
|
||||
* Single-shot mode; calls main_loop() after MAIN_LOOP_INTERVAL (10ms or 80ms)
|
||||
*/
|
||||
void main_timer_start(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_start(m_main_loop_timer_id, APP_TIMER_TICKS(MAIN_LOOP_INTERVAL), NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start main loop timer with specified interval (ms)
|
||||
*
|
||||
* Used when a different period than the default is needed (e.g. IMU streaming)
|
||||
*/
|
||||
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 Stop main loop timer
|
||||
*/
|
||||
void main_timer_stop(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_stop(m_main_loop_timer_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize main loop timer (call once at app startup)
|
||||
*
|
||||
* Creates a single-shot timer with main_loop() as callback.
|
||||
* Must manually restart via main_timer_start() after each firing.
|
||||
*/
|
||||
void main_timer_init(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_create(&m_main_loop_timer_id, APP_TIMER_MODE_SINGLE_SHOT, main_loop));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
* @file timer_routine.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
*******************************************************************************
|
||||
*
|
||||
* [Header overview]
|
||||
* Public interface header for the main event loop timer.
|
||||
*
|
||||
* Uses a single-shot timer at 10ms (normal) or 80ms (detail) interval.
|
||||
* The main_loop() callback handles sensor data collection and system control.
|
||||
*
|
||||
* [Key functions]
|
||||
* main_timer_start() : Start timer (single-shot, manual restart required)
|
||||
* main_timer_stop() : Stop timer
|
||||
* main_timer_init() : Initialize timer (call once at app startup)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef TIMER_ROUTINE_H__
|
||||
#define TIMER_ROUTINE_H__
|
||||
|
||||
/** @brief Start main loop timer (single-shot, calls main_loop after MAIN_LOOP_INTERVAL) */
|
||||
void main_timer_start(void);
|
||||
|
||||
/** @brief Start main loop timer with specified interval (ms) */
|
||||
void main_timer_start_ms(uint32_t interval_ms);
|
||||
|
||||
/** @brief Stop main loop timer */
|
||||
void main_timer_stop(void);
|
||||
|
||||
/** @brief Initialize main loop timer (call once at startup, creates single-shot timer) */
|
||||
void main_timer_init(void);
|
||||
|
||||
#endif //TIMER_ROUTINE_H__
|
||||
@@ -0,0 +1,188 @@
|
||||
/*******************************************************************************
|
||||
TEST medi50 Dec 23
|
||||
//=========power_control.c====================
|
||||
*******************************************************************************
|
||||
*
|
||||
* [Module overview]
|
||||
* Device power sequence manager (power on / off / sleep).
|
||||
*
|
||||
* [Power-on flow]
|
||||
* device_activated()
|
||||
* -> Start power_loop timer -> completes immediately (no sensor init needed)
|
||||
* -> Sensor (IMU) is handled by imu_read_direct() at measurement time
|
||||
*
|
||||
* [Sleep mode]
|
||||
* device_sleep_mode()
|
||||
* -> Clear processing flag
|
||||
*
|
||||
* [Reactivation]
|
||||
* device_reactivated()
|
||||
* -> Re-init I2C then restart power sequence from the beginning
|
||||
*
|
||||
* [Timer]
|
||||
* Single-shot app_timer, calls power_loop at 20ms interval
|
||||
*
|
||||
******************************************************************************/
|
||||
#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"
|
||||
|
||||
|
||||
/* Single-shot timer instance for power sequence */
|
||||
APP_TIMER_DEF(m_power_timer_id);
|
||||
|
||||
/* Power sequence state machine timer interval (20ms) */
|
||||
// 2025-12-08 change to #define POWER_LOOP_INTERVAL 30 -> 20
|
||||
#define POWER_LOOP_INTERVAL 20
|
||||
|
||||
/* Power sequence current step (0: I2C init, 1: reserved, 2: complete) */
|
||||
static uint8_t p_order;
|
||||
|
||||
/* Power sequence lock flag (true = sequence in progress) */
|
||||
bool lock_check = false;
|
||||
|
||||
/**
|
||||
* @brief Enter device sleep mode
|
||||
*
|
||||
* @return 0 (always succeeds)
|
||||
*/
|
||||
int device_sleep_mode(void)
|
||||
{
|
||||
int rc = 0;
|
||||
nrf_delay_ms(2);
|
||||
DBG_PRINTF("Device_Sleep_Mode OK!\r\n");
|
||||
nrf_delay_ms(10);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Power on device (start power sequence)
|
||||
*
|
||||
* Resets the sequence step to 0, sets the lock flag, and starts
|
||||
* the timer to drive the power_loop() state machine.
|
||||
*
|
||||
* @return 0 (always succeeds)
|
||||
*/
|
||||
int device_activated(void)
|
||||
{
|
||||
int rc = 0;
|
||||
p_order = 0; /* State machine start step (Step 0: I2C init) */
|
||||
lock_check =true; /* Lock: power sequence in progress */
|
||||
power_timer_start(); /* First power_loop() call after 20ms */
|
||||
|
||||
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
|
||||
*/
|
||||
/*
|
||||
* Power sequence state machine (20ms single-shot timer callback).
|
||||
*
|
||||
* [Execution flow]
|
||||
* 1) Timer callback entry -> stop timer (single-shot)
|
||||
* 2) Execute init step for current p_order
|
||||
* 3) If p_order < 2, advance to next step and restart timer
|
||||
* 4) If p_order == 2, power sequence complete
|
||||
*
|
||||
* No sensor init needed -- imu_read_direct() handles it per measurement.
|
||||
*/
|
||||
void power_loop(void *p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
power_timer_stop(); /* Stop current timer (single-shot, manual restart needed) */
|
||||
|
||||
/* No sensor init needed -- imu_read_direct() handles it per measurement */
|
||||
/* Add switch(p_order) here if future power sequence steps are needed */
|
||||
p_order = 2;
|
||||
|
||||
/* Advance to next step or finish */
|
||||
/* Advance to next step or finish sequence */
|
||||
if (p_order < 2)
|
||||
{
|
||||
p_order++; /* Move to next step */
|
||||
power_timer_start(); /* Execute next step after 20ms */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Power sequence fully complete */
|
||||
DBG_PRINTF("[PWR] Device Activated OK!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reactivate device (on wake from sleep)
|
||||
*
|
||||
* Re-initializes I2C and restarts the power sequence from the beginning.
|
||||
* Called when waking from sleep mode.
|
||||
*
|
||||
* @return 0 (always succeeds)
|
||||
*/
|
||||
int device_reactivated(void)
|
||||
{
|
||||
int rc = 0;
|
||||
sw_i2c_init_once(); /* Re-initialize I2C bus */
|
||||
nrf_delay_ms(10); /* Stabilization delay */
|
||||
lock_check = true; /* Lock: power sequence in progress */
|
||||
p_order = 0; /* Restart state machine from Step 0 */
|
||||
power_timer_start(); /* Start power_loop() after 20ms */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start power sequence timer
|
||||
*
|
||||
* Single-shot mode; calls power_loop() after POWER_LOOP_INTERVAL (20ms).
|
||||
*/
|
||||
void power_timer_start(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_start(m_power_timer_id, APP_TIMER_TICKS(POWER_LOOP_INTERVAL), NULL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop power sequence timer
|
||||
*/
|
||||
void power_timer_stop(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_stop(m_power_timer_id));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize power sequence timer (call once at app startup)
|
||||
*
|
||||
* Creates a single-shot timer with power_loop() as callback.
|
||||
* Must manually restart via power_timer_start() after each step.
|
||||
*/
|
||||
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));
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
* @file power_control.h
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
*******************************************************************************
|
||||
*
|
||||
* [Header overview]
|
||||
* Public interface header for the device power sequence manager.
|
||||
*
|
||||
* [Key functions]
|
||||
* device_activated() : Power on -> start power_loop state machine
|
||||
* device_sleep_mode() : Enter sleep mode (stop processing)
|
||||
* device_reactivated() : Wake from sleep -> restart power sequence
|
||||
* power_loop() : 20ms power sequence state machine callback
|
||||
* power_timer_start/stop : Power sequence timer control
|
||||
* power_timer_init() : Initialize power sequence timer (call once at startup)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _POWER_CONTROL_H_
|
||||
#define _POWER_CONTROL_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/** @brief Enter device sleep mode (clears processing flag) */
|
||||
int device_sleep_mode(void);
|
||||
|
||||
/** @brief Power on device (start power sequence state machine) */
|
||||
int device_activated(void);
|
||||
|
||||
/** @brief Reactivate device (re-init I2C and restart sequence on wake from sleep) */
|
||||
int device_reactivated(void);
|
||||
|
||||
/** @brief Power sequence state machine (20ms timer callback, Step 0->1->2) */
|
||||
void power_loop(void * p_context); /* For x ms */
|
||||
|
||||
/** @brief Start power sequence timer (20ms single-shot) */
|
||||
void power_timer_start(void);
|
||||
|
||||
/** @brief Stop power sequence timer */
|
||||
void power_timer_stop(void);;
|
||||
|
||||
/** @brief Initialize power sequence timer (call once at app startup) */
|
||||
void power_timer_init(void);
|
||||
#endif //_POWER_CONTROL_H_
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @file ble_quick_security.c
|
||||
* @brief Ultra-simple BLE Security Configuration Implementation
|
||||
*
|
||||
* Compatible with existing debug_print.h system.
|
||||
*/
|
||||
|
||||
#include "ble_quick_security.h"
|
||||
#include "peer_manager_handler.h"
|
||||
#include "nrf_ble_lesc.h"
|
||||
#include "app_error.h"
|
||||
#include <string.h>
|
||||
|
||||
// Use existing debug system
|
||||
#include "debug_print.h"
|
||||
|
||||
// Module state
|
||||
static struct {
|
||||
bool dev_mode;
|
||||
bool bonds_delete_pending;
|
||||
} m_state = {0};
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE security
|
||||
*/
|
||||
void ble_security_quick_init(bool development_mode)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
ble_gap_sec_params_t sec_params;
|
||||
|
||||
// Save mode
|
||||
m_state.dev_mode = development_mode;
|
||||
m_state.bonds_delete_pending = false;
|
||||
|
||||
// Initialize Peer Manager FIRST
|
||||
err_code = pm_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Initialize LESC module (ECDH P-256 key pair generation)
|
||||
err_code = nrf_ble_lesc_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Configure security parameters
|
||||
memset(&sec_params, 0, sizeof(ble_gap_sec_params_t));
|
||||
|
||||
if (development_mode) {
|
||||
// ===== DEVELOPMENT MODE: No security =====
|
||||
sec_params.bond = 0; // No bonding
|
||||
sec_params.mitm = 0; // No MITM
|
||||
sec_params.lesc = 0; // No LESC
|
||||
sec_params.keypress = 0;
|
||||
sec_params.io_caps = BLE_GAP_IO_CAPS_NONE; // No passkey
|
||||
sec_params.oob = 0;
|
||||
sec_params.min_key_size = 7;
|
||||
sec_params.max_key_size = 16;
|
||||
|
||||
DBG_PRINTF("DEV MODE: Security DISABLED - Fast connection\r\n");
|
||||
|
||||
// Delete all bonds (async)
|
||||
err_code = pm_peers_delete();
|
||||
if (err_code == NRF_SUCCESS) {
|
||||
m_state.bonds_delete_pending = true;
|
||||
DBG_PRINTF("DEV MODE: Deleting all bonds...\r\n");
|
||||
}
|
||||
} else {
|
||||
// ===== PRODUCTION MODE: Full security =====
|
||||
sec_params.bond = 1; // Enable bonding
|
||||
sec_params.mitm = 1; // Enable MITM
|
||||
sec_params.lesc = 1; // LE Secure Connections (ECDH P-256)
|
||||
sec_params.keypress = 0;
|
||||
sec_params.io_caps = BLE_GAP_IO_CAPS_DISPLAY_ONLY; // Show passkey
|
||||
sec_params.oob = 0;
|
||||
sec_params.min_key_size = 7;
|
||||
sec_params.max_key_size = 16;
|
||||
sec_params.kdist_own.enc = 1;
|
||||
sec_params.kdist_own.id = 1;
|
||||
sec_params.kdist_peer.enc = 1;
|
||||
sec_params.kdist_peer.id = 1;
|
||||
|
||||
DBG_PRINTF("PROD MODE: Security ENABLED - Full protection\r\n");
|
||||
}
|
||||
|
||||
// Apply security parameters
|
||||
err_code = pm_sec_params_set(&sec_params);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current mode
|
||||
*/
|
||||
bool ble_security_is_dev_mode(void)
|
||||
{
|
||||
return m_state.dev_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PM event handler
|
||||
*/
|
||||
void ble_security_quick_pm_handler(pm_evt_t const *p_evt)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
|
||||
// DEV mode: do not forward security failure events to SDK handler (prevent disconnect)
|
||||
if (m_state.dev_mode && p_evt->evt_id == PM_EVT_CONN_SEC_FAILED) {
|
||||
DBG_PRINTF("Security failed: error=%d\r\n",
|
||||
p_evt->params.conn_sec_failed.error);
|
||||
DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Call standard handlers (required)
|
||||
pm_handler_on_pm_evt(p_evt);
|
||||
pm_handler_flash_clean(p_evt);
|
||||
|
||||
// Handle events
|
||||
switch (p_evt->evt_id) {
|
||||
case PM_EVT_CONN_SEC_SUCCEEDED:
|
||||
if (m_state.dev_mode) {
|
||||
DBG_PRINTF("DEV: Connected (no security)\r\n");
|
||||
} else {
|
||||
pm_conn_sec_status_t status;
|
||||
if (pm_conn_sec_status_get(p_evt->conn_handle, &status) == NRF_SUCCESS) {
|
||||
DBG_PRINTF("PROD: Link secured - LESC=%d MITM=%d bonded=%d\r\n",
|
||||
status.lesc, status.mitm_protected, status.bonded);
|
||||
} else {
|
||||
DBG_PRINTF("PROD: Link secured (bonded)\r\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_FAILED:
|
||||
DBG_PRINTF("Security failed: error=%d\r\n",
|
||||
p_evt->params.conn_sec_failed.error);
|
||||
|
||||
if (m_state.dev_mode) {
|
||||
// DEV mode: ignore security failure, keep connection
|
||||
DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING) {
|
||||
// Key missing: attempt re-pairing, fall back to disconnect on failure
|
||||
err_code = pm_conn_secure(p_evt->conn_handle, true);
|
||||
if (err_code != NRF_ERROR_INVALID_STATE &&
|
||||
err_code != NRF_ERROR_BUSY &&
|
||||
err_code != BLE_ERROR_INVALID_CONN_HANDLE) {
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
// Re-pairing not possible -> disconnect
|
||||
pm_handler_disconnect_on_sec_failure(p_evt);
|
||||
}
|
||||
} else {
|
||||
// Other security failure -> delete bond then attempt re-pairing
|
||||
pm_peer_id_t peer_id;
|
||||
if (pm_peer_id_get(p_evt->conn_handle, &peer_id) == NRF_SUCCESS
|
||||
&& peer_id != PM_PEER_ID_INVALID) {
|
||||
pm_peer_delete(peer_id);
|
||||
}
|
||||
err_code = pm_conn_secure(p_evt->conn_handle, true);
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
pm_handler_disconnect_on_sec_failure(p_evt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_CONN_SEC_CONFIG_REQ:
|
||||
{
|
||||
pm_conn_sec_config_t config = {
|
||||
.allow_repairing = true
|
||||
};
|
||||
pm_conn_sec_config_reply(p_evt->conn_handle, &config);
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EVT_PEERS_DELETE_SUCCEEDED:
|
||||
if (m_state.bonds_delete_pending) {
|
||||
m_state.bonds_delete_pending = false;
|
||||
DBG_PRINTF("DEV MODE: Bonds cleared!\r\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file ble_quick_security.h
|
||||
* @brief Ultra-simple BLE Security Configuration
|
||||
*
|
||||
* ONE function call to control entire security behavior.
|
||||
* Works with existing debug_print.h system.
|
||||
*/
|
||||
|
||||
#ifndef BLE_QUICK_SECURITY_H
|
||||
#define BLE_QUICK_SECURITY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "peer_manager.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE security with ONE simple parameter
|
||||
*
|
||||
* @param[in] development_mode true (1) = Fast development (no security)
|
||||
* false (0) = Production (full security)
|
||||
*
|
||||
* Development mode (1):
|
||||
* - No pairing/bonding required
|
||||
* - Auto-deletes all bonds on startup
|
||||
* - Instant connection
|
||||
* - Fast iteration
|
||||
*
|
||||
* Production mode (0):
|
||||
* - Full security with passkey
|
||||
* - Bonding preserved
|
||||
* - MITM protection
|
||||
* - Secure deployment
|
||||
*
|
||||
* Usage in main.c:
|
||||
* #define BLE_DEV_MODE 1 // or 0
|
||||
* ble_security_quick_init(BLE_DEV_MODE);
|
||||
*/
|
||||
void ble_security_quick_init(bool development_mode);
|
||||
|
||||
/**
|
||||
* @brief Get current mode
|
||||
* @return true if in development mode, false if production
|
||||
*/
|
||||
bool ble_security_is_dev_mode(void);
|
||||
|
||||
/**
|
||||
* @brief Peer Manager event handler
|
||||
*
|
||||
* Call this from your pm_evt_handler() function.
|
||||
* It handles all security events automatically.
|
||||
*
|
||||
* @param[in] p_evt Peer Manager event
|
||||
*/
|
||||
void ble_security_quick_pm_handler(pm_evt_t const *p_evt);
|
||||
|
||||
#endif // BLE_QUICK_SECURITY_H
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
/* This file was automatically generated by nrfutil on 2022-09-06 (YY-MM-DD) at 15:11:25 */
|
||||
|
||||
#include "stdint.h"
|
||||
#include "compiler_abstraction.h"
|
||||
|
||||
/** @brief Public key used to verify DFU images */
|
||||
__ALIGN(4) const uint8_t pk[64] =
|
||||
{
|
||||
0x67, 0x5b, 0xcb, 0x03, 0xe5, 0x70, 0x6a, 0x83, 0x6c, 0x5e, 0x17, 0xbc, 0x81, 0x20, 0x27, 0xdc, 0x76, 0x6b, 0xae, 0x9b, 0x89, 0x72, 0x1a, 0x28, 0x31, 0x2a, 0x9b, 0x35, 0xbe, 0x1a, 0x90, 0xd5,
|
||||
0xec, 0x4b, 0x24, 0x39, 0xb5, 0x79, 0x5f, 0x5a, 0xd7, 0x3b, 0xd8, 0x86, 0xa7, 0x80, 0xa9, 0x2d, 0xc4, 0xf6, 0xd6, 0x03, 0xa0, 0xe6, 0xd8, 0xc7, 0x03, 0x3e, 0x28, 0xe2, 0x76, 0x08, 0x88, 0xfa
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
/*******************************************************************************
|
||||
* @file main.c
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "boards.h"
|
||||
#include "nrf_mbr.h"
|
||||
#include "nrf_bootloader.h"
|
||||
#include "nrf_bootloader_app_start.h"
|
||||
#include "nrf_bootloader_dfu_timers.h"
|
||||
#include "nrf_dfu.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
#include "app_error.h"
|
||||
#include "app_error_weak.h"
|
||||
#include "nrf_bootloader_info.h"
|
||||
#include "nrf_delay.h"
|
||||
|
||||
#define POWER_HOLD NRF_GPIO_PIN_MAP(0,8) // power hold port for medithings device
|
||||
|
||||
static void on_error(void)
|
||||
{
|
||||
NRF_LOG_FINAL_FLUSH();
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
|
||||
// To allow the buffer to be flushed by the host.
|
||||
nrf_delay_ms(100);
|
||||
#endif
|
||||
#ifdef NRF_DFU_DEBUG_VERSION
|
||||
NRF_BREAKPOINT_COND;
|
||||
#endif
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
|
||||
void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
|
||||
{
|
||||
NRF_LOG_ERROR("%s:%d", p_file_name, line_num);
|
||||
on_error();
|
||||
}
|
||||
|
||||
|
||||
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
|
||||
{
|
||||
NRF_LOG_ERROR("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id, pc, info);
|
||||
on_error();
|
||||
}
|
||||
|
||||
|
||||
void app_error_handler_bare(uint32_t error_code)
|
||||
{
|
||||
NRF_LOG_ERROR("Received an error: 0x%08x!", error_code);
|
||||
on_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function notifies certain events in DFU process.
|
||||
*/
|
||||
static void dfu_observer(nrf_dfu_evt_type_t evt_type)
|
||||
{
|
||||
switch (evt_type)
|
||||
{
|
||||
case NRF_DFU_EVT_DFU_FAILED:
|
||||
case NRF_DFU_EVT_DFU_ABORTED:
|
||||
case NRF_DFU_EVT_DFU_INITIALIZED:
|
||||
bsp_board_init(BSP_INIT_LEDS);
|
||||
bsp_board_led_on(BSP_BOARD_LED_0);
|
||||
break;
|
||||
case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
|
||||
bsp_board_led_on(BSP_BOARD_LED_0);
|
||||
break;
|
||||
case NRF_DFU_EVT_DFU_STARTED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for application main entry. */
|
||||
int main(void)
|
||||
{
|
||||
uint32_t ret_val;
|
||||
|
||||
nrf_gpio_cfg_output(POWER_HOLD);
|
||||
nrf_gpio_pin_set(POWER_HOLD); // The medithings device performs power hold when the power button is pressed for 3 seconds.
|
||||
// And then, The medithings device loads the bootloader.
|
||||
|
||||
// Must happen before flash protection is applied, since it edits a protected page.
|
||||
nrf_bootloader_mbr_addrs_populate();
|
||||
|
||||
// Protect MBR and bootloader code from being overwritten.
|
||||
ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE);
|
||||
APP_ERROR_CHECK(ret_val);
|
||||
ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE);
|
||||
APP_ERROR_CHECK(ret_val);
|
||||
|
||||
(void) NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
|
||||
NRF_LOG_DEFAULT_BACKENDS_INIT();
|
||||
|
||||
NRF_LOG_INFO("Inside main");
|
||||
|
||||
ret_val = nrf_bootloader_init(dfu_observer);
|
||||
APP_ERROR_CHECK(ret_val);
|
||||
|
||||
NRF_LOG_FLUSH();
|
||||
|
||||
NRF_LOG_ERROR("After main, should never be reached.");
|
||||
NRF_LOG_FLUSH();
|
||||
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef NRF_CRYPTO_ALLOCATOR_H__
|
||||
#define NRF_CRYPTO_ALLOCATOR_H__
|
||||
|
||||
#include "nrf_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Crypto library in bootloader case does not use dynamic allocation */
|
||||
#define NRF_CRYPTO_ALLOC(size) NULL; ASSERT(0)
|
||||
#define NRF_CRYPTO_ALLOC_ON_STACK(size) NULL; ASSERT(0)
|
||||
#define NRF_CRYPTO_FREE(ptr) (void)ptr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NRF_CRYPTO_ALLOCATOR_H__ */
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
; Copyright (c) 2009-2021 ARM Limited. All rights reserved.
|
||||
;
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
;
|
||||
; Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; not use this file except in compliance with the License.
|
||||
; You may obtain a copy of the License at
|
||||
;
|
||||
; www.apache.org/licenses/LICENSE-2.0
|
||||
;
|
||||
; Unless required by applicable law or agreed to in writing, software
|
||||
; distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; See the License for the specific language governing permissions and
|
||||
; limitations under the License.
|
||||
;
|
||||
; NOTICE: This file has been modified by Nordic Semiconductor ASA.
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
#ifdef __STARTUP_CONFIG
|
||||
#include "startup_config.h"
|
||||
#ifndef __STARTUP_CONFIG_STACK_ALIGNEMENT
|
||||
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3
|
||||
#endif
|
||||
#endif
|
||||
ENDIF
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Stack_Size EQU __STARTUP_CONFIG_STACK_SIZE
|
||||
ELIF :DEF: __STACK_SIZE
|
||||
Stack_Size EQU __STACK_SIZE
|
||||
ELSE
|
||||
Stack_Size EQU 16384
|
||||
ENDIF
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Stack_Align EQU __STARTUP_CONFIG_STACK_ALIGNEMENT
|
||||
ELSE
|
||||
Stack_Align EQU 3
|
||||
ENDIF
|
||||
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=Stack_Align
|
||||
Stack_Mem SPACE Stack_Size
|
||||
__initial_sp
|
||||
|
||||
IF :DEF: __STARTUP_CONFIG
|
||||
Heap_Size EQU __STARTUP_CONFIG_HEAP_SIZE
|
||||
ELIF :DEF: __HEAP_SIZE
|
||||
Heap_Size EQU __HEAP_SIZE
|
||||
ELSE
|
||||
Heap_Size EQU 16384
|
||||
ENDIF
|
||||
|
||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
; Vector Table Mapped to Address 0 at Reset
|
||||
|
||||
AREA RESET, DATA, READONLY
|
||||
EXPORT __Vectors
|
||||
EXPORT __Vectors_End
|
||||
EXPORT __Vectors_Size
|
||||
|
||||
__Vectors DCD __initial_sp ; Top of Stack
|
||||
DCD Reset_Handler
|
||||
DCD NMI_Handler
|
||||
DCD HardFault_Handler
|
||||
DCD MemoryManagement_Handler
|
||||
DCD BusFault_Handler
|
||||
DCD UsageFault_Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD SVC_Handler
|
||||
DCD DebugMon_Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD PendSV_Handler
|
||||
DCD SysTick_Handler
|
||||
|
||||
; External Interrupts
|
||||
DCD POWER_CLOCK_IRQHandler
|
||||
DCD RADIO_IRQHandler
|
||||
DCD UARTE0_UART0_IRQHandler
|
||||
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
|
||||
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
|
||||
DCD NFCT_IRQHandler
|
||||
DCD GPIOTE_IRQHandler
|
||||
DCD SAADC_IRQHandler
|
||||
DCD TIMER0_IRQHandler
|
||||
DCD TIMER1_IRQHandler
|
||||
DCD TIMER2_IRQHandler
|
||||
DCD RTC0_IRQHandler
|
||||
DCD TEMP_IRQHandler
|
||||
DCD RNG_IRQHandler
|
||||
DCD ECB_IRQHandler
|
||||
DCD CCM_AAR_IRQHandler
|
||||
DCD WDT_IRQHandler
|
||||
DCD RTC1_IRQHandler
|
||||
DCD QDEC_IRQHandler
|
||||
DCD COMP_LPCOMP_IRQHandler
|
||||
DCD SWI0_EGU0_IRQHandler
|
||||
DCD SWI1_EGU1_IRQHandler
|
||||
DCD SWI2_EGU2_IRQHandler
|
||||
DCD SWI3_EGU3_IRQHandler
|
||||
DCD SWI4_EGU4_IRQHandler
|
||||
DCD SWI5_EGU5_IRQHandler
|
||||
DCD TIMER3_IRQHandler
|
||||
DCD TIMER4_IRQHandler
|
||||
DCD PWM0_IRQHandler
|
||||
DCD PDM_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD MWU_IRQHandler
|
||||
DCD PWM1_IRQHandler
|
||||
DCD PWM2_IRQHandler
|
||||
DCD SPIM2_SPIS2_SPI2_IRQHandler
|
||||
DCD RTC2_IRQHandler
|
||||
DCD I2S_IRQHandler
|
||||
DCD FPU_IRQHandler
|
||||
DCD USBD_IRQHandler
|
||||
DCD UARTE1_IRQHandler
|
||||
DCD QSPI_IRQHandler
|
||||
DCD CRYPTOCELL_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD PWM3_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD SPIM3_IRQHandler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
|
||||
__Vectors_End
|
||||
|
||||
__Vectors_Size EQU __Vectors_End - __Vectors
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
; Reset Handler
|
||||
|
||||
|
||||
Reset_Handler PROC
|
||||
EXPORT Reset_Handler [WEAK]
|
||||
IMPORT SystemInit
|
||||
IMPORT __main
|
||||
|
||||
|
||||
LDR R0, =SystemInit
|
||||
BLX R0
|
||||
LDR R0, =__main
|
||||
BX R0
|
||||
ENDP
|
||||
|
||||
; Dummy Exception Handlers (infinite loops which can be modified)
|
||||
|
||||
NMI_Handler PROC
|
||||
EXPORT NMI_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
HardFault_Handler\
|
||||
PROC
|
||||
EXPORT HardFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
MemoryManagement_Handler\
|
||||
PROC
|
||||
EXPORT MemoryManagement_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
BusFault_Handler\
|
||||
PROC
|
||||
EXPORT BusFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
UsageFault_Handler\
|
||||
PROC
|
||||
EXPORT UsageFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
DebugMon_Handler\
|
||||
PROC
|
||||
EXPORT DebugMon_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
|
||||
Default_Handler PROC
|
||||
|
||||
EXPORT POWER_CLOCK_IRQHandler [WEAK]
|
||||
EXPORT RADIO_IRQHandler [WEAK]
|
||||
EXPORT UARTE0_UART0_IRQHandler [WEAK]
|
||||
EXPORT SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler [WEAK]
|
||||
EXPORT SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler [WEAK]
|
||||
EXPORT NFCT_IRQHandler [WEAK]
|
||||
EXPORT GPIOTE_IRQHandler [WEAK]
|
||||
EXPORT SAADC_IRQHandler [WEAK]
|
||||
EXPORT TIMER0_IRQHandler [WEAK]
|
||||
EXPORT TIMER1_IRQHandler [WEAK]
|
||||
EXPORT TIMER2_IRQHandler [WEAK]
|
||||
EXPORT RTC0_IRQHandler [WEAK]
|
||||
EXPORT TEMP_IRQHandler [WEAK]
|
||||
EXPORT RNG_IRQHandler [WEAK]
|
||||
EXPORT ECB_IRQHandler [WEAK]
|
||||
EXPORT CCM_AAR_IRQHandler [WEAK]
|
||||
EXPORT WDT_IRQHandler [WEAK]
|
||||
EXPORT RTC1_IRQHandler [WEAK]
|
||||
EXPORT QDEC_IRQHandler [WEAK]
|
||||
EXPORT COMP_LPCOMP_IRQHandler [WEAK]
|
||||
EXPORT SWI0_EGU0_IRQHandler [WEAK]
|
||||
EXPORT SWI1_EGU1_IRQHandler [WEAK]
|
||||
EXPORT SWI2_EGU2_IRQHandler [WEAK]
|
||||
EXPORT SWI3_EGU3_IRQHandler [WEAK]
|
||||
EXPORT SWI4_EGU4_IRQHandler [WEAK]
|
||||
EXPORT SWI5_EGU5_IRQHandler [WEAK]
|
||||
EXPORT TIMER3_IRQHandler [WEAK]
|
||||
EXPORT TIMER4_IRQHandler [WEAK]
|
||||
EXPORT PWM0_IRQHandler [WEAK]
|
||||
EXPORT PDM_IRQHandler [WEAK]
|
||||
EXPORT MWU_IRQHandler [WEAK]
|
||||
EXPORT PWM1_IRQHandler [WEAK]
|
||||
EXPORT PWM2_IRQHandler [WEAK]
|
||||
EXPORT SPIM2_SPIS2_SPI2_IRQHandler [WEAK]
|
||||
EXPORT RTC2_IRQHandler [WEAK]
|
||||
EXPORT I2S_IRQHandler [WEAK]
|
||||
EXPORT FPU_IRQHandler [WEAK]
|
||||
EXPORT USBD_IRQHandler [WEAK]
|
||||
EXPORT UARTE1_IRQHandler [WEAK]
|
||||
EXPORT QSPI_IRQHandler [WEAK]
|
||||
EXPORT CRYPTOCELL_IRQHandler [WEAK]
|
||||
EXPORT PWM3_IRQHandler [WEAK]
|
||||
EXPORT SPIM3_IRQHandler [WEAK]
|
||||
POWER_CLOCK_IRQHandler
|
||||
RADIO_IRQHandler
|
||||
UARTE0_UART0_IRQHandler
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
|
||||
NFCT_IRQHandler
|
||||
GPIOTE_IRQHandler
|
||||
SAADC_IRQHandler
|
||||
TIMER0_IRQHandler
|
||||
TIMER1_IRQHandler
|
||||
TIMER2_IRQHandler
|
||||
RTC0_IRQHandler
|
||||
TEMP_IRQHandler
|
||||
RNG_IRQHandler
|
||||
ECB_IRQHandler
|
||||
CCM_AAR_IRQHandler
|
||||
WDT_IRQHandler
|
||||
RTC1_IRQHandler
|
||||
QDEC_IRQHandler
|
||||
COMP_LPCOMP_IRQHandler
|
||||
SWI0_EGU0_IRQHandler
|
||||
SWI1_EGU1_IRQHandler
|
||||
SWI2_EGU2_IRQHandler
|
||||
SWI3_EGU3_IRQHandler
|
||||
SWI4_EGU4_IRQHandler
|
||||
SWI5_EGU5_IRQHandler
|
||||
TIMER3_IRQHandler
|
||||
TIMER4_IRQHandler
|
||||
PWM0_IRQHandler
|
||||
PDM_IRQHandler
|
||||
MWU_IRQHandler
|
||||
PWM1_IRQHandler
|
||||
PWM2_IRQHandler
|
||||
SPIM2_SPIS2_SPI2_IRQHandler
|
||||
RTC2_IRQHandler
|
||||
I2S_IRQHandler
|
||||
FPU_IRQHandler
|
||||
USBD_IRQHandler
|
||||
UARTE1_IRQHandler
|
||||
QSPI_IRQHandler
|
||||
CRYPTOCELL_IRQHandler
|
||||
PWM3_IRQHandler
|
||||
SPIM3_IRQHandler
|
||||
B .
|
||||
ENDP
|
||||
ALIGN
|
||||
|
||||
; User Initial Stack & Heap
|
||||
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
|
||||
__user_initial_stackheap PROC
|
||||
|
||||
LDR R0, = Heap_Mem
|
||||
LDR R1, = (Stack_Mem + Stack_Size)
|
||||
LDR R2, = (Heap_Mem + Heap_Size)
|
||||
LDR R3, = Stack_Mem
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
ALIGN
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user