Neil's assignment for this week:
   individual assignment:
      add an output device to a microcontroller board you've designed,
         and program it to do something
   group assignment:
      measure the power consumption of an output device

Group work

I was unable to complete this week's group assignment with my group, so I did it on my own and am writing up my results here.

The group assignment was to measure the power consumption of an output device. Power is calculated by multiplying the voltage across a component times the current through the component:

   P = I V
I calculated the power flow through a small DC electric motor. I connected it to a 5V, 2A DC power supply. I connected my multimeter across the motor's terminals, and measured V = 5.16 volts while it was running. Then, I switched the meter into 10A current mode, and measured the current flowing through the circuit. (It's important to put the meter "in the loop" while doing this, if you connect it across the motor you'll create a short circuit through the meter!) I measured I = 0.057 A when the motor was free-wheeling, and I = 0.531 A when the motor's axle was held in place and unable to turn.

Measuring voltage
Measuring freewheeling current
Measuring stall current

Thus, we can calculate that the motor consumes 5.16 x .057 = 0.29 watts when freewheeling, and 2.74 watts when stalled. It may seem surprising that the motor consumes less electrical power when stalled, given that when it's not moving it cannot produce any mechanical power. The explanation is that in this case, the electrical power is being turned into heat rather than motion.

About this documentation

This week's documentation is going to be a lot less formal than previous weeks. Instead of explaining step by step what I did and how I did it, it's going to focus on my screwups, my problem-solving process, and how I tried and failed and eventually succeeded. The heroes' journey, I suppose, with a really dumb hero. One thing's for sure, if you're new to Arduino it's worth reading, just to see that you're not alone in struggling, and maybe you'll learn from my mistakes.

I did keep running notes of my step-by-step process, but they're not very readable. It's all documented in my week09-notes.txt file, swear words and all. On this page, I give a summary of what I tried, what I learned, and include little pull quotes from the running notes as comic relief.

Individual Assignment: TFT Displays

My final project will be a magnetic field mapping device. If possible, I want to integrate the display and sensors into a handheld package, so you can see the fields on the device. That means I really want a cool sexy color display. (If I can't get this to work, I'll do the visualization on a desktop computer, but that's less cool.)

TFT LED displays are the best option for high-resolution color displays compatible with Arduino and other microcontrollers. They have screens about the size of a cell phone, display thousands or millions of colors, and can use the SPI interface supported by many microcontrollers. Many of these boards also include resistive touch-screens, but that's a topic for Input Devices week. They are generally powered by a driver chip mounted in the edge of the display.

an Amazon page for a TFT LED display
An Amazon page showing off a TFT LED display, and -- as it will turn out -- lying about it.

One of the most common driver chip families is the ILITek series. Here are the specs for a few ILI driver chip models:

Chip (link to datasheet)PixelsColors
ILI9341240x32018-bit
ILI9481320x48018-bit
ILI9486 (no idea how this is different than ILI9481)320x48018-bit
ILI9488320x48024-bit
These chips can talk to a microcontroller in several different ways, including ordinary 4-wire SPI, a 3-wire variant of SPI that uses one data line but is somehow different from I2C(?), a faster 8-wire parallel system, and an even faster 16-wire parallel system. I'll probably be using the Seeed Xiao RP2040 board for my development. The RP2040 has plenty of pins and could easily support the fast parallel communications, but the Xiao board doesn't expose enough pins to the outside world (It has 11, and I think I'd need 12 for the 8-bit parallel method.) So I'll be sticking with 4-wire SPI.

My "Beansprout" dev board has multiple I2C ports, but no SPI port. It does, however, provide optional pins to plug it into a breadboard, so I used that to wire up the TFT displays. I don't know whether "crappy rat's-nest of wires" is allowed this week, but I had enough trouble getting this to work that I don't have time to mill a new board.

The biggest problem with these TFT displays -- and it's a huge problem -- is that you can buy them for super-cheap on Amazon for like $16-$20, and you get what you pay for. They may include no information about what driver chip is included, no libraries or how-to documentation, and are unlabeled, so you have no idea whether the board you found in the lab is the same as the similar-looking thing you found on the Internet.

In the end, I tried to work with all of the following:

(Images from http://www.lcdwiki.com)

These things don't have documentation. They don't have part numbers printed on them. They don't have support websites. The manufacturer doesn't have a web presence except for an Amazon store page, and bunch of yahoos on discussion forums and wikis trying to get them to work.

Now, there are companies that provide good support for these. Adafruit, in particular, has a set of lovely libraries for TFT displays they sell, full tutorials and documentation. What I should have bought is a Adafruit 3.5" TFT 320x480 + Touchscreen Breakout Board w/MicroSD Socket - HXD8357D. In addition to great support, it has a two-sided header so you can use it in either 4-wire SPI mode or 8-wire parallel mode. It also has a touchscreen. But it was out of stock when I went to order stuff. Instead I planned to try to use Adafruit's lovely libraries with these no-name Amazon boards.

Setup Hell

Getting these to work was pure hell. I spent at least 12 hours going around in circles, trying various combinations of display, microcontroller, driver libraries, and example codes. Is the display broken? Did I miswire them? Is the library not compatible with this board? Is my dev board not soldered right? Did I not configure the example code correctly? In the end, it was just me, making a stupid stupid rookie mistake.

I tried to get simple example scripts provided by various library developers running on the following boards:

My previous microcontroller experience has taught me to always try it on an Uno first. Everybody supports the Uno, it's a known quantity. It may be slow, but it always works. (Oooh, foreshadowing!)

Here's a list of the libraries and tools I tried out:

Here's what happened with each display:

Breakthrough

In the end, what saved me was Neil's notes. Or not the notes specifically, but a statement buried two links deep into the Wiki for the UCGLib graphics library he used:
"The red breakout board from the following picture is a 3.3V board. It can be connected to the Arduino Due, but requires level shifters for the Uno and Mega boards."
olikraus, "How to Connect a ILI9341 Display"
3.3V? Level shifting? What? Most of my efforts were focused on getting these displays working on the Arduino Uno. I got a blank display with the Xiao, at least the Uno showed something crappy. But the Uno uses 5-volt logic. And it turns out that the 240x320 display and the 320x480 one are both 3.3V only.

How could I screw this up? Didn't I check for voltage compatibility? I sure did! The Amazon pages for both displays describe the as "5V/3.3V". The 240x320 one says in the description "5V compatible, use with 3.3V or 5V logic." This is a lie. Adafruit -- God I love Adafruit -- goes into detail about how their boards use level shifters to be 3.3V or 5V compatible, so I didn't think twice about whether the Amazon ones did too.

Farther down on the page, in fine print, they both say something about "Logic I/O Voltage: 3.3V (TTL). Apparently the LED backlight takes 5 volts but the driver chip doesn't. Arrrrgh.

Of course this doesn't explain why the Xiao didn't work, that's a 3.3V chip. But since the Uno was almost working, I decided to stick with that. But I don't have any level shifting chips on hand. Is it possible to convert from 5V to 3.3V with just parts on hand? Yes, by adding a voltage divider to each digital output. Is it pretty? No. Did it work? Also no.

Voltage divider circuit to convert from 5V logic to 3.3V.
Let he who is without sin cast the first stone.

The Uno was a bust, so I went back to the Xiao RP2040 and tried again, wiring it up exactly the same as before, using the same Bodmer TFT_eSPI library as before. And this time it worked! I must have miswired it the first time, and then got so focused on the Uno I never tried the Xiao again.

A Working Setup

Here's my configuration and setup to get the 320x480 display working.

And oh man is it fast. The Uno was able to get through the standard "TFT_graphicstest_one_lib.ino" graphics test script in about 10 seconds, compared to several minutes on the Uno. Yes the RP2040 can do SPI at almost 80 Mhz, and the display can keep up, and it goes through Dupont wires and a breadboard just fine.

My Own Code

With a working display, I set out to learn more about the TFT_eSPI library's capabilities. As advertised, it can draw anti-aliased lines, moving sprites, and transparency. It can do "direct memory access", sending data directly from the microcontroller's memory to the display. I didn't mess with any of that. But I did learn how to print to the screen, use different fonts, and draw lines on the screen. My tft_testing.ino sketch was my attempt to play around and learn these features. It displays text in a variety of fonts, then clears the screen and draws a "spirograph" pattern.

It's a great library but man, I could not find any well-written documentation! Just a bunch of patch notes that say "it can now do XYZ" and you're expected to dig through the code to figure out how.

Testing text and fonts
Testing line drawing with a spirograph pattern

Back to Julia

I wanted to wrap up with something cool, so I modified my Julia set code from Week 4 to display a Julia set on the TFT screen. The main change was to change the "colors" from different sizes of O's output to the serial port, to an actual color map output to the TFT. I'm drawing pixels one drawPixel() at a time, if there's a faster way to do it I haven't figured it out yet.

I also learned that the RP2040 doesn't have a hardware floating point processor. That might be an issue for my final project.

Julia set on TFT with Xiao RP2040
Another Julia set on TFT with Xiao RP2040
Overall wiring and operation

Lessons Learned

Design Files