Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,792 @@
|
||||
/*!
|
||||
\file gd32h7xx_sai.c
|
||||
\brief SAI driver
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
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 the copyright holder 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.
|
||||
*/
|
||||
|
||||
#include "gd32h7xx_sai.h"
|
||||
|
||||
/* SAI pdm mode microphone delay mask */
|
||||
#define PDM_MICROPHONE_DELAY_MASK ((uint32_t)0x00000007U)
|
||||
/*!< bit offset of MTFCNT in SAI_CFG1 */
|
||||
#define CFG1_MTFCNT_OFFSET ((uint32_t)0x00000007U)
|
||||
|
||||
/*!
|
||||
\brief reset SAI
|
||||
\param[in] sai_periph: SAIx(x = 0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_deinit(uint32_t sai_periph)
|
||||
{
|
||||
switch(sai_periph) {
|
||||
case SAI0:
|
||||
/* reset SAI0 */
|
||||
rcu_periph_reset_enable(RCU_SAI0RST);
|
||||
rcu_periph_reset_disable(RCU_SAI0RST);
|
||||
break;
|
||||
case SAI1:
|
||||
/* reset SAI1 */
|
||||
rcu_periph_reset_enable(RCU_SAI1RST);
|
||||
rcu_periph_reset_disable(RCU_SAI1RST);
|
||||
break;
|
||||
case SAI2:
|
||||
/* reset SAI2 */
|
||||
rcu_periph_reset_enable(RCU_SAI2RST);
|
||||
rcu_periph_reset_disable(RCU_SAI2RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the parameter of SAI structure with a default value
|
||||
\param[in] none
|
||||
\param[out] sai_init_stuct: the initialization data needed to initialize SAI
|
||||
\retval none
|
||||
*/
|
||||
void sai_struct_para_init(sai_parameter_struct *sai_init_stuct)
|
||||
{
|
||||
/* initialize the initpara struct member with the default value */
|
||||
sai_init_stuct->operating_mode = SAI_MASTER_TRANSMITTER;
|
||||
sai_init_stuct->protocol = SAI_PROTOCOL_POLYMORPHIC;
|
||||
sai_init_stuct->data_width = SAI_DATAWIDTH_32BIT;
|
||||
sai_init_stuct->shift_dir = SAI_SHIFT_MSB;
|
||||
sai_init_stuct->sample_edge = SAI_SAMPEDGE_FALLING;
|
||||
sai_init_stuct->sync_mode = SAI_SYNCMODE_ASYNC;
|
||||
sai_init_stuct->output_drive = SAI_OUTPUT_WITH_SAIEN;
|
||||
sai_init_stuct->clk_div_bypass = SAI_CLKDIV_BYPASS_OFF;
|
||||
sai_init_stuct->mclk_div = SAI_MCLKDIV_1;
|
||||
sai_init_stuct->mclk_oversampling = SAI_MCLK_OVERSAMP_256;
|
||||
sai_init_stuct->mclk_enable = SAI_MCLK_DISABLE;
|
||||
sai_init_stuct->fifo_threshold = SAI_FIFOTH_EMPTY;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the parameter of SAI frame structure with a default value
|
||||
\param[in] none
|
||||
\param[out] sai_frame_init_struct: the initialization data needed to initialize SAI frame
|
||||
\retval none
|
||||
*/
|
||||
void sai_frame_struct_para_init(sai_frame_parameter_struct *sai_frame_init_struct)
|
||||
{
|
||||
/* initialize the initpara struct member with the default value */
|
||||
sai_frame_init_struct->frame_width = 256U;
|
||||
sai_frame_init_struct->frame_sync_width = 128U;
|
||||
sai_frame_init_struct->frame_sync_function = SAI_FS_FUNC_START;
|
||||
sai_frame_init_struct->frame_sync_polarity = SAI_FS_POLARITY_LOW;
|
||||
sai_frame_init_struct->frame_sync_offset = SAI_FS_OFFSET_BEGINNING;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize the parameter of SAI slot structure with a default value
|
||||
\param[in] none
|
||||
\param[out] sai_slot_init_struct: the initialization data needed to initialize SAI slot
|
||||
\retval none
|
||||
*/
|
||||
void sai_slot_struct_para_init(sai_slot_parameter_struct *sai_slot_init_struct)
|
||||
{
|
||||
/* initialize the initpara struct member with the default value */
|
||||
sai_slot_init_struct->slot_number = 16U;
|
||||
sai_slot_init_struct->slot_width = SAI_SLOT_WIDTH_DATA;
|
||||
sai_slot_init_struct->data_offset = 0U;
|
||||
sai_slot_init_struct->slot_active = SAI_SLOT_ACTIVE_NONE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize SAI
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x = 0,1)
|
||||
\param[in] sai_struct: SAI parameter initialization stuct members of the structure
|
||||
and the member values are shown as below:
|
||||
operating_mode: SAI_MASTER_TRANSMITTER, SAI_MASTER_RECEIVER, SAI_SLAVE_TRANSMITTER, SAI_SLAVE_RECEIVER;
|
||||
protocol: SAI_PROTOCOL_POLYMORPHIC, SAI_PROTOCOL_SPDIF, SAI_PROTOCOL_AC97
|
||||
data_width: SAI_DATA_WIDTH_xBIT (x = 8, 10, 16, 20, 24, 32)
|
||||
shift_dir: SAI_SHIFT_MSB, SAI_SHIFT_LSB
|
||||
sample_edge: SAI_SAMPEDGE_FALLING, SAI_SAMPEDGE_RISING
|
||||
sync_mode: SAI_SYNCMODE_ASYNC, SAI_SYNCMODE_OTHERBLOCK, SAI_SYNCMODE_EXTERNALSAI
|
||||
output_drive: SAI_OUTPUT_WITH_SAIEN, SAI_OUTPUT_NOW
|
||||
clk_div_bypass: SAI_CLKDIV_BYPASS_OFF, SAI_CLKDIV_BYPASS_ON
|
||||
mck_div: SAI_MCLKDIV_x (x = 1,2,..,63)
|
||||
mck_oversampling: SAI_MASTERCLK_OVERSAMP_256, SAI_MASTERCLK_OVERSAMP_512
|
||||
mck_enable: SAI_MASTERCLK_DISABLE, SAI_MASTERCLK_ENABLE
|
||||
fifo_threshold: SAI_FIFOTH_EMPTY, SAI_FIFOTH_QUARTER, SAI_FIFOTH_HALF, SAI_FIFOTH_THREE_QUARTER, SAI_FIFOTH_FULL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_init(uint32_t sai_periph, uint32_t block, sai_parameter_struct *sai_struct)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
|
||||
/* configure the SAI CFGR0 value */
|
||||
reg = SAI_CFG0(sai_periph, block);
|
||||
reg &= ~(SAI_CFG0_OPTMOD | SAI_CFG0_PROT | \
|
||||
SAI_CFG0_DATAWD | SAI_CFG0_SHIFTDIR | \
|
||||
SAI_CFG0_SAMPEDGE | SAI_CFG0_SYNCMOD | \
|
||||
SAI_CFG0_ODRIV | SAI_CFG0_BYPASS | \
|
||||
SAI_CFG0_MDIV | SAI_CFG0_MOSPR | \
|
||||
SAI_CFG0_MCLKEN | SAI_CFG0_SAIEN);
|
||||
|
||||
reg |= (uint32_t)(sai_struct->operating_mode | sai_struct->protocol | \
|
||||
sai_struct->data_width | sai_struct->shift_dir | \
|
||||
sai_struct->sample_edge | sai_struct->sync_mode | \
|
||||
sai_struct->output_drive | sai_struct->clk_div_bypass | \
|
||||
sai_struct->mclk_div | sai_struct->mclk_oversampling | \
|
||||
sai_struct->mclk_enable);
|
||||
SAI_CFG0(sai_periph, block) = reg;
|
||||
|
||||
/* configure the SAI CFGR1 FIFO threshold */
|
||||
reg = SAI_CFG1(sai_periph, block);
|
||||
reg &= ~SAI_CFG1_FFTH;
|
||||
reg |= (uint32_t)(sai_struct->fifo_threshold);
|
||||
SAI_CFG1(sai_periph, block) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize SAI frame
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] sai_frame_struct: SAI frame parameter initialization stuct members of the structure
|
||||
and the member values are shown as below:
|
||||
frame_width: 1~256, frame width
|
||||
frame_sync_width: 1~128, frame synchronization active width
|
||||
frame_sync_function: SAI_FS_FUNC_START, SAI_FS_FUNC_START_CHANNEL
|
||||
frame_sync_polarity: SAI_FS_POLARITY_LOW, SAI_FS_POLARITY_HIGH
|
||||
frame_sync_offset: SAI_FS_OFFSET_BEGINNING, SAI_FS_OFFSET_ONEBITBEFORE
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_frame_init(uint32_t sai_periph, uint32_t block, sai_frame_parameter_struct *sai_frame_struct)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_FCFG(sai_periph, block);
|
||||
reg &= ~(SAI_FCFG_FWD | SAI_FCFG_FSAWD | SAI_FCFG_FSFUNC | \
|
||||
SAI_FCFG_FSPL | SAI_FCFG_FSOST);
|
||||
reg |= (uint32_t)(sai_frame_struct->frame_sync_offset | \
|
||||
sai_frame_struct->frame_sync_polarity | \
|
||||
sai_frame_struct->frame_sync_function | \
|
||||
((sai_frame_struct->frame_sync_width - 1U) << 8U) | \
|
||||
(sai_frame_struct->frame_width - 1U));
|
||||
/* config the SAI freame */
|
||||
SAI_FCFG(sai_periph, block) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize SAI slot
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] sai_slot_struct: SAI slot parameter initialization stuct members of the structure
|
||||
and the member values are shown as below:
|
||||
slot_number: 1~16, slot number
|
||||
slot_width: SAI_SLOTWIDTH_DATA, SAI_SLOTWIDTH_16BIT, SAI_SLOTWIDTH_32BIT
|
||||
data_offset: 0~31, data offset
|
||||
slot_active: one or more parameters can be selected, SAI_SLOT_ACTIVE_NONE, SAI_SLOT_ACTIVE_x(x=0..15), SAI_SLOT_ACTIVE_ALL
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_slot_init(uint32_t sai_periph, uint32_t block, sai_slot_parameter_struct *sai_slot_struct)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_SCFG(sai_periph, block);
|
||||
reg &= ~(SAI_SCFG_DATAOST | SAI_SCFG_SLOTWD | SAI_SCFG_SLOTNUM | SAI_SCFG_SLOTAV);
|
||||
reg = (uint32_t)(((sai_slot_struct->slot_number - 1U) << 8U) | \
|
||||
sai_slot_struct->slot_width | \
|
||||
sai_slot_struct->data_offset | \
|
||||
sai_slot_struct->slot_active);
|
||||
/* configure the SAI slot */
|
||||
SAI_SCFG(sai_periph, block) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI enable
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_enable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG0(sai_periph, block) |= SAI_CFG0_SAIEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI disable
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_disable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_SAIEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI serial data near inactive slot output management
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] sdout: serial data output management
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_SDLINE_DRIVE: SD line output is driven entirely during the audio frame
|
||||
\arg SAI_SDLINE_RELEASE: SD line output is released near inactive slots
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_sdoutput_config(uint32_t sai_periph, uint32_t block, uint32_t sdout)
|
||||
{
|
||||
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_SDOM;
|
||||
SAI_CFG1(sai_periph, block) |= sdout;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI mono mode
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[in] mono: stereo and mono mode selection
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_STEREO_MODE: stereo mode
|
||||
\arg SAI_MONO_MODE: mono mode
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_monomode_config(uint32_t sai_periph, uint32_t block, uint32_t mono)
|
||||
{
|
||||
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_MONO;
|
||||
SAI_CFG0(sai_periph, block) |= mono ;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI companding mode
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[in] compander: compander mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_COMPANDER_OFF: no compansion applies
|
||||
\arg SAI_COMPANDER_ULAW: u-law algorithm
|
||||
\arg SAI_COMPANDER_ALAW: A-law algorithm
|
||||
\param[in] complement:complement mode
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_COMPLEMENT_1S: data represented in 1's complement form
|
||||
\arg SAI_COMPLEMENT_2S: data represented in 2's complement form
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_companding_config(uint32_t sai_periph, uint32_t block, uint32_t compander,
|
||||
uint32_t complement)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_CFG1(sai_periph, block);
|
||||
reg &= ~(SAI_CFG1_CPLMOD | SAI_CFG1_CPAMOD);
|
||||
reg |= (compander | complement);
|
||||
SAI_CFG1(sai_periph, block) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI mute detected enable or mute send enable
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_mute_enable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG1(sai_periph, block) |= SAI_CFG1_MT;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI mute detected disable or mute send disable
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_mute_disable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_MT;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI mute value
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[in] value: mute value
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_MUTESENT_0: 0 is sent via the serial data line when mute is on
|
||||
\arg SAI_MUTESENT_LASTFREAM: If SLOTNUM is less or equals to two, last frame is sent via the serial data line
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_mute_value_config(uint32_t sai_periph, uint32_t block, uint32_t value)
|
||||
{
|
||||
SAI_CFG1(sai_periph, block) &= ~SAI_CFG1_MTVAL;
|
||||
SAI_CFG1(sai_periph, block) |= value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI mute frame count
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[in] count: 0~63, mute frame count
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_mute_count_config(uint32_t sai_periph, uint32_t block, uint32_t count)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_CFG1(sai_periph, block);
|
||||
reg &= ~SAI_CFG1_MTFCNT;
|
||||
reg |= count << CFG1_MTFCNT_OFFSET;
|
||||
SAI_CFG1(sai_periph, block) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI transmit data
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[in] data: 32-bit data
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_data_transmit(uint32_t sai_periph, uint32_t block, uint32_t data)
|
||||
{
|
||||
SAI_DATA(sai_periph, block) = data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI receive data
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval received data
|
||||
*/
|
||||
uint32_t sai_data_receive(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
return SAI_DATA(sai_periph, block);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get SAI fifo status
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval state of fifo
|
||||
\arg FIFO_EMPTY: empty
|
||||
\arg FIFO_EMPTY_TO_1_4_FULL: empty < fifo_level <= 1/4_full
|
||||
\arg FIFO_1_4_FULL_TO_1_2_FULL: 1/4_full < fifo_level <= 1/2_full
|
||||
\arg FIFO_1_2_FULL_TO_3_4_FULL: 1/2_full < fifo_level <= 3/4_full
|
||||
\arg FIFO_3_4_FULL_TO_FULL: 3/4_full < fifo_level < full
|
||||
\arg FIFO_FULL: full
|
||||
*/
|
||||
sai_fifo_state_enum sai_fifo_status_get(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
sai_fifo_state_enum sai_fifo_state = FIFO_EMPTY;
|
||||
|
||||
if(SAI_FIFO_STAT_EMPTY == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
|
||||
sai_fifo_state = FIFO_EMPTY;
|
||||
} else if(SAI_FIFO_STAT_QUARTER == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
|
||||
sai_fifo_state = FIFO_EMPTY_TO_1_4_FULL;
|
||||
} else if(SAI_FIFO_STAT_HALF == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
|
||||
sai_fifo_state = FIFO_1_4_FULL_TO_1_2_FULL;
|
||||
} else if(SAI_FIFO_STAT_THREE_QUARTER == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
|
||||
sai_fifo_state = FIFO_1_2_FULL_TO_3_4_FULL;
|
||||
} else if(SAI_FIFO_STAT_NEARFULL == (SAI_STAT(sai_periph, block) & SAI_STAT_FFSTAT)) {
|
||||
sai_fifo_state = FIFO_3_4_FULL_TO_FULL;
|
||||
} else {
|
||||
sai_fifo_state = FIFO_FULL;
|
||||
}
|
||||
|
||||
return sai_fifo_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI fifo flush
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_fifo_flush(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG1(sai_periph, block) |= SAI_CFG1_FLUSH;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAI dma
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_dma_enable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG0(sai_periph, block) |= SAI_CFG0_DMAEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAI dma
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx (x=0,1)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_dma_disable(uint32_t sai_periph, uint32_t block)
|
||||
{
|
||||
SAI_CFG0(sai_periph, block) &= ~SAI_CFG0_DMAEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI synchronization input select
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] input: specify which external SAI to be select for synchronization
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_SYNCINPUT_SAI0: SAI1 or SAI2 selects the synchronization coming from SAI0
|
||||
\arg SAI_SYNCINPUT_SAI1: SAI0 or SAI2 selects the synchronization coming from SAI1
|
||||
\arg SAI_SYNCINPUT_SAI2: SAI0 or SAI1 selects the synchronization coming from SAI2
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_sync_input_config(uint32_t sai_periph, uint32_t input)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_SYNCFG(sai_periph);
|
||||
reg &= ~SAI_SYNCFG_SYNI;
|
||||
reg |= input;
|
||||
SAI_SYNCFG(sai_periph) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SAI synchronization output select
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] output: specify which block to be used for further synchronization for others SAI
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_SYNCOUTPUT_OFF: no synchronization output signals
|
||||
\arg SAI_SYNCOUTPUT_BLOCK0: block 0 used for further synchronization for others SAI
|
||||
\arg SAI_SYNCOUTPUT_BLOCK1: block 1 used for further synchronization for others SAI
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_sync_output_config(uint32_t sai_periph, uint32_t output)
|
||||
{
|
||||
uint32_t reg = 0U;
|
||||
reg = SAI_SYNCFG(sai_periph);
|
||||
reg &= ~SAI_SYNCFG_SYNO;
|
||||
reg |= output;
|
||||
SAI_SYNCFG(sai_periph) = reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAI pdm mode
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_enable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_PDMEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAI pdm mode
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_disable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_PDMEN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI pdm mode microphone number
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] microphonenum: 2, 4, 6 or 8(not applicable to GD32H7xx), select microphones number
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_microphone_number_config(uint32_t sai_periph, uint32_t microphonenum)
|
||||
{
|
||||
uint32_t temp = SAI_PDMCTL(sai_periph);
|
||||
temp &= ~SAI_PDMCTL_MICNUMSEL;
|
||||
temp |= ((microphonenum / 2U - 1U) << 4U);
|
||||
SAI_PDMCTL(sai_periph) = temp;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SAI pdm mode microphone delay
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] microphone: specify which microphone delay parameter to config
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_PDM_MICROPHONE0_L: microphone 0 channel left
|
||||
\arg SAI_PDM_MICROPHONE0_R: microphone 0 channel right
|
||||
\arg SAI_PDM_MICROPHONE1_L: microphone 1 channel left
|
||||
\arg SAI_PDM_MICROPHONE1_R: microphone 1 channel right
|
||||
\arg SAI_PDM_MICROPHONE2_L: microphone 2 channel left
|
||||
\arg SAI_PDM_MICROPHONE2_R: microphone 2 channel right
|
||||
\arg SAI_PDM_MICROPHONE3_L: microphone 3 channel left, (not applicable to GD32H7xx)
|
||||
\arg SAI_PDM_MICROPHONE3_R: microphone 3 channel right, (not applicable to GD32H7xx)
|
||||
\param[in] delay: 0~7, the microphone data flow delay period
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_delay_config(uint32_t sai_periph, uint32_t microphone, uint32_t delay)
|
||||
{
|
||||
uint32_t temp = SAI_PDMCFG(sai_periph);
|
||||
temp &= ~(PDM_MICROPHONE_DELAY_MASK << (microphone * 4U));
|
||||
temp |= (delay << (microphone * 4U));
|
||||
SAI_PDMCFG(sai_periph) = temp;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAI pdm mode clock line 0
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_clk0_enable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_CLKL0EN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAI pdm mode clock line 0
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_clk0_disable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_CLKL0EN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable SAI pdm mode clock line 1
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_clk1_enable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) |= SAI_PDMCTL_CLKL1EN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable SAI pdm mode clock line 1
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_pdm_clk1_disable(uint32_t sai_periph)
|
||||
{
|
||||
SAI_PDMCTL(sai_periph) &= ~SAI_PDMCTL_CLKL1EN;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief enable the SAI interrupt
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] interrupt: specify which interrupt to enable
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg SAI_INT_OUERR: FIFO overrun or underrun interrupt enable
|
||||
\arg SAI_INT_MTDET: mute detection interrupt enable
|
||||
\arg SAI_INT_ERRCK: error clock interrupt enable
|
||||
\arg SAI_INT_FFREQ: FIFO request interrupt enable
|
||||
\arg SAI_INT_ACNRDY: audio codec not ready interrupt enable
|
||||
\arg SAI_INT_FSADET: frame synchronization advanced detection interrupt enable
|
||||
\arg SAI_INT_FSPDET: frame synchronization postpone detection interrupt enable
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_interrupt_enable(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
|
||||
{
|
||||
SAI_INTEN(sai_periph, block) |= interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief disable the SAI interrupt
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] interrupt: specify which interrupt to disable
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg SAI_INT_OUERR: FIFO overrun or underrun interrupt
|
||||
\arg SAI_INT_MTDET: mute detection interrupt
|
||||
\arg SAI_INT_ERRCK: error clock interrupt
|
||||
\arg SAI_INT_FFREQ: FIFO request interrupt
|
||||
\arg SAI_INT_ACNRDY: audio codec not ready interrupt
|
||||
\arg SAI_INT_FSADET: frame synchronization advanced detection interrupt
|
||||
\arg SAI_INT_FSPDET: frame synchronization postpone detection interrupt
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_interrupt_disable(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
|
||||
{
|
||||
SAI_INTEN(sai_periph, block) &= ~interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the SAI interrupt flag
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] interrupt: specify which interrupt flag to get
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_FLAG_OUERR: FIFO overrun or underrun interrupt flag
|
||||
\arg SAI_FLAG_MTDET: mute detection interrupt flag
|
||||
\arg SAI_FLAG_ERRCK: error clock interrupt flag
|
||||
\arg SAI_FLAG_FFREQ: FIFO request interrupt flag
|
||||
\arg SAI_FLAG_ACNRDY: audio codec not ready interrupt flag
|
||||
\arg SAI_FLAG_FSADET: frame synchronization advanced detection interrupt flag
|
||||
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection interrupt flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus sai_interrupt_flag_get(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
|
||||
{
|
||||
uint32_t inten = 0U;
|
||||
inten = SAI_INTEN(sai_periph, block) & interrupt;
|
||||
if((RESET != (SAI_STAT(sai_periph, block) & interrupt)) && (RESET != inten)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the SAI interrupt flag
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] interrupt: specify which interrupt flag to clear
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg SAI_FLAG_OUERR: FIFO overrun or underrun interrupt flag
|
||||
\arg SAI_FLAG_MTDET: mute detection interrupt flag
|
||||
\arg SAI_FLAG_ERRCK: error clock interrupt flag
|
||||
\arg SAI_FLAG_ACNRDY: audio codec not ready interrupt flag
|
||||
\arg SAI_FLAG_FSADET: frame synchronization advanced detection interrupt flag
|
||||
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection interrupt flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_interrupt_flag_clear(uint32_t sai_periph, uint32_t block, uint32_t interrupt)
|
||||
{
|
||||
SAI_INTC(sai_periph, block) = interrupt;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief get the SAI flag
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] flag: specify which flag to get
|
||||
only one parameter can be selected which are shown as below:
|
||||
\arg SAI_FLAG_OUERR: FIFO overrun or underrun flag
|
||||
\arg SAI_FLAG_MTDET: mute detection flag
|
||||
\arg SAI_FLAG_ERRCK: error clock flag
|
||||
\arg SAI_FLAG_FFREQ: FIFO request flag
|
||||
\arg SAI_FLAG_ACNRDY: audio codec not ready flag
|
||||
\arg SAI_FLAG_FSADET: frame synchronization advanced detection flag
|
||||
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection flag
|
||||
\param[out] none
|
||||
\retval FlagStatus: SET or RESET
|
||||
*/
|
||||
FlagStatus sai_flag_get(uint32_t sai_periph, uint32_t block, uint32_t flag)
|
||||
{
|
||||
if(RESET != (SAI_STAT(sai_periph, block) & flag)) {
|
||||
return SET;
|
||||
} else {
|
||||
return RESET;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief clear the SAI flag
|
||||
\param[in] sai_periph: SAIx(x=0,1,2)
|
||||
\param[in] block: specify which bolck is initialized
|
||||
only one parameter can be selected which is shown as below:
|
||||
\arg SAI_BLOCKx(x=0,1)
|
||||
\param[in] flag: specify which flag to clear
|
||||
one or more parameters can be selected which are shown as below:
|
||||
\arg SAI_FLAG_OUERR: FIFO overrun or underrun flag
|
||||
\arg SAI_FLAG_MTDET: mute detection flag
|
||||
\arg SAI_FLAG_ERRCK: error clock flag
|
||||
\arg SAI_FLAG_ACNRDY: audio codec not ready flag
|
||||
\arg SAI_FLAG_FSADET: frame synchronization advanced detection flag
|
||||
\arg SAI_FLAG_FSPDET: frame synchronization postpone detection flag
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void sai_flag_clear(uint32_t sai_periph, uint32_t block, uint32_t flag)
|
||||
{
|
||||
SAI_INTC(sai_periph, block) = flag;
|
||||
}
|
||||
Reference in New Issue
Block a user