-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathlistener.ino
252 lines (208 loc) · 6.19 KB
/
listener.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
******************************************************************************
* @file listener.ino
* @author Joe Todd
* @version
* @date November 2017
* @brief I2S interface for ESP8266 and SPH0645 MEMS microphone.
*
******************************************************************************/
#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
#include "i2s_reg.h"
#include "slc_register.h"
#include "esp8266_peri.h"
void rom_i2c_writeReg_Mask(int, int, int, int, int, int);
}
// #define DEBUG
#define I2S_CLK_FREQ 160000000 // Hz
#define I2S_24BIT 3 // I2S 24 bit half data
#define I2S_LEFT 2 // I2S RX Left channel
#define I2SI_DATA 12 // I2S data on GPIO12
#define I2SI_BCK 13 // I2S clk on GPIO13
#define I2SI_WS 14 // I2S select on GPIO14
#define SLC_BUF_CNT 8 // Number of buffers in the I2S circular buffer
#define SLC_BUF_LEN 64 // Length of one buffer, in 32-bit words.
/**
* Convert I2S data.
* Data is 18 bit signed, MSBit first, two's complement.
* Note: We can only send 31 cycles from ESP8266 so we only
* shift by 13 instead of 14.
* The 240200 is a magic calibration number I haven't figured
* out yet.
*/
#define convert(sample) (((int32_t)(sample) >> 13) - 240200)
typedef struct {
uint32_t blocksize : 12;
uint32_t datalen : 12;
uint32_t unused : 5;
uint32_t sub_sof : 1;
uint32_t eof : 1;
volatile uint32_t owner : 1;
uint32_t *buf_ptr;
uint32_t *next_link_ptr;
} sdio_queue_t;
static sdio_queue_t i2s_slc_items[SLC_BUF_CNT]; // I2S DMA buffer descriptors
static uint32_t *i2s_slc_buf_pntr[SLC_BUF_CNT]; // Pointer to the I2S DMA buffer data
static volatile uint32_t rx_buf_cnt = 0;
static volatile uint32_t rx_buf_idx = 0;
static volatile bool rx_buf_flag = false;
void i2s_init();
void slc_init();
void i2s_set_rate(uint32_t rate);
void slc_isr(void *para);
/* Main -----------------------------------------------------------------------*/
void
setup()
{
rx_buf_cnt = 0;
pinMode(I2SI_WS, OUTPUT);
pinMode(I2SI_BCK, OUTPUT);
pinMode(I2SI_DATA, INPUT);
WiFi.forceSleepBegin();
delay(500);
Serial.begin(115200);
slc_init();
i2s_init();
}
void
loop()
{
int32_t value;
char withScale[256];
if (rx_buf_flag) {
for (int x = 0; x < SLC_BUF_LEN; x++) {
if (i2s_slc_buf_pntr[rx_buf_idx][x] > 0) {
#ifdef DEBUG
Serial.print(i2s_slc_buf_pntr[rx_buf_idx][x], BIN);
Serial.println("");
#else
value = convert(i2s_slc_buf_pntr[rx_buf_idx][x]);
sprintf(withScale, "-1 %f 1", (float)value / 4096.0f);
Serial.println(withScale);
#endif
}
}
rx_buf_flag = false;
}
}
/* Function definitions -------------------------------------------------------*/
/**
* Initialise I2S as a RX master.
*/
void
i2s_init()
{
// Config RX pin function
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_I2SI_DATA);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_I2SI_BCK);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_I2SI_WS);
// Enable a 160MHz clock
I2S_CLK_ENABLE();
// Reset I2S
I2SC &= ~(I2SRST);
I2SC |= I2SRST;
I2SC &= ~(I2SRST);
// Reset DMA
I2SFC &= ~(I2SDE | (I2SRXFMM << I2SRXFM));
// Enable DMA
I2SFC |= I2SDE | (I2S_24BIT << I2SRXFM);
// Set RX single channel (left)
I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM));
I2SCC |= (I2S_LEFT << I2SRXCM);
i2s_set_rate(16667);
// Set RX data to be received
I2SRXEN = SLC_BUF_LEN;
// Bits mode
I2SC |= (15 << I2SBM);
// Start receiver
I2SC |= I2SRXS;
}
/**
* Set I2S clock.
* I2S bits mode only has space for 15 extra bits,
* 31 in total. The
*/
void
i2s_set_rate(uint32_t rate)
{
uint32_t i2s_clock_div = (I2S_CLK_FREQ / (rate * 31 * 2)) & I2SCDM;
uint32_t i2s_bck_div = (I2S_CLK_FREQ / (rate * i2s_clock_div * 31 * 2)) & I2SBDM;
#ifdef DEBUG
Serial.printf("Rate %u Div %u Bck %u Freq %u\n",
rate, i2s_clock_div, i2s_bck_div, I2S_CLK_FREQ / (i2s_clock_div * i2s_bck_div * 31 * 2));
#endif
// RX master mode, RX MSB shift, right first, msb right
I2SC &= ~(I2STSM | I2SRSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD));
I2SC |= I2SRF | I2SMR | I2SRMS | (i2s_bck_div << I2SBD) | (i2s_clock_div << I2SCD);
}
/**
* Initialize the SLC module for DMA operation.
* Counter intuitively, we use the TXLINK here to
* receive data.
*/
void
slc_init()
{
for (int x = 0; x < SLC_BUF_CNT; x++) {
i2s_slc_buf_pntr[x] = (uint32_t *)malloc(SLC_BUF_LEN * 4);
for (int y = 0; y < SLC_BUF_LEN; y++) i2s_slc_buf_pntr[x][y] = 0;
i2s_slc_items[x].unused = 0;
i2s_slc_items[x].owner = 1;
i2s_slc_items[x].eof = 0;
i2s_slc_items[x].sub_sof = 0;
i2s_slc_items[x].datalen = SLC_BUF_LEN * 4;
i2s_slc_items[x].blocksize = SLC_BUF_LEN * 4;
i2s_slc_items[x].buf_ptr = (uint32_t *)&i2s_slc_buf_pntr[x][0];
i2s_slc_items[x].next_link_ptr = (uint32_t *)((x < (SLC_BUF_CNT - 1)) ? (&i2s_slc_items[x + 1]) : (&i2s_slc_items[0]));
}
// Reset DMA
ETS_SLC_INTR_DISABLE();
SLCC0 |= SLCRXLR | SLCTXLR;
SLCC0 &= ~(SLCRXLR | SLCTXLR);
SLCIC = 0xFFFFFFFF;
// Configure DMA
SLCC0 &= ~(SLCMM << SLCM); // Clear DMA MODE
SLCC0 |= (1 << SLCM); // Set DMA MODE to 1
SLCRXDC |= SLCBINR | SLCBTNR; // Enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE
// Feed DMA the 1st buffer desc addr
SLCTXL &= ~(SLCTXLAM << SLCTXLA);
SLCTXL |= (uint32_t)&i2s_slc_items[0] << SLCTXLA;
ETS_SLC_INTR_ATTACH(slc_isr, NULL);
// Enable EOF interrupt
SLCIE = SLCITXEOF;
ETS_SLC_INTR_ENABLE();
// Start transmission
SLCTXL |= SLCTXLS;
}
/**
* Triggered when SLC has finished writing
* to one of the buffers.
*/
void ICACHE_RAM_ATTR
slc_isr(void *para)
{
uint32_t status;
status = SLCIS;
SLCIC = 0xFFFFFFFF;
if (status == 0) {
return;
}
if (status & SLCITXEOF) {
// We have received a frame
ETS_SLC_INTR_DISABLE();
sdio_queue_t *finished = (sdio_queue_t*)SLCTXEDA;
finished->eof = 0;
finished->owner = 1;
finished->datalen = 0;
for (int i = 0; i < SLC_BUF_CNT; i++) {
if (finished == &i2s_slc_items[i]) {
rx_buf_idx = i;
}
}
rx_buf_cnt++;
rx_buf_flag = true;
ETS_SLC_INTR_ENABLE();
}
}