完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
可以参考蓝牙协议栈里的相关I2S例子
比如: C:tisimplelinkble_sdk_2_02_01_18examplescc2650stksensortag_audioiar 或者 C:tisimplelinkble_sdk_2_02_01_18examplescc2650rchid_adv_remote_privacyiar 可以从里面的PDMCC26XX.C里借鉴 /* * Copyright (c) 2015-2016, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * * Neither the name of Texas Instruments Incorporated 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 OWNER 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /********************************************************************* * CONSTANTS */ const int32_t PDMCC26XX_aBqCoeffs[] = [ //--v-- Adjust overall gain by changing this coefficient 331, 0, -1024, -1356, 342, // DC-notch, halfband LP filter (@32 kHz) 200, 789, 934, -994, 508, 538, 381, 944, -519, 722, 732, 124, 987, -386, 886, 763, 11, 1014, -386, 886, 0, // Terminate first filter // Insert optional second filter here (@16 kHz). Some examples: //1147,-1516, 522, -1699, 708, // +5dB peak filter (F0=500 Hz, BW=3 octaves) //1313, -565, -6, -725, 281, // +5dB peak filter (F0=2.5 kHz, BW=2 octaves) //1335, 532, -66, 694, 225, // +5 dB peak filter (F0=5.5 kHz, BW=1 octave) 0, // Terminate second filter ]; const uint16_t PDMCC26XX_gainTable[PDMCC26XX_GAIN_END] = [ 1318, //PDMCC26XX_GAIN_24, 660, //PDMCC26XX_GAIN_18, 331, //PDMCC26XX_GAIN_12, // Default 166, //PDMCC26XX_GAIN_6, 83, //PDMCC26XX_GAIN_0, // 42, //PDMCC26XX_GAIN_N6, // 21, //PDMCC26XX_GAIN_N12, // 7, //PDMCC26XX_GAIN_N22, // 2, //PDMCC26XX_GAIN_N32 ]; /********************************************************************* * MACROS */ #define MIN(a,b) ((a) < (b) ? a : b) #define MAX(a,b) ((a) > (b) ? a : b) /********************************************************************* * TYPEDEFS */ /*! Struct that contains a PCM queue element and a pointer to the data buffer it is responsible for */ typedef struct [ Queue_Elem _elem; /*!< Queue element */ PDMCC26XX_pcmBuffer *pBufferPCM; /*!< Pointer to a ::PDMCC26XX_pcmBuffer */ ] PDMCC26XX_queuePCM; /********************************************************************* * LOCAL VARIABLES */ /* PDM Task Configuration */ Task_Struct pdmTask; Char pdmTaskStack[PDM_TASK_STACK_SIZE]; /* PDM Hwi Configuration */ Hwi_Struct pdmHwi; Hwi_Params pdmHwiParams; /* Static allocated memory for PDM data stream * Used instead of dynamic allocation due to heap fragmentation seen during test. */ pdmSample_t pdmContinuousBuffer[PDM_BUFFER_SIZE_IN_BLOCKS * PDM_BLOCK_SIZE_IN_SAMPLES * PDM_NUM_OF_CHANNELS]; uint8_t pdmContMgtBuffer[PDM_BUFFER_SIZE_IN_BLOCKS * I2S_BLOCK_OVERHEAD_IN_BYTES]; /* Keep track of compression variables */ static PDMCC26XX_metaData metaDataForNextFrame = [0]; static int32_t decimationFilterInRAM[sizeof(PDMCC26XX_aBqCoeffs) / sizeof(PDMCC26XX_aBqCoeffs[0])]; static uint32_t decimationState[6+5*2] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; static Queue_Struct pcmMsgReady; static Queue_Handle pcmMsgReadyQueue; static Event_Struct sPDMEvents; static Event_Handle pdmEvents; static PDMCC26XX_Handle pdmHandle = NULL; static int byteCount = 0; static int currTempBufIndex = 0; static PDMCC26XX_queuePCM *activePcmBuffer; PDMCC26XX_StreamNotification streamNotification = [ .arg = NULL, .status = PDMCC26XX_STREAM_IDLE ]; PDMCC26XX_I2S_StreamNotification pdmStream; PDMCC26XX_I2S_Handle i2sHandle; /********************************************************************* * LOCAL FUNCTIONS */ static void PDMCC26XX_taskFxn(UArg a0, UArg a1); static bool PDMCC26XX_initIO(PDMCC26XX_Handle handle); static void PDMCC26XX_setPcmBufferReady(PDMCC26XX_Handle handle, PDMCC26XX_queuePCM *pcmBuffer, PDMCC26XX_I2S_BufferRequest *bufReq); static PDMCC26XX_queuePCM * PDMCC26XX_getNewPcmBuffer(PDMCC26XX_Handle handle); static void PDMCC26XX_i2sCallbackFxn(PDMCC26XX_I2S_Handle handle, PDMCC26XX_I2S_StreamNotification *notification); static void PDMCC26XX_rollbackDriverInitialisation(PDMCC26XX_Handle handle, uint32_t rollbackVector); /********************************************************************* * EXTERNAL FUNCTIONS */ extern bool pdm2pcm16k(const void* pIn, uint32_t* pState, const int32_t* pBqCoeffs, int16_t* pOut); extern uint8_t tic1_EncodeBuff(uint8_t* dst, int16_t* src, int16_t srcSize, int8_t *si, int16_t *pv); /********************************************************************* * PUBLIC FUNCTIONS */ void PDMCC26XX_init(PDMCC26XX_Handle handle); PDMCC26XX_Handle PDMCC26XX_open(PDMCC26XX_Params *params); void PDMCC26XX_close(PDMCC26XX_Handle handle); bool PDMCC26XX_startStream(PDMCC26XX_Handle handle); bool PDMCC26XX_stopStream(PDMCC26XX_Handle handle); bool PDMCC26XX_requestBuffer(PDMCC26XX_Handle handle, PDMCC26XX_BufferRequest *bufferRequest); /* * ======== PDMCC26XX_init ======== * @pre Function assumes that it is called *once* on startup before BIOS init * * @param handle handle to the PDM object */ void PDMCC26XX_init(PDMCC26XX_Handle handle) [ /* Locals */ PDMCC26XX_Object *object; PDMCC26XX_HWAttrs const *pdmCC26XXHWAttrs; Task_Params taskParams; /* Set local reference to return to callers */ pdmHandle = handle; /* Get object for this handle */ object = handle->object; pdmCC26XXHWAttrs = handle->hwAttrs; /* Mark the objects as available */ object->isOpen = false; /* Then initialize I2S driver */ i2sHandle = (PDMCC26XX_I2S_Handle)&(PDMCC26XX_I2S_config); PDMCC26XX_I2S_init(i2sHandle); /* Configure task */ Task_Params_init(&taskParams); taskParams.stack = pdmTaskStack; taskParams.stackSize = PDM_TASK_STACK_SIZE; taskParams.priority = pdmCC26XXHWAttrs->taskPriority; /* Construct task */ Task_construct(&pdmTask, PDMCC26XX_taskFxn, &taskParams, NULL); ] /* * ======== PDMCC26XX_open ======== * @brief Function for opening the PDM driver on CC26XX devices * * @param params Parameters needed to configure the driver * * @return handle to the opened PDM driver */ PDMCC26XX_Handle PDMCC26XX_open(PDMCC26XX_Params *params) [ PDMCC26XX_Handle handle; PDMCC26XX_Object *object; unsigned int key; /* Get handle for this driver instance */ handle = pdmHandle; /* Get the pointer to the object */ object = handle->object; /* Disable preemption while checking if the PDM is open. */ key = Hwi_disable(); /* Check if the PDM is open already with the base addr. */ if (object->isOpen == true) [ Hwi_restore(key); Log_warning0("PDM: already in use."); return (NULL); ] /* Mark the handle as being used */ object->isOpen = true; Hwi_restore(key); /* Initialize the PDM object */ object->callbackFxn = params->callbackFxn; object->useDefaultFilter = params->useDefaultFilter; object->micGain = params->micGain; object->micPowerActiveHigh = params->micPowerActiveHigh; object->applyCompression = params->applyCompression; object->startupDelayWithClockInSamples = params->startupDelayWithClockInSamples; object->bStreamStarted = false; object->streamNotification = &streamNotification; object->mallocFxn = params->mallocFxn; object->freeFxn = params->freeFxn; object->retBufSizeInBytes = params->retBufSizeInBytes; /* Get first buffer for PCM data so that we don't get NULL * pointer exception. */ if ((activePcmBuffer = PDMCC26XX_getNewPcmBuffer(pdmHandle)) == NULL) [ /* We didn't manage to allocate enough space on the heap for the activePcmBuffer. * Exit with return value NULL to prevent the driver running with activePcmBuffer == NULL */ PDMCC26XX_rollbackDriverInitialisation(handle, PDM_ROLLBACK_OPEN); Log_warning0("PDM: heap is full could not allocate space for activePcmBuffer."); return (NULL); ] /* Default PDMCC26XX_I2S parameters structure */ PDMCC26XX_I2S_Params PDMCC26XX_I2S_params = [ .requestMode = PDMCC26XX_I2S_CALLBACK_MODE, .ui32requestTimeout = BIOS_WAIT_FOREVER, .callbackFxn = PDMCC26XX_i2sCallbackFxn, .blockSize = PDM_BLOCK_SIZE_IN_SAMPLES, .pvContBuffer = (void *) pdmContinuousBuffer, .ui32conBufTotalSize = sizeof(pdmContinuousBuffer), .pvContMgtBuffer = (void *) pdmContMgtBuffer, .ui32conMgtBufTotalSize = sizeof(pdmContMgtBuffer), .currentStream = &pdmStream ]; /* Init IOs */ if (PDMCC26XX_initIO(handle) == false)[ /* We couldn't allocate the necessary pins though the PIN driver. */ PDMCC26XX_rollbackDriverInitialisation(pdmHandle, PDM_ROLLBACK_OPEN | PDM_ROLLBACK_ACTIVE_PCM_BUFFER); Log_warning0("PDM: PIN driver could not allocate necessary i/o's."); return (NULL); ] /* Then open the interface with these parameters */ if ((i2sHandle = PDMCC26XX_I2S_open(i2sHandle, &PDMCC26XX_I2S_params)) == NULL)[ PDMCC26XX_rollbackDriverInitialisation(pdmHandle, PDM_ROLLBACK_OPEN | PDM_ROLLBACK_ACTIVE_PCM_BUFFER | PDM_ROLLBACK_PIN); Log_print0(Diags_USER1, "Failed to open the I2S driver"); return (NULL); ] /* Set dependency on the UDMA. This makes sure it's clocked, which in turn keeps the system bus active. */ Power_setDependency(PowerCC26XX_PERIPH_UDMA); /* Construct ready and available queues */ Queue_construct(&pcmMsgReady, NULL); pcmMsgReadyQueue = Queue_handle(&pcmMsgReady); /* Initialize filters */ if (object->useDefaultFilter) [ /* Use default */ object->decimationFilter = decimationFilterInRAM; memcpy(object->decimationFilter, PDMCC26XX_aBqCoeffs, sizeof(PDMCC26XX_aBqCoeffs)); ] else [ object->decimationFilter = params->decimationFilter; ] /* Apply gain, if set */ if (object->micGain < PDMCC26XX_GAIN_END) [ object->decimationFilter[0] = PDMCC26XX_gainTable[object->micGain]; ] return (handle); ] /* * ======== PDMCC26XX_close ======== * @brief Function for closing the PDM driver on CC26XX devices * * @param handle Handle to the PDM object */ void PDMCC26XX_close(PDMCC26XX_Handle handle) [ /* Post close event to shutdown synchronously and prevent resetting settings and datastructures in the middle of a block ready event */ Event_post(pdmEvents, PDM_EVT_CLOSE); Log_print0(Diags_USER1, "PDM: close event posted"); ] /* * ======== PDMCC26XX_startStream ======== * @brief Function for starting a PDM stream * * @param handle Handle to the PDM object * * @pre ::PDMCC26XX_open() must be called first and there must not already be a stream in progress. * * @return true if stream started, false if something went wrong. */ bool PDMCC26XX_startStream(PDMCC26XX_Handle handle) [ unsigned int key; PDMCC26XX_Object *object; PDMCC26XX_HWAttrs const *hwAttrs; object = handle->object; hwAttrs = handle->hwAttrs; /* Disable preemption while checking if a transfer is in progress */ key = Hwi_disable(); if (object->bStreamStarted) [ Hwi_restore(key); Log_error0("PDM: stream in progress"); /* Stream is in progress */ return (false); ] /* Power microphone --> It typically requires some startup time */ PIN_setOutputValue(object->pinHandle, hwAttrs->micPower, (object->micPowerActiveHigh) ? 1 : 0); uint32_t i = 0; /* Reset decimation states */ for (i = 0; i < sizeof(decimationState)/sizeof(decimationState[0]); ++i) [ decimationState = 0x00; ] /* Move unused ready elements to available queue*/ while (!Queue_empty(pcmMsgReadyQueue)) [ PDMCC26XX_queuePCM *readyNode = Queue_dequeue(pcmMsgReadyQueue); /* Free up memory used for PCM data buffer */ object->freeFxn(readyNode->pBufferPCM, object->retBufSizeInBytes); /* Then free up memory used by the queue element */ object->freeFxn(readyNode, sizeof(PDMCC26XX_queuePCM)); ] /* Reset compression data */ metaDataForNextFrame.seqNum = 0; metaDataForNextFrame.si = 0; metaDataForNextFrame.pv = 0; /* Then start stream */ if (PDMCC26XX_I2S_startStream(i2sHandle)) [ /* The starting of stream succeeded, don't allow the device to enter * standby. */ Power_setConstraint(PowerCC26XX_SB_DISALLOW); /* Make sure to flag that a stream is now active */ object->bStreamStarted = true; Hwi_restore(key); /* Let thread prepare to throw the first PDM_DECIMATION_STARTUP_DELAY_IN_SAMPLES samples */ Event_post(pdmEvents, PDM_EVT_START); return true; ] else [ /* If the starting of stream failed, return false*/ Hwi_restore(key); return false; ] ] /* * ======== PDMCC26XX_stopStream ======== * @brief Function for starting a PDM stream * * @param handle Handle to the PDM object * * @pre ::PDMCC26XX_startStream must have been called first. * * @return true if stream stopped correctly, false if something went wrong. */ bool PDMCC26XX_stopStream(PDMCC26XX_Handle handle) [ unsigned int key; bool retVal = false; PDMCC26XX_Object *object; PDMCC26XX_HWAttrs const *hwAttrs; /* Get the pointer to the object and hwAttr */ object = handle->object; hwAttrs = handle->hwAttrs; /* Disable preemption while checking if a transfer is in progress */ key = Hwi_disable(); if (!(object->bStreamStarted)) [ Hwi_restore(key); Log_error0("PDM: stream not in progress"); /* Stream is not in progress */ return (false); ] /* Make sure to flag that a stream is no longer active */ object->bStreamStarted = false; Hwi_restore(key); if (!PDMCC26XX_I2S_stopStream(i2sHandle)) [ /* We failed to stop!! */ object->bStreamStarted = true; ] else [ /* Allow system to enter standby again */ Power_releaseConstraint(PowerCC26XX_SB_DISALLOW); /* Unpower microphone */ PIN_setOutputValue(object->pinHandle, hwAttrs->micPower, (object->micPowerActiveHigh) ? 0 : 1); retVal = true; ] return retVal; ] /********************************************************************* * @fn PDMCC26XX_taskFxn * * @brief PDM task function which is processing the PDM events from the * driver (e.g. callback). * * @param none * * @return none */ static void PDMCC26XX_taskFxn(UArg a0, UArg a1) [ uint32_t events; static int16_t tempPcmBuf[32]; PDMCC26XX_I2S_BufferRequest bufferRequest; PDMCC26XX_I2S_BufferRelease bufferRelease; static uint32_t throwAwayCount = 0; static bool pcmBufferFull = false; static bool tempBufActive = false; PDMCC26XX_Object *object; object = pdmHandle->object; /* Semaphore and event for the task */ Event_Params evParams; Event_Params_init(&evParams); Event_construct(&sPDMEvents, &evParams); pdmEvents = Event_handle(&sPDMEvents); /* Loop forever */ for (;;) [ events = Event_pend(pdmEvents, Event_Id_NONE, (PDM_EVT_BLK_RDY | PDM_EVT_START | PDM_EVT_BLK_ERROR | PDM_EVT_CLOSE), BIOS_WAIT_FOREVER); if ( events & PDM_EVT_CLOSE) [ /* Release dependency on the UDMA, such that the bus can be deactivated as needed */ Power_releaseDependency(PowerCC26XX_PERIPH_UDMA); /* Move unused ready elements to available queue */ while (!Queue_empty(pcmMsgReadyQueue)) [ PDMCC26XX_queuePCM *readyNode = Queue_dequeue(pcmMsgReadyQueue); /* Free up memory used for PCM data buffer */ object->freeFxn(readyNode->pBufferPCM, object->retBufSizeInBytes); /* Then free up memory used by the queue element */ object->freeFxn(readyNode, sizeof(PDMCC26XX_queuePCM)); ] Queue_destruct(&pcmMsgReady); Hwi_destruct(&pdmHwi); /* * Deallocate the activePcmBuffer, close down the I2S driver, release the pins back to the PIN driver, and set the PDM driver to closed. */ PDMCC26XX_rollbackDriverInitialisation(pdmHandle, PDM_ROLLBACK_OPEN | PDM_ROLLBACK_ACTIVE_PCM_BUFFER | PDM_ROLLBACK_I2S_DRIVER | PDM_ROLLBACK_PIN); Log_print0(Diags_USER1, "PDM: close driver synchronously"); /* Cancel all other queued events. After closed is called, we don't want the driver to do anything else without being reopened. */ events &= 0; ] if ( events & PDM_EVT_START ) [ pcmBufferFull = false; byteCount = 0; tempBufActive = false; /* Some microphones require a startup delay with clock applied. The * throw counter is used for this. */ if(object->applyCompression) [ /* If compression is enabled, the throwAwayCount is decremented * with respect to compressed data output. This number is the half * of the number of samples: */ throwAwayCount = MAX(PDM_DECIMATION_STARTUP_DELAY_IN_SAMPLES / 2, object->startupDelayWithClockInSamples / 2); ] else [ /* If compression is disabled, the throwAwayCount is decremented * with respect to raw data, but in bytes not samples. Each sample * is two bytes and the throwAwayCount is operating * in bytes, this gives us: */ throwAwayCount = MAX(PDM_DECIMATION_STARTUP_DELAY_IN_SAMPLES * 2, object->startupDelayWithClockInSamples * 2); ] events &= ~PDM_EVT_START; ] if ( events & PDM_EVT_BLK_ERROR ) [ /* Notify caller of error */ streamNotification.status = PDMCC26XX_STREAM_ERROR; object->callbackFxn(pdmHandle, &streamNotification); ] if ( events & PDM_EVT_BLK_RDY ) [ /* Request PDM data from I2S driver */ while ( PDMCC26XX_I2S_requestBuffer(i2sHandle, &bufferRequest) ) [ /* Buffer is available as long as it returns true */ if (throwAwayCount == 0) [ /* Get new buffer from queue if active PCM buffer * is full. */ if (pcmBufferFull) [ /* PDMCC26XX_getNewPcmBuffer() * Get new container from available queue and allocate * memory for new buffer. */ if ((activePcmBuffer = PDMCC26XX_getNewPcmBuffer(pdmHandle)) != NULL) [ pcmBufferFull = false; byteCount = 0; ] else [ /* If we did not succeed getting a new pcm buffer, we * need to start throwing data. * * Update throwAwayCount * In this case throw bytes equal to the size of the * PCM buffer minus the data output size of one iteration * (which is dependent on compression/no compression). * * Note: Assuming that the (object->retBufSizeInBytes-PCM_METADATA_SIZE) is * larger than the data output of one iteration. */ if((object->retBufSizeInBytes-PCM_METADATA_SIZE) > (object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE))[ throwAwayCount = (object->retBufSizeInBytes-PCM_METADATA_SIZE) - (object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE); ] else [ /* If the retBufSizeInBytes without the metadata is less than the output of one iteration, we would get an underflow on the throwAwayCount. * Instead, we throw away the entire buffer and leave the throwAwayCount at 0. * Since we've thrown away more than one PCM buffer worth of PDM data, we need to increment sequence number. */ metaDataForNextFrame.seqNum++; ] ] ] /* Decimate PDM data to PCM, result is stored in tempPcmBuf */ pdm2pcm16k(bufferRequest.bufferIn, decimationState, object->decimationFilter, (int16_t *)&tempPcmBuf); /* Mark the temp buf as active */ tempBufActive = true; /* Since the tempPcmBuffer might fill up the current pcm * buffer, we might have to perform the operation (compression * or memcpy) on the tempPcmBuffer in more than one iteration. * * If we did not allocate a new buffer succesfully above, we * are about to throw away data. In that case we should not * perform an operation on the PDM data. */ while(tempBufActive && !pcmBufferFull) [ int srcSize; /* Next step is to handle the data in the tempPcmBuffer * - If compression is enabled, the compression function * will read in data from tempPcmBuffer and output the * compressed data to the dynamically allocated pcmBuffer. * - If compression is disabled, we use memcpy to move the pcm * data from the tempPcmBuffer to the dynamically allocated * pcmBuffer. */ if (object->applyCompression) [ /* Prepare metadata. * This is done before the first compression into the * allocated PCM buffer. */ if(byteCount == 0) [ activePcmBuffer->pBufferPCM->metaData.si = metaDataForNextFrame.si; activePcmBuffer->pBufferPCM->metaData.pv = metaDataForNextFrame.pv; ] /* If the current PCM buffer can fit the output of a * compression of what is left in tempPcmBuf, set srcSize * to that size. If not, set the srcSize to whatever will * fit and mark the current pcm buffer as full. * * Note: currTempBufIndex will always be multiple of 2. */ if (((object->retBufSizeInBytes-PCM_METADATA_SIZE) - byteCount) > PDMCC26XX_COMPR_ITER_OUTPUT_SIZE - (currTempBufIndex/2)) [ /* srcSize set to whatever is left in the tempPcmBuffer. */ srcSize = PDMCC26XX_COMPR_ITER_OUTPUT_SIZE*2 - currTempBufIndex; ] else [ /* This is the last compression into the current data buffer, * mark it as full. */ pcmBufferFull = true; srcSize = ((object->retBufSizeInBytes-PCM_METADATA_SIZE) - byteCount)*2; ] /* Perform compression * * Since the source (tempPcmBuf) is operated as int16_t, * while the output as uint8_t srcSize is size in samples * (int16), it must be multiple of 2. */ Codec1_encodeBuff((uint8_t *)&(activePcmBuffer->pBufferPCM->pBuffer[byteCount]), (int16_t *)&(tempPcmBuf[currTempBufIndex]), srcSize, (int8_t *)&metaDataForNextFrame.si, (int16_t *)&metaDataForNextFrame.pv); /* Update byteCount for next iteration. * * Since the compression is reduzing the size with a factor 4, * and the pcm output buffer and the tempPcm buffer are of * different types, the byteCount will be incremented with * half the size of srcSize. */ byteCount += srcSize/2; /* Prepare currTempBufIndex for next iteration */ currTempBufIndex += srcSize; ] else [ /* Compression is disabled */ /* Compression will not be performed, so we copy data from * temporary pcm buffer to allocated memory. Uncompressed * PCM data buffer is 64 Bytes wide. * * Output and input are handled as bytes. */ if (((object->retBufSizeInBytes-PCM_METADATA_SIZE) - byteCount) > (PDMCC26XX_CPY_ITER_OUTPUT_SIZE - (currTempBufIndex*2))) [ srcSize = PDMCC26XX_CPY_ITER_OUTPUT_SIZE - (currTempBufIndex*2); ] else [ /* This is the last compression into the current data buffer, * mark it as full. */ pcmBufferFull = true; srcSize = (object->retBufSizeInBytes-PCM_METADATA_SIZE) - byteCount; ] /* Copy PCM data from temp buffer to allocated memory */ memcpy(&(activePcmBuffer->pBufferPCM->pBuffer[byteCount]), &tempPcmBuf[currTempBufIndex], srcSize);/* <- size in bytes */ /* Prepare byteCount for next iteration, for memcpy the * byteCount is equal to the srcSize. */ byteCount += srcSize; /* Prepare currTempBufIndex for next iteration. * Since the srcSize is byte aligned, but the tempBuffer * is sample (int16_t) aligned, divide srcSize with 2. */ currTempBufIndex += srcSize/2; ] /* Is all the data in the tempPcmBuffer consumed? * If so, reset the index count and clear active flag. * */ if(currTempBufIndex >= (sizeof(tempPcmBuf)/sizeof(tempPcmBuf[0]))) [ tempBufActive = false; currTempBufIndex = 0; ] if (pcmBufferFull) [ /* If the allocated PCM buffer is full, we need to flag * that the PCM buffer is ready (and making the callback). * * And last, allocate a new PCM buffer to be used. */ PDMCC26XX_setPcmBufferReady(pdmHandle, activePcmBuffer, (PDMCC26XX_I2S_BufferRequest *)&bufferRequest); /* Get new PCM buffer from available queue and allocate * memory for new buffer. */ if ((activePcmBuffer = PDMCC26XX_getNewPcmBuffer(pdmHandle)) != NULL) [ pcmBufferFull = false; byteCount = 0; ] else [ /* if we did not succeed getting a new pcm buffer, * we need to start throwing data. * * Update ThrowCount * In this case throw count is equal to data fitting * in one allocated PCM buffer minus the output data * which will be thrown in this iteration. * Data thrown amount is data size of one iteration (which is dependent on * compression/no compression), minus the data already * consumed by the previous buffer. */ if((object->retBufSizeInBytes-PCM_METADATA_SIZE) > (object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE) - currTempBufIndex)[ throwAwayCount = (object->retBufSizeInBytes-PCM_METADATA_SIZE) - ((object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE) - currTempBufIndex); ] else [ /* If the retBufSizeInBytes without the metadata is less than the output of one iteration minus the currTempBufIndex, we would get an underflow on the throwAwayCount. * Instead, we throw away the entire buffer and leave the throwAwayCount at 0. * Since we've thrown away more than one PCM buffer worth of PDM data, we need to increment sequence number. */ metaDataForNextFrame.seqNum++; ] /* Mark the tempBuf as no longer active */ tempBufActive = false; ] ] ] ] else [ /* Still throwing away data */ if (throwAwayCount<=(object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE)) [ /* if the amount to be thrown away is less than or equal to * the output of one iteration of the data operation, the * count must be set to zero, the sequence number must be * incremented, and the index to be used by next data operation * must be updated correspondingly. */ /* Note: Currently the startup delay will use the throwAwayCount * and that means the sequence number will be incremented * after the startup throwing has finished. */ metaDataForNextFrame.seqNum++; /* tempPcmBuf is int16 array, but the throwAwayCount is * count in bytes. */ if(object->applyCompression) [ /* If compression is enabled, the throwAwayCount number * is the half of the number of samples: */ currTempBufIndex = throwAwayCount * 2; ] else [ /* If compression is disabled, the throwAwayCount is decremented * with respect to raw data, but in bytes not samples. Since * the currTempBufIndex is sample oriented, we need to divide * that number with 2. */ currTempBufIndex = (throwAwayCount + 1) / 2; ] throwAwayCount = 0; ] else [ /* Decrement the throw counter with amount corresponding to * output data size of one iteration. */ throwAwayCount -= (object->applyCompression ? PDMCC26XX_COMPR_ITER_OUTPUT_SIZE : PDMCC26XX_CPY_ITER_OUTPUT_SIZE); ] ] /* Release PDM buffer */ bufferRelease.bufferHandleIn = bufferRequest.bufferHandleIn; PDMCC26XX_I2S_releaseBuffer(i2sHandle, &bufferRelease); ] events &= ~PDM_EVT_BLK_RDY; ] ] ] /* * ======== PDMCC26XX_requestBuffer ======== * @pre Function assumes that the stream has started and that bufferRequest is not NULL. */ bool PDMCC26XX_requestBuffer(PDMCC26XX_Handle handle, PDMCC26XX_BufferRequest *bufferRequest) [ PDMCC26XX_Object *object; /* Get the pointer to the object */ object = pdmHandle->object; /* We expect the user to call this after being notified of available * buffers. Hence we may directly check queue and dequeue buffer */ if (!Queue_empty(pcmMsgReadyQueue))[ PDMCC26XX_queuePCM *readyNode = Queue_get(pcmMsgReadyQueue); /* Provide pointer to buffer including 4 byte metadata */ bufferRequest->buffer = readyNode->pBufferPCM; bufferRequest->status = streamNotification.status; /* free up memory used by queue element */ object->freeFxn(readyNode, sizeof(PDMCC26XX_queuePCM)); ] else [ return false; ] return true; ] static void PDMCC26XX_i2sCallbackFxn(PDMCC26XX_I2S_Handle handle, PDMCC26XX_I2S_StreamNotification *notification) [ if (notification->status == PDMCC26XX_I2S_STREAM_ERROR) [ /* Let thread process PDM error */ Event_post(pdmEvents, PDM_EVT_BLK_ERROR); ] else [ /* Let thread process PDM data */ Event_post(pdmEvents, PDM_EVT_BLK_RDY); ] ] /* * ======== PDMCC26XX_initIO ======== * This functions initializes the PDM IOs. * * @pre Function assumes that the PDM handle is pointing to a hardware * module which has already been opened. */ static bool PDMCC26XX_initIO(PDMCC26XX_Handle handle) [ PDMCC26XX_Object *object; PDMCC26XX_HWAttrs const *hwAttrs; PIN_Config micPinTable[PDM_NUMBER_OF_PINS + 1]; uint32_t i=0; /* Get the pointer to the object and hwAttrs */ object = handle->object; hwAttrs = handle->hwAttrs; /* Configure IOs */ /* Build local list of pins, allocate through PIN driver and map HW ports */ if (hwAttrs->micPower != PIN_UNASSIGNED) [ micPinTable[i++] = hwAttrs->micPower | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX; ] micPinTable = PIN_TERMINATE; /* Open and assign pins through pin driver */ if (!(object->pinHandle = PIN_open(&(object->pinState), micPinTable))) [ return false; ] return true; ] /* * ======== PDMCC26XX_setPcmBufferReady ======== * This function prepares metadata, puts the buffer in ready queue, sets stream * status and makes the callback. * * @pre Function assumes that the PDM handle is pointing to a hardware * module which has already been opened. */ static void PDMCC26XX_setPcmBufferReady(PDMCC26XX_Handle handle, PDMCC26XX_queuePCM *pcmBuffer, PDMCC26XX_I2S_BufferRequest *bufReq) [ PDMCC26XX_Object *object; object = handle->object; /* Update sequence number */ pcmBuffer->pBufferPCM->metaData.seqNum = metaDataForNextFrame.seqNum++; /* Place PCM buffer in ready queue */ Queue_put(pcmMsgReadyQueue, &pcmBuffer->_elem); /* Notify caller by updating the stream status */ if (bufReq->status == PDMCC26XX_I2S_STREAM_BUFFER_READY) [ streamNotification.status = PDMCC26XX_STREAM_BLOCK_READY; ] else if (bufReq->status == PDMCC26XX_I2S_STREAM_BUFFER_READY_BUT_NO_AVAILABLE_BUFFERS) [ streamNotification.status = PDMCC26XX_STREAM_BLOCK_READY_BUT_PDM_OVERFLOW; ] else [ streamNotification.status = PDMCC26XX_STREAM_STOPPING; ] /* Only notify when PCM buffer is complete */ object->callbackFxn(pdmHandle, &streamNotification); ] /* * ======== PDMCC26XX_getNewPcmBuffer ======== * This function gets a new queue element from the available queue and then * tries to allocate the memory space needed for a new buffer. * * @return true if a new PCM buffer was succesfully allocated, false if the * available queue was empty or the memory allocation function did not * succeed. */ static PDMCC26XX_queuePCM * PDMCC26XX_getNewPcmBuffer(PDMCC26XX_Handle handle) [ PDMCC26XX_Object *object; PDMCC26XX_queuePCM *buf; object = handle->object; /* Allocate memory for a new queue element */ buf = object->mallocFxn(sizeof(PDMCC26XX_queuePCM)); /* If allocation went OK, allocate more... */ if (buf != NULL) [ /* Dynamically allocated memory for new pcm buffer */ buf->pBufferPCM = object->mallocFxn(object->retBufSizeInBytes); /* If new memory was allocated correctly, return pointer. */ if (buf->pBufferPCM != NULL) [ return buf; ] else [ /* Was not able to allocate memory for the pcm buffer, deallocate * the memory used by queue element. */ object->freeFxn(buf, sizeof(PDMCC26XX_queuePCM)); ] ] return NULL; ] /* * ======== PDMCC26XX_rollbackDriverInitialisation ======== * This function rolls back different parts of the PDM driver initialisation depending on the rollbackVector. * Passing ~0 as the rollbackVector will reverse all failable initialisations. * Only those parts of the driver that can fail when calling PDMCC26XX_open can be included as entries in the rollbackVector. */ static void PDMCC26XX_rollbackDriverInitialisation(PDMCC26XX_Handle handle, uint32_t rollbackVector)[ unsigned int key; PDMCC26XX_Object *object; object = handle->object; if (rollbackVector & PDM_ROLLBACK_I2S_DRIVER) [ /* Release ownership and revert to init settings. */ PDMCC26XX_I2S_close(i2sHandle); ] if (rollbackVector & PDM_ROLLBACK_PIN) [ /* Release the allocated pins back to the pin driver */ PIN_close(object->pinHandle); ] if (rollbackVector & PDM_ROLLBACK_ACTIVE_PCM_BUFFER) [ /* * Free the activePcmBuffer if it is not NULL. It can be NULL if either insufficient time was provided after PDMCC26XX_open for * the open event in the task function to run and allocate the memory or if we ran out of heap space earlier and the PDMCC26XX_getNewPcmBuffer * function returned NULL. */ if(activePcmBuffer != NULL)[ /* Free up memory used for activePcmBuffer */ object->freeFxn(activePcmBuffer->pBufferPCM, object->retBufSizeInBytes); /* Then free up memory used by the queue element */ object->freeFxn(activePcmBuffer, sizeof(PDMCC26XX_queuePCM)); /* Make sure the activePcmBuffer doesn't point anywhere anymore as the target no longer exists. */ activePcmBuffer = NULL; ] ] if (rollbackVector & PDM_ROLLBACK_OPEN) [ /* Mark the module as available */ key = Hwi_disable(); object->isOpen = false; Hwi_restore(key); ] ] |
|
|
|
|
|
只有小组成员才能发言,加入小组>>
NA555DR VCC最低电压需要在5V供电,为什么用3.3V供电搭了个单稳态触发器也使用正常?
669 浏览 3 评论
MSP430F249TPMR出现高温存储后失效了的情况,怎么解决?
597 浏览 1 评论
对于多级放大电路板,在PCB布局中,电源摆放的位置应该注意什么?
1048 浏览 1 评论
731 浏览 0 评论
普中科技F28335开发板每次上电复位后数码管都会显示,如何熄灭它?
520 浏览 1 评论
请问下tpa3220实际测试引脚功能和官方资料不符,哪位大佬可以帮忙解答下
158浏览 20评论
请教下关于TAS5825PEVM评估模块原理图中不太明白的地方,寻求答疑
120浏览 14评论
在使用3254进行录音的时候出现一个奇怪的现象,右声道有吱吱声,请教一下,是否是什么寄存器设置存在问题?
123浏览 13评论
TLV320芯片内部自带数字滤波功能,请问linein进来的模拟信号是否是先经过ADC的超采样?
122浏览 12评论
TPA6304-Q1: TPA6304 两片公用一组I2C的话,其中一片配置不成功怎么办
164浏览 10评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 22:42 , Processed in 0.695665 second(s), Total 58, Slave 45 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号