MC2023 Chapter 3: More PWM with a servo.
Page created: 2023-04-18 , updated: 2023-04-22Welcome to the third "chapter" of my Year of the Microcontroller!
2023-04-16
Today I read Chapter 9 of Programming the Raspberry Pi Pico in C. Learned about motor PWM for controlling motors and servos. Great info!
Having skimmed ahead, I saw this coming and had already purchased a pack of little hobby servos to try out. I had no idea they were so cheap!

But given my little hiatus, I had to find them again. Ah, there they are!
Aren’t these things cute?
2023-04-17
Spent this evening drawing the circuit several different ways:
-
As a diagram (straight out of the book) for handy reference.
-
With the servo functions annotated by wire color (apparently there are three different "standards" for these colors).
-
As a drawing with the parts as they actually appear in the real world all connected together.
-
With the pins of the transistor used in the circuit all annotated between the diagram symbol and the real world object.
-
In the positions where I’ve plugged the components into my breadboard.

(And even still, there were mistakes!)
I have no illusions about my ability to read a schematic and translate it into a working device without taking these extra steps to get it right. I understand the schematic just fine, but I have not built up the fluency to look at the diagram and go straight to the breadboard yet.
I know I mentioned in in the previous "chapter", but I’m gonna say it again: I’ve been keeping my notes for the Year in this cheap spiral-bound notebook. The notebook lives with the project. I’ve got code notes, my script aliases, and drawings like these.
If nothing else, the notebook is super helpful to remind myself where I left off last time. Especially when I had those long breaks, but even just from evening to evening.
2023-04-18
No progress on the circuit today because I spent tonight finishing the page for Chapter 2 and posting it.
I plan to keep this chapter more up-to-date so I can just clean it up and post it when I’m done. (Yup, I did.)
2023-04-19
Out sick this evening. :-(
2023-04-20
Got the circuit physically wired up tonight. I had to find another male-to-female Dupont connector to get from the Pi computer +5v output pin to my Pico project breadboard to power the servo. I knew those connectors were somewhere in the house, but the box was hiding. What a rascal, hiding in that closet.
Maybe I’ll power up tomorrow?
2023-04-21
Okay, ha ha, so I figured I’d double-check all of my wire colors and the transistor pin orientation and that sort of thing before powering up this servo circuit. And there goes another evening.
What an adventure.
First off, it turns out the servo wire colors I’d written down were not correct. But the manufacturer had them, so that was no problem. I just had the red and orange swapped.
But the transistor situation got real confusing real fast. There was no data sheet with this cheap "kit" I bought and I started to see all sorts of surprisingly contradictory pin information online.
Turns out I was right to be confused. The lack of transistor pin order standards is nuts.
The answers on this EE StackExchange question explained the insane situation: 2N2222A Mismatch between emitter and collector (electronics.stackexchange.com).
And one of them explained how to determine the pins on a bipolar transistor with a multimeter’s "diode" feature. So I printed that out and tried it out.
Since I knew what kind of transistor I had (2N2222 NPN), I didn’t have to try too many combinations. I just wanted to verify that the most likely configuration was correct.
Here’s the voltage drop measured between the middle and two outside pins:

Sure enough, when tested with the center (which I was pretty sure was the base pin), the "left" pin consistantly had a 0.001 to 0.002 V higher reading.
Here’s a drawing with my findings. It confirms that my transistor matches the majority (but not all!) of the pin designations for this part number:

For someone arriving here via a Web search, the package label reads "2N2222A331". The pin order I determined with the flat side of the package facing you is: emitter (left), base (center), collector (right). This came from a "Bojack" brand kit purchased on Amazon.
Well, maybe I’ll power this circuit up tomorrow night. Slow and steady wins the race, right?
2023-04-22
It works!
Well, it didn’t at first.
I entered the program more-or-less straight from the book. I fiddled with it a fair bit, but the servo didn’t even twitch.
I’m sure it was a simple bug (in fact, I think I had the polarity wrong during one of my attempts or it would have been fine). But the thing is, without really understanding exactly how it’s supposed to work, how can I even begin to debug it?
So, there’s no avoiding it. I sat on the couch with the book and a calculator and my notebook and did the work.

It’s really not that bad.
-
The clock is running at 125,000,000 Hz
-
clkdiv is the 8-bit clock divider (max 256)
-
wrap is the 16-bit "top" value (max 65,536); when the counter hits this, it resets to 0
-
level is a value between 0 and wrap; when the counter hits this, it toggles the GPIO level high/low
The clock divider and wrap values give you the PWM frequency.
The level gives you the "duty cycle" (pin is set to high) out of the total. If you set level to 50% of wrap, the pin will be high half the time and low the other half.
The hardest part is working backward from your target frequency to figure out a clock divider value that will give you a number of ticks per second that will then count up to a wrap value that is pretty close to 65,536. (The only reason you care about getting close to that max value is so you can get the most out of your 16-bit counter resolution).
In the case of my servo, I needed a PWM frequency of 50Hz (or 20ms), a servo standard). A duty cycle of 1.0ms high per pulse will position the servo at -90 degrees of rotation. 1.5ms positions to 0 degrees. 2.0ms positions to 90 degrees. Anything between those values is a position between those degrees of rotation.
I was tired of flying blind and printf() statements aren’t going to get me out of this one. So I decided to bust the oscilloscope out and see if I still remembered how it works:

The resistor on the right was a handy connection to ground that I could grab with the lead’s grounding alligator clip.
The pin on the left was a piece of header pin strip that I put in line with the servo inputs specifically for attaching the oscilloscope lead.
With the help of the scope (at last, I can see what’s happening!), I was able to fix a couple mistakes (one of which was to use the PWM reverse polarity setting in software because the simple transistor servo driving circuit reverses it in hardware).
Then the signal was just right!

And sure enough, as soon as it looked exactly right on the scope, the servo moved!
By switching between different duty cycles (setting the level to different values), I can control the servo’s position.

It’s strong enough to press a key. I set it on a sleep delay and then had it press ENTER to re-flash the Pico to a blinky program. It’s alive! It can program itself! Run!
It took me a week of evenings to piece together this simple circuit with four components and get it right, but what a payoff: I made a thing move. And best of all, I understand why it moves. I’m glad I put in the time to figure this out the right way.
I’m already thinking of so many different things I could do with these servos. This stuff is great.
I thought everyone would enjoy seeing what my setup looks like now. Getting kinda messy:

I2C communication is next. See you in "YotM Chapter 4".
Back to Year of the Microcontroller!