Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: ST_FREQUENCY_DIVIDER ST_I2S USBDEVICE
Fork of X_NUCLEO_CCA02M1 by
Diff: BSP/x_nucleo_cca02m1_class.cpp
- Revision:
- 2:9f389fd8fb2e
- Parent:
- 1:245f83276546
- Child:
- 3:c5091e8deede
--- a/BSP/x_nucleo_cca02m1_class.cpp Fri Apr 21 10:31:01 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,373 +0,0 @@
-/**
- ******************************************************************************
- * @file x_nucleo_cca02m1_class.cpp
- * @author AST / Software Platforms and Cloud
- * @version V1.0
- * @date October 17th, 2016
- * @brief Implementation file for the X_NUCLEO_CCA02M1 expansion board.
- ******************************************************************************
- * @attention
- *
- * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- ******************************************************************************
- */
-
-
-/* Includes ------------------------------------------------------------------*/
-
-/* ACTION 1 ------------------------------------------------------------------*
- * Include here platform specific header files. *
- *----------------------------------------------------------------------------*/
-#include "mbed.h"
-/* ACTION 2 ------------------------------------------------------------------*
- * Include here expansion board specific header files. *
- *----------------------------------------------------------------------------*/
-#include "x_nucleo_cca02m1_class.h"
-
-
-/* Variables -----------------------------------------------------------------*/
-
-/* Indexes of the PCM buffer. */
-uint32_t X_NUCLEO_CCA02M1::_PCM_buffer_read_index = 0;
-uint32_t X_NUCLEO_CCA02M1::_PCM_buffer_write_index = 0;
-
-/* Number of expansion boards. */
-uint8_t X_NUCLEO_CCA02M1::_number_of_boards = 0;
-
-/* Accessing shared areas: the PCM buffer. */
-SingletonPtr<PlatformMutex> X_NUCLEO_CCA02M1::_mutex;
-
-
-/* Methods -------------------------------------------------------------------*/
-
-/**
-* @brief Initializing the X_NUCLEO_CCA02M1 board.
-* @param init Pointer to device specific initalization structure.
-* @retval "0" in case of success, an error code otherwise.
-*/
-Status_t X_NUCLEO_CCA02M1::Init(void *init)
-{
- /* Storing data. */
- if (init != NULL)
- {
- _frequency = (*((X_NUCLEO_CCA02M1_Init_t *) init)).frequency;
- _channels = (*((X_NUCLEO_CCA02M1_Init_t *) init)).channels;
- }
-
- /* Setting configuration. */
- switch (_frequency)
- {
- case I2S_AUDIOFREQ_8K:
- _decimation_factor = 128;
- break;
-
- case I2S_AUDIOFREQ_16K:
- case I2S_AUDIOFREQ_32K:
- case I2S_AUDIOFREQ_48K:
- default:
- _decimation_factor = 64;
- break;
- }
-
- /* Buffer sizes in 16-bits samples. */
- _PCM_samples_one_ms = ((_frequency * _channels) / 1000);
- _PDM_samples_one_ms = ((_PCM_samples_one_ms * _decimation_factor) / 16);
- _PDM_samples_two_ms = (_PDM_samples_one_ms << 1);
-
- /* Allocating input and output buffers. */
- _PDM_buffer_two_ms = (uint16_t *) calloc(_PDM_samples_two_ms, sizeof(uint16_t));
- _PCM_buffer_n_ms = (int16_t *) calloc(_PCM_samples_one_ms * PCM_BUFFER_SIZE_ms, sizeof(uint16_t));
-
- /* Allocating support buffers. */
- _PDM_buffer_one_ms = (uint16_t *) calloc(_PDM_samples_one_ms, sizeof(uint16_t));
-
- /* Starting the I2S timer, if needed. */
- if (_channels != 1)
- if (InitI2STimer() != COMPONENT_OK)
- return COMPONENT_ERROR;
-
- /* Initializing the PDM to PCM conversion library. */
- if ((_pdm2pcm = new PDM2PCMAudio(_frequency, _channels)) == NULL)
- return COMPONENT_ERROR;
-
- /* Setting I2S parameters. */
- dev_i2s.mode(MASTER_RX, true);
- dev_i2s.audio_frequency(_frequency == I2S_AUDIOFREQ_8K ? 4 * _frequency : 2 * _frequency);
- dev_i2s.protocol(MSB);
- dev_i2s.format(_channels == 1 ? 16 : 32, _channels == 1 ? 16 : 32, 1);
-
- return COMPONENT_OK;
-}
-
-/**
- * @brief Enabling transmission via USB.
- * @param None.
- * @retval "0" in case of success, an error code otherwise.
- */
-Status_t X_NUCLEO_CCA02M1::EnableUSB(void)
-{
- /* Initializing the USBAudio object. */
- if ((_usb_audio = new USBAudio(32000, 2, _frequency, _channels)) == NULL)
- return COMPONENT_ERROR;
-
- /* Allocating support buffers. */
- _USB_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms + _channels, sizeof(uint16_t));
-
- _usb_enabled = true;
-
- return COMPONENT_OK;
-}
-
-/**
- * @brief Disabling transmission via USB.
- * @param None.
- * @retval "0" in case of success, an error code otherwise.
- */
-Status_t X_NUCLEO_CCA02M1::DisableUSB(void)
-{
- /* Freeing memory for the USBAudio object and support buffers. */
- delete _usb_audio;
- free(_USB_PCM_buffer_one_ms);
-
- _usb_enabled = false;
-
- return COMPONENT_OK;
-}
-
-/*
- * @brief Start recording audio.
- * @param None.
- * @retval "0" in case of success, an error code otherwise.
- */
-Status_t X_NUCLEO_CCA02M1::Record(void)
-{
- /* Reading microphones via I2S. */
- int res = dev_i2s.transfer(
- (void *) NULL, 0,
- (void *) _PDM_buffer_two_ms, _PDM_samples_two_ms * BYTES_PER_SAMPLE,
- event_callback_t(this, &X_NUCLEO_CCA02M1::I2SCallback),
- I2S_EVENT_ALL
- );
- if (res != 0)
- return COMPONENT_ERROR;
-
- /* Attaching a callback to send data through the USB at a standard frequency
- of 1KHz. */
- if (_usb_enabled)
- _usb_audio->attachTx(this, &X_NUCLEO_CCA02M1::USBHandler);
-
- return COMPONENT_OK;
-}
-
-/**
- * @brief Attach a user-defined callback that will be executed whenever PCM
- * data are ready, i.e. once each millisecond.
- * The provided PCM buffer will be filled by the microphones.
- * @param fptr Callback to attach.
- * @retval None.
- */
-void X_NUCLEO_CCA02M1::Attach(void (*fptr) (int16_t *PCM_buffer, uint16_t PCM_buffer_bytes))
-{
- /* Allocating support buffers. */
- if ((_USER_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms, sizeof(uint16_t))) == NULL)
- error("Instantiation of support buffers failed.\r\n");
-
- /* Attaching the callback. */
- _callback.attach(fptr);
- _callback_attached = true;
-}
-
-/**
- * @brief Attach a user-defined non-static callback that will be executed
- * whenever PCM data are ready, i.e. once each millisecond.
- * The provided PCM buffer will be filled by the microphones.
- * @param tptr Pointer to an object.
- * @param mptr Pointer to an object's callback.
- * @retval None.
- */
-template<typename T>
-void X_NUCLEO_CCA02M1::Attach(T *tptr, void (T::*mptr) (int16_t *PCM_buffer, uint16_t PCM_buffer_bytes))
-{
- /* Allocating support buffers. */
- if ((_USER_PCM_buffer_one_ms = (int16_t *) calloc(_PCM_samples_one_ms, sizeof(uint16_t))) == NULL)
- error("Instantiation of support buffers failed.\r\n");
-
- /* Attaching the callback. */
- _callback.attach(tptr, mptr);
- _callback_attached = true;
-}
-
-/**
- * @brief Initializing the I2S timer.
- * @param None.
- * @retval COMPONENT_OK in case of success, COMPONENT_ERROR otherwise.
- */
-Status_t X_NUCLEO_CCA02M1::InitI2STimer(void)
-{
- if (AUDIO_IN_Timer_Init() != COMPONENT_OK)
- return COMPONENT_ERROR;
-
- if (AUDIO_IN_Timer_Start() != COMPONENT_OK)
- return COMPONENT_ERROR;
-
- return COMPONENT_OK;
-}
-
-/**
- * @brief I2S callback which is executed whenever PCM data are ready, i.e. once
- * each millisecond.
- * @param narg Narg flag.
- * @retval None.
- */
-void X_NUCLEO_CCA02M1::I2SCallback(int narg)
-{
- /* Checking for errors. */
- if (!(narg & (I2S_EVENT_RX_COMPLETE | I2S_EVENT_RX_HALF_COMPLETE)))
- error("Unexpected transmission event.\r\n");
-
- /* PDM to PCM Conversion. */
- if (narg & (I2S_EVENT_RX_COMPLETE | I2S_EVENT_RX_HALF_COMPLETE))
- {
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _i2s_signal = 1;
-#endif
-
- uint32_t PDM_index = (narg & I2S_EVENT_RX_HALF_COMPLETE ? 0 : _PDM_samples_one_ms);
- switch (_channels)
- {
- case 1:
- /* Scrambling PDM audio data. */
- _pdm2pcm->Scramble(_PDM_buffer_one_ms, &_PDM_buffer_two_ms[PDM_index], _PDM_samples_one_ms);
- break;
-
- case 2:
- /* Demuxing PDM audio data. */
- _pdm2pcm->Demux(_PDM_buffer_one_ms, &_PDM_buffer_two_ms[PDM_index], _PDM_samples_one_ms);
- break;
- }
-
- /* Acquiring resources. */
- _mutex->lock();
-
- /* Converting PDM to PCM audio data. */
- _pdm2pcm->Convert(&_PCM_buffer_n_ms[_PCM_buffer_write_index], _PDM_buffer_one_ms, _volume, _decimation_factor);
-
- /* Copying PCM data to the user buffer. */
- if (_callback_attached)
- memcpy(_USER_PCM_buffer_one_ms, &_PCM_buffer_n_ms[_PCM_buffer_write_index], _PCM_samples_one_ms * BYTES_PER_SAMPLE);
-
- /* Updating write index. */
- _PCM_buffer_write_index += _PCM_samples_one_ms;
- _PCM_buffer_write_index %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
-
- /* Releasing resources. */
- _mutex->unlock();
-
- /* Executing user-defined callback. */
- static bool first_time = true;
- if (_callback_attached && first_time)
- {
- _callback.call(_USER_PCM_buffer_one_ms, _PCM_samples_one_ms * BYTES_PER_SAMPLE);
- first_time = !first_time;
- }
-
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _i2s_signal = 0;
-#endif
- }
-
- /* Start sending data through the USB whenever the PCM buffer has been
- filled up to the medium threshold. */
- if (_usb_enabled)
- {
- static bool done = false;
- static uint32_t calls = 0;
- if (!done)
- if (calls++ >= PCM_BUFFER_TH_MED_ms)
- {
- USBHandler();
- done = true;
- }
- }
-}
-
-/**
- * @brief Sending PCM data via USB.
- * @param None.
- * @retval None.
- */
-void X_NUCLEO_CCA02M1::USBHandler(void)
-{
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _usb_signal = 1;
-#endif
-
- /* Acquiring resources. */
- _mutex->lock();
-
- /* Computing the delta-data to send through the USB depending on the
- dis-alignment between the read and write index of the PCM buffer,
- which may happen whenever the I2S and the USB do not works at the
- same frequency (i.e. 1KHz). */
- int32_t PCM_diff = _PCM_buffer_write_index - _PCM_buffer_read_index;
- PCM_diff = (PCM_diff >= 0 ? PCM_diff : PCM_diff + PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
- int32_t PCM_buffer_high_index = PCM_BUFFER_TH_HIG_ms * _PCM_samples_one_ms;
- int32_t PCM_buffer_low_index = PCM_BUFFER_TH_LOW_ms * _PCM_samples_one_ms;
- int32_t PCM_delta_samples = 0;
-
- if (PCM_diff >= PCM_buffer_high_index) {
- PCM_delta_samples = 1;
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _buffer_overrun = 1;
- _buffer_underrun = 0;
-#endif
- }
- else if (PCM_diff <= PCM_buffer_low_index) {
- PCM_delta_samples = -1;
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _buffer_overrun = 0;
- _buffer_underrun = 1;
- } else {
- _buffer_overrun = _buffer_underrun = 0;
-#endif
- }
-
- /* Writing data through the USB. */
- for (uint32_t i = 0, j = _PCM_buffer_read_index; i < _PCM_samples_one_ms + PCM_delta_samples * _channels; j %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms))
- _USB_PCM_buffer_one_ms[i++] = _PCM_buffer_n_ms[j++];
- _usb_audio->writeSync((uint8_t *) _USB_PCM_buffer_one_ms, PCM_delta_samples);
-
- /* Updating read index. */
- _PCM_buffer_read_index += _PCM_samples_one_ms + PCM_delta_samples * _channels;
- _PCM_buffer_read_index %= (PCM_BUFFER_SIZE_ms * _PCM_samples_one_ms);
-
- /* Releasing resources. */
- _mutex->unlock();
-
-#ifdef X_NUCLEO_CCA02M1_DEBUG
- _usb_signal = 0;
-#endif
-}
