//! [callback_eic] static void eic_callback_to_clear_halt(void) { if (port_pin_get_input_level(CONF_FAULT_EIC_PIN)) { tcc_clear_status(&tcc_instance, TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0) | TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0)); } }
/** * \brief Retrieves the current module status. * * Retrieves the status of the module, giving overall state information. * * \param[in] module_inst Pointer to the TCC software instance struct * * \return Bitmask of \c TCC_STATUS_* flags. * * \retval TCC_STATUS_CHANNEL_MATCH_CAPTURE(n) Channel n match/capture has occured * \retval TCC_STATUS_CHANNEL_OUTPUT(n) Channel n match/capture output state * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) Non-recoverable fault x has occured * \retval TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) Recoverable fault n has occured * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) Non-recoverable fault x input present * \retval TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) Recoverable fault n input present * \retval TCC_STATUS_SYNC_READY None of register is syncing * \retval TCC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed * \retval TCC_STATUS_COUNTER_EVENT Timer counter event has occurred * \retval TCC_STATUS_COUNT_OVERFLOW Timer count value has overflowed * \retval TCC_STATUS_COUNTER_RETRIGGERED Timer counter has been retriggered * \retval TCC_STATUS_STOP Timer counter has been stopped * \retval TCC_STATUS_RAMP_CYCLE_INDEX Wave ramp index for cycle */ uint32_t tcc_get_status( struct tcc_module *const module_inst) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); uint32_t int_flags = module_inst->hw->INTFLAG.reg; uint32_t status_flags = module_inst->hw->STATUS.reg; uint32_t status = 0; int i; /* SYNC */ if (module_inst->hw->SYNCBUSY.reg == 0) { status |= TCC_STATUS_SYNC_READY; } /* Channels */ for (i = 0; i < TCC_NUM_CHANNELS; i++) { if (int_flags & TCC_INTFLAG_MC(i)) { status |= TCC_STATUS_CHANNEL_MATCH_CAPTURE(i); } if (status_flags & TCC_STATUS_CMP(i)) { status |= TCC_STATUS_CHANNEL_OUTPUT(i); } } /* Non-recoverable fault state */ if ((int_flags & TCC_INTFLAG_FAULT1) || (status_flags & TCC_STATUS_FAULT1)) { status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1); } if ((int_flags & TCC_INTFLAG_FAULT0) || (status_flags & TCC_STATUS_FAULT0)) { status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0); } /* Non-recoverable fault inputs */ if (status_flags & TCC_STATUS_FAULT0IN) { status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0); } if (status_flags & TCC_STATUS_FAULT1IN) { status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(1); } /* Recoverable fault state */ if ((int_flags & TCC_INTFLAG_FAULTB) || (status_flags & TCC_STATUS_FAULTB)) { status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1); } if ((int_flags & TCC_INTFLAG_FAULTA) || (status_flags & TCC_STATUS_FAULTA)) { status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0); } /* Recoverable fault inputs */ if (status_flags & TCC_STATUS_FAULTAIN) { status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(0); } if (status_flags & TCC_STATUS_FAULTBIN) { status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(1); } /* Check for TCC capture overflow */ if (int_flags & TCC_INTFLAG_ERR) { status |= TCC_STATUS_CAPTURE_OVERFLOW; } /* Check for TCC count counter */ if (int_flags & TCC_INTFLAG_CNT) { status |= TCC_STATUS_COUNTER_EVENT; } /* Check for TCC count retrigger */ if (int_flags & TCC_INTFLAG_TRG) { status |= TCC_STATUS_COUNTER_RETRIGGERED; } /* Check for TCC count overflow */ if (int_flags & TCC_INTFLAG_OVF) { status |= TCC_STATUS_COUNT_OVERFLOW; } /* Check for TCC count stop */ if (status_flags & TCC_STATUS_STOP) { status |= TCC_STATUS_STOPPED; } return status; }
/** * \internal * \brief Test Non-Recoverable Fault (FAULTx) * * This test uses TCC0 as a PWM generator (compare function). * EXTINT will be used to route fault input to TCC0. * * \param test Current test case. */ static void run_faultx_test(const struct test_case *test) { test_assert_true(test, tcc_init_success == true, "TCC initialization failed, skipping test"); /* Configure TCC module for PWM generation with fault */ tcc_reset(&tcc_test0_module); tcc_get_config_defaults(&tcc_test0_config, CONF_TEST_TCC0); tcc_test0_config.counter.period = 0x03FF; tcc_test0_config.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; tcc_test0_config.compare.match[TCC_MATCH_CAPTURE_CHANNEL_0] = 0x01FF; tcc_test0_config.wave_ext.non_recoverable_fault[TCC_WAVE_OUTPUT_0].output = TCC_FAULT_STATE_OUTPUT_1; tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); /* Configure TCC events for non-recoverable fault input */ struct tcc_events tcc_test_events; memset(&tcc_test_events, 0, sizeof(struct tcc_events)); tcc_test_events.on_input_event_perform_action[0] = true; tcc_test_events.input_config[0].modify_action = true; tcc_test_events.input_config[0].action = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT; tcc_enable_events(&tcc_test0_module, &tcc_test_events); tcc_enable(&tcc_test0_module); /* Configure IO pin to generate fault */ struct port_config config_pin; port_get_config_defaults(&config_pin); config_pin.direction = PORT_PIN_DIR_OUTPUT; port_pin_set_config(CONF_TEST_PIN_OUT, &config_pin); port_pin_set_output_level(CONF_TEST_PIN_OUT, true); /* Configure EIC to capture fault input */ struct extint_chan_conf config; extint_chan_get_config_defaults(&config); config.filter_input_signal = true; config.detection_criteria = EXTINT_DETECT_BOTH; config.gpio_pin = CONF_EIC_PIN; config.gpio_pin_mux = CONF_EIC_MUX; extint_chan_set_config(CONF_EIC_CHAN, &config); struct extint_events extint_test_events; memset(&extint_test_events, 0, sizeof(struct extint_events)); extint_test_events.generate_event_on_detect[CONF_EIC_CHAN] = true; extint_enable_events(&extint_test_events); /* Configure EVENTs to route fault input */ struct events_resource event_resource; struct events_config event_config; events_get_config_defaults(&event_config); event_config.generator = CONF_EVENT_GENERATOR_ID; event_config.path = EVENTS_PATH_ASYNCHRONOUS; events_allocate(&event_resource, &event_config); events_attach_user(&event_resource, CONF_EVENT_USER_ID_FAULTx); /* Clear halt status */ tcc_clear_status(&tcc_test0_module, TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0) | TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0)); uint32_t test_val1 = tcc_get_count_value(&tcc_test0_module); uint32_t test_val2 = tcc_get_count_value(&tcc_test0_module); /* Check TCC is running */ test_assert_true(test, test_val1 != test_val2, "The counter failed to stop on non-recoverable fault"); /* Set fault */ port_pin_set_output_level(CONF_TEST_PIN_OUT, false); /* Check fault state */ test_assert_true(test, TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0) & tcc_get_status(&tcc_test0_module), "The counter failed to detect non-recoverable fault"); /* Check TCC is running */ test_val1 = tcc_get_count_value(&tcc_test0_module); test_val2 = tcc_get_count_value(&tcc_test0_module); test_assert_true(test, test_val1 == test_val2, "The counter failed to stop on non-recoverable fault"); }