// Configure all of the LED ports as PWM outputs void configure_LED_PWM(void) { struct tcc_config config_tcc; tcc_get_config_defaults(&config_tcc, TCC0); config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[0] = 0; config_tcc.compare.match[1] = 0; config_tcc.compare.match[2] = 0; config_tcc.compare.match[3] = 0; config_tcc.pins.enable_wave_out_pin[0] = true; config_tcc.pins.enable_wave_out_pin[1] = true; config_tcc.pins.enable_wave_out_pin[2] = true; config_tcc.pins.enable_wave_out_pin[3] = true; config_tcc.pins.wave_out_pin[0] = PIN_PA21F_TCC0_WO7; config_tcc.pins.wave_out_pin[1] = PIN_PA20F_TCC0_WO6; config_tcc.pins.wave_out_pin[2] = PIN_PA15F_TCC0_WO5; config_tcc.pins.wave_out_pin[3] = PIN_PA14F_TCC0_WO4; config_tcc.pins.wave_out_pin_mux[0] = MUX_PA21F_TCC0_WO7; config_tcc.pins.wave_out_pin_mux[1] = MUX_PA20F_TCC0_WO6; config_tcc.pins.wave_out_pin_mux[2] = MUX_PA15F_TCC0_WO5; config_tcc.pins.wave_out_pin_mux[3] = MUX_PA14F_TCC0_WO4; tcc_init(&tcc0, TCC0, &config_tcc); tcc_enable(&tcc0); tcc_get_config_defaults(&config_tcc, TCC1); config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[0] = 0; config_tcc.compare.match[1] = 0; config_tcc.pins.enable_wave_out_pin[0] = true; config_tcc.pins.enable_wave_out_pin[1] = true; config_tcc.pins.wave_out_pin[0] = PIN_PA06E_TCC1_WO0; config_tcc.pins.wave_out_pin[1] = PIN_PA07E_TCC1_WO1; config_tcc.pins.wave_out_pin_mux[0] = MUX_PA06E_TCC1_WO0; config_tcc.pins.wave_out_pin_mux[1] = MUX_PA07E_TCC1_WO1; tcc_init(&tcc1, TCC1, &config_tcc); tcc_enable(&tcc1); tcc_get_config_defaults(&config_tcc, TCC2); config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[0] = 0; config_tcc.compare.match[1] = 0; config_tcc.pins.enable_wave_out_pin[0] = true; config_tcc.pins.enable_wave_out_pin[1] = true; config_tcc.pins.wave_out_pin[0] = PIN_PA16E_TCC2_WO0; config_tcc.pins.wave_out_pin[1] = PIN_PA17E_TCC2_WO1; config_tcc.pins.wave_out_pin_mux[0] = MUX_PA16E_TCC2_WO0; config_tcc.pins.wave_out_pin_mux[1] = MUX_PA17E_TCC2_WO1; tcc_init(&tcc2, TCC2, &config_tcc); tcc_enable(&tcc2); }
/** * \internal * \brief Test initializing and resetting TCC and reinitialize * * This test tests the software reset of a TCC by the use of the * tcc_reset(). * * \param test Current test case. */ static void run_reset_test(const struct test_case *test) { test_assert_true(test, tcc_init_success == true, "TCC initialization failed, skipping test"); /* Configure TCC module and run test*/ tcc_reset(&tcc_test0_module); tcc_get_config_defaults(&tcc_test0_config, CONF_TEST_TCC0); tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); tcc_enable(&tcc_test0_module); while (tcc_is_syncing(&tcc_test0_module)) { /* Synchronize enable */ } test_assert_true(test, tcc_test0_module.hw->CTRLA.reg & TCC_CTRLA_ENABLE, "Failed first enable of TCC"); /* Reset and test if both TCC modules are disabled after reset */ tcc_reset(&tcc_test0_module); while (tcc_is_syncing(&tcc_test0_module)) { /* Synchronize reset */ } test_assert_false(test, tcc_test0_module.hw->CTRLA.reg & TCC_CTRLA_ENABLE, "Failed reset of TCC TEST"); }
//! [setup] static void configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, TCC0); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.clock_source = GCLK_GENERATOR_1; config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV64; config_tcc.counter.period = 2000; config_tcc.compare.match[0] = 900; config_tcc.compare.match[1] = 930; config_tcc.compare.match[2] = 1100; config_tcc.compare.match[3] = 1250; //! [setup_change_config] //! [setup_set_config] tcc_init(&tcc_instance, TCC0, &config_tcc); //! [setup_set_config] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] }
//! [setup] static void _configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[CONF_PWM_CHANNEL] = (0xFFFF / 4); //! [setup_change_config] //! [setup_change_config_pwm] config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true; config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT] = CONF_PWM_OUT_PIN; config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT] = CONF_PWM_OUT_MUX; //! [setup_change_config_pwm] //! [setup_set_config] tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); //! [setup_set_config] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] }
/** * \internal * \brief Test of tcc_init() and tcc_get_config_defaults() * * This test is used to initialize the tccx_module structs and associate the * given hw module with the struct. This test should be run at the very * beginning of testing as other tests depend on the result of this test. */ static void run_init_test(const struct test_case *test) { tcc_get_config_defaults(&tcc_test0_config, CONF_TEST_TCC0); enum status_code test1 = tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); tcc_get_config_defaults(&tcc_test1_config, CONF_TEST_TCC1); enum status_code test2 = tcc_init(&tcc_test1_module, CONF_TEST_TCC1, &tcc_test1_config); if ((test1 == STATUS_OK) && (test2 == STATUS_OK)) { tcc_init_success = true; } test_assert_true(test, (test2 == STATUS_OK) && (test1 == STATUS_OK), "Failed to initialize modules"); }
/** * \internal * \brief Test the callback API * * This test tests the callback API for the TCC. The TCC uses one-shot mode. * * \param test Current test case. */ static void run_callback_test(const struct test_case *test) { test_assert_true(test, tcc_init_success == true, "TCC initialization failed, skipping test"); test_assert_true(test, basic_functionality_test_passed == true, "Basic functionality test failed, skipping test"); /* Setup TCC0 */ tcc_reset(&tcc_test0_module); tcc_get_config_defaults(&tcc_test0_config, CONF_TEST_TCC0); tcc_test0_config.counter.period = 4000; tcc_test0_config.compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ; tcc_test0_config.compare.match[TCC_MATCH_CAPTURE_CHANNEL_0] = 3990; tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); /* Setup callbacks */ tcc_register_callback(&tcc_test0_module, tcc_callback_function, TCC_CALLBACK_CHANNEL_0); tcc_enable_callback(&tcc_test0_module, TCC_CALLBACK_CHANNEL_0); tcc_enable(&tcc_test0_module); while ((tcc_get_status(&tcc_test0_module) & TCC_STATUS_COUNT_OVERFLOW) == 0) { /* Wait for overflow of TCC1 */ } tcc_disable(&tcc_test0_module); tcc_clear_status(&tcc_test0_module, TCC_STATUS_COUNT_OVERFLOW); test_assert_true(test, callback_function_entered == 1, "The callback has failed callback_function_entered = %d", (int)callback_function_entered); /* Test disable callback function */ tcc_disable_callback(&tcc_test0_module, TCC_CALLBACK_CHANNEL_0); tcc_set_count_value(&tcc_test0_module, 0x00000000); tcc_enable(&tcc_test0_module); while (!(tcc_get_status(&tcc_test0_module) & TCC_STATUS_COUNT_OVERFLOW)) { /* Wait for overflow of TC1*/ } /* Test tcc_disable() */ tcc_disable(&tcc_test0_module); test_assert_true(test, callback_function_entered == 1, "Disabling the callback has failed"); }
// // TCC Configuration Function static void tcc_configure_function(void){ struct tcc_config config_tcc; // Configuration structure tcc_get_config_defaults(&config_tcc, TCC0); // Initialize with known values // Custom Counter Configuration config_tcc.counter.clock_source = GCLK_GENERATOR_0; config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV64; config_tcc.counter.period = 750000UL; tcc_init(&tcc_instance, TCC0, &config_tcc); // Commit Counter Configuration tcc_enable(&tcc_instance); // Enable this counter instance }
void hitecServoInit(void) { struct tcc_config config_tcc; tcc_get_config_defaults(&config_tcc, TCC0); config_tcc.counter.clock_source = GCLK_GENERATOR_3; config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1; config_tcc.counter.period = HITECSERVO_TIME_PERIOD; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.pins.enable_wave_out_pin[6] = true; config_tcc.pins.wave_out_pin[6] = PIN_PB12F_TCC0_WO6 ; config_tcc.pins.wave_out_pin_mux[6] = MUX_PB12F_TCC0_WO6; tcc_init(&tcc_instance, TCC0, &config_tcc); tcc_enable(&tcc_instance); }
/** * \brief Configure Timer module. */ static void configure_timer(void) { /** * Timer period is 1s = Prescaler(256) * Period(46875) / Clock(12Mhz). */ struct tcc_config tcc_conf; tcc_get_config_defaults(&tcc_conf, TCC0); tcc_conf.counter.period = 46875 * TIMER_CB_INTERVAL; tcc_conf.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV256; tcc_init(&tempTccModule, TCC0, &tcc_conf); /* Register timer callback for the Request RSSI. */ tcc_register_callback(&tempTccModule, timer_cb, TCC_CALLBACK_CHANNEL_3); tcc_enable(&tempTccModule); }
//! [setup] static void configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[CONF_PWM_CHANNEL] = 0xFFFF; //! [setup_change_config] //! [setup_change_config_faults] config_tcc.wave_ext.recoverable_fault[CONF_PWM_CHANNEL].source = TCC_FAULT_SOURCE_ENABLE; config_tcc.wave_ext.recoverable_fault[CONF_PWM_CHANNEL].halt_action = TCC_FAULT_HALT_ACTION_SW_HALT; //! [setup_change_config_faults] //! [setup_change_config_pwm] config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true; config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT] = CONF_PWM_OUT_PIN; config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT] = CONF_PWM_OUT_MUX; //! [setup_change_config_pwm] //! [setup_set_config] tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); //! [setup_set_config] //! [setup_events] struct tcc_events events; memset(&events, 0, sizeof(struct tcc_events)); //! [setup_events] //! [setup_change_events_faults] events.on_event_perform_channel_action[CONF_PWM_CHANNEL] = true; //! [setup_change_events_faults] //! [setup_events_enable] tcc_enable_events(&tcc_instance, &events); //! [setup_events_enable] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] }
/** * \internal * \brief Test basic functionality. * * This test tests the basic functionality for the TCC. It tests the following * functions: * - tcc_get_count_value() * - tcc_stop_counter() * - tcc_set_count_value() * - tcc_restart_counter() * * \param test Current test case. */ static void run_basic_functionality_test(const struct test_case *test) { test_assert_true(test, tcc_init_success == true, "TCC initialization failed, skipping test"); /* Setup TCC0 */ tcc_reset(&tcc_test0_module); tcc_get_config_defaults(&tcc_test0_config, CONF_TEST_TCC0); tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); tcc_enable(&tcc_test0_module); /* Test tcc_get_count_value() */ uint32_t test_val0 = tcc_get_count_value(&tcc_test0_module); test_assert_true(test, test_val0 > 0, "The tcc_get_count_value() returned 0 expected larger value"); /* Test tcc_stop_counter() */ tcc_stop_counter(&tcc_test0_module); uint32_t test_val1 = tcc_get_count_value(&tcc_test0_module); uint32_t test_val2 = tcc_get_count_value(&tcc_test0_module); test_assert_true(test, test_val1 == test_val2, "The counter failed to stop"); /* Test tcc_set_count_value() */ tcc_set_count_value(&tcc_test0_module, 0x00FF); test_assert_true(test, tcc_get_count_value(&tcc_test0_module) == 0x00FF, "tcc_set_count_value() have failed"); /* Test tcc_start_counter() */ tcc_restart_counter(&tcc_test0_module); test_assert_true(test, tcc_get_count_value(&tcc_test0_module) > 0x00FF, "tcc_get_count_value() have failed"); basic_functionality_test_passed = true; }
//! [setup] static void configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.period = 0xFFFF; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[CONF_PWM_CHANNEL] = 0xFFFF; //! [setup_change_config] //! [setup_change_config_faults] config_tcc.wave_ext.non_recoverable_fault[0].output = TCC_FAULT_STATE_OUTPUT_1; //! [setup_change_config_faults] //! [setup_change_config_pwm] config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true; config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT] = CONF_PWM_OUT_PIN; config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT] = CONF_PWM_OUT_MUX; //! [setup_change_config_pwm] //! [setup_set_config] tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); //! [setup_set_config] //! [setup_events] struct tcc_events events; memset(&events, 0, sizeof(struct tcc_events)); //! [setup_events] //! [setup_change_events_faults] events.on_input_event_perform_action[0] = true; events.input_config[0].modify_action = true; events.input_config[0].action = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT; //! [setup_change_events_faults] //! [setup_events_enable] tcc_enable_events(&tcc_instance, &events); //! [setup_events_enable] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] }
void init_pwm(int HWtimer,int pin0, int mux0, int pin1, int mux1){ struct tcc_config config_tcc; tcc_get_config_defaults(&config_tcc, hw[HWtimer]); config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.counter.period = 0xFFFF; if(pin0 != 0 && mux0 != 0){ config_tcc.pins.enable_wave_out_pin[0] = true; config_tcc.pins.wave_out_pin[0] = pin0; config_tcc.pins.wave_out_pin_mux[0] = mux0; } if(pin1 != 0 && mux0 != 0){ config_tcc.pins.enable_wave_out_pin[1] = true; config_tcc.pins.wave_out_pin[1] = pin1; config_tcc.pins.wave_out_pin_mux[1] = mux1; } tcc_init(&tcc_instance[HWtimer], hw[HWtimer], &config_tcc); tcc_enable(&tcc_instance[HWtimer]); }
void sw_timer_init(struct sw_timer_module *const module_inst, struct sw_timer_config *const config) { struct tcc_config tcc_conf; struct tcc_module *tcc_module; Tcc *hw[] = TCC_INSTS; Assert(module_inst); Assert(config); Assert(config->tcc_dev < TCC_INST_NUM); Assert(config->tcc_callback_channel < TCC_NUM_CHANNELS); module_inst->accuracy = config->accuracy; /* Start the TCC module. */ tcc_module = &module_inst->tcc_inst; tcc_get_config_defaults(&tcc_conf, hw[config->tcc_dev]); tcc_conf.counter.period = system_cpu_clock_get_hz() / (64 * 1000 / config->accuracy); tcc_conf.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV64; tcc_init(tcc_module, hw[config->tcc_dev], &tcc_conf); tcc_register_callback(tcc_module, sw_timer_tcc_callback, config->tcc_callback_channel + TCC_CALLBACK_CHANNEL_0); tcc_enable_callback(tcc_module, config->tcc_callback_channel + TCC_CALLBACK_CHANNEL_0); }
//! [setup] static void configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1024; config_tcc.counter.period = 8000; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.match[CONF_PWM_CHANNEL] = (8000 / 4); //! [setup_change_config] //! [setup_change_config_pwm] config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true; config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT] = CONF_PWM_OUT_PIN; config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT] = CONF_PWM_OUT_MUX; //! [setup_change_config_pwm] //! [setup_set_config] tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); //! [setup_set_config] //! [setup_set_buffering] tcc_set_compare_value(&tcc_instance, (enum tcc_match_capture_channel)CONF_PWM_CHANNEL, 8000*3/4); tcc_enable_circular_buffer_compare(&tcc_instance, (enum tcc_match_capture_channel)CONF_PWM_CHANNEL); //! [setup_set_buffering] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] }
/** * \internal * \brief Test capture and compare * * This test uses TCC0 as a PWM generator (compare function). TCC1 will be set * to capture the signal from TCC0 to test the capture functionality. * * \param test Current test case. */ static void run_capture_and_compare_test(const struct test_case *test) { test_assert_true(test, tcc_init_success == true, "TCC initialization failed, skipping test"); test_assert_true(test, callback_function_entered == 1, "The callback test has failed, skipping test"); /* Configure TCC module for PWM generation */ 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; /* Calculate the theoretical PWM frequency & duty */ uint32_t frequency_output, duty_output; frequency_output = system_clock_source_get_hz(SYSTEM_CLOCK_SOURCE_OSC8M) / (0x03FF+1); /* This value is depend on the WaveGeneration Mode */ duty_output = (uint32_t)(tcc_test0_config.compare.match[TCC_MATCH_CAPTURE_CHANNEL_0] * 100) / tcc_test0_config.counter.period; tcc_test0_config.pins.enable_wave_out_pin[TCC_MATCH_CAPTURE_CHANNEL_0] = true; tcc_test0_config.pins.wave_out_pin[TCC_MATCH_CAPTURE_CHANNEL_0] = CONF_TEST_PIN_OUT; tcc_test0_config.pins.wave_out_pin_mux[TCC_MATCH_CAPTURE_CHANNEL_0] = CONF_TEST_PIN_MUX; tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); tcc_register_callback(&tcc_test0_module, tcc_callback_function, TCC_CALLBACK_CHANNEL_0); tcc_enable_callback(&tcc_test0_module, TCC_CALLBACK_CHANNEL_0); /* Configure TCC module for capture */ tcc_reset(&tcc_test1_module); tcc_get_config_defaults(&tcc_test1_config, CONF_TEST_TCC1); tcc_test1_config.counter.period = 0xFFFF; tcc_test1_config.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1; tcc_test1_config.capture.channel_function[CONF_CAPTURE_CHAN_0] = TCC_CHANNEL_FUNCTION_CAPTURE; tcc_test1_config.capture.channel_function[CONF_CAPTURE_CHAN_1] = TCC_CHANNEL_FUNCTION_CAPTURE; tcc_init(&tcc_test1_module, CONF_TEST_TCC1, &tcc_test1_config); struct tcc_events tcc_events = { .on_input_event_perform_action[1] = true, .input_config[1].modify_action = true, .input_config[1].action = TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE }; tcc_enable_events(&tcc_test1_module, &tcc_events); /* Configure external interrupt controller */ struct extint_chan_conf extint_chan_config; extint_chan_config.gpio_pin = CONF_EIC_PIN; extint_chan_config.gpio_pin_mux = CONF_EIC_MUX; extint_chan_config.gpio_pin_pull = EXTINT_PULL_UP; extint_chan_config.wake_if_sleeping = false; extint_chan_config.filter_input_signal = false; extint_chan_config.detection_criteria = EXTINT_DETECT_HIGH; extint_chan_set_config(CONF_EIC_CHAN, &extint_chan_config); /* Configure external interrupt module to be event generator */ struct extint_events extint_event_conf; extint_event_conf.generate_event_on_detect[CONF_EIC_CHAN] = true; extint_enable_events(&extint_event_conf); /* Configure event system */ struct events_resource event_res; /* Configure channel */ struct events_config config; events_get_config_defaults(&config); config.generator = CONF_EVENT_GENERATOR_ID; config.edge_detect = EVENTS_EDGE_DETECT_NONE; config.path = EVENTS_PATH_ASYNCHRONOUS; events_allocate(&event_res, &config); /* Configure user */ events_attach_user(&event_res, CONF_EVENT_USED_ID); /* Enable TCC modules */ tcc_enable(&tcc_test1_module); tcc_enable(&tcc_test0_module); uint16_t period_after_capture = 0; uint16_t pulse_width_after_capture = 0; uint32_t capture_frequency = 0; uint32_t capture_duty = 0; while (callback_function_entered < 4) { period_after_capture = tcc_get_capture_value(&tcc_test1_module, TCC_MATCH_CAPTURE_CHANNEL_0); pulse_width_after_capture = tcc_get_capture_value(&tcc_test1_module, TCC_MATCH_CAPTURE_CHANNEL_1); } if(period_after_capture != 0) { capture_frequency = system_clock_source_get_hz(SYSTEM_CLOCK_SOURCE_OSC8M) / period_after_capture; capture_duty = (uint32_t)(pulse_width_after_capture) * 100 / period_after_capture; } test_assert_true(test, (capture_frequency <= (frequency_output * (100 + CONF_TEST_TOLERANCE) / 100)) && \ (capture_frequency >= (frequency_output * (100 - CONF_TEST_TOLERANCE) / 100)) && \ (capture_duty <= (duty_output * (100 + CONF_TEST_TOLERANCE) / 100)) && \ (capture_duty >= (duty_output * (100 - CONF_TEST_TOLERANCE) / 100)) \ ,"The result of Capture is wrong, captured frequency: %ldHz, captured duty: %ld%%", capture_frequency, capture_duty ); } /** * \internal * \brief Test Recoverable Fault (FAULTn) * * 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_faultn_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.recoverable_fault[TCC_MATCH_CAPTURE_CHANNEL_0].source = TCC_FAULT_SOURCE_ENABLE; tcc_test0_config.wave_ext.recoverable_fault[TCC_MATCH_CAPTURE_CHANNEL_0].halt_action = TCC_FAULT_HALT_ACTION_SW_HALT; tcc_init(&tcc_test0_module, CONF_TEST_TCC0, &tcc_test0_config); /* Configure TCC events for recoverable fault input */ struct tcc_events tcc_test_events; memset(&tcc_test_events, 0, sizeof(struct tcc_events)); tcc_test_events.on_event_perform_channel_action[TCC_MATCH_CAPTURE_CHANNEL_0] = true; 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_FAULTn); /* Clear halt status */ tcc_clear_status(&tcc_test0_module, TCC_STATUS_RECOVERABLE_FAULT_PRESENT(0) | TCC_STATUS_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 recoverable fault"); /* Set fault */ port_pin_set_output_level(CONF_TEST_PIN_OUT, false); /* Check fault state */ test_assert_true(test, TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0) & tcc_get_status(&tcc_test0_module), "The counter failed to detect 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 recoverable fault"); }
/** * \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"); }
static void configure_tcc_ramp2c_mode(void) { struct tcc_config config_tcc; delay_init(); tcc_get_config_defaults(&config_tcc, TCC0); /* Set up output pins */ /* CC2 will be included to generate ramp output WO[0] in RAMP2C mode*/ config_tcc.pins.enable_wave_out_pin[0] = true; config_tcc.pins.wave_out_pin[0] = PIN_PA04E_TCC0_WO0; config_tcc.pins.wave_out_pin_mux[0] = MUX_PA04E_TCC0_WO0; /* CC1 will be included to generate ramp output WO[1] RAMP2C mode */ config_tcc.pins.enable_wave_out_pin[1] = true; config_tcc.pins.wave_out_pin[1] = PIN_PA09E_TCC0_WO1; config_tcc.pins.wave_out_pin_mux[1] = MUX_PA09E_TCC0_WO1; /* Generator 1 as clock source */ config_tcc.counter.clock_source = GLCK_SOURCE; config_tcc.counter.clock_prescaler = TCC_CLOCK_DIVIDER; /* Set up initial period */ config_tcc.counter.period = PER_Value; /* set CC0 */ /* CC0 will act as ramp A top in RAMP2C mode */ config_tcc.compare.match[0] = CC0_Value; /* set compare reg CC1 & CC2 in RAMP2C mode */ config_tcc.compare.match[1] = CC1_Value; config_tcc.compare.match[2] = CC2_Value; /* Set up polarity output ramp */ config_tcc.compare.wave_polarity[1] = 1; config_tcc.compare.wave_polarity[2] = 1; /* Normal PWM in RAMP2 mode */ config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.wave_ramp = TCC_RAMP_RAMP2; #if (ENABLE_FAULT_BALNKING == true) /* Set up recoverable fault A on virtual pulse */ config_tcc.wave_ext.recoverable_fault[0].qualification = true; config_tcc.wave_ext.recoverable_fault[0].source = TCC_FAULT_SOURCE_ENABLE; config_tcc.wave_ext.recoverable_fault[0].restart = true; config_tcc.wave_ext.recoverable_fault[0].blanking_cycles = 10; config_tcc.wave_ext.recoverable_fault[0].blanking = TCC_FAULT_BLANKING_RISING_EDGE; /* Set up recoverable fault A on on WO */ config_tcc.wave_ext.recoverable_fault[1].qualification = true; config_tcc.wave_ext.recoverable_fault[1].source = TCC_FAULT_SOURCE_ENABLE; config_tcc.wave_ext.recoverable_fault[1].restart = true; config_tcc.wave_ext.recoverable_fault[1].blanking_cycles = 10; config_tcc.wave_ext.recoverable_fault[1].blanking = TCC_FAULT_BLANKING_RISING_EDGE; #endif /* Initialize with given configuration */ tcc_init(&tcc_inst, TCC0, &config_tcc); /* RAMP2C mode */ while(TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE); TCC0->WAVE.bit.RAMP = TCC_WAVEB_RAMPB_RAMP2C_Val; while(TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE); #if (ENABLE_FAULT_BALNKING == true) /* set fault blanking prescaler*/ tcc_inst.hw->FCTRLA.reg |= 1 << BLANKPRESC; tcc_inst.hw->FCTRLB.reg |= 1 << BLANKPRESC; /* Enable recoverable fault event */ struct tcc_events events; memset(&events, 0, sizeof(struct tcc_events)); events.on_event_perform_channel_action[0] = true; events.on_event_perform_channel_action[1] = true; tcc_enable_events(&tcc_inst, &events); #endif /* Enable TCC */ tcc_enable(&tcc_inst); }
//! [setup] static void configure_tcc(void) { //! [setup_config] struct tcc_config config_tcc; //! [setup_config] //! [setup_config_defaults] tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); //! [setup_config_defaults] //! [setup_change_config] config_tcc.counter.period = 0x1000; config_tcc.compare.channel_function[CONF_TCC_CAPTURE_CHANNEL] = TCC_CHANNEL_FUNCTION_CAPTURE; config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; config_tcc.compare.wave_polarity[CONF_PWM_CHANNEL] = TCC_WAVE_POLARITY_0; config_tcc.compare.match[CONF_PWM_CHANNEL] = compare_values[2]; //! [setup_change_config] //! [setup_change_config_pwm] config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true; config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT] = CONF_PWM_OUT_PIN; config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT] = CONF_PWM_OUT_MUX; //! [setup_change_config_pwm] //! [setup_set_config] tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); //! [setup_set_config] //! [setup_events] struct tcc_events events_tcc = { .input_config[0].modify_action = false, .input_config[1].modify_action = false, .output_config.modify_generation_selection = false, .generate_event_on_channel[CONF_PWM_CHANNEL] = true, .on_event_perform_channel_action[CONF_TCC_CAPTURE_CHANNEL] = true }; tcc_enable_events(&tcc_instance, &events_tcc); //! [setup_events] //! [setup_event_sys] config_event_for_capture(); //! [setup_event_sys] //! [setup_dma] config_dma_for_capture(); config_dma_for_wave(); //! [setup_dma] //! [setup_enable] tcc_enable(&tcc_instance); //! [setup_enable] } //! [setup] int main(void) { system_init(); //! [setup_init] configure_tcc(); //! [setup_init] //! [main] //! [main_loop] while (true) { /* Infinite loop */ } //! [main_loop] //! [main] }