After getting the PWM backlight working in my last post (here are links to parts 1, 2, 3, 4, 5, and 6), there was only one piece remaining for having a fully functional display in my Chumby 8: the touchscreen controller. The display output worked perfectly fine but I couldn’t detect presses on it.
The Chumby 8 and Insignia Infocast 8 have a 4-wire resistive touchscreen:
These aren’t so common anymore — it seems like almost everything is capacitive touch nowadays. I wasn’t familiar with the theory of operation behind resistive touchscreens until I wrote this post. Basically there are two transparent resistive layers. One layer goes left and right and the other goes up and down. When you press the touchscreen they connect together. You can calculate the X and Y positions where the layers meet by driving a voltage across one layer and then measuring the voltage of the other layer. Here’s a nice document that does a great job of explaining it in detail.
I recently ran into an interesting warning on newer versions of ARM GCC, including the latest (as of this writing) Arm GNU Toolchain 12.3.Rel1. In particular I’m dealing with arm-none-linux-gnueabihf-g++. Here’s a very simple example program that demonstrates the warning:
In the previous post in this series (here are links to parts 1, 2, 3, 4, and 5), I really got the Chumby to start looking like a Chumby. The display was alive! But getting the LCD controller working was really only one puzzle piece when it came to the display. The backlight needed more work so that I could control the brightness, and the touchscreen controller is a completely nonstandard design that is specific to the Chumby.
Let’s start with the backlight. This should be pretty straightforward, right? Looking at the schematics, the backlight control is connected to GPIO_84 (also known as PWM_OUT1) on ball A4 of the PXA166. I already knew that I could turn the backlight on full blast by using this pin as a normal GPIO pin and driving it high. That’s what I did in the previous post in order to quickly get it working.
At this point in my Chumby kernel upgrade project (parts 1, 2, 3, and 4 here), I had made a ton of progress but there wasn’t really much to show for it because I didn’t have the LCD working. Even though I had put a ton of work into the project, the display was still black. I knew it was time to get it working.
I started out with U-Boot. As a very basic overview of the LCD controller in the PXA168, basically you just set aside some of your RAM for a framebuffer, copy image data into it, tell the controller the format and address of the framebuffer, set up the clocking and timing, and turn it on. Then it just handles everything in the background for you.
The steps I listed above are overly simplified — there is more stuff going on with the PXA168’s display controller. But it’s enough to get a splash screen working in U-Boot. I booted into the old kernel and dumped the LCD registers using devmem. Here’s an example of this process. The LCD_SPU_DMA_CTRL0 register contains a bunch of format configuration bits for the framebuffer, such as which bits are red/green/blue. It’s at offset 0x190 in the LCD controller, and the LCD controller is located at an offset of 0xD420B000, so I could dump the 32-bit register value with this command:
devmem 0xD420B190 32
This resulted in a printout of the value of the register:
For the next post in my series about upgrading my Chumby 8’s Linux kernel (here are links to parts 1, 2, and 3), I thought I’d look at what was involved in getting the reboot and poweroff commands working properly. I noticed pretty early during the development process that they didn’t work, which was pretty annoying.
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system reboot
[ 46.457580] reboot: Restarting system
[ 47.458947] Reboot failed -- System halted
This meant that in order to restart the Chumby, I had to physically press a button to power it off and again to power it back on. As you can imagine, this got old really fast during development. For that reason it was one of the earliest things that I got working.
I actually implemented it in U-Boot first, but I thought the Linux side of it would be more fun to share. If you want to see what was involved on the U-Boot side, see this commit from my fork of U-Boot.
This is the next post in my series about upgrading my old Chumby 8’s kernel. Here are links to part 1 and part 2 if you missed them. As a quick summary, I got U-Boot working in part 1 and then got the SD card working in part 2. In this part I’ll describe the complicated process of how I got Wi-Fi working.
The Chumby 8/Insignia Infocast 8 has a built-in AzureWave AW-GH321 802.11g module. This is a pretty old module that doesn’t even support 802.11n, so it maxes out at 54 Mbps and the link is an archive.org link because it’s nowhere to be found these days. The module makes use of the Marvell 88W8686 chipset, which connects through the SDIO bus. SDIO is basically just the same as SD, except it’s for I/O devices like Wi-Fi and Bluetooth modules instead of SD cards. This wireless chipset is supported by a Linux driver called libertas.
This is a continuation of my previous post about upgrading the old 2.6.28 Linux kernel that came with my Chumby 8. In that post, I got a modern U-Boot working with SD card support, which is what I needed in order to boot Linux.
After I finished getting U-Boot working, I began work on the kernel. I based my work on the stable kernel version 5.15.33. I started by compiling a kernel using the bundled pxa168_defconfig file. I created a device tree file called pxa168-chumby8.dts based on pxa168-aspenite.dts. It needed a few tweaks. I specified the correct amount of RAM for the Chumby 8 (128 MB) and changed the model and compatible strings. I also disabled “twsi1” which is an I2C host. I wasn’t ready to deal with I2C yet. Here’s a small snippet of the relevant changed parts of my new device tree file.
As I mentioned in my last post, I spent a good chunk of my spare time over the past 6 months working on a project I’ve been thinking about for over a decade. I bought a Chumby 8 in 2011. It’s an 8″ touchscreen device powered by the Marvell PXA166 processor. It is essentially a souped-up digital picture frame with extra capabilities like speakers, a microphone, and Wi-Fi. There are a bunch of little Flash-based “apps” you can install for stuff like pictures, music, sports scores, weather, games, etc. I have no idea how many of the apps still work these days. Chumby actually went out of business a few months after I bought mine, although one of the founders stepped up to keep the service running. A variant of this device was also created for Insignia, which was called the Infocast 8″ Internet Media Display.
I was never really interested in using it for any of the stock functionality. I thought it would be a fun development platform. It would be exciting to make some custom apps in Qt or something. One thing that was a little frustrating was that it came with a Linux 2.6.28 “Erotic Pickled Herring” kernel circa Christmas 2008, which was ancient even at the time I bought it. This is a pretty common issue with Linux-based devices. I will even admit I’ve been responsible for some old kernels out in the field in Internet-connected devices. I don’t blame Chumby. It’s tough when the SoC vendor doesn’t submit their kernel modifications upstream or at least keep their fork up to date. I’ve been there.
I’ve been doing some Linux kernel development in my spare time over the past 6 months or so. The goal has been to get my old Chumby 8 (stock kernel 2.6.28) running on a modern kernel with custom firmware. It has been going really well and there have been lots of fun problems I’ve needed to solve along the way. I may write some posts about that process if there is any interest. It’s been a blast.
Anyway, I thought it would also be fun to jump into the current craze of OpenAI’s ChatGPT free research preview and apply it to Linux kernel development. Let’s see just how well this AI can write a basic kernel module that I describe. Can it improve the module as I ask it to make tweaks?
I started out by asking:
Write a Linux kernel module that prints “Hello world” to the console every 5 seconds. Also provide a Makefile for compiling it.
On a daily basis, I work on firmware for an embedded device that uses the BridgetekFT800. It’s a nifty chip that takes commands over SPI/I2C and turns them into an image displayed on an LCD. It’s very useful for displaying user interfaces with simple microcontrollers. Bridgetek is actually a spinoff company from FTDI, and this kind of solution seems right up their alley — take something complicated like USB or a display controller, and create a simpler interface for dealing with it, such as UART/SPI/I2C.
One thing that’s usually important about user interfaces is the ability to display text. The FT800 has a very basic capability for handling fonts. It’s not really much more than the ability to deal with sets of 127 sprites that each comprise a “font”. As a developer, if you want to use fonts aside from the (very limited) stock ones that come bundled in the FT800’s ROM, you have to create bitmap images that you upload into the 256 KB of available display RAM.
Several years ago, we had to deal with converting the user interface to display in a bunch of different languages, including Chinese. Most of the new languages we added weren’t a big problem, because we could just create a couple of fonts containing all of the special accented characters we needed and be done with it. Chinese, though, was a bigger challenge. There are so many different characters. Putting every character for every string into the limited display RAM is impossible. My coworker at the time came up with a clever script that automatically rasterized the font glyphs and created groups of different 127-character fonts for each displayed screen in the user interface. Every time you changed screens, the new set of fonts for that screen would be loaded into the display RAM.