Read Sensor at 1344Hz
Read Sensor at 1344Hz
Dear community,
I want to acquire data from accelerometer LIS3DH at 1344Hz sample rate.
- Approach using ISR rising edge for data ready pin, that means LIS3DH generate interrupt at approximately 1344Hz. In the ISR will enable semaphore which is evaluate in ReadSensorTask, the problem with this approach is that system doesn't work. It run slowly or sometime stuck, I try to collect 1024 samples and print msg when it succeed however the time to get 1024 samples is irregular or sometimes stuck. Maybe because tick rate is 1ms and the interrupt happen fastest than it.
- Another approach, will try to use a DelayTask with 1/1344ms, i don't know if tick rate can be reconfigure without generate possible error in RTOS. That is possible?
Another approach or some idea to test.
I want to acquire data from accelerometer LIS3DH at 1344Hz sample rate.
- Approach using ISR rising edge for data ready pin, that means LIS3DH generate interrupt at approximately 1344Hz. In the ISR will enable semaphore which is evaluate in ReadSensorTask, the problem with this approach is that system doesn't work. It run slowly or sometime stuck, I try to collect 1024 samples and print msg when it succeed however the time to get 1024 samples is irregular or sometimes stuck. Maybe because tick rate is 1ms and the interrupt happen fastest than it.
- Another approach, will try to use a DelayTask with 1/1344ms, i don't know if tick rate can be reconfigure without generate possible error in RTOS. That is possible?
Another approach or some idea to test.
-
- Posts: 1709
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Read Sensor at 1344Hz
Can you show some code? Specifically the ISR and the task that's reacting to it?
Do you use the I2C or the SPI interface?
Do you use the I2C or the SPI interface?
Re: Read Sensor at 1344Hz
I use I2C at 400kHz, here the code:MicroController wrote: ↑Fri May 12, 2023 8:50 amCan you show some code? Specifically the ISR and the task that's reacting to it?
Do you use the I2C or the SPI interface?
Code: Select all
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include "hal/gpio_types.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "lis3dh.h"
#include "vibration.h"
/* Vibration Analysis Parameters */
#define samples 1024
#define samplingFrequency 1344
#define ampFactor 3.7067873
#define GPIO_INPUT_PIN 15
SemaphoreHandle_t readSemaphore; // Semaphore handle
static const char *TAG = "esp-basic-vibration";
void VibrationTask(void *pvParameter)
{
printf("============== Starting Vibration Analysis Task ==============\n");
// Variables definition
AxesAccel_t ac;
float aRMS = 0;
float vRMS = 0;
float ax[samples];
float ay[samples];
float az[samples];
float ve[samples];
float Img[samples];
// Temp debug
uint8_t value = 0x02;
bool sts = 0;
unsigned int counter = 0;
// Peripherals Init
ESP_ERROR_CHECK(I2C_MASTER_INIT());
ESP_LOGI(TAG, "I2C initialized successfully");
// Accelerometer Config
LIS3DH_SetInt1Pin(LIS3DH_I1_DRDY1_ON_INT1_ENABLE);
LIS3DH_SetODR(LIS3DH_ODR_1344Hz_NP_5367HZ_LP);
LIS3DH_SetMode(LIS3DH_NORMAL);
LIS3DH_SetFullScale(LIS3DH_FULLSCALE_8);
LIS3DH_SetAxis(LIS3DH_X_ENABLE | LIS3DH_Y_ENABLE | LIS3DH_Z_ENABLE);
// Config Internal High Pass Filter
// LIS3DH_SetMode(LIS3DH_HPM_NORMAL_MODE);
// LIS3DH_SetHPFCutOFF(LIS3DH_HPFCF_3);
// LIS3DH_SetFilterDataSel(0x00);
sts = LIS3DH_GetWHO_AM_I(&value);
printf("Read Status: %d\n", sts);
printf("Who I am : %d\n", value);
vTaskDelay(2000 / portTICK_PERIOD_MS);
LIS3DH_GetAccAxes(&ac);
while (true)
{
// Get acceleration data in mg and save each axis
LIS3DH_GetAccAxes(&ac);
az[counter] = ac.axis_z;
ay[counter] = ac.axis_y;
ax[counter] = ac.axis_x;
// Espera a que la interrupción indique que se puede leer el sensor
xSemaphoreTake(readSemaphore, 100 / portTICK_PERIOD_MS);
if (counter >= samples)
{
printf("============== Running Vibration Analysis Task ==============\n");
printf("= Counter value : %d\n", counter);
// Counter reset
counter = 0;
// Remove DC Component
RemoveOffset(ax, samples);
RemoveOffset(ay, samples);
RemoveOffset(az, samples);
// Get Acceleration resultant 3 axis
// Resultant(ax, ay, az, samples);
// Get velocity applying numerical integration
Velocity(ax, ve, samples, samplingFrequency);
// Get Vibration RMS Values
RMS_Value(ax, samples, &aRMS);
RMS_Value(ve, samples, &vRMS);
// Save vector data on vReal and vImg for FFT
memset(Img, 0, samples * sizeof(float));
// FFT
FFT_Init(ve, Img, samples, samplingFrequency);
FFT_Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); // Recommended use for high frequencies. Relative to Sampling Frequency. In this case: 70Hz
FFT_Compute(FFT_FORWARD);
FFT_ComplexToMagnitude();
// Find Peaks
float amp[5], freq[5];
FFT_MajorPeaks(&[0], &freq[0], 1, 3);
// printf("============== Ended Vibration Analysis ==============\n");
// =========== DEBUG LOG ================
// printf("[$] Ac RMS : %.2f mg.\n", aRMS);
// printf("[$] Ve RMS : %.2f mm/s.\n", vRMS);
// printf("1st Peak -> Freq: %.2f Hz - Amp: %.2f mm/s \n", freq[0], amp[0]);
// printf("2nd Peak -> Freq: %.2f Hz - Amp: %.2f mm/s \n", freq[0], amp[0]);
// printf("3rd Peak -> Freq: %.2f Hz - Amp: %.2f mm/s \n", freq[0], amp[0]);
// for (uint i = 128; i < 256; i++) {
// printf("[#] Accel [%d] --> X: %.2f - Y: %.2f - Z: %.2f\n", i, ax[i], ay[i], az[i]);
// }
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
else
counter++;
}
}
void IRAM_ATTR isr_handler(void *arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(readSemaphore, &xHigherPriorityTaskWoken); // Se despierta la tarea que espera por el semáforo
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR(); // Se cambia a una tarea de mayor prioridad
}
}
void configure_interrupt(void)
{
gpio_config_t gpio_cfg = {
.intr_type = GPIO_INTR_POSEDGE, // Configurar el modo de interrupción como flanco de subida
.mode = GPIO_MODE_INPUT, // Configurar el modo de pin como entrada
.pin_bit_mask = (1ULL << GPIO_INPUT_PIN) // Configurar el pin que se utilizará como entrada
};
gpio_config(&gpio_cfg);
// Configurar la rutina de interrupción
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); // Nivel de prioridad de interrupción
gpio_isr_handler_add(GPIO_INPUT_PIN, isr_handler, NULL); // Configurar el manejador de interrupción
}
void app_main(void)
{
configure_interrupt();
readSemaphore = xSemaphoreCreateBinary(); // Se crea el semáforo
xTaskCreate(&VibrationTask, "xVibrationTask", 24576, NULL, 5, NULL);
}
-
- Posts: 1709
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Read Sensor at 1344Hz
Code looks ok, though I cannot find the code of the library you use to control the sensor.
One thing however is that you don't check the result of
So you don't know if the interrupt actually got triggered or if the SemaphoreTake timed out without the interrupt working.
One thing however is that you don't check the result of
Code: Select all
xSemaphoreTake(readSemaphore, 100 / portTICK_PERIOD_MS);
Re: Read Sensor at 1344Hz
I decided define timeout to prevent process stuck, if i replace with max delay the program sometimes stuck and If the read happen at interrupt frequency, it shouldn't´t active timeout. My question is about the ISR (1344Hz), it enable a semaphore for a task. but scheduler switching frequency are limited for tickrate (1000Hz) If it is the problem how i can solve it? Also i tried to execute I2C read function into ISR but stack isn't enough and the system reboot.MicroController wrote: ↑Fri May 12, 2023 8:42 pmCode looks ok, though I cannot find the code of the library you use to control the sensor.
One thing however is that you don't check the result ofSo you don't know if the interrupt actually got triggered or if the SemaphoreTake timed out without the interrupt working.Code: Select all
xSemaphoreTake(readSemaphore, 100 / portTICK_PERIOD_MS);
-
- Posts: 1709
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Read Sensor at 1344Hz
I know. And checking the return value of xSemaphoreTake would have let you know directly that there was no interrupt detected within 100ms.I decided define timeout to prevent process stuck, if i replace with max delay the program sometimes stuck
Since you're using a binary semaphore, the signalling of the ISR may also get lost when the ISR gives the semaphore more than once before the task has a chance to take it.
That said, an important question is: How long does LIS3DH_GetAccAxes(...) take to run?
No, it's not. The tick rate is the lower limit for the rate at which tasks get switched, i.e. at 100 Hz a task will be preempted after 10ms by FreeRTOS itself, but it can be switched in and out much faster by other means, e.g. by your ISR.scheduler switching frequency are limited for tickrate
Don't bother, this is never going to work.i tried to execute I2C read function into ISR
Re: Read Sensor at 1344Hz
I think this happens or the problem is related to this, but I don't know why it happens.MicroController wrote: ↑Mon May 15, 2023 7:08 pmSince you're using a binary semaphore, the signalling of the ISR may also get lost when the ISR gives the semaphore more than once before the task has a chance to take it.
Then, it should be worked with ISR, if task execute around 1 - 2 microseconds and ISR its called each 744us. Now i dont know how and where find the error, please some suggest?MicroController wrote: ↑Mon May 15, 2023 7:08 pmNo, it's not. The tick rate is the lower limit for the rate at which tasks get switched, i.e. at 100 Hz a task will be preempted after 10ms by FreeRTOS itself, but it can be switched in and out much faster by other means, e.g. by your ISR.
Using esp_timer_get_time() to get times, it execute in less than 1 micro second.MicroController wrote: ↑Mon May 15, 2023 7:08 pmThat said, an important question is: How long does LIS3DH_GetAccAxes(...) take to run?
**Important note is that sensor not generate a new interrupt if u don't read it previous.
**When I set sensor at 400Hz using exactly same code it works.
-
- Posts: 1709
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Read Sensor at 1344Hz
Think about that for a moment. At 400kHz clock, can the I2C bus transfer dozens of bits of data in "less than 1 micro second"?Using esp_timer_get_time() to get times, it execute in less than 1 micro second.
Re: Read Sensor at 1344Hz
Thats true, I made a mistake. Now I corrected it and get 1095us read time, its the problem but I just execute simple reads I guess I2C at 400kHz not support 1344Hz data rate at 16bits resolution. I configured 8 bits resolution with 1620Hz(618us) data rate and get a read time 550us but sometime stuck. Thanks u so much! I find the problem, maybe then I use SPI to test.MicroController wrote: ↑Tue May 16, 2023 7:18 amThink about that for a moment. At 400kHz clock, can the I2C bus transfer dozens of bits of data in "less than 1 micro second"?
-
- Posts: 1709
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Read Sensor at 1344Hz
Well, it could work. The whole transaction should be able to be done in about 210us of bus time:I guess I2C at 400kHz not support 1344Hz data rate at 16bits
START, Addr+W, (0x28 | 0x80), START, Addr+R, Read 6 bytes, STOP
I guess the library you're using is making sub-optimal use of the LIS3DH's I2C interface, i.e. using 6 transactions of one byte each instead of one transaction to read 6 consecutive bytes. If you want, you can create and run an "optimized" I2C transaction yourself just to retrieve the data, while still using the library for all the non-time critical stuff.
Who is online
Users browsing this forum: 137502805@qq.com, Bing [Bot] and 106 guests