esp32_shock/components/lis3dsh/shake_detect.c
2024-04-29 17:35:50 +08:00

685 lines
22 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"
#include "esp_dsp.h"
#include "esp_err.h"
#include "esp_log.h"
#include "shake_detect.h"
#include "lis3dsh_lib/lis3dsh_reg.h"
#include "nvs_storage.h"
#include "twai_communication.h"
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)
{
int ret = 0;
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));
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);
}
}
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;
lis3dsh_config_t lis3dsh_config = {LIS3DSH_2g, LIS3DSH_1kHz6, 2, 1600};
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);
md.fs = lis3dsh_config.fscale;
md.odr = lis3dsh_config.odr;
lis3dsh_mode_set(&dev_ctx, &md);
/* 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);
}
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;
}
// 乒乓缓冲区定义fft一次需要取N_SAMPLES个数据运算定义缓冲区大小为其2倍在写另一边的时候fft可以对这边数据进行运算
__attribute__((aligned(16)))
lis3dsh_adata_t lis3dsh_data[N_SAMPLES * 2];
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);
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;
buf_r++;
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;
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)
{
if (feq_data == NULL) return false;
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;
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)
{
esp_err_t ret;
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);
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))
{
// ESP_LOGI(TAG, "enter...");
// 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];
}
unsigned int start_b = dsp_get_cpu_cycle_count();
// FFT
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);
unsigned int end_b = dsp_get_cpu_cycle_count();
// 归一化处理参考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]);
// float freq = i * 1.0 / N_SAMPLES * 1600; // 单位HZ
// 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]);
}
// 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);
// 震动检测
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);
// twai上报fft array数据
twai_send_fft_array_data(feq_data, N_SAMPLES / 2);
fft_data.count++;
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);
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++;
}
}
}
void shake_detect_init(void)
{
int ret = 0;
lis3dsh_init();
fft_queue = xQueueCreate(1, sizeof(uint32_t));
angle_queue = xQueueCreate(1, sizeof(uint32_t));
// 加载默认参数
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);
}
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);
}