Barnsley fern fractal

Thoughts on software architecture and development, and methods and techniques for improving the quality thereof.

David B. Robins (home)


Code Visions: Improving software quality
PWM motor control on the pcDuino (V2)

By David B. Robins tags: Development, Embedded, Debugging Sunday, November 6, 2016 13:35 EST (link)

It's been a year since my last public post here; way too long; but so it goes. It's certainly not from lack of material; perhaps I'll backfill some.

We are starting to build an HO-scale model railroad layout; it really is quite early, but rather than starting from scratch I'm starting from a box of ~25-year-old supplies, including a diesel and two steam locomotives, various cars, track, a power supply, and various scenery elements. We purchased an 4' x 8' x 1/2" birch plywood board and have assembled a simple oval and can drive the engines around it (much better after cleaning the track and wheels with isopropyl alcohol).

Eventually I'll do a DCC (Digital Command Control) conversion, and to that end I've ordered DCC decoders for the locomotives, and dusted off a pcDuino V2 I had in storage and installed Arch Linux ARM on it (with LXDE) so I can use it as a controller. This weekend I thought I'd set up the pcDuino to control the existing DC circuit, since I had H-bridges (TI's SN754410)s on hand (used earlier to test automating solenoid turnouts; worked fine, best with 12V+). (Since Arrow has had free shipping for October and November, I've been buying whatever I could from them, although I much prefer Octopart's search engine—which can be set to show parts from Arrow only.)

The old DC controller puts out a little over 14V DC at max throttle, so it became the output supply (Vcc2) for the H-bridge, which I set up on a breadboard. GPIO pins from the pcDuino for motor contol (1A, 2A) and enable, outputs (1Y, 2Y) to the track, ground and 5V from the pcDuino, checked passthrough, all good. I used the /sys/class/gpio interface for the GPIO pins; one gotcha was that it uses the Sun4i pin numbering; see extension headers, and calculate (letter - 'A') * 32 + number, e.g., J11 header pin 3 is PH7 which is ('H' - 'A' = 7) * 32 + 7 = 224 + 7 = 231; echo 231 > /sys/class/gpio/export creates /sys/class/gpio/gpio231 and echo out > /sys/clas/gpio/gpio231/direction makes it an output, and so forth. There was supposed to be a /sys/class/pwm with a similar interface—but it wasn't there!

That began a long hunt for how to make the PWM device work. The relevant kernel module was pwm-sun4i, but loading it didn't help. That lead me down the rabbit-hole of device trees, and I found I had to make some changes to the .dts file. On Arch, /boot/dtbs stores the .dtb files, compiled .dts files; dtc can "decompile" them. Since Arch Linux ARM didn't have a pcDuino V2 boot loader, I was using the V1 (only V3 is listed on the page, but the V1 files exist in a "pcduino" directory next to "pcduino3"). I override the .dtb file in boot.txt (compiled with mkscr) using setenv fdtfile pcduino2.dtb. I produced that .dtb by decompiling /boot/dtbs/sun4i-a10-pcduino2.dtb, editing the .dts, and recompiling it. First I removed status = "disabled"; from pwm@01c20e00, and that gave me files in /sys/class/pwm, but it still didn't work. Further reading in the A10 manual and other places suggested that the pin needed to be put into PWM mode, and wasn't. That lead me to determine I needed to add pinctrl-names = "default"; and pinctrl-0 = < &pwm0 &pwm1 >; to that section too (and I also added status = "okay"; just in case), with pwm0: and pwm1: labels placed in front of pwm1@0 and pwm1@1 respectively. I had added some debug logging to the relevant kernel modules to ensure that the "pinmux" commands to set the pin mode were being sent. Building a kernel on that machine is very slow, and I used distcc to offload some of the building to a cross-compiler on another machine.

The last surprise was that setting the PWM duty_cycle to 0 actually meant full 100% power all the time. I read that a 1 kHz period was good for a DC motor, which means echo 1000000 > period (since it's in ns). This mostly worked; slow speeds are a bit dubious and I may experiment with different period values. Also it is problematic to change direction while the enable is being pulsed; I think this is what killed my H-bridge (loud pop, reset the DC source's transformer), but fortunately I had more.

I want to control the eventual DCC controller with a joystick, a mostly-unused Logitech that I played TIE Fighter with once upon a time; so I'll set up a basic user interface for the current DC controller to learn how the joystick events work.

Content on this site is licensed under a Creative Commons Attribution 3.0 License and is copyrighted by the authors.