Il y avait des problèmes dans la libraire...

Dependencies:   ST_FREQUENCY_DIVIDER ST_I2S USBDEVICE

Fork of X_NUCLEO_CCA02M1 by ST

Committer:
Davidroid
Date:
Thu May 04 10:39:39 2017 +0000
Revision:
19:1a061e306cc9
Parent:
15:17bdadc6aa9c
Child:
20:9952bef19da1
Enabled 44.1 and 48 KHz configurations.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
davide.aliprandi@st.com 2:9f389fd8fb2e 1 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 2 ******************************************************************************
davide.aliprandi@st.com 2:9f389fd8fb2e 3 * @file XNucleoCCA02M1.cpp
davide.aliprandi@st.com 2:9f389fd8fb2e 4 * @author AST / Software Platforms and Cloud
davide.aliprandi@st.com 2:9f389fd8fb2e 5 * @version V1.0
davide.aliprandi@st.com 2:9f389fd8fb2e 6 * @date October 17th, 2016
davide.aliprandi@st.com 2:9f389fd8fb2e 7 * @brief Implementation file for the X_NUCLEO_CCA02M1 expansion board.
davide.aliprandi@st.com 2:9f389fd8fb2e 8 ******************************************************************************
davide.aliprandi@st.com 2:9f389fd8fb2e 9 * @attention
davide.aliprandi@st.com 2:9f389fd8fb2e 10 *
davide.aliprandi@st.com 2:9f389fd8fb2e 11 * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
davide.aliprandi@st.com 2:9f389fd8fb2e 12 *
davide.aliprandi@st.com 2:9f389fd8fb2e 13 * Redistribution and use in source and binary forms, with or without modification,
davide.aliprandi@st.com 2:9f389fd8fb2e 14 * are permitted provided that the following conditions are met:
davide.aliprandi@st.com 2:9f389fd8fb2e 15 * 1. Redistributions of source code must retain the above copyright notice,
davide.aliprandi@st.com 2:9f389fd8fb2e 16 * this list of conditions and the following disclaimer.
davide.aliprandi@st.com 2:9f389fd8fb2e 17 * 2. Redistributions in binary form must reproduce the above copyright notice,
davide.aliprandi@st.com 2:9f389fd8fb2e 18 * this list of conditions and the following disclaimer in the documentation
davide.aliprandi@st.com 2:9f389fd8fb2e 19 * and/or other materials provided with the distribution.
davide.aliprandi@st.com 2:9f389fd8fb2e 20 * 3. Neither the name of STMicroelectronics nor the names of its contributors
davide.aliprandi@st.com 2:9f389fd8fb2e 21 * may be used to endorse or promote products derived from this software
davide.aliprandi@st.com 2:9f389fd8fb2e 22 * without specific prior written permission.
davide.aliprandi@st.com 2:9f389fd8fb2e 23 *
davide.aliprandi@st.com 2:9f389fd8fb2e 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
davide.aliprandi@st.com 2:9f389fd8fb2e 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
davide.aliprandi@st.com 2:9f389fd8fb2e 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
davide.aliprandi@st.com 2:9f389fd8fb2e 27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
davide.aliprandi@st.com 2:9f389fd8fb2e 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
davide.aliprandi@st.com 2:9f389fd8fb2e 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
davide.aliprandi@st.com 2:9f389fd8fb2e 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
davide.aliprandi@st.com 2:9f389fd8fb2e 31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
davide.aliprandi@st.com 2:9f389fd8fb2e 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
davide.aliprandi@st.com 2:9f389fd8fb2e 33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
davide.aliprandi@st.com 2:9f389fd8fb2e 34 *
davide.aliprandi@st.com 2:9f389fd8fb2e 35 ******************************************************************************
davide.aliprandi@st.com 2:9f389fd8fb2e 36 */
davide.aliprandi@st.com 2:9f389fd8fb2e 37
davide.aliprandi@st.com 2:9f389fd8fb2e 38
davide.aliprandi@st.com 2:9f389fd8fb2e 39 /* Includes ------------------------------------------------------------------*/
davide.aliprandi@st.com 2:9f389fd8fb2e 40
davide.aliprandi@st.com 2:9f389fd8fb2e 41 /* ACTION 1 ------------------------------------------------------------------*
davide.aliprandi@st.com 2:9f389fd8fb2e 42 * Include here platform specific header files. *
davide.aliprandi@st.com 2:9f389fd8fb2e 43 *----------------------------------------------------------------------------*/
davide.aliprandi@st.com 2:9f389fd8fb2e 44 #include "mbed.h"
davide.aliprandi@st.com 2:9f389fd8fb2e 45 /* ACTION 2 ------------------------------------------------------------------*
davide.aliprandi@st.com 2:9f389fd8fb2e 46 * Include here expansion board specific header files. *
davide.aliprandi@st.com 2:9f389fd8fb2e 47 *----------------------------------------------------------------------------*/
davide.aliprandi@st.com 2:9f389fd8fb2e 48 #include "XNucleoCCA02M1.h"
davide.aliprandi@st.com 2:9f389fd8fb2e 49
davide.aliprandi@st.com 2:9f389fd8fb2e 50
davide.aliprandi@st.com 2:9f389fd8fb2e 51 /* Variables -----------------------------------------------------------------*/
davide.aliprandi@st.com 2:9f389fd8fb2e 52
davide.aliprandi@st.com 2:9f389fd8fb2e 53 /* Indexes of the PCM buffer. */
davide.aliprandi@st.com 2:9f389fd8fb2e 54 uint32_t XNucleoCCA02M1::_PCM_buffer_read_index = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 55 uint32_t XNucleoCCA02M1::_PCM_buffer_write_index = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 56
davide.aliprandi@st.com 2:9f389fd8fb2e 57 /* Number of expansion boards. */
davide.aliprandi@st.com 2:9f389fd8fb2e 58 uint8_t XNucleoCCA02M1::_number_of_boards = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 59
davide.aliprandi@st.com 2:9f389fd8fb2e 60 /* Accessing shared areas: the PCM buffer. */
davide.aliprandi@st.com 2:9f389fd8fb2e 61 SingletonPtr<PlatformMutex> XNucleoCCA02M1::_mutex;
davide.aliprandi@st.com 2:9f389fd8fb2e 62
davide.aliprandi@st.com 2:9f389fd8fb2e 63
davide.aliprandi@st.com 2:9f389fd8fb2e 64 /* Methods -------------------------------------------------------------------*/
davide.aliprandi@st.com 2:9f389fd8fb2e 65
davide.aliprandi@st.com 2:9f389fd8fb2e 66 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 67 * @brief Initializing the X_NUCLEO_CCA02M1 board.
davide.aliprandi@st.com 2:9f389fd8fb2e 68 * @param init Pointer to device specific initalization structure.
davide.aliprandi@st.com 2:9f389fd8fb2e 69 * @retval "0" in case of success, an error code otherwise.
davide.aliprandi@st.com 9:4c3d94b67a6b 70 * @note Currently only two channels at 16KHz are supported.
davide.aliprandi@st.com 2:9f389fd8fb2e 71 */
davide.aliprandi@st.com 2:9f389fd8fb2e 72 status_t XNucleoCCA02M1::init(void *init)
davide.aliprandi@st.com 2:9f389fd8fb2e 73 {
davide.aliprandi@st.com 2:9f389fd8fb2e 74 /* Storing data. */
davide.aliprandi@st.com 2:9f389fd8fb2e 75 if (init != NULL)
davide.aliprandi@st.com 2:9f389fd8fb2e 76 {
davide.aliprandi@st.com 9:4c3d94b67a6b 77 _frequency = (*((XNucleoCCA02M1_init_t *) init)).frequency;
davide.aliprandi@st.com 9:4c3d94b67a6b 78 _channels = (*((XNucleoCCA02M1_init_t *) init)).channels;
davide.aliprandi@st.com 2:9f389fd8fb2e 79 }
davide.aliprandi@st.com 2:9f389fd8fb2e 80
davide.aliprandi@st.com 9:4c3d94b67a6b 81 #ifdef USE_OPEN_PDM2PCM_LIBRARY
davide.aliprandi@st.com 9:4c3d94b67a6b 82 /* Checking input parameters. */
davide.aliprandi@st.com 11:b2f7f79026e4 83 if (!(((_frequency == 16000) && (_channels == 1)) ||
davide.aliprandi@st.com 11:b2f7f79026e4 84 ((_frequency == 16000) && (_channels == 2)) ||
davide.aliprandi@st.com 15:17bdadc6aa9c 85 ((_frequency == 32000) && (_channels == 1)) ||
Davidroid 19:1a061e306cc9 86 ((_frequency == 32000) && (_channels == 2)) ||
Davidroid 19:1a061e306cc9 87 ((_frequency == 44100) && (_channels == 1)) ||
Davidroid 19:1a061e306cc9 88 ((_frequency == 44100) && (_channels == 2)) ||
Davidroid 19:1a061e306cc9 89 ((_frequency == 48000) && (_channels == 1)) ||
Davidroid 19:1a061e306cc9 90 ((_frequency == 48000) && (_channels == 2))))
Davidroid 19:1a061e306cc9 91 error("\r\nError: please set one of the following configurations: mono/stereo 16/32/44.1/48 KHz.\n\r");
davide.aliprandi@st.com 9:4c3d94b67a6b 92 #endif
davide.aliprandi@st.com 9:4c3d94b67a6b 93
davide.aliprandi@st.com 2:9f389fd8fb2e 94 /* Setting configuration. */
davide.aliprandi@st.com 2:9f389fd8fb2e 95 switch (_frequency)
davide.aliprandi@st.com 2:9f389fd8fb2e 96 {
davide.aliprandi@st.com 2:9f389fd8fb2e 97 case I2S_AUDIOFREQ_8K:
davide.aliprandi@st.com 2:9f389fd8fb2e 98 _decimation_factor = 128;
davide.aliprandi@st.com 2:9f389fd8fb2e 99 break;
davide.aliprandi@st.com 2:9f389fd8fb2e 100
davide.aliprandi@st.com 2:9f389fd8fb2e 101 case I2S_AUDIOFREQ_16K:
davide.aliprandi@st.com 2:9f389fd8fb2e 102 case I2S_AUDIOFREQ_32K:
davide.aliprandi@st.com 2:9f389fd8fb2e 103 case I2S_AUDIOFREQ_48K:
davide.aliprandi@st.com 2:9f389fd8fb2e 104 default:
davide.aliprandi@st.com 2:9f389fd8fb2e 105 _decimation_factor = 64;
davide.aliprandi@st.com 2:9f389fd8fb2e 106 break;
davide.aliprandi@st.com 2:9f389fd8fb2e 107 }
davide.aliprandi@st.com 2:9f389fd8fb2e 108
davide.aliprandi@st.com 2:9f389fd8fb2e 109 /* Buffer sizes in 16-bits samples. */
davide.aliprandi@st.com 2:9f389fd8fb2e 110 _PCM_samples_one_ms = ((_frequency * _channels) / 1000);
davide.aliprandi@st.com 2:9f389fd8fb2e 111 _PDM_samples_one_ms = ((_PCM_samples_one_ms * _decimation_factor) / 16);
davide.aliprandi@st.com 2:9f389fd8fb2e 112 _PDM_samples_two_ms = (_PDM_samples_one_ms << 1);
davide.aliprandi@st.com 2:9f389fd8fb2e 113
davide.aliprandi@st.com 2:9f389fd8fb2e 114 /* Allocating input and output buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 115 _PDM_buffer_two_ms = (uint16_t *) calloc(_PDM_samples_two_ms, sizeof(uint16_t));
davide.aliprandi@st.com 2:9f389fd8fb2e 116 _PCM_buffer_n_ms = (int16_t *) calloc(_PCM_samples_one_ms * PCM_BUFFER_SIZE_ms, sizeof(uint16_t));
davide.aliprandi@st.com 2:9f389fd8fb2e 117
davide.aliprandi@st.com 2:9f389fd8fb2e 118 /* Allocating support buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 119 _PDM_buffer_one_ms = (uint16_t *) calloc(_PDM_samples_one_ms, sizeof(uint16_t));
davide.aliprandi@st.com 2:9f389fd8fb2e 120
Davidroid 14:377677cca2e9 121 /*
Davidroid 14:377677cca2e9 122 * Starting the I2S frequency divider.
Davidroid 14:377677cca2e9 123 * Note: put a jumper to connect PB_5 and PB_13 on the MORPHO connector when
Davidroid 14:377677cca2e9 124 * running a mono configuration.
Davidroid 14:377677cca2e9 125 */
Davidroid 14:377677cca2e9 126 if (_channels >= 2)
Davidroid 14:377677cca2e9 127 {
Davidroid 14:377677cca2e9 128 FrequencyDivider *divider = new FrequencyDivider();
Davidroid 14:377677cca2e9 129 divider->start();
Davidroid 14:377677cca2e9 130 }
davide.aliprandi@st.com 2:9f389fd8fb2e 131
davide.aliprandi@st.com 2:9f389fd8fb2e 132 /* Initializing the PDM to PCM conversion library. */
davide.aliprandi@st.com 2:9f389fd8fb2e 133 if ((_pdm2pcm = new PDM2PCMAudio(_frequency, _channels)) == NULL)
davide.aliprandi@st.com 2:9f389fd8fb2e 134 return COMPONENT_ERROR;
davide.aliprandi@st.com 2:9f389fd8fb2e 135
davide.aliprandi@st.com 2:9f389fd8fb2e 136 /* Setting I2S parameters. */
davide.aliprandi@st.com 2:9f389fd8fb2e 137 dev_i2s.mode(MASTER_RX, true);
davide.aliprandi@st.com 2:9f389fd8fb2e 138 dev_i2s.audio_frequency(_frequency == I2S_AUDIOFREQ_8K ? 4 * _frequency : 2 * _frequency);
davide.aliprandi@st.com 2:9f389fd8fb2e 139 dev_i2s.protocol(MSB);
davide.aliprandi@st.com 2:9f389fd8fb2e 140 dev_i2s.format(_channels == 1 ? 16 : 32, _channels == 1 ? 16 : 32, 1);
davide.aliprandi@st.com 2:9f389fd8fb2e 141
davide.aliprandi@st.com 2:9f389fd8fb2e 142 return COMPONENT_OK;
davide.aliprandi@st.com 2:9f389fd8fb2e 143 }
davide.aliprandi@st.com 2:9f389fd8fb2e 144
davide.aliprandi@st.com 2:9f389fd8fb2e 145 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 146 * @brief Enabling transmission via USB.
davide.aliprandi@st.com 2:9f389fd8fb2e 147 * @param None.
davide.aliprandi@st.com 2:9f389fd8fb2e 148 * @retval "0" in case of success, an error code otherwise.
davide.aliprandi@st.com 2:9f389fd8fb2e 149 */
davide.aliprandi@st.com 2:9f389fd8fb2e 150 status_t XNucleoCCA02M1::enable_usb(void)
davide.aliprandi@st.com 2:9f389fd8fb2e 151 {
davide.aliprandi@st.com 2:9f389fd8fb2e 152 /* Initializing the USBAudio object. */
davide.aliprandi@st.com 2:9f389fd8fb2e 153 if ((_usb_audio = new USBAudio(32000, 2, _frequency, _channels)) == NULL)
davide.aliprandi@st.com 2:9f389fd8fb2e 154 return COMPONENT_ERROR;
davide.aliprandi@st.com 2:9f389fd8fb2e 155
davide.aliprandi@st.com 2:9f389fd8fb2e 156 /* Allocating support buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 157 _USB_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms + _channels, sizeof(uint16_t));
davide.aliprandi@st.com 2:9f389fd8fb2e 158
davide.aliprandi@st.com 2:9f389fd8fb2e 159 _usb_enabled = true;
davide.aliprandi@st.com 2:9f389fd8fb2e 160
davide.aliprandi@st.com 2:9f389fd8fb2e 161 return COMPONENT_OK;
davide.aliprandi@st.com 2:9f389fd8fb2e 162 }
davide.aliprandi@st.com 2:9f389fd8fb2e 163
davide.aliprandi@st.com 2:9f389fd8fb2e 164 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 165 * @brief Disabling transmission via USB.
davide.aliprandi@st.com 2:9f389fd8fb2e 166 * @param None.
davide.aliprandi@st.com 2:9f389fd8fb2e 167 * @retval "0" in case of success, an error code otherwise.
davide.aliprandi@st.com 2:9f389fd8fb2e 168 */
davide.aliprandi@st.com 2:9f389fd8fb2e 169 status_t XNucleoCCA02M1::disable_usb(void)
davide.aliprandi@st.com 2:9f389fd8fb2e 170 {
davide.aliprandi@st.com 2:9f389fd8fb2e 171 /* Freeing memory for the USBAudio object and support buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 172 delete _usb_audio;
davide.aliprandi@st.com 2:9f389fd8fb2e 173 free(_USB_PCM_buffer_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 174
davide.aliprandi@st.com 2:9f389fd8fb2e 175 _usb_enabled = false;
davide.aliprandi@st.com 2:9f389fd8fb2e 176
davide.aliprandi@st.com 2:9f389fd8fb2e 177 return COMPONENT_OK;
davide.aliprandi@st.com 2:9f389fd8fb2e 178 }
davide.aliprandi@st.com 2:9f389fd8fb2e 179
davide.aliprandi@st.com 2:9f389fd8fb2e 180 /*
davide.aliprandi@st.com 2:9f389fd8fb2e 181 * @brief Start recording audio.
davide.aliprandi@st.com 2:9f389fd8fb2e 182 * @param None.
davide.aliprandi@st.com 2:9f389fd8fb2e 183 * @retval "0" in case of success, an error code otherwise.
davide.aliprandi@st.com 2:9f389fd8fb2e 184 */
davide.aliprandi@st.com 2:9f389fd8fb2e 185 status_t XNucleoCCA02M1::record(void)
davide.aliprandi@st.com 2:9f389fd8fb2e 186 {
davide.aliprandi@st.com 2:9f389fd8fb2e 187 /* Reading microphones via I2S. */
davide.aliprandi@st.com 2:9f389fd8fb2e 188 int res = dev_i2s.transfer(
davide.aliprandi@st.com 2:9f389fd8fb2e 189 (void *) NULL, 0,
davide.aliprandi@st.com 2:9f389fd8fb2e 190 (void *) _PDM_buffer_two_ms, _PDM_samples_two_ms * BYTES_PER_SAMPLE,
davide.aliprandi@st.com 2:9f389fd8fb2e 191 event_callback_t(this, &XNucleoCCA02M1::i2s_callback),
davide.aliprandi@st.com 2:9f389fd8fb2e 192 I2S_EVENT_ALL
davide.aliprandi@st.com 2:9f389fd8fb2e 193 );
davide.aliprandi@st.com 2:9f389fd8fb2e 194 if (res != 0)
davide.aliprandi@st.com 2:9f389fd8fb2e 195 return COMPONENT_ERROR;
davide.aliprandi@st.com 2:9f389fd8fb2e 196
davide.aliprandi@st.com 2:9f389fd8fb2e 197 /* Attaching a callback to send data through the USB at a standard frequency
davide.aliprandi@st.com 2:9f389fd8fb2e 198 of 1KHz. */
davide.aliprandi@st.com 2:9f389fd8fb2e 199 if (_usb_enabled)
davide.aliprandi@st.com 2:9f389fd8fb2e 200 _usb_audio->attachTx(this, &XNucleoCCA02M1::usb_handler);
davide.aliprandi@st.com 2:9f389fd8fb2e 201
davide.aliprandi@st.com 2:9f389fd8fb2e 202 return COMPONENT_OK;
davide.aliprandi@st.com 2:9f389fd8fb2e 203 }
davide.aliprandi@st.com 2:9f389fd8fb2e 204
davide.aliprandi@st.com 2:9f389fd8fb2e 205 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 206 * @brief Attach a user-defined callback that will be executed whenever PCM
davide.aliprandi@st.com 2:9f389fd8fb2e 207 * data are ready, i.e. once each millisecond.
davide.aliprandi@st.com 2:9f389fd8fb2e 208 * The provided PCM buffer will be filled by the microphones.
davide.aliprandi@st.com 2:9f389fd8fb2e 209 * @param fptr Callback to attach.
davide.aliprandi@st.com 2:9f389fd8fb2e 210 * @retval None.
davide.aliprandi@st.com 2:9f389fd8fb2e 211 */
davide.aliprandi@st.com 2:9f389fd8fb2e 212 void XNucleoCCA02M1::attach(void (*fptr) (int16_t *PCM_buffer, uint16_t PCM_buffer_bytes))
davide.aliprandi@st.com 2:9f389fd8fb2e 213 {
davide.aliprandi@st.com 2:9f389fd8fb2e 214 /* Allocating support buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 215 if ((_USER_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms, sizeof(uint16_t))) == NULL)
davide.aliprandi@st.com 2:9f389fd8fb2e 216 error("Instantiation of support buffers failed.\r\n");
davide.aliprandi@st.com 2:9f389fd8fb2e 217
davide.aliprandi@st.com 2:9f389fd8fb2e 218 /* Attaching the callback. */
davide.aliprandi@st.com 2:9f389fd8fb2e 219 _callback.attach(fptr);
davide.aliprandi@st.com 2:9f389fd8fb2e 220 _callback_attached = true;
davide.aliprandi@st.com 2:9f389fd8fb2e 221 }
davide.aliprandi@st.com 2:9f389fd8fb2e 222
davide.aliprandi@st.com 2:9f389fd8fb2e 223 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 224 * @brief Attach a user-defined non-static callback that will be executed
davide.aliprandi@st.com 2:9f389fd8fb2e 225 * whenever PCM data are ready, i.e. once each millisecond.
davide.aliprandi@st.com 2:9f389fd8fb2e 226 * The provided PCM buffer will be filled by the microphones.
davide.aliprandi@st.com 2:9f389fd8fb2e 227 * @param tptr Pointer to an object.
davide.aliprandi@st.com 2:9f389fd8fb2e 228 * @param mptr Pointer to an object's callback.
davide.aliprandi@st.com 2:9f389fd8fb2e 229 * @retval None.
davide.aliprandi@st.com 2:9f389fd8fb2e 230 */
davide.aliprandi@st.com 2:9f389fd8fb2e 231 template<typename T>
davide.aliprandi@st.com 2:9f389fd8fb2e 232 void XNucleoCCA02M1::attach(T *tptr, void (T::*mptr) (int16_t *PCM_buffer, uint16_t PCM_buffer_bytes))
davide.aliprandi@st.com 2:9f389fd8fb2e 233 {
davide.aliprandi@st.com 2:9f389fd8fb2e 234 /* Allocating support buffers. */
davide.aliprandi@st.com 2:9f389fd8fb2e 235 if ((_USER_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms, sizeof(uint16_t))) == NULL)
davide.aliprandi@st.com 2:9f389fd8fb2e 236 error("Instantiation of support buffers failed.\r\n");
davide.aliprandi@st.com 2:9f389fd8fb2e 237
davide.aliprandi@st.com 2:9f389fd8fb2e 238 /* Attaching the callback. */
davide.aliprandi@st.com 2:9f389fd8fb2e 239 _callback.attach(tptr, mptr);
davide.aliprandi@st.com 2:9f389fd8fb2e 240 _callback_attached = true;
davide.aliprandi@st.com 2:9f389fd8fb2e 241 }
davide.aliprandi@st.com 2:9f389fd8fb2e 242
davide.aliprandi@st.com 2:9f389fd8fb2e 243 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 244 * @brief I2S callback which is executed whenever PCM data are ready, i.e. once
davide.aliprandi@st.com 2:9f389fd8fb2e 245 * each millisecond.
davide.aliprandi@st.com 2:9f389fd8fb2e 246 * @param narg Narg flag.
davide.aliprandi@st.com 2:9f389fd8fb2e 247 * @retval None.
davide.aliprandi@st.com 2:9f389fd8fb2e 248 */
davide.aliprandi@st.com 2:9f389fd8fb2e 249 void XNucleoCCA02M1::i2s_callback(int narg)
davide.aliprandi@st.com 2:9f389fd8fb2e 250 {
davide.aliprandi@st.com 2:9f389fd8fb2e 251 /* Checking for errors. */
davide.aliprandi@st.com 2:9f389fd8fb2e 252 if (!(narg & (I2S_EVENT_RX_COMPLETE | I2S_EVENT_RX_HALF_COMPLETE)))
davide.aliprandi@st.com 2:9f389fd8fb2e 253 error("Unexpected transmission event.\r\n");
davide.aliprandi@st.com 2:9f389fd8fb2e 254
davide.aliprandi@st.com 2:9f389fd8fb2e 255 /* PDM to PCM Conversion. */
davide.aliprandi@st.com 2:9f389fd8fb2e 256 if (narg & (I2S_EVENT_RX_COMPLETE | I2S_EVENT_RX_HALF_COMPLETE))
davide.aliprandi@st.com 2:9f389fd8fb2e 257 {
davide.aliprandi@st.com 2:9f389fd8fb2e 258 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 259 _i2s_signal = 1;
davide.aliprandi@st.com 2:9f389fd8fb2e 260 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 261
davide.aliprandi@st.com 2:9f389fd8fb2e 262 uint32_t PDM_index = (narg & I2S_EVENT_RX_HALF_COMPLETE ? 0 : _PDM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 263 switch (_channels)
davide.aliprandi@st.com 2:9f389fd8fb2e 264 {
davide.aliprandi@st.com 2:9f389fd8fb2e 265 case 1:
davide.aliprandi@st.com 2:9f389fd8fb2e 266 /* Scrambling PDM audio data. */
davide.aliprandi@st.com 2:9f389fd8fb2e 267 _pdm2pcm->scramble(_PDM_buffer_one_ms, &_PDM_buffer_two_ms[PDM_index], _PDM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 268 break;
davide.aliprandi@st.com 2:9f389fd8fb2e 269
davide.aliprandi@st.com 2:9f389fd8fb2e 270 case 2:
davide.aliprandi@st.com 2:9f389fd8fb2e 271 /* Demuxing PDM audio data. */
davide.aliprandi@st.com 2:9f389fd8fb2e 272 _pdm2pcm->demux(_PDM_buffer_one_ms, &_PDM_buffer_two_ms[PDM_index], _PDM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 273 break;
davide.aliprandi@st.com 2:9f389fd8fb2e 274 }
davide.aliprandi@st.com 2:9f389fd8fb2e 275
davide.aliprandi@st.com 2:9f389fd8fb2e 276 /* Acquiring resources. */
davide.aliprandi@st.com 2:9f389fd8fb2e 277 _mutex->lock();
davide.aliprandi@st.com 2:9f389fd8fb2e 278
davide.aliprandi@st.com 2:9f389fd8fb2e 279 /* Converting PDM to PCM audio data. */
davide.aliprandi@st.com 2:9f389fd8fb2e 280 _pdm2pcm->convert(&_PCM_buffer_n_ms[_PCM_buffer_write_index], _PDM_buffer_one_ms, _volume, _decimation_factor);
davide.aliprandi@st.com 2:9f389fd8fb2e 281
davide.aliprandi@st.com 2:9f389fd8fb2e 282 /* Copying PCM data to the user buffer. */
davide.aliprandi@st.com 2:9f389fd8fb2e 283 if (_callback_attached)
davide.aliprandi@st.com 2:9f389fd8fb2e 284 memcpy(_USER_PCM_buffer_one_ms, &_PCM_buffer_n_ms[_PCM_buffer_write_index], _PCM_samples_one_ms * BYTES_PER_SAMPLE);
davide.aliprandi@st.com 2:9f389fd8fb2e 285
davide.aliprandi@st.com 2:9f389fd8fb2e 286 /* Updating write index. */
davide.aliprandi@st.com 2:9f389fd8fb2e 287 _PCM_buffer_write_index += _PCM_samples_one_ms;
davide.aliprandi@st.com 2:9f389fd8fb2e 288 _PCM_buffer_write_index %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 289
davide.aliprandi@st.com 2:9f389fd8fb2e 290 /* Releasing resources. */
davide.aliprandi@st.com 2:9f389fd8fb2e 291 _mutex->unlock();
davide.aliprandi@st.com 2:9f389fd8fb2e 292
davide.aliprandi@st.com 2:9f389fd8fb2e 293 /* Executing user-defined callback. */
davide.aliprandi@st.com 2:9f389fd8fb2e 294 static bool first_time = true;
davide.aliprandi@st.com 2:9f389fd8fb2e 295 if (_callback_attached && first_time)
davide.aliprandi@st.com 2:9f389fd8fb2e 296 {
davide.aliprandi@st.com 2:9f389fd8fb2e 297 _callback.call(_USER_PCM_buffer_one_ms, _PCM_samples_one_ms * BYTES_PER_SAMPLE);
davide.aliprandi@st.com 2:9f389fd8fb2e 298 first_time = !first_time;
davide.aliprandi@st.com 2:9f389fd8fb2e 299 }
davide.aliprandi@st.com 2:9f389fd8fb2e 300
davide.aliprandi@st.com 2:9f389fd8fb2e 301 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 302 _i2s_signal = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 303 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 304 }
davide.aliprandi@st.com 2:9f389fd8fb2e 305
davide.aliprandi@st.com 2:9f389fd8fb2e 306 /* Start sending data through the USB whenever the PCM buffer has been
davide.aliprandi@st.com 2:9f389fd8fb2e 307 filled up to the medium threshold. */
davide.aliprandi@st.com 2:9f389fd8fb2e 308 if (_usb_enabled)
davide.aliprandi@st.com 2:9f389fd8fb2e 309 {
davide.aliprandi@st.com 2:9f389fd8fb2e 310 static bool done = false;
davide.aliprandi@st.com 2:9f389fd8fb2e 311 static uint32_t calls = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 312 if (!done)
davide.aliprandi@st.com 2:9f389fd8fb2e 313 if (calls++ >= PCM_BUFFER_TH_MED_ms)
davide.aliprandi@st.com 2:9f389fd8fb2e 314 {
davide.aliprandi@st.com 2:9f389fd8fb2e 315 usb_handler();
davide.aliprandi@st.com 2:9f389fd8fb2e 316 done = true;
davide.aliprandi@st.com 2:9f389fd8fb2e 317 }
davide.aliprandi@st.com 2:9f389fd8fb2e 318 }
davide.aliprandi@st.com 2:9f389fd8fb2e 319 }
davide.aliprandi@st.com 2:9f389fd8fb2e 320
davide.aliprandi@st.com 2:9f389fd8fb2e 321 /**
davide.aliprandi@st.com 2:9f389fd8fb2e 322 * @brief Sending PCM data via USB.
davide.aliprandi@st.com 2:9f389fd8fb2e 323 * @param None.
davide.aliprandi@st.com 2:9f389fd8fb2e 324 * @retval None.
davide.aliprandi@st.com 2:9f389fd8fb2e 325 */
davide.aliprandi@st.com 2:9f389fd8fb2e 326 void XNucleoCCA02M1::usb_handler(void)
davide.aliprandi@st.com 2:9f389fd8fb2e 327 {
davide.aliprandi@st.com 2:9f389fd8fb2e 328 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 329 _usb_signal = 1;
davide.aliprandi@st.com 2:9f389fd8fb2e 330 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 331
davide.aliprandi@st.com 2:9f389fd8fb2e 332 /* Acquiring resources. */
davide.aliprandi@st.com 2:9f389fd8fb2e 333 _mutex->lock();
davide.aliprandi@st.com 2:9f389fd8fb2e 334
davide.aliprandi@st.com 2:9f389fd8fb2e 335 /* Computing the delta-data to send through the USB depending on the
davide.aliprandi@st.com 2:9f389fd8fb2e 336 dis-alignment between the read and write index of the PCM buffer,
davide.aliprandi@st.com 2:9f389fd8fb2e 337 which may happen whenever the I2S and the USB do not works at the
davide.aliprandi@st.com 2:9f389fd8fb2e 338 same frequency (i.e. 1KHz). */
davide.aliprandi@st.com 2:9f389fd8fb2e 339 int32_t PCM_diff = _PCM_buffer_write_index - _PCM_buffer_read_index;
davide.aliprandi@st.com 2:9f389fd8fb2e 340 PCM_diff = (PCM_diff >= 0 ? PCM_diff : PCM_diff + PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 341 int32_t PCM_buffer_high_index = PCM_BUFFER_TH_HIG_ms * _PCM_samples_one_ms;
davide.aliprandi@st.com 2:9f389fd8fb2e 342 int32_t PCM_buffer_low_index = PCM_BUFFER_TH_LOW_ms * _PCM_samples_one_ms;
davide.aliprandi@st.com 2:9f389fd8fb2e 343 USBAudio::AudioSampleCorrectType PCM_delta_samples = USBAudio::NoCorrection;
davide.aliprandi@st.com 2:9f389fd8fb2e 344
davide.aliprandi@st.com 2:9f389fd8fb2e 345 if (PCM_diff >= PCM_buffer_high_index) {
davide.aliprandi@st.com 2:9f389fd8fb2e 346 PCM_delta_samples = USBAudio::AddOneSample;
davide.aliprandi@st.com 2:9f389fd8fb2e 347 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 348 _buffer_overrun = 1;
davide.aliprandi@st.com 2:9f389fd8fb2e 349 _buffer_underrun = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 350 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 351 }
davide.aliprandi@st.com 2:9f389fd8fb2e 352 else if (PCM_diff <= PCM_buffer_low_index) {
davide.aliprandi@st.com 2:9f389fd8fb2e 353 PCM_delta_samples = USBAudio::RemoveOneSample;
davide.aliprandi@st.com 2:9f389fd8fb2e 354 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 355 _buffer_overrun = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 356 _buffer_underrun = 1;
davide.aliprandi@st.com 2:9f389fd8fb2e 357 } else {
davide.aliprandi@st.com 2:9f389fd8fb2e 358 _buffer_overrun = _buffer_underrun = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 359 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 360 }
davide.aliprandi@st.com 2:9f389fd8fb2e 361
davide.aliprandi@st.com 2:9f389fd8fb2e 362 /* Writing data through the USB. */
davide.aliprandi@st.com 2:9f389fd8fb2e 363 for (uint32_t i = 0, j = _PCM_buffer_read_index; i < _PCM_samples_one_ms + ((uint32_t) PCM_delta_samples) * _channels; j %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms))
davide.aliprandi@st.com 2:9f389fd8fb2e 364 _USB_PCM_buffer_one_ms[i++] = _PCM_buffer_n_ms[j++];
davide.aliprandi@st.com 2:9f389fd8fb2e 365 _usb_audio->writeSync((uint8_t *) _USB_PCM_buffer_one_ms, PCM_delta_samples);
davide.aliprandi@st.com 2:9f389fd8fb2e 366
davide.aliprandi@st.com 2:9f389fd8fb2e 367 /* Updating read index. */
davide.aliprandi@st.com 2:9f389fd8fb2e 368 _PCM_buffer_read_index += _PCM_samples_one_ms + ((uint32_t) PCM_delta_samples) * _channels;
davide.aliprandi@st.com 2:9f389fd8fb2e 369 _PCM_buffer_read_index %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
davide.aliprandi@st.com 2:9f389fd8fb2e 370
davide.aliprandi@st.com 2:9f389fd8fb2e 371 /* Releasing resources. */
davide.aliprandi@st.com 2:9f389fd8fb2e 372 _mutex->unlock();
davide.aliprandi@st.com 2:9f389fd8fb2e 373
davide.aliprandi@st.com 2:9f389fd8fb2e 374 #ifdef X_NUCLEO_CCA02M1_DEBUG
davide.aliprandi@st.com 2:9f389fd8fb2e 375 _usb_signal = 0;
davide.aliprandi@st.com 2:9f389fd8fb2e 376 #endif
davide.aliprandi@st.com 2:9f389fd8fb2e 377 }