Files
99_7018_lmx/cpu/br28/pdm_link.c
2025-10-29 13:10:02 +08:00

247 lines
6.1 KiB
C

#include "includes.h"
#include "asm/includes.h"
#include "asm/gpio.h"
#include "asm/dac.h"
#include "media/includes.h"
#include "pdm_link.h"
#define PLNK_DEBUG_ENABLE
#ifdef PLNK_DEBUG_ENABLE
//#define PLNK_LOG(fmt, ...) printf("[PLNK] "fmt, ##__VA_ARGS__)
#define PLNK_LOG y_printf
#else
#define PLNK_LOG(...)
#endif
#define PLNK_TEST_ENABLE 0
static audio_plnk_t *pdm_hdl = NULL;
___interrupt
static void audio_plnk_isr(void)
{
JL_PORTA->OUT ^= BIT(12);
u8 buf_flag;
s16 *buf = pdm_hdl->buf;
u16 len = pdm_hdl->buf_len;
s16 *data_buf;
if (JL_PLNK->CON & BIT(15)) {
PLNK_PND_CLR();
if (JL_PLNK->CON & BIT(9)) {
buf_flag = 0; //buf0 available
} else {
buf_flag = 1; //buf1 available
}
data_buf = (s16 *)buf;
data_buf += buf_flag * len;
}
if (pdm_hdl && pdm_hdl->output) {
pdm_hdl->output(data_buf, len);
}
}
static void plnk_info_dump()
{
PLNK_LOG("PLNK_CON = 0x%x", JL_PLNK->CON);
PLNK_LOG("CLK_CON = 0x%x", JL_CLOCK->CLK_CON0);
PLNK_LOG("PLNK_CON1 = 0x%x", JL_PLNK->CON1);
PLNK_LOG("PLNK_LEN = 0x%x", JL_PLNK->LEN);
PLNK_LOG("PLNK_ADR = 0x%x", JL_PLNK->ADR);
PLNK_LOG("PLNK_SMR = %d", JL_PLNK->SMR);
PLNK_LOG("PLNK_DOR = %d", JL_PLNK->DOR);
}
static void audio_plnk_sr_set(u16 sr)
{
PLNK_LOG("PLNK_SR = %d\n", sr);
JL_PLNK->DOR = PLNK_SCLK / sr - 1;
u8 div = PLNK_CLK / PLNK_SCLK - 1;
SFR(JL_ASS->CLK_CON, 2, 5, div);
}
static void audio_plnk_sclk_io_init(u8 port)
{
r_printf("port === %d\n", port);
gpio_set_fun_output_port(port, FO_PLNK_SCLK, 0, 1, LOW_POWER_FREE);
gpio_set_direction(port, 0);
gpio_set_die(port, 0);
gpio_direction_output(port, 1);
}
static void audio_plnk_ch_io_init(u8 ch_index, u8 port)
{
gpio_set_pull_down(port, 0);
gpio_set_pull_up(port, 1);
gpio_set_direction(port, 1);
gpio_set_die(port, 1);
if (ch_index) {
gpio_set_fun_input_port(port, PFI_PLNK_DAT1, LOW_POWER_FREE);
} else {
gpio_set_fun_input_port(port, PFI_PLNK_DAT0, LOW_POWER_FREE);
}
}
int audio_plnk_open(audio_plnk_t *hdl)
{
if (hdl == NULL) {
return -EINVAL;
}
pdm_hdl = hdl;
PLNK_LOG("audio_plnk_open,ch=%d,sr=%d", pdm_hdl->ch_num, pdm_hdl->sr);
PLNK_CON_RESET();
JL_PLNK->ADR = (u32)pdm_hdl->buf;
JL_PLNK->LEN = pdm_hdl->buf_len;
/*
*PLNK_CLK -> SMR -> SCLK -> DOR ->SR
*1MHz <= SCLK <= 4MHz
*sclk = PLINK_CLK / (SMR + 1)
*5 <= SMR <= 47
*PLNK_DOR
*Version(A/B):0~4096
*Version(C):1~2048
*/
SFR(JL_PLNK->CON, 1, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
SFR(JL_PLNK->CON, 5, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
audio_plnk_sr_set(pdm_hdl->sr);
audio_plnk_sclk_io_init(pdm_hdl->sclk_io);
audio_plnk_ch_io_init(0, pdm_hdl->ch0_io);
/* audio_plnk_ch_io_init(1, pdm_hdl->ch1_io); */
SFR(JL_PLNK->CON1, 26, 1, 0); //DFDLY1_SEL(0:M=1 1:M=2)
SFR(JL_PLNK->CON1, 10, 1, 0); //DFDLY0_SEL(0:M=1 1:M=2)
SFR(JL_PLNK->CON1, 19, 5, 10); //SHIFT1_SEL[23:19]
SFR(JL_PLNK->CON1, 3, 5, 10); //SHIFT0_SEL[7:3]
SFR(JL_PLNK->CON1, 16, 3, 3); //SCALE1_SEL
SFR(JL_PLNK->CON1, 0, 3, 3); //SCALE0_SEL
SFR(JL_PLNK->CON1, 24, 2, 0); //ORDER1_SEL
SFR(JL_PLNK->CON1, 8, 2, 0); //ORDER0_SEL
SFR(JL_PLNK->CON1, 27, 1, 0); //SHDIR1_SEL
SFR(JL_PLNK->CON1, 11, 1, 0); //SHDIR0_SEL
SFR(JL_PLNK->CON1, 28, 2, 0);
SFR(JL_PLNK->CON1, 12, 2, 0);
SFR(JL_PLNK->CON1, 30, 1, 0); //CIC1_EN
SFR(JL_PLNK->CON1, 14, 1, 0); //CIC0_EN
if (PLNK_CH_EN == PLNK_CH0_EN) {
PLNK_CH0_MD_SET(pdm_hdl->ch0_mode);
} else if (PLNK_CH_EN == PLNK_CH1_EN) {
PLNK_CH1_MD_SET(pdm_hdl->ch1_mode);
} else {
PLNK_CH0_MD_SET(pdm_hdl->ch0_mode);
PLNK_CH1_MD_SET(pdm_hdl->ch1_mode);
}
PLNK_PND_CLR();
request_irq(IRQ_PDM_LINK_IDX, 1, audio_plnk_isr, 0);
return 0;
}
int audio_plnk_start(audio_plnk_t *hdl)
{
JL_PLNK->CON |= BIT(8); //IE
if (hdl->ch_num == 1) {
SFR(JL_PLNK->CON, 0, 1, 1); //CH0EN
SFR(JL_PLNK->CON, 4, 1, 0); //CH1 DIS
} else {
SFR(JL_PLNK->CON, 0, 1, 1); //CH0EN
SFR(JL_PLNK->CON, 4, 1, 1); //CH1EN
}
plnk_info_dump();
return 0;
}
int audio_plnk_close(void)
{
JL_PLNK->CON = 0;
pdm_hdl = NULL;
return 0;
}
#if PLNK_TEST_ENABLE
extern struct audio_dac_hdl dac_hdl;
static short const sin0_16k[16] = {
0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
};
static u16 tx1_s_cnt = 0;
static int get_sine0_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
{
while (points--) {
if (*s_cnt >= 16) {
*s_cnt = 0;
}
*data++ = sin0_16k[*s_cnt];
if (ch == 2) {
*data++ = sin0_16k[*s_cnt];
}
(*s_cnt)++;
}
return 0;
}
static void handle_output(void *buf, u16 len)
{
/* get_sine0_data(&tx1_s_cnt, buf, 256, 1); */
s16 *paddr = (s16 *)buf;
u32 len0 = 256 * 2;
u32 rlen = 256 * 2;
while (len0) {
rlen = audio_dac_write(&dac_hdl, paddr, len0);
/* printf("rlen = %d\n", rlen); */
if (rlen != len0) {
printf("rlen = %d, len0 = %d\n", rlen, len0);
}
len0 -= rlen;
paddr += rlen / 2;
if (rlen == 0) {
}
}
}
audio_plnk_t test_plink = {
.sclk_io = IO_PORTA_04,
.ch_num = 1,
.ch0_io = IO_PORTA_03,
.ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE,
.sr = 16000,
.buf_len = 256,
};
void audio_plnk_test(void)
{
y_printf("pdm link demo\n");
test_plink.output = handle_output;
test_plink.buf = zalloc(test_plink.buf_len * test_plink.ch_num * 2 * 2);
ASSERT(test_plink.buf);
/* JL_WL_AUD->CON0 |= BIT(0); */
audio_plnk_open(&test_plink);
audio_plnk_start(&test_plink);
#if 1
extern void app_audio_state_switch(u8 state, s16 max_volume);
app_audio_state_switch(1, 16);
audio_dac_set_volume(&dac_hdl, 16);
audio_dac_set_sample_rate(&dac_hdl, 16000);
audio_dac_start(&dac_hdl);
SFR(JL_ASS->CLK_CON, 0, 2, 3);
#endif
while (1);
}
#endif