From 838c430635b146a545033bf4f4552c02958508f2 Mon Sep 17 00:00:00 2001 From: Uros Majstorovic Date: Sun, 4 Sep 2022 18:22:50 +0200 Subject: new stereo audio driver --- fw/fe310/eos/soc/i2s.c | 293 +++++++++++++++++++++++++++++-------------------- 1 file changed, 174 insertions(+), 119 deletions(-) (limited to 'fw/fe310/eos/soc/i2s.c') diff --git a/fw/fe310/eos/soc/i2s.c b/fw/fe310/eos/soc/i2s.c index 5e5eaa7..c5b52bf 100644 --- a/fw/fe310/eos/soc/i2s.c +++ b/fw/fe310/eos/soc/i2s.c @@ -6,39 +6,54 @@ #include "prci_driver.h" #include "eos.h" -#include "interrupt.h" #include "event.h" +#include "interrupt.h" #include "board.h" +#include "dev/eve.h" + +#include "uart.h" + #include "i2s.h" #include "i2s_priv.h" #define I2S_REG_CK(o) _REG32(I2S_CTRL_ADDR_CK, o) -#define I2S_REG_WS_MIC(o) _REG32(I2S_CTRL_ADDR_WS_MIC, o) -#define I2S_REG_WS_SPK(o) _REG32(I2S_CTRL_ADDR_WS_SPK, o) +#define I2S_REG_WS(o) _REG32(I2S_CTRL_ADDR_WS, o) +#define I2S_REG_SR_SEL(o) _REG32(I2S_CTRL_ADDR_SR_SEL, o) -#define I2S_PIN_PWM ((1 << I2S_PIN_CK) | (1 << I2S_PIN_CK_SW) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK)) +#define I2S_PIN_PWM ((1 << I2S_PIN_CK) | (1 << I2S_PIN_SR_SEL) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK)) #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) #define EOS_ABUF_IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1)) -EOSABuf _eos_i2s_mic_buf; -EOSABuf _eos_i2s_spk_buf; -uint32_t _eos_i2s_fmt = 0; -uint32_t _eos_i2s_mic_wm = 0; -uint32_t _eos_i2s_spk_wm = 0; -uint32_t _eos_i2s_mic_evt_enable = 0; -uint32_t _eos_i2s_spk_evt_enable = 0; - -static eos_i2s_handler_t i2s_spk_handler = NULL; static eos_i2s_handler_t i2s_mic_handler = NULL; +static eos_i2s_handler_t i2s_spk_handler = NULL; static uint32_t i2s_clk_period; static uint8_t i2s_mic_volume = 0; /* 0 - 8 */ static uint8_t i2s_spk_volume = 16; /* 0 - 16 */ +EOSABuf _eos_i2s_mic_buf; +EOSABuf _eos_i2s_spk_buf; + +uint32_t _eos_i2s_drvr[] = { + EOS_I2S_FMT_PCM16, /* I2S_FMT */ + EOS_I2S_MODE_STEREO, /* I2S_MODE */ + 0, /* I2S_MIC_WM */ + 0, /* I2S_SPK_WM */ + 0, /* I2S_MIC_EVT */ + 0, /* I2S_SPK_EVT */ + }; + +#define I2S_FMT 0 +#define I2S_MODE 1 +#define I2S_MIC_WM 2 +#define I2S_SPK_WM 3 +#define I2S_MIC_EVT 4 +#define I2S_SPK_EVT 5 + static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) { buf->idx_r = 0; buf->idx_w = 0; @@ -84,7 +99,6 @@ static int _abuf_pop16(EOSABuf *buf, uint16_t *sample) { } } - static void _abuf_flush(EOSABuf *buf) { buf->idx_r = 0; buf->idx_w = 0; @@ -94,45 +108,48 @@ static uint16_t _abuf_len(EOSABuf *buf) { return buf->idx_w - buf->idx_r; } +__attribute__ ((section (".itim"))) static void i2s_handle_evt(unsigned char type, unsigned char *buffer, uint16_t len) { switch(type & ~EOS_EVT_MASK) { case EOS_I2S_ETYPE_MIC: - if (i2s_mic_handler) i2s_mic_handler(type); - clear_csr(mstatus, MSTATUS_MIE); - _eos_i2s_mic_evt_enable = 1; - set_csr(mstatus, MSTATUS_MIE); + if (i2s_mic_handler) { + i2s_mic_handler(type); + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_drvr[I2S_MIC_EVT] = 1; + set_csr(mstatus, MSTATUS_MIE); + } break; + case EOS_I2S_ETYPE_SPK: - if (i2s_spk_handler) i2s_spk_handler(type); - clear_csr(mstatus, MSTATUS_MIE); - _eos_i2s_spk_evt_enable = 1; - set_csr(mstatus, MSTATUS_MIE); + if (i2s_spk_handler) { + i2s_spk_handler(type); + clear_csr(mstatus, MSTATUS_MIE); + _eos_i2s_drvr[I2S_SPK_EVT] = 1; + set_csr(mstatus, MSTATUS_MIE); + } break; + default: eos_evtq_bad_handler(type, buffer, len); break; } } -static void _mic_vol_set(uint8_t vol) { - I2S_REG_WS_MIC(PWM_CMP2) = i2s_clk_period * (vol + 1); - I2S_REG_WS_MIC(PWM_CMP3) = I2S_REG_WS_MIC(PWM_CMP2) + i2s_clk_period * 16; -} - -static void _spk_vol_set(uint8_t vol) { - int spk_cmp = vol + i2s_mic_volume - 16; +static void i2s_set_cmp(void) { + int spk_ws_offset = i2s_spk_volume - 16 + i2s_mic_volume; - if (spk_cmp <= 0) { - I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * (32 + spk_cmp); - I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (64 + spk_cmp); - I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * 33; + /* adjust spk ws relative to mic ws */ + if (spk_ws_offset <= 0) { + spk_ws_offset += 32; GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK); } else { - I2S_REG_WS_SPK(PWM_CMP1) = i2s_clk_period * spk_cmp; - I2S_REG_WS_SPK(PWM_CMP2) = i2s_clk_period * (32 + spk_cmp); - I2S_REG_WS_SPK(PWM_CMP3) = i2s_clk_period * (33 + spk_cmp); - GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << I2S_PIN_WS_SPK); } + I2S_REG_WS(PWM_CMP2) = spk_ws_offset * i2s_clk_period - i2s_clk_period / 2; + I2S_REG_WS(PWM_CMP3) = (32 + spk_ws_offset) * i2s_clk_period - i2s_clk_period / 2; + + I2S_REG_SR_SEL(PWM_CMP1) = (1 + i2s_mic_volume) * i2s_clk_period; + I2S_REG_SR_SEL(PWM_CMP2) = (17 + i2s_mic_volume) * i2s_clk_period - (i2s_clk_period / 4); } extern void _eos_i2s_start_pwm(void); @@ -140,109 +157,127 @@ extern void _eos_i2s_start_pwm(void); int eos_i2s_init(uint8_t wakeup_cause) { eos_evtq_set_handler(EOS_EVT_I2S, i2s_handle_evt); - eos_i2s_init_mux(); - - GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW); - GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_CK_SR); - - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SW); - GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SW); - - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK_SR); - GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK_SR); - - return EOS_OK; -} - -void eos_i2s_init_mux(void) { - GPIO_REG(GPIO_OUTPUT_VAL) &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_WS_MIC) | (1 << I2S_PIN_WS_SPK)); - - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK); - GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK); + I2S_REG_CK(PWM_CFG) = 0; + I2S_REG_WS(PWM_CFG) = 0; + I2S_REG_SR_SEL(PWM_CFG) = 0; - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_MIC); - GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_SR_SEL); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_SR_CK); - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS_SPK); - GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_SR_SEL); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_SR_CK); GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD_IN); - GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_IN); - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); - GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); + return EOS_OK; } -void eos_i2s_start(uint32_t sample_rate, unsigned char fmt) { - i2s_clk_period = ((PRCI_get_cpu_freq() / (sample_rate * 64)) & ~I2S_PWM_SCALE_CK_MASK) + 1; - - GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD_IN); - GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_IN); - - GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); - GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD_OUT); +void eos_i2s_start(uint32_t sample_rate) { + uint32_t iof_mask; + i2s_clk_period = PRCI_get_cpu_freq() / (sample_rate * 64); + i2s_clk_period = (i2s_clk_period & ~I2S_PWM_SCALE_CK_MASK) + 1; I2S_REG_CK(PWM_CMP0) = i2s_clk_period >> I2S_PWM_SCALE_CK; I2S_REG_CK(PWM_CMP1) = I2S_REG_CK(PWM_CMP0) / 2; I2S_REG_CK(PWM_CMP2) = 0; I2S_REG_CK(PWM_CMP3) = 0; - I2S_REG_WS_MIC(PWM_CMP0) = i2s_clk_period * 64 - 1; - I2S_REG_WS_MIC(PWM_CMP1) = i2s_clk_period * 32; - _mic_vol_set(i2s_mic_volume); + I2S_REG_WS(PWM_CMP0) = i2s_clk_period * 64 - 1; + I2S_REG_WS(PWM_CMP1) = i2s_clk_period * 32; - I2S_REG_WS_SPK(PWM_CMP0) = i2s_clk_period * 64 - 1; - _spk_vol_set(i2s_spk_volume); + I2S_REG_SR_SEL(PWM_CMP0) = i2s_clk_period * 32 - 1; + I2S_REG_SR_SEL(PWM_CMP3) = 0; + i2s_set_cmp(); I2S_REG_CK(PWM_COUNT) = 0; - I2S_REG_WS_MIC(PWM_COUNT) = 0; - I2S_REG_WS_SPK(PWM_COUNT) = i2s_clk_period / 2; + I2S_REG_WS(PWM_COUNT) = 0; + I2S_REG_SR_SEL(PWM_COUNT) = 0; - _eos_i2s_fmt = fmt; - _eos_i2s_mic_evt_enable = 1; - _eos_i2s_spk_evt_enable = 1; + if (i2s_mic_handler) _eos_i2s_drvr[I2S_MIC_EVT] = 1; + if (i2s_spk_handler) _eos_i2s_drvr[I2S_SPK_EVT] = 1; - eos_intr_set_priority(I2S_IRQ_WS_ID, IRQ_PRIORITY_I2S_WS); - eos_intr_set_priority(I2S_IRQ_SD_ID, 0); - eos_intr_enable(I2S_IRQ_WS_ID); + eos_eve_intr_disable(); + eos_uart_disable(); + eos_intr_set_priority(I2S_IRQ_SD_ID, IRQ_PRIORITY_I2S_SD); eos_intr_enable(I2S_IRQ_SD_ID); + GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_INT); + GPIO_REG(GPIO_FALL_IE) |= (1 << I2S_PIN_INT); + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_SR_CK); + + iof_mask = I2S_PIN_PWM; + if (_eos_i2s_mic_buf.size == 0) { + iof_mask &= ~(1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_WS_MIC); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_MIC); + } else if (_eos_i2s_drvr[I2S_MIC_WM] == 0) { + _eos_i2s_drvr[I2S_MIC_WM] = _eos_i2s_mic_buf.size / 2; + } + if (_eos_i2s_spk_buf.size == 0) { + iof_mask &= ~(1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_SD_OUT); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_WS_SPK); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS_SPK); + } else if (_eos_i2s_drvr[I2S_SPK_WM] == 0) { + _eos_i2s_drvr[I2S_SPK_WM] = _eos_i2s_spk_buf.size / 2; + } + GPIO_REG(GPIO_IOF_SEL) |= iof_mask; + GPIO_REG(GPIO_IOF_EN) |= iof_mask; + _eos_i2s_start_pwm(); /* I2S_REG_CK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | I2S_PWM_SCALE_CK; - I2S_REG_WS_MIC(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG; - I2S_REG_WS_SPK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG; + I2S_REG_WS(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP2GANG; + I2S_REG_SR_SEL(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP | PWM_CFG_CMP1GANG; */ - - GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SR); - GPIO_REG(GPIO_IOF_SEL) |= I2S_PIN_PWM; - GPIO_REG(GPIO_IOF_EN) |= I2S_PIN_PWM; } void eos_i2s_stop(void) { I2S_REG_CK(PWM_CFG) = 0; - I2S_REG_WS_MIC(PWM_CFG) = 0; - I2S_REG_WS_SPK(PWM_CFG) = 0; + I2S_REG_WS(PWM_CFG) = 0; + I2S_REG_SR_SEL(PWM_CFG) = 0; I2S_REG_CK(PWM_COUNT) = 0; - I2S_REG_WS_MIC(PWM_COUNT) = 0; - I2S_REG_WS_SPK(PWM_COUNT) = 0; - - _eos_i2s_mic_evt_enable = 0; - _eos_i2s_spk_evt_enable = 0; - eos_intr_set_priority(I2S_IRQ_WS_ID, 0); - eos_intr_set_priority(I2S_IRQ_SD_ID, 0); - eos_intr_disable(I2S_IRQ_WS_ID); + I2S_REG_WS(PWM_COUNT) = 0; + I2S_REG_SR_SEL(PWM_COUNT) = 0; + eos_intr_disable(I2S_IRQ_SD_ID); - GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_CK_SW); - GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_CK_SR); + if (!(GPIO_REG(GPIO_IOF_EN) & I2S_PIN_WS_MIC)) { + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_WS_MIC); + } + if (!(GPIO_REG(GPIO_IOF_EN) & I2S_PIN_WS_SPK)) { + GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_WS_SPK); + } + GPIO_REG(GPIO_FALL_IE) &= ~(1 << I2S_PIN_INT); + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_INT); + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << I2S_PIN_SR_SEL); + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_SR_CK); GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS_SPK); GPIO_REG(GPIO_IOF_EN) &= ~I2S_PIN_PWM; + eos_uart_enable(); + eos_eve_intr_enable(); + + _eos_i2s_drvr[I2S_MIC_EVT] = 0; + _eos_i2s_drvr[I2S_SPK_EVT] = 0; + _eos_i2s_drvr[I2S_MIC_WM] = 0; + _eos_i2s_drvr[I2S_SPK_WM] = 0; + i2s_mic_handler = NULL; + i2s_spk_handler = NULL; + _abuf_init(&_eos_i2s_mic_buf, NULL, 0); + _abuf_init(&_eos_i2s_spk_buf, NULL, 0); } int eos_i2s_running(void) { - return !!(GPIO_REG(GPIO_IOF_EN) & I2S_PIN_PWM); + return !!(GPIO_REG(GPIO_IOF_EN) & (1 << I2S_PIN_CK)); +} + +void eos_i2s_set_fmt(unsigned char fmt) { + _eos_i2s_drvr[I2S_FMT] = fmt; +} + +void eos_i2s_set_mode(unsigned char mode) { + _eos_i2s_drvr[I2S_MODE] = mode; } void eos_i2s_mic_init(uint8_t *mic_arr, uint16_t mic_arr_size) { @@ -259,18 +294,22 @@ void eos_i2s_mic_set_handler(eos_i2s_handler_t wm_handler) { void eos_i2s_mic_set_wm(uint16_t wm) { clear_csr(mstatus, MSTATUS_MIE); - _eos_i2s_mic_wm = wm; + _eos_i2s_drvr[I2S_MIC_WM] = wm; set_csr(mstatus, MSTATUS_MIE); - } +__attribute__ ((section (".itim"))) uint16_t eos_i2s_mic_len(void) { + uint16_t ret; + clear_csr(mstatus, MSTATUS_MIE); - uint16_t ret = _abuf_len(&_eos_i2s_mic_buf); + ret = _abuf_len(&_eos_i2s_mic_buf); set_csr(mstatus, MSTATUS_MIE); + return ret; } +__attribute__ ((section (".itim"))) uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) { uint16_t i; uint16_t _ssize = 0; @@ -291,31 +330,36 @@ uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) { } int eos_i2s_mic_pop8(uint8_t *sample) { + int ret; + clear_csr(mstatus, MSTATUS_MIE); - int ret = _abuf_pop8(&_eos_i2s_mic_buf, sample); + ret = _abuf_pop8(&_eos_i2s_mic_buf, sample); set_csr(mstatus, MSTATUS_MIE); + return ret; } int eos_i2s_mic_pop16(uint16_t *sample) { + int ret; + clear_csr(mstatus, MSTATUS_MIE); - int ret = _abuf_pop16(&_eos_i2s_mic_buf, sample); + ret = _abuf_pop16(&_eos_i2s_mic_buf, sample); set_csr(mstatus, MSTATUS_MIE); + return ret; } -int eos_i2s_mic_vol_get(void) { +int eos_i2s_mic_get_vol(void) { return i2s_mic_volume; } -void eos_i2s_mic_vol_set(int vol) { +void eos_i2s_mic_set_vol(int vol) { if ((vol < 0) || (vol > 8)) return; i2s_mic_volume = vol; clear_csr(mstatus, MSTATUS_MIE); - _mic_vol_set(vol); - _spk_vol_set(i2s_spk_volume); + i2s_set_cmp(); set_csr(mstatus, MSTATUS_MIE); } @@ -333,17 +377,22 @@ void eos_i2s_spk_set_handler(eos_i2s_handler_t wm_handler) { void eos_i2s_spk_set_wm(uint16_t wm) { clear_csr(mstatus, MSTATUS_MIE); - _eos_i2s_spk_wm = wm; + _eos_i2s_drvr[I2S_SPK_WM] = wm; set_csr(mstatus, MSTATUS_MIE); } +__attribute__ ((section (".itim"))) uint16_t eos_i2s_spk_len(void) { + uint16_t ret; + clear_csr(mstatus, MSTATUS_MIE); - uint16_t ret = _abuf_len(&_eos_i2s_spk_buf); + ret = _abuf_len(&_eos_i2s_spk_buf); set_csr(mstatus, MSTATUS_MIE); + return ret; } +__attribute__ ((section (".itim"))) uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) { uint16_t i; uint16_t _ssize = 0; @@ -364,29 +413,35 @@ uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) { } int eos_i2s_spk_push8(uint8_t sample) { + int ret; + clear_csr(mstatus, MSTATUS_MIE); - int ret = _abuf_push8(&_eos_i2s_spk_buf, sample); + ret = _abuf_push8(&_eos_i2s_spk_buf, sample); set_csr(mstatus, MSTATUS_MIE); + return ret; } int eos_i2s_spk_push16(uint16_t sample) { + int ret; + clear_csr(mstatus, MSTATUS_MIE); - int ret = _abuf_push16(&_eos_i2s_spk_buf, sample); + ret = _abuf_push16(&_eos_i2s_spk_buf, sample); set_csr(mstatus, MSTATUS_MIE); + return ret; } -int eos_i2s_spk_vol_get(void) { +int eos_i2s_spk_get_vol(void) { return i2s_spk_volume; } -void eos_i2s_spk_vol_set(int vol) { +void eos_i2s_spk_set_vol(int vol) { if ((vol < 0) || (vol > 16)) return; i2s_spk_volume = vol; clear_csr(mstatus, MSTATUS_MIE); - _spk_vol_set(vol); + i2s_set_cmp(); set_csr(mstatus, MSTATUS_MIE); } -- cgit v1.2.3