/** * \brief Run tests and turn on power to simulated oven plate * * This functions runs some class B tests, reinitializes Timer/Counters, ADC and * DAC used by the oven, then turns on and starts monitoring of periodic tests. */ static void ovenctl_turn_on_plate(void) { /* Store current DAC value since the analog IO test is destructive */ uint16_t dac_val = DACB.CH0DATA; /* Run tests -- classb_error is updated if any of them fail */ oven_classb_run_tests(); /* Initialize the ADC and DAC modules, as well as the Timer/Counters * we use to emulate real world application. */ main_init_adc_dac(); DACB.CH0DATA = dac_val; main_init_tc(); /* Enable and set up timer for periodic temperature checking */ tc_enable(&OVEN_PERIODIC_TEMPTEST_TC); /* Set timer to overflow every 600ms: 24MHz / (1024 * 14063) = 0.6s */ tc_write_clock_source(&OVEN_PERIODIC_TEMPTEST_TC, TC_CLKSEL_DIV1024_gc); tc_write_period(&OVEN_PERIODIC_TEMPTEST_TC, 14062); /* Set up temperature check as interrupt callback function, then enable * interrupts */ tc_set_overflow_interrupt_callback(&OVEN_PERIODIC_TEMPTEST_TC, ovenctl_periodic_temperature_sanity_check); tc_set_overflow_interrupt_level(&OVEN_PERIODIC_TEMPTEST_TC, TC_OVFINTLVL_LO_gc); /* Enable monitoring of the periodic temperature check */ classb_intmon_set_state(TEMP_SANITY_TEST, M_ENABLE); /* Enable and set up timer for periodic execution of Class B tests */ tc_enable(&OVEN_PERIODIC_CLASSB_TC); /* Set timer to overflow every second: 24MHz / (1024 * 23438) = 1s */ tc_write_clock_source(&OVEN_PERIODIC_CLASSB_TC, TC_CLKSEL_DIV1024_gc); tc_write_period(&OVEN_PERIODIC_CLASSB_TC, 23437); /* Set up periodic class B test as interrupt callback function, then * enable interrupts */ tc_set_overflow_interrupt_callback(&OVEN_PERIODIC_CLASSB_TC, ovenctl_periodic_classb_tests); tc_set_overflow_interrupt_level(&OVEN_PERIODIC_CLASSB_TC, TC_OVFINTLVL_LO_gc); /* Enable monitoring of the periodic temperature check */ classb_intmon_set_state(PER_CLASSB_TESTS, M_ENABLE); }
/** * \brief Main function. * * Initializes the board, displays splash screens, then launches application. * * If the application exits (fails), the error is written to display and an * infinite loop with watchdog resets is entered. */ int main(void) { /* Holds state of the QTouch button */ enum pot_t potstate = POT_OFF; /* Last state of the QTouch button for change detection */ enum pot_t last_potstate = POT_OFF; /* Holds user-selected power-setting */ uint8_t wattage = 0; /* Last power-setting for change detection */ uint8_t last_wattage = 0; /* Whether the plate element is/should be actuated */ bool power = false; /* Last power setting for change detection */ bool last_power = false; /* Last time a simulation step was executed */ uint32_t last_sim_step; /* Last time a control step was executed */ uint32_t last_ctl_step; /* The WDT was just reset by the WDT functional test*/ classb_last_wdt_reset = rtc_get_time(); last_sim_step = classb_last_wdt_reset; last_ctl_step = classb_last_wdt_reset; sysclk_init(); board_init(); pmic_init(); gfx_mono_init(); touch_init(); main_init_rtc32(); cpu_irq_enable(); /* Enable display backlight */ ioport_set_pin_level(LCD_BACKLIGHT_ENABLE_PIN, LCD_BACKLIGHT_ENABLE_LEVEL); /* If an error was detected, skip directly to displaying it */ if (classb_error) { goto display_error; } /* Check if required jumpers are mounted, show explanation if not */ if (!main_check_jumpers()) { show_explain_splash(); } /* Display a splash screen showing button functions */ show_button_splash(); /* Initialize the ADC, DAC and Timer/Counter modules that are used to * emulate real world objects. */ main_init_adc_dac(); main_init_tc(); /* Initialize subsystems used for Class B testing */ oven_classb_init_tests(); /* Reset the simulation states */ oven_plant_init(); /* Clear screen */ gfx_mono_draw_filled_rect(0, 0, 128, 32, GFX_PIXEL_CLR); /* Draw the initial axis system */ oven_ui_draw_axis(); /* Draw the user interface */ oven_ui_update_graphics(potstate, wattage, power); /* Run simulation as long as no error is detected in class B tests */ while (!classb_error) { uint32_t current_time; oven_wdt_periodic_reset(); current_time = rtc_get_time(); /* Add power on SW1 press, wrap at 20 */ if (oven_ui_power_button_is_pressed()) { wattage = (wattage + 5) % 20; } /* Check QTouch sensor and map this to `potstate`. This is * needed both for simulation and for the control routine. */ potstate = (!touch_key_is_pressed()) ? POT_ON : POT_OFF; /* Execute control routine periodically */ if (current_time > (last_ctl_step + OVEN_CTL_STEP_TIME)) { ovenctl_execute_control_step(current_time, &wattage, &power, potstate); last_ctl_step = current_time; } /* Execute simulation step periodically */ if (current_time > (last_sim_step + OVEN_SIM_STEP_TIME)) { main_execute_simulation_step(current_time, potstate); last_sim_step = current_time; } /* Update graphics on wattage, power or pot on/off change */ if ((potstate != last_potstate) || (power != last_power) || (wattage != last_wattage)) { oven_ui_update_graphics(potstate, wattage, power); } /* Update variable states for change detection on next loop * iteration. */ last_power = power; last_wattage = wattage; last_potstate = potstate; /* If back/menu button is pressed, pause simulation and test * timers, and show menu. */ if (oven_ui_back_button_is_pressed()) { /* Disable interrupt monitoring, if enabled */ classb_intmon_set_state(TEMP_SANITY_TEST, M_DISABLE); classb_intmon_set_state(PER_CLASSB_TESTS, M_DISABLE); OVEN_PERIODIC_TEMPTEST_TC.CTRLA &= ~TC1_CLKSEL_gm; OVEN_PERIODIC_CLASSB_TC.CTRLA &= ~TC0_CLKSEL_gm; /* Show the error insertion menu */ oven_classb_error_insertion(); /* Re-enable timers upon return */ OVEN_PERIODIC_CLASSB_TC.CTRLA |= TC_CLKSEL_DIV1024_gc; /* If user did not induce an error in the temperature * test timing, re-enable it correctly. */ if ((OVEN_PERIODIC_TEMPTEST_TC.CTRLA & TC1_CLKSEL_gm) == TC_CLKSEL_OFF_gc) { OVEN_PERIODIC_TEMPTEST_TC.CTRLA |= TC_CLKSEL_DIV1024_gc; } /* Re-enable interrupt monitoring if the oven is * supposed to be on, i.e., they were enabled before. */ if (wattage > 0) { classb_intmon_set_state(TEMP_SANITY_TEST, M_ENABLE); classb_intmon_set_state(PER_CLASSB_TESTS, M_ENABLE); } /* Reset UI */ gfx_mono_draw_filled_rect(0, 0, 128, 32, GFX_PIXEL_CLR); oven_ui_draw_axis(); oven_ui_update_graphics(potstate, wattage, power); } } display_error: /* Show red status LED and write the error on display */ oven_ui_set_status_leds(S_RED); oven_classb_display_error(); /* Enter infinite loop of watchdog resets so user can read display */ while (true) { oven_wdt_periodic_reset(); } }