1185 lines
46 KiB
C
1185 lines
46 KiB
C
/**
|
|
*******************************************************************************
|
|
* @file hc32f4a0_i2s.c
|
|
* @brief This file provides firmware functions to manage the Inter IC Sound Bus
|
|
* (I2S).
|
|
@verbatim
|
|
Change Logs:
|
|
Date Author Notes
|
|
2020-06-12 Yangjp First version
|
|
@endverbatim
|
|
*******************************************************************************
|
|
* Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
|
|
*
|
|
* This software component is licensed by HDSC under BSD 3-Clause license
|
|
* (the "License"); You may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at:
|
|
* opensource.org/licenses/BSD-3-Clause
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* Include files
|
|
******************************************************************************/
|
|
#include "hc32f4a0_i2s.h"
|
|
#include "hc32f4a0_utility.h"
|
|
|
|
/**
|
|
* @addtogroup HC32F4A0_DDL_Driver
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @defgroup DDL_I2S I2S
|
|
* @brief Inter IC Sound Bus Driver Library
|
|
* @{
|
|
*/
|
|
|
|
#if (DDL_I2S_ENABLE == DDL_ON)
|
|
|
|
/*******************************************************************************
|
|
* Local type definitions ('typedef')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Local pre-processor symbols/macros ('#define')
|
|
******************************************************************************/
|
|
/**
|
|
* @defgroup I2S_Local_Macros I2S Local Macros
|
|
* @{
|
|
*/
|
|
|
|
/* I2S CTRL register Mask */
|
|
#define I2S_CTRL_CLEAR_MASK (I2S_CTRL_WMS | I2S_CTRL_ODD | I2S_CTRL_MCKOE | \
|
|
I2S_CTRL_TXBIRQWL | I2S_CTRL_RXBIRQWL | I2S_CTRL_I2SPLLSEL | \
|
|
I2S_CTRL_SDOE | I2S_CTRL_LRCKOE | I2S_CTRL_CKOE | \
|
|
I2S_CTRL_DUPLEX | I2S_CTRL_CLKSEL)
|
|
|
|
/**
|
|
* @defgroup I2S_Check_Parameters_Validity I2S Check Parameters Validity
|
|
* @{
|
|
*/
|
|
#define IS_I2S_UNIT(x) \
|
|
( ((x) == M4_I2S1) || \
|
|
((x) == M4_I2S2) || \
|
|
((x) == M4_I2S3) || \
|
|
((x) == M4_I2S4))
|
|
|
|
#define IS_I2S_CLK_SRC(x) \
|
|
( ((x) == I2S_CLK_SRC_PLL) || \
|
|
((x) == I2S_CLK_SRC_EXT))
|
|
|
|
#define IS_I2S_MD(x) \
|
|
( ((x) == I2S_MD_MASTER) || \
|
|
((x) == I2S_MD_SLAVE))
|
|
|
|
#define IS_I2S_COM_PROTOCOL(x) \
|
|
( ((x) == I2S_COM_PROTOCOL_PHILLIPS) || \
|
|
((x) == I2S_COM_PROTOCOL_MSB) || \
|
|
((x) == I2S_COM_PROTOCOL_LSB) || \
|
|
((x) == I2S_COM_PROTOCOL_PCM_SHORT) || \
|
|
((x) == I2S_COM_PROTOCOL_PCM_LONG))
|
|
|
|
#define IS_I2S_TRANS_MD(x) \
|
|
( ((x) == I2S_TRANS_MD_HALF_DUPLEX_RX) || \
|
|
((x) == I2S_TRANS_MD_HALF_DUPLEX_TX) || \
|
|
((x) == I2S_TRANS_MD_FULL_DUPLEX))
|
|
|
|
#define IS_I2S_AUDIO_FREQ(x) \
|
|
( ((x) == I2S_AUDIO_FREQ_DEFAULT) || \
|
|
(((x) >= I2S_AUDIO_FREQ_8K) && ((x) <= I2S_AUDIO_FREQ_192K)))
|
|
|
|
#define IS_I2S_CH_LEN(x) \
|
|
( ((x) == I2S_CH_LEN_16BIT) || \
|
|
((x) == I2S_CH_LEN_32BIT))
|
|
|
|
#define IS_I2S_DATA_LEN(x) \
|
|
( ((x) == I2S_DATA_LEN_16BIT) || \
|
|
((x) == I2S_DATA_LEN_24BIT) || \
|
|
((x) == I2S_DATA_LEN_32BIT))
|
|
|
|
#define IS_I2S_MCK_OUTPUT(x) \
|
|
( ((x) == I2S_MCK_OUTPUT_DISABLE) || \
|
|
((x) == I2S_MCK_OUTPUT_ENABLE))
|
|
|
|
#define IS_I2S_TRANS_LVL(x) \
|
|
( ((x) == I2S_TRANS_LVL0) || \
|
|
((x) == I2S_TRANS_LVL1) || \
|
|
((x) == I2S_TRANS_LVL2) || \
|
|
((x) == I2S_TRANS_LVL3) || \
|
|
((x) == I2S_TRANS_LVL4))
|
|
|
|
#define IS_I2S_RECEIVE_LVL(x) \
|
|
( ((x) == I2S_RECEIVE_LVL0) || \
|
|
((x) == I2S_RECEIVE_LVL1) || \
|
|
((x) == I2S_RECEIVE_LVL2) || \
|
|
((x) == I2S_RECEIVE_LVL3) || \
|
|
((x) == I2S_RECEIVE_LVL4))
|
|
|
|
#define IS_I2S_FUNC(x) \
|
|
( ((x) != 0U) && \
|
|
(((x) | I2S_FUNC_ALL) == I2S_FUNC_ALL))
|
|
|
|
#define IS_I2S_RST_TYPE(x) \
|
|
( ((x) != 0U) && \
|
|
(((x) | I2S_RST_TYPE_ALL) == I2S_RST_TYPE_ALL))
|
|
|
|
#define IS_I2S_INT(x) \
|
|
( ((x) != 0U) && \
|
|
(((x) | I2S_INT_ALL) == I2S_INT_ALL))
|
|
|
|
#define IS_I2S_FLAG(x) \
|
|
( ((x) != 0U) && \
|
|
(((x) | I2S_FLAG_ALL) == I2S_FLAG_ALL))
|
|
|
|
#define IS_I2S_CLR_FLAG(x) \
|
|
( ((x) != 0U) && \
|
|
(((x) | I2S_CLR_FLAG_ALL) == I2S_CLR_FLAG_ALL))
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* Global variable definitions (declared in header file with 'extern')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Local function prototypes ('static')
|
|
******************************************************************************/
|
|
static uint32_t I2S_GetClockFreq(const M4_I2S_TypeDef *I2Sx);
|
|
static en_result_t I2S_WaitStatus(const M4_I2S_TypeDef *I2Sx, uint32_t u32Flag, en_flag_status_t enStatus, uint32_t u32Timeout);
|
|
|
|
/*******************************************************************************
|
|
* Local variable definitions ('static')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Function implementation - global ('extern') and local ('static')
|
|
******************************************************************************/
|
|
/**
|
|
* @defgroup I2S_Global_Functions I2S Global Functions
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief De-Initialize I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @retval None
|
|
*/
|
|
void I2S_DeInit(M4_I2S_TypeDef *I2Sx)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
/* Reset all registers of I2S */
|
|
WRITE_REG32(I2Sx->CTRL, 0x00004400UL);
|
|
WRITE_REG32(I2Sx->ER, 0x00000003UL);
|
|
WRITE_REG32(I2Sx->CFGR, 0x00000000UL);
|
|
WRITE_REG32(I2Sx->PR, 0x00000002UL);
|
|
SET_REG32_BIT(I2Sx->CTRL, I2S_RST_TYPE_ALL);
|
|
CLEAR_REG32_BIT(I2Sx->CTRL, I2S_RST_TYPE_ALL);
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] pstcI2sInit Pointer to a @ref stc_i2s_init_t structure
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Initialize success
|
|
* - ErrorInvalidParameter: Invalid parameter
|
|
* - Error: Initialize failed
|
|
*/
|
|
en_result_t I2S_Init(M4_I2S_TypeDef *I2Sx, const stc_i2s_init_t *pstcI2sInit)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
uint32_t u32I2sClk;
|
|
uint32_t u32Temp;
|
|
uint32_t u32I2sDiv = 2UL;
|
|
uint32_t u32I2sOdd = 0UL;
|
|
uint32_t u32ChLen;
|
|
|
|
if (NULL == pstcI2sInit)
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_CLK_SRC(pstcI2sInit->u32ClockSrc));
|
|
DDL_ASSERT(IS_I2S_MD(pstcI2sInit->u32Mode));
|
|
DDL_ASSERT(IS_I2S_COM_PROTOCOL(pstcI2sInit->u32ComProtocol));
|
|
DDL_ASSERT(IS_I2S_TRANS_MD(pstcI2sInit->u32TransMode));
|
|
DDL_ASSERT(IS_I2S_AUDIO_FREQ(pstcI2sInit->u32AudioFreq));
|
|
DDL_ASSERT(IS_I2S_CH_LEN(pstcI2sInit->u32ChLen));
|
|
DDL_ASSERT(IS_I2S_DATA_LEN(pstcI2sInit->u32DataLen));
|
|
DDL_ASSERT(IS_I2S_MCK_OUTPUT(pstcI2sInit->u32MCKOutput));
|
|
DDL_ASSERT(IS_I2S_TRANS_LVL(pstcI2sInit->u32TransFIFOLevel));
|
|
DDL_ASSERT(IS_I2S_RECEIVE_LVL(pstcI2sInit->u32ReceiveFIFOLevel));
|
|
|
|
if (I2S_AUDIO_FREQ_DEFAULT != pstcI2sInit->u32AudioFreq)
|
|
{
|
|
/* Get I2S source Clock frequency */
|
|
if (I2S_CLK_SRC_EXT == pstcI2sInit->u32ClockSrc)
|
|
{
|
|
/* If an external I2S clock has to be used, this define
|
|
should be set in the ddl_config.h file */
|
|
u32I2sClk = I2S_EXT_CLK_FREQ;
|
|
}
|
|
else
|
|
{
|
|
u32I2sClk = I2S_GetClockFreq(I2Sx);
|
|
}
|
|
|
|
/* The actual frequency division value is calculated according to the output state of MCK */
|
|
if (I2S_CH_LEN_16BIT != pstcI2sInit->u32ChLen)
|
|
{
|
|
u32ChLen = 32UL;
|
|
}
|
|
else
|
|
{
|
|
u32ChLen = 16UL;
|
|
}
|
|
|
|
if (I2S_MCK_OUTPUT_ENABLE == pstcI2sInit->u32MCKOutput)
|
|
{
|
|
if (I2S_CH_LEN_16BIT != pstcI2sInit->u32ChLen)
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U * 4U)) * 10U) / pstcI2sInit->u32AudioFreq) + 5U;
|
|
}
|
|
else
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U * 8U)) * 10U) / pstcI2sInit->u32AudioFreq) + 5U;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U)) * 10U) / pstcI2sInit->u32AudioFreq) + 5U;
|
|
}
|
|
u32Temp = u32Temp / 10U;
|
|
u32I2sOdd = u32Temp & 0x01U;
|
|
u32I2sDiv = (u32Temp - u32I2sOdd) / 2U;
|
|
}
|
|
|
|
if ((u32I2sDiv < 2U) || (u32I2sDiv > 0xFFU))
|
|
{
|
|
/* Set the default values */
|
|
u32I2sOdd = 0U;
|
|
u32I2sDiv = 2U;
|
|
enRet = Error;
|
|
}
|
|
|
|
u32Temp = pstcI2sInit->u32ClockSrc | pstcI2sInit->u32Mode |
|
|
pstcI2sInit->u32ComProtocol | pstcI2sInit->u32TransMode |
|
|
pstcI2sInit->u32ChLen | pstcI2sInit->u32DataLen |
|
|
pstcI2sInit->u32MCKOutput | pstcI2sInit->u32TransFIFOLevel |
|
|
pstcI2sInit->u32ReceiveFIFOLevel | (u32I2sOdd << I2S_CTRL_ODD_POS);
|
|
if (I2S_MD_MASTER == pstcI2sInit->u32Mode)
|
|
{
|
|
u32Temp |= (I2S_CTRL_CKOE | I2S_CTRL_LRCKOE);
|
|
}
|
|
/* Set I2S_CFGR register */
|
|
WRITE_REG32(I2Sx->CFGR, (pstcI2sInit->u32ComProtocol | pstcI2sInit->u32ChLen | pstcI2sInit->u32DataLen));
|
|
/* set I2S_PR register */
|
|
WRITE_REG32(I2Sx->PR, u32I2sDiv);
|
|
/* Set I2S_CTRL register */
|
|
MODIFY_REG32(I2Sx->CTRL, I2S_CTRL_CLEAR_MASK, u32Temp);
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief Fills each stc_i2s_init_t member with default value.
|
|
* @param [out] pstcI2sInit Pointer to a @ref stc_i2s_init_t structure
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: stc_i2s_init_t member initialize success
|
|
* - ErrorInvalidParameter: Invalid parameter
|
|
*/
|
|
en_result_t I2S_StructInit(stc_i2s_init_t *pstcI2sInit)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
|
|
if (NULL == pstcI2sInit)
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
pstcI2sInit->u32ClockSrc = I2S_CLK_SRC_PLL;
|
|
pstcI2sInit->u32Mode = I2S_MD_MASTER;
|
|
pstcI2sInit->u32ComProtocol = I2S_COM_PROTOCOL_PHILLIPS;
|
|
pstcI2sInit->u32TransMode = I2S_TRANS_MD_HALF_DUPLEX_RX;
|
|
pstcI2sInit->u32AudioFreq = I2S_AUDIO_FREQ_DEFAULT;
|
|
pstcI2sInit->u32ChLen = I2S_CH_LEN_16BIT;
|
|
pstcI2sInit->u32DataLen = I2S_DATA_LEN_16BIT;
|
|
pstcI2sInit->u32MCKOutput = I2S_MCK_OUTPUT_DISABLE;
|
|
pstcI2sInit->u32TransFIFOLevel = I2S_TRANS_LVL2;
|
|
pstcI2sInit->u32ReceiveFIFOLevel = I2S_RECEIVE_LVL2;
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the software reset of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32ResetType Software reset type
|
|
* This parameter can be one or any combination of the following values:
|
|
* @arg I2S_RST_TYPE_SW: I2S software reset
|
|
* @arg I2S_RST_TYPE_CODEC: Reset codec of I2S
|
|
* @arg I2S_RST_TYPE_FIFO: Reset FIFO of I2S
|
|
* @arg I2S_RST_TYPE_ALL: All of the above
|
|
* @retval None
|
|
*/
|
|
void I2S_SetSWReset(M4_I2S_TypeDef *I2Sx, uint32_t u32ResetType)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_RST_TYPE(u32ResetType));
|
|
|
|
SET_REG32_BIT(I2Sx->CTRL, u32ResetType);
|
|
CLEAR_REG32_BIT(I2Sx->CTRL, u32ResetType);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the transfer mode for the I2S communication.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Mode Transfer mode
|
|
* This parameter can be one of the following values:
|
|
* @arg I2S_TRANS_MD_HALF_DUPLEX_RX: Receive only and half duplex mode
|
|
* @arg I2S_TRANS_MD_HALF_DUPLEX_TX: Send only and half duplex mode
|
|
* @arg I2S_TRANS_MD_FULL_DUPLEX: Full duplex mode
|
|
* @retval None
|
|
*/
|
|
void I2S_SetTransMode(M4_I2S_TypeDef *I2Sx, uint32_t u32Mode)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_TRANS_MD(u32Mode));
|
|
|
|
MODIFY_REG32(I2Sx->CTRL, (I2S_CTRL_DUPLEX | I2S_CTRL_SDOE), u32Mode);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the transfer FIFO level of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Level Transfer FIFO level
|
|
* This parameter can be one of the following values:
|
|
* @arg I2S_TRANS_LVL0: Transfer FIFO level is 0
|
|
* @arg I2S_TRANS_LVL1: Transfer FIFO level is 1
|
|
* @arg I2S_TRANS_LVL2: Transfer FIFO level is 2
|
|
* @arg I2S_TRANS_LVL3: Transfer FIFO level is 3
|
|
* @arg I2S_TRANS_LVL4: Transfer FIFO level is 4
|
|
* @retval None
|
|
*/
|
|
void I2S_SetTransFIFOLevel(M4_I2S_TypeDef *I2Sx, uint32_t u32Level)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_TRANS_LVL(u32Level));
|
|
|
|
MODIFY_REG32(I2Sx->CTRL, I2S_CTRL_TXBIRQWL, u32Level);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the receive FIFO level of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Level Receive FIFO level
|
|
* This parameter can be one of the following values:
|
|
* @arg I2S_RECEIVE_LVL0: Receive FIFO level is 0
|
|
* @arg I2S_RECEIVE_LVL1: Receive FIFO level is 1
|
|
* @arg I2S_RECEIVE_LVL2: Receive FIFO level is 2
|
|
* @arg I2S_RECEIVE_LVL3: Receive FIFO level is 3
|
|
* @arg I2S_RECEIVE_LVL4: Receive FIFO level is 4
|
|
* @retval None
|
|
*/
|
|
void I2S_SetReceiveFIFOLevel(M4_I2S_TypeDef *I2Sx, uint32_t u32Level)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_RECEIVE_LVL(u32Level));
|
|
|
|
MODIFY_REG32(I2Sx->CTRL, I2S_CTRL_RXBIRQWL, u32Level);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the communication protocol of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Protocol Communication protocol
|
|
* This parameter can be one of the following values:
|
|
* @arg I2S_COM_PROTOCOL_PHILLIPS: Phillips protocol
|
|
* @arg I2S_COM_PROTOCOL_MSB: MSB justified protocol
|
|
* @arg I2S_COM_PROTOCOL_LSB: LSB justified protocol
|
|
* @arg I2S_COM_PROTOCOL_PCM_SHORT: PCM short-frame protocol
|
|
* @arg I2S_COM_PROTOCOL_PCM_LONG: PCM long-frame protocol
|
|
* @retval None
|
|
*/
|
|
void I2S_SetComProtocol(M4_I2S_TypeDef *I2Sx, uint32_t u32Protocol)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_COM_PROTOCOL(u32Protocol));
|
|
|
|
MODIFY_REG32(I2Sx->CFGR, (I2S_CFGR_I2SSTD | I2S_CFGR_PCMSYNC), u32Protocol);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the audio frequency for the I2S communication.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Freq Audio frequency
|
|
* This parameter can be 'I2S_AUDIO_FREQ_DEFAULT' or between
|
|
* 'I2S_AUDIO_FREQ_8K' and 'I2S_AUDIO_FREQ_192K':
|
|
* @arg I2S_AUDIO_FREQ_192K: FS = 192000Hz
|
|
* @arg I2S_AUDIO_FREQ_8K: FS = 8000Hz
|
|
* @arg I2S_AUDIO_FREQ_DEFAULT
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Set success
|
|
* - Error: Set failed
|
|
*/
|
|
en_result_t I2S_SetAudioFreq(M4_I2S_TypeDef *I2Sx, uint32_t u32Freq)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
uint32_t u32I2sClk;
|
|
uint32_t u32Temp;
|
|
uint32_t u32I2sDiv = 2UL;
|
|
uint32_t u32I2sOdd = 0UL;
|
|
uint32_t u32ChLen;
|
|
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_AUDIO_FREQ(u32Freq));
|
|
|
|
if (I2S_AUDIO_FREQ_DEFAULT != u32Freq)
|
|
{
|
|
/* Get I2S source Clock frequency */
|
|
if (I2S_CLK_SRC_EXT == READ_REG32_BIT(I2Sx->CTRL, I2S_CTRL_CLKSEL))
|
|
{
|
|
/* If an external I2S clock has to be used, this define
|
|
should be set in the ddl_config.h file */
|
|
u32I2sClk = I2S_EXT_CLK_FREQ;
|
|
}
|
|
else
|
|
{
|
|
u32I2sClk = I2S_GetClockFreq(I2Sx);
|
|
}
|
|
|
|
/* The actual frequency division value is calculated according to the output state of MCK */
|
|
if (I2S_CH_LEN_16BIT != READ_REG32_BIT(I2Sx->CFGR, I2S_CFGR_CHLEN))
|
|
{
|
|
u32ChLen = 32UL;
|
|
}
|
|
else
|
|
{
|
|
u32ChLen = 16UL;
|
|
}
|
|
|
|
if (I2S_MCK_OUTPUT_ENABLE == READ_REG32_BIT(I2Sx->CTRL, I2S_CTRL_MCKOE))
|
|
{
|
|
if (I2S_CH_LEN_16BIT != READ_REG32_BIT(I2Sx->CFGR, I2S_CFGR_CHLEN))
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U * 4U)) * 10U) / u32Freq) + 5U;
|
|
}
|
|
else
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U * 8U)) * 10U) / u32Freq) + 5U;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Temp = (((u32I2sClk / (u32ChLen*2U)) * 10U) / u32Freq) + 5U;
|
|
}
|
|
u32Temp = u32Temp / 10U;
|
|
u32I2sOdd = u32Temp & 0x01U;
|
|
u32I2sDiv = (u32Temp - u32I2sOdd) / 2U;
|
|
}
|
|
|
|
if ((u32I2sDiv < 2U) || (u32I2sDiv > 0xFFU))
|
|
{
|
|
enRet = Error;
|
|
}
|
|
else
|
|
{
|
|
/* Set clock division */
|
|
WRITE_REG32(I2Sx->PR, u32I2sDiv);
|
|
MODIFY_REG32(I2Sx->CTRL, I2S_CTRL_ODD, (u32I2sOdd << I2S_CTRL_ODD_POS));
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable or disable MCK clock output.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] enNewState The function new state
|
|
* @arg This parameter can be: Enable or Disable.
|
|
* @retval None
|
|
*/
|
|
void I2S_MCKOutputCmd(M4_I2S_TypeDef *I2Sx, en_functional_state_t enNewState)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
|
|
|
if (Disable != enNewState)
|
|
{
|
|
SET_REG32_BIT(I2Sx->CTRL, I2S_CTRL_MCKOE);
|
|
}
|
|
else
|
|
{
|
|
CLEAR_REG32_BIT(I2Sx->CTRL, I2S_CTRL_MCKOE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enable or disable the function of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Func I2S function
|
|
* This parameter can be one or any combination of the following values:
|
|
* @arg I2S_FUNC_TXE: Transfer function
|
|
* @arg I2S_FUNC_RXE: Receive function
|
|
* @arg I2S_FUNC_ALL: All of the above
|
|
* @param [in] enNewState The function new state
|
|
* @arg This parameter can be: Enable or Disable.
|
|
* @retval None
|
|
*/
|
|
void I2S_FuncCmd(M4_I2S_TypeDef* I2Sx, uint32_t u32Func, en_functional_state_t enNewState)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_FUNC(u32Func));
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
|
|
|
if (Disable != enNewState)
|
|
{
|
|
SET_REG32_BIT(I2Sx->CTRL, u32Func);
|
|
}
|
|
else
|
|
{
|
|
CLEAR_REG32_BIT(I2Sx->CTRL, u32Func);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief I2S send data.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Data Send data
|
|
* @retval None
|
|
*/
|
|
void I2S_WriteData(M4_I2S_TypeDef *I2Sx, uint32_t u32Data)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
WRITE_REG32(I2Sx->TXBUF, u32Data);
|
|
}
|
|
|
|
/**
|
|
* @brief I2S receive data.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @retval uint32_t Receive data
|
|
*/
|
|
uint32_t I2S_ReadData(const M4_I2S_TypeDef *I2Sx)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
return READ_REG32(I2Sx->RXBUF);
|
|
}
|
|
|
|
/**
|
|
* @brief I2S transmit data in polling mode.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] pvTxBuf The pointer to data transmitted buffer
|
|
* @param [in] u32Len Data length
|
|
* @param [in] u32Timeout Transfer timeout(ms)
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Transmit data success
|
|
* - ErrorInvalidParameter: Invalid parameter
|
|
* - ErrorTimeout: Transmission timeout
|
|
*/
|
|
en_result_t I2S_Trans(M4_I2S_TypeDef *I2Sx, const void *pvTxBuf, uint32_t u32Len, uint32_t u32Timeout)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
uint32_t i;
|
|
uint32_t u32DataWidth;
|
|
|
|
if ((NULL == pvTxBuf) || (0UL == u32Len))
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
u32DataWidth = READ_REG32_BIT(I2Sx->CFGR, I2S_CFGR_DATLEN);
|
|
if (((I2S_DATA_LEN_16BIT == u32DataWidth) && IS_ADDRESS_ALIGN_HALFWORD(pvTxBuf)) ||
|
|
(IS_ADDRESS_ALIGN_WORD(pvTxBuf)))
|
|
{
|
|
for (i = 0UL; i < u32Len; i++)
|
|
{
|
|
enRet = I2S_WaitStatus(I2Sx, I2S_FLAG_TX_FULL, Reset, u32Timeout);
|
|
if (Ok != enRet)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (I2S_DATA_LEN_16BIT == u32DataWidth)
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint16_t *)pvTxBuf)[i]);
|
|
}
|
|
else
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint32_t *)pvTxBuf)[i]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief I2S receive data in polling mode.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] pvRxBuf The pointer to data received buffer
|
|
* @param [in] u32Len Data length
|
|
* @param [in] u32Timeout Transfer timeout(ms)
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Receive data success
|
|
* - ErrorInvalidParameter: Invalid parameter
|
|
* - ErrorTimeout: Transmission timeout
|
|
*/
|
|
en_result_t I2S_Receive(const M4_I2S_TypeDef *I2Sx, void *pvRxBuf, uint32_t u32Len, uint32_t u32Timeout)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
uint32_t i;
|
|
uint32_t u32DataWidth;
|
|
uint32_t u32Temp;
|
|
|
|
if ((NULL == pvRxBuf) || (0UL == u32Len))
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
u32DataWidth = READ_REG32_BIT(I2Sx->CFGR, I2S_CFGR_DATLEN);
|
|
if (((I2S_DATA_LEN_16BIT == u32DataWidth) && IS_ADDRESS_ALIGN_HALFWORD(pvRxBuf)) ||
|
|
(IS_ADDRESS_ALIGN_WORD(pvRxBuf)))
|
|
{
|
|
for (i = 0UL; i < u32Len; i++)
|
|
{
|
|
enRet = I2S_WaitStatus(I2Sx, I2S_FLAG_RX_EMPTY, Reset, u32Timeout);
|
|
if (Ok != enRet)
|
|
{
|
|
break;
|
|
}
|
|
|
|
u32Temp = READ_REG32(I2Sx->RXBUF);
|
|
if (I2S_DATA_LEN_16BIT == u32DataWidth)
|
|
{
|
|
((uint16_t *)pvRxBuf)[i] = (uint16_t)(u32Temp & 0xFFFFUL);
|
|
}
|
|
else if (I2S_DATA_LEN_24BIT == u32DataWidth)
|
|
{
|
|
((uint32_t *)pvRxBuf)[i] = u32Temp & 0xFFFFFFUL;
|
|
}
|
|
else
|
|
{
|
|
((uint32_t *)pvRxBuf)[i] = u32Temp;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief I2S transmit and receive data in polling mode.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] pvTxBuf The pointer to data transmitted buffer
|
|
* @param [in] pvRxBuf The pointer to data received buffer
|
|
* @param [in] u32Len Data length
|
|
* @param [in] u32Timeout Transfer timeout(ms)
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Receive data success
|
|
* - ErrorInvalidParameter: Invalid parameter
|
|
* - ErrorTimeout: Transmission timeout
|
|
*/
|
|
en_result_t I2S_TransReceive(M4_I2S_TypeDef *I2Sx, const void *pvTxBuf, void *pvRxBuf, uint32_t u32Len, uint32_t u32Timeout)
|
|
{
|
|
en_result_t enRet;
|
|
uint32_t u32TxCnt = 0U;
|
|
uint32_t u32RxCnt = 0U;
|
|
uint32_t u32DataWidth;
|
|
uint32_t u32Temp;
|
|
uint8_t u8BreakFlag = 0U;
|
|
|
|
if ((NULL == pvTxBuf) || (NULL == pvRxBuf) || (0UL == u32Len))
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
else
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
|
|
u32DataWidth = READ_REG32_BIT(I2Sx->CFGR, I2S_CFGR_DATLEN);
|
|
if (((I2S_DATA_LEN_16BIT == u32DataWidth) && IS_ADDRESS_ALIGN_HALFWORD(pvTxBuf) && IS_ADDRESS_ALIGN_HALFWORD(pvRxBuf)) ||
|
|
(IS_ADDRESS_ALIGN_WORD(pvTxBuf) && IS_ADDRESS_ALIGN_WORD(pvRxBuf)))
|
|
{
|
|
enRet = I2S_WaitStatus(I2Sx, I2S_FLAG_TX_FULL, Reset, u32Timeout);
|
|
if (Ok == enRet)
|
|
{
|
|
/* Preload data */
|
|
if (I2S_DATA_LEN_16BIT == u32DataWidth)
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint16_t *)pvTxBuf)[u32TxCnt]);
|
|
}
|
|
else
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint32_t *)pvTxBuf)[u32TxCnt]);
|
|
}
|
|
u32TxCnt++;
|
|
|
|
for (;;)
|
|
{
|
|
/* Transmit data */
|
|
if (u32TxCnt < u32Len)
|
|
{
|
|
enRet = I2S_WaitStatus(I2Sx, I2S_FLAG_TX_FULL, Reset, u32Timeout);
|
|
if (Ok != enRet)
|
|
{
|
|
u8BreakFlag = 1U;
|
|
}
|
|
else
|
|
{
|
|
if (I2S_DATA_LEN_16BIT == u32DataWidth)
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint16_t *)pvTxBuf)[u32TxCnt]);
|
|
}
|
|
else
|
|
{
|
|
WRITE_REG32(I2Sx->TXBUF, ((const uint32_t *)pvTxBuf)[u32TxCnt]);
|
|
}
|
|
u32TxCnt++;
|
|
}
|
|
}
|
|
/* Receive data */
|
|
if ((1U != u8BreakFlag) && (u32RxCnt < u32Len))
|
|
{
|
|
enRet = I2S_WaitStatus(I2Sx, I2S_FLAG_RX_EMPTY, Reset, u32Timeout);
|
|
if (Ok != enRet)
|
|
{
|
|
u8BreakFlag = 1U;
|
|
}
|
|
else
|
|
{
|
|
u32Temp = READ_REG32(I2Sx->RXBUF);
|
|
if (I2S_DATA_LEN_16BIT == u32DataWidth)
|
|
{
|
|
((uint16_t *)pvRxBuf)[u32RxCnt] = (uint16_t)(u32Temp & 0xFFFFUL);
|
|
}
|
|
else if (I2S_DATA_LEN_24BIT == u32DataWidth)
|
|
{
|
|
((uint32_t *)pvRxBuf)[u32RxCnt] = u32Temp & 0xFFFFFFUL;
|
|
}
|
|
else
|
|
{
|
|
((uint32_t *)pvRxBuf)[u32RxCnt] = u32Temp;
|
|
}
|
|
u32RxCnt++;
|
|
}
|
|
}
|
|
|
|
/* Complete the transmission */
|
|
if ((1U == u8BreakFlag) || ((u32Len == u32TxCnt) && (u32Len == u32RxCnt)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enRet = ErrorInvalidParameter;
|
|
}
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable or disable specified I2S interrupt.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32IntType Interrupt type
|
|
* This parameter can be one or any combination of the following values:
|
|
* @arg I2S_INT_TX: Transfer interrupt
|
|
* @arg I2S_INT_RX: Receive interrupt
|
|
* @arg I2S_INT_ERR: Communication error interrupt
|
|
* @arg I2S_INT_ALL: All of the above
|
|
* @param [in] enNewState The function new state
|
|
* @arg This parameter can be: Enable or Disable.
|
|
* @retval None
|
|
*/
|
|
void I2S_IntCmd(M4_I2S_TypeDef *I2Sx, uint32_t u32IntType, en_functional_state_t enNewState)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_INT(u32IntType));
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
|
|
|
if (Disable != enNewState)
|
|
{
|
|
SET_REG32_BIT(I2Sx->CTRL, u32IntType);
|
|
}
|
|
else
|
|
{
|
|
CLEAR_REG32_BIT(I2Sx->CTRL, u32IntType);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Get I2S flag status.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Flag I2S flag type
|
|
* This parameter can be one or any combination of the following values:
|
|
* @arg I2S_FLAG_TX_ALARM: Transfer buffer alarm flag
|
|
* @arg I2S_FLAG_RX_ALARM: Receive buffer alarm flag
|
|
* @arg I2S_FLAG_TX_EMPTY: Transfer buffer empty flag
|
|
* @arg I2S_FLAG_TX_FULL: Transfer buffer full flag
|
|
* @arg I2S_FLAG_RX_EMPTY: Receive buffer empty flag
|
|
* @arg I2S_FLAG_RX_FULL: Receive buffer full flag
|
|
* @arg I2S_FLAG_TX_ERR: Transfer overflow or underflow flag
|
|
* @arg I2S_FLAG_RX_ERR: Receive overflow flag
|
|
* @arg I2S_FLAG_ALL: All of the above
|
|
* @retval An en_flag_status_t enumeration value:
|
|
* - Set: Flag is set
|
|
* - Reset: Flag is reset
|
|
*/
|
|
en_flag_status_t I2S_GetStatus(const M4_I2S_TypeDef *I2Sx, uint32_t u32Flag)
|
|
{
|
|
en_flag_status_t enFlagSta = Reset;
|
|
uint32_t u32NormalFlag;
|
|
uint32_t u32ErrorFlag;
|
|
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_FLAG(u32Flag));
|
|
|
|
u32NormalFlag = u32Flag & 0xFFFFUL;
|
|
u32ErrorFlag = u32Flag >> 16U;
|
|
if (0UL != u32NormalFlag)
|
|
{
|
|
if (0UL != (READ_REG32_BIT(I2Sx->SR, u32NormalFlag)))
|
|
{
|
|
enFlagSta = Set;
|
|
}
|
|
}
|
|
if ((Reset == enFlagSta) && (0UL != u32ErrorFlag))
|
|
{
|
|
if (0UL != (READ_REG32_BIT(I2Sx->ER, u32ErrorFlag)))
|
|
{
|
|
enFlagSta = Set;
|
|
}
|
|
}
|
|
|
|
return enFlagSta;
|
|
}
|
|
|
|
/**
|
|
* @brief Clear I2S flag.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Flag I2S flag type
|
|
* This parameter can be one or any combination of the following values:
|
|
* @arg I2S_FLAG_TX_ERR: Transfer overflow or underflow flag
|
|
* @arg I2S_FLAG_RX_ERR: Receive overflow flag
|
|
* @arg I2S_CLR_FLAG_ALL: All of the above
|
|
* @retval None
|
|
*/
|
|
void I2S_ClearStatus(M4_I2S_TypeDef *I2Sx, uint32_t u32Flag)
|
|
{
|
|
/* Check parameters */
|
|
DDL_ASSERT(IS_I2S_UNIT(I2Sx));
|
|
DDL_ASSERT(IS_I2S_CLR_FLAG(u32Flag));
|
|
|
|
CLEAR_REG32_BIT(I2Sx->ER, u32Flag);
|
|
}
|
|
|
|
/**
|
|
* @brief Get I2S clock frequency.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @retval uint32_t The I2S clock frequency
|
|
*/
|
|
static uint32_t I2S_GetClockFreq(const M4_I2S_TypeDef *I2Sx)
|
|
{
|
|
uint32_t u32ClockShift;
|
|
uint16_t u32ClockSrc;
|
|
uint32_t u32ClockFreq;
|
|
uint32_t u32PllP;
|
|
uint32_t u32PllQ;
|
|
uint32_t u32PllR;
|
|
uint32_t u32PllN;
|
|
uint32_t u32PllM;
|
|
uint32_t u32PllIn;
|
|
uint32_t u32Temp;
|
|
|
|
/* Get the offset of the I2S clock source in CMU_I2SCKSEL */
|
|
if (M4_I2S1 == I2Sx)
|
|
{
|
|
u32ClockShift = CMU_I2SCKSEL_I2S1CKSEL_POS;
|
|
}
|
|
else if (M4_I2S2 == I2Sx)
|
|
{
|
|
u32ClockShift = CMU_I2SCKSEL_I2S2CKSEL_POS;
|
|
}
|
|
else if (M4_I2S3 == I2Sx)
|
|
{
|
|
u32ClockShift = CMU_I2SCKSEL_I2S3CKSEL_POS;
|
|
}
|
|
else if (M4_I2S4 == I2Sx)
|
|
{
|
|
u32ClockShift = CMU_I2SCKSEL_I2S4CKSEL_POS;
|
|
}
|
|
else
|
|
{
|
|
u32ClockShift = 0UL;
|
|
}
|
|
|
|
u32ClockSrc = (READ_REG16(M4_CMU->I2SCKSEL) >> u32ClockShift) & CMU_I2SCKSEL_I2S1CKSEL;
|
|
if (0UL != READ_REG32_BIT(M4_CMU->PLLHCFGR, CMU_PLLHCFGR_PLLSRC))
|
|
{
|
|
u32PllIn = HRC_VALUE;
|
|
}
|
|
else
|
|
{
|
|
u32PllIn = XTAL_VALUE;
|
|
}
|
|
/* Calculate the clock frequency */
|
|
switch(u32ClockSrc)
|
|
{
|
|
case 0x00U: /* PCLK1 */
|
|
u32ClockFreq = SystemCoreClock >> ((READ_REG32_BIT(M4_CMU->SCFGR, CMU_SCFGR_PCLK1S) >> CMU_SCFGR_PCLK1S_POS));
|
|
break;
|
|
case 0x08U: /* PLLHQ */
|
|
u32Temp = READ_REG32(M4_CMU->PLLHCFGR);
|
|
u32PllM = (u32Temp >> CMU_PLLHCFGR_PLLHM_POS) & 0x03UL;
|
|
u32PllN = (u32Temp >> CMU_PLLHCFGR_PLLHN_POS) & 0xFFUL;
|
|
u32PllQ = (u32Temp >> CMU_PLLHCFGR_PLLHQ_POS) & 0x0FUL;
|
|
u32ClockFreq = ((u32PllIn / (u32PllM + 1UL)) * (u32PllN + 1UL)) / (u32PllQ + 1UL);
|
|
break;
|
|
case 0x09U: /* PLLHR */
|
|
u32Temp = READ_REG32(M4_CMU->PLLHCFGR);
|
|
u32PllM = (u32Temp >> CMU_PLLHCFGR_PLLHM_POS) & 0x03UL;
|
|
u32PllN = (u32Temp >> CMU_PLLHCFGR_PLLHN_POS) & 0xFFUL;
|
|
u32PllR = (u32Temp >> CMU_PLLHCFGR_PLLHR_POS) & 0x0FUL;
|
|
u32ClockFreq = ((u32PllIn / (u32PllM + 1UL)) * (u32PllN + 1UL)) / (u32PllR + 1UL);
|
|
break;
|
|
case 0x0AU: /* PLLAP */
|
|
u32Temp = READ_REG32(M4_CMU->PLLACFGR);
|
|
u32PllM = (u32Temp >> CMU_PLLACFGR_PLLAM_POS) & 0x1FUL;
|
|
u32PllN = (u32Temp >> CMU_PLLACFGR_PLLAN_POS) & 0x1FFUL;
|
|
u32PllP = (u32Temp >> CMU_PLLACFGR_PLLAP_POS) & 0x0FUL;
|
|
u32ClockFreq = ((u32PllIn / (u32PllM + 1UL)) * (u32PllN + 1UL)) / (u32PllP + 1UL);
|
|
break;
|
|
case 0x0BU: /* PLLAQ */
|
|
u32Temp = READ_REG32(M4_CMU->PLLACFGR);
|
|
u32PllM = (u32Temp >> CMU_PLLACFGR_PLLAM_POS) & 0x1FUL;
|
|
u32PllN = (u32Temp >> CMU_PLLACFGR_PLLAN_POS) & 0x1FFUL;
|
|
u32PllQ = (u32Temp >> CMU_PLLACFGR_PLLAQ_POS) & 0x0FUL;
|
|
u32ClockFreq = ((u32PllIn / (u32PllM + 1UL)) * (u32PllN + 1UL)) / (u32PllQ + 1UL);
|
|
break;
|
|
case 0x0CU: /* PLLAR */
|
|
u32Temp = READ_REG32(M4_CMU->PLLACFGR);
|
|
u32PllM = (u32Temp >> CMU_PLLACFGR_PLLAM_POS) & 0x1FUL;
|
|
u32PllN = (u32Temp >> CMU_PLLACFGR_PLLAN_POS) & 0x1FFUL;
|
|
u32PllR = (u32Temp >> CMU_PLLACFGR_PLLAR_POS) & 0x0FUL;
|
|
u32ClockFreq = ((u32PllIn / (u32PllM + 1UL)) * (u32PllN + 1UL)) / (u32PllR + 1UL);
|
|
break;
|
|
default:
|
|
u32ClockFreq = 0UL;
|
|
break;
|
|
}
|
|
|
|
return u32ClockFreq;
|
|
}
|
|
|
|
/**
|
|
* @brief Wait for the flag status of I2S.
|
|
* @param [in] I2Sx Pointer to I2S instance register base
|
|
* This parameter can be one of the following values:
|
|
* @arg M4_I2S1: I2S unit 1 instance register base
|
|
* @arg M4_I2S2: I2S unit 2 instance register base
|
|
* @arg M4_I2S3: I2S unit 3 instance register base
|
|
* @arg M4_I2S4: I2S unit 4 instance register base
|
|
* @param [in] u32Flag I2S flag type
|
|
* This parameter can be one of the following values:
|
|
* @arg I2S_FLAG_TX_ALARM: Transfer buffer alarm flag
|
|
* @arg I2S_FLAG_RX_ALARM: Receive buffer alarm flag
|
|
* @arg I2S_FLAG_TX_EMPTY: Transfer buffer empty flag
|
|
* @arg I2S_FLAG_TX_FULL: Transfer buffer full flag
|
|
* @arg I2S_FLAG_RX_EMPTY: Receive buffer empty flag
|
|
* @arg I2S_FLAG_RX_FULL: Receive buffer full flag
|
|
* @arg I2S_FLAG_TX_ERR: Transfer overflow or underflow flag
|
|
* @arg I2S_FLAG_RX_ERR: Receive overflow flag
|
|
* @param [in] enStatus The flag status
|
|
* This parameter can be one of the following values:
|
|
* @arg Set: Wait for the flag to set
|
|
* @arg Reset: Wait for the flag to reset
|
|
* @param [in] u32Timeout Wait the flag timeout(ms)
|
|
* @retval An en_result_t enumeration value:
|
|
* - Ok: Wait status success
|
|
* - ErrorTimeout: Wait timeout
|
|
*/
|
|
static en_result_t I2S_WaitStatus(const M4_I2S_TypeDef *I2Sx, uint32_t u32Flag, en_flag_status_t enStatus, uint32_t u32Timeout)
|
|
{
|
|
en_result_t enRet = Ok;
|
|
__IO uint32_t u32Count;
|
|
|
|
/* Waiting for the flag status to change to the enStatus */
|
|
u32Count = u32Timeout * (HCLK_VALUE / 20000UL);
|
|
while (enStatus != I2S_GetStatus(I2Sx, u32Flag))
|
|
{
|
|
if (u32Count == 0UL)
|
|
{
|
|
enRet = ErrorTimeout;
|
|
break;
|
|
}
|
|
u32Count--;
|
|
}
|
|
|
|
return enRet;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* DDL_I2S_ENABLE */
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/******************************************************************************
|
|
* EOF (not truncated)
|
|
*****************************************************************************/
|