Skip to content

Commit

Permalink
More TCD info I forgot...
Browse files Browse the repository at this point in the history
  • Loading branch information
SpenceKonde committed Apr 3, 2020
1 parent fbe74eb commit 3ca7f3c
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 6 deletions.
2 changes: 1 addition & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
* Lower prescaler on TCA0 to 16 when system clock is 4 Mhz or 5 MHz and 8 when running at 1 MHz (was 64)
* Increase prescaler on TCD0 to 64 when used as millis() source with 1 MHz system clock (it still runs from unprescaled 20/16 MHz oscillator) in order to reduce portion of time spent in the ISR. Previously it spent more than 12% of it's time in the ISR.
* micros() times returned are now as close to the time when micros() was called as possible
* Add support for writing to the user row using EEPROM.h
* Move millis interrupt to HUNF instead of LUNF when TCA0 is used for timing
* Don't prescale TCB clock in Servo at 10MHz or lower for smoother output
* Correct TRIM_DURATION in Servo library
* Add support for writing to the user row using EEPROM.h
* Add support for receiving general call messages in slave mode using the TWI peripheral through the Wire library (Thanks @LordJakson - #146 )
* Add support for second address or masking off bits of the address using the TWI0.SADDRMSK register
* Added support for the Atmel embedded debugger on the explained pro kits as programmer (thanks @rneurink #149 )
Expand Down
10 changes: 5 additions & 5 deletions megaavr/extras/PWMandTimers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
This document describes how the timers are configured by the core prior to the sketch starting and/or by the built-in peripherals, and how this may impact users who wish to take full control of these peripherals.

## The Timers on megaAVR parts
This applies to the megaAVR ATtiny parts, or as Microchip calls them the "tinyAVR 0-series and 1-series" (these are all parts supported by megaTinyCore), and the ATmega4809 and it's smaller brethren, the "megaAVR 0-series". The ATmega parts are used on the Arduino Nano Every, Arduino Uno WiFi Rev. 2, and the whole family is supported as bare chips by [Hans/MCUdude](https://github.com/MCUdude)'s excellent [MegaCoreX](https://github.com/MCUdude/MegaCoreX). The ATmega 4809 is particularly notable for being the only megaAVR part available in a DIP package (excepting the 128AVRxxDA series, which will begin shipping in the second quarter of 2020 - some of those are available in a 28-pin DIP - but there is no compiler support for them on Arduino yet, and their peripherals are slightly different). Not all parts have all peripherals, and the number available will vary depending on the part - see the part-specific megaTinyCore documentation pages for a list, or the relevant datasheets for excruciating detail.
This applies to the megaAVR ATtiny parts, or as Microchip calls them the "tinyAVR 0-series and 1-series" (these are all parts supported by megaTinyCore), and the ATmega4809 and it's smaller brethren, the "megaAVR 0-series". The ATmega parts are used on the Arduino Nano Every, Arduino Uno WiFi Rev. 2, and the whole family is supported as bare chips by [Hans/MCUdude](https://github.com/MCUdude)'s excellent [MegaCoreX](https://github.com/MCUdude/MegaCoreX). The ATmega 4809 is particularly notable for being the only megaAVR part available in a DIP package (excepting the 128AVRxxDA series, which will begin shipping in the second quarter of 2020 - some of those are available in a 28-pin DIP - but there is no compiler support for them on Arduino yet, and their peripherals are slightly different). Not all parts have all peripherals, and the number available will vary depending on the part - see the part-specific megaTinyCore documentation pages for a list, or the relevant datasheets for excruciating detail. One thing worth keeping in mind if using these as "Event Generators" with the event system: All of the events these generate last a single clock cycle (except for the PIT). This means, for example, that you cannot use the TCBn event in PWM mode to get PWM output to an arbitrary pin as many had hoped on a first read of these datasheets.

### TCA0 - Type A 16-bit Timer with 3/6 PWM channels
This timer is the crown jewel of the megavr product line, as far as timers go. It can be operated in two very different modes. The default mode on startup is "Normal" or "Single" mode - it acts as a single 16-bit timer with 3 output compare channels. It can count in either direction, and can also be used as an event counter (ie, effectively "clocked" off the event) s capable of counting up or down, generating PWM in single and dual slope modes, and has 7-output prescaler. For most use cases, this timer is on the same level as the classiv avr 16-bit Timers, only with an extra output - the newly added features aren't ones that are particularly relevant for Arduino users. In this mode, TCA0 can generate events or interrupts on compare match for each channel (independently), as well as on an overflow.
Expand All @@ -18,12 +18,12 @@ They can be set to act as 8 bit PWM source, but none of the pins usable as a TCB

While this makes them poor output generators, they are excellent utility timers, which is what they are clearly designed for. They can be used to time the duration of events down to single system clock cycles in the input capture modes, and with the event being timed coming from the event system, any pin can be used as the source for the input capture, as well as the analog comparators, the CCL modules, and more. As input capture timers, they are far more powerful than the 16-bit timers of the classic AVR parts. They can also be used as high resolution timers independent of the builtin millis()/micros() timekeeping system if this is needed for specific applications.



### TCD0 - Type D 12-bit Async Timer
The Type D timer, only present on the 1-series parts, is a very strange timer indeed. It can run from a totally separate clock supplied on EXTCLK, or from the unprescaled 20MHz internal oscillator.It was apparently designed with a particular eye towards motor control and SMPS control applications. This makes it very nice for those sorts of use cases, but in a variety of ways,these get in the way of using it for the sort of things that people who would be using the Arduino IDE typical arduino-timer purposes. First, none of the control registers can be changed while it is running; it must be briefly stopped, the register changed, and the timer restarted. In addition, the transition between stopping and starting the timer is not instant due to the synchronization proces. This is fast (it looks to me to be about 2 x the synchronizer prescaler 1-8x Synchronizer-prescaler, in clock cycless. The same thing applies to reading the value of the counter - you have to request a capture by writing the SCAPTUREx bit of TCD0.CTRLE, and wait a sync-delay for it. can *also* be clocked from the unprescaled 20 MHz (or 16 MHz) internal oscillator, even if the main CPU is running more slowly. - though it also has it's own prescaler - actually, two of them - a "synchronizer" clock that can then be further prescaled for the timer itself. It supports normal PWM (what they call one-ramp mode) and dual slope mode without that much weirdness, beyond the fact that CMPBSET is TOP, rather than it being set by a dedicated register. But the other modes are quite clearly made for driving motors and switching power supplies.
The Type D timer, only present on the 1-series parts, is a very strange timer indeed. It can run from a totally separate clock supplied on EXTCLK, or from the unprescaled 20MHz internal oscillator.It was apparently designed with a particular eye towards motor control and SMPS control applications. This makes it very nice for those sorts of use cases, but in a variety of ways,these get in the way of using it for the sort of things that people who would be using the Arduino IDE typical arduino-timer purposes. First, none of the control registers can be changed while it is running; it must be briefly stopped, the register changed, and the timer restarted. In addition, the transition between stopping and starting the timer is not instant due to the synchronization proces. This is fast (it looks to me to be about 2 x the synchronizer prescaler 1-8x Synchronizer-prescaler, in clock cycless. The same thing applies to reading the value of the counter - you have to request a capture by writing the SCAPTUREx bit of TCD0.CTRLE, and wait a sync-delay for it. can *also* be clocked from the unprescaled 20 MHz (or 16 MHz) internal oscillator, even if the main CPU is running more slowly. - though it also has it's own prescaler - actually, two of them - a "synchronizer" clock that can then be further prescaled for the timer itself. It supports normal PWM (what they call one-ramp mode) and dual slope mode without that much weirdness, beyond the fact that CMPBSET is TOP, rather than it being set by a dedicated register. But the other modes are quite clearly made for driving motors and switching power supplies. Similar to Timer1 on the ATtiny x5 and x61 series parts in the classic AVR product line, this timer can also create programmable dead-time between cycles.

It also has a 'dither' option to allow PWM at a frequency in between frequencies possible by normal division of the clock - a 4-bit value is supplied to the TCD0.DITHER register, and this is added to a 4-bit accumulator at the end of each cycle; when this rolls over, another clock cycle is inserted in the next TCD0 cycle.

The asychronous nature of this timer, however, comes at a great cost. Most changes to settings require it to be disabled - and you need to wait for that operation to complete (check for the ENABLERDY bit in TCD0.STATUS). Similarly, to tell it to apply changes made to the CMPxSET and CMPxCLR registers, you must use the TCD.CTRLE (the "command" register) to instruct it to synchronize the registers. Similarly, to capture the current count, you need to issue a SCAPTUREx command (x is A or B - there are two capture channels) - and then wait for the corresponding bit to be set in the TCD0.STATUS register. In the case of turning PWM channels on and off, not only must the timer be stopped, but a timed write sequence is needed ie, `_PROTECTED_WRITE(TCD0.FAULTCTRL,value)` to write to the register that controls whether PWM is enabled. Thus, making use of the type D timer for even simple tasks requires careful study of the datasheet, and can be frustrating and counterintuitive.
The asychronous nature of this timer, however, comes at a great cost: It is much harder to use than the other timers. Most changes to settings require it to be disabled - and you need to wait for that operation to complete (check for the ENABLERDY bit in TCD0.STATUS). Similarly, to tell it to apply changes made to the CMPxSET and CMPxCLR registers, you must use the TCD.CTRLE (the "command" register) to instruct it to synchronize the registers. Similarly, to capture the current count, you need to issue a SCAPTUREx command (x is A or B - there are two capture channels) - and then wait for the corresponding bit to be set in the TCD0.STATUS register. In the case of turning PWM channels on and off, not only must the timer be stopped, but a timed write sequence is needed ie, `_PROTECTED_WRITE(TCD0.FAULTCTRL,value)` to write to the register that controls whether PWM is enabled; this is apparenmtly because, in the intended use-cases of motor and switching power supply control, changing this accidentally (due to a wild pointer or other software bug) could have catastrophic consequences. Writes to any register when it is not "legal" to write to it will be ignored. Thus, making use of the type D timer for even simple tasks requires careful study of the datasheet - which is itself quite terse in places where it really shouldn't be - and can be frustrating and counterintuitive.


### RTC - 16-bit Real Time Clock and Programmable Interrupt Timer
Expand Down

0 comments on commit 3ca7f3c

Please sign in to comment.