Custom Display for Elliptical Trainer

Buy a cheap exercise device, get cheap display. But we can fix this!

Similar projects worth following
A few years back I bought an elliptical trainer from Aldi for somewhere around $150. It works, but the display is very hard to read. I'm taking the plunge and figuring out how to add my own for better results.

If you get Aldi coupons in the mail, look for store deals. This is for weird stuff, like patio furniture sets and exercise equipment, both of which we've purchased at Aldi. Usually each store only has one or two of the special deal in stock so get there when the store opens.

Both of these things have been okay. The patio furniture is actually really good, but a bad job of powder coating and not protecting the threaded holes made it a horrible task to put together yourself. But being a hacker I can deal with it (especially at a 6-piece set with table and umbrella for $250).

The elliptical trainer is okay. It was also rather difficult to put together. And there's a bug in two of the six training programs that prevents it from displaying how fast you're supposed to be going at any given stage. Obviously a discerning shopper would have take this back. But I did okay.

The Problem:

For me, the viewing angle and contrast of the non-backlit LCD display is pretty awful. The display is about waist height for me. And the optimum viewing angle is about navel height for me. All I really want is some nice bright LEDs at eye-level that tell me my current RPM rate (as a bar graph) and the target rate for the exercise routine I'm working on. I can do this!

First External Display Prototype:


  1. Stop Using Batteries (read the project log): This is made for 4 AA batteries with no way to power it from mains (facepalm). It's not like this is a portable piece of equipment. After going through one set of batteries I hit my junk bin and made a mains adapter for it.
  2. Investigation (read the project log): I disassembled the controller enclosure and poked around on the board for clues about how it works. Great news, there's a separate LCD controller potted under some epoxy but they wrote the chip number on the silk screen!
  3. Reverse Engineering the Protocol (early samples and how I figured it out): All I want to do is make a second display that sniffs the SPI commands on the stock controller and acts accordingly. I've been sampling data and working out the scheme.
  4. Prototype Hardware (read the project log): Implemented a proof of concept using ATmega168 and a two-digit 7-segment display that receives LCD data from the elliptical machine, decodes it, and shows the middle two digits of the time display on the breadboard's LED display.

  • Prototype Hardware

    Mike Szczys01/26/2017 at 17:56 0 comments

    Now that I've figured out some of the SPI schema I want to make sure I can automatically harvest and display that data with some add-on hardware.

    I have measured the logic levels at 3.3V which is perfect for hardware options I have on hand. I grabbed my trusty ATmega168 which I use for a lot of prototyping. It will run on 3.3V and has hardware SPI which can operate in slave mode and has plenty of IO to hook up a two digit 7-segment display (6940HR).

    Firmware Description:

    SPI packets are sent out by the elliptical machine every 100ms with a clock rate of 125kHz. The packets are 16 bytes (plus one extra bit but I'm really just ignoring that).

    Follow along in main.c code. This is from tagged snapshot (prototype1).

    I'm using a hardware interrupt to received each byte but it's important to make sure we know where each packet begins. Because of this, my interrupt sets a flag when it begins to receive data. My main loop watches for this flag and checks for the Chip Select to go high, signaling the end of a packet. The two of these allow the main loop to know when transmission has ended at which point the interrupts are disabled and the received data is processed. Here's the general flow of the program:

    • SPI transmission starts. The interrupt service routine clears the flag (SShighFlag = 0) and begins filling an array with the data, incrementing an index as it goes. If that index overflows the first item in the array is set to 0x00 and transmission continues.
    • The main loop watches for the SShighFlag to be zero an for the SS pin to go high again. These two will indicate the packet transmission has finished
    • Global interrupts are disabled while we process data (transmission happen every 10ms so missing some will not matter
    • Received data must start with 0xA0, if no there has been a problem (like buffer overflow described above) and the packet is ignored
    • The validated packet is processed, display updated, SShighFlag is set, and global interrupts enabled once more to watch for the next packet

    The segment decoding in this prototype firmware is extreme. The display has a finite number of states (0-9 and the letter P for 7-segment displays) to a lookup table should be used for subsequent versions of the firmware.

    Here's the prototype connected to the elliptical machine. With this proof of concept I can not take the time to reverse engineer the rest of the SPI scheme and then begin work on the final hardware.

    7-segment Display Pin Connections:

    For verbosity of documentation, here are the connections for this set setup (I'm not planning to make a schematic of this setup):

    • Pin 1 -- PD1
    • Pin 2 -- PD2
    • Pin 3 -- PD3
    • Pin 4 -- NC
    • Pin 5 -- PD4
    • Pin 6 -- PB6
    • Pin 7 -- PB7
    • Pin 8 -- PD5
    • Pin 9 -- NC
    • Pin 10 -- PD6
    • Pin 11 -- PD7
    • Pin 12 -- PB0
    • Pin 13 -- GND
    • Pin 14 -- GND
    • Pin 15 -- PB1
    • Pin 16 -- PC0
    • Pin 17 -- PC1
    • Pin 18 -- PC2

    SPI connections:

    • GND -- GND
    • CS -- PB2
    • WR -- PB5
    • DATA -- PB3

  • Progress Reverse Engineering

    Mike Szczys01/24/2017 at 21:16 0 comments

    When adjusting the resistance of the exercise machine, one single digit of the large time dispaly (the 10's digit) is shown on the screen. This is perfect for reverse engineering the protocol because there is very little data change from sample to sample to puzzle out.


    I first looked only at the two changing bytes of the SPI packet (line 2-8 below). I arbitrarily assigned a number to each of seven segments of a digit (lines 25-31 below). I then began comparing the samples that I had for numbers where just one segment is different.

    To do so I made a list of segments -- and missing segments in parenthesis -- for each number (lines 33-42 below). This makes it obvious that 0 and 6 both uses segment 3 and 4 differently which makes the bit location for those obvious. Once that was established I removed those columns from lines 16-21 using stars. I just kept going until I had almost all of them.

    The only problem I had is that I had not captured a 7 or a 9 which is the only way to establish the difference between the top segment and the bottom segment. But I had a way around that.

    When choosing one of the six exercise routines the display shows only P1, P2... P6. I had also captured this data (below). A close look at this showed that the next digit to the left (hour-ones digit) uses the same data scheme. Showing "P" on the display doesn't use the bottom segment and this solved the rest of the puzzle.

    Spotting the Peculiar:

    Looking closely, each digit spans a curious number of nibbles. Here's a binary example for the numeral 8:

    0b0000 0111 1011 1000
    The data can easily fit in two nibbles, why does it bleed over into 3? The answer is in the datasheet for the LCD controller (HT621):

    Look at the data line and count the bits up to the first data nibble. There are 3 bits to signify a "write" operation, then 6 bits for the memory address followed by an indeterminate number of 4-bit nibbles of data.

    My microcontroller's hardware SPI accepts 8-bit packets. So after this 9-bit preamble, all of the data nibbles are shifted by 1 bit. Oh well, I'm going to be decoding this data packet for my own custom display anyway so I'll deal with it on that end of things.

    I've seen 9-bit SPI before, but in that case every operation was 9-bits. I don't know if there are microcontrollers out there that can roll with this peculiarity in hardware.

  • Reverse Engineering the Protocol

    Mike Szczys01/16/2017 at 02:30 0 comments

    I'm beginning to reverse engineer the protocol used by the LCD controller. I think this is simply prefaced by a memory address and then the binary values for which segments of the LCD should be turned on. If I'm right, the memory address will always be the same, and it's just a matter of correlating which segments are on with which bits are written to each register..

    Here are four screens to get me started:

    Preprogrammed exercise 1 splash screen. Captured output:

    0xA0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x98, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80

    Timing screen for preprogrammed exercise 1. Captured output:
    0xA0, 0x00, 0x00, 0x00, 0x06, 0xDF, 0xAF, 0xEF, 0xA8, 0x40, 0x07, 0xA9, 0x20, 0x00, 0x00, 0x00, 0x00

    Splash screen for preprogrammed exercise 3. Captured output:
    0xA0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00

    Timing screen for preprogrammed exercise routine 3. Captured output:

    0xA0, 0x00, 0x7E, 0xFA, 0xC4, 0xFF, 0xAF, 0xEF, 0xA8, 0x40, 0x07, 0xA9, 0x20, 0x00, 0x00, 0x00, 0x00

    I'm just now starting process some of this data to figure out if it is a direct bit-to-segment mapping (which I think it is). Take these early samples with a grain of salt. I might have an off-by-one error on the pictures I took versus the data samples I snapshotted :-/

    I'll update this log as I go.

    I am optimistic that this will be a straightforward process. Looking at the timing diagram for continuous writes I should be in good shape. The leading bits should be 0b101 (write) 0bxxxxx (address) so 0xA0 which we have for each sample is "Write to register 0"

  • Investigation

    Mike Szczys01/16/2017 at 02:04 0 comments

    It was easy to take the computer off of the elliptical machine. All the screws are standard phillips... four holding it to the metal bracket on the machine, five holding the two pieces of the plastic enclosure together.

    Back of the single-PCB computer. Just remove four silver screws at the corners to free it. I was thinking it was too bad that the ICs are potted and I wouldn't be able to read part numbers. But there was a pleasant surpise waiting.

    Here's the other side of that board that hosts the LCD. This is a custom LCD so I figured the driver should be pretty simple to figure out as it's just driving a limited number of segments.

    Not a great picture (and ignore those wires... I soldered to the wrong pins but realized it before anything went awry). But what this does show is the very conveniently named component. The silk screen reads "HT1621_DIE_48SSOP". There's a datasheet for that and it lets you know the pins we're interested: CS, WR, and DATA. I traced those out and soldered wires onto via that made the task pretty easy.

    I've never used the SPI decode feature of my RIGOL 1054z before so I thought I'd give it a try. Success! I took a few sample readings and saved them to CSV on a thumb drive to start the investigation. I don't have a logic analyzer but my Bus Pirate is also a viable option for figuring out the LCD data I want to sniff.

    I actually use this thing exercise so I wanted to get it back together asap. Now that I knew my test points were valid I soldered on some ribbon cable, snaked it out the battery door, and put everything back together.

    It still works, yay! I just need to figure out the order of the serial data and I should have no problem implementing my own auxiliary display that just listens in on the SPI bus.

    For my own records... that ribbon cable is as follows:

    • Brown: Ground
    • Red: CS
    • Orange: WR (CLK)
    • Yellow: DATA

  • Stop Using Batteries

    Mike Szczys01/15/2017 at 19:38 0 comments

    The first thing I did to this was to get rid of batteries. I used some scrap wood with a screw in the end for a battery stand-in. Here you can see the positive and negative connections made in the original battery slots. The only alteration to the exercise machine is a slot cut in the battery lid for the wire from the wall wart to exit.

View all 5 project logs

Enjoy this project?



Does this project spark your interest?

Become a member to follow this project and never miss any updates