void ms3_dac_mute(bool mute) { if (mute) { U32 save_dac_reload_callback_opt; // Mute all channels // ms3_write_reg(MS3_MUTE_VOL_CTRL, 0xAF); // Disable the reload callback function save_dac_reload_callback_opt = ms3_output_params.callback_opt; ms3_output_params.callback_opt = 0; // Disable the transfer complete interruption and wait until the transfer is complete pdca_disable_interrupt_reload_counter_zero(MS3_SSC_TX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); // Re-enable the reload callback function ms3_output_params.callback_opt = save_dac_reload_callback_opt; // Set as gpio pin gpio_enable_gpio(MS3_GPIO_MAP, sizeof(MS3_GPIO_MAP) / sizeof(MS3_GPIO_MAP[0])); } else { // Re-enable the reload interrupt pdca_enable_interrupt_reload_counter_zero(MS3_SSC_TX_PDCA_CHANNEL); // Unmute all channels // ms3_write_reg(MS3_MUTE_VOL_CTRL, 0xA0); // Enable SSC interface gpio_enable_module(MS3_GPIO_MAP, sizeof(MS3_GPIO_MAP) / sizeof(MS3_GPIO_MAP[0])); } }
void aic23b_dac_mute(bool mute) { #if (AIC23B_MODE==AIC23B_MODE_DAC) /* if(mute==true) { pdca_disable(AIC23B_SSC_TX_PDCA_CHANNEL); } else { pdca_enable(AIC23B_SSC_TX_PDCA_CHANNEL); } */ if (mute) { uint32_t save_dac_reload_callback_opt; // Disable the reload callback function save_dac_reload_callback_opt = aic23b_output_params.callback_opt; aic23b_output_params.callback_opt = 0; // Disable the transfer complete interruption and wait until the transfer is complete pdca_disable_interrupt_reload_counter_zero(AIC23B_SSC_TX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); // Re-enable the reload callback function aic23b_output_params.callback_opt = save_dac_reload_callback_opt; } else { // Re-enable the reload interrupt pdca_enable_interrupt_reload_counter_zero(AIC23B_SSC_TX_PDCA_CHANNEL); } #endif }
uint32_t pdca_init_channel(uint8_t pdca_ch_number, const pdca_channel_options_t *opt) { /* get the correct channel pointer */ volatile avr32_pdca_channel_t *pdca_channel = pdca_get_handler( pdca_ch_number); pdca_disable_interrupt_transfer_complete(pdca_ch_number); pdca_disable_interrupt_reload_counter_zero(pdca_ch_number); irqflags_t flags = cpu_irq_save(); pdca_channel->mar = (uint32_t)opt->addr; pdca_channel->tcr = opt->size; pdca_channel->psr = opt->pid; pdca_channel->marr = (uint32_t)opt->r_addr; pdca_channel->tcrr = opt->r_size; pdca_channel->mr = #if (AVR32_PDCA_H_VERSION >= 120) opt->etrig << AVR32_PDCA_ETRIG_OFFSET | #endif opt->transfer_size << AVR32_PDCA_SIZE_OFFSET; pdca_channel->cr = AVR32_PDCA_ECLR_MASK; pdca_channel->isr; cpu_irq_restore(flags); return PDCA_SUCCESS; }
void aic23b_dac_flush(void) { pdca_disable_interrupt_transfer_complete(AIC23B_SSC_TX_PDCA_CHANNEL); pdca_disable_interrupt_reload_counter_zero(AIC23B_SSC_TX_PDCA_CHANNEL); while (!(pdca_get_transfer_status(AIC23B_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); }
/*! \brief Flushes the sample buffer being output to the ABDAC. */ void tpa6130_dac_flush(void) { pdca_disable_interrupt_transfer_complete(TPA6130_ABDAC_PDCA_CHANNEL); pdca_disable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL); /*TODO Do we really want to wait here? Or do we just don't care when * the buffer is empty/flushed */ //while(!pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & // PDCA_TRANSFER_COMPLETE); pdca_disable (TPA6130_ABDAC_PDCA_CHANNEL ); pdca_load_channel (TPA6130_ABDAC_PDCA_CHANNEL,0x0, 0); pdca_reload_channel(TPA6130_ABDAC_PDCA_CHANNEL,0x0, 0); pdca_enable (TPA6130_ABDAC_PDCA_CHANNEL ); }
ISR(tpa6130_abdac_tx_pdca_int_handler, TPA6130_ABDAC_PDCA_IRQ_GROUP, TPA6130_ABDAC_PDCA_INT_LEVEL) { if (pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE) { pdca_disable_interrupt_transfer_complete(TPA6130_ABDAC_PDCA_CHANNEL); if (tpa6130_output_param.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB) tpa6130_output_param.callback(AUDIO_DAC_OUT_OF_SAMPLE_CB); } if (pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO) { pdca_disable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL); if (tpa6130_output_param.callback_opt & AUDIO_DAC_RELOAD_CB) tpa6130_output_param.callback(AUDIO_DAC_RELOAD_CB); } }
__interrupt #endif static void aic23b_ssc_rx_pdca_int_handler(void) { if (pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE) { pdca_disable_interrupt_transfer_complete(AIC23B_SSC_RX_PDCA_CHANNEL); if (aic23b_output_params.callback_opt & AUDIO_ADC_OUT_OF_SAMPLE_CB) aic23b_output_params.callback(AUDIO_ADC_OUT_OF_SAMPLE_CB); } if (pdca_get_transfer_status(AIC23B_SSC_RX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO) { pdca_disable_interrupt_reload_counter_zero(AIC23B_SSC_RX_PDCA_CHANNEL); if (aic23b_output_params.callback_opt & AUDIO_ADC_RELOAD_CB) aic23b_output_params.callback(AUDIO_ADC_RELOAD_CB); } }
__interrupt #endif static void ms3_ssc_tx_pdca_int_handler(void) { if (pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE) { pdca_disable_interrupt_transfer_complete(MS3_SSC_TX_PDCA_CHANNEL); if (ms3_output_params.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB) ms3_output_params.callback(AUDIO_DAC_OUT_OF_SAMPLE_CB); } if (pdca_get_transfer_status(MS3_SSC_TX_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO) { pdca_disable_interrupt_reload_counter_zero(MS3_SSC_TX_PDCA_CHANNEL); if (ms3_output_params.callback_opt & AUDIO_DAC_RELOAD_CB) ms3_output_params.callback(AUDIO_DAC_RELOAD_CB); } }
//! //! @brief Entry point of the AK5394A task management //! void AK5394A_task(void *pvParameters) { portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); int i; while (TRUE) { // All the hardwork is done by the pdca and the interrupt handler. // Just check whether sampling freq is changed, to do rate change etc. vTaskDelayUntil(&xLastWakeTime, configTSK_AK5394A_PERIOD); if (freq_changed){ if (current_freq.frequency == 96000){ pdca_disable_interrupt_reload_counter_zero(PDCA_CHANNEL_SSC_RX); pdca_disable(PDCA_CHANNEL_SSC_RX); gpio_set_gpio_pin(AK5394_DFS0); // L H -> 96khz gpio_clr_gpio_pin(AK5394_DFS1); pm_gc_disable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_GCLK1, // gc 0, // osc_or_pll: use Osc (if 0) or PLL (if 1) 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1 1, // diven - enabled 0); // divided by 2. Therefore GCLK1 = 6.144Mhz pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); if (Is_usb_full_speed_mode()) FB_rate = 96 << 14; else FB_rate = (96) << 13; } else if (current_freq.frequency == 192000) { pdca_disable_interrupt_reload_counter_zero(PDCA_CHANNEL_SSC_RX); pdca_disable(PDCA_CHANNEL_SSC_RX); gpio_clr_gpio_pin(AK5394_DFS0); // H L -> 192khz gpio_set_gpio_pin(AK5394_DFS1); pm_gc_disable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_GCLK1, // gc 0, // osc_or_pll: use Osc (if 0) or PLL (if 1) 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1 0, // diven - disabled 0); // GCLK1 = 12.288Mhz pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); if (Is_usb_full_speed_mode()) FB_rate = 192 << 14; else FB_rate = (192) << 13; } else if (current_freq.frequency == 48000) // 48khz { pdca_disable_interrupt_reload_counter_zero(PDCA_CHANNEL_SSC_RX); pdca_disable(PDCA_CHANNEL_SSC_RX); gpio_clr_gpio_pin(AK5394_DFS0); // L L -> 48khz gpio_clr_gpio_pin(AK5394_DFS1); pm_gc_disable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_GCLK1, // gc 0, // osc_or_pll: use Osc (if 0) or PLL (if 1) 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1 1, // diven - enabled 1); // divided by 4. Therefore GCLK1 = 3.072Mhz pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_GCLK1); if (Is_usb_full_speed_mode()) FB_rate = 48 << 14; else FB_rate = (48) << 13; } // re-sync SSC to LRCK // Wait for the next frame synchronization event // to avoid channel inversion. Start with left channel - FS goes low // However, the channels are reversed at 192khz if (current_freq.frequency == 192000) { while (gpio_get_pin_value(AK5394_LRCK)); while (!gpio_get_pin_value(AK5394_LRCK)); // exit when FS goes high } else { while (!gpio_get_pin_value(AK5394_LRCK)); while (gpio_get_pin_value(AK5394_LRCK)); // exit when FS goes low } // Enable now the transfer. pdca_enable(PDCA_CHANNEL_SSC_RX); // Init PDCA channel with the pdca_options. pdca_init_channel(PDCA_CHANNEL_SSC_RX, &PDCA_OPTIONS); // init PDCA channel with options. pdca_enable_interrupt_reload_counter_zero(PDCA_CHANNEL_SSC_RX); // reset freq_changed flag freq_changed = FALSE; } if (usb_alternate_setting_out_changed){ if (usb_alternate_setting_out != 1){ for (i = 0; i < SPK_BUFFER_SIZE; i++){ spk_buffer_0[i] = 0; spk_buffer_1[i] = 0; } }; usb_alternate_setting_out_changed = FALSE; } } }
/*! \brief Sets the DACs up with new settings. * * \note The DACs must have been started beforehand. */ void tpa6130_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) { // save input parameters to local driver data tpa6130_output_param.num_channels = num_channels; tpa6130_output_param.callback = callback; tpa6130_output_param.callback_opt = callback_opt; /* Probe for amplifier and initialize it */ tpa6130_init(); #if defined(TPA6130_DAC_CLOCK_SET_CALLBACK) TPA6130_DAC_CLOCK_SET_CALLBACK(sample_rate_hz); #else /* ABDAC configuration * The ABDAC needs the input frequency of its generic clock (bus_hz) * Here we use the configuration value from the conf_tpa6130.h file * (TPA6130_ABDAC_GCLK_INPUT_HZ). * The sample rate specifies the desired sample rate for the ABDAC. * The generic clock input must be greater than 256*sample_rate_hz * or the setup of the ABDAC will fail silently here. * TODO we could add asserts here to detect wrong settings during * compile time. */ if(!abdac_set_dac_sample_rate(sample_rate_hz)) { // if it is not possible to set correctly the sample rate // Use default set function abdac_set_dac_hz(TPA6130_ABDAC, TPA6130_ABDAC_GCLK_INPUT_HZ,sample_rate_hz); } #endif if(swap_channels) { abdac_swap_channels(TPA6130_ABDAC); } abdac_enable(TPA6130_ABDAC); /* PDCA setup */ /*FIXME we use only word as transfer size for now. * half-word transfer size will only write to channel0 * of the ABDAC, this can be used to implement mono */ pdca_channel_options_t tpa6130_abdac_pdca_options = { .addr = NULL, .size = 0, .r_addr = 0, .r_size = 0, .pid = TPA6130_ABDAC_PDCA_PID, .transfer_size = PDCA_TRANSFER_SIZE_WORD }; /* Initialize the PCDA for the ABDAC * The channel number can be set in the configuration file * with the define TPA6130_ABDAC_PDCA_CHANNEL. */ pdca_init_channel(TPA6130_ABDAC_PDCA_CHANNEL, &tpa6130_abdac_pdca_options); /* Enable the PDCA channel. Since we did not provide any data * yet the channel is in idle mode */ pdca_enable(TPA6130_ABDAC_PDCA_CHANNEL); } /*! \brief Outputs a sample buffer to the DACs. * The input requires a sample buffer that consists of words (32-bit) * which contain two (16-bit) samples, one for each channel. * * \note The DACs must have been started beforehand. */ bool tpa6130_dac_output(void *sample_buffer, size_t sample_length) { //int global_interrupt_enabled; /*Wait until the PDCA loads the reload value to its transfer * counter register(TCRR=0). Then we are ready to set up a new * transfer */ if(!(pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COUNTER_RELOAD_IS_ZERO)) { return false; } /* Nothing to do if we get no data. */ if(sample_length) { /*TODO Do we really need to adjust the buffer for mono*/ /* While reloading the PDC we do not need any active interrupt*/ //if((global_interrupt_enabled = cpu_irq_is_enabled())) // cpu_irq_disable(); /*FIXME This assumes a stereo 16-bit sample size */ // one sample here consists of 2x16-bit (16-bit stereo) pdca_reload_channel(TPA6130_ABDAC_PDCA_CHANNEL, sample_buffer, sample_length); //if(global_interrupt_enabled) // cpu_irq_enable(); /*TODO enable transfer complete interrupt * Is it possible to move this to setup or other places?*/ if(tpa6130_output_param.callback_opt & AUDIO_DAC_OUT_OF_SAMPLE_CB) pdca_enable_interrupt_transfer_complete(TPA6130_ABDAC_PDCA_CHANNEL); if (tpa6130_output_param.callback_opt & AUDIO_DAC_RELOAD_CB) pdca_enable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL); } return true; } bool tpa6130_dac_is_volume_muted(void) { return false; } void tpa6130_dac_mute(bool mute) { // //1st Version Mute Audio for Play/Pause /* int volume=tpa6130_get_volume(); if(mute==true) { //Mute volume volume= volume|MUTE_L|MUTE_R; } else { //Unmute volume volume= volume&(~(MUTE_L|MUTE_R)); } tpa6130_write_data(TPA6130_VOLUME_AND_MUTE,volume); */ //2n Version Stop PDCA >> No lost of audio when pause /* if(mute==true) { pdca_disable(TPA6130_ABDAC_PDCA_CHANNEL); } else { pdca_enable(TPA6130_ABDAC_PDCA_CHANNEL); } */ // 3rd Version wait until the current buffers are empty and disable the interrupts int8_t volume = tpa6130_get_volume(); if (mute) { uint32_t save_dac_reload_callback_opt; // Mute the audio stream volume = volume | MUTE_L | MUTE_R; tpa6130_write_data(TPA6130_VOLUME_AND_MUTE, volume); // Disable the reload channel of the interrupt save_dac_reload_callback_opt = tpa6130_output_param.callback_opt; tpa6130_output_param.callback_opt = 0; // Disable the reload interruption and wait until the transfer is complete pdca_disable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL); while (!(pdca_get_transfer_status(TPA6130_ABDAC_PDCA_CHANNEL) & PDCA_TRANSFER_COMPLETE)); // Restore the reload callback function tpa6130_output_param.callback_opt = save_dac_reload_callback_opt; } else { // Re-enable the interrupts pdca_enable_interrupt_reload_counter_zero(TPA6130_ABDAC_PDCA_CHANNEL); // Un-mute the audio stream volume = volume & (~(MUTE_L | MUTE_R)); tpa6130_write_data(TPA6130_VOLUME_AND_MUTE, volume); } }