Ejemplo n.º 1
0
/**
 * \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);
}
Ejemplo n.º 2
0
/**
 * \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();
    }
}