arduino-audio-tools
Loading...
Searching...
No Matches
I2SNanoSenseBLE.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
4
5#if defined(USE_NANO33BLE)
6
11
12#define IS_I2S_IMPLEMENTED
13
14namespace audio_tools {
15
16static int i2s_buffer_size = 0;
18static uint8_t *p_i2s_array = nullptr; // current array
19static uint8_t *p_i2s_array_1 = nullptr; // array 1
20static uint8_t *p_i2s_array_2 = nullptr; // array 2
22// alternative API
23static Stream *p_nano_ble_stream = nullptr;
24
29 int id;
30 float freq; // in mhz
31};
32
47
52 int id;
53 float ratio;
54};
55
62
63void I2S_IRQWrite(void) {
64 // Handle Wrtie
65 if (NRF_I2S->EVENTS_TXPTRUPD == 1) {
66 size_t eff_read = 0;
67
68 // toggle arrays to avoid noise
70
71 if (p_nano_ble_stream != nullptr) {
72 // Alternative API via Stream
74 } else {
75 // Using readArray
77 }
78 // if we did not get any valid data we provide silence
81 // allow checking for underflows
83 }
84 NRF_I2S->TXD.PTR = (uint32_t)p_i2s_array;
85 NRF_I2S->EVENTS_TXPTRUPD = 0;
86 }
87}
88
89void I2S_IRQRead(void) {
90 // Handle Read
91 if (NRF_I2S->EVENTS_RXPTRUPD == 1) {
92 // reading from pins writing to buffer - overwrite oldest data on overflow
94 // switch buffer assuming that this is necessary like in the write case
96 NRF_I2S->RXD.PTR = (uint32_t)p_i2s_array;
97 NRF_I2S->EVENTS_RXPTRUPD = 0;
98 }
99}
100
104void I2S_IRQHandler(void) {
105 // prevent NPE
106 if (p_i2s_buffer == nullptr || p_i2s_array == 0) {
107 NRF_I2S->EVENTS_TXPTRUPD = 0;
108 NRF_I2S->EVENTS_RXPTRUPD = 0;
109 return;
110 }
111
112 I2S_IRQWrite();
113 I2S_IRQRead();
114}
115
126 friend class I2SStream;
127
128 public:
129 I2SDriverNanoBLE() = default;
130
133 I2SConfigStd c(mode);
134 return c;
135 }
137 bool setAudioInfo(AudioInfo) { return false; }
138
140 bool begin(RxTxMode mode = TX_MODE) { return begin(defaultConfig(mode)); }
141
144 TRACEI();
145 cfg.logInfo();
146 this->cfg = cfg;
147
148 if (cfg.bits_per_sample == 32) {
149 LOGE("32 bits not supported");
150 return false;
151 }
152
153 if (!setupBuffers()) {
154 LOGE("out of memory");
155 return false;
156 }
157
158 // setup IRQ
161
162 if (!setupRxTx(cfg)) {
163 return false;
164 }
167 setupMode(cfg);
168 setupPins(cfg);
169
170 // TX_MODE is started with first write
171 if (cfg.rx_tx_mode == RX_MODE || p_nano_ble_stream != nullptr) {
173 }
174
175 return true;
176 }
177
178 int available() {
179 if (cfg.rx_tx_mode == TX_MODE) return 0;
180 return p_i2s_buffer->available();
181 }
182
184 if (cfg.rx_tx_mode == RX_MODE) return 0;
186 }
187
189 void end() {
190 LOGD(__func__);
191 // stop task
192 NRF_I2S->TASKS_START = 0;
193 // disble I2S
194 NRF_I2S->ENABLE = 0;
195
197
198 is_active = false;
199 }
200
202 I2SConfigStd config() { return cfg; }
203
205 size_t writeBytes(const void *src, size_t size_bytes) {
206 size_t result = p_i2s_buffer->writeArray((uint8_t *)src, size_bytes);
207
208 // activate I2S when the buffer is full
209 if (!is_active && result < size_bytes) {
211 }
212 return result;
213 }
214
216 size_t readBytes(void *dest, size_t size_bytes) {
217 size_t result = p_i2s_buffer->readArray((uint8_t *)dest, size_bytes);
218 return result;
219 }
220
222 void setStream(Stream &stream) { p_nano_ble_stream = &stream; }
223
225 void clearStream() { p_nano_ble_stream = nullptr; }
226
227 void setBufferSize(int size) { i2s_buffer_size = size; }
228
229 protected:
231 bool is_active = false;
232
235 TRACED();
236 switch (cfg.rx_tx_mode) {
237 case TX_MODE:
238 // Enable transmission
239 NRF_I2S->CONFIG.TXEN =
241 return true;
242 case RX_MODE:
243 // Enable reception
244 NRF_I2S->CONFIG.RXEN =
246 return true;
247 default:
248 LOGE("rx_tx_mode not supported");
249 return false;
250 }
251 }
252
255 TRACED();
256
257 // Enable MCK generator if in master mode
258 if (cfg.is_master) {
259 NRF_I2S->CONFIG.MCKEN =
261 }
262
263 // find closest frequency for requested sample_rate
264 float freq_requested = cfg.sample_rate; // * cfg.bits_per_sample ;
265 float selected_freq = 0;
266 for (auto freq : freq_table) {
267 for (auto div : ratio_table) {
268 float freq_value = freq.freq * 1000000 / div.ratio;
271 // MCKFREQ
272 NRF_I2S->CONFIG.MCKFREQ = freq.id << I2S_CONFIG_MCKFREQ_MCKFREQ_Pos;
273 // Ratio
274 NRF_I2S->CONFIG.RATIO = div.id << I2S_CONFIG_RATIO_RATIO_Pos;
276 LOGD("frequency requested %f vs %f", freq_requested, selected_freq);
277 }
278 }
279 }
280 LOGI("Frequency req. %f vs eff. %f", freq_requested, selected_freq);
281 }
282
285 TRACED();
287 switch (cfg.bits_per_sample) {
288 case 8:
291 break;
292 case 16:
295 break;
296 case 24:
299 break;
300 default:
301 LOGE("Unsupported bit width: %d", cfg.bits_per_sample);
302 }
303 }
304
307 TRACED();
308 // setup mode
309 switch (cfg.i2s_format) {
310 case I2S_STD_FORMAT:
312 case I2S_MSB_FORMAT:
318 ;
319 break;
320 case I2S_LSB_FORMAT:
326 ;
327 break;
328 default:
329 LOGW("i2s_format not supported");
330 }
331 }
332#ifdef IS_ZEPHYR
333 int digitalPinToPinName(int pin) {return pin;}
334#endif
336 int getPinName(int pin) {
337#if defined(USE_ALT_PIN_SUPPORT)
338 return cfg.is_arduino_pin_numbers ? digitalPinToPinName(pin) : pin;
339#else
340 return digitalPinToPinName(pin);
341#endif
342 }
343
346 TRACED();
347
348 // MCK
349 if (cfg.is_master && cfg.pin_mck >= 0) {
351 }
352 // SCK - bit clock
354 // LRCK
356 // i2s Data Pins
357 switch (cfg.rx_tx_mode) {
358 case TX_MODE:
359 NRF_I2S->PSEL.SDOUT = getPinName(cfg.pin_data)
361 break;
362 case RX_MODE:
364 break;
365 default:
366 TRACEW();
367 }
368 }
369
371 unsigned long getINTENSET() {
372 unsigned long result = 0;
373 switch (cfg.rx_tx_mode) {
374 case TX_MODE:
376 break;
377 case RX_MODE:
379 break;
380 default:
381 TRACEE();
382 }
383 return result;
384 }
385
388 TRACED();
389 // Use stereo
392 // Setup master or slave mode
393 NRF_I2S->CONFIG.MODE =
396
397 // initial empty buffer
398 NRF_I2S->TXD.PTR = (uint32_t)p_i2s_array;
399 NRF_I2S->RXD.PTR = (uint32_t)p_i2s_array;
400 // define copy size (always defined as number of 32 bits)
401 NRF_I2S->RXTXD.MAXCNT = i2s_buffer_size / 4;
402
403 NRF_I2S->INTENSET = getINTENSET();
404
405 // ensble I2S
406 NRF_I2S->ENABLE = 1;
407 // start task
408 NRF_I2S->TASKS_START = 1;
409
410 is_active = true;
411 }
412
415 TRACED();
417
418 if (p_i2s_array == nullptr) {
422 } else {
425 }
426
427 // allocate buffer only when needed
428 if (p_i2s_buffer == nullptr && p_nano_ble_stream == nullptr) {
430 }
431
432 // on stream option we only need to have the arrays allocated
433 if (p_nano_ble_stream != nullptr) {
434 return p_i2s_array_1 != nullptr && p_i2s_array_2 != nullptr;
435 }
436 return p_i2s_array_1 != nullptr && p_i2s_array_2 != nullptr &&
437 p_i2s_buffer != nullptr;
438 }
439
442 TRACED();
443 i2s_buffer_size = 0;
444
445 p_i2s_array = nullptr;
446 delete p_i2s_array_1;
447 p_i2s_array_1 = nullptr;
448 delete p_i2s_array_2;
449 p_i2s_array_2 = nullptr;
450
451 delete p_i2s_buffer;
452 p_i2s_buffer = nullptr;
453 }
454};
455
456using I2SDriver = I2SDriverNanoBLE;
457
458} // namespace audio_tools
459
460#endif
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define TRACEW()
Definition AudioLoggerIDF.h:33
#define TRACEE()
Definition AudioLoggerIDF.h:34
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Shared functionality of all buffers.
Definition Buffers.h:22
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:33
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:55
virtual int writeArrayOverwrite(const T data[], int len)
Fills the buffer data and overwrites the oldest data if the buffer is full.
Definition Buffers.h:72
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual int available()=0
provides the number of entries that are available to read
Configuration for i2s.
Definition I2SConfigStd.h:17
int pin_mck
Definition I2SConfigStd.h:58
RxTxMode rx_tx_mode
public settings
Definition I2SConfigStd.h:48
int pin_ws
Definition I2SConfigStd.h:54
int pin_data
Definition I2SConfigStd.h:56
bool is_master
Definition I2SConfigStd.h:49
int pin_bck
Definition I2SConfigStd.h:55
I2SFormat i2s_format
Definition I2SConfigStd.h:50
void logInfo(const char *source="")
Definition I2SConfigStd.h:73
int buffer_size
Definition I2SConfigStd.h:52
Basic I2S API - for the Arduino Nano BLE Sense See https://content.arduino.cc/assets/Nano_BLE_MCU-nRF...
Definition I2SNanoSenseBLE.h:125
bool setupBuffers()
dynamic buffer management
Definition I2SNanoSenseBLE.h:414
bool setAudioInfo(AudioInfo)
Potentially updates the sample rate (if supported)
Definition I2SNanoSenseBLE.h:137
void setupPins(I2SConfigStd cfg)
setup pins
Definition I2SNanoSenseBLE.h:345
I2SConfigStd config()
provides the actual configuration
Definition I2SNanoSenseBLE.h:202
bool is_active
Definition I2SNanoSenseBLE.h:231
int available()
Definition I2SNanoSenseBLE.h:178
void clearStream()
Deactivate alternative API: don't forget to call begin()
Definition I2SNanoSenseBLE.h:225
void setStream(Stream &stream)
alternative API which provides the data directly via a Stream
Definition I2SNanoSenseBLE.h:222
I2SConfigStd defaultConfig(RxTxMode mode)
Provides the default configuration.
Definition I2SNanoSenseBLE.h:132
unsigned long getINTENSET()
Determine the INTENSET value.
Definition I2SNanoSenseBLE.h:371
int availableForWrite()
Definition I2SNanoSenseBLE.h:183
void setupBitWidth(I2SConfigStd cfg)
setup SWIDTH
Definition I2SNanoSenseBLE.h:284
int getPinName(int pin)
Provides the arduino or unconverted pin name.
Definition I2SNanoSenseBLE.h:336
bool begin(I2SConfigStd cfg)
starts the I2S
Definition I2SNanoSenseBLE.h:143
void end()
stops the I2S
Definition I2SNanoSenseBLE.h:189
void setupMode(I2SConfigStd cfg)
setup format and align
Definition I2SNanoSenseBLE.h:306
void setBufferSize(int size)
Definition I2SNanoSenseBLE.h:227
size_t writeBytes(const void *src, size_t size_bytes)
writes the data to the I2S buffer
Definition I2SNanoSenseBLE.h:205
bool setupRxTx(I2SConfigStd cfg)
setup TXEN or RXEN
Definition I2SNanoSenseBLE.h:234
size_t readBytes(void *dest, size_t size_bytes)
reads the data from the I2S buffer
Definition I2SNanoSenseBLE.h:216
bool begin(RxTxMode mode=TX_MODE)
starts the I2S with the default config in TX Mode
Definition I2SNanoSenseBLE.h:140
void releaseBuffers()
Release buffers.
Definition I2SNanoSenseBLE.h:441
I2SConfigStd cfg
Definition I2SNanoSenseBLE.h:230
void setupClock(I2SConfigStd cfg)
setup MCKFREQ and RATIO
Definition I2SNanoSenseBLE.h:254
void startI2SActive()
Start IRQ and I2S.
Definition I2SNanoSenseBLE.h:387
We support the Stream interface for the I2S access. In addition we allow a separate mute pin which mi...
Definition I2SStream.h:33
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:663
Definition NoArduino.h:142
virtual size_t readBytes(uint8_t *data, size_t len)
Definition NoArduino.h:147
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:30
@ TX_MODE
Definition AudioTypes.h:30
@ RX_MODE
Definition AudioTypes.h:30
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
static const Nano_BLE_freq_info freq_table[]
Definition I2SNanoSenseBLE.h:33
static uint8_t * p_i2s_array_2
Definition I2SNanoSenseBLE.h:20
I2SDriverESP32 I2SDriver
Definition I2SESP32.h:400
static uint8_t * p_i2s_array
Definition I2SNanoSenseBLE.h:18
void I2S_IRQWrite(void)
Definition I2SNanoSenseBLE.h:63
@ I2S_STD_FORMAT
Definition AudioTypes.h:421
@ I2S_PHILIPS_FORMAT
Definition AudioTypes.h:424
@ I2S_LSB_FORMAT
Definition AudioTypes.h:422
@ I2S_LEFT_JUSTIFIED_FORMAT
Definition AudioTypes.h:426
@ I2S_RIGHT_JUSTIFIED_FORMAT
Definition AudioTypes.h:425
@ I2S_MSB_FORMAT
Definition AudioTypes.h:423
void I2S_IRQHandler(void)
Definition I2SNanoSenseBLE.h:104
static const Nano_BLE_ratio_info ratio_table[]
Definition I2SNanoSenseBLE.h:56
static uint8_t * p_i2s_array_1
Definition I2SNanoSenseBLE.h:19
void I2S_IRQRead(void)
Definition I2SNanoSenseBLE.h:89
static uint32_t i2s_underflow_count
Definition I2SNanoSenseBLE.h:21
static int i2s_buffer_size
Definition I2SNanoSenseBLE.h:16
static Stream * p_nano_ble_stream
Definition I2SNanoSenseBLE.h:23
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:512
static BaseBuffer< uint8_t > * p_i2s_buffer
Definition I2SNanoSenseBLE.h:17
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:55
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:61
Mapping Frequency constants to available frequencies.
Definition I2SNanoSenseBLE.h:28
float freq
Definition I2SNanoSenseBLE.h:30
int id
Definition I2SNanoSenseBLE.h:29
Mapping from Ratio Constants to frequency ratios.
Definition I2SNanoSenseBLE.h:51
float ratio
Definition I2SNanoSenseBLE.h:53
int id
Definition I2SNanoSenseBLE.h:52