bool aic23b_adc_input(void *sample_buffer, size_t sample_length) { if (!(pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)) return false; if (sample_length) { pdca_reload_channel(AIC23B_SSC_RX_PDCA_CHANNEL, sample_buffer, sample_length * 2); pdca_get_reload_size(AIC23B_SSC_RX_PDCA_CHANNEL); if (aic23b_output_params.callback_opt & AUDIO_ADC_OUT_OF_SAMPLE_CB) pdca_enable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL); if (aic23b_output_params.callback_opt & AUDIO_ADC_RELOAD_CB) pdca_enable_interrupt_reload_counter_zero(AIC23B_SSC_RX_PDCA_CHANNEL); } return true; }
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 ms3_dac_setup(U32 sample_rate_hz, U8 num_channels, U8 bits_per_sample, bool swap_channels, void (*callback)(U32 arg), U32 callback_opt, U32 pba_hz) { //configure clock if (sample_rate_hz < (8000 + 8021) / 2) { usb_stream_resync_frequency = 4096000; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } else if (sample_rate_hz < (8021 + 22050) / 2) { usb_stream_resync_frequency = 4106752; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } else if (sample_rate_hz < (22050 + 32000) / 2) { usb_stream_resync_frequency = 11289600; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } else if (sample_rate_hz < (32000 + 44100) / 2) { usb_stream_resync_frequency = 16384000; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } else if (sample_rate_hz < (44100 + 48000) / 2) { usb_stream_resync_frequency = 22579200; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } else if (sample_rate_hz < (48000 + 88200) / 2) { usb_stream_resync_frequency = 24576000; cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); } //configure ssc to use clock on TX_CLOCK pin AVR32_SSC.tcmr = (0 << AVR32_SSC_TCMR_CKO_OFFSET) | (1 << AVR32_SSC_TCMR_STTDLY_OFFSET) | (2 << AVR32_SSC_TCMR_CKS_OFFSET) | (7 << AVR32_SSC_TCMR_START_OFFSET) | (0x1f << AVR32_SSC_TCMR_PERIOD_OFFSET); AVR32_SSC.tfmr = (0xf << AVR32_SSC_TFMR_DATLEN_OFFSET) | (1 << AVR32_SSC_TFMR_MSBF_OFFSET) | (1 << AVR32_SSC_TFMR_FSOS_OFFSET) | (1 << AVR32_SSC_TFMR_FSLENHI_OFFSET) | (0xf << AVR32_SSC_TFMR_FSLEN_OFFSET); AVR32_SSC.cr = AVR32_SSC_CR_TXEN_MASK; //configure DMA pdca_channel_options_t ms3_ssc_pdca_options = { .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .pid = AVR32_PDCA_PID_SSC_TX, .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(MS3_SSC_TX_PDCA_CHANNEL, &ms3_ssc_pdca_options); pdca_enable(MS3_SSC_TX_PDCA_CHANNEL); //configure audio parameters ms3_output_params.num_channels = num_channels; ms3_output_params.callback = callback; ms3_output_params.callback_opt = callback_opt; } bool ms3_dac_output(void *sample_buffer, size_t sample_length) { bool global_interrupt_enabled; if (!(pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)) return false; if (sample_length) { if (ms3_output_params.num_channels == 1) { S16 *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(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE) { while (gpio_get_pin_value(MS3_SSC_TX_FRAME_SYNC_PIN)); while (!gpio_get_pin_value(MS3_SSC_TX_FRAME_SYNC_PIN)); } pdca_reload_channel(MS3_SSC_TX_PDCA_CHANNEL, sample_buffer, sample_length * 2); pdca_get_reload_size(MS3_SSC_TX_PDCA_CHANNEL); if (global_interrupt_enabled) Enable_global_interrupt(); if (ms3_output_params.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB) pdca_enable_interrupt_transfer_complete(MS3_SSC_TX_PDCA_CHANNEL); if (ms3_output_params.callback_opt & AUDIO_DAC_RELOAD_CB) pdca_enable_interrupt_reload_counter_zero(MS3_SSC_TX_PDCA_CHANNEL); } return true; }