1
+ /*
2
+ PDM.cpp - library to interface with STM32 PDM microphones
3
+ Part of Arduino - http://www.arduino.cc/
4
+
5
+ Copyright (c) 2020 Arduino SA
6
+
7
+ This library is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU Lesser General Public
9
+ License as published by the Free Software Foundation; either
10
+ version 2.1 of the License, or (at your option) any later version.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General
18
+ Public License along with this library; if not, write to the
19
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20
+ Boston, MA 02111-1307 USA
21
+ */
22
+
23
+ #ifdef TARGET_STM
24
+
25
+ #include " PDM.h"
26
+ #include " audio.h"
27
+ #include " mbed.h"
28
+
29
+ #define AUDIO_FREQUENCY BSP_AUDIO_FREQUENCY_16K
30
+ #define AUDIO_IN_PDM_BUFFER_SIZE (uint32_t )(128 )
31
+
32
+ // ALIGN_32BYTES (uint16_t recordPDMBuf[AUDIO_IN_PDM_BUFFER_SIZE]) __attribute__((section(".OPEN_AMP_SHMEM")));
33
+ // FIXME: need to add an entry for RAM_D3 to linker script
34
+ uint16_t * recordPDMBuf = (uint16_t *)0x38000000 ;
35
+
36
+ PDMClass::PDMClass (int dinPin, int clkPin, int pwrPin) :
37
+ _dinPin(dinPin),
38
+ _clkPin(clkPin),
39
+ _pwrPin(pwrPin),
40
+ _onReceive(NULL )
41
+ {
42
+ }
43
+
44
+ PDMClass::~PDMClass ()
45
+ {
46
+ }
47
+
48
+ int PDMClass::begin (int channels, long sampleRate) {
49
+
50
+ _channels = channels;
51
+
52
+ // fixme: only works in stereo mode
53
+ channels = 2 ;
54
+
55
+ setBufferSize (AUDIO_IN_PDM_BUFFER_SIZE / 4 * channels);
56
+
57
+ if (isBoardRev2 ()) {
58
+ mbed::I2C i2c (PB_7, PB_6);
59
+ char data[2 ];
60
+
61
+ // SW2 to 3.3V (SW2_VOLT)
62
+ data[0 ] = 0x3B ;
63
+ data[1 ] = 0xF ;
64
+ i2c.write (8 << 1 , data, sizeof (data));
65
+
66
+ // SW1 to 3.0V (SW1_VOLT)
67
+ data[0 ] = 0x35 ;
68
+ data[1 ] = 0xF ;
69
+ i2c.write (8 << 1 , data, sizeof (data));
70
+ }
71
+
72
+ BSP_AUDIO_IN_SelectInterface (AUDIO_IN_INTERFACE_PDM);
73
+
74
+ /* Initialize audio IN at REC_FREQ*/
75
+ if (BSP_AUDIO_IN_InitEx (INPUT_DEVICE_DIGITAL_MIC, AUDIO_FREQUENCY, DEFAULT_AUDIO_IN_BIT_RESOLUTION, channels) != AUDIO_OK)
76
+ {
77
+ return 0 ;
78
+ }
79
+
80
+ /* Start the record */
81
+ BSP_AUDIO_IN_Record ((uint16_t *)recordPDMBuf, AUDIO_IN_PDM_BUFFER_SIZE * channels);
82
+ return 1 ;
83
+ }
84
+
85
+ void PDMClass::end ()
86
+ {
87
+ }
88
+
89
+ int PDMClass::available ()
90
+ {
91
+ size_t avail = _doubleBuffer.available ();
92
+ if (_channels == 1 ) {
93
+ return avail/2 ;
94
+ } else {
95
+ return avail;
96
+ }
97
+ }
98
+
99
+ int PDMClass::read (void * buffer, size_t size)
100
+ {
101
+ if (_channels == 1 ) {
102
+ uint16_t temp[size*2 ];
103
+ int read = _doubleBuffer.read (temp, size*2 );
104
+ for (int i = 0 ; i < size; i++) {
105
+ ((uint16_t *)buffer)[i] = temp[i*2 ];
106
+ }
107
+ return read;
108
+ }
109
+ int read = _doubleBuffer.read (buffer, size);
110
+ return read;
111
+ }
112
+
113
+ void PDMClass::onReceive (void (*function)(void ))
114
+ {
115
+ _onReceive = function;
116
+ }
117
+
118
+ void PDMClass::setGain (int gain)
119
+ {
120
+
121
+ }
122
+
123
+ void PDMClass::setBufferSize (int bufferSize)
124
+ {
125
+ _doubleBuffer.setSize (bufferSize);
126
+ }
127
+
128
+ void PDMClass::IrqHandler (bool halftranfer)
129
+ {
130
+
131
+ int start = halftranfer ? 0 : AUDIO_IN_PDM_BUFFER_SIZE;
132
+
133
+ if (BSP_AUDIO_IN_GetInterface () == AUDIO_IN_INTERFACE_PDM && _doubleBuffer.available () == 0 ) {
134
+
135
+ /* Invalidate Data Cache to get the updated content of the SRAM*/
136
+ SCB_InvalidateDCache_by_Addr ((uint32_t *)&recordPDMBuf[start], AUDIO_IN_PDM_BUFFER_SIZE * 2 );
137
+
138
+ // memcpy((uint16_t*)_doubleBuffer.data(), (uint16_t*)&recordPDMBuf[start], AUDIO_IN_PDM_BUFFER_SIZE/2);
139
+ BSP_AUDIO_IN_PDMToPCM ((uint16_t *)&recordPDMBuf[start], (uint16_t *)_doubleBuffer.data ());
140
+
141
+ /* Clean Data Cache to update the content of the SRAM */
142
+ SCB_CleanDCache_by_Addr ((uint32_t *)_doubleBuffer.data (), AUDIO_IN_PDM_BUFFER_SIZE * 2 );
143
+
144
+ _doubleBuffer.swap (_doubleBuffer.availableForWrite ());
145
+ }
146
+ if (_onReceive) {
147
+ _onReceive ();
148
+ }
149
+ }
150
+
151
+ extern " C" {
152
+ /* *
153
+ @brief Calculates the remaining file size and new position of the pointer.
154
+ @param None
155
+ @retval None
156
+ */
157
+ __attribute__ ((__used__)) void BSP_AUDIO_IN_TransferComplete_CallBack(void )
158
+ {
159
+ PDM.IrqHandler (false );
160
+ }
161
+
162
+ /* *
163
+ @brief Manages the DMA Half Transfer complete interrupt.
164
+ @param None
165
+ @retval None
166
+ */
167
+ __attribute__ ((__used__)) void BSP_AUDIO_IN_HalfTransfer_CallBack(void )
168
+ {
169
+ PDM.IrqHandler (true );
170
+ }
171
+ }
172
+
173
+ PDMClass PDM (0 , 0 , 0 );
174
+
175
+ #endif
0 commit comments