esp32_shock/components/lis3dsh/shake_detect.c

685 lines
22 KiB
C
Raw Normal View History

2024-04-27 09:15:55 +08:00
// lis3dsh数据手册https://www.findic.com/doc/browser/8LWZ55XQZ?doc_id=48813340#locale=zh-CN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c.h"
#include "driver/gpio.h"
2024-04-27 09:42:47 +08:00
#include "esp_dsp.h"
2024-04-27 09:15:55 +08:00
#include "esp_err.h"
#include "esp_log.h"
#include "shake_detect.h"
#include "lis3dsh_lib/lis3dsh_reg.h"
2024-04-29 17:35:50 +08:00
#include "nvs_storage.h"
#include "twai_communication.h"
2024-04-27 09:15:55 +08:00
static const char *TAG = "shake_detect";
static QueueHandle_t int1_evt_queue = NULL;
// 0--SPI, 1--I2C
static void lis3dsh_cs_io_init(int mode)
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL << LIS3DSH_CS_IO);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
gpio_set_level(LIS3DSH_CS_IO, mode);
}
static void lis3dsh_i2c_sel_io_init(int addr01)
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL << LIS3DSH_I2C_SEL_IO);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
gpio_set_level(LIS3DSH_I2C_SEL_IO, addr01);
}
static esp_err_t lis3dsh_i2c_master_init(void)
{
int i2c_master_port = LIS3DSH_I2C_MASTER_NUM;
lis3dsh_cs_io_init(1);
lis3dsh_i2c_sel_io_init(0);
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = LIS3DSH_I2C_MASTER_SDA_IO,
.scl_io_num = LIS3DSH_I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = LIS3DSH_I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}
static void lis3dsh_led_init(void)
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL << LIS3DSH_LED_IO);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
}
static void lis3dsh_led_toggle(void)
{
static int state = 0;
gpio_set_level(LIS3DSH_LED_IO, state);
state = !state;
}
static void IRAM_ATTR int1_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
if (gpio_num == LIS3DSH_INT1_IO)
{
xQueueSendFromISR(int1_evt_queue, &gpio_num, NULL);
}
}
static void lis3dsh_int1_int_init(void)
{
2024-04-29 17:35:50 +08:00
int ret = 0;
2024-04-27 09:15:55 +08:00
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << LIS3DSH_INT1_IO);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
int1_evt_queue = xQueueCreate(1, sizeof(uint32_t));
2024-04-29 17:35:50 +08:00
ESP_LOGI(TAG, "gpio_install_isr_service...");
ret = gpio_install_isr_service(0); // 注这里会和twai有冲突当先调这个再进行twai install的时候不成功没有中断资源
if (ret != 0)
{
if (ret == ESP_ERR_NOT_FOUND)
{
ESP_LOGI(TAG, "gpio_install_isr_service: no isr service found");
}
else
{
ESP_LOGE(TAG, "gpio_install_isr_service: err 0x%x", ret);
}
}
2024-04-27 09:15:55 +08:00
gpio_isr_handler_add(LIS3DSH_INT1_IO, int1_isr_handler, (void*) LIS3DSH_INT1_IO);
}
static int platform_init(void)
{
ESP_ERROR_CHECK(lis3dsh_i2c_master_init());
lis3dsh_int1_int_init();
lis3dsh_led_init();
return LIS3DSH_I2C_MASTER_NUM;
}
static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
{
uint8_t write_buf[128];
if (len > 127)
return -1;
write_buf[0] = reg;
memcpy(&write_buf[1], bufp, len);
return i2c_master_write_to_device(LIS3DSH_I2C_MASTER_NUM, LIS3DSH_I2C_ADD_L >> 1, write_buf, len + 1, LIS3DSH_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
{
return i2c_master_write_read_device(LIS3DSH_I2C_MASTER_NUM, LIS3DSH_I2C_ADD_L >> 1, &reg, 1, bufp, len, LIS3DSH_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}
static void platform_delay(uint32_t ms)
{
vTaskDelay(pdMS_TO_TICKS(ms));
}
stmdev_ctx_t dev_ctx;
2024-04-29 17:35:50 +08:00
lis3dsh_config_t lis3dsh_config = {LIS3DSH_2g, LIS3DSH_1kHz6, 2, 1600};
2024-04-27 09:15:55 +08:00
void lis3dsh_init(void)
{
int ret = 0;
lis3dsh_pin_int1_route_t int1_route;
lis3dsh_all_sources_t all_sources;
lis3dsh_bus_mode_t bus_mode;
lis3dsh_status_var_t status;
lis3dsh_ctrl_reg3_t ctrl_reg3;
lis3dsh_id_t id = {0};
lis3dsh_md_t md;
lis3dsh_reg_t reg;
/* Initialize mems driver interface */
dev_ctx.handle = (void *)platform_init();
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
/* Wait sensor boot time */
platform_delay(BOOT_TIME);
/* Check device ID */
ret = lis3dsh_id_get(&dev_ctx, &id);
ESP_LOGI(TAG, "ret=%d, lis3dsh_id=%02x%02x%02x", ret, id.whoami, id.info1, id.info2);
while (id.whoami != LIS3DSH_ID)
{
platform_delay(100);
memset(&id, 0, sizeof(id));
ret = lis3dsh_id_get(&dev_ctx, &id);
ESP_LOGI(TAG, "ret=%d, lis3dsh_id=%02x%02x%02x", ret, id.whoami, id.info1, id.info2);
}
// 有时候系统启动会卡在这个循环里
// /* Restore default configuration */
// lis3dsh_init_set(&dev_ctx, LIS3DSH_RESET);
// do
// {
// lis3dsh_status_get(&dev_ctx, &status);
// } while (status.sw_reset);
/* Set bdu and if_inc recommended for driver usage */
lis3dsh_init_set(&dev_ctx, LIS3DSH_DRV_RDY);
/* Set Output Data Rate */
// ctrl_reg4, ctrl_reg5
lis3dsh_mode_get(&dev_ctx, &md);
2024-04-29 17:35:50 +08:00
md.fs = lis3dsh_config.fscale;
md.odr = lis3dsh_config.odr;
2024-04-27 09:15:55 +08:00
lis3dsh_mode_set(&dev_ctx, &md);
2024-04-29 17:35:50 +08:00
2024-04-27 09:15:55 +08:00
/* FIFO configuration */
// fifo_ctrl
lis3dsh_read_reg(&dev_ctx, LIS3DSH_FIFO_CTRL, &reg.byte, 1);
reg.fifo_ctrl.fmode = 2; /* FIFO stream mode */
reg.fifo_ctrl.wtmp = 16;
lis3dsh_write_reg(&dev_ctx, LIS3DSH_FIFO_CTRL, &reg.byte, 1);
// ctrl_reg6:fifo使能地址自增使能fifo水位中断int1使能
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG6, &reg.byte, 1);
memset(&reg.byte, 0, sizeof(reg.byte));
ESP_LOGI(TAG, "LIS3DSH_CTRL_REG6 old=%02x", reg.byte);
reg.ctrl_reg6.fifo_en = PROPERTY_ENABLE;
reg.ctrl_reg6.wtm_en = PROPERTY_ENABLE;
reg.ctrl_reg6.add_inc = PROPERTY_ENABLE;
reg.ctrl_reg6.p1_wtm = PROPERTY_ENABLE;
lis3dsh_write_reg(&dev_ctx, LIS3DSH_CTRL_REG6, &reg.byte, 1);
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG6, &reg.byte, 1);
ESP_LOGI(TAG, "LIS3DSH_CTRL_REG6 new=%02x", reg.byte);
// ctrl_reg3:中断配置int1使能DRDY失能int2失能低电平有效锁存
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG3, (uint8_t *)&ctrl_reg3, 1);
memset(&ctrl_reg3, 0, sizeof(ctrl_reg3));
ctrl_reg3.int1_en = PROPERTY_ENABLE;
lis3dsh_write_reg(&dev_ctx, LIS3DSH_CTRL_REG3, (uint8_t *)&ctrl_reg3, 1);
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG4, &reg.byte, 1);
ESP_LOGI(TAG, "LIS3DSH_CTRL_REG4 old=%02x", reg.byte);
}
2024-04-29 17:35:50 +08:00
int lis3dsh_set_fscale(uint8_t fscale)
{
int fscale_v = 0;
switch (fscale)
{
case LIS3DSH_2g:
fscale_v = 2;
break;
case LIS3DSH_4g:
fscale_v = 4;
break;
case LIS3DSH_6g:
fscale_v = 6;
break;
case LIS3DSH_8g:
fscale_v = 8;
break;
case LIS3DSH_16g:
fscale_v = 16;
break;
default:
return -1;
}
int ret = 0;
lis3dsh_reg_t reg;
ret = lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG5, &reg.byte, 1);
if (ret != 0) return ret;
reg.ctrl_reg5.fscale = fscale & 0x07;
ret = lis3dsh_write_reg(&dev_ctx, LIS3DSH_CTRL_REG5, &reg.byte, 1);
if (ret != 0) return ret;
lis3dsh_config.fscale = fscale;
lis3dsh_config.fscale_v = fscale_v;
return ret;
}
int lis3dsh_set_odr(uint8_t odr)
{
int odr_v = 0;
switch (odr)
{
case LIS3DSH_25Hz:
odr_v = 25;
break;
case LIS3DSH_50Hz:
odr_v = 50;
break;
case LIS3DSH_100Hz:
odr_v = 100;
break;
case LIS3DSH_400Hz:
odr_v = 400;
break;
case LIS3DSH_800Hz:
odr_v = 800;
break;
case LIS3DSH_1kHz6:
odr_v = 1600;
break;
default:
return -1;
}
int ret = 0;
lis3dsh_reg_t reg;
ret = lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG4, &reg.byte, 1);
if (ret != 0) return ret;
reg.ctrl_reg4.odr = odr & 0x0F;
ret = lis3dsh_write_reg(&dev_ctx, LIS3DSH_CTRL_REG4, &reg.byte, 1);
if (ret != 0) return ret;
lis3dsh_config.odr = odr;
lis3dsh_config.odr_v = odr_v;
return 0;
}
uint8_t lis3dsh_get_fscale(void)
{
lis3dsh_reg_t reg = {0};
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG5, &reg.byte, 1);
return reg.ctrl_reg5.fscale;
}
uint8_t lis3dsh_get_odr(void)
{
lis3dsh_reg_t reg = {0};
lis3dsh_read_reg(&dev_ctx, LIS3DSH_CTRL_REG4, &reg.byte, 1);
return reg.ctrl_reg4.odr;
}
int lis3dsh_config_restore_default(void)
{
int ret = 0;
ret = lis3dsh_set_fscale(LIS3DSH_2g); // 2g
if (ret != 0) return ret;
ret = lis3dsh_set_odr(LIS3DSH_1kHz6); // 1kHz6
if (ret != 0) return ret;
return 0;
}
int lis3dsh_config_nvs_load(void)
{
int ret = 0;
ret = nvs_storage_read(LIS3DSH_CONFIG_FS_NVS_KAY, &lis3dsh_config.fscale, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
switch (lis3dsh_config.fscale)
{
case LIS3DSH_2g:
lis3dsh_config.fscale_v = 2;
break;
case LIS3DSH_4g:
lis3dsh_config.fscale_v = 4;
break;
case LIS3DSH_6g:
lis3dsh_config.fscale_v = 6;
break;
case LIS3DSH_8g:
lis3dsh_config.fscale_v = 8;
break;
case LIS3DSH_16g:
lis3dsh_config.fscale_v = 16;
break;
default:
lis3dsh_config.fscale = LIS3DSH_2g;
lis3dsh_config.fscale_v = 2;
return -1;
}
ret = nvs_storage_read(LIS3DSH_CONFIG_ODR_NVS_KAY, &lis3dsh_config.odr, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
switch (lis3dsh_config.odr)
{
case LIS3DSH_25Hz:
lis3dsh_config.odr_v = 25;
break;
case LIS3DSH_50Hz:
lis3dsh_config.odr_v = 50;
break;
case LIS3DSH_100Hz:
lis3dsh_config.odr_v = 100;
break;
case LIS3DSH_400Hz:
lis3dsh_config.odr_v = 400;
break;
case LIS3DSH_800Hz:
lis3dsh_config.odr_v = 800;
break;
case LIS3DSH_1kHz6:
lis3dsh_config.odr_v = 1600;
break;
default:
lis3dsh_config.odr = LIS3DSH_1kHz6;
lis3dsh_config.odr_v = 1600;
return -1;
}
return 0;
}
int lis3dsh_config_nvs_save(void)
{
int ret = 0;
ret = nvs_storage_write(LIS3DSH_CONFIG_FS_NVS_KAY, &lis3dsh_config.fscale, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(LIS3DSH_CONFIG_ODR_NVS_KAY, &lis3dsh_config.odr, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
return 0;
}
2024-04-27 09:15:55 +08:00
// 乒乓缓冲区定义fft一次需要取N_SAMPLES个数据运算定义缓冲区大小为其2倍在写另一边的时候fft可以对这边数据进行运算
__attribute__((aligned(16)))
2024-04-29 17:35:50 +08:00
lis3dsh_adata_t lis3dsh_data[N_SAMPLES * 2];
2024-04-27 09:15:55 +08:00
int buf_r = 0;
int fft_h = 0;
int angle_h = 0;
static QueueHandle_t fft_queue = NULL;
static QueueHandle_t angle_queue = NULL;
void lis3dsh_read_task(void)
{
uint32_t io_num;
lis3dsh_reg_t reg;
uint8_t rx_buffer[128];
while (1)
{
if(xQueueReceive(int1_evt_queue, &io_num, pdMS_TO_TICKS(1000)))
{
lis3dsh_read_reg(&dev_ctx, LIS3DSH_FIFO_SRC, &reg.byte, 1);
// ESP_LOGI(TAG, "fss:%d", reg.fifo_src.fss);
for (int i = 0; i < reg.fifo_src.fss; i++)
{
lis3dsh_read_reg(&dev_ctx, LIS3DSH_OUT_X_L, rx_buffer, 6);
// ESP_LOGI(TAG, "read %02d:%10f, %10f, %10f", i, (int16_t)(rx_buffer[0] | (rx_buffer[1] << 8)) * 2.0 / 0x7fff, (int16_t)(rx_buffer[2] | (rx_buffer[3] << 8)) * 2.0 / 0x7fff, (int16_t)(rx_buffer[4] | (rx_buffer[5] << 8)) * 2.0 / 0x7fff);
2024-04-29 17:35:50 +08:00
lis3dsh_data[buf_r].a[0] = (int16_t)(rx_buffer[0] | (rx_buffer[1] << 8)) * lis3dsh_config.fscale_v * 1.0 / 0x7fff;
lis3dsh_data[buf_r].a[1] = (int16_t)(rx_buffer[2] | (rx_buffer[3] << 8)) * lis3dsh_config.fscale_v * 1.0 / 0x7fff; // y 有重力加速度分量计算fft的时候需要去掉
lis3dsh_data[buf_r].a[2] = (int16_t)(rx_buffer[4] | (rx_buffer[5] << 8)) * lis3dsh_config.fscale_v * 1.0 / 0x7fff;
2024-04-27 09:15:55 +08:00
buf_r++;
2024-04-29 17:35:50 +08:00
2024-04-27 09:15:55 +08:00
if (buf_r == N_SAMPLES || buf_r == N_SAMPLES * 2)
{
// ESP_LOGI(TAG, "send fft queue");
fft_h = buf_r - N_SAMPLES;
xQueueSend(fft_queue, &fft_h, portMAX_DELAY);
}
if (buf_r != 0 && buf_r % ANGLE_N_SAMPLES == 0)
{
// ESP_LOGI(TAG, "send angle queue");
angle_h = buf_r - ANGLE_N_SAMPLES;
xQueueSend(angle_queue, &angle_h, portMAX_DELAY);
}
if (buf_r == N_SAMPLES * 2)
{
buf_r = 0;
}
}
}
else
{
ESP_LOGI(TAG, "wait int1..."); // 很奇怪,第一次中断进不去,只有读一次才能进
lis3dsh_read_reg(&dev_ctx, LIS3DSH_OUT_X_L, rx_buffer, 6);
ESP_LOGI(TAG, "read :%f, %f, %f", (int16_t)(rx_buffer[0] | (rx_buffer[1] << 8)) * 2.0 / 0x7fff, (int16_t)(rx_buffer[2] | (rx_buffer[3] << 8)) * 2.0 / 0x7fff, (int16_t)(rx_buffer[4] | (rx_buffer[5] << 8)) * 2.0 / 0x7fff);
}
}
}
shake_detect_cfg_t shake_cfg = {10, 25, 0.06, 0.03, 2, 3, 3};
__attribute__((aligned(16)))
fft_data_t fft_data;
2024-04-29 17:35:50 +08:00
int shake_config_restore_default(void)
{
shake_cfg.feq_min_id = 10;
shake_cfg.feq_max_id = 25;
shake_cfg.enter_amplitude_th = 0.06;
shake_cfg.exit_amplitude_th = 0.03;
shake_cfg.channel1 = 2;
shake_cfg.channel2 = 3;
shake_cfg.select = 3;
return 0;
}
int shake_config_nvs_load(void)
{
int ret = 0;
ret = nvs_storage_read(SHAKE_CONFIG_FMIN_NVS_KAY, &shake_cfg.feq_min_id, NVS_STORAGE_UINT16);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_FMAX_NVS_KAY, &shake_cfg.feq_max_id, NVS_STORAGE_UINT16);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_INATH_NVS_KAY, &shake_cfg.enter_amplitude_th, NVS_STORAGE_UINT32);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_OUTATH_NVS_KAY, &shake_cfg.exit_amplitude_th, NVS_STORAGE_UINT32);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_CH1_NVS_KAY, &shake_cfg.channel1, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_CH2_NVS_KAY, &shake_cfg.channel2, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
ret = nvs_storage_read(SHAKE_CONFIG_SEL_NVS_KAY, &shake_cfg.select, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
return 0;
}
int shake_config_nvs_save(void)
{
int ret = 0;
ret = nvs_storage_write(SHAKE_CONFIG_FMIN_NVS_KAY, &shake_cfg.feq_min_id, NVS_STORAGE_UINT16);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_FMAX_NVS_KAY, &shake_cfg.feq_max_id, NVS_STORAGE_UINT16);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_INATH_NVS_KAY, &shake_cfg.enter_amplitude_th, NVS_STORAGE_UINT32);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_OUTATH_NVS_KAY, &shake_cfg.exit_amplitude_th, NVS_STORAGE_UINT32);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_CH1_NVS_KAY, &shake_cfg.channel1, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_CH2_NVS_KAY, &shake_cfg.channel2, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
ret = nvs_storage_write(SHAKE_CONFIG_SEL_NVS_KAY, &shake_cfg.select, NVS_STORAGE_UINT8);
if (ret != ESP_OK) return ret;
return 0;
}
bool shake_detect_fun(fft_type_t *feq_data)
2024-04-27 09:15:55 +08:00
{
if (feq_data == NULL) return false;
2024-04-29 17:35:50 +08:00
fft_type_t a_max = 0;
fft_type_t a_th = fft_data.is_shake ? shake_cfg.exit_amplitude_th : shake_cfg.enter_amplitude_th;
2024-04-27 09:15:55 +08:00
for (int i = shake_cfg.feq_min_id; i <= shake_cfg.feq_max_id; i++)
{
a_max = a_max >= feq_data[i] ? a_max : feq_data[i];
}
if (a_max >= a_th)
return true;
return false;
}
void fft_calculate_task(void)
{
2024-04-27 09:42:47 +08:00
esp_err_t ret;
2024-04-27 09:15:55 +08:00
fft_data.y1_cf = &fft_data.y_cf[0];
fft_data.y2_cf = &fft_data.y_cf[N_SAMPLES];
// fft 初始化
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
2024-04-29 17:35:50 +08:00
2024-04-27 09:15:55 +08:00
if (ret != ESP_OK) {
ESP_LOGI(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
// Generate hann window
dsps_wind_hann_f32(fft_data.wind, N_SAMPLES);
while (1)
{
// ESP_LOGI(TAG, "fft wait...");
if(xQueueReceive(fft_queue, &fft_h, portMAX_DELAY))
{
2024-04-29 17:35:50 +08:00
// ESP_LOGI(TAG, "enter...");
2024-04-27 09:15:55 +08:00
// Convert two input vectors to one complex vector
uint8_t ch1 = shake_cfg.channel1;
uint8_t ch2 = shake_cfg.channel2;
if (ch1 <= 0 || ch1 > 3 || ch2 <= 0 || ch2 > 3)
{
ESP_LOGI(TAG, "CH select err[1-3]: ch1=%d, ch2=%d", ch1, ch2);
continue;
}
for (int i = 0 ; i < N_SAMPLES ; i++) {
fft_data.y_cf[i * 2 + 0] = lis3dsh_data[fft_h + i].a[ch1 - 1] * fft_data.wind[i];
fft_data.y_cf[i * 2 + 1] = lis3dsh_data[fft_h + i].a[ch2 - 1] * fft_data.wind[i];
}
2024-04-29 17:35:50 +08:00
2024-04-27 09:42:47 +08:00
unsigned int start_b = dsp_get_cpu_cycle_count();
2024-04-29 17:35:50 +08:00
// FFT
2024-04-27 09:15:55 +08:00
dsps_fft2r_fc32(fft_data.y_cf, N_SAMPLES);
// Bit reverse
dsps_bit_rev_fc32(fft_data.y_cf, N_SAMPLES);
// Convert one complex vector to two complex vectors
dsps_cplx2reC_fc32(fft_data.y_cf, N_SAMPLES);
2024-04-29 17:35:50 +08:00
unsigned int end_b = dsp_get_cpu_cycle_count();
2024-04-27 09:15:55 +08:00
// 归一化处理参考https://blog.csdn.net/weixin_39591031/article/details/110392352
for (int i = 0 ; i < N_SAMPLES / 2 ; i++) {
int normal_div = N_SAMPLES / 2.0;
if (i == 0) normal_div = N_SAMPLES;
fft_data.y1_cf[i] = (sqrt(fft_data.y1_cf[i * 2 + 0] * fft_data.y1_cf[i * 2 + 0] + fft_data.y1_cf[i * 2 + 1] * fft_data.y1_cf[i * 2 + 1]) / normal_div);
fft_data.y2_cf[i] = (sqrt(fft_data.y2_cf[i * 2 + 0] * fft_data.y2_cf[i * 2 + 0] + fft_data.y2_cf[i * 2 + 1] * fft_data.y2_cf[i * 2 + 1]) / normal_div);
// Simple way to show two power spectrums as one plot
fft_data.sum_y[i] = fmax(fft_data.y1_cf[i], fft_data.y2_cf[i]);
2024-04-29 17:35:50 +08:00
// float freq = i * 1.0 / N_SAMPLES * 1600; // 单位HZ
2024-04-27 09:15:55 +08:00
// ESP_LOGI(TAG, "fft %d: f=%f, y=%f, z=%f sum=%f", i, freq, fft_data.y1_cf[i], fft_data.y2_cf[i], fft_data.sum_y[i]);
}
2024-04-29 17:35:50 +08:00
// ESP_LOGW(TAG, "Signal ch1");
// dsps_view(fft_data.y1_cf, N_SAMPLES / 2, 64, 10, -2, 2, '|');
// ESP_LOGI(TAG, "FFT for %i complex points take %i cycles", N_SAMPLES, end_b - start_b);
2024-04-27 09:42:47 +08:00
2024-04-27 09:15:55 +08:00
// 震动检测
float *feq_data = NULL;
switch (shake_cfg.select)
{
case 1:
feq_data = fft_data.y1_cf;
break;
case 2:
feq_data = fft_data.y2_cf;
break;
case 3:
feq_data = fft_data.sum_y;
break;
default:
ESP_LOGI(TAG, "select err[1-3]: %d", shake_cfg.select);
continue;
break;
}
fft_data.is_shake = shake_detect_fun(feq_data);
// ESP_LOGI(TAG, "is_shake = %d", fft_data.is_shake);
2024-04-29 17:35:50 +08:00
// twai上报fft array数据
twai_send_fft_array_data(feq_data, N_SAMPLES / 2);
fft_data.count++;
2024-04-27 09:15:55 +08:00
lis3dsh_led_toggle();
}
}
}
#define PI (3.1415926)
void lis3dsh_calculating_angle(float ax, float ay, float az, float *anglex, float *angley, float *anglez)
{
float axy = sqrt(ax * ax + ay * ay);
*anglez = (atan2(axy, az) * 180 / PI);
float axz = sqrt(ax * ax + az * az);
*angley = (atan2(ay, axz) * 180 / PI);
float ayz = sqrt(ay * ay + az * az);
*anglex = (atan2(ax, ayz) * 180 / PI);
}
angle_data_t angle_data;
void angle_calculate_task(void)
{
float ax = 0, ay = 0, az = 0;
while (1)
{
// ESP_LOGI(TAG, "angle wait...");
if(xQueueReceive(angle_queue, &angle_h, portMAX_DELAY))
{
for (int i = 0; i < ANGLE_N_SAMPLES; i++)
{
ax += lis3dsh_data[angle_h + i].a[0];
ay += lis3dsh_data[angle_h + i].a[1];
az += lis3dsh_data[angle_h + i].a[2];
}
ax /= ANGLE_N_SAMPLES;
ay /= ANGLE_N_SAMPLES;
az /= ANGLE_N_SAMPLES;
lis3dsh_calculating_angle(ax, ay, az, &angle_data.x, &angle_data.y, &angle_data.z);
2024-04-29 17:35:50 +08:00
ESP_LOGI(TAG, "angle: x=%5.5f\ty=%5.5f\tz=%5.5f", angle_data.x, angle_data.y, angle_data.z);
angle_data.count++;
2024-04-27 09:15:55 +08:00
}
}
}
void shake_detect_init(void)
{
2024-04-29 17:35:50 +08:00
int ret = 0;
2024-04-27 09:15:55 +08:00
lis3dsh_init();
fft_queue = xQueueCreate(1, sizeof(uint32_t));
angle_queue = xQueueCreate(1, sizeof(uint32_t));
2024-04-29 17:35:50 +08:00
// 加载默认参数
ret = lis3dsh_config_nvs_load();
if (ret != 0)
{
ESP_LOGI(TAG, "load lisdsh config err[%d], use default config", ret);
}
ret = shake_config_nvs_load();
if (ret != 0)
{
ESP_LOGI(TAG, "load shake config err[%d], use default config", ret);
}
2024-04-27 09:15:55 +08:00
xTaskCreatePinnedToCore(lis3dsh_read_task, "lis3dsh_read_task", 4096, NULL, 9, NULL, tskNO_AFFINITY);
xTaskCreatePinnedToCore(fft_calculate_task, "fft_calculate_task", 4096, NULL, 9, NULL, tskNO_AFFINITY);
xTaskCreatePinnedToCore(angle_calculate_task, "angle_calculate_task", 4096, NULL, 9, NULL, tskNO_AFFINITY);
}