/** * \brief Callback function for ADCIFE interrupt. */ static void adcife_read_conv_result(void) { if ((adc_get_status(&g_adc_inst) & ADCIFE_SR_SEOC) == ADCIFE_SR_SEOC) { g_adc_sample_data[0] = adc_get_last_conv_value(&g_adc_inst); g_uc_condone_flag = 1; adc_clear_status(&g_adc_inst, ADCIFE_SCR_SEOC); } }
/** Display current information,including * voltage on division resistor, thresholds and window monitor mode. */ static void display_info(void) { uint32_t ul_adc_value = adc_get_last_conv_value(&g_adc_inst); float f_low_threshold = (float)gs_us_low_threshold * VOLT_REF / MAX_DIGITAL; float f_high_threshold = (float)gs_us_high_threshold * VOLT_REF / MAX_DIGITAL; uint32_t ul_low_threshold = f_to_int(f_low_threshold); uint32_t ul_high_threshold = f_to_int(f_high_threshold); printf("-I- Thresholds: %u mv - %u mv.\n\r", ul_low_threshold, ul_high_threshold); printf("-I- Voltage on tested channel: %u mv.\n\r", (unsigned int)(ul_adc_value * VOLT_REF / MAX_DIGITAL)); printf("-I- Comparison mode is %u\n\r.", (unsigned int)(adc_get_wm_mode(&g_adc_inst))); }
/** * \brief Callback function for ADCIFE interrupt. */ static void adcife_wm_handler(void) { uint32_t ul_mode; uint16_t us_adc; /* Disable Window Monitor Interrupt. */ adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); if ((adc_get_status(&g_adc_inst) & ADCIFE_SR_WM) == ADCIFE_SR_WM) { ul_mode = adc_get_wm_mode(&g_adc_inst); us_adc = adc_get_last_conv_value(&g_adc_inst); switch (ul_mode) { case 1: printf("-ISR-:DAC output voltage %d mv is above the low threshold:%d mv!\n\r", (int)(us_adc * VOLT_REF / MAX_DIGITAL), (int)(gs_us_low_threshold * VOLT_REF / MAX_DIGITAL)); break; case 2: printf("-ISR-:DAC output voltage %d mv is below the high threshold:%d mv!\n\r", (int)(us_adc * VOLT_REF / MAX_DIGITAL), (int)(gs_us_high_threshold * VOLT_REF / MAX_DIGITAL)); break; case 3: printf("-ISR-:DAC output voltage %d mv is in the comparison window:%d-%d mv!\n\r", (int)(us_adc * VOLT_REF / MAX_DIGITAL), (int)(gs_us_low_threshold * VOLT_REF / MAX_DIGITAL), (int)(gs_us_high_threshold * VOLT_REF / MAX_DIGITAL)); break; case 4: printf("-ISR-:DAC output voltage %d mv is out of the comparison window:%d-%d mv!\n\r", (int)(us_adc * VOLT_REF / MAX_DIGITAL), (int)(gs_us_low_threshold * VOLT_REF / MAX_DIGITAL), (int)(gs_us_high_threshold * VOLT_REF / MAX_DIGITAL)); break; } adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); } }
/** * \brief Test ADCIFE in Differential mode. * * \param test Current test case. */ static void run_adcife_diff_test(const struct test_case *test) { uint32_t timeout = ADC_NUM_OF_ATTEMPTS; bool conversion_timeout = false; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* Scaled Vcc, Vcc/10 */ .muxpos = ADC_MUXPOS_2, /* Enables the internal voltage sources */ .internal = ADC_INTERNAL_3, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, /* 12-bits resolution */ .res = ADC_RES_12_BIT, /* Enables the differential mode */ .bipolar = ADC_BIPOLAR_DIFFERENTIAL }; struct adc_ch_config adc_ch_cfg = { .seq_cfg = &adc_seq_cfg, /* Internal Timer Max Counter */ .internal_timer_max_count = 60, /* Window monitor mode is off */ .window_mode = 0, .low_threshold = 0, .high_threshold = 0, }; adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); while (!((adc_get_status(&g_adc_inst) & ADCIFE_SR_SEOC) == ADCIFE_SR_SEOC)) { if (!timeout--) { conversion_timeout = true; } } test_assert_true(test, conversion_timeout == false, "ADCIFE Differential conversion timeout"); /* Because selected channel is positive input, then in differential mode * the output conversion result will = 2047 + (Vin/Vref)*2047. */ test_assert_true(test, adc_get_last_conv_value(&g_adc_inst) > 2047, "ADCIFE Differential test failed"); } /** * \brief Test ADCIFE in internal timer trigger mode, * which also tests interrupt driven conversions. * * \param test Current test case. */ static void run_adcife_itimer_trig_test(const struct test_case *test) { struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* Scaled Vcc, Vcc/10 */ .muxpos = ADC_MUXPOS_2, /* Enables the internal voltage sources */ .internal = ADC_INTERNAL_3, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, /* 12-bits resolution */ .res = ADC_RES_12_BIT, /* Enables the single-ended mode */ .bipolar = ADC_BIPOLAR_SINGLEENDED }; struct adc_ch_config adc_ch_cfg = { .seq_cfg = &adc_seq_cfg, /* Internal Timer Max Counter */ .internal_timer_max_count = 60, /* Window monitor mode is off */ .window_mode = 0, .low_threshold = 0, .high_threshold = 0, }; adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_set_callback(&g_adc_inst, ADC_SEQ_SEOC, adcife_set_conv_flag, ADCIFE_IRQn, 1); adc_configure_trigger(&g_adc_inst, ADC_TRIG_INTL_TIMER); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); adc_configure_itimer_period(&g_adc_inst, adc_ch_cfg.internal_timer_max_count); adc_start_itimer(&g_adc_inst); delay_ms(100); test_assert_true(test, g_uc_condone_flag == 1, "ADCIFE Internal Timer trigger test failed"); } /* When VDDANA is in MIN value = 2.4V, the equivalent voltage value is * (2400 * 255) / ((1 << 10) - 1) = 598mv. The relative digital value is * 598 * 4095 / 1000 = 2449. */ #define DAC_INTERNAL_MIN_VALUE 2449 /* When VDDANA is in MAX value = 3.6V the equivalent voltage value is * (3600 * 255) / ((1 << 10) - 1) = 897mv. The relative digital value is * 897 * 4095 / 1000 = 3673. */ #define DAC_INTERNAL_MAX_VALUE 3673 /* When VCC is in MIN value = 1.6V, the equivalent voltage value is * 1600 / 10 = 160mv. The relative digital value is * 160 * 4095 / 1000 = 434. */ #define VCC_SCALED_MIN_VALUE 434 /* When VCC is in MAX value = 3.6V, the equivalent voltage value is * 3600 / 10 = 360mv. The relative digital value is * 360 * 4095 / 1000 = 1474. */ #define VCC_SCALED_MAX_VALUE 1474 /** * \brief Test ADCIFE in multiple channel mode. * * \param test Current test case. */ static void run_adcife_multichannel_test(const struct test_case *test) { start_dac(); adc_pdca_set_config(&g_adc_pdca_cfg); pdca_channel_set_callback(CONFIG_ADC_PDCA_RX_CHANNEL, pdca_transfer_done, PDCA_0_IRQn, 1, PDCA_IER_TRC); adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); delay_ms(100); /* The DAC output voltage value is 823mv, so the equivalent ADC value should be * 4095 * 823 / 1000 = 3370. The scaled VCC output voltage is 330mv, so the * equivalent ADC value should be 4095 * 330 / 1000 = 1351. */ test_assert_true(test, ((DAC_INTERNAL_MIN_VALUE < g_adc_sample_data[0] < DAC_INTERNAL_MAX_VALUE) && (VCC_SCALED_MIN_VALUE < g_adc_sample_data[1] < VCC_SCALED_MAX_VALUE)), "ADCIFE Multichannel test failed"); } /** * \brief Test ADCIFE in window monitor mode. * * \param test Current test case. */ static void run_adcife_wm_test(const struct test_case *test) { struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* Scaled Vcc, Vcc/10 */ .muxpos = ADC_MUXPOS_2, /* Enables the internal voltage sources */ .internal = ADC_INTERNAL_3, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, /* 12-bits resolution */ .res = ADC_RES_12_BIT, /* Enables the single-ended mode */ .bipolar = ADC_BIPOLAR_SINGLEENDED }; struct adc_ch_config adc_ch_cfg = { .seq_cfg = &adc_seq_cfg, /* Internal Timer Max Counter */ .internal_timer_max_count = 60, /* Window monitor mode is off */ .window_mode = ADC_WM_MODE_3, /* The equivalent voltage value is 205 * 1000 / 4095 = 50mv. */ .low_threshold = 205, /* The equivalent voltage value is 2050 * 1000 / 4095 = 500mv. */ .high_threshold = 2050, }; adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); adc_set_callback(&g_adc_inst, ADC_WINDOW_MONITOR, adcife_set_wm_flag, ADCIFE_IRQn, 1); delay_ms(100); test_assert_true(test, g_uc_enter_win_flag == 1, "ADCIFE Inside Window Mode test failed"); /* The teseted channel voltage is outside window */ adc_disable(&g_adc_inst); g_uc_enter_win_flag = 0; adc_seq_cfg.muxpos = ADC_MUXPOS_3; adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); delay_ms(100); test_assert_true(test, g_uc_enter_win_flag == 0, "ADCIFE Outside Window Mode test failed"); } /** * \brief Run ADCIFE driver unit tests. */ int main(void) { const usart_serial_options_t usart_serial_options = { .baudrate = CONF_TEST_BAUDRATE, .charlength = CONF_TEST_CHARLENGTH, .paritytype = CONF_TEST_PARITY, .stopbits = CONF_TEST_STOPBITS }; /* Initialize the system clock and board */ sysclk_init(); board_init(); /* Enable the debug uart */ stdio_serial_init(CONF_TEST_USART, &usart_serial_options); #if defined(__GNUC__) setbuf(stdout, NULL); #endif /* Define all the test cases */ DEFINE_TEST_CASE(adcife_init_test, NULL, run_adcife_init_test, NULL, "ADCIFE Initialize test"); DEFINE_TEST_CASE(adcife_diff_test, NULL, run_adcife_diff_test, NULL, "ADCIFE Differential test"); DEFINE_TEST_CASE(adcife_itmer_trig_test, NULL, run_adcife_itimer_trig_test, NULL, "ADCIFE Internal Timer trigger test"); DEFINE_TEST_CASE(adcife_multichannel_test, NULL, run_adcife_multichannel_test, NULL, "ADCIFE Multichannel test"); DEFINE_TEST_CASE(adcife_wm_test, NULL, run_adcife_wm_test, NULL, "ADCIFE Window Monitor Mode test"); /* Put test case addresses in an array */ DEFINE_TEST_ARRAY(adcife_tests) = { &adcife_init_test, &adcife_diff_test, &adcife_itmer_trig_test, &adcife_multichannel_test, &adcife_wm_test, }; /* Define the test suite */ DEFINE_TEST_SUITE(adcife_suite, adcife_tests, "SAM ADCIFE driver test suite"); /* Run all tests in the test suite */ test_suite_run(&adcife_suite); while (1) { /* Busy-wait forever. */ } }