MXC_A39_20240320/SW/components/drivers/peripheral/Src/driver_i2s.c

514 lines
16 KiB
C

/*
******************************************************************************
* @file driver_i2s.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief I2S module driver.
* This file provides firmware functions to manage the
* Inter¡ªIC Sound (I2S) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn i2s_IRQHandler
*
* @brief Handle I2S interrupt request.
*
* @param huart: I2S handle.
*/
//void i2s_IRQHandler(I2S_HandleTypeDef *hi2s)
//{
// /* Format 20Bit/24Bit/32bit */
// if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
// {
// /* TxFIFO half full interrupt enable */
// if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_FIFOS_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_FULL))
// {
// /* right channel*/
// if (hi2s->u32_TxCount % 2)
// {
// hi2s->I2Sx->DATA_R = hi2s->p_TxData[hi2s->u32_TxCount++];
// }
// /* left channel*/
// else
// {
// hi2s->I2Sx->DATA_L = hi2s->p_TxData[hi2s->u32_TxCount++];
// }
//
// if (hi2s->u32_TxCount >= hi2s->u32_TxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_TX_FIFOS_HALF_FULL);
//
// hi2s->b_TxBusy = false;
//
// break;
// }
// }
// }
// }
// /* Rx FIFO full interrupt enable */
// if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_EMPTY))
// {
// /* right channel*/
// if (hi2s->u32_RxCount % 2)
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_R;
// }
// /* left channel*/
// else
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_L;
// }
//
// if(hi2s->u32_RxCount >= hi2s->u32_RxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL);
//
// hi2s->b_RxBusy = false;
// break;
// }
// }
// }
// }
// }
// /* Format 8Bit/16Bit */
// else
// {
// /* TxFIFO half full interrupt enable */
// if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_L_FIFO_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_FULL))
// {
// hi2s->I2Sx->DATA_L = hi2s->p_TxData[hi2s->u32_TxCount++];
//
// if (hi2s->u32_TxCount >= hi2s->u32_TxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_TX_L_FIFO_HALF_FULL);
//
// hi2s->b_TxBusy = false;
//
// break;
// }
// }
// }
// }
// /* Rx FIFO full interrupt enable */
// if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL))
// {
// /* FIFO half full */
// if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_HALF_FULL))
// {
// while(!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_EMPTY))
// {
// hi2s->p_RxData[hi2s->u32_RxCount++] = hi2s->I2Sx->DATA_L;
//
// if(hi2s->u32_RxCount >= hi2s->u32_RxSize)
// {
// __I2S_INT_DISABLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL);
//
// hi2s->b_RxBusy = false;
// break;
// }
// }
// }
// }
// }
//}
void i2s_IRQHandler(I2S_HandleTypeDef *hi2s)
{
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
/* TxFIFO half full interrupt enable */
if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_FIFOS_ALMOST_EMPTY))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_ALMOST_EMPTY))
{
if (hi2s->TxIntCallback)
{
hi2s->TxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
hi2s->I2Sx->DATA_L = 0;
hi2s->I2Sx->DATA_R = 0;
}
}
}
}
/* Rx FIFO full interrupt enable */
if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_HALF_FULL))
{
if (hi2s->RxIntCallback)
{
hi2s->RxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
volatile uint32_t l_data = hi2s->I2Sx->DATA_L;
volatile uint32_t r_data = hi2s->I2Sx->DATA_R;
}
}
}
}
}
/* Format 8Bit/16Bit */
else
{
/* TxFIFO half full interrupt enable */
if (__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_TX_L_FIFO_ALMOST_EMPTY))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_ALMOST_EMPTY))
{
if (hi2s->TxIntCallback)
{
hi2s->TxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
hi2s->I2Sx->DATA_L = 0;
}
}
}
}
/* Rx FIFO full interrupt enable */
if(__I2S_INT_IS_ENANLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL))
{
/* FIFO half full */
if ((__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_HALF_FULL))
{
if (hi2s->RxIntCallback)
{
hi2s->RxIntCallback(hi2s);
}
else
{
for (uint32_t i=0; i<I2S_FIFO_HALF_DEPTH; i++)
{
volatile uint32_t l_data = hi2s->I2Sx->DATA_L;
}
}
}
}
}
}
/************************************************************************************
* @fn i2s_init
*
* @brief Initialize the I2S peripheral according to the specified
* parameters in the struct_I2SInit_t
*
* @param hi2s: I2S handle.
*/
void i2s_init(I2S_HandleTypeDef *hi2s)
{
hi2s->b_TxBusy = false;
hi2s->b_RxBusy = false;
/* disable all interrupt */
__I2S_INT_DISABLE(hi2s->I2Sx, I2S_ALL_FIFO_STATUS);
/* Enable Rx/Tx FIFO */
__I2S_RxFIFO_EN(hi2s->I2Sx);
__I2S_TxFIFO_EN(hi2s->I2Sx);
/* Clear Rx/Tx FIFO */
__I2S_RxFIFO_CLR(hi2s->I2Sx);
__I2S_TxFIFO_CLR(hi2s->I2Sx);
/* left and right channels operate simultaneously */
__I2S_WD_SWAP_HIGH16SIZE_RIGHT(hi2s->I2Sx);
/* config mode */
hi2s->I2Sx->CTRL0.MSTSLV = hi2s->Init.Mode;
/* Calculate audio frequency */
hi2s->I2Sx->FrmDiv.BCLKDIV = hi2s->Init.BCLKDIV - 1;
/* Calculate channel length */
hi2s->I2Sx->FrmDiv.FRMDIV = hi2s->Init.ChannelLength - 1;
/* Data length */
hi2s->I2Sx->CTRL1.I2S_DATA_LENGTH = hi2s->Init.DataFormat;
switch (hi2s->Init.Standard)
{
/* philips */
case I2S_STANDARD_PHILIPS:
{
hi2s->I2Sx->CTRL1.I2S_NORMAL = 1;
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* MSB */
case I2S_STANDARD_MSB:
{
hi2s->I2Sx->CTRL1.I2S_NORMAL = 0;
hi2s->I2Sx->CTRL1.I2S_ADJUST = 0;
__I2S_FRAME_INV_ENABLE(hi2s->I2Sx);
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* LSB */
case I2S_STANDARD_LSB:
{
uint32_t data_length[5] = {8,16,20,24,32};
hi2s->I2Sx->CTRL1.I2S_NORMAL = 0;
hi2s->I2Sx->CTRL1.I2S_ADJUST = 1;
hi2s->I2Sx->CTRL1.I2SFBOFF = hi2s->Init.ChannelLength - data_length[hi2s->Init.DataFormat];
__I2S_FRAME_INV_ENABLE(hi2s->I2Sx);
__I2S_ENABLE(hi2s->I2Sx);
}break;
/* PCM */
case I2S_STANDARD_PCM:
{
/* Mono or Stereo select*/
hi2s->I2Sx->PCM_RHYCTRL.PCM_SAMPTYPE = 0;
hi2s->I2Sx->PCM_GENCTRL.PCM_MONO_STEREO = 0;
/* Frame Synchronization signal */
hi2s->I2Sx->PCM_RHYCTRL.PCM_FSYNCSHP = 0;
/* Sample size and slots */
__I2S_PCM_SLOTS_SET(hi2s->I2Sx, 1);
__I2S_PCM_SAMPLESIZE_16BIT(hi2s->I2Sx);
/* ENABLE PCM */
hi2s->I2Sx->PCM_RHYCTRL.PCM_DOUTCFG = 1;
__I2S_PCM_ENABLE(hi2s->I2Sx);
}break;
default: break;
}
}
/************************************************************************************
* @fn i2s_deinit
*
* @brief deinit an ongoing i2s.
*
* @param hi2s: I2S handle.
*/
void i2s_deinit(I2S_HandleTypeDef *hi2s)
{
__I2S_PCM_DISABLE(hi2s->I2Sx);
__I2S_DISABLE(hi2s->I2Sx);
hi2s->b_TxBusy = false;
hi2s->b_RxBusy = false;
}
/************************************************************************************
* @fn i2s_transmit_IT
*
* @brief Transmit an I2S data in interrupt mode, user should send data in TxCallback with
* i2s_send_data function.
*
* @param huart: I2S handle.
*/
bool i2s_transmit_IT(I2S_HandleTypeDef *hi2s)
{
if (hi2s->b_TxBusy) return false;
hi2s->b_TxBusy = true;
__I2S_L_TxFIFO_EMPTY_LEVEL(hi2s->I2Sx, I2S_FIFO_HALF_DEPTH);
__I2S_R_TxFIFO_EMPTY_LEVEL(hi2s->I2Sx, I2S_FIFO_HALF_DEPTH);
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
__I2S_LR_WD_DISABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_TX_FIFOS_ALMOST_EMPTY);
}
/* Format 8Bit/16Bit */
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_TX_L_FIFO_ALMOST_EMPTY);
}
return true;
}
/************************************************************************************
* @fn i2s_receive_IT
*
* @brief Receive an I2S data in interrupt mode. User read received data with function
* i2s_read_data in RxCallback.
*
* @param huart: I2S handle.
*/
bool i2s_receive_IT(I2S_HandleTypeDef *hi2s)
{
if (hi2s->b_RxBusy) return false;
hi2s->b_RxBusy = true;
__I2S_L_RxFIFO_FULL_LEVEL(hi2s->I2Sx, 16);
__I2S_R_RxFIFO_FULL_LEVEL(hi2s->I2Sx, 16);
/* Format 20Bit/24Bit/32bit */
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
__I2S_LR_WD_DISABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_RX_FIFOS_HALF_FULL);
}
/* Format 8Bit/16Bit */
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
__I2S_INT_ENABLE(hi2s->I2Sx, I2S_RX_L_FIFO_HALF_FULL);
}
return true;
}
/************************************************************************************
* @fn i2s_read_data
*
* @brief Read data from RX FIFO. One sample contains left and right channel data. When
* DataFormat is not more than 16-bits, one sample takes 32-bits, left channel data
* is stored in high 16-bits and right channel data is stored in low 16-bits. When
* DataFormat is more than 16-bits, one sample takes 2 words.
*
* @param huart: I2S handle.
* buffer: buffer used to store received data.
* samples: How many samples expected to receive.
*
* @return How many samples read from RX FIFO
*/
uint32_t i2s_read_data(I2S_HandleTypeDef *hi2s, uint32_t *buffer, uint32_t samples)
{
uint32_t count = 0;
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_FIFOS_EMPTY))
&& (count < samples))
{
buffer[count] = hi2s->I2Sx->DATA_L;
buffer[count] = hi2s->I2Sx->DATA_R;
count++;
}
}
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_RX_L_FIFO_EMPTY))
&& (count < samples))
{
buffer[count] = hi2s->I2Sx->DATA_L;
count++;
}
}
return count;
}
/************************************************************************************
* @fn i2s_send_data
*
* @brief write data to TX FIFO. One sample contains left and right channel data. When
* DataFormat is not more than 16-bits, one sample takes 32-bits, left channel data
* is stored in high 16-bits and right channel data is stored in low 16-bits. When
* DataFormat is more than 16-bits, one sample takes 2 words.
*
* @param huart: I2S handle.
* buffer: buffer used to store sending data.
* samples: How many samples expected to send.
*
* @return How many samples sent to TX FIFO
*/
uint32_t i2s_send_data(I2S_HandleTypeDef *hi2s, uint32_t *buffer, uint32_t samples)
{
uint32_t count = 0;
if (hi2s->Init.DataFormat > I2S_DATA_FORMAT_16BIT)
{
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_FIFOS_FULL))
&& (count < samples))
{
hi2s->I2Sx->DATA_L = buffer[count];
hi2s->I2Sx->DATA_R = buffer[count];
count++;
}
}
else
{
__I2S_LR_WD_ENABLE(hi2s->I2Sx);
while ((!(__I2S_GET_INT_STATUS(hi2s->I2Sx) & I2S_TX_L_FIFO_FULL))
&& (count < samples))
{
hi2s->I2Sx->DATA_L = buffer[count];
count++;
}
}
return count;
}
/************************************************************************************
* @fn i2s_transmit_DMA
*
* @brief Transmit an amount of data in DMA mode.
*/
void i2s_transmit_DMA(I2S_HandleTypeDef *hi2s)
{
hi2s->I2Sx->DMA_CFG.DMACR_L_TX = 1;
hi2s->I2Sx->DMA_CFG.DMACR_R_TX = 1;
/* Tx empty dma level */
__I2S_TX_DMA_EMPTY_LEVEL(hi2s->I2Sx, 16);
}
/************************************************************************************
* @fn i2s_receive_DMA
*
* @brief Receive an amount of data in DMA mode.
*/
void i2s_receive_DMA(I2S_HandleTypeDef *hi2s)
{
hi2s->I2Sx->DMA_CFG.DMACR_L_RX = 1;
hi2s->I2Sx->DMA_CFG.DMACR_R_RX = 1;
/* Rx empty dma level */
__I2S_RX_DMA_EMPTY_LEVEL(hi2s->I2Sx, 16);
}