sdk-ameba-v4.0c_180328/component/common/mbed/targets/hal/rtl8711b/i2s_api.c
2019-04-02 16:34:25 +08:00

361 lines
11 KiB
C
Executable file

/** mbed Microcontroller Library
******************************************************************************
* @file i2s_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for I2S.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "i2s_api.h"
#include "pinmap.h"
typedef struct {
VOID (*TxCCB)(uint32_t id, char *pbuf);
u32 TxCBId;
VOID (*RxCCB)(uint32_t id, char *pbuf);
u32 RxCBId;
} I2S_USER_CB;
static I2S_InitTypeDef I2SInitStruct;
static I2S_USER_CB I2SUserCB; //Pointer to I2S User Callback
static u32 next_tx_complete = 0;
extern u32 i2s_cur_tx_page;
extern u32 i2s_cur_rx_page;
static void i2s_sw_reset(void)
{
i2s_cur_tx_page = 0;
i2s_cur_rx_page = 0;
next_tx_complete = 0;
}
static void i2s_isr(void *Data)
{
u32 I2STxIsr, I2SRxIsr;
u8 I2SPageNum = I2SInitStruct.I2S_PageNum;
u32 i;
u32 pbuf;
u32 cur_tx_page = 0;
u32 cur_rx_page = 0;
I2S_ISRGet(I2S_DEV, &I2STxIsr, &I2SRxIsr);
I2S_INTClear(I2S_DEV, I2STxIsr, I2SRxIsr);
for (i=0 ; i<I2SPageNum; i++) { // page 0, 1, 2, 3
cur_rx_page = I2S_GetRxPage(I2S_DEV);
if (I2SRxIsr & (1<<cur_rx_page)) {
pbuf = I2S_GetRxPageAddr(cur_rx_page);
I2SRxIsr &= ~(1<<cur_rx_page);
I2SUserCB.RxCCB(I2SUserCB.RxCBId, (char*)pbuf);
} else {
break;
}
}
for (i=0 ; i<I2SPageNum; i++) { // page 0, 1, 2, 3
if (I2STxIsr & (1<<next_tx_complete)) {
pbuf = I2S_GetTxPageAddr(next_tx_complete);
I2STxIsr &= ~(1<<next_tx_complete);
next_tx_complete++;
next_tx_complete &= 0x03;
I2SUserCB.TxCCB(I2SUserCB.TxCBId, (char*)pbuf);
} else {
break;
}
}
}
/**
* @brief Initializes the I2S device, include clock/function/interrupt/I2S registers.
* @param obj: i2s object define in application software.
* @param sck: Serial clock PinName according to pinmux spec.
* @param ws: Word select PinName according to pinmux spec.
* @param sd_tx: Tx PinName according to pinmux spec.
* @param sd_rx: Rx PinName according to pinmux spec.
* @param mck: Master clock PinName according to pinmux spec.
* @retval none
*/
void i2s_init(i2s_t *obj, PinName sck, PinName ws, PinName sd_tx, PinName sd_rx, PinName mck)
{
obj->i2s_idx = 0;
DBG_PRINTF(MODULE_I2S, LEVEL_INFO, "%s: Use I2S%d \n", __func__, obj->i2s_idx);
// Load user defined parameters
I2S_StructInit(&I2SInitStruct);
/*I2S Interrupt Initialization*/
InterruptRegister((IRQ_FUN) i2s_isr, I2S0_PCM0_IRQ, NULL, 3);
InterruptEn(I2S0_PCM0_IRQ, 3);
/* enable system pll */
PLL1_Set(BIT_SYS_SYSPLL_CK22P5792_EN | BIT_SYS_SYSPLL_CK24P576_EN, ENABLE);
/* enable lx bus for i2s */
LXBUS_FCTRL(ON);
/*I2S Pin Mux Initialization*/
RCC_PeriphClockCmd(APBPeriph_I2S0, APBPeriph_I2S0_CLOCK, ENABLE);
Pinmux_Config(sck, PINMUX_FUNCTION_I2S);
Pinmux_Config(ws, PINMUX_FUNCTION_I2S);
Pinmux_Config(sd_tx, PINMUX_FUNCTION_I2S);
Pinmux_Config(sd_rx, PINMUX_FUNCTION_I2S);
Pinmux_Config(mck, PINMUX_FUNCTION_I2S);
next_tx_complete = 0;
I2SInitStruct.I2S_TRxAct = obj->direction;
I2SInitStruct.I2S_ChNum = obj->channel_num;
I2SInitStruct.I2S_Rate = obj->sampling_rate;
I2SInitStruct.I2S_WordLen = obj->word_length;
/*I2S HAL Initialization*/
I2S_Init(I2S_DEV, &I2SInitStruct);
/*I2S Enable Module*/
I2S_Cmd(I2S_DEV, ENABLE);
I2S_INTConfig(I2S_DEV, (I2S_TX_INT_PAGE0_OK|I2S_TX_INT_PAGE1_OK| I2S_TX_INT_PAGE2_OK|I2S_TX_INT_PAGE3_OK),
(I2S_RX_INT_PAGE0_OK|I2S_RX_INT_PAGE1_OK | I2S_RX_INT_PAGE2_OK|I2S_RX_INT_PAGE3_OK));
}
/**
* @brief Sets page number, page size, page address.
* @param obj: i2s object define in application software.
* @param tx_buf: pointer to the start address of Tx page.
* @param rx_buf: pointer to the start address of Rx page.
* @param page_num: page number. This parameter must be set to a value in the 2~4 range
* @param page_size: page size. This parameter must be set to a value in the 4~16384 bytes range
* @retval none
*/
void i2s_set_dma_buffer(i2s_t *obj, char *tx_buf, char *rx_buf,
uint32_t page_num, uint32_t page_size)
{
u32 i;
//uint8_t i2s_idx = obj->i2s_idx;
if ((page_num < 2) || (page_num > 4) || (page_size < 8)) {
DBG_PRINTF(MODULE_I2S, LEVEL_INFO, "%s: PageNum(%d) valid value is 2~4; PageSize(%d must > 8)\r\n", \
__FUNCTION__, page_num, page_size);
return;
}
I2SInitStruct.I2S_PageNum = page_num;
I2SInitStruct.I2S_PageSize = page_size/4; // unit is 4-bytes
I2S_SetPageSize(I2S_DEV, (page_size/4));
I2S_SetPageNum(I2S_DEV, (page_num));
I2S_SetDMABuf(I2S_DEV, (u8*)tx_buf, (u8*)rx_buf);
for (i=0;i<page_num;i++) {
I2S_SetTxPageAddr(i, (uint32_t)(tx_buf + ((page_size) * i)));
I2S_SetRxPageAddr(i, (uint32_t)(rx_buf + ((page_size) * i)));
}
}
/**
* @brief Sets TX interrupt handler.
* @param obj: i2s object define in application software.
* @param handler: TX interrupt callback function.
* @param id: TX interrupt callback function parameter.
* @retval none
*/
void i2s_tx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2SUserCB.TxCCB = handler;
I2SUserCB.TxCBId = id;
}
/**
* @brief Sets RX interrupt handler.
* @param obj: i2s object define in application software.
* @param handler: RX interrupt callback function.
* @param id: RX interrupt callback function parameter.
* @retval none
*/
void i2s_rx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2SUserCB.RxCCB = handler;
I2SUserCB.RxCBId = id;
}
/**
* @brief Sets i2s data transfer direction.
* @param obj: i2s object define in application software.
* @param trx_type: transfer direction.
* This parameter can be one of the following values:
* @arg I2S_DIR_RX: Rx receive direction
* @arg I2S_DIR_TX: Tx transmission direction
* @arg I2S_DIR_TXRX: Tx & Rx bi-direction
* @retval none
*/
void i2s_set_direction(i2s_t *obj, int trx_type)
{
obj->direction = trx_type;
I2SInitStruct.I2S_TRxAct = trx_type;
I2S_SetDirection(I2S_DEV, trx_type);
if (trx_type == I2S_DIR_TX) {
I2S_RxDmaCmd(I2S_DEV, DISABLE);
} else if ((trx_type == I2S_DIR_TXRX) ||(trx_type == I2S_DIR_RX) ) {
I2S_RxDmaCmd(I2S_DEV, ENABLE);
}
}
/**
* @brief Sets i2s channel number, sample rate, word length.
* @param obj: i2s object define in application software.
* @param channel_num: this parameter can be one of the following values:
* @arg CH_STEREO: stereo channel
* @arg CH_MONO: mono channel
* @param rate: this parameter can be one of the following values:
* @arg SR_8KHZ: sample rate is 8kHz
* @arg SR_16KHZ: sample rate is 16kHz
* @arg SR_24KHZ: sample rate is 24kHz
* @arg SR_32KHZ: sample rate is 32kHz
* @arg SR_48KHZ: sample rate is 48kHz
* @arg SR_96KHZ: sample rate is 96kHz
* @arg SR_7p35KHZ: sample rate is 7.35kHz
* @arg SR_14p7KHZ: sample rate is 14.7kHz
* @arg SR_22p05KHZ: sample rate is 22.05kHz
* @arg SR_29p4KHZ: sample rate is 29.4kHz
* @arg SR_44p1KHZ: sample rate is 44.1kHz
* @arg SR_88p2KHZ: sample rate is 88.2kHz
* @param word_len: this parameter can be one of the following values:
* @arg WL_16b: sample bit is 16 bit
* @arg WL_24b: sample bit is 24 bit
* @retval none
*/
void i2s_set_param(i2s_t *obj, int channel_num, int rate, int word_len)
{
obj->channel_num = channel_num;
obj->sampling_rate = rate;
obj->word_length = word_len;
I2SInitStruct.I2S_ChNum = channel_num;
I2SInitStruct.I2S_Rate = rate;
I2SInitStruct.I2S_WordLen = word_len;
I2S_SetChNum(I2S_DEV, I2SInitStruct.I2S_ChNum);
I2S_SetRate(I2S_DEV, rate);
I2S_SetWordLen(I2S_DEV, I2SInitStruct.I2S_WordLen);
}
/**
* @brief Deinitializes the I2S device, include function/interrupt/I2S registers.
* @param obj: i2s object define in application software.
* @retval none
*/
void i2s_deinit(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
IRQn_Type IrqNum = I2S0_PCM0_IRQ;
/*I2S Interrupt DeInitialization*/
InterruptDis(IrqNum);
InterruptUnRegister(IrqNum);
/*I2S Disable Module*/
I2S_INTConfig(I2S_DEV, 0, 0);
I2S_Cmd(I2S_DEV, DISABLE);
i2s_sw_reset();
}
/**
* @brief Gets current tx page address.
* @param obj: i2s object define in application software.
* @retval address of current tx page or NULL
* @note current page own by cpu, return address of current tx page
* @note current page own by i2s, return NULL
*/
int* i2s_get_tx_page(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
u8 cur_tx_page;
cur_tx_page = I2S_GetTxPage(I2S_DEV);
if (!I2S_TxPageBusy(I2S_DEV, cur_tx_page)) {
return ((int*)I2S_GetTxPageAddr(cur_tx_page));
} else {
return NULL;
}
}
/**
* @brief Sets current tx page own by i2s.
* @param obj: i2s object define in application software.
* @param pbuf: tx buffer adderss.
* @retval none
*/
void i2s_send_page(i2s_t *obj, uint32_t *pbuf)
{
u32 cur_tx_page;
cur_tx_page = I2S_GetTxPage(I2S_DEV);
if (I2S_GetTxPageAddr(cur_tx_page) != (uint32_t)pbuf)
DBG_8195A("%s: tx buffer not match cur_tx_page \n", __func__);
I2S_TxPageDMA_EN(I2S_DEV, cur_tx_page);
}
/**
* @brief Sets current rx page own by i2s.
* @param obj: i2s object define in application software.
* @retval none
*/
void i2s_recv_page(i2s_t *obj)
{
u32 cur_rx_page;
cur_rx_page = I2S_GetRxPage(I2S_DEV);
if ((I2S_DEV->IS_RX_PAGE_OWN[cur_rx_page] & BIT(31)) == 0) {
I2S_RxPageDMA_EN(I2S_DEV,cur_rx_page);
} else {
//DBG_8195A("i2s_recv_page: re-enable\r\n");
}
}
/**
* @brief Enable i2s interrupt and function.
* @retval none
*/
void i2s_enable(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2S_Cmd(I2S_DEV, ENABLE);
I2S_INTConfig(I2S_DEV, (I2S_TX_INT_PAGE0_OK|I2S_TX_INT_PAGE1_OK| I2S_TX_INT_PAGE2_OK|I2S_TX_INT_PAGE3_OK),
(I2S_RX_INT_PAGE0_OK|I2S_RX_INT_PAGE1_OK | I2S_RX_INT_PAGE2_OK|I2S_RX_INT_PAGE3_OK));
}
/**
* @brief Disable i2s interrupt and function.
* @retval none
*/
void i2s_disable(i2s_t *obj)
{
//uint8_t i2s_idx = obj->i2s_idx;
I2S_INTConfig(I2S_DEV, 0, 0);
I2S_Cmd(I2S_DEV, DISABLE);
i2s_sw_reset();
}
/******************* (C) COPYRIGHT 2016 Realtek Semiconductor *****END OF FILE****/