|
| 1 | +/** |
| 2 | +****************************************************************************** |
| 3 | +* @file LSM6DSV16BX_TDM_Python_Wave_Serial_Encoder.ino |
| 4 | +* @author STMicroelectronics |
| 5 | +* @version V1.0.0 |
| 6 | +* @date 5 June 2025 |
| 7 | +* @brief Arduino test application for STMicroelectronics LSM6DSV16BX |
| 8 | +* IMU sensor with TDM. |
| 9 | +* This application makes use of C++ classes obtained from the C |
| 10 | +* components' drivers. |
| 11 | +****************************************************************************** |
| 12 | +* @attention |
| 13 | +* |
| 14 | +* <h2><center>© COPYRIGHT(c) 2025 STMicroelectronics</center></h2> |
| 15 | +* |
| 16 | +* Redistribution and use in source and binary forms, with or without modification, |
| 17 | +* are permitted provided that the following conditions are met: |
| 18 | +* 1. Redistributions of source code must retain the above copyright notice, |
| 19 | +* this list of conditions and the following disclaimer. |
| 20 | +* 2. Redistributions in binary form must reproduce the above copyright notice, |
| 21 | +* this list of conditions and the following disclaimer in the documentation |
| 22 | +* and/or other materials provided with the distribution. |
| 23 | +* 3. Neither the name of STMicroelectronics nor the names of its contributors |
| 24 | +* may be used to endorse or promote products derived from this software |
| 25 | +* without specific prior written permission. |
| 26 | +* |
| 27 | +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 28 | +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 29 | +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 30 | +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| 31 | +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 32 | +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 33 | +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 34 | +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 35 | +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 36 | +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 37 | +* |
| 38 | +****************************************************************************** |
| 39 | +*/ |
| 40 | +/* |
| 41 | + * To use this example you need to connect the STEVAL-MKI237KA eval board to the NUCLEO-U575ZI-Q board with wires as explained below: |
| 42 | + * pin 1 (VDD) of the STEVAL-MKI237KA eval board connected to pin 3V3 of the NUCLEO-U575ZI-Q board |
| 43 | + * pin 2 (VDDIO) of the STEVAL-MKI237KA eval board connected to pin IOREF of the NUCLEO-U575ZI-Q board |
| 44 | + * pin 3 (WCLK) of the STEVAL-MKI237KA eval board connected to pin FS of SAI_B of the NUCLEO-U575ZI-Q board |
| 45 | + * pin 4 (BCLK) of the STEVAL-MKI237KA eval board connected to pin SCK of SAI_B of the NUCLEO-U575ZI-Q board |
| 46 | + * pin 6 (TDM) of the STEVAL-MKI237KA eval board connected to pin SD of SAI_B of the NUCLEO-U575ZI-Q board |
| 47 | + * pin 13 (GND) of the STEVAL-MKI237KA eval board connected to GND of the NUCLEO-U575ZI-Q board |
| 48 | + * pin 19 (CS) of the STEVAL-MKI237KA eval board connected to pin AVDD of the NUCLEO-U575ZI-Q board |
| 49 | + * pin 20 (SCL) of the STEVAL-MKI237KA eval board connected to pin D15 SCL of the NUCLEO-U575ZI-Q board |
| 50 | + * pin 21 (SDA) of the STEVAL-MKI237KA eval board connected to pin D14 SDA of the NUCLEO-U575ZI-Q board |
| 51 | + */ |
| 52 | + |
| 53 | +/* This example was developed for NUCLEO-U575ZI-Q only. If you want to use other Nucleo or Architecture |
| 54 | + * you have to implement the dedicated file to manage the low level PCM part |
| 55 | + */ |
| 56 | +#if !defined(ARDUINO_NUCLEO_U575ZI_Q) |
| 57 | + #error "This example is only for STM32 NUCLEO-U575ZI-Q!" |
| 58 | +#endif |
| 59 | + |
| 60 | +#include "Arduino.h" |
| 61 | +#include "LSM6DSV16BXSensor.h" |
| 62 | +#include "PCM.h" |
| 63 | +#include "iir2.h" |
| 64 | + |
| 65 | +/* I2C_ADD_L means SA0 connected to GND */ |
| 66 | +LSM6DSV16BXSensor sensor(&Wire, LSM6DSV16BX_I2C_ADD_H); |
| 67 | +/* Enable only z-axis */ |
| 68 | +lsm6dsv16bx_tdm_xl_axis_t tdm_axis = {.x = 0, .y = 0, .z = 1}; |
| 69 | + |
| 70 | +struct iir2 iir2; |
| 71 | +const float b[2][3] = { |
| 72 | + { 0.972613898499844f, -1.945227796999688f, 0.972613898499844f }, |
| 73 | + { 0.986211924627082f, -1.972423849254165f, 0.986211924627082f }, |
| 74 | +}; |
| 75 | +const float a[2][3] = { |
| 76 | + { 1.000000000000000f, -1.944477657767094f, 0.945977936232282f }, |
| 77 | + { 1.000000000000000f, -1.972233729195266f, 0.972613969313063f }, |
| 78 | +}; |
| 79 | + |
| 80 | +static float audio_gain = 64.0f; |
| 81 | + |
| 82 | +#define TDM_RATE_8KHZ 0 |
| 83 | +#define TDM_RATE_16KHZ 1 |
| 84 | + |
| 85 | +/* PCM */ |
| 86 | +int16_t sampleBuffer[(((AUDIO_IN_SAMPLING_FREQUENCY / 1000) * N_MS_PER_INTERRUPT) / 2)] = {0}; |
| 87 | +int16_t audio_data[(((AUDIO_IN_SAMPLING_FREQUENCY / 1000) * N_MS_PER_INTERRUPT) / 2)] = {0}; |
| 88 | +bool recording = false; |
| 89 | +byte inByte = 0; |
| 90 | + |
| 91 | +static void tdm_audio_filter_data(struct iir2 *filter, uint16_t len, uint16_t offset); |
| 92 | + |
| 93 | +volatile uint8_t interrupt = 0; |
| 94 | + |
| 95 | +void setup() |
| 96 | +{ |
| 97 | + |
| 98 | + pinMode(LED_BUILTIN, OUTPUT); |
| 99 | + |
| 100 | + Wire.begin(); |
| 101 | + |
| 102 | + /* Serial */ |
| 103 | + Serial.begin(921600); |
| 104 | + Serial.flush(); |
| 105 | + while (Serial.available() > 0) { |
| 106 | + Serial.read(); |
| 107 | + } |
| 108 | + |
| 109 | + iir2_init(&iir2, b[TDM_RATE_16KHZ], a[TDM_RATE_16KHZ]); // init hp filter (fc = 50 Hz) |
| 110 | + sensor.begin(); |
| 111 | + sensor.Disable_X(); |
| 112 | + sensor.Set_TDM_XL_Axis(tdm_axis); |
| 113 | + sensor.Set_TDM_WCLK_BCLK(LSM6DSV16BX_WCLK_16kHZ_BCLK_2048kHz); |
| 114 | + sensor.Set_TDM_XL_Full_Scale(LSM6DSV16BX_TDM_8g); |
| 115 | + sensor.Set_X_Power_Mode(LSM6DSV16BX_XL_HIGH_PERFORMANCE_TDM_MD); |
| 116 | + |
| 117 | + /* Enable and Start */ |
| 118 | + if (PCM.Begin() != PCM_OK) { |
| 119 | + while (1) { |
| 120 | + digitalWrite(LED_BUILTIN, HIGH); |
| 121 | + delay(100); |
| 122 | + digitalWrite(LED_BUILTIN, LOW); |
| 123 | + delay(100); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + /* Function to execute with data */ |
| 128 | + PCM.onReceive(foo); |
| 129 | +} |
| 130 | + |
| 131 | +void loop() |
| 132 | +{ |
| 133 | + while (Serial.available() > 0) { |
| 134 | + inByte = Serial.read(); |
| 135 | + } |
| 136 | + |
| 137 | + if (inByte == 0x00) { |
| 138 | + recording = 0; |
| 139 | + PCM.Stop(); |
| 140 | + digitalWrite(LED_BUILTIN, LOW); |
| 141 | + } |
| 142 | + |
| 143 | + if (inByte == 0x01 && recording == 0) { |
| 144 | + PCM.Record(sampleBuffer); |
| 145 | + recording = 1; |
| 146 | + digitalWrite(LED_BUILTIN, HIGH); |
| 147 | + } |
| 148 | + |
| 149 | + if (interrupt == 1 && recording == 1) { |
| 150 | + interrupt = 0; |
| 151 | + Serial.write((const char *)audio_data, sizeof(audio_data)); |
| 152 | + Serial.flush(); |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +static void tdm_audio_filter_data(struct iir2 *filter, uint16_t len, uint16_t offset) |
| 157 | +{ |
| 158 | + for (uint16_t i = 0; i < len; i++) { |
| 159 | + if (audio_gain == 0.0f) { |
| 160 | + audio_data[offset + i] = sampleBuffer[offset + i]; |
| 161 | + } else { |
| 162 | + float zf = iir2_run(filter, sampleBuffer[offset + i]) * audio_gain; |
| 163 | + zf = zf > INT16_MAX ? INT16_MAX : zf; |
| 164 | + zf = zf < INT16_MIN ? INT16_MIN : zf; |
| 165 | + audio_data[offset + i] = (int16_t)zf; |
| 166 | + } |
| 167 | + } |
| 168 | +} |
| 169 | + |
| 170 | +extern "C" void foo() |
| 171 | +{ |
| 172 | + tdm_audio_filter_data(&iir2, (((AUDIO_IN_SAMPLING_FREQUENCY / 1000) * N_MS_PER_INTERRUPT) / 2), 0); |
| 173 | + interrupt = 1; |
| 174 | +} |
0 commit comments