예제 #1
0
/**
 * \brief Perform a simulation step.
 *
 * This function first reads the received frequency signal representing the
 * power level the plate element is actuated with, then performs a simulation
 * step and outputs the simulated temperature of the plate element as an analog
 * value via DACB on the pin marked ADC2.
 *
 * The simulation plant is a discretized version of the continuous system:
 * \f$ \dot{x} = \mathbf{F}*\vec{x} + \mathbf{B}*\vec{u} \f$, where:
 * \f[
   \begin{array}{c}
   \mathbf{F} = \left[ \begin{array}{c c}
           \frac{-1}{C_\textnormal{plate} * K_\textnormal{plate}} & 0 \\
	   \\
	   0 & \frac{-1}{C_\textnormal{pot} * K_\textnormal{pot}}
       \end{array} \right] \\
   \vec{x} = \left[ \begin{array}{c}
           E_\textnormal{plate} \\
	   \\
	   E_\textnormal{pot}
       \end{array} \right] \\
   \mathbf{B} = \left[ \begin{array}{c c}
           1 & 0 \\
	   \\
	   0 & 1
       \end{array} \right] \\
   \vec{u} = \left[ \begin{array}{c}
           \frac{T_\textnormal{environment}}{K_\textnormal{plate}} \\
	   \\
           \frac{T_\textnormal{environment}}{K_\textnormal{pot}}
       \end{array} \right]
   \end{array} \\
   \f]
 * in the case when the pot is OFF the plate.
 *
 * This corresponds to the plate and the pot cooling separately by Newton's law
 * of cooling because no power can be induced when the pot is not on the plate.
 *
 * When the pot is ON the stove, the system is similar, but \b F is modified by
 * adding heat transfer between the plate and the contents of the pot, and
 * disregarding heat loss from the plate to the environment.
 * Likewise \b u is modified by adding energy induction into the bottom of the
 * pot, simplified here as being the same point as the plate:
 * \f[
   \begin{array}{c}
   \mathbf{F} = \left[ \begin{array}{c c}
           \frac{-1}{C_\textnormal{plate}* K_\textnormal{plate}} &
	   		\frac{1}{C_\textnormal{pot}* K_\textnormal{plate}} \\
	   \\
           \frac{1}{C_\textnormal{plate}* K_\textnormal{plate}} &
	   		\frac{-1}{C_\textnormal{pot}* K_\textnormal{plate}}
                   - \frac{1}{C_\textnormal{pot} * K_\textnormal{pot}}
	\end{array} \right] \\
   \vec{u} = \left[ \begin{array}{c}
           \delta E_\textnormal{induced} \\
	   \\
           \frac{T_\textnormal{environment}}{K_\textnormal{pot}}
       \end{array} \right]
   \end{array}
   \f]
 *
 *
 * \param pot Whether the pot is on or off the plate.
 */
void oven_plant_sim_step(enum pot_t pot)
{
	/* Remap period of incoming signal to power */
	float u = oven_plant_calculate_u_from_period(
			oven_plant_read_signal_period());

	switch (pot) {
	case POT_OFF:
		state[0] = state[0] + u - (state[0] / C_PLATE - ENV_TEMP)
				/ K_PLATE;
		state[1] = state[1] - (state[1] / C_POT - ENV_TEMP) / K_POT;
		break;

	case POT_ON:
		state[0] = state[0] + u - (state[0] / C_PLATE - state[1]
				/ C_POT) / K_PLATE;
		state[1] = state[1] + (state[0] / C_PLATE - state[1] / C_POT)
				/ K_PLATE - (state[1] / C_POT - ENV_TEMP)
				/ K_POT;
		break;

	default:
		break;
	}

	/* Output DAC value, simulating an analog temperature sensor. */
	dac_wait_for_channel_ready(&DACB, DAC_CH0);
	dac_set_channel_value(&DACB, DAC_CH0, state[0] * 1);

	return;
}
예제 #2
0
/**
 * \brief Main application rutine
 */
int main (void)
{
	/* Variables used to produce a saw tooth signal */
	static uint16_t dac_data = 0;
	static int8_t direction = 1;

	board_init();

	sysclk_init();
	
	/* Calibrate the DAC */
	dac_calibrate();

	/* Generate a SAW tooth signal, just as a demo that the calibration works */
	while (true) {

		dac_wait_for_channel_ready(&DACB, DAC_CH0);

		dac_set_channel_value(&DACB, DAC_CH0, dac_data);
		dac_set_channel_value(&DACB, DAC_CH1, dac_data);

		dac_data = dac_data + direction;

		/* If the output value is the top value, switch direction */
		if (dac_data == 4095) {
			direction = -1;
		}

		/* If the output value is the lowest value, switch direction */
		if (dac_data == 0) {
			direction = 1;
		}
	}
}
예제 #3
0
/**
 * \brief Changes the DAC ouput value
 *
 * \param volt Value to output on DAC pins
 */
static void main_dac_output(int16_t volt)
{
	/* Samples of values used:
	 * | ADC0 |    V+   | ADC1 |    V-   | V+ - V- |
	 * ---------------------------------------------
	 * | 4096 |   Vcc   |    0 |    0V   |   Vcc   |
	 * | 3072 | Vcc 3/4 | 1024 | Vcc 1/4 |  Vcc/2  |
	 * | 2048 | Vcc 1/2 | 2048 | Vcc 1/2 |    0V   |
	 * | 1024 | Vcc 1/4 | 3072 | Vcc 3/4 | -Vcc/2  |
	 * |    0 |    0V   | 4096 |   Vcc   |  -Vcc   |
	 */
	dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1);
	dac_set_channel_value(&DACA, DAC_CH0,
			(1 << 11) + (((1 << 11) * (int32_t)volt) / 3300));
	dac_set_channel_value(&DACA, DAC_CH1,
			(1 << 11) - (((1 << 11) * (int32_t)volt) / 3300));
	dac_wait_for_channel_ready(&DACA, DAC_CH0 | DAC_CH1);
}
예제 #4
0
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);
}
예제 #5
0
/**
 * \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);
			}
		}
	}
}
예제 #6
0
/**
 * \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);
		}
	}
}
예제 #7
0
/**
 * \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);
			}
		}
	}
}
예제 #8
0
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);
}