/** * \brief Run all Class B tests * * Destructively test ADC and DAC; modules must be reinitialized for application * use. Then test the SRAM, CPU registers and CRC of Flash (if enabled). */ void oven_classb_run_tests(void) { oven_ui_set_status_leds(S_ORANGE); /* Tests started */ /* Test the DAC and ADC used in this application */ dac_enable(&DACB); adc_enable(&ADCA); classb_analog_io_test(&DACB, &ADCA); /* Disable interrupts globally. Normally one would disable * this also for the analog test, but to emulate an error * we allow interrupts during the analog test. */ cli(); for (uint8_t i = 0; i < CLASSB_NSECS; ++i) { classb_sram_test(); } /* Test the register file */ classb_register_test(); /* Test CRC Checksum */ /* Uncomment the code below and set a breakpoint on it, then press * F10/Step over to read the calculated checksum. Insert the value in * classb_precalculated_flash_crc at the top of this file and recompile * to get a working CRC check. */ /* checksum_test_flash = CLASSB_CRC32_Flash_HW (CRC_APP, 0, 0, * &classb_precalculated_flash_crc); */ sei(); /* Update status LED according to test results */ if (classb_error == CLASSB_ERROR_NONE) { oven_ui_set_status_leds(S_GREEN); } else { oven_ui_set_status_leds(S_RED); } }
/** * \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(); } }