OSStatus platform_adc_take_sample( const platform_adc_t* adc, uint16_t* output ) { OSStatus err = kNoErr; platform_mcu_powersave_disable(); require_action_quiet( adc != NULL, exit, err = kParamErr); channel_num = adc->channel; adc_channel_enable(ADC, adc->channel); adc_set_callback(ADC, adc->interrupt, adc_end_conversion, 1); /* Start conversion */ adc_start_software_conversion(ADC); adc_start_calibration(ADC); while (adc_get_interrupt_status(ADC) & (1 << adc->channel)); *output = adc_channel_get_value(ADC, adc->channel); mico_thread_msleep(1); adc_channel_disable(ADC, adc->channel); exit: platform_mcu_powersave_enable(); return err; }
int main(void) { struct adc_config adc_conf; struct adc_channel_config adcch_conf; board_init(); sysclk_init(); sleepmgr_init(); irq_initialize_vectors(); cpu_irq_enable(); gfx_mono_init(); // Enable back light of display ioport_set_pin_high(LCD_BACKLIGHT_ENABLE_PIN); // Initialize configuration structures. adc_read_configuration(&ADCA, &adc_conf); adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf); /* Configure the ADC module: * - unsigned, 12-bit results * - VCC voltage reference * - 200 kHz maximum clock rate * - manual conversion triggering * - temperature sensor enabled * - callback function */ adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_VCC); adc_set_clock_rate(&adc_conf, 200000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE); adc_write_configuration(&ADCA, &adc_conf); adc_set_callback(&ADCA, &adc_handler); /* Configure ADC channel 0: * - single-ended measurement from temperature sensor * - interrupt flag set on completed conversion * - interrupts disabled */ adcch_set_input(&adcch_conf, ADCCH_POS_PIN1, ADCCH_NEG_NONE, 1); adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf); // Enable the ADC and start the first conversion. adc_enable(&ADCA); adc_start_conversion(&ADCA, ADC_CH0); do { // Sleep until ADC interrupt triggers. sleepmgr_enter_sleep(); } while (1); }
int main(void) { struct adc_config adc_conf; struct adc_channel_config adcch_conf; board_init(); sysclk_init(); sleepmgr_init(); irq_initialize_vectors(); cpu_irq_enable(); // Initialize configuration structures. adc_read_configuration(&ADCA, &adc_conf); adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf); /* Configure the ADC module: * - unsigned, 12-bit results * - bandgap (1 V) voltage reference * - 200 kHz maximum clock rate * - manual conversion triggering * - temperature sensor enabled * - callback function */ adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 200000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE); adc_write_configuration(&ADCA, &adc_conf); adc_set_callback(&ADCA, &adc_handler); /* Configure ADC channel 0: * - single-ended measurement from temperature sensor * - interrupt flag set on completed conversion * - interrupts disabled */ adcch_set_input(&adcch_conf, ADCCH_POS_TEMPSENSE, ADCCH_NEG_NONE, 1); adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf); // Get measurement for 85 degrees C (358 kelvin) from calibration data. tempsense = adc_get_calibration_data(ADC_CAL_TEMPSENSE); // Enable the ADC and start the first conversion. adc_enable(&ADCA); adc_start_conversion(&ADCA, ADC_CH0); do { // Sleep until ADC interrupt triggers. sleepmgr_enter_sleep(); } while (1); }
/** * \brief Application entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { int32_t ul_vol; int32_t ul_temp; /* Initialize the SAM system. */ sysclk_init(); board_init(); configure_console(); /* Output example information. */ puts(STRING_HEADER); adc_enable(); struct adc_config adc_cfg; adc_get_config_defaults(&adc_cfg); adc_init(ADC, &adc_cfg); adc_channel_enable(ADC,ADC_TEMPERATURE_SENSOR); adc_set_trigger(ADC, ADC_TRIG_SW); struct adc_temp_sensor_config adc_temp_sensor_cfg; adc_temp_sensor_get_config_defaults(&adc_temp_sensor_cfg); adc_temp_sensor_set_config(ADC, &adc_temp_sensor_cfg); adc_set_callback(ADC, ADC_INTERRUPT_EOC_16, adc_temp_sensor_end_conversion, 1); adc_start_software_conversion(ADC); while (1) { if (is_conversion_done == true) { is_conversion_done = false; ul_vol = g_ul_value * VOLT_REF / MAX_DIGITAL; /* * According to datasheet, The output voltage VT = 1.44V at 27C * and the temperature slope dVT/dT = 4.7 mV/C */ ul_temp = (ul_vol - 1440) * 100 / 470 + 27; printf("-- Temperature is: %4d\r\n", (int)ul_temp); delay_ms(1000); adc_start_software_conversion(ADC); } } }
void owltemp_init() { struct adc_config adc_conf; struct adc_channel_config adcch_conf; // Clear the configuration structures. memset(&adc_conf, 0, sizeof(struct adc_config)); memset(&adcch_conf, 0, sizeof(struct adc_channel_config)); /* Configure the ADC module: * - unsigned, 12-bit results * - bandgap (1 V) voltage reference * - 200 kHz maximum clock rate * - manual conversion triggering * - temperature sensor enabled * - callback function */ adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_BANDGAP); adc_set_clock_rate(&adc_conf, 200000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 0, 0); adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE); adc_write_configuration(&ADCA, &adc_conf); adc_set_callback(&ADCA, &adc_handler); /* Configure ADC channel 0: * - single-ended measurement from temperature sensor * - interrupt flag set on completed conversion * - interrupts disabled */ adcch_set_input(&adcch_conf, ADCCH_POS_TEMPSENSE, ADCCH_NEG_NONE, 1); adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&ADCA, 0, &adcch_conf); // Get measurement for 85 degrees C (358 kelvin) from calibration data. tempsense = adc_get_calibration_data(ADC_CAL_TEMPSENSE); // Enable the ADC and start the first conversion. adc_enable(&ADCA); adc_start_conversion(&ADCA, ADC_CH0); }
/** * \brief Application entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { int32_t ul_vol; /* Initialize the SAM system. */ sysclk_init(); board_init(); configure_console(); /* Output example information. */ puts(STRING_HEADER); adc_enable(); struct adc_config adc_cfg; adc_get_config_defaults(&adc_cfg); adc_init(ADC, &adc_cfg); adc_channel_enable(ADC, ADC_CHANNEL_11); adc_set_trigger(ADC, ADC_TRIG_TIO_CH_0); adc_set_callback(ADC, ADC_INTERRUPT_EOC_11, adc_end_conversion, 1); set_adc_resolution(); adc_start_calibration(ADC); /* Configure TC */ configure_tc_trigger(); while (1) { /* Check if ADC sample is done. */ if (is_conversion_done == true) { ul_vol = g_ul_value * VOLT_REF / g_max_digital; printf("-- Voltage is: %4dmv\r\n", (int)ul_vol); is_conversion_done = false; } } }
void app_sampling_init(void) { /* QDec configuration */ qdec_get_config_defaults(&qdec_config); qdec_config_phase_pins(&qdec_config, &PORTA, 6, false, 500); qdec_config_enable_rotary(&qdec_config); qdec_config_tc(&qdec_config, &TCC5); qdec_config_revolution(&qdec_config, 40); qdec_enabled(&qdec_config); /* ! ADC module configuration */ struct adc_config adc_conf; /* Configure the ADC module: * - signed, 12-bit results * - VCC reference * - 200 kHz maximum clock rate * - manual conversion triggering * - callback function */ adc_read_configuration(&LIGHT_SENSOR_ADC_MODULE, &adc_conf); adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_VCC); adc_set_clock_rate(&adc_conf, 200000); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&LIGHT_SENSOR_ADC_MODULE, &adc_conf); adc_set_callback(&LIGHT_SENSOR_ADC_MODULE, &app_sampling_handler); adc_enable(&LIGHT_SENSOR_ADC_MODULE); /* Configure ADC A channel 0 for light and NTC sensors. * - differantial measurement (V- linked on internal GND) * - gain x0.5 * - interrupt flag set on completed conversion * - interrupts enabled */ adcch_read_configuration(&LIGHT_SENSOR_ADC_MODULE, ADC_CH0, &adcch_conf); adcch_set_input(&adcch_conf, LIGHT_SENSOR_ADC_INPUT, ADCCH_NEG_INTERNAL_GND, 0); adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&LIGHT_SENSOR_ADC_MODULE, ADC_CH0, &adcch_conf); fifo_init(&app_sampling_fifo_desc, app_sampling_fifo_buffer, APP_SAMPLING_FIFO_SIZE); rtc_set_callback(&app_sampling_start); /* Display background */ gfx_mono_draw_line(DISPLAY_SAMPLING_TEXT_POS_X - 3, 0, DISPLAY_SAMPLING_TEXT_POS_X - 3, 32, GFX_PIXEL_SET); app_sampling_display_rate(); gfx_mono_draw_string(DISPLAY_LIGHT_TEXT, DISPLAY_LIGHT_TEXT_POS_X, DISPLAY_LIGHT_TEXT_POS_Y, &sysfont); gfx_mono_draw_filled_rect( DISPLAY_LIGHT_PROBAR_START_POS_X, DISPLAY_LIGHT_PROBAR_START_POS_Y, DISPLAY_LIGHT_PROBAR_START_SIZE_X, DISPLAY_LIGHT_PROBAR_START_SIZE_Y, GFX_PIXEL_SET); gfx_mono_draw_filled_rect( DISPLAY_LIGHT_PROBAR_STOP_POS_X, DISPLAY_LIGHT_PROBAR_STOP_POS_Y, DISPLAY_LIGHT_PROBAR_STOP_SIZE_X, DISPLAY_LIGHT_PROBAR_STOP_SIZE_Y, GFX_PIXEL_SET); /* Start a RTC alarm immediatly */ rtc_set_alarm_relative(0); }
/** * \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 Show menu for error insertion and handle user's selection. * * This function changes device configurations and does some hacks to make * the device behave incorrectly. * * The menu entries are * - Change clock frequency: Changes the peripheral clock divider, simulating * that the clock system has malfunctioned. This should be detected by the * Class B frequency consistency test. * * - Mess with test timer: Changes how often periodic tests are performed, * simulating an error with an interrupt timer. This should be detected by * the Class B interrupt monitor. * * - Change a Flash section: Changes the string for the menu title stored in * program memory to "Out of cheese", simulating Flash memory corruption. * This can be changed back by selecting the menu item again. This should be * detected by the Class B Flash CRC test. * * - Scramble SRAM section: Starts a continuous DMA transfer in the background * to a memory location, simulating transient SRAM corruption. This should * be detected by the periodic and power-on Class B SRAM test. * * - Enter infinite loop: Simulates a runaway program counter by looping * forever. This should be detected by the watchdog timer system which is * tested on device power-up. * * - Change ADC reference: Enables a callback function for the ADC, which will * change the voltage reference after the next completed conversion. This * will cause the analog IO test to fail when user turns up the power to the * plate. */ void oven_classb_error_insertion(void) { uint8_t menu_status; struct keyboard_event input; struct adc_channel_config adcch_conf; /* Initialize menu system */ gfx_mono_menu_init(&error_menu); /* Wait for user to select something in the menu system */ do { do { keyboard_get_key_state(&input); oven_wdt_periodic_reset(); /* Wait for key release */ } while (input.type != KEYBOARD_RELEASE); /* Send key to menu system */ menu_status = gfx_mono_menu_process_key(&error_menu, input.keycode); oven_wdt_periodic_reset(); } while (menu_status == GFX_MONO_MENU_EVENT_IDLE); /* Handle the user's selection */ switch (menu_status) { case 0: /* Change cpu frequency by modifying the prescalers */ sysclk_set_prescalers(CLK_PSADIV_4_gc, CLK_PSBCDIV_1_1_gc); break; case 1: /* Change timing of the periodic temperature tests */ OVEN_PERIODIC_TEMPTEST_TC.CTRLA = TC_CLKSEL_DIV256_gc; break; case 2: /* Change flash section. */ oven_classb_flash_corrupter(); break; case 3: /* Disrupt SRAM by setting up the DMA to write to a location on * the heap, triggered by the class B frequency monitor timer */ PR.PRGEN &= ~PR_DMA_bm; DMA.CTRL |= DMA_ENABLE_bm; DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_TCD1_CCA_gc; /* Address of Timer D1 CNT base is 0x0960. */ DMA.CH0.SRCADDR0 = 0x60; DMA.CH0.SRCADDR1 = 0x09; DMA.CH0.SRCADDR2 = 0x00; DMA.CH0.DESTADDR0 = ((uint16_t)&variable_for_sram_error) & 0xFF; DMA.CH0.DESTADDR1 = (((uint16_t)&variable_for_sram_error) >> 8) & 0xFF; DMA.CH0.DESTADDR2 = 0x00; DMA.CH0.CTRLA = DMA_CH_BURSTLEN_2BYTE_gc | DMA_CH_REPEAT_bm | DMA_CH_ENABLE_bm; break; case 4: /* Enter infinite loop */ while (1) { } break; case 5: /* Set up ADC channel interrupt */ adc_set_callback(&ADCA, adc_foul_callback); adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf); adcch_read_configuration(&ADCA, ADC_CH2, &adcch_conf); adcch_enable_interrupt(&adcch_conf); adcch_write_configuration(&ADCA, ADC_CH2, &adcch_conf); break; case 6: /* Back */ break; case GFX_MONO_MENU_EVENT_EXIT: /* Fall through to default */ default: /* Nothing, go back. */ break; } }
/** * \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 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 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"); } }
/** * \brief This function initialize the ADCB,gets ADCB-CH0 offset and configure * ADCB-CH0 for oversampling * - ADCB-CH0 is configured in 12bit, signed differential mode without gain * - To read ADC offset, ADCB-Pin3(PB3) used as both +ve and -ve input * - After reading ADC offset,to start oversampling,ADCB +ve and -ve input * are configured */ void init_adc(void) { /* Initialize configuration structures */ adc_read_configuration(&ADCB, &adc_conf); adcch_read_configuration(&ADCB, ADC_CH0, &adc_ch_conf); /* Configure the ADCB module: * - Signed, 12-bit resolution * - External reference on AREFB pin. * - 250 KSPS ADC clock rate * - Manual conversion triggering * - Callback function */ adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12, ADC_REF_AREFB); adc_set_clock_rate(&adc_conf, 250000UL); adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0); adc_write_configuration(&ADCB, &adc_conf); adc_set_callback(&ADCB, &adc_handler); /* Configure ADC B channel 0 for offset calculation * - Differential mode without gain * - Selected Pin3 (PB3) as +ve and -ve input for offset calculation */ adcch_set_input(&adc_ch_conf, ADCCH_POS_PIN3, ADCCH_NEG_PIN3, 1); adcch_write_configuration(&ADCB, ADC_CH0, &adc_ch_conf); /* Enable ADCB */ adc_enable(&ADCB); /* Get ADC offset in to ADC_Offset variable and disable ADC */ adc_offset_one_sample = adc_offset_get_signed(); /* Find ADC_Offset for for total number of samples */ adc_offset = adc_offset_one_sample * ADC_OVER_SAMPLED_NUMBER; /* Disable ADC to configure for oversampling */ adc_disable(&ADCB); /* Configure the ADCB module for oversampling: * - Signed, 12-bit resolution * - External reference on AREFB pin. * - 250 KSPS ADC clock rate * - Free running mode on Channel0 ( First Channel) */ adc_set_conversion_trigger(&adc_conf, ADC_TRIG_FREERUN_SWEEP, 1, 0); adc_write_configuration(&ADCB, &adc_conf); /* Configure ADC B channel 0 for oversampling input * - Differential mode without gain * - Selected Pin1 (PB1) as +ve and Pin2 (PB2) as-ve input * - Conversion complete interrupt */ adcch_set_input(&adc_ch_conf, ADC_OVER_SAMP_POSTIVE_PIN, ADC_OVER_SAMP_NEGATIVE_PIN, 1); adcch_set_interrupt_mode(&adc_ch_conf, ADCCH_MODE_COMPLETE); adcch_enable_interrupt(&adc_ch_conf); adcch_write_configuration(&ADCB, ADC_CH0, &adc_ch_conf); /* Enable ADCB */ adc_enable(&ADCB); }