@@ -27,75 +27,71 @@ static constexpr auto SAMPLES_LEQ = SPLMeter::SAMPLE_RATE * LEQ_PERIOD;
2727/* * Specifies the type of weighting to use for decibel calculation: dBA, dBC, or None/Z. */
2828static constexpr auto & WEIGHTING = A_weighting;
2929/* * Specifies the microphone's equalization filter. See pre-defined filters or set to 'None'. */
30- static constexpr auto & MIC_EQUALIZER = SPH0645LM4H_B_RB ;
30+ static constexpr auto & MIC_EQUALIZER = None ;
3131
3232/* * Valid number of bits in a received I2S data sample. */
33- static constexpr auto MIC_BITS = 24u ;
33+ static constexpr auto MIC_BITS = 16u ;
3434/* * dBFS value expected at MIC_REF_DB (Sensitivity value from datasheet). */
35- static constexpr auto MIC_SENSITIVITY = -26 .f;
35+ static constexpr auto MIC_SENSITIVITY = -36 .f;
3636/* * Value at which point sensitivity is specified in datasheet (dB). */
3737static constexpr auto MIC_REF_DB = 94 .f;
3838/* * Acoustic overload point (dB). */
39- static constexpr auto MIC_OVERLOAD_DB = 120 .f;
39+ static constexpr auto MIC_OVERLOAD_DB = 130 .f;
4040/* * Noise floor (dB). */
41- static constexpr auto MIC_NOISE_DB = 29 .f;
41+ static constexpr auto MIC_NOISE_DB = 30 .f;
4242/* * Linear calibration offset to apply to calculated decibel values. */
4343static constexpr auto MIC_OFFSET_DB = 0 .f;
4444
4545/* * Reference amplitude level for the microphone. */
4646static constexpr auto MIC_REF_AMPL = std::pow(10 .f, MIC_SENSITIVITY / 20 .f) * ((1 << (MIC_BITS - 1 )) - 1 );
4747
48- const i2s_config_t SPLMeter::i2s_config = {
49- mode: i2s_mode_t (I2S_MODE_MASTER | I2S_MODE_RX),
50- sample_rate: SAMPLE_RATE,
51- bits_per_sample: i2s_bits_per_sample_t (SPLMeter::SAMPLE_BITS),
52- channel_format: I2S_FORMAT,
53- communication_format: i2s_comm_format_t (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
54- intr_alloc_flags: ESP_INTR_FLAG_LEVEL1,
55- dma_buf_count: 32 ,
56- dma_buf_len: SPLMeter::SAMPLES_SHORT / 16u ,
57- use_apll: true ,
58- tx_desc_auto_clear: false ,
59- fixed_mclk: 0 ,
60- mclk_multiple: I2S_MCLK_MULTIPLE_DEFAULT,
61- bits_per_chan: I2S_BITS_PER_CHAN_DEFAULT,
62- };
63-
64- const i2s_pin_config_t SPLMeter::pin_config = {
65- mck_io_num: -1 , // not used
66- bck_io_num: I2S_SCK,
67- ws_io_num: I2S_WS,
68- data_out_num: -1 , // not used
69- data_in_num: I2S_SD
70- };
71-
72- constexpr std::int32_t SPLMeter::micConvert (std::int32_t s)
73- {
74- return s >> (SAMPLE_BITS - MIC_BITS);
75- }
76-
7748void SPLMeter::initMicrophone () noexcept
7849{
79- i2s_driver_install (I2S_PORT, &i2s_config, 0 , NULL );
80- i2s_set_pin (I2S_PORT, &pin_config);
81-
82- // Discard first block, microphone may need time to startup and settle.
83- i2sRead ();
50+ i2s_chan_handle_t rx_chan;
51+
52+ /* Setp 1: Determine the I2S channel configuration and allocate RX channel only
53+ * The default configuration can be generated by the helper macro,
54+ * but note that PDM channel can only be registered on I2S_NUM_0 */
55+ i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG (I2S_PORT, I2S_ROLE_MASTER);
56+ ESP_ERROR_CHECK (i2s_new_channel (&rx_chan_cfg, nullptr , &rx_chan));
57+
58+ /* Step 2: Setting the configurations of PDM RX mode and initialize the RX channel
59+ * The slot configuration and clock configuration can be generated by the macros
60+ * These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM RX mode.
61+ * They can help to specify the slot and clock configurations for initialization or re-configuring */
62+ i2s_pdm_rx_config_t pdm_rx_cfg = {
63+ .clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG (SAMPLE_RATE),
64+ /* The data bit-width of PDM mode is fixed to 16 */
65+ .slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG (I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
66+ .gpio_cfg = {
67+ .clk = I2S_SCK,
68+ .din = I2S_SD,
69+ .invert_flags = { .clk_inv = false , },
70+ },
71+ };
72+
73+ ESP_ERROR_CHECK (i2s_channel_init_pdm_rx_mode (rx_chan, &pdm_rx_cfg));
74+
75+ /* Step 3: Enable the rx channels before reading data */
76+ ESP_ERROR_CHECK (i2s_channel_enable (rx_chan));
77+ i2s_handle = rx_chan;
8478}
8579
8680std::optional<float > SPLMeter::readMicrophoneData () noexcept
8781{
8882 i2sRead ();
8983
90- // Convert (including shifting) integer microphone values to floats,
91- // using the same buffer (assumed sample size is same as size of float),
92- // to save a bit of memory
93- for (auto & s : samples)
94- s.f = micConvert (s.i );
84+ // I2S samples are 16-bit integers stored into samples's memory.
85+ // These need to be expanded into 32-bit floats for processing.
86+ // Iterate in reverse to avoid overwriting data.
87+ auto src = reinterpret_cast <const int16_t *>(samples.data ()) + samples.size ();
88+ auto dst = samples.data () + samples.size ();
89+ for (int i = 0 ; i < samples.size (); i++)
90+ *--dst = *--src;
9591
9692 // Apply equalization and calculate Z-weighted sum of squares,
9793 // writes filtered samples back to the same buffer.
98- auto fptr = & samples[ 0 ]. f ;
94+ const auto fptr = samples. data () ;
9995 const auto sum_sqr_SPL = MIC_EQUALIZER.filter (fptr, fptr, samples.size ());
10096
10197 // Apply weighting and calucate weigthed sum of squares
@@ -134,7 +130,8 @@ void SPLMeter::i2sRead() noexcept
134130 //
135131 // Data is moved from DMA buffers to our 'samples' buffer by the driver ISR
136132 // and when there is requested ammount of data, task is unblocked
137- size_t bytes_read;
138- i2s_read (I2S_PORT, samples.data (), samples.size () * sizeof (samples[0 ]), &bytes_read, portMAX_DELAY);
133+ size_t bread;
134+ (void )bread;
135+ i2s_channel_read (i2s_handle, samples.data (), samples.size () * sizeof (int16_t ), &bread, portMAX_DELAY);
139136}
140137
0 commit comments