/** * \brief Initialize ADC and DAC used to simulate a temperature sensor * * DACB is used by the simulation plant to output a temperature reading of the * oven plate. It is set up to output a voltage on pin B2 which is marked as * ADC2 on header J2. * * ADCA is used in the control step and graphical interface to show the current * temperature of the oven plate. It is set up to read a voltage on pin A4 which * is marked as ADC4 on header J2. * * ADC2 and ADC4 should be connected together, so that the ADC samples the DAC * directly. */ void main_init_adc_dac(void) { struct adc_config adc_conf; struct adc_channel_config adcch_conf; struct dac_config dac_conf; /* Set up the DAC for the simulation to output "real" temperature */ dac_read_configuration(&DACB, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, DAC_CH0, 0); dac_write_configuration(&DACB, &dac_conf); dac_enable(&DACB); /* Set up the ADC for the controller to read "real" temperature */ adc_read_configuration(&ADCA, &adc_conf); adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf); adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 20000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&ADCA, &adc_conf); adcch_set_input(&adcch_conf, ADCCH_POS_PIN4, ADCCH_NEG_NONE, 1); adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf); adc_enable(&ADCA); adc_start_conversion(&ADCA, ADC_CH0); /* Enable pull-down, so an open circuit can be detected */ ioport_set_pin_dir(J2_PIN4, IOPORT_DIR_INPUT); ioport_set_pin_mode(J2_PIN4, IOPORT_MODE_PULLDOWN); }
void dac_init(void){ struct dac_config dac_conf; dac_read_configuration(&MY_DAC, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, NTX2B_DAC, 0); dac_set_conversion_trigger(&dac_conf, 0, 1); dac_write_configuration(&MY_DAC, &dac_conf); }
/** * \brief Configure the DAC for calibration */ static void configure_dac(void) { struct dac_config conf; dac_read_configuration(&DACB, &conf); dac_set_conversion_parameters(&conf, DAC_REF_AVCC, DAC_ADJ_RIGHT); dac_set_active_channel(&conf, DAC_CH0 | DAC_CH1, 0); dac_write_configuration(&DACB, &conf); dac_enable(&DACB); }
void ntx2b_mod_disable( void) { // wait till end transmission while(ntx2b_mod_busy_flag); // set the DAC to update when data sent struct dac_config dac_conf; dac_read_configuration(&MY_DAC, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, NTX2B_DAC, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_write_configuration(&MY_DAC, &dac_conf); ioport_set_pin_mode(GPIO_NTX2B_EN, IOPORT_MODE_TOTEM | IOPORT_MODE_INVERT_PIN ); }
/** * \brief Initializes the DAC */ static void main_dac_init(void) { /* DAC module configuration structure */ struct dac_config dac_conf; /* Create configuration: * - AVCC as reference * - right adjusted channel value * - both DAC channels active on : * - DAC0 (PA2 pin) for ADC V+ * - DAC1 (PA3 pin) for ADC V- * - manually triggered conversions on both channels */ dac_read_configuration(&DACA, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_AVCC, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, DAC_CH0 | DAC_CH1, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_write_configuration(&DACA, &dac_conf); dac_enable(&DACA); }
void ntx2b_mod_enable( char mode) { // Set DAC to Space frequency dac_set_channel_value(&MY_DAC, NTX2B_DAC, RTTY300_MARK); // set DAC to update on events struct dac_config dac_conf; dac_read_configuration(&MY_DAC, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, NTX2B_DAC, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_write_configuration(&MY_DAC, &dac_conf); // Set DAC to Mark frequency dac_set_channel_value(&MY_DAC, NTX2B_DAC, RTTY300_MARK); ioport_set_pin_mode(GPIO_NTX2B_EN, IOPORT_MODE_TOTEM | IOPORT_MODE_INVERT_PIN ); }
int main(void) { struct dac_config conf; uint8_t i = 0; board_init(); sysclk_init(); // Initialize the dac configuration. dac_read_configuration(&SPEAKER_DAC, &conf); /* Create configuration: * - 1V from bandgap as reference, left adjusted channel value * - one active DAC channel, no internal output * - conversions triggered by event channel 0 * - 1 us conversion intervals */ dac_set_conversion_parameters(&conf, DAC_REF_BANDGAP, DAC_ADJ_LEFT); dac_set_active_channel(&conf, SPEAKER_DAC_CHANNEL, 0); dac_set_conversion_trigger(&conf, SPEAKER_DAC_CHANNEL, 0); #if XMEGA_DAC_VERSION_1 dac_set_conversion_interval(&conf, 1); #endif dac_write_configuration(&SPEAKER_DAC, &conf); dac_enable(&SPEAKER_DAC); #if XMEGA_E // Configure timer/counter to generate events at sample rate. sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC4); TCC4.PER = (sysclk_get_per_hz() / RATE_OF_CONVERSION) - 1; // Configure event channel 0 to generate events upon T/C overflow. sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); EVSYS.CH0MUX = EVSYS_CHMUX_TCC4_OVF_gc; // Start the timer/counter. TCC4.CTRLA = TC45_CLKSEL_DIV1_gc; #else // Configure timer/counter to generate events at sample rate. sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); TCC0.PER = (sysclk_get_per_hz() / RATE_OF_CONVERSION) - 1; // Configure event channel 0 to generate events upon T/C overflow. sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); EVSYS.CH0MUX = EVSYS_CHMUX_TCC0_OVF_gc; // Start the timer/counter. TCC0.CTRLA = TC_CLKSEL_DIV1_gc; #endif /* Write samples to the DAC channel every time it is ready for new * data, i.e., when it is done converting. Conversions are triggered by * the timer/counter. */ do { dac_wait_for_channel_ready(&SPEAKER_DAC, SPEAKER_DAC_CHANNEL); dac_set_channel_value(&SPEAKER_DAC, SPEAKER_DAC_CHANNEL, sine[i]); i++; i %= NR_OF_SAMPLES; } while (1); }
/** * \internal * \brief Test differential conversion with gain in 12-bit mode using the DAC * * This test outputs a gain compensated level on DAC output that should result * in a value of half maximum positive value on the ADC. * * These values are then measured using the ADC on the pins that are connected * to the DAC channel, and the results are compared and checked to see if they * are within the acceptable range of values that passes the test. * * \param test Current test case. */ static void run_differential_12bit_with_gain_conversion_test( const struct test_case *test) { // Number of MUX inputs that are to be read const uint8_t num_inputs = 2; /* Connection between DAC outputs and ADC MUX inputs. * Only the high nibble on PORTA is possible for gain. * input 4, 6 is connected to DACA0 * input 5, 7 is connected to DACA1. */ const uint8_t channel_pos[] = {4, 6}; const uint8_t channel_neg[] = {5, 7}; /* * Go through gain level up to 8, since any higher gives too much * propagated error for sensible unit test limits. */ const uint8_t gain[] = {1, 2, 4, 8}; uint8_t gain_index; uint8_t adc_channel; uint8_t mux_index; int16_t results[2]; struct dac_config dac_conf; struct adc_config adc_conf; // Configure ADC adc_read_configuration(&ADCA, &adc_conf); adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 2000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&ADCA, &adc_conf); // Configure DAC dac_read_configuration(&DACA, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, DAC_CH0 | DAC_CH1, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_set_conversion_interval(&dac_conf, 10); dac_set_refresh_interval(&dac_conf, 20); dac_write_configuration(&DACA, &dac_conf); dac_enable(&DACA); // Set negative output to zero dac_wait_for_channel_ready(&DACA, DAC_CH1); dac_set_channel_value(&DACA, DAC_CH1, DAC_MIN); for (gain_index = 0; gain_index < sizeof(gain); gain_index++) { // Set positive output to half positive range adjusted to gain dac_wait_for_channel_ready(&DACA, DAC_CH0); dac_set_channel_value(&DACA, DAC_CH0, DAC_MAX / (gain[gain_index] * 2)); /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { differential_signed_average(&ADCA, 1 << adc_channel, channel_pos, channel_neg, num_inputs, results, gain[gain_index]); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_signed_result(test, ADC_SIGNED_12BIT_MAX / 2, results[mux_index], adc_channel, channel_pos[mux_index], channel_neg[mux_index], ADC_SIGNED_12BIT_MIN, ADC_SIGNED_12BIT_MAX, gain[gain_index], true); } } } }
/** * \internal * \brief Test differential conversion in 12-bit mode using the DAC * * This tests output three different values on the two DAC channels: * - 1/2 * \ref DAC_MAX on both outputs to get a differential zero * - \ref DAC_MAX on positive and \ref DAC_MIN on negative to get max positive * result * - \ref DAC_MIN on positive and \ref DAC_MAX on negative to get max negative * result * * These values are then measured using the ADC on the pins that are connected * to the DAC channel, and the results are compared and checked to see if they * are within the acceptable range of values that passes the test. * * \param test Current test case. */ static void run_differential_12bit_conversion_test( const struct test_case *test) { // Number of MUX inputs that are to be read const uint8_t num_inputs = 4; /* Connection between DAC outputs and ADC MUX inputs * input 0, 2, 4, 6 is connected to DACA0 * input 1, 3, 5, 7 is connected to DACA1. */ const uint8_t channel_pos[] = {0, 2, 4, 6}; const uint8_t channel_neg[] = {1, 3, 5, 7}; uint8_t adc_channel; uint8_t mux_index; int16_t results[4]; struct dac_config dac_conf; struct adc_config adc_conf; // Configure ADC adc_read_configuration(&ADCA, &adc_conf); adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 2000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&ADCA, &adc_conf); // Configure DAC dac_read_configuration(&DACA, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, DAC_CH0 | DAC_CH1, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_set_conversion_interval(&dac_conf, 10); dac_set_refresh_interval(&dac_conf, 20); dac_write_configuration(&DACA, &dac_conf); dac_enable(&DACA); // Set outputs to same (1/2 * MAX_VALUE) to get zero dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MAX / 2); dac_set_channel_value(&DACA, DAC_CH1, DAC_MAX / 2); /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { differential_signed_average(&ADCA, 1 << adc_channel, channel_pos, channel_neg, num_inputs, results, 1); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_signed_result(test, ADC_ZERO, results[mux_index], adc_channel, channel_pos[mux_index], channel_neg[mux_index], ADC_SIGNED_12BIT_MIN, ADC_SIGNED_12BIT_MAX, 1, true); } } // Set output to max positive range for positive result dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MAX); dac_set_channel_value(&DACA, DAC_CH1, DAC_MIN); /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { differential_signed_average(&ADCA, 1 << adc_channel, channel_pos, channel_neg, num_inputs, results, 1); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_signed_result(test, ADC_SIGNED_12BIT_MAX, results[mux_index], adc_channel, channel_pos[mux_index], channel_neg[mux_index], ADC_SIGNED_12BIT_MIN, ADC_SIGNED_12BIT_MAX, 1, true); } } // Set output to max negative range for negative result dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MIN); dac_set_channel_value(&DACA, DAC_CH1, DAC_MAX); /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { differential_signed_average(&ADCA, 1 << adc_channel, channel_pos, channel_neg, num_inputs, results, 1); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_signed_result(test, ADC_SIGNED_12BIT_MIN, results[mux_index], adc_channel, channel_pos[mux_index], channel_neg[mux_index], ADC_SIGNED_12BIT_MIN, ADC_SIGNED_12BIT_MAX, 1, true); } } }
/** * \internal * \brief Test single ended conversion in 8-bit mode using the DAC * * This tests output three different values on the two DAC channels: * - 0 (output analog value is greater than 0, as the DAC cannot go that low) * - 1/2 * \ref DAC_MAX Half of the maximum value of the DAC * - \ref DAC_MAX The maximum value (VREF) of the DAC. * * These values are then measured using the ADC on the pins that are connected * to the DAC channel, using all available ADC channels and the results are * compared and checked to see if they are within the acceptable range of * values that passes the test. * * \param test Current test case. */ static void run_single_ended_8bit_conversion_test( const struct test_case *test) { // Number of MUX inputs that are to be read const uint8_t num_inputs = 4; /* Connection between DAC outputs and ADC MUX inputs * input 0, 2, 4, 6 is connected to DACA0 * input 1, 3, 5, 7 is connected to DACA1. */ const uint8_t channelgroup[2][4] = {{0, 2, 4, 6}, {1, 3, 5, 7}}; uint8_t dac_channel; uint8_t adc_channel; uint8_t mux_index; uint16_t results[4]; struct dac_config dac_conf; struct adc_config adc_conf; // Configure ADC adc_read_configuration(&ADCA, &adc_conf); adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_8, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 2000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&ADCA, &adc_conf); // Configure DAC dac_read_configuration(&DACA, &dac_conf); dac_set_conversion_parameters(&dac_conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT); dac_set_active_channel(&dac_conf, DAC_CH0 | DAC_CH1, 0); dac_set_conversion_trigger(&dac_conf, 0, 0); dac_set_conversion_interval(&dac_conf, 10); dac_set_refresh_interval(&dac_conf, 20); dac_write_configuration(&DACA, &dac_conf); dac_enable(&DACA); // Set outputs as zero dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MIN); dac_set_channel_value(&DACA, DAC_CH1, DAC_MIN); for(dac_channel = 0; dac_channel < 2; dac_channel++) { /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { single_ended_unsigned_average(&ADCA, 1 << adc_channel, (uint8_t *)&channelgroup[dac_channel], num_inputs, results); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_unsigned_result(test, ADC_ZERO, results[mux_index], dac_channel, adc_channel, channelgroup[dac_channel] [mux_index], ADC_UNSIGNED_8BIT_MAX, false); } } } // Set outputs as 1/2 * MAX_VALUE dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MAX / 2); dac_set_channel_value(&DACA, DAC_CH1, DAC_MAX / 2); for(dac_channel = 0; dac_channel < 2; dac_channel++) { /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { single_ended_unsigned_average(&ADCA, 1 << adc_channel, (uint8_t *)&channelgroup[dac_channel], num_inputs, results); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_unsigned_result(test, ADC_UNSIGNED_8BIT_MAX / 2, results[mux_index], dac_channel, adc_channel, channelgroup[dac_channel] [mux_index], ADC_UNSIGNED_8BIT_MAX, false); } } } // Set outputs as MAX_VALUE dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1); dac_set_channel_value(&DACA, DAC_CH0, DAC_MAX); dac_set_channel_value(&DACA, DAC_CH1, DAC_MAX); for(dac_channel = 0; dac_channel < 2; dac_channel++) { /* Read all ADC pins connected to active DAC output. * All channels are converted NUM_SAMPLES times and the * final value used for the assert is an average. */ for (adc_channel = 0; adc_channel < NUM_CHANNELS; adc_channel++) { single_ended_unsigned_average(&ADCA, 1 << adc_channel, (uint8_t *)&channelgroup[dac_channel], num_inputs, results); for (mux_index = 0; mux_index < num_inputs; mux_index++) { verify_unsigned_result(test, ADC_UNSIGNED_8BIT_MAX, results[mux_index], dac_channel, adc_channel, channelgroup[dac_channel] [mux_index], ADC_UNSIGNED_8BIT_MAX, false); } } } }
int main(void) { struct dac_config conf; board_init(); sysclk_init(); // Initialize the dac configuration. dac_read_configuration(&OUTPUT_DAC, &conf); /* Create configuration: * - AVCC as reference, right adjusted channel value * - both DAC channels active, no internal output * - manually triggered conversions on both channels * - 2 us conversion intervals * - 10 us refresh intervals */ dac_set_conversion_parameters(&conf, DAC_REF_AVCC, DAC_ADJ_RIGHT); dac_set_active_channel(&conf, DAC_CH0 | DAC_CH1, 0); dac_set_conversion_trigger(&conf, 0, 0); #if XMEGA_DAC_VERSION_1 dac_set_conversion_interval(&conf, 10); dac_set_refresh_interval(&conf, 20); #endif dac_write_configuration(&OUTPUT_DAC, &conf); dac_enable(&OUTPUT_DAC); dac_wait_for_channel_ready(&OUTPUT_DAC, DAC_CH0 | DAC_CH1); dac_set_channel_value(&OUTPUT_DAC, DAC_CH0, 0); dac_set_channel_value(&OUTPUT_DAC, DAC_CH1, 0); dac_wait_for_channel_ready(&OUTPUT_DAC, DAC_CH0 | DAC_CH1); #if !XMEGA_E // Configure timer/counter to generate events at conversion rate. sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); TCC0.PER = (sysclk_get_per_hz() / RATE_OF_CONVERSION) - 1; // Configure event channel 0 to generate events upon T/C overflow. sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); EVSYS.CH0MUX = EVSYS_CHMUX_TCC0_OVF_gc; // Start the timer/counter. TCC0.CTRLA = TC_CLKSEL_DIV1_gc; #else // Configure timer/counter to generate events at conversion rate. sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC4); TCC4.PER = (sysclk_get_per_hz() / RATE_OF_CONVERSION) - 1; // Configure event channel 0 to generate events upon T/C overflow. sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS); EVSYS.CH0MUX = EVSYS_CHMUX_TCC4_OVF_gc; // Start the timer/counter. TCC4.CTRLA = TC45_CLKSEL_DIV1_gc; #endif /* Write samples to the DAC channel every time it is ready. * Conversions are triggered by the timer/counter. */ do { /* Wait for channels to get ready for new values, then set the * value of one to 10% and the other to 90% of maximum. */ wait_for_timer(); dac_set_channel_value(&OUTPUT_DAC, DAC_CH0, 410); dac_set_channel_value(&OUTPUT_DAC, DAC_CH1, 3686); wait_for_timer(); dac_set_channel_value(&OUTPUT_DAC, DAC_CH0, 3686); dac_set_channel_value(&OUTPUT_DAC, DAC_CH1, 410); } while (1); }