SAMC PWM capture - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: April 06, 2023, 03:02:57 pm
content: Now I knew that this would not be the simplest to set up but now I am dumbfounded.I set up the external interrupt controller (EIC) so that it generates an event on both pulses.I set up the event system to route the events through.I set up a counter to capture the pulse and the period.The result is that I always get the same value appear in both capture registers even with a 20% duty. I can't fathom this. I have tried various settings but it's either some number or 0 and both capture registers are always the same value.SetupCode:void tc_pwmCapture_setup(Tc * instance , tc_tcc_prescaler_type prescaler , uint8_t portpin , uint8_t eventChannel ) // must come before EIC is enabled{// setup pin in external interrupt controllereic_pin_setup(portpin , eitherEdge , noInterrupt , eventEnable ) ;EIC->ASYNCH.reg |= 0x1 << ( portpin % 16) ;// event user channel setupclock_setup((eventChannel + 6 ), GCLK0) ;if (instance == TC0){EVSYS->USER.reg = eventChannel +1 ;}if (instance == TC1){EVSYS->USER.reg = eventChannel + 1 ;}if (instance == TC2){EVSYS->USER.reg = eventChannel + 1 ;}if (instance == TC3){EVSYS->USER.reg = eventChannel + 1 ;}if (instance == TC4){EVSYS->USER.reg = eventChannel + 1 ;}// event generator channel setupEVSYS->CHANNEL.reg = 0x2 << 8 | ((portpin % 16U) + 0x0E ) | 0x0 << 10 ;// setup counterinstance->COUNT16.CTRLA.bit.MODE = 0 ; // use in 16 bit modeinstance->COUNT16.CTRLA.bit.CAPTEN0 = 1 ; // capture enable on channel 0instance->COUNT16.CTRLA.bit.CAPTEN1 = 1 ; // capture enable on channel 1instance->COUNT16.CTRLA.bit.PRESCALER = prescaler ;instance->COUNT16.EVCTRL.bit.EVACT = 0x6 ; // PWPinstance->COUNT16.EVCTRL.bit.TCINV = 0 ; // don't invert input signalinstance->COUNT16.EVCTRL.bit.TCEI = 1 ; // enable input eventsinstance->COUNT16.INTENSET.bit.MC0 = 1 ; // enable match compare channel 1 interruptinstance->COUNT16.INTENSET.bit.MC1 = 1 ; // enable match compare channel 1 interruptif (instance == TC0){nvic_int_enable(0x1 << NVIC_INT_TC0_CH) ;}if (instance == TC1){nvic_int_enable(0x1 << NVIC_INT_TC1_CH) ;}if (instance == TC2){nvic_int_enable(0x1 << NVIC_INT_TC2_CH) ;}if (instance == TC3){nvic_int_enable(0x1 << NVIC_INT_TC3_CH) ;}if (instance == TC4){nvic_int_enable(0x1 << NVIC_INT_TC4_CH) ;}instance->COUNT16.CTRLA.bit.ENABLE = 0x1 ;} // end tc_pwmCapture_setupInterrupt handler:Code:void tc_pwmCapture_interrupt_handler(uint8_t counter){if (countern->COUNT16.INTFLAG.bit.MC0){while (countern->COUNT16.SYNCBUSY.bit.CC0);tc_pulse = countern->COUNT16.CC.reg ;}if (countern->COUNT16.INTFLAG.bit.MC1){while (countern->COUNT16.SYNCBUSY.bit.CC1);tc_period = countern->COUNT16.CC.reg ;interrupt_has_fired ++ ;}}EIC pin setupCode:static inline void eic_pin_setup(uint8_t portPin, eic_trigger_signal_type action_on, eic_interrupt_enable_type interrupt_enable, eic_event_enable_type event_enable){clock_enable_per_on_gclk(EIC_GCLK, 0) ;uint8_t portn = portPin >> 5 ; // dump pin number section leaving port numberuint8_t pin_number = portPin % 32 ; // dump port number leaving pin numberif (portPin % 2) // if the pin is odd numbered{PORT->Group.PMUX[pin_number/2].bit.PMUXO = 0x0 ; // fill in multiplexer}else // else the pin is even numbered{PORT->Group.PMUX[pin_number/2].bit.PMUXE = 0x0 ; // fill in multiplexer}PORT->Group.PINCFG.bit.PMUXEN = 0x1 ; // enable pin multiplexerif (interrupt_enable) EIC->INTENSET.reg = 0x1 << (portPin % 16) ; // if applicable enable interruptif (event_enable) EIC->EVCTRL.reg |= 0x1 << (portPin % 16) ; // if applicable enable eventEIC->CONFIG[ (portPin & 0xF) / 0x8 ].reg |= action_on << ((portPin % 8) *4) ; // configure events}

author: jpanhalt
author_rank: Super Contributor
timestamp: April 06, 2023, 03:50:01 pm
content: I can't read C, but I have done capture to measure PWM. When you say "both" pulses, if that is both rising (or both falling) edges, then you are measuring frequency. You need to capture a rising edge and falling edge.If you work through the graphics, note that the "2nd" rising edge is the end of the first period and start of the second and so forth. So, after the very first period, you only need the two pieces of new data, assuming a relatively constant frequency. I let the timer run continuously (assuming no more than one overflow) and math takes care of the rollover. If there is more than one overflow, you can either count them separately or adjust pre/post scalers.

author: ataradov
author_rank: Super Contributor
timestamp: April 06, 2023, 03:52:51 pm
content: EIC must be configured for level, not for edges. This would essentially pass the signal to the TC directly.Here is a code that does PWM capturehttps://github.com/ataradov/siggen/blob/master/fw/counter.cIt is for the TCC, not TC, but the idea is the same.

author: Simon
author_rank: Unknown
timestamp: April 06, 2023, 08:56:43 pm
content: Ah, thank you. that makes sense. Probably the one option I did not try. But this does confuse me slightly. I thought the purpose of using event inputs was to use some functionality they had that is not in the counter because the counter will only do a pulse capture with it's own inputs.

author: ataradov
author_rank: Super Contributor
timestamp: April 06, 2023, 09:11:12 pm
content: Not really, I have no idea why it is done that way. It makes little sense.I think it may be some legacy from the D20/D21 where WOx were outputs only and could not even do timestamp capture.

author: Simon
author_rank: Unknown
timestamp: April 07, 2023, 07:19:57 am
content: Oh I see, so SAMC came out after the SAMD.

author: Simon
author_rank: Unknown
timestamp: April 11, 2023, 08:53:36 am
content: Well this still does not seem to work. I have tried high and low level but all this does is pick up on the high pulse or the low pulse, not the period, the period interrupt is not firing at all. I'm finding your example code a little confusing. I'm sure some of those options are apparently not supported on the SAMC maybe they are a SAMD thing.

author: Simon
author_rank: Unknown
timestamp: April 11, 2023, 11:01:07 am
content: Works now, my mistake seems to have been to have separate interrupts for each capture value. Seems this has all been baffling a few people for a long time:https://forum.microchip.com/s/topic/a5C3l000000UgaUEAS/t176817?page=1

author: ataradov
author_rank: Super Contributor
timestamp: April 11, 2023, 04:15:39 pm
content: When capturing two values, they just go into CC0, CC1 registers, but it is a single action, so you should expect only one interrupt. It is pretty logical, I think.

author: Simon
author_rank: Unknown
timestamp: April 11, 2023, 06:42:24 pm
content: I think it is what I first did but having had the issues I tried various things. It's all working now.