Outputting a Clock using TCD0 #413
-
I'm trying to output a 12 MHz clock using TCD0 on PORTA, PIN7. I can see it on the oscilloscope (with a 12 MHz frequency), but the waveform is ~200 mV p2p. Is there some additional setting I'm missing that would enable something more like 5V p2p?
|
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 4 replies
-
What chip is this? I have not had issues with 12 MHz. (also - you don't need to go setting the data direction bit in the port! Noticed that gem this weekend: timers all have direction override on the port directly contrary to what the datasheet says!) My guess is that you haven't turned the bandwidth limit off on your scope. To make the more common low frequency signals stand out against high frequency noise, most modern scopes have a bandwidth filter turned on by default. Depending when it kicks in, when you're trying to output unusually fast PWM you can end up seeing the output signal much smaller than it is, because the scope is trying to be helpful and attenuate the high frequency "noise" that you're hoping to look at!) The timebase from which the PWM is derived is: is: Input frequency (either system clock (internal can be 1, 2, 4, 8, 12, 16, 20, 24, 28 (undocumented) or 32 (undocumented) MHz, external clock on PA0, or system clock multiplied by 2, 3, or 4x (undocumented; that's the reserved MULFACT bitfield value) via the PLL) divided by sync prescaler (/1 /2 /4 or /8) - this wants to be the lowest prescaler you can use and get the desired frequency), divided by the count prescaler. (/1 /4 or /32 (async event inputs don't work at 32 cnt prescale except on DD) The timebase must be twice the frequency you want to output. Assuming you want to output 12 MHz and are running at 24 MHz, You also need to:
This makes the core pretend that TCD doesn't exist for the purposes of analog and digitalWrite, giving you full control - once you do that, the TCD will never be reconfigured by any core function. (The core supports analogWrite() on TCD but can be expected to work with only when CMPBCLR is 254, 509, (actually done by default at the higher speeds, to keep sync prescale at 1 while keeping the frequency of the generated PWM between 490 hz and 2kHz), 1019, 2039, or 4079 (the last two only are tested for if F_CPU is > 32 MHz) - if this is detected, we leftshift the value passed to analogWrite before subtracting 1 to the the CMPxSET values. (for WOA, you would also want to set CMPACLR to the same value - or a higher one, assuming you're using one-ramp mode, which is probably what you want to use....) but we don't support values other than those unless you take full control. The reason we offer even this feature, or state that the API functions are still expected to work if the prescaler or clock source is changed (which is an exception to our policy of "if you modify the registers, all bets are off with the API functions") is because the TCD can be very challenging to work with (it is the most complicated peripheral on the modern AVRs by length of the chapter dedicated to it - and the chapter should have been about 50% longer to really explain how the damned thing works), and if you are directly driving the gate of a MOSFET to dim an LED strip or something - a very common use case, you don't want to have the PWM signal coming out at higher than 2k Hz. With the beefiest of big power MOSFETs sometimes trouble even starts as low as 1 kHz for - the 20-40mA from the pin drivers is not able to overcome the gate capacitance, before it's supposed to switch again, and it gets stuck between on and off, usually on the miller plateau, conducting a large current, but with much higher resistance than you were expecting. In extreme cases (the people who want 15-25 kHz PWM to run a motor to get above the limit of human hearing), I've heard of people burning out their FETs To switch the FETs faster, you need a gate driver chip - these are equipped with their own (4.7-22uf, typically) decoupling caps, and are able to drive current into and out of the gate at AMPS, slamming the gate open much faster than than the paltry tens of mA from the microcontroller pin (and you can usually power them from 10v in order to use "standard voltage" instead of logic level FETs easily) (See this guide for much more detail if your actual goal is driving a MOSFET: https://github.com/SpenceKonde/ProductInfo/blob/master/MOSFETs/Guide.md - it covers sizing and the impact of PWM on mosfet performance in detail, and I think links to a calculator in google sheets that you can play with). Since most people don't want to have to do all that manually, and since we want to make sure that the PWM is within our target range of 490 kHz to 1.96 kHz at all supported frequencies without having to use the sync prescaler (which slows down updates) we had to add that anyway. I think at the really high clock overclocked speeds, we may even default 1019 for CMPBCLR. Okay, so if you actually want a 12 MHz squarewave out, you've gotta take over TCD0 with the function above in setup. While TCAs (second most complicated peripheral by length of chapter, but the chapter is not excessively terse like the TCD one) have a command that resets their configuration on all registers to the defaults (and we call it as part of takeOverTCA0/1() to give you a clean slate), TCD0 has no such feature. So to start from the default values in the datasheet you need to also define a function:
And you probably do want to start from that clean slate because the type D timers are hard enough to use without having to deal with a preexisting configuration. After that:
TCD0.STATUS is not going to be important immediately, since we overrode init_TCD0, but it is super important after you enable it for the first time. You must check it in the following cases:
You can ignore the rest of the registers, except for these:
(internal HF oscillator - which is usually the same as the system clock when running from internal clock - the exception to this on DxCore is running at clock speeds not possible without prescaling (5, 6, 7, 10, and 14 MHz - I think I only expose 5 and 10 though. I know I've calculated out how to do micros() math without division for the other speeds though, and written delayMicroseconds() for them - Actually it looks like 5 is not exposed, and it should be for code portability with tinyAVR... I'll fix that in next release, which is coming soon to fix the fact that PWM was so badly fucked up in 1.5.x - the bugs were all in variants and analogWrite though, so they don't concern you if you're trying to generate obscenely fast squarewaves like you are and need to take full control. And the 48 MHz crystal is missing from DD for some reason; at least all the the E-spec DB's I've tested will run at 48 at room temperature, and I'm confident that at least some of the E-spec DD's will as well. I've never seen I-spec Dx-series fail to hit 32MHz from internal and run stable at that speed room temp, and most do 40 but not all). I've gotten the TCD to output up to 64 MHz on an AVR128DB64. using PLL as input, with the PLL set to the undocumented 4x multiplier, and the chip running from internal oscillator at the undocumented 32 MHz setting, meaning the timer was running at 128 MHz, a whopping 2.67 x the spec! Switching to 40 MHz crystal (and running PLL from sysclock of course), though, TCD0 wouldn't run at 160 MHz even though the chip was stable at 40) - It maintained time cycle-to-cycle, but didn't turn the pin on sometimes. The two times I've had to turn off bandwidth limit on my scope both happened with a DB. There was the time I was seeing how hard the chips could be overclocked and was generating the 64 MHz clock output with TCD mentioned above. (though I was so sure 48 wouldn't work for system clock, since it was fully 20% higher than a speed which I had already observed to not even work with an external clock on an I-spec DB, and I felt like I was lucky it worked even with an external clock. External clocks always work better than crystals,. so I didn't bother trying it on an e-spec until last month, when I was assembling boards using E-spec 128DB48's in QFN (we did 20 boards, 2 out of the 15 with what I had thought was my best solder for QFNs, and none of the 5 I made with this too-good-to-be-true 190C lead-free solder that actually tests negative for lead (unlike the common PPD "S600 183C lead free" which neither melts at 183C nor is lead free - it melts lower, and tests strong positive for lead) required any rework; hand-placed parts, stainless steel stencil, and reflowed in a chinese reflow oven that won't get hot enough for 217C lead free solder. But enough bragging about my assembly skills, lets get back to bragging about how fast I got the chip to run)... And I found a 48 MHz crystal - actually a 10-strip of - some reason, never had used any, and was like "oh what the hell, I have a hotplate, I'll just test before I pin it so if it doesn't work it's easy enough to swap it out for something else. Even if it "kinda" runs, it'll be obviously unstable, get math wrong and eventually reset or hang for sure..." but since it sure would be cool to have that option - I was looking at my cycle budget for pattern generation on an LED lighting project and I was nervous about some of the particularly demanding modes I had in mind and the number of LEDs I wanted, so threw a 48 MHz crystal on one, and then set the clock to 48 MHz crystal to see how it would fail.... it ran without issues I was quite stunned. And the other time, I was trying to understand the limits of the CCL's async capabilities, so I set up a CCL LUT with "feedback" as the only input, the other two being masked off, and had it invert it's own feedback input and enable the output pin. That will oscillate around 80-100 MHz IIRC, though it was not stable against speed changes due to temperature and bad juju, and there's wide variation between parts). I then jumpered that to the clock input pin (PA0), configured a prescaler of 4 on the system clock and switched the clock source to the external clock. I calculated the speed it was running at after that prescaling from the frequency I measured with the scope, and multiplied the baud rate I passed to Serial.begin() by the ratio of the clock speed I compiled for, and what it would actually be running at... AND IN THIS BATSHIT CRAZY SETUP with the super dodgy clock source THE CHIP ACTUALLY WORKED! It printed to serial (though just resting a soldering iron tip on the chip was enough to change the speed enough to break serial; On the proper internal oscillator, that doesn't even change theclock speed by 1%) But yeah, if you have TCD configured correctly (note that the core does not correctly configure anything for PWM on the current released version, I need to stop writing this and finish fixing those bugs... |
Beta Was this translation helpful? Give feedback.
-
So, this whole TCD thing causes my head to hurt a bit when I read the data sheet. There’s a lot going on there, as has been discussed. I read (somewhere – Microchip docs?) that TCD is well suited to control motors and switching power supplies. I expect that’s its well suited for something or Microchip wouldn’t have invested the R&D into developing the TCD nor putting it onto silicon. Yet, when I do google searches regarding using an MCU for motor control or a switching power supply, most of the responses I’m seeing (admittedly from enthusiasts postings rather than professional engineers) suggest it’s a bad idea to use an MCU for those applications and that one should use function specific ICs instead. I’ve read application notes TB3236 and TB3212 and they are fine for what they are, but they barely scratch the surface. Is anyone aware of application notes (from Microchip or elsewhere) that describe in some detail out to use a counter like TCD to control a motor or switching power supply. I guess if one was a switching power supply designer it might be obvious how to use TCD for that application, but it’s not for me. Any suggestions would be appreciated. |
Beta Was this translation helpful? Give feedback.
-
I should have added that AN3998 does discuss motors, but my interest is more switching power supplies. |
Beta Was this translation helpful? Give feedback.
-
Ive been exploring the same thing and see two rather divergent applications, one where you might want a constant voltage (or current) much like a classic power supply, and one that is quite dynamic like a motor controller or a grid tie power supply. One could argue that something as static as a classic power supply could be done safer and better in hardware, while implementing a motor controller for the arm of a robot in hardware would be quite a feat. I think the app note you are looking for is AN3725: Buck-ConvDesign-Feedback-Ctrl-Using-CIP-DS00003725A.pdf Configuring a current-mode smps using a DB with its analog peripherals gives a bit of both worlds. Use a timerB to set switch frequency and max on-time, an opamp to condition the current sensor, and a comparator to implement current-mode. A CCL block or two to tie it together. Once configured it might run with no cpu intervention at all, or use the dac to adjust the set point for a programmable supply... At the hobbiest level its kind of silly (not counting the challenge) as Mouser sells the UC3845 qty 1 at 75c each. But if you were to mount one to the back of every solar panel of a large install, it could add up to a chunk of change. |
Beta Was this translation helpful? Give feedback.
What chip is this?
I have not had issues with 12 MHz. (also - you don't need to go setting the data direction bit in the port! Noticed that gem this weekend: timers all have direction override on the port directly contrary to what the datasheet says!)
My guess is that you haven't turned the bandwidth limit off on your scope. To make the more common low frequency signals stand out against high frequency noise, most modern scopes have a bandwidth filter turned on by default. Depending when it kicks in, when you're trying to output unusually fast PWM you can end up seeing the output signal much smaller than it is, because the scope is trying to be helpful and attenuate the high frequency "no…