Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x5 PWM #737

Open
prandeamus opened this issue Jan 6, 2023 · 6 comments
Open

x5 PWM #737

prandeamus opened this issue Jan 6, 2023 · 6 comments
Labels
2.0.0-dev bug This bug is present in 2.0.0-dev Documentation

Comments

@prandeamus
Copy link

For the v2 core, the x5 documentation has been re-written. It currently says for PWM that 4 channels are available "PA5-7, PB2"

  • Trivial: there's no port A on X5 devices. There's no PB6,7
  • Less trivial, do you really mean 4 PWM channels? The x5 documentation for V1.x says three, which is consistent with the OC0A, OC1A, OC0B, OC1B designations on the diagram above. I have seen tricks to get four independent PWM outputs from the X5, like the one by David Johnson-Davies at http://www.technoblogy.com/show?LE0, but as far as I can see that uses Timer1, and you'd want to draw attention to that if you used it in the core because it would screw with Tone and Servo.

Anyway, this feels like a cut/paste documentation mistake. Your thoughts?

@prandeamus
Copy link
Author

Correction. There is statement under "Servo and Tone break PB4 (and possibly PB1 for PWM)" saying "The servo library and the tone function require full control of timer1. " So there is some mention of possible interactions, and maybe the use of Timer1 in some PWM functions, but PB1 isn't consistent with the "PA5-7,PB2" statement, so I think my overall point is still valid.

@SpenceKonde SpenceKonde added Documentation 2.0.0-dev bug This bug is present in 2.0.0-dev labels Jan 8, 2023
@SpenceKonde
Copy link
Owner

SpenceKonde commented Jan 8, 2023

Yeah it's cut and paste error. At one point in the 2.0.0 dev process, I realized that the part-specific docs were like.... all totally different from each other, and there was no coherent structure to them (same with the variant files). So I made a template, pasted it into each part specific doc, then modified it for that part. And I missed some things.

And... Shit, yeah, that's the problem with using Timer1 for PB1 PWM isn't it? Is that behavior what's wrong? Sigh, I think I feel a tools submenu approaching, since that has to be known at compile time, and known to all compilation units, and the only way to do that is if you pass the define as a -DMACRONAME=VALUE parameter in the compiler flags, and that means a tools submenu to set which timer generates that pin's PWM - Timer1 to get a second pin controlled by the more powerful timer? Or vanilla PWM only from Timer0, but a second PWM pin that can coexist with tone. (we do not have any sort of facility to alter this at runtime, nor is there a clear path towards it which would be effective in the general case. ).

(note: Yes, I do allow runtime timer PWM pinmapping changes with full API support on some Dx-series, over on DxCore - but only for some types of timers, and those parts have far more resources than classic tinyAVRs (flash/ram, plus a rated speed of 24 MHz from 1.8-5.5V, vs 5-20 MHz depending on voltage for tiny, and they also overclock better), and the pins change in groups with a simple structure to them, so it both takes less resources and there are more resources to go around. Over 80% of pins on some parts supported by DxCore can, under some configurations, generate PWM, and if you were locked into using the one set of pins the idiot who wrote the core (me) picked, the PWM functionality would have been gimped (recall that on classic AVRs, at it's most complicated on the t841, there are 3 timers with 2 channels each, and each of 8 PWM pins can be assigned to a timer). On megaTinyCore with the modern tinyAVRs, you get 2 options per channel assigned individually, at most. On DxCore, a timer's set of pins can get pointed at 3-6 different ports, and some parts have 2 TCAs and a TCD, with 6 and 2 channels each, respectively, so forcibly assigning fixed pins reduces the number of potential (not simultaneous) PWM pins by not < 50%, but >80%. Basically, what I'm saying is, there will never be runtime swapping of PWM pin control between timers on ATTinyCore in the general case. There are a few odd special cases where it was easy to give limited support for the alternate pins, the one that comes to my mind is the x7, where you get 2 channels on timer1... but each can go to one or more of 4 pins! We don't dictate which ones are allowed I think as of 1.5.0 or 1.4.x, instead, Instead, when you analog write any pin on channel A, it turns on that pin's PWM output and sets the duty cycle of channel A, and when you digitalWrite() it, the PWM is disconnected from that pin, but nothing keeps you from analogWriting all 4 of the pins for channel A - they will all output PWM. Always the most recently requested duty cycle is used for all pins, and we suggest that sticking to a single pin is more useful, but we don't force you to. In this case, it was actually basically trivial to implement that functionality. The route to runtime pin switching on the t85 would have been much more work, and require new API functions specific to that part (oh - that's another thing about the Dx-series that favored that feature: The pin swapping works the same way on all of them, while on classic AVRs every damned thing is adhoc).

But it might make sense to do a tools submenu for the x5-series tiny that just lets you pick which timer is used for the one pin that can use either timer - the machinery is all there already, it just needs a lever attached for changing it.

@prandeamus
Copy link
Author

Well, it's your call, but it does sound like if you configure all this with submenus we're just bloating the number of options and making testing even harder. At the end of the day, Tiny devices are tiny. You don't expect the same ease of use as you do with larger parts and the more modern ones, and you'll go mad trying to make a tiny 85 exactly as easy to use as the more advanced parts.

I'd be happy with implementation that covers the basics and points out potential problems. "For tiny 85, does up to three PWM channels on (whatever the pins are) and uses timer. When you use PWM, you can't also do because you're a skinflint and you didn't buy a bigger/better chip".

Put another way, if you break your back trying to implement 4 PWM channels in the core and documenting just how to make that work and what breaks when you do (and to some extent it can be done as the technoblogy article proves) No One Will Thank You. It's masochism. Use the 80/20 rule. Three PWM channels is fine. You'll go mad otherwise.

@SpenceKonde
Copy link
Owner

You can get 4? No you can't! the inverted PWM channels are neither independent nor available in the normally desired modes. I looked at that for a long time back when I was first noticing the way the t85's timers were laid out, I couldn't see any way to do it in the general case. There are whackjob special cases that can, but setting up crazy shit like that is on the user.

You easily get 3, though, the question is just whether you get 1 channel controlled by the 8-bit high speed timer with the amazing prescaler (but which can't be used with tone) and 2 that are controlled by the normal 8-bit timer with a limited prescaler and no warp-speed option (you can clock timer1 from 64 MHz PLL, the one that's divided by 4 to generate the 16 MHz internal pll system clock option, yasee, and get insanely high frequency PWM which is important in the target market for the t85, which was centered around 2-pole BLDC motors (the drone I have that goes out of control and divebombs bystanders in a slight breeze uses them to control it's motors! Yeah, I flew that thing twice, nearly losing the drone and nearly hitting someone both times (as in, on both occasions, someone was nearly hit, and it nearly went into a body of water - useless thing, mainly because the control mechanism didn't have anywhere near the range or reliability it would have needed, though my poor pilot skills did it no favors. The t85-driven motors worked fine, though...), and decided maybe drone flight wasn't my calling), but those 2 lower speed, less-prescalable timers can do PWM while tone is in use. Or you can do the other way around. I picked 2 high speed channels because that seemed like a better use of the chip's resources, but it had previously been the other way around, so when I implemented it, I just put a #define somewhere that chooses between the two, so it's just a matter of adding the menu, and we have a script that generates boards.txt here (because it was infeasable any other way for 2.0.0)

@prandeamus
Copy link
Author

Yes. "Crazy sh1t like that" is a user concern. I was quoting a use case where a "4th" pwm was actually an interrupt handler with user code yadda yadda.

Some of the details in your reply went a bit over my head. I can see that design choices have to be made in the x5 core about which timers to use. On general software engineering principles (if no other) I'd settle for a solution which is broadly in line with the way 1.x uses timers. The principle of least surprise, perhaps. Having said that, I'm not the expert and if you think it's in the general best interest to use the timers differently I can't argue with you. I'm just thinking of your sanity!

Interesting, if I understand you correctly, that the x5 was built for high speed PWM uses. I'm sure a lot of it's popularity in the hobby market is that it once hit a sweet spot with price, having a decent set of functions, and an 8 pin DIP package. And the boost it had via digispark and micronucleus. But that's a discussion for another time.

@SpenceKonde
Copy link
Owner

SpenceKonde commented Mar 17, 2023

Yes. "Crazy sh1t like that" is a user concern. I was quoting a use case where a "4th" pwm was actually an interrupt handler with user code yadda yadda.

Oh eeeww.... (I will note - If I was allowed to edit the hex file, and the chip had >8k of flash, I it is possible to make a "there and back again round trip" in the 2 words that the vector normally fills with a jump instruction... It would be fast, but a real pain in the ass to prepare, and it would be a lot of deep work to make the compiler do that automatically instead of you editing it after the fact. . you would have to redo the build process used to make the toolchain package to do it without modifying the exported hex file though! Where vectors are 2 words, you should be able to do an SBI or CBI in the first word and reti in the second, and pack the uinterrupt in the place of the vector. You could be back to the main code in 10 clocks). That's really not bad for a heinous hacky solution.

Test it? Oh I wasn't planning on testing something small like this. That's what end users do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.0.0-dev bug This bug is present in 2.0.0-dev Documentation
Projects
None yet
Development

No branches or pull requests

2 participants