Capture on TCD0 with ATTiny

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello.

 

I am using ATTiny816. I am attempting to capture a square wave and determine its timing. The signal is on pin PA5. It is usually 50% duty so I can capture the high pulse, low, or both, doesn't matter to me. Frequency range is fairly low - 10 Hz to 120 Hz range.

 

I would like to use Timer/counter D for this (called TCD in data sheet). The other two timers on the part are already in use.

 

I have done this before on other micros, trying to do the same here. I want to configure the peripheral so it automatically captures the timer value on either rising or falling, and automatically resets the timer and re-starts it. This way the peripheral will just run in the background, always being updated with the most recent capture duration, and any time I want to know the most recent capture duration, I want to read it from a capture register of some sort.

 

The configuration tree is fairly complicated. I haven't tried to write even pseudo code because I can't understand how to even begin to configure it. The DS is very sparse on how to do this very simple task. Section 22.3.2.6 "TCD Counter Capture" on pg 220 of the DS has brief notes, but doesn't tie them together in an example. The "Example" just tells me to capture Event A and Event B, and that one should be set to capture rising and one capture falling, but that's all it says. I can't see how I would configure them to rising/falling or how to configure the timer to do what I want.

 

I do see the part about writing '1' to the ACTION bit in the Event Control register, but that's all it says. Nothing about how to begin the next cycle, nothing explicitly telling me what happens. Section 22.3.2.4 "TCD Inputs" may hold the key, but it's not human readable. Table 22-4 doesn't seem to clearly show a selection doing what I'm looking for. 

 

I tried to generate some basic config code with an Atmel Start project, but the little selection dialog for Timer D is overwhelming and doesn't seem to match what is being said in the DS. Also, both DS and Atmel Start talk about a "fault" condition, but never seems to define it.

 

I found a few examples in app notes, but they are generating outputs and doing really complicated things. I'm trying to do something IMO is very simple, and the entire purpose of having a Capture peripheral in the first place.

 

Would someone mind to write some basic configuration code, or even pseudo code telling me what registers to set how, or if this is even possible? I don't see any option to auto reset the capture.

Thanks in advance for any help!

-K

 

This topic has a solution.
Last Edited: Thu. Aug 15, 2019 - 04:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't have the ability to explain in detail, but the TCD capture initialization code I'm actually using is:

 

void tcd_capt_start(void){
    // Event setup(trigger = PA1)
    EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_PORTA_PIN1_gc;
    EVSYS.ASYNCUSER6 = EVSYS_ASYNCUSER6_ASYNCCH0_gc;

    // TCD setup(capture mode)
    TCD0.CTRLA = 0;
    TCD0.CMPBCLR = 0xFFF;
    TCD0.INTFLAGS = TCD_TRIGA_bm;
    TCD0.INTCTRL = TCD_TRIGA_bm;
    TCD0.EVCTRLA = TCD_CFG_ASYNC_gc | TCD_ACTION_CAPTURE_gc | TCD_TRIGEI_bm;
    TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc;
    while (!(TCD0.STATUS & TCD_ENRDY_bm));
    TCD0.CTRLA = TCD_CLKSEL_EXTCLK_gc | TCD_ENABLE_bm;
}

 

Please replace the pin used for the trigger with yours.
Select a TCD clock considering the frequency to capture.
Perhaps this may be helpful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You may find that the second example in the Getting Started with Analog Comparator guide, titled "Analog Signal Pulse Duration/Frequency Measurements" also gives you something helpful. Their code segments are walked through with explanation of what each line is doing, so will also help you understand what kabasan's code is doing too.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smerrett79 would you like to contribute to the tutorials part and write about TCD in tiny 0/1 in series ?

 

Regards,

Moe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moe123 I'm only copying the guides! If that was a genuine offer, I'm flattered. If I have said something about the TCD that made my comment look stupid, I'm sorry. I have only really been studying the 402 because I have one (some) soldered onto a SOIC adapter and stuck into my breadboard. I did buy a 416 xplained board after I got some comments about why I was wasting my time with a jtag2updi programmer on a previous thread! But I haven't used it yet. So this means I don't know about TCD (402 doesn't have it) and I probably made an error in recommending the AC guide?

 

I do have some guides to the 402 basic stuff on hackaday.io if anyone wants but I get the feeling you are all professionals on this forum and don't need such hand-holding. Personally, I think there should be more guides and example code made available on how to implement different features, especially where they are a large change (as far as I can tell) from the older, commonly used AVRs, such as the event system and the custom configurable logic.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smerrett79 !! i definetly didnt mean to make fun, it was a genuine offer, the thing is that the tiny 0/1 series are realtively new so not a lot of documentation or examples are available. so it would be nice to have some sort of tutorials for new beginners to help overcome the errors that are often found in the appnotes and datasheets of tiny 0/1 series...consider this as an apology if you felt offended.

 

Regards,

Moe

Last Edited: Wed. Jul 17, 2019 - 08:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No apology needed if your heart was genuine! I'm just nervous because I'm relatively new with this stuff compared to most of you on this forum! 

 

If you look at my hackaday project logs and let me know what you would like to see. I have recently "cracked" the use of the single shot pulse generator on TCB0 using a pin input as the trigger. Is that the sort of example you were thinking?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Anything that you feel would help the others would be nice to have...I dont think that TCD has been discussed yet in the tutorial forum so maybe it would be nice to have one over there.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smerrett79 wrote:
I'm just nervous because I'm relatively new with this stuff compared to most of you on this forum! 

 

Don't worry, many people here are experts on classic AVRs but the new series is still being explored. I don't think any of us can really be considered "experts", we are still learning. I know I am, there are several peripherals I haven't touched yet and timer D is one of them.

If you go to the tutorials section, you will see that there is only an handful of AVR-0/1 tutorials. Not everyone has time or inclination to write tutorials, I try to write something but only when I'm in the mood and have time. It's volunteers work, after all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all but I'm going to have to give up on this. I've now invested 1.5 full work days trying to capture a pulse on a "capture" peripheral and I'm still totally lost.

 

It is so frustrating because I've done this several times on PIC processors with no trouble. Their CCP peripherals are straightforward and they provide simple little snips of code to make them work. This has never been more than a 15 minute job.

 

kabasan I appreciate the code - that would be helpful but I can't tell how those flags are being set. I've never understood the tribal knowledge of all those _gc and _bm flags all over so I can't tell how the registers are even being set. I don't know why they can't just set the register with a hex value or something so I can clearly see what bits are 1's and which are 0's.

 

I can't believe the data sheet doesn't just list the whole 6 lines of code required to do this with some basic comments.

 

The data sheet doesn't explain the registers at all. You are setting CMPBCLR to 0xFFF for example, but the data sheet doesn't explain this at all - it just lists the register, so I don't know if that's even important. :\

 

smerrett79 thanks for the link to the app note. Their example is for TCB which looks to be a million times simpler than TCD. I think that's where I'm stuck. Massively over-complicated peripheral that IMO is very poorly documented.
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I apologize for posting a writing that does not fit your style.

 

But I think _gc and _bm make the code easier to understand. In fact, the code I posted has very few comments, but this is not a trick or a cutback.
CMPBCLR is also described in the datasheet but is hard to find.

ATtiny816 is still a young chip, and the data sheet has not been fully corrected. Furthermore, TCD is a new type of timer that is sophisticated but difficult to use.

 

I am sorry that there are many things unhappy to you.
I just want to tell you this. For me, the AVR core is a million times easier to use than PIC.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kjav wrote:
I've never understood the tribal knowledge of all those _gc and _bm flags

 

It's not "tribal knowledge" they are clearly defined in the header files, in this case iotn816.h. These files are included by the generic header <avr/io.h>. It's not like there is some kind of black magic going on...

OK, we know where to look from experience, but you could have found these files too with a bit of effort.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found them but they are very cryptic.

 

For example this line:

 

TCD0.EVCTRLA = TCD_CFG_ASYNC_gc | TCD_ACTION_CAPTURE_gc | TCD_TRIGEI_bm;

I have no idea what this is actually setting in the EVCTRLA register. I look to the definition of the first term TCD_CFG_ASYNC_gc and get this:

 

TCD_CFG_ASYNC_gc = (0x02<<6),  /* Asynchronous Event output qualification enabled */

I know this is a bit shift, but don't know what it is doing or how it plays into the above line. I don't know if _gc sets a bit, or clears it, or what it does to the rest of the register, same with _bm (which is "bit mask" apparently, but still have no idea what it actually does). If I wanted to "set" this option, I don't know how I would syntax that, and more importantly if I wanted to then turn this bit off, absolutely no clue what I would write to do that - tribal knowledge. It would be great if Atmel would produce a 1st grade human-readable guide that clearly spells this all out. I have looked and looked and looked and it doesn't exist.

 

I'm obviously no C expert but I've designed 50 or so boards and 15+ commercial products over 10 years with processors that control things. I'm more of a board design / physical enclosure kind of guy, not an expert in software but I get by. I can usually make things work if I have some starting point, I just can't make heads or tails of any of the starting points or reference code generated in this style. This is the 3rd time I've been forced to use an Atmel processor due to customer need and for whatever reason, I always bang my head on them. I have historically always just set registers to exactly what is needed like:

 

REGISTER = 0xAB;

REGISTER = 0b00001111;

or just using bit shifting to set what I want

 

I've been given links and tried to understand them before, but I feel the guides are always written over my head. Just have to pick our battles I guess.

 

The above code did compile, but the TCD0.CAPTUREAL, TCD0.CAPTUREAH, TCD0.CAPTUREBL, TCD0.CAPTUREBH all registers remain zero. I did change the pin in the example to PA5 in the event system. It's like the peripheral isn't doing anything at all.

 

After all this I'm just going to poll the pin, start another timer from zero, poll the pin until it goes low and stop the timer, which is all I'm really trying to do. It just would have been cool to have this wiz-bang peripheral do it for me.

 

Thanks again for the help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For example this line:

TCD0.EVCTRLA = TCD_CFG_ASYNC_gc | TCD_ACTION_CAPTURE_gc | TCD_TRIGEI_bm;

 

This is equivalent to

TCD0.EVCTRLA = (0x02 << 6) | (1 << 2) | (1 << 0);

 

It will finally be this.

TCD0.EVCTRLA = 0x85;

 

Perhaps the last thing is your style-matched expression.
However, you will not understand at all what you are doing even if you look at this 0x85 later.

 

If you want to express explicitly that you do not set a bit

TCD0.EVCTRLA = !TCD_CFG_ASYNC_gc | !TCD_ACTION_CAPTURE_gc | !TCD_TRIGEI_bm;

The result is 0x00.

 

 

Various expressions have been conceived in the long history.
And these are not AVR specific dialects.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kjav wrote:
I've never understood the tribal knowledge of all those _gc and _bm flags all over so I can't tell how the registers are even being set.
kjav wrote:
I found them but they are very cryptic.
They are simply the names of the bits that are given in the datasheet. Then _bp means bit position (ie bit number 0..7) and _bm means bit mask (a single 1 bit shifted to the right position so 0x01, 0x08, 0x20 etc)

 

When a register has several bits grouped together the suffix is _gm or _gc. _gm is group mask so is a bit pattern like 0x18 (sets bits 3 and 4). _gc is an opportunity to give a sensible name to a group of bits like WDT_PERIOD_64MS_gc or that kind of thing (which might mean 0b10 for bits 5 and 6 or something.

 

See:

 

http://ww1.microchip.com/downloa...

 

(anyone programming anything "Xmega based" shoould read AVR1000 anyway).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

See:

 

http://ww1.microchip.com/downloa...

 

(anyone programming anything "Xmega based" shoould read AVR1000 anyway).

 

Thanks. I've been programming xtinies but I had never read that document. Anyway, the style rules can be deduced fairly easily from reading the header files.

And Microchip should definitely put links to AVR1000 on their xtiny product pages.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:

See:

 

http://ww1.microchip.com/downloa...

 

(anyone programming anything "Xmega based" shoould read AVR1000 anyway).

 

Moe123 please can we add that to  https://www.avrfreaks.net/forum/getting-started-attiny-1-0-series-application-notes ?  

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smerrett79 wrote:

El Tangas wrote:

 

See:

 

http://ww1.microchip.com/downloa...

 

(anyone programming anything "Xmega based" shoould read AVR1000 anyway).

 

Moe123 please can we add that to  https://www.avrfreaks.net/forum/getting-started-attiny-1-0-series-application-notes ?  

 

 

Yes sure, I will add it now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry it took so long to get back to this. Thank you so much for recommending app note AVR1000. I've been fighting with these AVR processors in various projects for over a year and I've never seen that app note and I've spent countless hours/days digging on these things. That contains much of the tribal knowledge I have always been looking for. This should be in large bold type on the first page of every AVR microprocessor data sheet. Unfortunately the atmel/microchip website was written by marketing people and they don't make it easy to find useful information.

 

When a register has several bits grouped together the suffix is _gm or _gc. _gm is group mask so is a bit pattern like 0x18 (sets bits 3 and 4). _gc is an opportunity to give a sensible name to a group of bits like WDT_PERIOD_64MS_gc or that kind of thing (which might mean 0b10 for bits 5 and 6 or something.

I will carefully read that app note together with the posts above and post a new thread in the future if I still have questions. clawson above provided the closest thing to a human readable explanation I've heard so far. The other explanation showing the literal equivalent bit shifting line is hard to understand unless you're already an expert at bit shifting and pipes | and stuff, which still doesn't really say why all these strange underlined suffixes exist, what they mean, and how they are used.

Thanks again for the help everyone. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kjav wrote:
which still doesn't really say why all these strange underlined suffixes exist, what they mean, and how they are used.
But that IS what AVR1000 does surely? The _bp/_bm thing is simply a case of whether you prefer when setting/clearing some bit in a register to use:

REG |= (1 << ISGNAME_bp);

or:

REG |= SIGNNAME_bm;

Given that the Xmega headers (unlike tiny/mega) now go to some length to provide _bm's I don't actually know (apart from Asm) why you would ever bother with _bp as it necessitates a (1 << ???_bp).

 

To be honest this is all historical and stems from the oldest AVRs that were limited to 64 SFRs and put their "most used" SFRs in the bottom 32 of those. Many were also programmed in Asm (small/limited resources). So the attraction was to use the SBI and CBI opcodes when clearing and setting bits. So if you wanted to enable transmit on a UART (say) then a hypothetical example was:

SBI UCSRA, TXEN

The SBI (and CBI) opcode take the name of an SFR (in the range 00..1F) in the first parameter then a bit position (0..7) in the second. Because the second is a bit position not a bit mask then all these traditional AVRs defined all their bits in terms of position (0..7) not in in terms of a mask (0x01 .. 0x80). 

 

Later when the same symbols were used for C it meant that instead of:

UCSRA |= TXEN;

it would need to be:

UCSRA |= (1 << TXEN);

and to this day all the C code for all the traditional Tiny/Mega is littered with the (1 << n) construct (some people use a macro like _BV() which converts a bit position to a bit value (aka mask)).

 

Then along came Xmega. Atmel recognised that (for C) it was a serious pain in the behind that if they just gave bit positions (to be used in assembler) that code would once again be littered with (1 << n). So they gave both. But if you now have a "TXEN" how do you know if it is a bit position or a bit mask? The answer is you put _bp or _bm on the end. Now I suppose there is an argument to say that you didn't really need both. Rather than TXEN_bp and TXEN_bm, given that most use C and would use the bit mask it might have been better to use no suffix for that one and just _bp for the assembler programmers? But I suppose _bp/_bm is "balanced".

 

Then _gc / _gm etc just covers things when a setting is wider than one bit and things are grouped together.