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