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)); }
//! //! @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 Initializes SD/MMC resources: GPIO, SPI and SD/MMC. */ static void sd_mmc_resources_init(void) { // GPIO pins used for SD/MMC interface static const gpio_map_t SD_MMC_SPI_GPIO_MAP = { {SD_MMC_SPI_SCK_PIN, SD_MMC_SPI_SCK_FUNCTION }, // SPI Clock. {SD_MMC_SPI_MISO_PIN, SD_MMC_SPI_MISO_FUNCTION}, // MISO. {SD_MMC_SPI_MOSI_PIN, SD_MMC_SPI_MOSI_FUNCTION}, // MOSI. {SD_MMC_SPI_NPCS_PIN, SD_MMC_SPI_NPCS_FUNCTION} // Chip Select NPCS. }; // SPI options. spi_options_t spiOptions = { .reg = SD_MMC_SPI_NPCS, .baudrate = SD_MMC_SPI_MASTER_SPEED, // Defined in conf_sd_mmc_spi.h. .bits = SD_MMC_SPI_BITS, // Defined in conf_sd_mmc_spi.h. .spck_delay = 0, .trans_delay = 0, .stay_act = 1, .spi_mode = 0, .modfdis = 1 }; // Assign I/Os to SPI. gpio_enable_module(SD_MMC_SPI_GPIO_MAP, sizeof(SD_MMC_SPI_GPIO_MAP) / sizeof(SD_MMC_SPI_GPIO_MAP[0])); // Initialize as master. spi_initMaster(SD_MMC_SPI, &spiOptions); // Set SPI selection mode: variable_ps, pcs_decode, delay. spi_selectionMode(SD_MMC_SPI, 0, 0, 0); // Enable SPI module. spi_enable(SD_MMC_SPI); // Initialize SD/MMC driver with SPI clock (PBA). sd_mmc_spi_init(spiOptions, PBA_HZ); } /*! \brief Initialize PDCA (Peripheral DMA Controller A) resources for the SPI transfer and start a dummy transfer */ void local_pdca_init(void) { // this PDCA channel is used for data reception from the SPI pdca_channel_options_t pdca_options_SPI_RX ={ // pdca channel options .addr = ram_buffer, // memory address. We take here the address of the string dummy_data. This string is located in the file dummy.h .size = 512, // transfer counter: here the size of the string .r_addr = NULL, // next memory address after 1st transfer complete .r_size = 0, // next transfer counter not used here .pid = AVR32_PDCA_CHANNEL_USED_RX, // select peripheral ID - data are on reception from SPI1 RX line .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer: 8,16,32 bits }; // this channel is used to activate the clock of the SPI by sending a dummy variables pdca_channel_options_t pdca_options_SPI_TX ={ // pdca channel options .addr = (void *)&dummy_data, // memory address. // We take here the address of the string dummy_data. // This string is located in the file dummy.h .size = 512, // transfer counter: here the size of the string .r_addr = NULL, // next memory address after 1st transfer complete .r_size = 0, // next transfer counter not used here .pid = AVR32_PDCA_CHANNEL_USED_TX, // select peripheral ID - data are on reception from SPI1 RX line .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer: 8,16,32 bits }; // Init PDCA transmission channel pdca_init_channel(AVR32_PDCA_CHANNEL_SPI_TX, &pdca_options_SPI_TX); // Init PDCA Reception channel pdca_init_channel(AVR32_PDCA_CHANNEL_SPI_RX, &pdca_options_SPI_RX); //! \brief Enable pdca transfer interrupt when completed INTC_register_interrupt(&pdca_int_handler, AVR32_PDCA_IRQ_0, AVR32_INTC_INT1); // pdca_channel_spi1_RX = 0 } /*! \brief Main function. Execution starts here. */ int main(void) { int i, j; // Switch the main clock to the external oscillator 0 pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP); // Initialize debug RS232 with PBA clock init_dbg_rs232(PBA_HZ); //start test print_dbg("\r\nInit SD/MMC Driver"); print_dbg("\r\nInsert SD/MMC..."); // Initialize Interrupt Controller INTC_init_interrupts(); // Initialize SD/MMC driver resources: GPIO, SPI and SD/MMC. sd_mmc_resources_init(); // Wait for a card to be inserted while (!sd_mmc_spi_mem_check()); print_dbg("\r\nCard detected!"); // Read Card capacity sd_mmc_spi_get_capacity(); print_dbg("Capacity = "); print_dbg_ulong(capacity >> 20); print_dbg(" MBytes"); // Enable all interrupts. Enable_global_interrupt(); // Initialize PDCA controller before starting a transfer local_pdca_init(); // Read the first sectors number 1, 2, 3 of the card for(j = 1; j <= 3; j++) { // Configure the PDCA channel: the address of memory ram_buffer to receive the data at sector address j pdca_load_channel( AVR32_PDCA_CHANNEL_SPI_RX, &ram_buffer, 512); pdca_load_channel( AVR32_PDCA_CHANNEL_SPI_TX, (void *)&dummy_data, 512); //send dummy to activate the clock end_of_transfer = false; // open sector number j if(sd_mmc_spi_read_open_PDCA (j)) { print_dbg("\r\nFirst 512 Bytes of Transfer number "); print_dbg_ulong(j); print_dbg(" :\r\n"); spi_write(SD_MMC_SPI,0xFF); // Write a first dummy data to synchronize transfer pdca_enable_interrupt_transfer_complete(AVR32_PDCA_CHANNEL_SPI_RX); pdca_channelrx =(volatile avr32_pdca_channel_t*) pdca_get_handler(AVR32_PDCA_CHANNEL_SPI_RX); // get the correct PDCA channel pointer pdca_channeltx =(volatile avr32_pdca_channel_t*) pdca_get_handler(AVR32_PDCA_CHANNEL_SPI_TX); // get the correct PDCA channel pointer pdca_channelrx->cr = AVR32_PDCA_TEN_MASK; // Enable RX PDCA transfer first pdca_channeltx->cr = AVR32_PDCA_TEN_MASK; // and TX PDCA transfer while(!end_of_transfer); // Display the first 2O bytes of the ram_buffer content for( i = 0; i < 20; i++) { print_dbg_char_hex( (U8)(*(ram_buffer + i))); } } else { print_dbg("\r\n! Unable to open memory \r\n"); } } print_dbg("\r\nEnd of the example.\r\n"); while (1); }
/*! \brief This function commands the sending of a LIN header and response, MASTER task only * * \param l_node Node Value * \param l_handle Handle on the descriptor list * \param l_len Message length corresponding to the message pointed by the handle in the descriptor list * * \return Status PASS / FAIL * */ static U8 lin_tx_header_and_response( U8 l_node, U8 l_handle, U8 l_len ) { if (l_node == 0) { //! Enable Interrupt for Error flags and end ID Reception #if ( defined (AVR32_USART_400_H_INCLUDED) || \ defined (AVR32_USART_410_H_INCLUDED) || \ defined (AVR32_USART_420_H_INCLUDED) ) // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node0, // memory address .pid = USART_LIN_NODE0_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len+1), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE0_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node0[1],lin_descript_list_node0[l_handle].l_pt_data,l_len); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE0_TX_PDCA_CHANNEL); // Set the ID First lin_tx_buffer_node0[0] = lin_descript_list_node0[l_handle].l_id; // Start PDCA transfer ID + Data pdca_enable(USART_LIN_NODE0_TX_PDCA_CHANNEL); usart_lin_set_id_char(usart_lin_node0,lin_descript_list_node0[l_handle].l_id); #else // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node0, // memory address .pid = USART_LIN_NODE0_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len+1), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE0_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node0[1],lin_descript_list_node0[l_handle].l_pt_data,l_len); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE0_TX_PDCA_CHANNEL); // Set the ID First lin_tx_buffer_node0[0] = lin_descript_list_node0[l_handle].l_id; // Start PDCA transfer ID + Data pdca_enable(USART_LIN_NODE0_TX_PDCA_CHANNEL); #endif return PASS; } #ifdef USART_LIN_NODE1_INSTANCE else { //! Enable Interrupt for Error flags and end ID Reception #if ( defined (AVR32_USART_400_H_INCLUDED) || \ defined (AVR32_USART_410_H_INCLUDED) || \ defined (AVR32_USART_420_H_INCLUDED) ) // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node1, // memory address .pid = USART_LIN_NODE1_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len+1), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE1_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node1[1],lin_descript_list_node1[l_handle].l_pt_data,l_len); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE1_TX_PDCA_CHANNEL); // Set the ID First lin_tx_buffer_node1[0] = lin_descript_list_node1[l_handle].l_id; // Start PDCA transfer ID + Data pdca_enable(USART_LIN_NODE1_TX_PDCA_CHANNEL); usart_lin_set_id_char(usart_lin_node1,lin_descript_list_node1[l_handle].l_id); #else // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node1, // memory address .pid = USART_LIN_NODE1_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len+1), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE1_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node1[1],lin_descript_list_node1[l_handle].l_pt_data,l_len); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE1_TX_PDCA_CHANNEL); // Set the ID First lin_tx_buffer_node1[0] = lin_descript_list_node1[l_handle].l_id; // Start PDCA transfer ID + Data pdca_enable(USART_LIN_NODE1_TX_PDCA_CHANNEL); #endif return PASS; } #endif } /*! \brief This function commands the sending of a LIN response, SLAVE task of MASTER or SLAVE node. * * \param l_node Node Value * \param l_handle Handle on the descriptor list * \param l_data Pointer on the data corresponding to the message pointed by the handle in the descriptor list * \param l_len Message length corresponding to the message pointed by the handle in the descriptor list * * \return Status PASS / FAIL * */ static U8 lin_tx_response ( U8 l_node, U8 l_handle, U8 *l_data, U8 l_len ) { if (l_node == 0) { // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node0, // memory address .pid = USART_LIN_NODE0_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE0_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node0[0],lin_descript_list_node0[l_handle].l_pt_data,l_len+1); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE0_TX_PDCA_CHANNEL); // Start PDCA transfer Data pdca_enable(USART_LIN_NODE0_TX_PDCA_CHANNEL); return 1; } #ifdef USART_LIN_NODE1_INSTANCE else { // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_tx_buffer_node1, // memory address .pid = USART_LIN_NODE1_PDCA_PID_TX, // select peripheral - data are transmit on USART TX line. .size = (l_len), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE1_TX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); // Copy data of the data contained in the descriptor list into the tx buffer of the PDCA memcpy(&lin_tx_buffer_node1[0],lin_descript_list_node1[l_handle].l_pt_data,l_len+1); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE1_TX_PDCA_CHANNEL); // Start PDCA transfer Data pdca_enable(USART_LIN_NODE1_TX_PDCA_CHANNEL); return 1; } #endif } /*! \brief This function commands the reception of a LIN response, SLAVE task of MASTER or SLAVE node. * * \param l_node Node Value * \param l_handle Handle on the descriptor list * \param l_len Message length corresponding to the message pointed by the handle in the descriptor list * * \return Status PASS / FAIL * */ static U8 lin_rx_response ( U8 l_node, U8 l_handle, U8 l_len ) { if (l_node == 0) { // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_rx_buffer_node0, // memory address .pid = USART_LIN_NODE0_PDCA_PID_RX, // select peripheral - data are transmit on USART TX line. .size = (l_len), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE0_RX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE0_RX_PDCA_CHANNEL); // Start PDCA transfer Data pdca_enable(USART_LIN_NODE0_RX_PDCA_CHANNEL); return 1; } #ifdef USART_LIN_NODE1_INSTANCE else { // PDCA channel options pdca_channel_options_t USART_LIN_PDCA_OPTIONS = { .addr = (void *)lin_rx_buffer_node1, // memory address .pid = USART_LIN_NODE1_PDCA_PID_RX, // select peripheral - data are transmit on USART TX line. .size = (l_len), // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; pdca_init_channel(USART_LIN_NODE1_RX_PDCA_CHANNEL, &USART_LIN_PDCA_OPTIONS); pdca_enable_interrupt_transfer_complete(USART_LIN_NODE1_RX_PDCA_CHANNEL); // Start PDCA transfer Data pdca_enable(USART_LIN_NODE1_RX_PDCA_CHANNEL); return 1; } #endif } /*! \brief This function reads (empties) the reception data buffer when a LIN response * had been received. This function is additional of the `lin_rx_response()' * function. * * \param l_node Node Value * \param l_data Pointer on the data corresponding to the message pointed by the handle in the descriptor list * * \return Status PASS / FAIL * */ static void lin_get_response (U8 l_node, U8 *l_data) { U8 i, l_len; if (l_node == 0) { l_len = usart_lin_get_data_length(usart_lin_node0); for (i = 0; i < l_len; i++) { (*l_data++) = lin_rx_buffer_node0[i]; } } #ifdef USART_LIN_NODE1_INSTANCE else { l_len = usart_lin_get_data_length(usart_lin_node1); for (i = 0; i < l_len; i++) { (*l_data++) = lin_rx_buffer_node1[i]; } } #endif }
//! //! @brief This function initializes the hardware/software resources //! required for device CDC task. //! void AK5394A_task_init(void) { // Set up CS4344 // Set up GLCK1 to provide master clock for CS4344 gpio_enable_module_pin(GCLK1, GCLK1_FUNCTION); // for DA_SCLK // LRCK is SCLK / 64 generated by TX_SSC // so SCLK of 6.144Mhz ===> 96khz 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); pm_enable_osc1_ext_clock(&AVR32_PM); // OSC1 is clocked by 12.288Mhz Osc // from AK5394A Xtal Oscillator pm_enable_clk1(&AVR32_PM, OSC1_STARTUP); // Set up AK5394A gpio_clr_gpio_pin(AK5394_RSTN); // put AK5394A in reset gpio_clr_gpio_pin(AK5394_DFS0); // L L -> 48khz gpio_clr_gpio_pin(AK5394_DFS1); gpio_set_gpio_pin(AK5394_HPFE); // enable HP filter gpio_clr_gpio_pin(AK5394_ZCAL); // use VCOML and VCOMR to cal gpio_set_gpio_pin(AK5394_SMODE1); // SMODE1 = H for Master i2s gpio_set_gpio_pin(AK5394_SMODE2); // SMODE2 = H for Master/Slave i2s gpio_set_gpio_pin(AK5394_RSTN); // start AK5394A while (gpio_get_pin_value(AK5394_CAL)); // wait till CAL goes low // Assign GPIO to SSC. gpio_enable_module(SSC_GPIO_MAP, sizeof(SSC_GPIO_MAP) / sizeof(SSC_GPIO_MAP[0])); gpio_enable_pin_glitch_filter(SSC_RX_CLOCK); gpio_enable_pin_glitch_filter(SSC_RX_DATA); gpio_enable_pin_glitch_filter(SSC_RX_FRAME_SYNC); gpio_enable_pin_glitch_filter(SSC_TX_CLOCK); gpio_enable_pin_glitch_filter(SSC_TX_DATA); gpio_enable_pin_glitch_filter(SSC_TX_FRAME_SYNC); current_freq.frequency = 96000; // set up SSC ssc_i2s_init(ssc, 96000, 24, 32, SSC_I2S_MODE_STEREO_OUT_STEREO_IN, FPBA_HZ); // set up PDCA // In order to avoid long slave handling during undefined length bursts (INCR), the Bus Matrix // provides specific logic in order to re-arbitrate before the end of the INCR transfer. // // HSB Bus Matrix: By default the HSB bus matrix mode is in Undefined length burst type (INCR). // Here we have to put in single access (the undefined length burst is treated as a succession of single // accesses, allowing re-arbitration at each beat of the INCR burst. // Refer to the HSB bus matrix section of the datasheet for more details. // // HSB Bus matrix register MCFG1 is associated with the CPU instruction master interface. AVR32_HMATRIX.mcfg[AVR32_HMATRIX_MASTER_CPU_INSN] = 0x1; audio_buffer_in = 0; spk_buffer_out = 0; // Register PDCA IRQ interrupt. pdca_set_irq(); // 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); pdca_init_channel(PDCA_CHANNEL_SSC_TX, &SPK_PDCA_OPTIONS); // init PDCA channel with options. pdca_enable_interrupt_reload_counter_zero(PDCA_CHANNEL_SSC_TX); ////////////////////////////////////////////// // Enable now the transfer. pdca_enable(PDCA_CHANNEL_SSC_TX); xTaskCreate(AK5394A_task, configTSK_AK5394A_NAME, configTSK_AK5394A_STACK_SIZE, NULL, configTSK_AK5394A_PRIORITY, NULL); }
/** ** PDCA Init. **/ void init_pdca(void) { // PDCA channel 0/1 options static const pdca_channel_options_t PDCA_CH_OPTIONS = { .addr = (void *)aDataTransfered, // memory address .pid = AVR32_PDCA_PID_USART2_TX, // select peripheral - data are transmit on USART TX line. .size = 0, // transfer counter .r_addr = (void *)aDataTransfered, // next memory address .r_size = sizeof(aDataTransfered), // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE, // select size of one data packet .etrig = true // Trigger transfer on event. }; Disable_global_interrupt(); // Initialize interrupt vectors. INTC_init_interrupts(); // Register the PDCA interrupt handler to the interrupt controller. INTC_register_interrupt(&pdca_int_handler, PDCA_CHANNEL_IRQ, AVR32_INTC_INT0); Enable_global_interrupt(); // Init PDCA channel with the pdca_options. pdca_init_channel(PDCA_CHANNEL_USART, &PDCA_CH_OPTIONS); pdca_channel = pdca_get_handler(PDCA_CHANNEL_USART); // For use in the pdca interrupt handler. // Enable pdca transfer error interrupt & transfer complete interrupt. pdca_enable_interrupt_transfer_error(PDCA_CHANNEL_USART); pdca_enable_interrupt_transfer_complete(PDCA_CHANNEL_USART); // Enable the PEVC channel "PDCA CHANNEL 0/1 ONE-ITEM-TRANSFER" PEVC_CHANNELS_ENABLE(ppevc, 1<<PEVC_PDCA_SOT_USER); // Enable the PDCA. pdca_enable(PDCA_CHANNEL_USART); } /** ** AST Init. **/ void init_ast(void) { avr32_ast_pir0_t pir = { .insel = 14 // Set a event every second }; ast_calendar_t ast_calendar; ast_calendar.FIELD.sec = 30; ast_calendar.FIELD.min = 45; ast_calendar.FIELD.hour = 12; ast_calendar.FIELD.day = 7; ast_calendar.FIELD.month= 10; ast_calendar.FIELD.year = 9; scif_osc32_opt_t opt; opt.mode = SCIF_OSC_MODE_2PIN_CRYSTAL; opt.startup = AVR32_SCIF_OSCCTRL32_STARTUP_0_RCOSC; // Start OSC_32KHZ scif_start_osc32(&opt,true); // Initialize the AST if (!ast_init_calendar(&AVR32_AST, AST_OSC_32KHZ, AST_PSEL_32KHZ_1HZ, ast_calendar)) { print_dbg("Error initializing the AST\r\n"); while(1); } ast_set_periodic0_value(&AVR32_AST,pir); ast_enable_periodic0(&AVR32_AST); // Clear All Interrupt AVR32_AST.scr=0xFFFFFFFF; // Enable the AST ast_enable(&AVR32_AST); } /*! \brief Initializes the MCU system clocks. */ static void init_sys_clocks(void) { /*! \name System Clock Frequencies */ //! @{ static pcl_freq_param_t pcl_freq_param = { .cpu_f = FCPU_HZ, .pba_f = FPBA_HZ, .osc0_f = FOSC0, .osc0_startup = OSC0_STARTUP }; //! @} // Configure system clocks. if (pcl_configure_clocks(&pcl_freq_param) != PASS) { while(1); } } /*! \brief This example show a DMA transfer to USART controlled by the AST periodic alarm using the PEVC. */ int main(void) { int i; // Init the string with a simple recognizable pattern. for(i=0;i<sizeof(aDataTransfered);i++) aDataTransfered[i] = '0' + (i%36); init_sys_clocks(); init_usart(); gpio_clr_gpio_pin(LED0_GPIO); init_pevc(); init_ast(); init_pdca(); while(1) { gpio_tgl_gpio_pin(LED1_GPIO); delay_ms(500); //Wait 500ms } }
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; }
/*! \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); } }
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; }
// initialize application timer extern void init_tc (volatile avr32_tc_t *tc) { // waveform options static const tc_waveform_opt_t waveform_opt = { .channel = APP_TC_CHANNEL, // channel .bswtrg = TC_EVT_EFFECT_NOOP, // software trigger action on TIOB .beevt = TC_EVT_EFFECT_NOOP, // external event action .bcpc = TC_EVT_EFFECT_NOOP, // rc compare action .bcpb = TC_EVT_EFFECT_NOOP, // rb compare .aswtrg = TC_EVT_EFFECT_NOOP, // soft trig on TIOA .aeevt = TC_EVT_EFFECT_NOOP, // etc .acpc = TC_EVT_EFFECT_NOOP, .acpa = TC_EVT_EFFECT_NOOP, // Waveform selection: Up mode with automatic trigger(reset) on RC compare. .wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER, .enetrg = false, // external event trig .eevt = 0, // extern event select .eevtedg = TC_SEL_NO_EDGE, // extern event edge .cpcdis = false, // counter disable when rc compare .cpcstop = false, // counter stopped when rc compare .burst = false, .clki = false, // Internal source clock 5, connected to fPBA / 128. .tcclks = TC_CLOCK_SOURCE_TC5 }; // Options for enabling TC interrupts static const tc_interrupt_t tc_interrupt = { .etrgs = 0, .ldrbs = 0, .ldras = 0, .cpcs = 1, // Enable interrupt on RC compare alone .cpbs = 0, .cpas = 0, .lovrs = 0, .covfs = 0 }; // Initialize the timer/counter. tc_init_waveform(tc, &waveform_opt); // set timer compare trigger. // we want it to overflow and generate an interrupt every 1 ms // so (1 / fPBA / 128) * RC = 0.001 // so RC = fPBA / 128 / 1000 tc_write_rc(tc, APP_TC_CHANNEL, (FPBA_HZ / 128 / 1000)); // configure the timer interrupt tc_configure_interrupts(tc, APP_TC_CHANNEL, &tc_interrupt); // Start the timer/counter. tc_start(tc, APP_TC_CHANNEL); } // initialize usb USARTy void init_ftdi_usart (void) { // GPIO map for USART. static const gpio_map_t FTDI_USART_GPIO_MAP = { { FTDI_USART_RX_PIN, FTDI_USART_RX_FUNCTION }, { FTDI_USART_TX_PIN, FTDI_USART_TX_FUNCTION } }; // Options for USART. static const usart_options_t FTDI_USART_OPTIONS = { .baudrate = FTDI_USART_BAUDRATE, .charlength = 8, .paritytype = USART_NO_PARITY, .stopbits = USART_1_STOPBIT, .channelmode = USART_NORMAL_CHMODE }; // Set up GPIO for FTDI_USART gpio_enable_module(FTDI_USART_GPIO_MAP, sizeof(FTDI_USART_GPIO_MAP) / sizeof(FTDI_USART_GPIO_MAP[0])); // Initialize in RS232 mode. usart_init_rs232(FTDI_USART, &FTDI_USART_OPTIONS, FPBA_HZ); } // initialize spi1: OLED, ADC, SD/MMC extern void init_spi1 (void) { static const gpio_map_t OLED_SPI_GPIO_MAP = { {OLED_SPI_SCK_PIN, OLED_SPI_SCK_FUNCTION }, {OLED_SPI_MISO_PIN, OLED_SPI_MISO_FUNCTION}, {OLED_SPI_MOSI_PIN, OLED_SPI_MOSI_FUNCTION}, {OLED_SPI_NPCS0_PIN, OLED_SPI_NPCS0_FUNCTION }, {OLED_SPI_NPCS1_PIN, OLED_SPI_NPCS1_FUNCTION }, {OLED_SPI_NPCS2_PIN, OLED_SPI_NPCS2_FUNCTION }, }; // SPI options for OLED spi_options_t spiOptions = { .reg = OLED_SPI_NPCS, .baudrate = 40000000, .bits = 8, .trans_delay = 0, .spck_delay = 0, .stay_act = 1, .spi_mode = 3, .modfdis = 1 }; // Assign GPIO to SPI. gpio_enable_module(OLED_SPI_GPIO_MAP, sizeof(OLED_SPI_GPIO_MAP) / sizeof(OLED_SPI_GPIO_MAP[0])); // Initialize as master. spi_initMaster(OLED_SPI, &spiOptions); // Set SPI selection mode: variable_ps, pcs_decode, delay. spi_selectionMode(OLED_SPI, 0, 0, 0); // Enable SPI module. spi_enable(OLED_SPI); // setup chip register for OLED spi_setupChipReg( OLED_SPI, &spiOptions, FPBA_HZ ); // add ADC chip register spiOptions.reg = ADC_SPI_NPCS; spiOptions.baudrate = 20000000; spiOptions.bits = 16; spiOptions.spi_mode = 2; spiOptions.spck_delay = 0; spiOptions.trans_delay = 5; spiOptions.stay_act = 0; spiOptions.modfdis = 0; spi_setupChipReg( ADC_SPI, &spiOptions, FPBA_HZ ); // add SD/MMC chip register spiOptions.reg = SD_MMC_SPI_NPCS; spiOptions.baudrate = SD_MMC_SPI_MASTER_SPEED; // Defined in conf_sd_mmc_spi.h; spiOptions.bits = SD_MMC_SPI_BITS; // Defined in conf_sd_mmc_spi.h; spiOptions.spck_delay = 0; spiOptions.trans_delay = 0; spiOptions.stay_act = 1; spiOptions.spi_mode = 0; spiOptions.modfdis = 1; // Initialize SD/MMC driver with SPI clock (PBA). sd_mmc_spi_init(spiOptions, FPBA_HZ); } // init PDCA (Peripheral DMA Controller A) resources for the SPI transfer and start a dummy transfer void init_local_pdca(void) { // PDCA channel for SPI RX pdca_channel_options_t pdca_options_SPI_RX ={ // pdca channel options .addr = (void *)&pdcaRxBuf, .size = FS_BUF_SIZE, // transfer size .r_addr = NULL, // next memory address after 1st transfer complete .r_size = 0, // next transfer counter not used here .pid = AVR32_PDCA_CHANNEL_USED_RX, // select peripheral ID - SPI1 RX .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer: 8,16,32 bits }; // PDCA channel for SPI TX pdca_channel_options_t pdca_options_SPI_TX ={ // pdca channel options .addr = (void *)&pdcaTxBuf, // memory address. .size = FS_BUF_SIZE, // transfer size .r_addr = NULL, // next memory address after 1st transfer complete .r_size = 0, // next transfer counter not used here .pid = AVR32_PDCA_CHANNEL_USED_TX, // select peripheral ID - SPI1 TX .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer: 8,16,32 bits }; // Init PDCA transmission channel pdca_init_channel(AVR32_PDCA_CHANNEL_SPI_TX, &pdca_options_SPI_TX); // Init PDCA Reception channel pdca_init_channel(AVR32_PDCA_CHANNEL_SPI_RX, &pdca_options_SPI_RX); } // intialize resources for bf533 communication: SPI, GPIO void init_bfin_resources(void) { static const gpio_map_t BFIN_SPI_GPIO_MAP = { { BFIN_SPI_SCK_PIN, BFIN_SPI_SCK_FUNCTION }, { BFIN_SPI_MISO_PIN, BFIN_SPI_MISO_FUNCTION }, { BFIN_SPI_MOSI_PIN, BFIN_SPI_MOSI_FUNCTION }, { BFIN_SPI_NPCS0_PIN, BFIN_SPI_NPCS0_FUNCTION }, }; spi_options_t spiOptions = { .reg = BFIN_SPI_NPCS, //// FIXME: //// would prefer fast baudrate / lower trans delay during boot, //// but need multiple registers for boot (fast) and run (slow) //// investigate if this is possible... // .baudrate = 20000000, // .baudrate = 10000000, // .baudrate = 5000000, .baudrate = 20000000, .bits = 8, .spck_delay = 0, // .trans_delay = 0, .trans_delay = 20, .stay_act = 1, .spi_mode = 1, .modfdis = 1 }; // assign pins to SPI. gpio_enable_module(BFIN_SPI_GPIO_MAP, sizeof(BFIN_SPI_GPIO_MAP) / sizeof(BFIN_SPI_GPIO_MAP[0])); // intialize as master spi_initMaster(BFIN_SPI, &spiOptions); // set selection mode: variable_ps, pcs_decode, delay. spi_selectionMode(BFIN_SPI, 0, 0, 0); // enable SPI. spi_enable(BFIN_SPI); // intialize the chip register spi_setupChipReg(BFIN_SPI, &spiOptions, FPBA_HZ); // enable pulldown on bfin HWAIT line //// shit! not implemented... // gpio_enable_pin_pull_down(BFIN_HWAIT_PIN); // enable pullup on bfin RESET line gpio_enable_pin_pull_up(BFIN_RESET_PIN); } // intialize two-wire interface void init_twi(void) { // TWI/I2C GPIO map static const gpio_map_t TWI_GPIO_MAP = { { TWI_DATA_PIN, TWI_DATA_FUNCTION }, { TWI_CLOCK_PIN, TWI_CLOCK_FUNCTION } }; gpio_enable_module(TWI_GPIO_MAP, sizeof(TWI_GPIO_MAP) / sizeof(TWI_GPIO_MAP[0])); } // initialize USB host stack void init_usb_host (void) { // pm_configure_usb_clock(); uhc_start(); }
/****************************************************************************** rn42_init *//** @brief Initializes RN42 driver. @brief usart Pointer to the USART hardware structure the RN42 is on. @brief irq IRQ number to process interrupts on. @brief gpio_pin Pin connected to the RN42's status output. ******************************************************************************/ void rn42_init( volatile avr32_usart_t *usart, uint32_t irq, uint32_t gpio_pin) { static usart_options_t usart_options = { .baudrate = 115200, .charlength = 8, .paritytype = USART_NO_PARITY, .stopbits = USART_1_STOPBIT, .channelmode = USART_NORMAL_CHMODE }; static pdca_channel_options_t pdca_rx_options = { .pid = AVR32_PDCA_PID_USART3_RX, .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .transfer_size = PDCA_TRANSFER_SIZE_BYTE }; static pdca_channel_options_t pdca_tx_options = { .pid = AVR32_PDCA_PID_USART3_TX, .addr = NULL, .size = 0, .r_addr = NULL, .r_size = 0, .transfer_size = PDCA_TRANSFER_SIZE_BYTE }; /* Initialize the USART to use hardware handshaking. Without the handshaking, the RN42 has trouble keeping up when continuosly sending fairly small amounts of data. Note that when hardware handshaking is enabled, the PDCA must be used for receiving data. */ rn42_usart = usart; usart_serial_init(rn42_usart, &usart_options); rn42_usart->mr = (rn42_usart->mr & ~0xf) | 0x02; /* Register the ISR for USART's DMA completion IRQs. */ pdca_init_channel(PDCA_CHANNEL_RX, &pdca_rx_options); pdca_init_channel(PDCA_CHANNEL_TX, &pdca_tx_options); irq_register_handler(usart_isr, PDCA_IRQ, 0); setup_usart_rx_dma(bt_buf, sizeof(command_t)); usart_irq_enable(); pdca_enable(PDCA_CHANNEL_RX); pdca_enable(PDCA_CHANNEL_TX); /* Configure RN42 status GPIO. */ gpio_configure_pin(gpio_pin, GPIO_DIR_INPUT | GPIO_PULL_DOWN); gpio_disable_pin_pull_up(gpio_pin); rn42_status_pin = gpio_pin; } /****************************************************************************** rn42_connected *//** @brief Returns whether the RN42 is connected by examining the status GPIO. The RN42's status line appears to bounce, so this function takes care of debouncing it. ******************************************************************************/ static bool rn42_connected(void) { bool connected1; bool connected2; do { connected1 = gpio_pin_is_high(rn42_status_pin); delay_ms(50); connected2 = gpio_pin_is_high(rn42_status_pin); } while (connected1 != connected2); return connected1 & connected2; } /****************************************************************************** rn42_send_data *//** @brief Transmits data to a Bluetooth peer over the RN42 module. @param[in] buf Pointer to the data that should be sent. @param[in] size Number of bytes to send. ******************************************************************************/ void rn42_send_data(uint8_t *buf, uint32_t size) { uint32_t status; setup_usart_tx_dma(buf, size); while (true) { status = pdca_get_transfer_status(PDCA_CHANNEL_TX); if (status & PDCA_TRANSFER_COMPLETE) { break; } } } /****************************************************************************** send_response *//** @brief Sends a response packet to the host. @param[in] cmd_id The command ID we're responding to. @param[in] status The status code. @param[in] data Pointer to data to send to the PC. @param[in] data_length Number of bytes to send. ******************************************************************************/ static void send_response( uint8_t cmd_id, uint8_t status, uint8_t *data, uint32_t data_length) { response_t response = { {'C', 'C', 'M', 'D'}, cmd_id, status, }; storeBigU32(&response.data_length, data_length); rn42_send_data((uint8_t*) &response, sizeof(response)); rn42_send_data(data, data_length); }
int8_t i2c_driver_trigger_request(uint8_t i2c_device, uint8_t schedule_slot) { // initiate transfer of given request // set up DMA channel volatile avr32_twim_t *twim; i2c_packet_conf_t* conf = &schedule[i2c_device][schedule_slot].config; static pdca_channel_options_t PDCA_OPTIONS = { .addr = 0, // memory address .pid = AVR32_TWIM0_PDCA_ID_TX, // select peripheral .size = 4, // transfer counter .r_addr = NULL, // next memory address .r_size = 0, // next transfer counter .transfer_size = PDCA_TRANSFER_SIZE_BYTE // select size of the transfer }; switch (i2c_device) { case 0: twim = &AVR32_TWIM0; twim->cr = AVR32_TWIM_CR_MEN_MASK; twim->cr = AVR32_TWIM_CR_SWRST_MASK; twim->cr = AVR32_TWIM_CR_MDIS_MASK; switch (conf->direction) { case I2C_WRITE1_THEN_READ: case I2C_READ: PDCA_OPTIONS.pid = AVR32_TWIM0_PDCA_ID_RX; PDCA_OPTIONS.addr = (void *)conf->read_data; PDCA_OPTIONS.size=conf->read_count; // Init PDCA channel with the pdca_options. pdca_init_channel(TWI0_DMA_CH, &PDCA_OPTIONS); // init PDCA channel with options. break; case I2C_WRITE: PDCA_OPTIONS.pid = AVR32_TWIM0_PDCA_ID_TX; PDCA_OPTIONS.addr = (void *)conf->write_data; PDCA_OPTIONS.size=conf->write_count; // Init PDCA channel with the pdca_options. pdca_init_channel(TWI0_DMA_CH, &PDCA_OPTIONS); // init PDCA channel with options. pdca_load_channel(TWI0_DMA_CH, (void *)conf->write_data, conf->write_count); break; } //pdca_load_channel(TWI0_DMA_CH, (void *)schedule[i2c_device][schedule_slot].config.write_data, schedule[i2c_device][schedule_slot].config.write_count); // Enable pdca interrupt each time the reload counter reaches zero, i.e. each time // the whole block was received pdca_enable_interrupt_transfer_complete(TWI0_DMA_CH); pdca_enable_interrupt_transfer_error(TWI0_DMA_CH); break; case 1: twim = &AVR32_TWIM1; break; default: // invalid device ID return -1; } // set up I2C speed and mode //twim_set_speed(twim, 100000, sysclk_get_pba_hz()); switch (conf->direction) { case I2C_READ: twim->cmdr = (conf->slave_address << AVR32_TWIM_CMDR_SADR_OFFSET) | (conf->read_count << AVR32_TWIM_CMDR_NBYTES_OFFSET) | (AVR32_TWIM_CMDR_VALID_MASK) | (AVR32_TWIM_CMDR_START_MASK) | (0 << AVR32_TWIM_CMDR_STOP_OFFSET) | (0 << AVR32_TWIM_CMDR_READ_OFFSET); break; case I2C_WRITE1_THEN_READ: print_util_dbg_print( "wr"); // set up next command register for the burst read transfer // set up command register to initiate the write transfer. The DMA will take care of the reading once this is done. twim->cmdr = (conf->slave_address << AVR32_TWIM_CMDR_SADR_OFFSET) | (1 << AVR32_TWIM_CMDR_NBYTES_OFFSET) | (AVR32_TWIM_CMDR_VALID_MASK) | (AVR32_TWIM_CMDR_START_MASK) | (0 << AVR32_TWIM_CMDR_STOP_OFFSET) ; twim->ncmdr = (conf->slave_address << AVR32_TWIM_CMDR_SADR_OFFSET) | ((conf->read_count) << AVR32_TWIM_CMDR_NBYTES_OFFSET) | (AVR32_TWIM_CMDR_VALID_MASK) | (AVR32_TWIM_CMDR_START_MASK) | (0 << AVR32_TWIM_CMDR_STOP_OFFSET) | (0 << AVR32_TWIM_CMDR_READ_OFFSET); // set up writing of one byte (usually a slave register index) //twim->cr = AVR32_TWIM_CR_MEN_MASK; twim->thr = conf->write_then_read_preamble; twim->cr = AVR32_TWIM_CR_MEN_MASK; break; case I2C_WRITE: print_util_dbg_print( "w"); twim->cmdr = (conf->slave_address << AVR32_TWIM_CMDR_SADR_OFFSET) | ((conf->write_count) << AVR32_TWIM_CMDR_NBYTES_OFFSET) | (AVR32_TWIM_CMDR_VALID_MASK) | (AVR32_TWIM_CMDR_START_MASK) | (0 << AVR32_TWIM_CMDR_STOP_OFFSET) ; twim->ncmdr = (conf->slave_address << AVR32_TWIM_CMDR_SADR_OFFSET) | ((conf->write_count) << AVR32_TWIM_CMDR_NBYTES_OFFSET) //| (AVR32_TWIM_CMDR_VALID_MASK) | (AVR32_TWIM_CMDR_START_MASK) | (0 << AVR32_TWIM_CMDR_STOP_OFFSET) ; break; } // start transfer current_schedule_slot[i2c_device] = schedule_slot; schedule[i2c_device][schedule_slot].transfer_in_progress = 1; twim->cr = AVR32_TWIM_CR_MEN_MASK; pdca_enable(TWI0_DMA_CH); return 0; } int8_t i2c_driver_pause_request(uint8_t i2c_device, uint8_t schedule_slot) { // pause scheduler // if this request currently active, wait for current transfer to finish // deactivate request // resume scheduler } int8_t i2c_driver_enable_request(uint8_t i2c_device, uint8_t schedule_slot){ return 0; } int8_t i2c_driver_remove_request(uint8_t i2c_device, uint8_t schedule_slot){ return 0; }