void aic23b_dac_start(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t arg), uint32_t callback_opt, uint32_t pba_hz) { #if AIC23B_CTRL_INTERFACE == AIC23B_CTRL_INTERFACE_SPI static const spi_options_t AIC23B_SPI_OPTIONS = { .reg = AIC23B_SPI_NPCS, .baudrate = AIC23B_SPI_MASTER_SPEED, .bits = AIC23B_CTRL_SIZE, .spck_delay = 0, .trans_delay = 0, .stay_act = 0, .spi_mode = 3, .modfdis = 1 }; spi_setupChipReg(AIC23B_SPI, &AIC23B_SPI_OPTIONS, pba_hz); #endif aic23b_dac_stop(); gpio_enable_module(AIC23B_SSC_DAC_GPIO_MAP, sizeof(AIC23B_SSC_DAC_GPIO_MAP) / sizeof(AIC23B_SSC_DAC_GPIO_MAP[0])); aic23b_pdc_t pdc; pdc.data = AIC23B_DEFAULT(AIC23B_PDC); pdc.off = 0; pdc.clk = 0; pdc.osc = 0; pdc.out = 0; pdc.dac = 0; pdc.adc = 1; pdc.mic = 1; pdc.line = 1; aic23b_set_power_down_state(pdc); aic23b_dac_setup(sample_rate_hz, num_channels, bits_per_sample, swap_channels, callback, callback_opt, pba_hz); aic23b_aapc_t aapc; aapc.data = AIC23B_DEFAULT(AIC23B_AAPC); aapc.ste = 0; aapc.dac = 1; aapc.byp = 0; aapc.micm = 1; aapc.micb = 0; aic23b_set_analog_audio_path(aapc); aic23b_dapc_t dapc; dapc.data = AIC23B_DEFAULT(AIC23B_DAPC); dapc.dacm = 0; dapc.deemp = AIC23B_DAPC_DEEMP_NONE; dapc.adchp = 1; aic23b_set_digital_audio_path(dapc); // set an acceptable start volume aic23b_set_headphone_volume(AIC23B_LEFT_CHANNEL | AIC23B_RIGHT_CHANNEL, -30, true); aic23b_activate_dig_audio(true); INTC_register_interrupt(&aic23b_ssc_tx_pdca_int_handler, AIC23B_SSC_TX_PDCA_IRQ, AIC23B_SSC_TX_PDCA_INT_LEVEL); } void aic23b_dac_setup(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t arg), uint32_t callback_opt, uint32_t pba_hz) { #if defined(AIC23B_DAC_USE_RX_CLOCK) && AIC23B_DAC_USE_RX_CLOCK == true #if defined(AIC23B_DAC_RX_CLOCK_SET_CALLBACK) AIC23B_DAC_RX_CLOCK_SET_CALLBACK(2 * sample_rate_hz * ((bits_per_sample <= 16) ? 16 : (bits_per_sample <= 20) ? 20 : (bits_per_sample <= 24) ? 24 : 32)); #endif ssc_i2s_init(AIC23B_SSC, sample_rate_hz, bits_per_sample, (bits_per_sample <= 16) ? 16 : (bits_per_sample <= 20) ? 20 : (bits_per_sample <= 24) ? 24 : 32, SSC_I2S_MODE_STEREO_OUT_EXT_CLK, pba_hz); #else ssc_i2s_init(AIC23B_SSC, sample_rate_hz, bits_per_sample, (bits_per_sample <= 16) ? 16 : (bits_per_sample <= 20) ? 20 : (bits_per_sample <= 24) ? 24 : 32, SSC_I2S_MODE_STEREO_OUT, pba_hz); #endif pdca_channel_options_t aic23b_ssc_pdca_options = { .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .pid = AIC23B_SSC_TX_PDCA_PID, .transfer_size = (bits_per_sample <= 8) ? PDCA_TRANSFER_SIZE_BYTE : (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD : PDCA_TRANSFER_SIZE_WORD }; pdca_init_channel(AIC23B_SSC_TX_PDCA_CHANNEL, &aic23b_ssc_pdca_options); pdca_enable(AIC23B_SSC_TX_PDCA_CHANNEL); #if !defined(AIC23B_DAC_USE_RX_CLOCK) || AIC23B_DAC_USE_RX_CLOCK == false || \ !defined(AIC23B_DAC_RX_CLOCK_SET_CALLBACK) // Set DAC frequency aic23b_configure_freq(AIC23B_MCLK_HZ, sample_rate_hz); #endif aic23b_daif_t daif; daif.data = AIC23B_DEFAULT(AIC23B_DAIF); daif.ms = AIC23B_DAIF_MS_SLAVE; daif.lrswap = swap_channels; daif.lrp = 0; daif.iwl = (bits_per_sample <= 16) ? AIC23B_DAIF_IWL_16 : (bits_per_sample <= 20) ? AIC23B_DAIF_IWL_20 : (bits_per_sample <= 24) ? AIC23B_DAIF_IWL_24 : AIC23B_DAIF_IWL_32; daif.fmt = AIC23B_DAIF_FMT_I2S; aic23b_write_reg(AIC23B_DAIF, daif.data); aic23b_output_params.num_channels = num_channels; aic23b_output_params.callback = callback; aic23b_output_params.callback_opt = callback_opt; } #endif bool aic23b_dac_output(void *sample_buffer, size_t sample_length) { bool global_interrupt_enabled; if (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)) return false; if (sample_length) { if (aic23b_output_params.num_channels == 1) { int16_t *s16_sample_buffer = sample_buffer; int i; for (i = sample_length - 1; i >= 0; i--) { s16_sample_buffer[2 * i + 1] = s16_sample_buffer[2 * i] = s16_sample_buffer[i]; } } // The PDCA is not able to synchronize its start of transfer with the SSC // start of period, so this has to be done by polling the TF pin. // Not doing so may result in channels being swapped randomly. if ((global_interrupt_enabled = Is_global_interrupt_enabled())) Disable_global_interrupt(); if (pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE) { while (gpio_get_pin_value(AIC23B_SSC_TX_FRAME_SYNC_PIN)); while (!gpio_get_pin_value(AIC23B_SSC_TX_FRAME_SYNC_PIN)); } pdca_reload_channel(AIC23B_SSC_TX_PDCA_CHANNEL, sample_buffer, sample_length * 2); pdca_get_reload_size(AIC23B_SSC_TX_PDCA_CHANNEL); if (global_interrupt_enabled) Enable_global_interrupt(); if (aic23b_output_params.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB) pdca_enable_interrupt_transfer_complete(AIC23B_SSC_TX_PDCA_CHANNEL); if (aic23b_output_params.callback_opt & AUDIO_DAC_RELOAD_CB) pdca_enable_interrupt_reload_counter_zero(AIC23B_SSC_TX_PDCA_CHANNEL); } return true; }
void aic23b_adc_start(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t arg), uint32_t callback_opt, uint32_t pba_hz) { #if AIC23B_CTRL_INTERFACE == AIC23B_CTRL_INTERFACE_SPI static const spi_options_t AIC23B_SPI_OPTIONS = { .reg = AIC23B_SPI_NPCS, .baudrate = AIC23B_SPI_MASTER_SPEED, .bits = AIC23B_CTRL_SIZE, .spck_delay = 0, .trans_delay = 0, .stay_act = 0, .spi_mode = 3, .modfdis = 1 }; spi_setupChipReg(AIC23B_SPI, &AIC23B_SPI_OPTIONS, pba_hz); #endif aic23b_adc_stop(); gpio_enable_module(AIC23B_SSC_ADC_GPIO_MAP, sizeof(AIC23B_SSC_ADC_GPIO_MAP) / sizeof(AIC23B_SSC_ADC_GPIO_MAP[0])); aic23b_pdc_t pdc; pdc.data = AIC23B_DEFAULT(AIC23B_PDC); pdc.off = 0; pdc.clk = 0; pdc.osc = 0; pdc.out = 0; pdc.dac = 1; pdc.adc = 0; #if (AIC23B_INPUT==AIC23B_INPUT_LINE) pdc.mic = 1; pdc.line = 0; #elif (AIC23B_INPUT==AIC23B_INPUT_MIC) pdc.mic = 0; pdc.line = 1; #else #error No Input defined in file 'conf_tlv320aic23b.h' #endif aic23b_set_power_down_state(pdc); aic23b_adc_setup(sample_rate_hz, num_channels, bits_per_sample, swap_channels, callback, callback_opt, pba_hz); aic23b_aapc_t aapc; aapc.data = AIC23B_DEFAULT(AIC23B_AAPC); #if (AIC23B_INPUT==AIC23B_INPUT_LINE) aapc.ste = 0; aapc.dac = 0; aapc.byp = 0; aapc.insel = 0; aapc.micm = 0; aapc.micb = 0; #elif (AIC23B_INPUT==AIC23B_INPUT_MIC) aapc.ste = 0; aapc.dac = 0; aapc.byp = 0; aapc.insel = 1; aapc.micm = 0; aapc.micb = 0; #else #error No Input defined in file 'conf_tlv320aic23b.h' #endif aic23b_set_analog_audio_path(aapc); aic23b_dapc_t dapc; dapc.data = AIC23B_DEFAULT(AIC23B_DAPC); dapc.dacm = 0; dapc.deemp = AIC23B_DAPC_DEEMP_NONE; dapc.adchp = 0; aic23b_set_digital_audio_path(dapc); aic23b_llicvc_t llivc; llivc.data = AIC23B_DEFAULT(AIC23B_LLICVC); llivc.liv = 20; llivc.lim = 0; llivc.lrs = 1; aic23b_write_reg(AIC23B_LLICVC, llivc.data); aic23b_rlicvc_t rlivc; rlivc.data = AIC23B_DEFAULT(AIC23B_RLICVC); rlivc.riv = 20; rlivc.rim = 0; rlivc.rls = 1; aic23b_write_reg(AIC23B_RLICVC, rlivc.data); INTC_register_interrupt(&aic23b_ssc_rx_pdca_int_handler, AIC23B_SSC_RX_PDCA_IRQ, AIC23B_SSC_RX_PDCA_INT_LEVEL); aic23b_activate_dig_audio(true); } void aic23b_adc_setup(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t arg), callback_opt, uint32_t pba_hz) { ssc_i2s_init(AIC23B_SSC, sample_rate_hz, bits_per_sample, (bits_per_sample <= 16) ? 16 : (bits_per_sample <= 20) ? 20 : (bits_per_sample <= 24) ? 24 : 32, SSC_I2S_MODE_STEREO_IN, pba_hz); pdca_channel_options_t aic23b_ssc_pdca_options = { .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .pid = AIC23B_SSC_RX_PDCA_PID, .transfer_size = (bits_per_sample <= 8) ? PDCA_TRANSFER_SIZE_BYTE : (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD : PDCA_TRANSFER_SIZE_WORD }; pdca_init_channel(AIC23B_SSC_RX_PDCA_CHANNEL, &aic23b_ssc_pdca_options); pdca_enable(AIC23B_SSC_RX_PDCA_CHANNEL); // Set ADC frequency aic23b_configure_freq(AIC23B_MCLK_HZ, sample_rate_hz); aic23b_daif_t daif; daif.data = AIC23B_DEFAULT(AIC23B_DAIF); daif.ms = AIC23B_DAIF_MS_SLAVE; daif.lrswap = swap_channels; daif.lrp = 0; daif.iwl = (bits_per_sample <= 16) ? AIC23B_DAIF_IWL_16 : (bits_per_sample <= 20) ? AIC23B_DAIF_IWL_20 : (bits_per_sample <= 24) ? AIC23B_DAIF_IWL_24 : AIC23B_DAIF_IWL_32; daif.fmt = AIC23B_DAIF_FMT_I2S; aic23b_write_reg(AIC23B_DAIF, daif.data); aic23b_output_params.num_channels = num_channels; aic23b_output_params.callback = callback; aic23b_output_params.callback_opt = callback_opt; } void aic23b_adc_flush(void) { pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); }
void aic23b_codec_start(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t arg), uint32_t callback_opt, uint32_t pba_hz) { #if AIC23B_CTRL_INTERFACE == AIC23B_CTRL_INTERFACE_SPI static const spi_options_t AIC23B_SPI_OPTIONS = { .reg = AIC23B_SPI_NPCS, .baudrate = AIC23B_SPI_MASTER_SPEED, .bits = AIC23B_CTRL_SIZE, .spck_delay = 0, .trans_delay = 0, .stay_act = 0, .spi_mode = 3, .modfdis = 1 }; spi_setupChipReg(AIC23B_SPI, &AIC23B_SPI_OPTIONS, pba_hz); #endif aic23b_codec_stop(); gpio_enable_module(AIC23B_SSC_CODEC_GPIO_MAP, sizeof(AIC23B_SSC_CODEC_GPIO_MAP) / sizeof(AIC23B_SSC_CODEC_GPIO_MAP[0])); aic23b_pdc_t pdc; pdc.data = AIC23B_DEFAULT(AIC23B_PDC); pdc.off = 0; pdc.clk = 0; pdc.osc = 0; pdc.out = 0; pdc.dac = 0; pdc.adc = 0; #if (AIC23B_INPUT==AIC23B_INPUT_LINE) pdc.mic = 1; pdc.line = 0; #elif (AIC23B_INPUT==AIC23B_INPUT_MIC) pdc.mic = 0; pdc.line = 1; #else #error No Input defined in file 'conf_tlv320aic23b.h' #endif aic23b_set_power_down_state(pdc); aic23b_codec_setup(sample_rate_hz, num_channels, bits_per_sample, swap_channels, callback, callback_opt, pba_hz); aic23b_aapc_t aapc; aapc.data = AIC23B_DEFAULT(AIC23B_AAPC); #if (AIC23B_INPUT==AIC23B_INPUT_LINE) aapc.ste = 0; aapc.dac = 1; aapc.byp = 0; aapc.insel = 0; aapc.micm = 0; aapc.micb = 1; #elif (AIC23B_INPUT==AIC23B_INPUT_MIC) aapc.ste = 0; aapc.dac = 1; aapc.sta = 4; aapc.byp = 0; aapc.insel = 1; aapc.micm = 0; aapc.micb = 1; #else #error No Input defined in file 'conf_tlv320aic23b.h' #endif aic23b_set_analog_audio_path(aapc); aic23b_dapc_t dapc; dapc.data = AIC23B_DEFAULT(AIC23B_DAPC); dapc.dacm = 0; dapc.deemp = AIC23B_DAPC_DEEMP_NONE; dapc.adchp = 0; aic23b_set_digital_audio_path(dapc); aic23b_llicvc_t llivc; llivc.data = AIC23B_DEFAULT(AIC23B_LLICVC); llivc.liv = 20; llivc.lim = 0; llivc.lrs = 1; aic23b_write_reg(AIC23B_LLICVC, llivc.data); aic23b_rlicvc_t rlivc; rlivc.data = AIC23B_DEFAULT(AIC23B_RLICVC); rlivc.riv = 20; rlivc.rim = 0; rlivc.rls = 1; aic23b_write_reg(AIC23B_RLICVC, rlivc.data); INTC_register_interrupt(&aic23b_ssc_rx_pdca_int_handler, AIC23B_SSC_RX_PDCA_IRQ, AIC23B_SSC_RX_PDCA_INT_LEVEL); // set an acceptable start volume aic23b_set_headphone_volume(AIC23B_LEFT_CHANNEL | AIC23B_RIGHT_CHANNEL, -30, true); aic23b_activate_dig_audio(true); INTC_register_interrupt(&aic23b_ssc_tx_pdca_int_handler, AIC23B_SSC_TX_PDCA_IRQ, AIC23B_SSC_TX_PDCA_INT_LEVEL); } void aic23b_codec_setup(uint32_t sample_rate_hz, uint8_t num_channels, uint8_t bits_per_sample, bool swap_channels, void (*callback)(uint32_t opt), uint32_t callback_opt, uint32_t pba_hz) { uint32_t master_clock = AIC23B_MCLK_HZ; // default configuration // Change the CPU frequency // //Disable_global_interrupt(); // Switch to OSC0 during OSC1 transition //pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP); // Switch to PLL0 as the master clock //pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0); if (sample_rate_hz < (8000 + 8021) / 2) { // 8000 Hz } else if (sample_rate_hz < (8021 + 32000) / 2) { // 8021 Hz } else if (sample_rate_hz < (32000 + 44100) / 2) { // 32000 Hz master_clock = usb_stream_resync_frequency = 8192000; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0)); pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(8192000); } else if (sample_rate_hz < (44100 + 48000) / 2) { // 44100 Hz master_clock = usb_stream_resync_frequency = 11289600; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0)); pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(11289600); } else if (sample_rate_hz < (48000 + 88200) / 2) { // 48000 Hz master_clock = usb_stream_resync_frequency = 12288000; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, FOSC0)); pba_hz = FCPU_HZ = FHSB_HZ = FPBA_HZ = FPBB_HZ = FMCK_HZ(12288000); } else if (sample_rate_hz < (88200 + 96000) / 2) { // 88200 Hz } else { // 96000 Hz } //Enable_global_interrupt(); ssc_i2s_init(AIC23B_SSC, sample_rate_hz, bits_per_sample, (bits_per_sample <= 16) ? 16 : (bits_per_sample <= 20) ? 20 : (bits_per_sample <= 24) ? 24 : 32, SSC_I2S_MODE_STEREO_OUT_STEREO_IN, pba_hz); pdca_channel_options_t aic23b_ssc_pdca_options_rx = { .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .pid = AIC23B_SSC_RX_PDCA_PID, .transfer_size = (bits_per_sample <= 8) ? PDCA_TRANSFER_SIZE_BYTE : (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD : PDCA_TRANSFER_SIZE_WORD }; pdca_init_channel(AIC23B_SSC_RX_PDCA_CHANNEL, &aic23b_ssc_pdca_options_rx); pdca_enable(AIC23B_SSC_RX_PDCA_CHANNEL); pdca_channel_options_t aic23b_ssc_pdca_options_tx = { .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .pid = AIC23B_SSC_TX_PDCA_PID, .transfer_size = (bits_per_sample <= 8) ? PDCA_TRANSFER_SIZE_BYTE : (bits_per_sample <= 16) ? PDCA_TRANSFER_SIZE_HALF_WORD : PDCA_TRANSFER_SIZE_WORD }; pdca_init_channel(AIC23B_SSC_TX_PDCA_CHANNEL, &aic23b_ssc_pdca_options_tx); pdca_enable(AIC23B_SSC_TX_PDCA_CHANNEL); // Set codec frequency aic23b_configure_freq(master_clock, sample_rate_hz); aic23b_daif_t daif; daif.data = AIC23B_DEFAULT(AIC23B_DAIF); daif.ms = AIC23B_DAIF_MS_SLAVE; daif.lrswap = swap_channels; daif.lrp = 0; daif.iwl = (bits_per_sample <= 16) ? AIC23B_DAIF_IWL_16 : (bits_per_sample <= 20) ? AIC23B_DAIF_IWL_20 : (bits_per_sample <= 24) ? AIC23B_DAIF_IWL_24 : AIC23B_DAIF_IWL_32; daif.fmt = AIC23B_DAIF_FMT_I2S; aic23b_write_reg(AIC23B_DAIF, daif.data); aic23b_output_params.num_channels = num_channels; aic23b_output_params.callback = callback; aic23b_output_params.callback_opt = callback_opt; } void aic23b_codec_flush(void) { pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); pdca_disable_interrupt_transfer_complete(AIC23B_SSC_TX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); } void aic23b_codec_stop(void) { aic23b_codec_flush(); aic23b_reset(); aic23b_pdc_t pdc; pdc.data = AIC23B_DEFAULT(AIC23B_PDC); pdc.off = 1; pdc.clk = 1; pdc.osc = 1; pdc.out = 1; pdc.dac = 1; pdc.adc = 1; pdc.mic = 1; pdc.line = 1; aic23b_set_power_down_state(pdc); pdca_disable(AIC23B_SSC_RX_PDCA_CHANNEL); pdca_disable(AIC23B_SSC_TX_PDCA_CHANNEL); ssc_i2s_reset(AIC23B_SSC); gpio_enable_gpio(AIC23B_SSC_CODEC_GPIO_MAP, sizeof(AIC23B_SSC_CODEC_GPIO_MAP) / sizeof(AIC23B_SSC_CODEC_GPIO_MAP[0])); aic23b_output_params.num_channels = 0; aic23b_output_params.callback = NULL; aic23b_output_params.callback_opt = 0; }