(AVR-DA) Check If TCD Running - Page 1
Forum section: electronics / general

author: T3sl4co1l
author_rank: Super Contributor
timestamp: April 04, 2022, 01:17:15 pm
content: Half question, half answer:Scope: anything with Timer Counter D. Appears to be at least tinyAVR and AVR Dx.Problem: how to verify if this peripheral is running?This is a semi-independent counter on its own clock domain. Rather than expose all the internal state, only select registers are provided, including control bits and strobes, status flags, and buffered values. In particular, the count and slope* registers are not accessible. How to determine if it's running?*As in, which slope it's currently counting, or up/down direction. This has 1, 2 or 4-slope modes for counting the dead time and pulse duration of bipolar waveforms (inverter or motor controls would be typical uses), and also direction for the "phase-correct" modes. There are also event-triggered states where counting or outputting is masked or latched off. It is particularly these that I think may be the most troublesome to figure out.References:http://ww1.microchip.com/downloads/en/Appnotes/TB3212-Getting-Started-with-TCD-90003212A.pdfhttp://ww1.microchip.com/downloads/en/DeviceDoc/40002183A.pdf(AVR128DA datasheet, I'm actually using AVR64DA64 but close enough)The datasheet is notably poor on details and examples, despite its 50+ page length for this peripheral. The most confusing thing about it I found, is the frequent use of the words "command" and "synchronization", as if referring to functional blocks in the device. What exactly is being "synchronized", or "commanded", and how and when, is very unclear. After reading it up and down several times, I think I've come to the conclusion that, by "command", they just mean that some state-change flag has been activated (i.e., CTRLE, CTRLA), and, I don't know if multiple can be changed at once because it's just aplain fuckin' old clock domain synchronization register, or if there's actually logic gating or sequencing multiple bits, but at least the, all of seven, things you can do anyway, are rather limited in terms of possible interactions. As for "synchronization", I think they sometimes mean the above process (which is asynchronizationprocess after all), butalsothe double-buffering process that the value registers (DLY, DITHER and CMP) go through, and which is triggered in several ways (which arecommandsthemselves, possibly even so if automatically generated).In any event, these docs are sadly a long ways away from the classic ATMEGA32 and such datasheets, which I found not only highly readable, but which also gave exact names of registers (as used in the headers), and brief code examples, in C and ASM, on how to use everything.So. Methods that I can think of:- Just set up all the damn registers and hope for the best.--> But certain input modes can stop output. Maybe suitable if not using those?- Sample WOx pins?--> Not always active, how to tell if a '0' is dead time or off?- Check input state, see if a stop was triggered? Enable event or trigger interrupt?--> Maybe. Requires knowing which mode it's in, and the corresponding behavior/logic of that mode. The bigger problem is this solves it in parallel: it's constructed alongside the desired information, but is not the actual desired information (the internal counter state). This is unsatisfying at least, being prone to bugs/discrepancies, and is not portable between versions of TCD (if they made any variations, or plan to in the future).- Check ACT flags (STATUS)?--> Flags have to be cleared, then wait some time for one or the other to become set. Which could take up to a full cycle, but you don't know exactly how long that is because of clock source, prescalers, and hidden TOP count (the counter goes up to CMPBCLRbuffered internally; if the visible register was written since then, it won't match)Likewise, other options as above might be reliable with waiting, but what if you can't wait?- Sample the internal counter with software captures (CTRLE[SCAPTUREA/B])--> We can synchronize to at least one clock cycle (or half cycle? I have no idea) by waiting on STATUS, and maybe add a few nop()s for good measure? Not suitable if both CAPTUREs are already in use, or can't be paused/disabled for the duration of this test.Still incurs some delay, potentially arbitrarily long (what if it's sourced from a frozen EXTCLK?). Seems one of the best options, but still far from a slam dunk.- I can't think of any other options; can you?My solution:Code:#include <stdint.h>#include <avr/io.h>#include <avr/cpufunc.h>bool tcd0IsRunning(void) {uint16_t tmp;//Trigger capture on unused capture channelTCD0.CTRLE = TCD_SCAPTUREA_bm;while ((TCD0.STATUS & TCD_CMDRDY_bm) == 0);tmp = TCD0.CAPTUREA;_NOP(); _NOP();TCD0.CTRLE = TCD_SCAPTUREA_bm;while ((TCD0.STATUS & TCD_CMDRDY_bm) == 0);return tmp != TCD0.CAPTUREA;}I'm not using CAPTUREA so this works for me, and I'm running it from a fast clock so the _NOP()s should be extra insurance on top of the while loops. It seems to work? I could stand to do some logic probing to see what's really going on (say, sampling STATUS, CAPTUREA, etc. very frequently to see when they update; and, combine with testing at lower TCD clock to see how they line up).(Ed: just tested, seems to work with CPU = 24MHz and TCD at 48 or 1.5MHz. Probably fine then?)Which, I should probably do sometime anyway, write a couple functions to test registers and measure responses, say by polling very quickly and buffering the results in an array. Use the CPU as its own logic analyzer of sorts. Maybe slightly handier than bit-banging the same out to PORTs. Feels kinda dumb considering how little RAM there is, but eh.Tim