/** * \brief Test ABDAC initialization APIs. * * \param test Current test case. */ static void run_abdac_init_test(const struct test_case *test) { status_code_t status; /* Config the ABDAC. */ abdac_get_config_defaults(&g_abdac_cfg); status = abdac_init(&g_abdac_inst, ABDACB, &g_abdac_cfg); abdac_enable(&g_abdac_inst); abdac_clear_interrupt_flag(&g_abdac_inst, ABDAC_INTERRUPT_TXRDY); abdac_clear_interrupt_flag(&g_abdac_inst, ABDAC_INTERRUPT_TXUR); test_assert_true(test, status == STATUS_OK, "Initialization fails!"); }
/** * \brief Application entry point for ABDAC example. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint8_t key; uint32_t i, count; status_code_t status; /* Initialize the SAM system. */ sysclk_init(); board_init(); /* Initialize the UART console. */ configure_console(); /* Output example information */ printf("-- ABDAC Example --\r\n"); printf("-- %s\r\n", BOARD_NAME); printf("-- Compiled: %s %s --\r\n", __DATE__, __TIME__); /* Config the push button. */ config_buttons(); /* Config the ABDAC. */ abdac_get_config_defaults(&g_abdac_cfg); g_abdac_cfg.sample_rate_hz = ABDAC_SAMPLE_RATE_11025; g_abdac_cfg.data_word_format = ABDAC_DATE_16BIT; g_abdac_cfg.mono = false; g_abdac_cfg.cmoc = false; status = abdac_init(&g_abdac_inst, ABDACB, &g_abdac_cfg); if (status != STATUS_OK) { printf("-- Initialization fails! --\r\n"); while (1) { } } abdac_enable(&g_abdac_inst); abdac_clear_interrupt_flag(&g_abdac_inst, ABDAC_INTERRUPT_TXRDY); abdac_clear_interrupt_flag(&g_abdac_inst, ABDAC_INTERRUPT_TXUR); /* Config PDCA module */ pdca_enable(PDCA); pdca_channel_set_config(PDCA_ABDAC_CHANNEL0, &pdca_abdac_config0); pdca_channel_enable(PDCA_ABDAC_CHANNEL0); pdca_channel_set_config(PDCA_ABDAC_CHANNEL1, &pdca_abdac_config1); pdca_channel_enable(PDCA_ABDAC_CHANNEL1); /* Display menu. */ display_menu(); while (1) { scanf("%c", (char *)&key); switch (key) { case 'h': display_menu(); break; case 's': printf("--Looped output audio, use push button to exit--\r\n"); abdac_set_volume0(&g_abdac_inst, false, 0x7FFF); abdac_set_volume1(&g_abdac_inst, false, 0x7FFF); i = 0; /* output sample from the sound_table array */ while(!exit_flag) { count = 0; // Store sample from the sound_table array while(count < (SOUND_SAMPLES)){ samples_left[count] = ((uint8_t)sound_table[i]) << 8; samples_right[count] = ((uint8_t)sound_table[i]) << 8; i++; count++; if (i >= sizeof(sound_table)) i = 0; } pdca_channel_write_reload(PDCA_ABDAC_CHANNEL0, (void *)samples_left, SOUND_SAMPLES); pdca_channel_write_reload(PDCA_ABDAC_CHANNEL1, (void *)samples_right, SOUND_SAMPLES); /** * Wait until the reload register is empty. This means that * one transmission is still ongoing but we are already able * to set up the next transmission. */ while(!(pdca_get_channel_status(PDCA_ABDAC_CHANNEL1) == PDCA_CH_COUNTER_RELOAD_IS_ZERO)); } exit_flag = false; printf("--Exit the audio output--\r\n\r\n"); /* Mute the volume */ abdac_set_volume0(&g_abdac_inst, true, 0x7FFF); abdac_set_volume1(&g_abdac_inst, true, 0x7FFF); break; default: break; } } }
/*! \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); } }