Install Other OS on Toshiba Chromebook 2 (CB35-B3340)

When I received a broken Chromebook to play with, I had assumed it was long out of support and my thoughts went to how I might install some operating system other than ChromeOS on it. Then I found that it actually still had some supported lifespan left so I decided to keep it as a Chromebook for occasional use. That supported life ended in September 2021, now it very bluntly tells me to buy a newer model: there will be no more Chrome OS after 92.

Time again to revisit the “install other OS” issue, starting with the very popular reference Mr. Chromebox. Where I learned newer (~2015 and later) Chromebooks are very difficult to get working with other operating systems. I guess this 2014 vintage Chromebook is accidentally close to optimal for this project. Following instructions, I determined this machine has the codename identifier “Swanky” and I have the option to replace default firmware with an implementation of UEFI, in theory allowing me to install any operating system that runs on this x86-64 chip and can boot off UEFI. But first, I had to figure out how to deactivate a physical write protect switch on this machine.

The line “Fw WP: Enabled” is what I need to change to proceed. Documentation on Mr. Chromebox site said I should look for a screw that grounds a special trace on the circuit board. Severing that connection would disable write protect. I found this guide on iFixit, but it is for a slightly different model of Toshiba Chromebook with different hardware. That is a CB35-C3300 and I have a CB35-B3340. The most visible difference is that CPU has active cooling with a heat pipe and fan, but the machine in front of me is passively cooled.

So I will need to find the switch on my own. Starting with looking up my old notes on how to open up this machine and get back to the point where I could see the metal shield protecting the mainboard.

With the bottom cover removed, I have a candidate front and center.

This screw has a two-part pad that could be grounding a trace, though there is an unpopulated provision for a component connected to that pad. This may or may not be the one. I’ll keep looking for other candidates under the metal shield.

A second candidate was visible once the metal shield was removed. And this one has a little resistor soldered to half of the pad.

I decided to try this one first.

I took a thin sheet of plastic (some random product packaging) and cut out a piece that would sit between the split pad and the metal shield with screw.

That was the correct choice, as firmware write-protection is now disabled. I suspect candidate #1 could be used for chassis intrusion protection (a.k.a. “has the lid been removed”) but at this point I have neither the knowledge or the motivation to investigate. I have what I want, the ability to install UEFI (Full ROM) Firmware.

What happens now? I contemplated the following options:

  1. Install Gallium OS. This is a Linux distribution based on Ubuntu and optimized for running on a Chromebook.
  2. I could go straight to the source and install Ubuntu directly. Supposedly system responsiveness and battery life won’t be as good, and I might have more hardware issues to deal with, but I’ll be on the latest LTS.
  3. Or I can stay with the world of Chrome and install a Chromium OS distribution like Neverware CloudReady.

Looking at Gallium, I see it purports to add hardware driver support missing from mainline Ubuntu and stripping things down to better suit a Chromebook’s (usually limited) hardware. There were some complaints that some of Ubuntu’s user-friendliness was trimmed along with the fat, but the bigger concern is that Gallium OS is based on Ubuntu 18 LTS and has yet to update to Ubuntu 20 LTS. This is very concerning as Ubuntu 22 LTS is expected to arrive soon. [UPDATE: Ubuntu 22 LTS “Jammy Jellyfish” has been officially released.] Has the Gallium project been abandoned? I decided to skip Gallium for now, maybe later I’ll decide it’s worth a try.

I already had an installation USB drive for Ubuntu 20.04 LTS, so I tried installing that. After about fifteen minutes of playing around I found a major annoyance: keyboard support. A Chromebook has a different keyboard layout than standard PC laptops. The Chromebook keys across the top of the keyboard mostly worked fine as function keys, but there are only ten keys between “Escape” and “Power” so I didn’t have F11 or F12. There is no “Fn” key for me to activate their non-F-key functions, such as adjusting screen brightness from the keyboard. Perhaps in time I could learn to navigate Ubuntu with a Chromebook keyboard, but I’ve already learned that I have muscle memory around these keys that I didn’t know I had until this moment. It was also missing support for this machine’s audio device, though that could be worked around with an external USB audio device like my Logitech H390 headset. (*) It is also possible to fix the audio issue within Ubuntu, work that Gallium OS supposedly has already done, but instead of putting in the work to figure it out I decided on the third option.

It’s nice to have access to the entire Ubuntu ecosystem and not restricted to the sandbox of a Chrome OS device, but I already have Ubuntu laptops for that. This machine was built to be a small light Chromebook and maybe it’s best to keep it in that world. I created an installation USB drive for Neverware CloudReady and returned this machine to the world of Chrome OS. Unlike Ubuntu, the keyboard works in the Chrome OS way. But like Ubuntu, there’s no sound. Darn. Oh well, I usually use my H390 headset when I wanted sound anyway, so that is no great hardship. And more importantly, it puts me back on the train of Chromium OS updates. Now it has Chromium OS 96, and there should be more to come. Not bad for a Chromebook that spent several years dumped in a cabinet because of a broken screen.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Window Shopping LovyanGFX

One part of having an open-source project is that anyone can offer their contribution for others to use in the future. Most of them were help that I was grateful to accept, such as people filling gaps in my Sawppy documentation. But occasionally, a proposed contribution unexpectedly pops out of left field and I needed to do some homework before I could even understand what’s going on. This was the case for pull request #30 on my ESP_8_BIT_composite Arduino library for generating color composite video signals from an ESP32. The author “riraosan” says it merged LovyanGFX and my library, to which I thought “Uh… what’s that?”

A web search found https://github.com/lovyan03/LovyanGFX which is a graphics library for embedded controllers, including ESP32. But also many others that ESP_8_BIT_composite does not support. While the API mimics AdafruitGFX, this library adds features like sprite support and palette manipulation. It looks like a pretty nifty library! Based on the README of that repository, the author’s primary language is Japanese and they are a big fan of M5Stack modules. So in addition to the software technical merits, LovyanGFX has extra appeal to native Japanese speakers who are playing with M5Stack modules. Roughly two dozen display modules were listed, but I don’t think I have any of them on hand to play with LovyanGFX myself.

Given this information and riraosan’s Instagram post, I guess the goal was to add ESP_8_BIT composite video signal generation as another supported output display for LovyanGFX. So I started digging into how the library was architected to enable support for different displays. I found that each supported display unit has corresponding files in the src/lgfx/v1/panel subdirectory. Each of which has a class that derives from the Panel_Device base class, which implements the IPanel interface. So if we want to add a composite video output capability to this library, that’s the code I expected to see. With this newfound knowledge, I returned to my pull request to see how it was handled. I saw nothing of what I expected. No IPanel implementation, no Panel_Device derived class. That work is in the contributor’s fork of LovyanGFX. The pull request for me has merely the minimal changes needed to ESP_8_BIT_composite to be used in that fork.

Since those changes are for a specialized usage independent of the main intention of my library, I’m not inclined to incorporate such changes. I suggested to riraosan that they fork the code and create a new LovyanGFX-focused library (removing AdafruitGFX support components) and it appears that will be the direction going forward. Whatever else happens, I now know about LovyanGFX and that knowledge would not have happened without a helpful contributor. I am thankful for that!

Power Control Board for TrueNAS Replication Raspberry Pi

Encouraged by (mostly) success of controlling my Pixel 3a phone’s charging, the next project is to control power for a Raspberry Pi dedicated to data backup for my TrueNAS CORE storage array. (It is a remote target for replication, in TrueNAS parlance.) There were a few reasons for dedicating a Raspberry PI for the task. The first (and somewhat embarrassing) reason was that I couldn’t figure out how to set up a remote replication target using a non-root account. With full root level access wide open, I wasn’t terribly comfortable using that Pi for anything else. The second reason was that I couldn’t figure out how to have a replication target wake up for the replication process and go to sleep after it was done. So in order to keep this process autonomous, I had to leave the replication target running around the clock, and a dedicated Raspberry Pi consumes far less power than a dedicated PC.

Now I want to take a step towards power autonomy and do the easy part first. I have my TrueNAS replications kick off in response to snapshots taken, and by default that takes place daily at midnight. The first and easiest step was then to turn on my Raspberry Pi a few minutes before midnight so it is booted up and ready to receive replication snapshot shortly after midnight. For the moment, I would still have to shut it down manually sometime after replication completes, but I’ll tackle that challenge later.

From an electrical design perspective, this was no different from the Pixel 3a project. I plan to dedicate another buck converter for this task and connect enable pin (via a cable and a 1k resistor) to another GPIO pin on my existing ESP32. This would have been easy enough to implement with a generic perforated prototype circuit board, but I took it as an opportunity to play with a prototype board tailored for Raspberry Pi projects. Aside from the form factor and pre-wired connections to Raspberry Pi GPIO, these prototype kits also usually come with appropriate pin header and standoff hardware for mounting on a Pi. Looking over the various offers, I chose this particular four-pack of blank boards. (*)

Somewhat surprisingly for cheap electronics supply vendors on Amazon, this board is not a direct copy of an existing Adafruit item. Relative to the Adafruit offering, this design is missing the EEPROM provision which I did not need for my project. Roughly two-thirds of the prototype area has pins connected as they are on a breadboard, and the remaining one-third are individual pins with no connection. In comparison the Adafruit board is breadboard-like throughout.

My concern with this design is in its connection to ground. It connects only a single pin, designated #39 in most Pi GPIO diagrams and lower-left in my picture. The many remaining GND pins: 6,9,14,20,25,30, and 34 appear to be unconnected. I’m not sure if I should be worried about this for digital signal integrity or other reasons, but at least it seems to work well enough for today’s simple power supply project. If I encounter problems down the line, I can always solder more grounding wires to see if that’s the cause.

I added a buck converter and a pair of 220uF capacitors: one across input and one across output. Then a JST-XH board-to-wire connector to link back to my ESP32 control board. I needed three wires: +Vin, GND and enable. But I used a four-pin connector just in case I want to surface +5Vout in the future. (Plus, I had more four-pin connectors remaining in my JST-XH assortment pack than three-pin connectors. *)

I thought about mounting the buck converter and capacitors on the underside of this board. There’s enough physical space between the board and the Raspberry Pi to fit them. I decided against it on concern of heat dissipation, and I was glad I did. After this board was installed on top of the Pi, the CPU temperature during replication rose from 65C to 75C presumably due to reduced airflow. If I had mounted components underneath, that probably would have been even worse. Perhaps even high enough to trigger throttling.

I plan to have my ESP32 control board run around the clock, so this particular node doesn’t have the GPIO deep sleep state problem of my earlier project with ESP8266. However, I am still concerned about making sure power stays on, and the potential problems of ensuring so.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

ESP8266 MicroPython Exception Handling Helps Robustness

I had to solve a few problems encountered publishing data to MQTT using ESP8266 MicroPython, running into MQTTException raised by the library. On the upside, dealing with MQTTException reminded me that I don’t usually have the luxury of exception handling on microcontrollers.

Exception handling in Python is my favorite part so far of using MicroPython on a microcontroller. I’m no stranger to calling APIs and checking error codes in typical C programming style and I can certainly work in that environment, but I do enjoy using a language like Python with exception handling mechanisms because it allows me to structure code in a way I find much more readable. This is important, especially for small projects where I don’t expect to look at the code on a regular basis. By the time I need to come back and modify the code months or years later, I’m looking at it with essentially fresh eyes. Comments are critical, but a good structure is very helpful too!

If I don’t have any exception handlers, an error would stop execution of my program and break into REPL awaiting diagnosis and repair. This is great while I’m developing the code, but I won’t want that later. During runtime I expect errors to be one of three types:

  1. Failing to connect to WiFi. This could happen if my WiFi router is in the middle of a firmware update, and for such harmless scenarios the best thing is to go to sleep and try again later.
  2. Failing to connect to MQTT broker. This could happen if I took down my Mosquitto docker container, again probably for an update.
  3. Failure to publish ADC data. This could happen if the WiFi router or Mosquitto went down in between connection and data publishing.

For all of these cases, the best thing to do is to try again later. Which for this project is actually the exact same thing I want to do even when everything is successful: go to sleep for a minute and repeat everything upon wake.

My first implementation caught all exceptions and proceeded to deep sleep for retry in one minute, but this is a problem: if I encounter a problem outside of the expected errors, or if I want to break into REPL for any other reason like updating the program with a new feature, I have only a very narrow window of time to do so. In fact, it was too fast for me to catch it awake!

So I actually want to do something different in case of error: keep the ESP8266 awake for 30 seconds or so. Long enough for me to connect a serial terminal and hit Control-C to break into REPL. I could trigger this path by taking down my Mosquitto docker container causing scenario #2 above.

This is an improvement over my first implementation, but I couldn’t upload my improved code. The ESP8266 wakes up, try to report ADC, and immediately go to deep sleep no matter what happens. After some time tearing my hair out trying to break into this narrow time window, I resorted to reflashing the ESP8266 with fresh MicroPython. Now I could actually get into REPL and upload the new code. It’s a good thing I keep these little code projects publicly accessible on GitHub where I could get a copy for my own use if I had to erase it.

I really like what I’ve seen of MicroPython so far, and it’ll definitely be a consideration for future projects. But for this project I’m changing course for no fault of MicroPython.

Second ESP8266 Voltage Monitor is Directly Wired to Buck Converter

Once I got my MicroPython ESP8266 connected to my home network, I expect to continue working with it over the network instead of an USB cable. Which meant it was time for me to take this development board and wire it to a DC voltage buck converter as I did earlier. However, this time I’m going to skip on the perforated prototype circuit board and going for direct wiring. (Sometimes called deadbug style due to folded pins and wires.)

But without the prototype board, I have to handle my own spacing. I cut up an expired credit card and placed the sheet of plastic in between Wemos D1 Mini clone (*) and its MP1584EN DC buck converter (*). Wires looped around the outside of this sheet to carry power lines 3.3V and GND, as well as the pair of 1 Megaohm resistors in series to ADC input pin for measuring voltage.

And relative to the previous iteration, I added one more wire: connecting ESP8266 GPIO16 (labeled D0 on a Wemos D1 Mini board) to the reset (RST) pin. This is required for an ESP8266 to wake from deep sleep, and this requirement is the very first sentence on MicroPython section for ESP8266 deep sleep. I’m going to guess that it is front and center because enough people forgot to do this critical step and their ESP8266 wouldn’t wake from sleep.

Once this package was tested to function over MicroPython WebREPL, I wrapped the whole thing up in clear heat shrink tube(*) (not pictured in title image) for a nice compact package. I could now query ADC value representing input voltage over WebREPL, but that’s not useful until I could report that value via MQTT.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

ESP8266 MicroPython Automatically Remembers WiFi

There were a few speed bumps on my way to a MicroPython interactive prompt, also known as REPL the read, evaluate, print loop. But once I got there, I was pretty impressed. It was much friendlier to iterative experimentation than Arduino on an ESP8266, because I don’t have to reflash and reboot every time. And since the ESP8266 has WiFi capabilities, getting REPL over the network (WebREPL) is even cooler. Now I can experiment while it runs on another power source, completely independent of USB for either power of data.

Before I got there, though, I needed to get this ESP8266 on my home WiFi network. By default, MicroPython sets up an access point for its own network so I need to turn “AP mode” off. Then I turn on “station mode” which allows connection to my WiFi router given its SSID and password.

import network

ap = network.WLAN(network.AP_IF)
ap.active(False)

sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.config(dhcp_hostname='my hostname')
sta.connect('my wifi ssid','my wifi password')

I added one optional element: the dhcp_hostname parameter. This is the name shown to my router and probably other devices on my home network. If I don’t set this, the default name is “ESP-” followed by six hexadecimal digits of the ESP8266’s MAC address. That’s not a particularly memorable name so I wanted something I could remember and recognize.

And then, to my surprise, MicroPython remembered the network settings upon restart. I wrote a piece of Python code to perform this routine that I could run whenever I rebooted the board. But when I set out to test it by rebooting the board, it automatically reconnected to WiFi. This tells me a successful WiFi connection would cause a write to flash memory, which implies I should not run my WiFi connection code upon every startup. I expect to make this board go to deep sleep frequently and, if it writes WiFi information to flash every time it wakes up, I will quickly wear out the flash.

But that is just a hypothesis. As MicroPython is an open source project, it should be possible for me to dig into the code and figure out exactly when MicroPython writes WiFi connection information to flash. Perhaps it isn’t as bad as I feared it would be. Until then, however, I will hold off running my WiFi connection script.

A downside of not running my script is the DHCP hostname, which is not remembered upon reboot and this board reverted back to the default ESP-prefix name. But I can live with that for now, the next step is to set up my hardware for playing with deep sleep under battery power.

A Few Speed Bumps on the Road to ESP8266 MicroPython

I decided to play with MicroPython on an ESP8266 and started with MicroPython documentation page appropriately titled Quick reference for the ESP8266. It was almost (but not entirely) smooth sailing with the inexpensive Wemos D1 Mini clone(*) I had on hand.

I had recently switched desktop computers, with a fresh installation of Windows, so everything had to be reinstalled. Starting with Python, since I need that to run esptool tool to flash Espressif devices. It got its own virtual Python environment with venv and I could start working with the ESP8266.

I verified that flash size matched 4MB as per Amazon product listing with esptool.py --port COM4 flash_id

Then the first step in MicroPython directions: erase whatever might be in flash: esptool.py --port COM4 erase_flash

Followed by flashing the board with MicroPython, version 1.17 was the latest as of this writing: esptool.py --port COM4 --baud 460800 write_flash --flash_size=detect 0 esp8266-20210902-v1.17.bin

esptool.py v3.1
Serial port COM4
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash will be erased from 0x00000000 to 0x0009afff...
Flash params set to 0x0040
Compressed 633688 bytes to 416262...
Wrote 633688 bytes (416262 compressed) at 0x00000000 in 9.4 seconds (effective 537.1 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

That looked good! But I thought I’d verify anyway: esptool.py --port COM4 --baud 460800 verify_flash --flash_size=detect 0 esp8266-20210902-v1.17.bin

esptool.py v3.1
Serial port COM4
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Verifying 0x9ab58 (633688) bytes @ 0x00000000 in flash against esp8266-20210902-v1.17.bin...
-- verify OK (digest matched)
Hard resetting via RTS pin...

This all looked good, but during this process I found communication with my board was unreliable. Occasionally I would fail to connect:

esptool.py v3.1
Serial port COM4
Connecting........_____....._____....._____....._____....._____....._____....._____

A fatal error occurred: Failed to connect to Espressif device: Invalid head of packet (0x08)

The frustrating part is that I don’t know what causes this, all I could do is retry until it worked. I didn’t notice anything I did differently between the times that worked and the times that failed. Is it the ESP8266? Is it the CH340 serial port bridge? Is it my USB cable? I can’t tell. The good news with MicroPython is that, once it is flashed, I could work via serial port without further headaches with esptool.

I remembered that PlatformIO Visual Studio Code had a serial port monitor, and it was indeed able to connect. But as the name stated, it was only a monitor and while I could see a MicroPython prompt I couldn’t type any commands back. Looking around Visual Studio extension marketplace I found a serial terminal extension published by Nordic Semiconductor. This allowed me to type commands into the MicroPython prompt and verify it worked, but frustratingly I could not copy/paste in this terminal. So much for a modern integrated environment! I returned to trusty old PuTTY for my MicroPython serial terminal needs and got to work.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Problems Making ESP32 Hold GPIO While Asleep

I had several motivations for using an ESP32 for my next exercise. In addition to those outlined earlier, I also wanted to explore using these microcontrollers to control things. Not just report a measurement. In other words, I wanted to see if they can be output nodes as well as data input nodes. This should be a straightforward use of GPIO pins, except for another twist: I also want the ESP32 to be asleep most of the time to save power.

The ESP32 has several sleep modes available, and I decided to go straight for the most power-saving deep sleep as my first experiment. It was straightforward to call esp_deep_sleep() at the end of my program, and this was the easiest sleep mode because I don’t have to do much configuration or handling different cases of things that might happen during sleep. When an ESP32 wakes up from deep sleep, my program starts from the beginning as if it had just been powered up. This gives me a clean slate. I don’t have to worry about testing to see if a connection is still good and maybe reconnecting if not: I always have to start from scratch.

So what are the states of GPIO pins while an ESP32 is asleep? Reading the documentation, I thought I could command digital output pins to be held either high or low while the ESP32 was in deep sleep. However, my program calling gpio_deep_sleep_hold_en() didn’t actually hold output state like I thought it would. I think my program is missing a critical step somewhere along the line.

Some research later, I haven’t figured out what I am missing, but I have learned I’m not alone in getting confused. I found ESP-IDF issue #3370, which was resolved as a duplicate of ESP32 Arduino Core issue #2712. Even though it was marked as resolved, it is still getting traffic from people confused about why GPIO states aren’t held during sleep.

As a workaround, I can use an IO expander chip like the PCF8574. Letting that hold output pin state high or low while the ESP32 is asleep. As a relatively simple chip, I expect the PCF8574 wouldn’t use a lot of power to do what it does. But it would still be an extra chip adding extra power draw. I intend to figure out ESP32 sleep mode GPIO at some point, but for now the project is both moving on. Well, at least in software, the hardware side is taking a step back to ESP8266.


[Source code for this project (flaws and all) is publicly available on GitHub]

Switching to ESP32 For Next Exercise

After deciding to move data processing off of the microcontroller, it would make sense to repeat my exercise with an even cheaper microcontroller. But there aren’t a lot of WiFi-capable microcontrollers cheaper than an ESP8266. So I looked at the associated decision to communicate via MQTT instead, because removing requirement for an InfluxDB client library meant opening up potential for other development platforms.

I thought it’d be interesting to step up to ESP8266’s big brother, the ESP32. I could still develop with the Arduino platform with an ESP32 but for the sake of practice I’m switching to Espressif’s ESP-IDF platform. There isn’t an InfluxDB client library for ESP-IDF, but it does have a MQTT library.

ESP32 has more than one ADC channel, and they are more flexible than the single channel on board the ESP8266. However, that is not a motivate at the moment as I don’t have an immediate use for that advantage. I thought it might be interesting to measure current as well as voltage. Unfortunately given how noisy my amateur circuits have proven to be, I doubt I could build a circuit that can pick up the tiny voltage drop across a shunt resistor. Best to delegate that to a dedicated module designed by people who know what they are doing.

One reason I wanted to use an ESP32 is actually the development board. My Wemos D1 Mini clone board used a voltage regulator I could not identify, so I powered it with a separate MP1584EN buck converter module. In contrast, the ESP32 board I have on hand has a regulator clearly marked as an AMS1117. The datasheet for AMS1117 indicated a maximum input voltage of 15V. Since I’m powering my voltage monitor with a lead-acid battery array that has a maximum voltage of 14.4V, in theory I could connect it directly to the voltage input pin on this module.

In practice, connecting ~13V to this dev board gave me an audible pop, a visible spark, and a little cloud of smoke. Uh-oh. I disconnected power and took a closer look. The regulator now has a small crack in its case, surrounded by shiny plastic that had briefly turned liquid and re-solidified. I guess this particular regulator is not genuine AMS1117. It probably works fine converting 5V to 3.3V, but it definitely did not handle a maximum of 15V like real AMS1117 chips are expected to do.

Fortunately, ESP32 development boards are cheap, counterfeit regulators and all. So I chalked this up to lesson learned and pulled another board out of my stockpile. This time voltage regulation is handled by an external MP1584EN buck converter. I still want to play with an ESP32 for its digital output pins.

Convert Nexus 5 To Use External DC Power

I just took apart a BL-T9 battery module from my old Nexus 5 cell phone. I had removed it as a precaution since its internal chemical situation had degraded, puffing up and pushing itself out of the phone. Even though the phone still seemed to work (or at least it would boot up) a puffed-up lithium-ion polymer battery is not a good situation.

But now I have an otherwise functional cell phone without a battery. It would be a shame to toss it in the e-waste, but it needs a power source to do more than just gathering dust. The first experiment was to see if the phone would run on USB power with the battery removed, and that was a bust. Trying to turn the phone on would show the low battery icon and then the screen goes dark again.

I then looked online for a replacement battery. (*) They range from a very poorly reviewed $10 unit on Amazon, up through the $35-$50 range. But did I want to spend that money? I don’t really need this device to be portable and battery-powered anyway. It’s more likely to go the way of my HP Stream 7 and become an always-on externally powered display, something I’ve tried earlier and plan to revisit in the future.

With my HP Stream 7 power experiments fresh on my mind, I decided to convert this device to run on external DC power as well. It won’t have a battery to buffer spikes in power draw, but that might be fine. An Android phone has lower power demand than a Windows tablet. For starters, I wouldn’t be plugging in external USB peripherals. Also with the HP experience in mind, I expect there are device drivers in its Android system image that expects to communicate with the chip in the battery module. So I’ll keep that module in the circuit and solder a JST-RCY connector where the battery cell terminals used to be. As a quick test, and one last farewell to the old puffy battery cell, I connected it to the JST-RCY connector. This electrically replicated original arrangement so I could verify everything still worked. I pushed the power button and there was no response. Oh no!

I mentally explored some possibilities: perhaps there is a thermal fuse on board the circuit board that killed the connection when it sensed the heat of my soldering iron. Or perhaps the chip would refuse to power up if the battery voltage ever sank to zero. As an experiment I plugged in USB power again, and I was presented with the battery charging animation. Pushing the power button now booted up the phone. Conclusion: if the battery had been disconnected and reconnected, a Nexus 5 requires USB power to jump start the cold boot process.

With the system verified to function (and learning the cold startup procedure with USB power) I disconnected the puffy battery for disposal. I replaced it with a MP1584EN DC voltage buck converter module (*) I adjusted to output 4.2V simulating a fully charged battery. I also added an electrolytic capacitor in the hope of buffering spikes in power draw. After using USB power for cold start, the Nexus 5 was content to run in this configuration for over a week. Perfectly happy to believe it was running on a huge battery the whole time.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Degraded Nexus 5 Battery Demands Immediate Removal

I’m happy I found a way to make use of the HP Stream 7 tablet, though I have no immediate use for it so I jotted down some notes before putting it away in my pile of old hardware. When I did so, I found an unpleasant surprise in that pile: my old Nexus 5 cell phone shows signs of lithium battery degradation. It has puffed up, pushing against the back panel of the phone and popping a few clips loose. This is not good. I don’t know how long it’s been in this state, but I need to pay immediate attention.

With the first few retaining clips popped loose by the puffy battery, it was relatively simple to pop the remainder loose in order to remove the back panel. However, more disassembly is necessary before the battery could be (nicely) removed.

Further disassembly meant removing six screws holding this inner shield.

Once that inner shield was removed, I could disconnect the data cable running between the top and bottom halves of the phone, and I could electrically disconnect the battery. Mechanically, the battery itself is held by adhesive strips. The puffiness pulled some loose, but the remainder required some persuasion to release. I used a bit of thin clear plastic cut from some thermoformed product packaging.

The battery has puffed up roughly triple of its original thickness. No wonder it didn’t fit inside the phone anymore.

I’m glad I was able to remove the problematic battery before it expressed its degradation in unwanted and exciting ways. (Fire? Maybe fire.) But now I have removed the battery, I might as well take a closer look.

Miscellaneous Notes on HP Stream 7 Installation

My old HP Stream 7 can now run around the clock on external power, once I figured out I needed to disable its battery drivers. Doing so silenced the module that foiled my previous effort. (It would raise an alert: “the tablet has run far longer than the battery capacity could support” and shut things down.) Ignoring that problematic module, remaining drivers in the same large Intel chipset driver package allowed the machine to step down its power consumption. From ten watts to under two watts, even with the screen on. (Though at minimum brightness.) Quite acceptable and I’m quite certain I’ll repurpose this tablet for a project in the future. In the meantime, I wanted to jot down some notes on this hardware as reference.

The magic incantation to get into boot select menu (getting into BIOS, reinstalling operating system, and other tools) is to first shut down the tablet. While holding [Volume Down], hold [Power] until the HP logo is visible. Release power immediately or else it might trigger the “hold power for four seconds to shut off” behavior. (This is very annoying.) The boot select menu should then be visible along with on-screen touch input to navigate without a keyboard.

There are many drivers on the HP driver downloads site. Critical for optimized power consumption — and majority of onboard hardware — is the “Intel Chipset, Graphics, Camera and Audio Driver Pack”. I also installed the “”Goodix Touch Controller Driver” so the touchscreen would work, but be warned: this installer has a mix of case-sensitive and case-insensitive code which would fail with a “File Not Found” error if the directory names got mixed up. (/SWSetup/ vs /swsetup/)

The available drivers are for Windows 8 32-bit (what the machine came with) and Windows 10 32-bit (what it is successfully running now.) The machine is not able to run 64-bit operating system despite the fact its Intel Atom Z3735G CPU is 64-bit capable. I don’t know exactly what the problem is, but when I try to boot into 64-bit operating system installer (true for both Windows 10 and Ubuntu) I get the error screen

The selected boot device failed. Press <Enter> to Continue.
[Ok]

Which reminds me of another fun fact: this machine has only a single USB micro-B port. In order to use USB peripherals, we need a USB OTG adapter. Which is good enough for a bootable USB drive for operating system installation… but then I need to press [Ok] to continue! The usual answer here is to use an USB hub so I could connect both the bootable OS installer and a keyboard. There’s actually no guarantee this would work: it’s not unusual for low-level hardware boot USB to support only root-level devices and not hubs. Fortunately, this tablet supported a hub to connect multiple USB devices allowing bootable USB flash driver for operating system installation to coexist with USB input devices to navigate a setup program.

I’ll probably need some or all of these pointers the next time I dig this tablet out of my pile of hardware. For now, I return it to the pile… where I noticed an unpleasant surprise.

Disable HP Stream 7 Battery Drivers When Externally Powered

I gave up trying to run my HP Stream 7 tablet on external DC power with the battery unplugged. The system is built with a high level of integration and it has become unreliable and too much of a headache to try running the hardware in a configuration it was not designed for. So I plugged the battery back in and installed Windows 10 again. And this time, the Intel chipset driver package installed successfully.

This was a surprise, because I thought my driver problems were caused by hardware I damaged when I soldered wires for direct DC power. Plugging in the battery allowed these drivers to install. And the driver package is definitely doing some good, because idle power draw with screen on minimum brightness has dropped from nearly 10W to just under 2W. This is a huge improvement in power efficiency!

So I wanted the drivers for low power operation, but maybe I don’t need every driver in the package. I went into device manager to poke around and found the key to my adventure: The “Batteries” section and more importantly the “Micro ACPI-Compliant Control Method Battery” device. This must have been the driver that rendered the system unbootable once I unplugged the battery — as an integrated system, there’s no reason for the driver to account for the possibility that the user would unplug the battery!

But now that I see this guy exists, I think perhaps it is part of the mechanism that outsmarted me and was skeptical running on external power. I disabled the drivers in the “Batteries” section and rebooted. I reconnected the external power supply keeping battery at 3.7V. Disabling the battery power related drivers were the key to around-the-clock operation. With the battery device absent from the driver roster, there’s nothing to tell the system to shut down due to low battery. But since the battery hardware is present, the driver package could load and run and there’s something to buffer sharp power draws like plugging in USB hardware. This configuration was successful running for a week of continuous operation.

Drawing a modest two watts while idle, this tablet can now be used as anything from a data dashboard, to a digital picture frame, or any other project I might want to do in the future. I don’t know what it will be yet, but I want to make sure I write down a few things I don’t want to forget.

HP Stream 7 Really Wants Its Battery

I’ve been trying to get a HP Stream 7 tablet running in a way suitable to use as a future project user interface or maybe a data dashboard. Meaning I wanted it to run on external power indefinitely even though it could not do so on USB power alone. When I supplied power directly to the battery it would shut down after some time. The current session deals with disconnecting the battery and feeding the tablet DC directly, but this machine was designed to run with a battery and it really, really wanted its battery.

While I could feed it DC power and it would power up, it would intermittently complain about its battery being very low. This must be in hardware because it would occur when booting into either Windows or a Debian distribution of Linux. This shouldn’t be an input voltage problem, as my bench power supply should be keeping it at 3.7V. But there’s something trigging this error message upon startup and I have to retry rebooting several times before operation would resume:

HP Battery Alert

The system has detected the storage capacity of the battery stated below to be very low. For optimal performance, please attach the power adapter to charge the battery over 3%, and then re-power on the unit.

Primary (internal) Battery

Currently Capacity: 2 %

System will auto-shutdown after 10 second

Perhaps my bench power supply isn’t as steady as I assume it is. Perhaps there are problems keeping up with changes in power demand and that would occasionally manifest as a dip in voltage that triggers the battery alert. Another symptom that supports the hypothesis is the fact I couldn’t use USB peripherals while running on the bench power supply. When I plug in a USB peripheral, the screen goes black and the system resets, consistent with a power brownout situation.

So to make the hardware happy and to support sudden spikes in power requirements, I really need to plug the battery back in. Trying to run without battery was a fun experiment but more importantly it gave me an idea on running this tablet on continuous external power: silence the battery driver.

HP Stream 7 Running Debian with Raspberry Pi Desktop

My HP Stream 7 seems to be having problems with a Windows device driver, but the problematic driver is somewhere in a large bundle of Intel chipset related drivers. For another data point I thought I would try an entirely different operating system: Debian with Raspberry Pi Desktop. Also, because I thought it would be fun.

Debian with Raspberry Pi Desktop is something I encountered earlier when looking for Linux distributions that are familiar to me and built for low-end (old) PC hardware left behind by mainline Ubuntu builds or even Chrome OS. The HP Stream 7 tablet fit the bill.

One amusing note is that since HP Stream 7 is formally a tablet, the default resolution is portrait-mode which means taller than it is wide. Unlike the Windows installer which knew to keep to the middle of the screen, the Debian installer scaled to fit the entire screen making for some very difficult to read tall narrow text.

Once up and running, the Debian with Raspberry Pi desktop ran on this tablet much as Raspberry Pi runs its Raspberry Pi OS, except this configuration is comparable to a fresh installation of Windows: many devices didn’t have drivers for proper function. I disabled Secure Boot in order to access non-mainline device drivers, which is thankfully straightforward unlike some other PCs of the era I had played with. But even then, many drivers were missing. Video and WiFi worked, but sound did not. A pleasant surprise was that the touchscreen worked as input, but only at the default orientation. If I rotate the desktop, the touchscreen did not adjust to fit. And while an idle Debian drew less power (~8W) than plain vanilla Windows (~10W) it is still significantly worse than this tablet running at its best.

Seeing Debian with Raspberry Pi Desktop run on this tablet was an amusing detour and possibly an option to keep in mind for the future. On the upside, at no point did Debian complain that the battery is low, because the operating system didn’t think there was a battery at all. The hardware, however, really misses the battery’s absence.

HP Stream 7 Reboot Loop Linked to Intel Chipset Windows Driver

I disconnected the battery on my HP Stream 7 tablet and soldered wires to put power on its voltage supply lines. The good news is that the tablet would start up, the bad news is that Windows couldn’t complete its boot sequence and gets stuck in a reboot loop. After a few loops, Windows notices something is wrong and attempted to perform startup repair. It couldn’t fix the problem.

My first thought was that I had damaged a component with my soldering. A small tablet has tiny components and I could have easily overheated something. But portions of the computer is apparently still running, because I could still access the Windows recovery console and boot into safe mode. But I didn’t have any idea on what to do to fix it while in safe mode.

Since there were no data of consequence on this tablet, I decided to perform a clean installation of Windows. If it succeeds, I have a baseline from which to work from. If it fails, perhaps the failure symptoms will give me more data points to diagnose. A few hours later (this is not a fast machine) I was up and running on Windows 10 21H2. Basic functionality seemed fine, which was encouraging, but it also meant the machine was running in unoptimized mode. The most unfortunate consequence is that the tablet runs hot. The power supply indicates the tablet is constantly drawing nearly 10 Watts, no matter if the CPU is busy or idle. A basic Windows installation doesn’t know how to put machine into a more power efficient mode, putting me on a search for drivers.

Since the tablet is quite old by now (Wikipedia says it launched in 2014) I was not optimistic, but I was pleasantly surprised to find that HP still maintains a driver download page for this device. Running down the list looking for an Intel chipset driver, I found a bundled deal in the “Intel Chipset, Graphics, Camera and Audio Driver Pack“. It sounded promising… but during installation of this driver pack, the tablet screen went black. When I turned it back on, the dreaded reboot loop returned. Something in this large package of Windows drivers is the culprit. Maybe I could try a different operating system instead?

Direct DC Power on HP Stream 7 Renders Windows Unbootable

While spending way too much time enjoying the game Hardspace: Shipbreaker, I was actually reminded of a project. In the game, safely depowering a ship’s computers involve learning which power systems are on board and disconnecting them without electrocuting yourself. It got me thinking about my old HP Stream 7 tablet that couldn’t run indefinitely on USB power and refused to believe an illusion of free energy when I supplied power on the lithium-ion battery cell. I thought it might be interesting to see what would happen if I disconnected the battery and supplied DC power directly.

My hypothesis is that the earlier experiment was foiled by the battery management PCB, it was too smart for its own good and realized the tablet had consumed far more capacity than its attached battery cell had any business providing and shutting the computer down. By disconnecting that PCB, perhaps the doubting voice would be silenced.

To test this idea, I would need to find the power supply and ground planes on the circuit board. I could solder directly to the empty battery connector, but that would make it impossible to plug the battery back in and was too drastic for my experiment. I could see pads underneath the connector clearly labeled VBAT + and – but I couldn’t realistically solder to them without damaging the connector either.

Taking my multi-meter, I started probing components near that battery connector for promising candidates. The search didn’t take long — the closest component had pads that connected to the voltage planes I wanted. I had hoped to find a decoupling capacitor nearby, but this doesn’t look like a capacitor. With a visible line on one side, it looks like a diode connected the “wrong” way. Perhaps this protects the tablet from reverse voltage: if VBAT +/- were reversed, this diode would happily short and burn out the battery in the interest of protecting the tablet.

Whatever its actual purpose, it serves my need providing a place to solder wires where I can put 3.7V (nominal voltage for single lithium-polymer battery cell) to power the tablet while its original battery is unplugged.

Good news: The machine powers up!

Bad news: Windows doesn’t boot anymore!

I could see the machine boot screen with the HP logo, and I could see the swirling dots of Windows starting up. But a few seconds later, the screen goes blank. We return to the HP logo, and the process repeats. Time to diagnose this reboot cycle.

Arduino Library Versioning For ESP_8_BIT_Composite

I think adding setRotation() support to my ESP_8_BIT_Composite library was a good technical exercise, but I made a few mistakes on the administrative side. These are the kind of lessons I expected to learn when I decided to publish my project as an Arduino library, but they are nevertheless a bit embarrassing as these lessons are happening in public view.

The first error was not following sematic versioning rules. Adding support for setRotation() is an implementation of missing functionality, it did not involve any change in API surface area. The way I read versioning rules, the setRotation() update should have been an increase in patch version number from v1.2.0 to v1.2.1, not an increase in minor version from v1.2.0 to v1.3.0. I guess I thought it deserved the minor version change because I changed behavior… but by that rule every bug fix is a change in behavior. If every bug fix is a minor version change, then when would we ever increase the patch number? (Never, as far as I can tell.)

Unfortunately, since I’ve already made that mistake, I can’t go back. Because that would violate another versioning rule: the numbers always increase and never decrease.

The next mistake was with a file library.properties in the repository, which describes my library for the Arduino Library Manager. I tagged and released v1.3.0 on GitHub but I didn’t update the version number in library.properties to match. With this oversight, the automated tools for Arduino library update didn’t pick up v1.3.0. To fix this, I updated library.properties to v1.3.1 and re-tagged and re-released everything as v1.3.1 on GitHub. Now v1.3.1 shows up as an updated version in a way v1.3.0 did not.

Screen Rotation Support for ESP_8_BIT_Composite Arduino Library

I’ve had my head buried in modern LED-illuminated digital panels, so it was a good change of pace to switch gears to old school CRTs for a bit. Several months have passed since I added animated GIF support to my ESP_8_BIT_Composite video out Arduino library for ESP32 microcontrollers. I opened up the discussion forum option for my GitHub repository and a few items have been raised, sadly I haven’t been able to fulfill the requests ranging from NTSC-J support (I don’t have a corresponding TV) to higher resolutions (I don’t know how). But one has just dropped in my lap, and it was something I can do.

Issue #21 was a request for the library to implement Adafruit GFX capability to rotate display orientation. When I first looked at rotation, I had naively thought Adafruit GFX would handle that above drawPixel() level and I won’t need to write any logic for it. This turned out to be wrong: my code was expected to check rotation and alter coordinate space accordingly. I looked at the big CRT TV I had sitting on my workbench and decided I wasn’t going to sit that beast on its side, and then promptly forgot about it until now. Whoops.

Looking into Adafruit’s generic implementation of drawPixel(), I saw a code fragment that I could copy:

  int16_t t;
  switch (rotation) {
  case 1:
    t = x;
    x = WIDTH - 1 - y;
    y = t;
    break;
  case 2:
    x = WIDTH - 1 - x;
    y = HEIGHT - 1 - y;
    break;
  case 3:
    t = x;
    x = y;
    y = HEIGHT - 1 - t;
    break;
  }

Putting this into my own drawPixel() was a pretty straightforward way to handle rotated orientations. But I had overridden several other methods for the sake of performance, and they needed to be adapted as well. I had drawFastVLine, drawFastHLine, and fillRect, each optimized for their specific scenario with minimal overhead. But now the meaning of a vertical or horizontal line has become ambiguous.

Looking over at what it would take to generalize the vertical or horizontal line drawing code, I realized they have become much like fillRect(). So instead of three different functions, I only need to make fillRect() rotation aware. Then my “fast vertical line” routine can call into fillRect() with a width of one, and similarly my “fast horizontal line” routine calls into fillRect() with a height of one. This invokes some extra computing overhead relative to before, but now the library is rotation aware and I have less code to maintain. A tradeoff I’m willing to make.

While testing behavior of this new code, I found that Adafruit GFX library uses different calls when rendering text. Text size of one uses drawPixel() for single-pixel manipulation. For text sizes larger than one, they switch to using fillRect() to draw more of the screen at a time. I wrote a program to print text at all four orientations, each at three different sizes, to exercise both code paths. It has been added to the collection of code examples as GFX_RotatedText.

Satisfied that my library now supports screen rotation, I published it as version 1.3.0. But that turned out to be incomplete, as I neglected to update the file library.properties.

HP Stream 7 Refuses to Believe in Free Energy

After salvaging the LED backlight from a Chunghwa CLAA133UA01 display panel, I have processed all the disembodied panels in my hardware stack. But I still have plenty of other displays still embodied in some type of hardware of varying levels of usefulness. The least useful item in the pile is my HP Stream 7 Windows tablet. For reasons I don’t understand, it doesn’t want to charge its battery while it is up and running. It seems the only way to charge the battery is to plug it in while it is powered off.

If I wanted to use this tablet as portable electronics as originally intended, this is annoying but workable. But there’s not much this old tablet could do that my phone (which has grown nearly as large…) can’t do, so I wanted to use it as a display. But if it can’t charge while running, and it can’t run without its battery, then it’s not going to be useful as an always-on display. After poking around its internals, I set the tablet aside in case I have ideas later.

It is now later! And here is the idea: if I can’t convince the tablet to charge its battery while running, perhaps I can do the charging myself. I peeled back some protective plastic to expose the battery management circuit board, and soldered a JST-RCY compatible power connector(*) in parallel with the lithium-polymer battery cell.

Putting this idea to the test, I first ran the tablet until the battery voltage dropped to 3.7V, the nominal voltage for a LiPo battery cell. I then connected my benchtop power supply to this newly soldered connector. The power supply was adjusted to deliver a steady 3.7V. In theory this means the battery would drain no further, and all power for the tablet would be supplied by my bench power supply.

To test longevity, I turned off all power-saving functions so the tablet would not turn off the screen or try to go to sleep. The tablet was content to run in this condition for many hours, and after the first day I was optimistic it would be happy to run indefinitely. Unfortunately, this budget tablet was smart enough to notice something was wrong. I’m not sure how it knew, but it definitely refused to believe the illusion its battery is an endless source of energy. Despite the fact that battery voltage was held steady at 3.7V, on-screen battery percentage started dropping after about forty hours. Eventually the indicated charge dropped below 10% and entered battery-saver mode, followed by shutting itself down. Despite the fact its battery voltage was held at 3.7V, this tablet acted as if the battery has been depleted.

After the failure of this test, I contemplated pulling it apart and extract the tablet backlight as I did to a broken Amazon Fire tablet. But I decided against doing anything destructive, and I put it aside yet again hoping to think of something else later. In the meantime I switch gears from this digital tablet to an analog glass tube TV.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.