Don’t get me wrong, I love Circuit Python. Sure, I could get stuff done in the ugly stepchild language that is Arduino, but the niggling details, the mediocre IDE, none of it was my friend. And truth to tell, it’s not often I need the full speed of even an ATTiny.
CircuitPython, in its quest for ease of use, sometimes does drive me completely around the bend. Particularly about the lengths its developers go to in avoiding interrupts. They’re right: interrupts are inelegant, interrupt code breaks way too easily, writing it just leaves you with a different set of problems, etcetera. I know that. And in theory I admire the tools they’ve developed to make interrupt routines unnecessary: countio, which right now just counts falling edges on a pin but soon will do all the things regular digital inputs do; pulseio, which gives you a Wow! bleeping list of the on and off times of the pins you’re watching. And the keyboard functions that tell you what switches you’ve got pressed. That’s almost all of what you might sensibly want interrupts for when you’re programming in an interpreted language.
Except. The gotchas. For example, pulseio counts in microseconds and only handles unsigned two-bye integers. So if whatever you’re watching go on and off does it slower than 16 times a second, that’s too darn bad.
Or the RP2040 and its PWM channels. For reasons that are no doubt obvious to the developers, you can only make countio objects on pins assigned to PWM port B. There are 8 of them, so that really shouldn’t be a problem, but wait. Ports A and B (as far as I’ve been able to figure out) share timer channels 0-7. So if you have a counter object on a pin that talks to timer channel 3 (on port B, natch), then woe unto you if you try to make some other PWM object (motor driver, servo control, tone out, dimmable LED, whatever) attached to the pin that talks to timer channel 3 on port A.
You can either make a matrix and cross out the pins you can’t use as you start assigning counter objects and PWM outputs, or you can just pick a number, see if an error message comes back and pick again. Or (if I were building new widgets on a slightly more frequent basis) it might even be worthwhile to create a tool where you tell it what inputs and outputs you need, and it hands back a list of plausible pin assignments. (Did I mention that my eyes are getting old and I really don’t like changing wires from one pin to another once I’ve got them set…)
It’s not a big deal, really, and mostly the problem is expectations. Python is supposed to be a language about orthogonality and abundance, not this-operation-only-uses-that-resource. If it were Arduino coding, I wouldn’t be surprised by arcane restrictions, but now I’m spoiled, and it’s hard to go backward.
(Ok, one latest debacle finally got me to post this). And then there’s my other favorite board, the Cytron Maker Pi 2040, which has a motor driver and servo drivers and a bunch of cute connectors. And no complete listing of what all the pins do. There’s a fuzzy silkscreen on the back for some of the pins, and a better silkscreen on the front that at least tells you what GPIO each special-purpose pin is connected to. Then you can either check table 1.4.3 in the Raspberry Pi datasheet, or consult the pictures of Raspberry Pi Pico board that tell you which functions go with which GPIO. Not sure which is more cumbersome.