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