/** * \brief Start ADC sample. * Initialize ADC, set clock and timing, and set ADC to given mode. */ static void start_adc(void) { struct adc_config adc_cfg = { /* System clock division factor is 16 */ .prescal = ADC_PRESCAL_DIV16, /* The APB clock is used */ .clksel = ADC_CLKSEL_APBCLK, /* Max speed is 150K */ .speed = ADC_SPEED_150K, /* ADC Reference voltage is 0.625*VCC */ .refsel = ADC_REFSEL_1, /* Enables the Startup time */ .start_up = CONFIG_ADC_STARTUP }; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* DAC internal */ .muxpos = ADC_MUXPOS_3, /* 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, }; if(adc_init(&g_adc_inst, ADCIFE, &adc_cfg) != STATUS_OK) { puts("-F- ADC Init Fail!\n\r"); while(1); } if(adc_enable(&g_adc_inst) != STATUS_OK) { puts("-F- ADC Enable Fail!\n\r"); while(1); } if (g_adc_test_mode.uc_pdc_en) { adc_disable_interrupt(&g_adc_inst, ADC_SEQ_SEOC); 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); } else { pdca_channel_disable_interrupt(CONFIG_ADC_PDCA_RX_CHANNEL, PDCA_IDR_TRC); pdca_channel_disable_interrupt(CONFIG_ADC_PDCA_TX_CHANNEL, PDCA_IDR_TRC); adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_set_callback(&g_adc_inst, ADC_SEQ_SEOC, adcife_read_conv_result, ADCIFE_IRQn, 1); } /* Configure trigger mode and start convention. */ switch (g_adc_test_mode.uc_trigger_mode) { case TRIGGER_MODE_SOFTWARE: adc_configure_trigger(&g_adc_inst, ADC_TRIG_SW); break; case TRIGGER_MODE_CON: adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); break; case TRIGGER_MODE_ITIMER: adc_configure_trigger(&g_adc_inst, ADC_TRIG_INTL_TIMER); adc_configure_itimer_period(&g_adc_inst, adc_ch_cfg.internal_timer_max_count); adc_start_itimer(&g_adc_inst); break; default: break; } if (g_adc_test_mode.uc_gain_en) { adc_configure_gain(&g_adc_inst, ADC_GAIN_2X); } else { adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); } } /** * \brief Start DAC ouput. * Initialize DAC, set clock and timing, and set DAC to given mode. */ static void start_dac(void) { sysclk_enable_peripheral_clock(DACC); /* Reset DACC registers */ dacc_reset(DACC); /* Half word transfer mode */ dacc_set_transfer_mode(DACC, 0); /* Timing: * startup - 0x10 (17 clocks) * internal trigger clock - 0x60 (96 clocks) */ dacc_set_timing(DACC, 0x10, 0x60); /* Enable DAC */ dacc_enable(DACC); /* The DAC is 10-bit resolution, so output voltage should be * (3300 * 255) / ((1 << 10) - 1) = 823mv */ dacc_write_conversion_data(DACC, 0xFF); }
/** * \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. */ } }
/** * \brief Initialize the temperature sensor */ void initialize_temperature(void) { /** not used at present */ #if 0 struct adc_config adc_cfg = { /* System clock division factor is 16 */ .prescal = ADC_PRESCAL_DIV16, /* The APB clock is used */ .clksel = ADC_CLKSEL_APBCLK, /* Max speed is 150K */ .speed = ADC_SPEED_150K, /* ADC Reference voltage is VCC/2 */ .refsel =ADC_REFSEL_4, /* Enables the Startup time */ .start_up = CONFIG_ADC_STARTUP }; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* Temperature sensor */ .muxpos = EPD_Temperature_Sensor_ADC, /* Enables the internal voltage sources */ .internal =ADC_INTERNAL_2, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, .gain=ADC_GAIN_1X, /* 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_init(&g_adc_inst, ADCIFE, &adc_cfg); adc_enable(&g_adc_inst); adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_set_callback(&g_adc_inst, ADC_SEQ_SEOC, adcife_read_conv_result, ADCIFE_IRQn, 1); adc_configure_trigger(&g_adc_inst,ADC_TRIG_SW); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); #endif } /** * \brief Initialize the EPD hardware setting */ void EPD_display_hardware_init (void) { EPD_initialize_gpio(); EPD_Vcc_turn_off(); epd_spi_init(); initialize_temperature(); EPD_cs_low(); EPD_pwm_low(); EPD_rst_low(); EPD_discharge_low(); EPD_border_low(); //initialize_EPD_timer(); }
/** * \brief Example entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint8_t c_choice; int16_t s_adc_value; int16_t s_dac_value; int16_t s_threshold = 0; float f_dac_data; uint32_t ul_dac_data; /* Initialize the SAM system. */ sysclk_init(); board_init(); configure_console(); /* Output example information. */ puts(STRING_HEADER); /* Initialize threshold. */ gs_us_low_threshold = 500; gs_us_high_threshold = 2000; struct adc_config adc_cfg = { /* System clock division factor is 16 */ .prescal = ADC_PRESCAL_DIV16, /* The APB clock is used */ .clksel = ADC_CLKSEL_APBCLK, /* Max speed is 150K */ .speed = ADC_SPEED_150K, /* ADC Reference voltage is 0.625*VCC */ .refsel = ADC_REFSEL_1, /* Enables the Startup time */ .start_up = CONFIG_ADC_STARTUP }; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* DAC Internal */ .muxpos = ADC_MUXPOS_3, /* 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 500 * VOLT_REF / 4095 = 251mv. */ .low_threshold = gs_us_low_threshold, /* The equivalent voltage value is 2000 * VOLT_REF / 4095 = 1002mv. */ .high_threshold = gs_us_high_threshold, }; start_dac(); if(adc_init(&g_adc_inst, ADCIFE, &adc_cfg) != STATUS_OK) { puts("-F- ADC Init Fail!\n\r"); while(1); } if(adc_enable(&g_adc_inst) != STATUS_OK) { puts("-F- ADC Enable Fail!\n\r"); while(1); } 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_wm_handler, ADCIFE_IRQn, 1); /* Display main menu. */ display_menu(); while (1) { scanf("%c", (char *)&c_choice); printf("%c\r\n", c_choice); switch (c_choice) { case '0': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("DAC output is set to(mv) from 0mv to %dmv: ", (int32_t)VOLT_REF); s_dac_value = get_voltage(); puts("\r"); f_dac_data = (float)s_dac_value * DACC_MAX_DATA / VDDANA; ul_dac_data = f_to_int(f_dac_data); if (s_dac_value >= 0) { dacc_write_conversion_data(DACC, ul_dac_data); } delay_ms(100); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '1': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("Low threshold is set to(mv) from 0mv to %dmv: ", (int32_t)VOLT_REF); s_threshold = get_voltage(); puts("\r"); if (s_threshold >= 0) { s_adc_value = s_threshold * MAX_DIGITAL / VOLT_REF; adc_configure_wm_threshold(&g_adc_inst, s_adc_value, gs_us_high_threshold); /* Renew low threshold. */ gs_us_low_threshold = s_adc_value; float f_low_threshold = (float)gs_us_low_threshold * VOLT_REF / MAX_DIGITAL; uint32_t ul_low_threshold = f_to_int(f_low_threshold); printf("Setting low threshold to %u mv (reg value to 0x%x ~%d%%)\n\r", ul_low_threshold, gs_us_low_threshold, gs_us_low_threshold * 100 / MAX_DIGITAL); } adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '2': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("High threshold is set to(mv)from 0mv to %dmv:", (int32_t)VOLT_REF); s_threshold = get_voltage(); puts("\r"); if (s_threshold >= 0) { s_adc_value = s_threshold * MAX_DIGITAL / VOLT_REF; adc_configure_wm_threshold(&g_adc_inst, gs_us_low_threshold, s_adc_value); /* Renew high threshold. */ gs_us_high_threshold = s_adc_value; float f_high_threshold = (float)gs_us_high_threshold * VOLT_REF / MAX_DIGITAL; uint32_t ul_high_threshold = f_to_int(f_high_threshold); printf("Setting high threshold to %u mv (reg value to 0x%x ~%d%%)\n\r", ul_high_threshold, gs_us_high_threshold, gs_us_high_threshold * 100 / MAX_DIGITAL); } adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '3': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); puts("-a. Above low threshold.\n\r" "-b. Below high threshold.\n\r" "-c. In the comparison window.\n\r" "-d. Out of the comparison window.\n\r" "-q. Quit the setting.\r"); c_choice = get_wm_mode(); adc_configure_wm_mode(&g_adc_inst, c_choice); printf("Comparison mode is %c.\n\r", 'a' + c_choice - 1); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case 'm': display_menu(); break; case 'i': display_info(); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; } puts("Press \'m\' or \'M\' to display the main menu again!\r"); } }