Bläddra i källkod

add:支持i2s

Dozingfiretruck 2 år sedan
förälder
incheckning
1494db6bfb

+ 360 - 0
app/audio_driver/es8311.c

@@ -0,0 +1,360 @@
+
+#include "luat_base.h"
+#include "luat_i2c.h"
+#include "luat_audio_air101.h"
+#include "wm_include.h"
+#include "es8311.h"
+
+static void es8311_write_reg(uint8_t addr, uint8_t data){
+    uint8_t temp[] = {addr,data};
+    luat_i2c_send(0, ES8311_ADDR, temp, 2 , 1);
+	tls_os_time_delay(1);
+}
+
+static uint8_t es8311_read_reg(uint8_t addr){
+	uint8_t temp=0;
+    luat_i2c_send(0, ES8311_ADDR, &addr, 1 , 0);
+    luat_i2c_recv(0, ES8311_ADDR, &temp, 1);
+	return temp;
+}
+
+static int es8311_codec_standby(void){
+    es8311_write_reg(ES8311_DAC_REG32, 0x00);
+    es8311_write_reg(ES8311_ADC_REG17, 0x00);
+    es8311_write_reg(ES8311_SYSTEM_REG0E, 0xFF);
+    es8311_write_reg(ES8311_SYSTEM_REG12, 0x02);
+    es8311_write_reg(ES8311_SYSTEM_REG14, 0x00);
+    es8311_write_reg(ES8311_SYSTEM_REG0D, 0xFA);
+    es8311_write_reg(ES8311_RESET_REG00, 0x00);
+    es8311_write_reg(ES8311_RESET_REG00, 0x1F);
+    es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x30);
+    es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x00);
+    es8311_write_reg(ES8311_GP_REG45, 0x01);
+    es8311_write_reg(ES8311_SYSTEM_REG0D, 0xFC);
+    return 0;
+}
+
+static uint8_t es8311_codec_vol(uint8_t vol){
+    if(vol < 0 || vol > 100){
+		return -1;
+    }
+    int gain = vol == 0 ? -955 : (vol - 80) * 5;
+	uint8_t reg_val = (uint8_t)((gain + 955) / 5);
+	es8311_write_reg(ES8311_DAC_REG32, reg_val);
+	return vol;
+}
+
+/*0---master, 1---slave*/
+static void es8311_codec_mode(uint8_t mode){
+	if (mode == 0){
+		es8311_write_reg(ES8311_RESET_REG00, 0xC0);
+	}else{	
+		es8311_write_reg(ES8311_RESET_REG00, 0x80);
+	}
+}
+
+static int es8311_codec_samplerate(uint16_t samplerate){
+    if(samplerate != 8000 && samplerate != 16000 && samplerate != 32000 &&
+        samplerate != 11025 && samplerate != 22050 && samplerate != 44100 &&
+        samplerate != 12000 && samplerate != 24000 && samplerate != 48000)
+    {
+        printf("samplerate error!\n");
+        return -1;
+    }
+    // uint8_t i = 0;
+	static int mclk = 0;
+	static int switchflag = 0;
+    switch(samplerate){
+        case 8000:
+			if (mclk == 0){
+				mclk = 1;
+			}
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, 0x08);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x44);
+			if (switchflag == 0){
+				switchflag = 1;
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x19);
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x19);
+			}
+            break;
+        case 16000:
+			if (mclk == 0){
+				mclk = 1;
+			}
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, 0x90);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+			if (switchflag == 0){
+				switchflag = 1;
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x19);
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x19);
+			}
+            break;
+        case 32000:
+			if (mclk == 0){
+				mclk = 1;
+			}
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, 0x18);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x44);
+			if (switchflag == 0){
+				switchflag = 1;
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x19);
+	            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x19);
+			}
+            break;
+        case 44100:
+			mclk = 0;
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x03 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        case 22050:
+			mclk = 0;
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x02 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        case 11025:
+			mclk = 0;			
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x01 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        case 48000:
+			mclk = 0;		
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x03 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        case 24000:
+			mclk = 0;		
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x02 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        case 12000:
+			mclk = 0;			
+			switchflag = 0;
+            es8311_write_reg(ES8311_CLK_MANAGER_REG02, (0x01 << 3));
+            es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x10);
+            es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x10);
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static int es8311_update_bits(uint8_t reg, uint8_t mask, uint8_t val){
+    uint8_t old, new;
+    old = es8311_read_reg(reg);
+    new = (old & ~mask) | (val & mask);
+    es8311_write_reg(reg, new);
+    return 0;
+}
+
+static int es8311_codec_samplebits(uint8_t samplebits){
+    if(samplebits != 8 && samplebits != 16 && samplebits != 24 && samplebits != 32){
+        wm_printf("bit_width error!\n");
+        return -1;
+    }
+    int wl;
+    switch (samplebits)
+    {
+    case 16:
+        wl = 3;
+        break;
+    case 18:
+        wl = 2;
+        break;
+    case 20:
+        wl = 1;
+        break;
+    case 24:
+        wl = 0;
+        break;
+    case 32:
+        wl = 4;
+        break;
+    default:
+        return -1;
+    }
+    es8311_update_bits(ES8311_SDPIN_REG09,
+                        ES8311_SDPIN_REG09_DACWL_MASK,
+                        wl << ES8311_SDPIN_REG09_DACWL_SHIFT);
+    es8311_update_bits(ES8311_SDPOUT_REG0A,
+                        ES8311_SDPOUT_REG0A_ADCWL_MASK,
+                        wl << ES8311_SDPOUT_REG0A_ADCWL_SHIFT);
+    return 0;
+}
+
+static int es8311_codec_channels(uint8_t channels){
+    return 0;
+}
+
+static int es8311_reg_init(void){
+    /* reset codec */
+    es8311_write_reg(ES8311_RESET_REG00, 0x1F);
+    es8311_write_reg(ES8311_GP_REG45, 0x00);
+
+    tls_os_time_delay(10);
+
+    // es8311_write_reg(ES8311_GPIO_REG44, 0x08);
+    // tls_os_time_delay(1);
+    // es8311_write_reg(ES8311_GPIO_REG44, 0x08);
+
+    /* set ADC/DAC CLK */
+    /* MCLK from BCLK  */
+    es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x30);
+    es8311_write_reg(ES8311_CLK_MANAGER_REG02, 0x90);
+    es8311_write_reg(ES8311_CLK_MANAGER_REG03, 0x19);
+    es8311_write_reg(ES8311_ADC_REG16, 0x02);// bit5:0~non standard audio clock
+    es8311_write_reg(ES8311_CLK_MANAGER_REG04, 0x19);
+    es8311_write_reg(ES8311_CLK_MANAGER_REG05, 0x00);
+	/*new cfg*/
+	es8311_write_reg(ES8311_CLK_MANAGER_REG06, BCLK_DIV);
+	es8311_write_reg(ES8311_CLK_MANAGER_REG07, 0x01);
+	es8311_write_reg(ES8311_CLK_MANAGER_REG08, 0xff);
+    /* set system power up */
+    es8311_write_reg(ES8311_SYSTEM_REG0B, 0x00);
+    es8311_write_reg(ES8311_SYSTEM_REG0C, 0x00);
+    es8311_write_reg(ES8311_SYSTEM_REG10, 0x1F);
+    es8311_write_reg(ES8311_SYSTEM_REG11, 0x7F);
+    /* chip powerup. slave mode */
+    es8311_write_reg(ES8311_RESET_REG00, 0x80);
+    tls_os_time_delay(50);
+
+    /* power up analog */
+    es8311_write_reg(ES8311_SYSTEM_REG0D, 0x01);
+    /* power up digital */
+    es8311_write_reg(ES8311_CLK_MANAGER_REG01, 0x3F);
+    // SET ADC
+    es8311_write_reg(ES8311_SYSTEM_REG14, DADC_GAIN);
+    // SET DAC
+    es8311_write_reg(ES8311_SYSTEM_REG12, 0x00);
+    // ENABLE HP DRIVE
+    es8311_write_reg(ES8311_SYSTEM_REG13, 0x10);
+    // SET ADC/DAC DATA FORMAT
+    es8311_write_reg(ES8311_SDPIN_REG09, 0x0c);
+    es8311_write_reg(ES8311_SDPOUT_REG0A, 0x0c);
+
+    /* set normal power mode */
+    es8311_write_reg(ES8311_SYSTEM_REG0E, 0x02);
+    es8311_write_reg(ES8311_SYSTEM_REG0F, 0x44);
+    // SET ADC
+    /* set adc softramp */
+    es8311_write_reg(ES8311_ADC_REG15, 0x00);
+    /* set adc hpf */
+    es8311_write_reg(ES8311_ADC_REG1B, 0x05);
+    /* set adc hpf,ADC_EQ bypass */
+    es8311_write_reg(ES8311_ADC_REG1C, 0x65);
+    /* set adc digtal vol */
+    es8311_write_reg(ES8311_ADC_REG17, ADC_VOLUME_GAIN);
+
+    /* set dac softramp,disable DAC_EQ */
+    es8311_write_reg(ES8311_DAC_REG37, 0x08);
+    es8311_write_reg(ES8311_DAC_REG32, 0xBF);
+
+    // /* set adc gain scale up */
+    // es8311_write_reg(ES8311_ADC_REG16, 0x24);
+    // /* set adc alc maxgain */
+    // es8311_write_reg(ES8311_ADC_REG17, 0xBF);
+    // /* adc alc disable,alc_winsize */
+    // es8311_write_reg(ES8311_ADC_REG18, 0x07);
+    // /* set alc target level */
+    // es8311_write_reg(ES8311_ADC_REG19, 0xFB);
+    // /* set adc_automute noise gate */
+    // es8311_write_reg(ES8311_ADC_REG1A, 0x03);
+    // /* set adc_automute vol */
+    // es8311_write_reg(ES8311_ADC_REG1B, 0xEA);
+    return 0;
+}
+
+static int es8311_codec_init(audio_codec_conf_t* conf){
+    uint8_t temp1 = 0, temp2 = 0, temp3 = 0;
+    if (conf->pa_pin != -1){
+        tls_gpio_cfg(conf->pa_pin, !conf->pa_on_level, WM_GPIO_ATTR_FLOATING);
+        tls_gpio_write(conf->pa_pin, !conf->pa_on_level);
+    }
+    luat_i2c_setup(0, I2C_REQ);
+    temp1 = es8311_read_reg(ES8311_CHD1_REGFD);
+    temp2 = es8311_read_reg(ES8311_CHD2_REGFE);
+    temp3 = es8311_read_reg(ES8311_CHVER_REGFF);
+    if(temp1 != 0x83 || temp2 != 0x11){
+        printf("codec err, id = 0x%x 0x%x ver = 0x%x\n", temp1, temp2, temp3);
+        return -1;
+    }
+    es8311_reg_init();
+    return 0;
+}
+
+static int es8311_codec_deinit(audio_codec_conf_t* conf){
+
+    return 0;
+}
+
+static void es8311_codec_pa(audio_codec_conf_t* conf,uint8_t on){
+	if (on){
+        tls_os_time_delay(conf->dummy_time_len);
+        tls_gpio_write(conf->pa_pin, conf->pa_on_level);
+        tls_os_time_delay(conf->pa_delay_time);
+	}else{	
+        tls_gpio_write(conf->pa_pin, !conf->pa_on_level);
+	}
+}
+
+static int es8311_codec_control(audio_codec_conf_t* conf,uint8_t cmd,int data){
+    switch (cmd)
+    {
+    case CODEC_CTL_MODE:
+        es8311_codec_mode((uint8_t)data);
+        break;
+    case CODEC_CTL_VOLUME:
+        es8311_codec_vol((uint8_t)data);
+        break;
+    case CODEC_CTL_RATE:
+        es8311_codec_samplerate((uint16_t)data);
+        break;
+    case CODEC_CTL_BITS:
+        es8311_codec_samplebits((uint8_t)data);
+        break;
+    case CODEC_CTL_CHANNEL:
+        es8311_codec_channels((uint8_t)data);
+        break;
+    case CODEC_CTL_PA:
+        es8311_codec_pa(conf,(uint8_t)data);
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static int es8311_codec_start(audio_codec_conf_t* conf){
+
+    return 0;
+}
+
+static int es8311_codec_stop(audio_codec_conf_t* conf){
+
+    return 0;
+}
+
+const audio_codec_opts_t codec_opts_es8311 = {
+    .name = "es8311",
+    .init = es8311_codec_init,
+    .deinit = es8311_codec_deinit,
+    .control = es8311_codec_control,
+    .start = es8311_codec_start,
+    .stop = es8311_codec_stop,
+};

+ 68 - 0
app/audio_driver/es8311.h

@@ -0,0 +1,68 @@
+#ifndef __ES8311_H__
+#define __ES8311_H__
+
+#define I2C_REQ     400*1000
+
+#define ADC_VOLUME_GAIN 0xDF  //0xEF
+#define DADC_GAIN 0x1A        //0x17
+#define BCLK_DIV  0x13        //0x07
+
+#define ES8311_ADDR  0x18
+
+/* ES8311_REGISTER NAME_REG_REGISTER ADDRESS */
+
+#define ES8311_RESET_REG00              0x00  /*reset digital,csm,clock manager etc.*/
+
+/* Clock Scheme Register definition */
+
+#define ES8311_CLK_MANAGER_REG01        0x01 /* select clk src for mclk, enable clock for codec */
+#define ES8311_CLK_MANAGER_REG02        0x02 /* clk divider and clk multiplier */
+#define ES8311_CLK_MANAGER_REG03        0x03 /* adc fsmode and osr  */
+#define ES8311_CLK_MANAGER_REG04        0x04 /* dac osr */
+#define ES8311_CLK_MANAGER_REG05        0x05 /* clk divier for adc and dac */
+#define ES8311_CLK_MANAGER_REG06        0x06 /* bclk inverter and divider */
+#define ES8311_CLK_MANAGER_REG07        0x07 /* tri-state, lrck divider */
+#define ES8311_CLK_MANAGER_REG08        0x08 /* lrck divider */
+#define ES8311_SDPIN_REG09              0x09 /* dac serial digital port */
+#define ES8311_SDPIN_REG09_DACWL_MASK   (7 << 2)
+#define ES8311_SDPIN_REG09_DACWL_SHIFT  2
+#define ES8311_SDPOUT_REG0A             0x0A /* adc serial digital port */
+#define ES8311_SDPOUT_REG0A_ADCWL_MASK  (7 << 2)
+#define ES8311_SDPOUT_REG0A_ADCWL_SHIFT 2
+#define ES8311_SYSTEM_REG0B             0x0B /* system */
+#define ES8311_SYSTEM_REG0C             0x0C /* system */
+#define ES8311_SYSTEM_REG0D             0x0D /* system, power up/down */
+#define ES8311_SYSTEM_REG0E             0x0E /* system, power up/down */
+#define ES8311_SYSTEM_REG0F             0x0F /* system, low power */
+#define ES8311_SYSTEM_REG10             0x10 /* system */
+#define ES8311_SYSTEM_REG11             0x11 /* system */
+#define ES8311_SYSTEM_REG12             0x12 /* system, Enable DAC */
+#define ES8311_SYSTEM_REG13             0x13 /* system */
+#define ES8311_SYSTEM_REG14             0x14 /* system, select DMIC, select analog pga gain */
+#define ES8311_ADC_REG15                0x15 /* ADC, adc ramp rate, dmic sense */
+#define ES8311_ADC_REG16                0x16 /* ADC */
+#define ES8311_ADC_REG17                0x17 /* ADC, volume */
+#define ES8311_ADC_REG18                0x18 /* ADC, alc enable and winsize */
+#define ES8311_ADC_REG19                0x19 /* ADC, alc maxlevel */
+#define ES8311_ADC_REG1A                0x1A /* ADC, alc automute */
+#define ES8311_ADC_REG1B                0x1B /* ADC, alc automute, adc hpf s1 */
+#define ES8311_ADC_REG1C                0x1C /* ADC, equalizer, hpf s2 */
+#define ES8311_DAC_REG31                0x31 /* DAC, mute */
+#define ES8311_DAC_REG32                0x32 /* DAC, volume */
+#define ES8311_DAC_REG33                0x33 /* DAC, offset */
+#define ES8311_DAC_REG34                0x34 /* DAC, drc enable, drc winsize */
+#define ES8311_DAC_REG35                0x35 /* DAC, drc maxlevel, minilevel */
+#define ES8311_DAC_REG37                0x37 /* DAC, ramprate */
+#define ES8311_GPIO_REG44               0x44 /* GPIO, dac2adc for test */
+#define ES8311_GP_REG45                 0x45 /* GP CONTROL */
+#define ES8311_CHD1_REGFD               0xFD /* CHIP ID1 */
+#define ES8311_CHD2_REGFE               0xFE /* CHIP ID2 */
+#define ES8311_CHVER_REGFF              0xFF /* VERSION */
+#define ES8311_CHD1_REGFD               0xFD /* CHIP ID1 */
+#define ES8311_MAX_REGISTER             0xFF
+
+
+const audio_codec_opts_t codec_opts_es8311;
+
+
+#endif /* __ES8311_H__ */

+ 114 - 0
app/port/luat_audio_air101.c

@@ -0,0 +1,114 @@
+#include "luat_base.h"
+#include "luat_audio.h"
+#include "luat_i2s.h"
+#include "wm_include.h"
+#include "luat_audio_air101.h"
+#include "es8311.h"
+
+extern volatile uint8_t run_status;
+
+audio_codec_conf_t audio_hardware = {
+    .pa_pin = -1
+};
+
+int luat_audio_play_multi_files(uint8_t multimedia_id, uData_t *info, uint32_t files_num, uint8_t error_stop){
+
+}
+
+int luat_audio_play_file(uint8_t multimedia_id, const char *path){
+
+}
+
+uint8_t luat_audio_is_finish(uint8_t multimedia_id){
+    return run_status;
+}
+
+int luat_audio_play_stop(uint8_t multimedia_id){
+    luat_i2s_close(0);
+}
+
+int luat_audio_play_get_last_error(uint8_t multimedia_id){
+
+}
+
+int luat_audio_start_raw(uint8_t multimedia_id, uint8_t audio_format, uint8_t num_channels, uint32_t sample_rate, uint8_t bits_per_sample, uint8_t is_signed){
+    if(sample_rate == 8000 && bits_per_sample == 8){
+        wm_printf("not support 8K 8Bit record!\n");
+        return -1;
+    }
+	
+    luat_i2s_conf_t conf = {
+        .channel_format = 0,
+        .communication_format = 0,
+        .bits_per_sample = bits_per_sample,
+        .sample_rate = sample_rate,
+        .mclk = 8000000
+    };
+    luat_i2s_setup(&conf);
+
+	luat_audio_vol(0, 5);
+	audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_RATE,sample_rate);
+	audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_MODE,CODEC_MODE_SLAVE);
+	audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_PA,CODEC_PA_ON);
+
+}
+
+int luat_audio_write_raw(uint8_t multimedia_id, uint8_t *data, uint32_t len){
+    int send_bytes = 0;
+    while (send_bytes < len) {
+        int length = luat_i2s_send(0,data + send_bytes, len - send_bytes);
+        if (length > 0) {
+            send_bytes += length;
+        }
+        vTaskDelay(1);
+    }
+    return 0;
+}
+
+int luat_audio_stop_raw(uint8_t multimedia_id){
+    luat_i2s_close(0);
+}
+
+int luat_audio_pause_raw(uint8_t multimedia_id, uint8_t is_pause){
+    if (is_pause){
+        audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_PA,CODEC_PA_OFF);
+        luat_i2s_stop(0);
+    }else{
+        audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_PA,CODEC_PA_ON);
+        luat_i2s_resume(0);
+    }
+}
+
+void luat_audio_config_pa(uint8_t multimedia_id, uint32_t pin, int level, uint32_t dummy_time_len, uint32_t pa_delay_time){
+	if (pin <= WM_IO_PB_31){
+		audio_hardware.pa_pin = pin;
+		audio_hardware.pa_on_level = level;
+        tls_gpio_cfg(pin, !level, WM_GPIO_ATTR_FLOATING);
+        tls_gpio_write(pin, !level);
+	}else{
+		audio_hardware.pa_pin = -1;
+	}
+    audio_hardware.dummy_time_len = dummy_time_len;
+	audio_hardware.pa_delay_time = pa_delay_time;
+}
+
+void luat_audio_config_dac(uint8_t multimedia_id, int pin, int level, uint32_t dac_off_delay_time){}
+
+uint16_t luat_audio_vol(uint8_t multimedia_id, uint16_t vol){
+    if(vol < 0 || vol > 100){
+		return -1;
+    }
+	audio_hardware.vol = vol;
+    audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_VOLUME,vol);
+	return audio_hardware.vol;
+}
+
+void luat_audio_set_bus_type(uint8_t bus_type){
+    if (bus_type == 1){
+        audio_hardware.codec_opts = &codec_opts_es8311;
+        audio_hardware.codec_opts->init(&audio_hardware);
+        audio_hardware.codec_opts->control(&audio_hardware,CODEC_CTL_MODE,CODEC_MODE_SLAVE);
+    }
+}
+
+

+ 42 - 0
app/port/luat_audio_air101.h

@@ -0,0 +1,42 @@
+#ifndef _LUAT_AUDIOAIR101_H_
+#define _LUAT_AUDIOAIR101_H_
+
+struct audio_codec_opts;
+
+typedef struct audio_codec_conf {
+    int samplerate;         //16k
+    int bits;               //16
+    int channels;           //1ch/2ch
+    int pa_pin;
+	uint8_t vol;
+	uint8_t pa_on_level;
+    uint32_t dummy_time_len;
+    uint32_t pa_delay_time;
+    const struct audio_codec_opts* codec_opts;
+} audio_codec_conf_t;
+
+typedef struct audio_codec_opts{
+    const char* name;
+    int (*init)(audio_codec_conf_t* conf);
+    int (*deinit)(audio_codec_conf_t* conf);
+    int (*control)(audio_codec_conf_t* conf,uint8_t cmd,int data);
+    int (*start)(audio_codec_conf_t* conf);
+    int (*stop)(audio_codec_conf_t* conf);
+} audio_codec_opts_t;
+
+#define CODEC_MODE_MASTER               0x00
+#define CODEC_MODE_SLAVE                0x01
+
+#define CODEC_PA_OFF                    0x00
+#define CODEC_PA_ON                     0x01
+
+#define CODEC_CTL_MODE                  0x00
+#define CODEC_CTL_VOLUME                0x01
+#define CODEC_CTL_RATE                  0x02
+#define CODEC_CTL_BITS                  0x03
+#define CODEC_CTL_CHANNEL               0x04
+#define CODEC_CTL_PA                    0x05
+
+#endif
+
+

+ 7 - 0
app/port/luat_base_air101.c

@@ -237,6 +237,13 @@ static const luaL_Reg loadedlibs[] = {
 #endif
 #ifdef LUAT_USE_FASTLZ
   {"fastlz", luaopen_fastlz},
+#endif
+#ifdef LUAT_USE_MEDIA
+  {"i2s", luaopen_i2s},
+  {"audio", luaopen_multimedia_audio},
+#ifndef LUAT_USE_TTS_ONLY
+  {"codec", luaopen_multimedia_codec},
+#endif
 #endif
   // {"opus", luaopen_opus},
   {NULL, NULL}

+ 2 - 0
app/port/luat_conf_bsp.h

@@ -114,6 +114,8 @@
 // 硬件加速的版本只支持AES128,若使用AES256就报错了
 #define LUAT_USE_CRYPTO_AES_MBEDTLS  1
 
+#define LUAT_USE_MEDIA  1
+
 //---------------SDIO-FATFS特别配置
 // sdio库对接的是fatfs
 // fatfs的长文件名和非英文文件名支持需要180k的ROM, 非常奢侈

+ 118 - 21
app/port/luat_i2s_air101.c

@@ -5,48 +5,128 @@
 #include "wm_i2s.h"
 #include "wm_gpio_afsel.h"
 
+#include "c_common.h"
+
 #define LUAT_LOG_TAG "i2s"
 #include "luat_log.h"
 
-int tls_i2s_io_init(void)
-{
+#define AUDIO_BUF_SIZE		(1024 * 10)
+
+#define PERIOD_PLAY   64
+static uint8_t i2s_tx_buffer[PERIOD_PLAY];
+
+static wm_dma_handler_type dma_tx;
+static Buffer_Struct dma_tx_buf;
+
+#define CODEC_RUNING      (1 << 0)
+volatile uint8_t run_status = 0;
+
+static int I2s_tx_send(){
+	uint16_t send_bytes;
+	if (PERIOD_PLAY>dma_tx_buf.Pos){
+		send_bytes = dma_tx_buf.Pos;
+	}else{
+		send_bytes = PERIOD_PLAY;
+	}
+	memcpy(i2s_tx_buffer, dma_tx_buf.Data, send_bytes);
+	OS_BufferRemove(&dma_tx_buf, send_bytes);
+    if(send_bytes == 0)
+		return -1;
+	DMA_SRCADDR_REG(dma_tx.channel) = (uint32_t )i2s_tx_buffer;
+	DMA_CTRL_REG(dma_tx.channel) &= ~0xFFFF00;
+	DMA_CTRL_REG(dma_tx.channel) |= (send_bytes<<8);
+	DMA_CHNLCTRL_REG(dma_tx.channel) = DMA_CHNL_CTRL_CHNL_ON;
+	wm_i2s_tx_dma_enable(1);
+	wm_i2s_tx_enable(1);
+	wm_i2s_enable(1);
+    return 0;
+}
+
+static void I2s_dma_tx_irq(void *p){
+	int ret_len = dma_tx_buf.Pos;
+	if(ret_len >= 4 ){
+		I2s_tx_send();
+	}else{
+		run_status &= ~CODEC_RUNING;  
+	}
+}
+
+static int I2s_tx_dma_init(void){
+	if (dma_tx_buf.Data){
+		return 0;
+	}
+    OS_InitBuffer(&dma_tx_buf, AUDIO_BUF_SIZE);
+	memset(&dma_tx, 0, sizeof(wm_dma_handler_type));
+	if(dma_tx.channel){
+		tls_dma_free(dma_tx.channel);
+	}
+	dma_tx.channel = tls_dma_request(WM_I2S_TX_DMA_CHANNEL, TLS_DMA_FLAGS_CHANNEL_SEL(TLS_DMA_SEL_I2S_TX) | TLS_DMA_FLAGS_HARD_MODE);
+	if(dma_tx.channel == 0){
+		return -1;
+	}
+	if (tls_dma_stop(dma_tx.channel)){
+		return -1;
+	}
+	tls_dma_irq_register(dma_tx.channel, I2s_dma_tx_irq, &dma_tx, TLS_DMA_IRQ_TRANSFER_DONE);
+    DMA_INTMASK_REG &= ~(0x02<<(dma_tx.channel*2));
+	DMA_DESTADDR_REG(dma_tx.channel) = HR_I2S_TX;
+	DMA_CTRL_REG(dma_tx.channel) = DMA_CTRL_SRC_ADDR_INC | DMA_CTRL_DATA_SIZE_WORD | DMA_CTRL_BURST_SIZE1;
+	DMA_MODE_REG(dma_tx.channel) = DMA_MODE_SEL_I2S_TX | DMA_MODE_HARD_MODE;
+	DMA_CTRL_REG(dma_tx.channel) &= ~0xFFFF00;
+	return 0;
+}
+
+static int tls_i2s_io_init(void){
     wm_i2s_ck_config(WM_IO_PB_08);
     wm_i2s_ws_config(WM_IO_PB_09);
     wm_i2s_di_config(WM_IO_PB_10);
     wm_i2s_do_config(WM_IO_PB_11);
-    LLOGD("ck--PB08, ws--PB09, di--PB10, do--PB11");
+    wm_i2s_extclk_config(WM_IO_PA_07);
+    LLOGD("ck--PB08, ws--PB09, di--PB10, do--PB11, mclk--PA07");
     return WM_SUCCESS;
 }
 
 int luat_i2s_setup(luat_i2s_conf_t *conf) {
-    // 首先, 配置io复用
+    if (I2s_tx_dma_init()){
+        return -1;
+    }
+    
     tls_i2s_io_init();
-
     // 然后转本地i2s配置
     I2S_InitDef opts = { I2S_MODE_MASTER, I2S_CTRL_STEREO, I2S_RIGHT_CHANNEL, I2S_Standard, I2S_DataFormat_16, 8000, 5000000 };
 
-    int mode = I2S_MODE_MASTER; // 当前强制master
-    int stereo = 0;
-    int format = 0; // i2s
-    int datawidth = 16;
-    int freq = 44100;
+    uint8_t stereo = 1;
 
-    opts.I2S_Mode_MS = mode;
+    opts.I2S_Mode_MS = I2S_MODE_MASTER;
     opts.I2S_Mode_SS = (stereo<<22);
-    opts.I2S_Mode_LR = I2S_LEFT_CHANNEL;
-    opts.I2S_Trans_STD = (format*0x1000000);
-    opts.I2S_DataFormat = (datawidth/8 - 1)*0x10;
-    opts.I2S_AudioFreq = freq;
-    opts.I2S_MclkFreq = 80000000;
-
+    opts.I2S_Mode_LR = conf->channel_format==0?I2S_LEFT_CHANNEL : I2S_RIGHT_CHANNEL;
+    opts.I2S_Trans_STD = (conf->communication_format*0x1000000);
+    opts.I2S_DataFormat = (conf->bits_per_sample/8 - 1)*0x10;
+    opts.I2S_AudioFreq = conf->sample_rate;
+    opts.I2S_MclkFreq = conf->mclk;
     wm_i2s_port_init(&opts);
-    wm_i2s_register_callback(NULL);
-
+    // wm_i2s_register_callback(NULL);
+    run_status = 0;
     return 0;
 }
 
 int luat_i2s_send(uint8_t id, char* buff, size_t len) {
-    wm_i2s_tx_int((int16_t *)buff, len / 2, NULL);
+	int ret;
+    if (buff == NULL) {
+        return -1;
+    }
+	if (len == 0) {
+        return 0;
+    }
+	OS_BufferWrite(&dma_tx_buf, buff, len);
+	if ((run_status & CODEC_RUNING) == 0) {
+		run_status |= CODEC_RUNING;
+	    ret = I2s_tx_send();
+		if(ret == -1){
+		    printf("fifo empty for send\n");
+			run_status &= ~CODEC_RUNING; 
+		}
+	}
     return len;
 }
 
@@ -55,7 +135,24 @@ int luat_i2s_recv(uint8_t id, char* buff, size_t len) {
     return len;
 }
 
+int luat_i2s_resume(uint8_t id) {
+    wm_i2s_tx_enable(1);
+    return 0;
+}
+
+int luat_i2s_stop(uint8_t id) {
+    wm_i2s_tx_enable(0);
+    run_status = 0;	
+    return 0;
+}
+
 int luat_i2s_close(uint8_t id) {
-    wm_i2s_tx_rx_stop();
+    luat_i2s_stop(id);
+	if(dma_tx.channel){
+		tls_dma_free(dma_tx.channel);
+	}
+	if (dma_tx_buf.Data){
+		OS_DeInitBuffer(&dma_tx_buf);
+	}
     return 0;
 }

+ 5 - 0
include/driver/wm_i2s.h

@@ -151,6 +151,11 @@ typedef struct wm_i2s_buf_s {
  * @{
  */
 
+void wm_i2s_enable(bool bl);
+void wm_i2s_tx_dma_enable(bool bl);
+void wm_i2s_tx_enable(bool bl);
+void wm_i2s_rx_enable(bool bl);
+
 /**
   * @brief Register a callback function
   * @param  callback pointer to a callback function in which you can prepare the next buffer

+ 2 - 2
platform/drivers/i2s/wm_i2s.c

@@ -57,7 +57,7 @@ static void wm_i2s_rx_dma_enable(bool bl)
 	tls_bitband_write(HR_I2S_CTRL, 21, bl);
 }
 
-static void wm_i2s_tx_dma_enable(bool bl)
+void wm_i2s_tx_dma_enable(bool bl)
 {
 	tls_bitband_write(HR_I2S_CTRL, 20, bl);
 }
@@ -148,7 +148,7 @@ void wm_i2s_tx_enable(bool bl)
 	tls_bitband_write(HR_I2S_CTRL, 1, bl);
 }
 
-static void wm_i2s_enable(bool bl)
+void wm_i2s_enable(bool bl)
 {
 	tls_bitband_write(HR_I2S_CTRL, 0, bl);
 }

+ 31 - 3
xmake.lua

@@ -275,6 +275,35 @@ target("eink")
     set_targetdir("$(buildir)/lib")
 target_end()
 
+target("audio")
+    set_kind("static")
+    set_plat("cross")
+    set_arch("c-sky")
+
+    add_includedirs("app/port")
+    add_includedirs("include")
+    add_includedirs(luatos.."lua/include")
+    add_includedirs(luatos.."luat/include")
+    add_includedirs(luatos.."components/common",{public = true})
+    
+    add_includedirs(luatos.."components/multimedia/")
+    add_includedirs(luatos.."components/multimedia/mp3_decode")
+    add_includedirs(luatos.."components/multimedia/amr_decode/amr_common/dec/include")
+    add_includedirs(luatos.."components/multimedia/amr_decode/amr_nb/common/include")
+    add_includedirs(luatos.."components/multimedia/amr_decode/amr_nb/dec/include")
+    add_includedirs(luatos.."components/multimedia/amr_decode/amr_wb/dec/include")
+    add_includedirs(luatos.."components/multimedia/amr_decode/opencore-amrnb")
+    add_includedirs(luatos.."components/multimedia/amr_decode/opencore-amrwb")
+    add_includedirs(luatos.."components/multimedia/amr_decode/oscl")
+    add_includedirs(luatos.."components/multimedia/amr_decode/amr_nb/enc/src")
+    add_files(luatos.."components/multimedia/**.c")
+
+    add_includedirs("app/audio_driver",{public = true})
+    add_files("app/audio_driver/*.c")
+
+    set_targetdir("$(buildir)/lib")
+target_end()
+
 target("network")
     set_kind("static")
     set_plat("cross")
@@ -409,7 +438,7 @@ target("air10x")
         end
 
         target:set("filename", TARGET_NAME..".elf")
-        target:add("ldflags", flto .. "-Wl,--gc-sections -Wl,-zmax-page-size=1024 -Wl,--whole-archive ./lib/libwmarch.a ./lib/libgt.a ./lib/libwlan.a ./lib/libdsp.a ./lib/libbtcontroller.a -Wl,--no-whole-archive -mcpu=ck804ef -nostartfiles -mhard-float -lm -Wl,-T./ld/air101_103.ld -Wl,-ckmap=./build/out/"..TARGET_NAME..".map ",{force = true})
+        target:add("ldflags", flto .. "-Wl,--gc-sections -Wl,-zmax-page-size=1024 -Wl,--whole-archive ./lib/libwmarch.a ./lib/libgt.a ./lib/libwlan.a ./lib/libdsp.a ./lib/libbtcontroller.a ./lib/libaispeech_cntts.a ./lib/libghost.a -Wl,--no-whole-archive -mcpu=ck804ef -nostartfiles -mhard-float -lm -Wl,-T./ld/air101_103.ld -Wl,-ckmap=./build/out/"..TARGET_NAME..".map ",{force = true})
     end)
 
     add_deps("app")
@@ -420,7 +449,7 @@ target("air10x")
     add_deps("network")
     -- add_deps("opus131")
     add_deps("nes")
-    
+    add_deps("audio")
     -- add files
     add_files("app/*.c")
     add_files("app/port/*.c")
@@ -589,7 +618,6 @@ target("air10x")
     -- profiler
     add_files(luatos.."components/repl/**.c")
     add_includedirs(luatos.."components/repl/")
-
     
     -- local opus_dir = luatos .. "components/opus/"
     -- add_includedirs(opus_dir .. "opus-1.3.1/src",