Skip to content

Commit 24d5384

Browse files
committed
refactor: keep support for earlier revs
Changed board definitions; ported older revs to latest I2S library; force older revs to only accept pre-v0.4 updates
1 parent caf44e1 commit 24d5384

6 files changed

Lines changed: 135 additions & 41 deletions

File tree

noisemeter-device/board.h

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
#undef SERIAL
2727

28-
#if defined(BOARD_ESP32_PCB)
28+
#if defined(BOARD_REV4)
2929

3030
/** Pin number for the board's LED. */
3131
#define PIN_LED1 GPIO_NUM_17
@@ -45,26 +45,40 @@
4545
/** Serial instance to use for logging output. */
4646
#define SERIAL USBSerial
4747

48+
#define USE_MIC_IM64D130A
49+
4850
#include <HWCDC.h>
4951
extern HWCDC USBSerial;
5052

51-
#elif defined(BOARD_ESP32_BREADBOARD)
53+
#elif defined(BOARD_REV123)
54+
55+
#define PIN_LED1 GPIO_NUM_0
56+
#define PIN_BUTTON GPIO_NUM_1
57+
#define I2S_WS GPIO_NUM_4
58+
#define I2S_SCK GPIO_NUM_5
59+
#define I2S_SD GPIO_NUM_6
60+
#define I2S_PORT I2S_NUM_0
61+
#define I2S_FORMAT I2S_CHANNEL_FMT_ONLY_LEFT
62+
#define SERIAL USBSerial
63+
64+
#define USE_MIC_SPH0645
65+
66+
#include <HWCDC.h>
67+
extern HWCDC USBSerial;
5268

53-
// Pin definitions
54-
#define PIN_LED1 (36) // random choice
55-
#define PIN_LED2 (39) // random choice
56-
#define PIN_BUTTON (5)
57-
#define I2S_WS (18)
58-
#define I2S_SCK (23)
59-
#define I2S_SD (19)
69+
#elif defined(BOARD_BREADBOARD)
6070

61-
// ESP32 has two I2S peripherals
71+
#define PIN_LED1 GPIO_NUM_36 // random choice
72+
#define PIN_LED2 GPIO_NUM_39 // random choice
73+
#define PIN_BUTTON GPIO_NUM_5
74+
#define I2S_WS GPIO_NUM_18
75+
#define I2S_SCK GPIO_NUM_23
76+
#define I2S_SD GPIO_NUM_19
6277
#define I2S_PORT I2S_NUM_0
6378
#define I2S_FORMAT I2S_CHANNEL_FMT_ONLY_RIGHT
64-
6579
#define SERIAL Serial
6680

67-
#elif defined(BOARD_TESTING)
81+
#define USE_MIC_SPH0645
6882

6983
#else
7084
#error "Please select a board from the list in board.h!"

noisemeter-device/noisemeter-device.ino

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include <list>
3535
#include <optional>
3636

37-
#ifdef BOARD_ESP32_PCB
37+
#if defined(BOARD_REV4) || defined(BOARD_REV123)
3838
HWCDC USBSerial;
3939
#endif
4040

@@ -211,15 +211,19 @@ void loop()
211211
}
212212
}
213213

214-
#if defined(BOARD_ESP32_PCB)
214+
#if defined(BOARD_REV4) || defined(BOARD_REV123)
215215
// We have WiFi: also check for software updates
216216
if (++wakeupCount >= OTA_INTERVAL_SEC / UPLOAD_INTERVAL_SEC) {
217217
wakeupCount = 0;
218218
SERIAL.println("Checking for updates...");
219219

220220
const auto ota = api.getLatestSoftware();
221221
if (ota) {
222-
if (ota->version.compareTo(NOISEMETER_VERSION) > 0) {
222+
if (ota->version.compareTo(NOISEMETER_VERSION) > 0
223+
#if defined(BOARD_REV123)
224+
&& ota->version.startsWith("0.3.")
225+
#endif // defined(BOARD_REV123)
226+
) {
223227
SERIAL.print(ota->version);
224228
SERIAL.println(" available!");
225229

@@ -231,7 +235,7 @@ void loop()
231235
} /*else { SERIAL.println("No new updates."); }*/
232236
} else { SERIAL.println("Failed to reach update server!"); }
233237
}
234-
#endif // BOARD_ESP32_PCB
238+
#endif // defined(BOARD_REV4) || defined(BOARD_REV123)
235239
}
236240
#endif // !UPLOAD_DISABLED
237241
}

noisemeter-device/secret-store.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "secret-store.h"
1818
#include "board.h"
1919

20-
#if defined(BOARD_ESP32_PCB)
20+
#if defined(BOARD_REV4) || defined(BOARD_REV123)
2121

2222
#include <esp_hmac.h>
2323
#include <mbedtls/aes.h>
@@ -56,7 +56,7 @@ void SecretStore::decrypt(const uint8_t *in, char *out, unsigned N) const noexce
5656
in, reinterpret_cast<uint8_t *>(out));
5757
}
5858

59-
#else // !defined(BOARD_ESP32_PCB)
59+
#else // BOARD_BREADBOARD
6060

6161
#include <algorithm>
6262

@@ -70,5 +70,5 @@ void SecretStore::decrypt(const uint8_t *in, char *out, unsigned N) const noexce
7070
std::copy(in, in + N, out);
7171
}
7272

73-
#endif // defined(BOARD_ESP32_PCB)
73+
#endif
7474

noisemeter-device/spl-meter.cpp

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020

2121
#include <cmath>
2222

23+
#if defined(USE_MIC_IM64D130A)
2324
/** Sample size time duration to use for Leq calculation (seconds). */
2425
static constexpr auto LEQ_PERIOD = 1.f;
25-
/** Number of samples to use for a Leq decibel calculation. */
26-
static constexpr auto SAMPLES_LEQ = SPLMeter::SAMPLE_RATE * LEQ_PERIOD;
2726
/** Specifies the type of weighting to use for decibel calculation: dBA, dBC, or None/Z. */
2827
static constexpr auto& WEIGHTING = A_weighting;
2928
/** Specifies the microphone's equalization filter. See pre-defined filters or set to 'None'. */
@@ -41,6 +40,19 @@ static constexpr auto MIC_OVERLOAD_DB = 130.f;
4140
static constexpr auto MIC_NOISE_DB = 30.f;
4241
/** Linear calibration offset to apply to calculated decibel values. */
4342
static constexpr auto MIC_OFFSET_DB = 0.f;
43+
#elif defined(USE_MIC_SPH0645)
44+
static constexpr auto LEQ_PERIOD = 1.f;
45+
static constexpr auto& WEIGHTING = A_weighting;
46+
static constexpr auto& MIC_EQUALIZER = SPH0645LM4H_B_RB;
47+
static constexpr auto MIC_BITS = 18u;
48+
static constexpr auto MIC_SENSITIVITY = -26.f;
49+
static constexpr auto MIC_REF_DB = 94.f;
50+
static constexpr auto MIC_OVERLOAD_DB = 120.f;
51+
static constexpr auto MIC_NOISE_DB = 29.f;
52+
static constexpr auto MIC_OFFSET_DB = 0.f;
53+
#else
54+
#error "Unsupported microphone! Use either SPH0645 or IM64D130A."
55+
#endif
4456

4557
/** Reference amplitude level for the microphone. */
4658
static constexpr auto MIC_REF_AMPL = std::pow(10.f, MIC_SENSITIVITY / 20.f) * ((1 << (MIC_BITS - 1)) - 1);
@@ -52,9 +64,19 @@ void SPLMeter::initMicrophone() noexcept
5264
/* Setp 1: Determine the I2S channel configuration and allocate RX channel only
5365
* The default configuration can be generated by the helper macro,
5466
* 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);
67+
i2s_chan_config_t rx_chan_cfg = {
68+
.id = I2S_PORT,
69+
.role = I2S_ROLE_MASTER,
70+
.dma_desc_num = 15,
71+
.dma_frame_num = 400,
72+
.auto_clear_after_cb = false,
73+
.auto_clear_before_cb = false,
74+
.allow_pd = false,
75+
.intr_priority = 0,
76+
};
5677
ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, nullptr, &rx_chan));
5778

79+
#if defined(USE_MIC_IM64D130A)
5880
/* Step 2: Setting the configurations of PDM RX mode and initialize the RX channel
5981
* The slot configuration and clock configuration can be generated by the macros
6082
* These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM RX mode.
@@ -71,6 +93,26 @@ void SPLMeter::initMicrophone() noexcept
7193
};
7294

7395
ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg));
96+
#elif defined(USE_MIC_SPH0645)
97+
i2s_std_config_t std_rx_cfg = {
98+
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
99+
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO),
100+
.gpio_cfg = {
101+
.mclk = I2S_GPIO_UNUSED,
102+
.bclk = I2S_SCK,
103+
.ws = I2S_WS,
104+
.dout = I2S_GPIO_UNUSED,
105+
.din = I2S_SD,
106+
.invert_flags = {
107+
.mclk_inv = false,
108+
.bclk_inv = false,
109+
.ws_inv = false,
110+
},
111+
},
112+
};
113+
114+
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &std_rx_cfg));
115+
#endif
74116

75117
/* Step 3: Enable the rx channels before reading data */
76118
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
@@ -79,26 +121,40 @@ void SPLMeter::initMicrophone() noexcept
79121

80122
std::optional<float> SPLMeter::readMicrophoneData() noexcept
81123
{
82-
i2sRead();
124+
const auto bread = i2sRead();
83125

126+
#if defined(USE_MIC_IM64D130A)
84127
// I2S samples are 16-bit integers stored into samples's memory.
85128
// These need to be expanded into 32-bit floats for processing.
86129
// 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++)
130+
const auto sread = bread / sizeof(int16_t);
131+
auto src = reinterpret_cast<const int16_t *>(samples.data()) + sread;
132+
auto dst = samples.data() + sread;
133+
for (int i = 0; i < sread; i++)
90134
*--dst = *--src;
135+
#elif defined(USE_MIC_SPH0645)
136+
// Convert (including shifting) integer microphone values to floats,
137+
// using the same buffer (assumed sample size is same as size of float),
138+
// to save a bit of memory
139+
const auto sread = bread / sizeof(int32_t) / 2;
140+
auto src = reinterpret_cast<const int32_t *>(samples.data());
141+
auto dst = samples.data();
142+
for (int i = 0; i < sread; i++) {
143+
const auto conv = src[i * 2] >> ((sizeof(int32_t) * 8u) - MIC_BITS);
144+
dst[i] = conv;
145+
}
146+
#endif
91147

92148
// Apply equalization and calculate Z-weighted sum of squares,
93149
// writes filtered samples back to the same buffer.
94150
const auto fptr = samples.data();
95-
const auto sum_sqr_SPL = MIC_EQUALIZER.filter(fptr, fptr, samples.size());
151+
const auto sum_sqr_SPL = MIC_EQUALIZER.filter(fptr, fptr, sread);
96152

97153
// Apply weighting and calucate weigthed sum of squares
98-
const auto sum_sqr_weighted = WEIGHTING.filter(fptr, fptr, samples.size());
154+
const auto sum_sqr_weighted = WEIGHTING.filter(fptr, fptr, sread);
99155

100156
// Calculate dB values relative to MIC_REF_AMPL and adjust for microphone reference
101-
const auto short_RMS = std::sqrt(sum_sqr_SPL / samples.size());
157+
const auto short_RMS = std::sqrt(sum_sqr_SPL / sread);
102158
const auto short_SPL_dB = MIC_OFFSET_DB + MIC_REF_DB + 20 * std::log10(short_RMS / MIC_REF_AMPL);
103159

104160
// In case of acoustic overload or below noise floor measurement, report infinty Leq value
@@ -110,7 +166,7 @@ std::optional<float> SPLMeter::readMicrophoneData() noexcept
110166

111167
// Accumulate Leq sum
112168
Leq_sum_sqr += sum_sqr_weighted;
113-
Leq_samples += samples.size();
169+
Leq_samples += sread;
114170

115171
// When we gather enough samples, calculate new Leq value
116172
if (Leq_samples >= SAMPLE_RATE * LEQ_PERIOD) {
@@ -124,14 +180,20 @@ std::optional<float> SPLMeter::readMicrophoneData() noexcept
124180
}
125181
}
126182

127-
void SPLMeter::i2sRead() noexcept
183+
size_t SPLMeter::i2sRead() noexcept
128184
{
129185
// Block and wait for microphone values from I2S
130186
//
131187
// Data is moved from DMA buffers to our 'samples' buffer by the driver ISR
132188
// and when there is requested ammount of data, task is unblocked
133189
size_t bread;
134-
(void)bread;
190+
191+
#if defined(USE_MIC_IM64D130A)
135192
i2s_channel_read(i2s_handle, samples.data(), samples.size() * sizeof(int16_t), &bread, portMAX_DELAY);
193+
#elif defined(USE_MIC_SPH0645)
194+
i2s_channel_read(i2s_handle, samples.data(), samples.size() * sizeof(int32_t), &bread, portMAX_DELAY);
195+
#endif
196+
197+
return bread;
136198
}
137199

noisemeter-device/spl-meter.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@
1919
#ifndef SPL_METER_H
2020
#define SPL_METER_H
2121

22+
#if defined(USE_MIC_IM64D130A)
23+
#include <driver/i2s_pdm.h>
24+
#elif defined(USE_MIC_SPH0645)
25+
#include <driver/i2s_std.h>
26+
#endif
27+
2228
#include <array>
2329
#include <cstdint>
24-
#include <driver/i2s_pdm.h>
2530
#include <optional>
2631

2732
/**
@@ -44,7 +49,7 @@ class SPLMeter
4449

4550
private:
4651
/** The number of samples to keep in the sample buffer. */
47-
static constexpr auto SAMPLES_SHORT = SAMPLE_RATE / 8u;
52+
static constexpr auto SAMPLES_SHORT = SAMPLE_RATE / 16u;
4853

4954
/** Buffer to store microphone samples in for reading and processing. */
5055
alignas(4)
@@ -58,7 +63,7 @@ class SPLMeter
5863
i2s_chan_handle_t i2s_handle;
5964

6065
/** Reads enough samples from the microphone to fill the samples buffer. */
61-
void i2sRead() noexcept;
66+
size_t i2sRead() noexcept;
6267
};
6368

6469
#endif // SPL_METER_H

platformio.ini

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
[platformio]
1212
src_dir = noisemeter-device
1313
include_dir = noisemeter-device
14-
default_envs = esp32-pcb
14+
default_envs = rev4
1515

1616
[env]
1717
extra_scripts = build_hooks.py
@@ -26,7 +26,6 @@ build_unflags =
2626
build_flags =
2727
-std=gnu++17
2828
-DNO_GLOBAL_EEPROM
29-
-DNOISEMETER_VERSION=\"0.4.0\"
3029
-Wall -Wextra
3130

3231
# Optional build flags:
@@ -37,13 +36,23 @@ build_flags =
3736
# Disable WiFi and data upload:
3837
# -DUPLOAD_DISABLED
3938

40-
[env:esp32-pcb]
39+
# v0.3.x is for pre-rev4 hardware (ESP32-C3)
40+
# v0.4.x and beyond is for rev4 and later (ESP32-S3)
41+
42+
[env:rev4]
4143
extra_scripts = build_hooks.py
4244
board = esp32-s3-devkitm-1
4345
board_build.f_cpu = 80000000L
44-
build_flags = ${env.build_flags} -DBOARD_ESP32_PCB
46+
build_flags = ${env.build_flags} -DBOARD_REV4 -DNOISEMETER_VERSION=\"0.4.1\"
47+
48+
[env:rev123]
49+
extra_scripts = build_hooks.py
50+
board = esp32-c3-devkitm-1
51+
board_build.f_cpu = 160000000L
52+
board_build.flash_mode = qio
53+
build_flags = ${env.build_flags} -DBOARD_REV123 -DNOISEMETER_VERSION=\"0.3.0\"
4554

46-
[env:esp32-breadboard]
55+
[env:breadboard]
4756
board = upesy_wroom
48-
build_flags = ${env.build_flags} -DBOARD_ESP32_BREADBOARD
57+
build_flags = ${env.build_flags} -DBOARD_BREADBOARD
4958

0 commit comments

Comments
 (0)