Battery Powered Raspberry Pi in Repurposed Laptop
by Frank_Adams in Circuits > Electronics
13855 Views, 70 Favorites, 0 Comments
Battery Powered Raspberry Pi in Repurposed Laptop

Repurposing an old laptop is a fun DIY project and it will breath new life into an old friend. I've put a Raspberry Pi in a Dell laptop before, utilizing a Teensy keyboard controller and EBay video card. What was missing from that project was a way to charge the original battery in order to make a truly portable laptop. I got lucky when I put a Pi in a Sony Vaio laptop that had a separate battery charger board. Usually the charger circuit goes away when you pull the old motherboard. This Instructable will describe two battery charge controller boards that work with 2, 3, or 4 series wired lithium cells. One board is based on a Max1873 chip along with an ATtiny85 microcontroller that acts as a supervisor. The other board uses a MP26123 or MP26124 chip and doesn't need a microcontroller. Both boards will shut down charging based on the battery voltage, temperature, current, and total time. The System Management Bus (SMBus) is controlled by the Pi to read the status registers that are part of the battery pack's, battery management system (BMS). If the battery charge runs low, the Pi automatically performs a safe shutdown. Cairo graphics is used to create a small window that shows a battery fuel gauge and the state of charge (SOC) percentage. I've added an alternative approach to read the battery status registers using a CP2112 bridge chip that translates USB to SM Bus. The following steps should work for most old laptops to build a portable Raspberry Pi.
I will include download buttons for the relevant files in the Instructable. You can also go to my GitHub repository to view and download all relevant files. The best way to download files from a GitHub repository is to navigate to the top level of the project (Laptop-Battery-Charger in this case) and click the green "Code" download button on the right. Choose the Download ZIP option from the Code pull-down menu. The ZIP file will contain the entire repository content, not just the code but also the board layouts and PDFs.
Keyboard, Touchpad, and Video Converter Card


The keyboard, touchpad, and video converter card are all controlled by a Teensy 3.2 using the same methods described in my KVM Instructable. The Teensy code for a Dell D630 keyboard and touchpad can be downloaded below. If you are using a different laptop, use my USB Keyboard Instructable and Touchpad Hackster project to modify the Teensy code. The FPC connector pins and Teensy I/O signals are detailed in the table shown above. New for this laptop is the power control latch on the battery charger board. Momentarily pushing the power button above the keyboard causes the latch to enable the regulators that power the laptop. To power down the laptop, the user selects a safe shutdown from the GUI or command line. The Pi sends a turn off signal to the Teensy that resets the power latch. The laptops' power button is also monitored by the Teensy for the special case of holding down the button for at least 5 seconds. This provides a way to shut down the laptop if the Pi is locked up.
The M.NT68676.2A video converter card was programmed by the EBay seller for the LCD's resolution. A 40cm long LVDS cable was purchased instead of lengthening the short cable that comes with the card. This laptop can be used as a Keyboard, Video, Mouse (KVM) by flipping the toggle switch on the left side so that the USB from the Teensy is routed to the Micro B USB connector on the back instead of to the wires soldered directly to the Pi's USB connector. This comes in handy when modifying the Teensy code with a PC. The VGA connector on the back of the laptop is cabled to the video converter card so that a PC or other video source can drive the display instead of the Pi. The Teensy code watches for Fn and F8 to be pressed and drives the video card push button signals to select either HDMI or VGA.
The Pi directly drives the video card's power control signal with GPIO 4. This is used to momentarily turn off the display if the battery needs charging. A power status signal from the video card is monitored by the Pi to detect when the video card has been turned off.
Downloads
Raspberry Pi




The laptop has a Raspberry Pi 4B mounted in the space that was previously for the hard drive. All thru hole leads were clipped off the back side of the Pi to reduce it's height. The back side was covered with electrical tape to prevent shorts to the aluminum case. The Pi was positioned out of the drive bay by about 1/4 inch because the bottom edge of the laptop is rounded and the lip of the USB connectors won't fit inside the case. The hard drive face plate was cut with a Dremel and glued with other scrap plastic to make a plastic box to surround the Pi. The box is double-back taped to the Pi to provide protection and so the case can be opened in the future. Heatsinks were added to the CPU, USB Controller, and Ethernet Controller on the Pi. The original laptop fan was positioned to blow on these heatsinks. The Stressberry temperature testing results (given above) show the Pi is sufficiently cooled with no clock throttling. The HDMI 0 connector was cabled to the video card and the 5 volt power was provided on the USB C connector from an LM2596 buck regulator. The GPIO pins were wired as follows:
GPIO 2 = SMBus Data to pin 4 of the battery
GPIO 3 = SMBus Clock to pin 3 of the battery
GPIO 4 = LCD On/Off driven to Video Converter Card (labeled "K0"). Pulse low to turn off, again to turn on.
GPIO 17 = 330Ω series resistor to Blue LED (previously for Bluetooth). 3.3V turns on LED
GPIO 19 = Disable Battery Charger. Driven to Charger Board (labeled "Pi_Cntrl"). 3.3V = Disable, 0V = Enable
GPIO 22 = Video Card Power Status (labeled "Red") received by the Pi. 0V = powered off, 3.3V = powered on
GPIO 26 = Shut Down from Pi to Teensy I/O 29. Sent low when user commands a shut down from the GUI or command line. The following dtoverlay was added to the /boot/config.txt file:
dtoverlay=gpio-poweroff,gpiopin=26,active_low="y"
5 Volt and 10 Volt Buck Regulators

Two LM2596 adjustable Buck regulator boards are used in the laptop. These can be purchased on Amazon or other sites. One regulator was adjusted to provide 10 volts to the video converter card. The other was set to 5.1 volts for the Pi, Teensy, Fan, and on/off LED. The on/off LED was previously for "Hard Disk" activity and needs an 820Ω series resistor. Pin 5 on the LM2596 is normally connected to ground to enable the regulator. I used wire cutters to cut pin 5 (see picture above) on both regulators and bend the pin up so it can be wired to the output of a digital latch circuit on the battery charger board. I added a heat sink on both LM2596 parts.
The video card is normally powered with 12 volts but a battery pack with 3 series cells will go below 11 volts when nearly empty. The LM2596 can regulate 11 volts down to 10 volts and the video card still operates normally. At that voltage, the backlight power supply outputs a lower voltage, causing a dimmer display. This can be compensated for by increasing the brightness setting with the video card push buttons. Be sure to adjust the brightness and contrast with the button board before you cut off the connector. This connector will be used to build a cable from the video board to the Pi and Teensy.
If your battery pack has 4 series wired cells, you can raise the voltage out of the LM2596 to 12 volts instead of 10 volts to drive the video card. At 0% SOC, the battery pack will provide about 13 volts which the LM2596 can regulate down to 12 volts.
Input Power Connector and Micro B USB Connector

I used SMD removal alloy to unsolder the connector from the motherboard that receives the 19 volt DC from the wall supply. The single sided copper clad board shown above, was cut to hold this connector and holes were drilled to match the mounting holes in the laptop case. A Sparkfun micro B USB breakout connector was also attached to this board for direct access to the Teensy. The 19 volts goes to the battery charger board and also thru two 8.2KΩ 1/8 watt resistors wired in parallel to turn on the "Power" LED.
Battery Pinout


I looked for schematics and battery pin lists online but it's difficult to know whether I could trust the information and where they define pin 1. I used the approach that the more information I can get, the better. Then take a lot of measurements to be sure it's correct.
Per Battery University, most laptop batteries have one or two ground pins on one side and an equal number of power pins on the other side. It's common to have a signal pin that must be a logic low to enable a solid state switch that connects the battery to the positive connector pin. Occasionally this control pin must be pulled high. The internal BMS often communicates to the motherboard using a 2 wire SMBus with clock and data signals although 1 wire buses are sometimes used. There may be a negative temperature coefficient (NTC) thermistor on one of the pins. It usually measures about 10KΩ to ground at room temperature.
Armed with this general information, I used my ohm meter on the motherboard battery connector to find the ground pins. There are lots of places you can find ground on the motherboard, such as the metal shield surrounding the VGA connector. I found 2 grounded motherboard pins on one end of the connector along with another ground in the middle that I suspected was the "system present" signal. The opposite end had 2 pins tied together with wide copper traces going to a large capacitor for the positive battery connection. The remaining pins had thin copper traces for low current signals. To gather more information, I set my meter to diode mode and put the positive meter lead on motherboard ground. Then I probed each signal pin on the connector with the negative lead and looked for a diode voltage drop. This showed the pins with electrostatic sensitive devices (ESD) protection diodes that go to logic I/O's including the SMBus clock and data. The results of probing the motherboard connector are shown above.
Next, I probed the battery with my ohm meter using metal blades from an old connector. I knew where ground was located thanks to the motherboard measurements so I measured the resistance to ground for all the other pins. I switched the meter to diode mode and put the positive lead on ground. Probing all the other pins with the negative lead showed which pins had ESD protection diodes. The results of probing the battery are shown above.
The final test was to connect the most likely "system present" pin to ground with a 1KΩ resistor. Using a resistor is a safe way to set a pin low when you're not sure what each pin is for. With the battery enabled, I measured the output voltage of the battery. In my case, the battery measured about 11 volts which is a normal (but low) value for a pack with 3 series cells. The next step will let you know if your battery has any life left in it.
Precharge a Depleted Battery

Lithium batteries can be very dangerous and must be charged in a safe manor. Please read "Safety Concerns with Lithium-Ion" and "LESSONS IN LI-ION SAFETY" so you will be prepared for a fire. If your battery pack is damaged or bulging, do not use it. Never leave the battery unattended while charging. Keep a meter on the battery voltage to make sure it never exceeds the maximum rating for your pack. Monitor the temperature since this is your first indication that things are going bad. I do all my initial battery testing and charging on a bench in the garage with the door open and the car moved outside along with any flammable items. I charge the battery on a sheet of wood so I can quickly unhook the wires and get it outside. If it starts a fire, I've got a fire extinguisher ready to put it out. So far, I have not had any emergencies but it's best to have a plan in case things go wrong.
If you are experimenting with a laptop battery that has not been used for some time, it may have "self discharged" below the normal operating range given at the AMPOW website. Most laptop batteries print the nominal voltage on the pack along with an amp hour or watt hour value. Sometimes the maximum voltage is given instead of the nominal so be careful. For a pack with 3 series cells, the nominal voltage printed on the battery will be 11.1 volts or 10.8 volts depending on their definition of "nominal". According to AMPOW, 3 series lithium cells are at 0% SOC when the pack measures 9.82 volts. They also say that a battery cell should never go below 3 volts. Therefore a pack with 3 series cells should never go below 9 volts. Battery University says that a cell that has dwelled at a voltage of less than 1.5V/cell for some time should not be charged. This means a pack with 3 series cells should not be charged if it has been below 4.5 volts for some time. This assumes the cells are each at the same voltage which is not necessarily the case.
Using the same math for a 4 series cell battery pack says it should be labeled with 14.8 volts or 14.4 volts nominal. A 4 series cell battery pack should never go below 12 volts and should not be charged if it has been below 6 volts for some time.
The MP26123/4 battery charge controller ICs have a low current precharge mode that drops the charge current to 10% if the voltage is below the normal operating range. Unfortunately the Max1873 charge controller IC does not have this feature so I programmed the ATtiny to pulse the enable pin of the Max1873 in a PWM fashion based on the battery voltage. Whichever charge controller is used, it's best to do a manual precharge if you are checking to see if a depleted battery can be revived. You should never have to do this manual procedure again once the Pi is programmed to shut down power if the battery is nearing 0% SOC. This shut down code will be described in a later step.
To do a manual precharge, tie the "system present" pin of the battery low with a 1KΩ resistor. Use a bench supply or an adjustable regulator like the XL4015 shown above. Reduce the current limit to about 80ma and set the voltage to the nominal battery pack value. The supply will drop the voltage in order to limit the current. Monitor the battery at all times while charging to see if it starts to overheat. Continue charging until the supply voltage comes up to the nominal value of the battery pack which will be about 10% SOC. Turn off the supply and disconnect the battery. Check the battery voltage 24 hours later and see if it has significantly dropped. This will tell you if the battery pack can hold a charge or needs to be replaced.
If your battery will not accept a charge, it may need the SMBus clock and data pins pulled to 3.3 volts. A simple register read over the SMBus may be needed once or repeated at a regular rate. Some Dell batteries need an activation code sent to the battery. The Pi code "read_battery_loop.c" described in a later step will provide the access codes every 15 seconds. This code was not needed for my aftermarket Dell D630 battery but I have seen this on other Dell packs. I have also seen Dell packs not accept a charge even after sending the SMBus activation codes.
Battery Connector



I used SMD removal alloy to unsolder the battery connector from the motherboard. The hot air rework station shown above came in handy to heat up the ground pins and connector mounting clips. You can avoid removing the connector if you can find a suitable replacement with the right pin count, pitch, and keying at Digikey or AliExpress. To mount the battery connector in the laptop, you will need a small board that uses the original chassis mounting holes (see picture above). I cut a single sided copper clad board and drilled the mounting holes a little oversized to allow for adjustment. The battery was plugged into the connector to hold it in alignment while the JB Weld epoxy was setting up. The wires to the battery charger board were trimmed down to keep them as short as possible.
Max1873 Battery Charger Board





There are charge controllers newer than the Max1873 with more features but I have prior experience with this chip and found it easy to get working. Besides charging lithium batteries, the Max1873 can also charge NiCd or NiMH batteries. I used the "typical application" schematic from the data sheet and the evaluation board schematic to design this board. The Autodesk Eagle schematic and layout files can be downloaded below. OSH Park accepts Eagle layout files directly but you will need the zipped Gerber layout file "Charge_Controller_2020-12-14.zip" (from my repo) for fabrication at JLCPCB. If you don't want to build this charger board from scratch, you can buy the Max1873 evaluation kit and add an SB540 or similar Schottky Diode from the BATT+ (anode) to the SYSTEM LOAD (cathode). Follow the schematic above to wire an 8 pin DIP socket to the kit so the ATtiny85 can shut down the charger as described in the next step. If you don't want to use an ATtiny, the Pi can monitor the battery charging parameters over the SMBus and disable charging by driving the enable signal with a GPIO pin.
A reflow oven or hot air rework station works best but if you can handle a soldering iron, you can assemble this board. I have built three boards as I improved the design. The first 2 were from JLCPCB and the last was from OSH Park. I hand soldered the first board and used my DIY reflow oven for the second with solder paste applied by syringe. For the third board, I used a stencil to apply the paste. This gave the best results with zero rework needed.
The parts list with links to Digikey and a test procedure can be downloaded below.
Items of note:
The Max1873 comes in 3 versions, R, S, or T depending on whether the battery pack has 2, 3, or 4 series cells. All versions hold the battery regulation voltage to ±0.75%
Adafruit and Battery University have voltage information for several types of lithium batteries. Adafruit says that older lithium batteries are rated at 4.1 volts maximum and 3.6 volts nominal but the more common lithium battery is rated at 4.2 volts maximum and 3.7 volts nominal. Battery University says that common lithium batteries are rated at 4.2 volts maximum and 3.6 volts nominal but many manufacturers specify 3.7 volts nominal in order to claim a higher watt-hour rating. There are newer lithium batteries with a maximum rating of 4.35 volts. The Max1873 can work with all of these batteries by setting the maximum cell voltage using resistors R5 and R6 (see schematic above). Using the formulas in the Max1873 data sheet gives the following resistor values:
4.1 volt maximum cell voltage: R5 = 54.9KΩ and R6 = 147KΩ.
4.2 volt maximum cell voltage: R5 = 100KΩ and R6 = 100KΩ.
4.35 volt maximum cell voltage: R5 = 169KΩ and R6 = 32.4KΩ.
If you are not sure what your maximum cell voltage is, use the 4.1 volt resistor values just to be safe.
R9 = 0.033Ω and sets the input current limit at 3 amps. The Max1873 will reduce the battery charge current in order to not exceed 3 amps from the wall supply.
R1 = 0.2Ω and sets the charge current limit to 1 amp. The Max1873 will charge the battery at 1 amp during the constant current phase. It will switch to constant voltage and reduce the current when the battery is nearly full.
The input voltage goes thru a 5 amp slow blow fuse for safety.
I used a schottky diode in earlier versions of the design to "Or-Tie" the battery to the load. The 0.4 volt drop from the diode has been eliminated in the latest board design by using an "Ideal Diode". This consists of a P channel FET controlled by an LTC4412. The 19 volt DC wall supply can be connected and disconnected while the Pi is operating and it will not cause any power glitches.
The circuit board trace widths were designed to handle at least 3 amps with no more than a 10ºC rise in temperature. Several trace width calculators and graphs for 1oz copper were checked and the worst case result was 4 mm from the IPC-2152 nomograph. The smallest power traces on my board are over 5mm wide.
SMPS IPC-2152 calculator minimum width = 2.25 mm
4PCB IPC-2221 calculator minimum width = 1.37 mm
IPC-2152 nomograph minimum width = 4 mm
Per the datasheet, battery capacitor C22 should have an ESR under 1Ω and a value of 68µF when using the Max1873R. It can be reduced to 47µF for the Max1873S or to 33µF for the Max1873T. I've used the Kemet 68µF capacitor given in the parts list with both the Max1873R and S chips. It has an ESR under 200mΩ.
ATtiny85 Supervisor for Max1873





The ATtiny85 controls the enable signal of the Max1873 chip and handles many of the tasks that a more complex charge controller chip would have, built in. The Tiny is powered by the 5.4 volt regulator inside the Max1873 so it only operates when the 19 VDC wall supply is connected. The 8 pin DIP socket on the Max1873 board allowed me to use the Tiny AVR programmer as I developed and tested the software using the Arduino IDE. The code for a 3 series or 4 series battery pack can be downloaded below. The internal 1.1 volt reference for the Tiny's 10 bit A to D converter is used and all analog signals have voltage dividers to reduce full scale below 1.1 volts. The Tiny code monitors the following signals with its A to D converter:
Voltage - The AT Tiny receives 1/17th of the battery voltage on its ADC input via resistor divider. If the battery voltage is below 9 volts for a 3 series pack, or below 12 volts for a 4 series pack, the charge controller is enabled to charge (at 1 amp) for a short duration every 2 seconds to slowly precharge the battery in a PWM fashion. The "on" time grows longer as the voltage increases. A better precharge method is the bench supply approach described in a previous step.
Temperature - The ATtiny85 monitors the voltage from a resistor divider to measure the temperature. The top resistor is 82KΩ and is connected to 5.4 volts. The bottom resistor is a 10KΩ NTC thermistor to ground. The temperature vs resistance for a typical thermistor is shown above. If the change in temperature from initial power up increases more than 10 degrees, the charge controller is disabled. It is normal for the battery to warm up slightly during charging but a large increase in temperature may indicate a bad pack. Battery University says "Discontinue using the battery or charger if the temperature rises more than 10ºC". If your battery does not provide a 10KΩ NTC thermistor on the connector, you should add one on the outside of the pack just to be safe. A typical part is Digikey 490-7171-ND. The picture above shows how I taped a thermistor in the battery compartment of the Dell D630.
Current - The Max1873 outputs a voltage on pin 7 that is proportional to the charge current. A resistor divider drops this voltage by 1/4th so that the Tiny's ADC can monitor the charge current. Per Power Stream and Battery University, you should not trickle charge a lithium battery. When the charge current reaches a reduced level, the charge controller is disabled by the Tiny. The Dell D630 battery reports 100% SOC has been reached when the charging current drops to 350ma. If you continue to charge the battery, it will report an overcharge in the status bits. I have tested other battery packs that required the charge current to go under 100ma before claiming 100% SOC. Experimentation may be required for your specific battery. Reaching 100% SOC is not necessary, plus if you terminate charging early, it will prolong your battery life. The value that will terminate charging is easily adjustable in the code.
Time - The ATtiny85 keeps track of the charge time and disables battery charging after 300 minutes. This value should be changed once you know how long it normally takes to charge your pack. My Dell D630 battery takes 230 minutes to charge from empty to full.
Pi GPIO 19 is connected to the Max1873 board signal labeled "Pi Control". If the Pi drives this signal to 3.3 volts, the ATtiny85 code will disable the Max1873. This can be used by new Pi software if readings from the SMBus show a shutdown is needed. A good example would be to watch for an overvoltage condition. The Pi can get a very accurate battery voltage via the SMBus as apposed to the Tiny using it's 10 bit ADC.
A 3.3 volt logic signal is available from the Max1873 board (labeled "Charger TP") that can be monitored by the Pi to determine when the Tiny has disabled the charger. If the Tiny is not installed, this pin can be driven high by the Pi to stop charging. New Pi software would need to take over the tasks of the Tiny by reading the various BMS registers and checking for conditions that require shutdown.
I originally used the 5.4 volt supply as the ADC reference and scaled all analog inputs to 5.4 volts max. This caused the current draw on the 5.4 volt regulator in the Max1873 to exceed its maximum value whenever an analog input was near 2.7 volts. I believe this is due to the multi-purpose I/O circuit in the ATtiny85. Even though I programmed the pin as an analog input, the digital input circuit also received the signal. At 1/2 Vcc, the N channel and P channel input FETs are both partially turned on, creating a power to ground path.
I've added some more information about the Max1873 battery charger design at Hackster.IO.
MP26123 or MP26124 Lithium Battery Charger Board




I designed a second lithium battery charger board (shown above) using the MP26123 for battery packs with 2 or 3 series cells. The board can also be used with the MP26124 for packs with 4 series cells. I used the "typical application" schematic from the data sheets and the evaluation board schematic to design this board. The part values that need to be changed for the different battery configurations are shown in the schematic above. The MP26123/4 chips hold the battery regulation voltage to ±0.75% and the switching FET is included in the IC. The MP26123/4 have additional features not in the Max1873, including - precharge a dead battery, terminate charging when full, monitor the battery temperature, and limit the total charge time. If you don't want to build this charger board from scratch, you can buy the MP26123 evaluation kit and modify as needed.
The MP26123/4 can only be used with 4.2 volt lithium cells. Older laptop battery packs that use 4.1 volt cells must use a charge controller like the Max1873 that can adjust their maximum voltage level. The MP26123/4 only comes in a leadless package making it more difficult to hand solder. Unlike the Max1873, the MP26123/4 chips do not reduce the charge current in order to limit their input current. The board design includes a 5 amp slow blow fuse on the input power for safety.
The MP26123/4 will perform a precharge if the battery pack voltage is below 3 volts per cell. The precharge time is limited to 30 minutes at a charge current of 100ma. If the battery voltage rises above 3 volts per cell within 30 minutes, the charge current increases to the full charge level which has been set at 1 amp by resistor R12. When the voltage reaches the maximum level (4.2V x Number of series cells), the charger transitions from constant current mode to constant voltage. This is shown above in the charge plot for a 3S2P battery from a Lenovo T61. The charge current will slowly drop until it goes below 100ma, causing the MP26123/4 to shut down. The maximum charge time is set at 4.5 hours with 0.15uf capacitor C6. A 10K NTC battery thermistor can be connected to the MP26123/4 to shut down charging if the temperature gets too hot (around 40 ºC) or too cold (around 11 ºC). If you don't connect a thermistor, you must add a 10K resistor to ground.
The Raspberry Pi can shut down the battery charger by driving GPIO 19 to 3.3 volts. This GPIO pin should be wired to the signal "Disable" on the MP26123/4 board. The Pi can monitor the status signal "CHGOK" from the MP26123/4 board using a spare GPIO pin. Logic low indicates the MP26123/4 is charging normally. A logic high is caused by a number of conditions; end of charge, NTC fault, time limit, thermal shutdown, disable pin, Vin under voltage.
The Eagle schematic and layout files are given below. The Eagle layout file can be sent to OSH Park for fabrication. To fabricate at JLCPCB, use the zipped Gerber file "MPS_Charge_Controller_2021-02-23.zip" from my repo. The parts list with links to Digikey can be downloaded below. For more information about this board, visit my Hackaday.IO project.
Power On/Off Control Using Enables or Load Switch


The MP26123/4 board has the same digital latch circuit as the Max1873 board for laptop power control (see first schematic above). A 74HC132A Schmidt trigger quad NAND is wired as an SR latch to control the enable pins on the 5 and 10 volt buck regulators. The set and reset inputs to the latch are active low. Pushing the "On" button on the keyboard sends a low to the "Set" input of the latch. The "Q" output is latched high and buffered with an inverter to drive the buck regulator enable pins low. When the Teensy receives a shut down signal from the Pi, it drives the "Reset" input of the latch low (thru an inverter), causing the enable signal to the buck regulators to go high. The Pi could be wired directly to the latch but I put the Teensy in the middle so it can shut down the laptop even if the Pi is locked up. The Teensy can also provide a delay before turning off power, if necessary. The latch circuit must operate when the laptop is off so it is powered by a 3.3 volt linear regulator fed by the battery or 19 volt input. The Max1873 board and the MP26123/4 board draw about 315ua when the laptop is turned off in order to power the latch. There is also the internal self-discharge of the battery pack (2% per month) plus the protection circuit (3% per month) that draw about 363ua. All together, a fully charged 58 watt hour battery would be depleted in about 324 days if the laptop is not plugged in.
If your loads do not have enable control signals or they draw too much current when disabled, you will need a load switch like the one shown in the second schematic above. The P-FET will cut power to the loads when its gate is pulled to the source voltage (battery or wall supply). When the digital latch turns on the small N-FET, the P-FET is turned on and supplies current to the loads. TI application note SLVA716A describes various discrete component load switches including the one shown above. The resistor and capacitor values can be adjusted to give some degree of in-rush current limiting as described by PowerCTC, section 2.1.
Using an Overlay for I2C/SMBus


The battery SMBus is fully documented in the Smart Battery Data Specification. It covers the bus timing and register definitions. The I2C bus protocol is very similar to the SMBus protocol with a few exceptions for clock speed and timout. I had problems using the Pi's I2C hardware for battery communications but there were no problems using the i2c-gpio device tree overlay. This overlay controls the GPIO clock and data signals in software (known as bit-banging). The following line needs to be added to the /boot/config.txt file.
dtoverlay=i2c-gpio,bus=7,i2c_gpio_delay_us=20,i2c_gpio_sda=2,i2c_gpio_scl=3
This overlay creates bus number 7 with a 20usec half clock period. Pi GPIO 3 and 2 are used as the SMBus clock and data. These pins have 1.8KΩ pull ups built into the Pi. This value is a little low per the SMBus spec but the batteries I've tested are still able to pull the data line low. If different GPIO pins are used, you must add pull up resistors to 3.3 volts. 2.4KΩ to 3.9KΩ is a popular pull up resistor range per Maxim.
You can access the BMS registers directly using the i2c-tools. Type the following in a terminal window:
i2cdetect -y 7
This will ping all addresses on the bus and any that send back an acknowledge will show up in the table. If you have the clock and data wired correctly to the battery, it will respond at address 0x0b as shown in the screen grab above.
The i2cget command will write a byte pointer to the battery that determines which 16 bit register you want to access next. Then it reads and displays the 16 bit value in the register. Type the following in a terminal window:
i2cget -y 7 0x0b 0x?? w
Replace ?? with the register you want to read to get the voltage, current, temperature, SOC, time to full/empty, and status values as shown in the screen grab above.
My Ugly C Code


There are sites that describe how to use the i2c-gpio device drivers within a C program but I'm still trying to figure this out. For now I'll use my own crude bit-bang C code that I developed for a Sony Vaio Pi that runs with a slow clock and long delays in order to avoid clock stretching. Linux will sometimes interrupt my code to run other operating system tasks which causes bus timing errors. If my code detects a bad read, it will read the battery register a second time. Adding the i2c-gpio dtoverlay as described in the previous step does not effect the operation of my code and it allows for the i2c-tools to be used in a terminal window for debugging.
The following instructions should be enough to get you up and running with my ugly code (which works just fine), then depending on your software skills and desire to make it "pretty", you can modify or rewrite it yourself. The following assumes the C code is placed at /home/pi/C_Code.
I used Geany to edit and build the code per this Sparkfun tutorial. They describe how to add -l wiringPi to the compile and build commands and sudo to the execute command.
You must have wiringPi version 2.52 or later if using a Raspberry Pi 4B. Check what version you have with:
gpio -v
Per the wiringPi website, you can load the latest version with these terminal commands.
cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb
I've tested batteries that required a single read over the SMBus before they would allow charging and others that needed a read every 30 seconds. Some Dell batteries require an activation code on the SMBus before they will accept a charge. Unfortunately, this means the Pi must be running in order to charge these "special" batteries. I've tried two different aftermarket Dell D630 batteries and neither needed the activation code. Other Dell batteries I've tried would not allow charging even after sending the activation code.
Per the Jena website, writing an activation code of 0x000A to register 0x00 in a Dell battery will enable charging. The function of this register is manufacturer specific. All of my C programs send this activation code just in case it is needed to enable charging. It doesn't seem to bother batteries that don't need activation.
The programs can be downloaded from the links below.
1. "read_battery.c" reads the registers in the battery to display the voltage, current, temperature, SOC, time to full/empty, and the status bits in a terminal window as shown above. Once you have built and debugged the code in Geany, you can run it from a terminal window (if you are currently in /home/pi/C_Code) with:
./read_battery
I've added a "bat" alias to my .bashrc file so I can run this program from any directory.
alias bat='/home/pi/C_Code/read_battery'
A desktop icon could also be created that runs this program.
2. "read_battery_loop.c" is the same as above but running in a continuous loop that repeats every 15 seconds. This is useful when precharging a battery that needs the activation codes or a register read on a regular basis. It also provides a convenient way to monitor temperature and the charging progress.
3. “monitor_battery.c” is a subset of the read_battery program. It does not display any results to a terminal window but it will blink the blue (formerly bluetooth) LED, momentarily turn off the LCD, and issue a shutdown command based on the battery state of charge. The blue LED is driven by Pi GPIO 17 and the LCD power control is driven with GPIO 4.The monitor_battery program is run at startup using a systemd unit file as explained by Dexter Industries (method 4). The bat_monitor.txt file can be downloaded below and renamed bat_monitor.service. The Instructable website would not allow me to upload a dot service file. Store the bat_monitor.service file at /lib/systemd/system. You must load and enable the service with terminal commands:
sudo systemctl daemon-reload
sudo systemctl enable bat_monitor --now
The monitor_battery program loops every 30 seconds. It reads the status bits and the SOC. If the discharge bit is set and the SOC is above 15%, the blue LED blinks on for 1 second as a "heart beat" to let you know the program is running. At 15% and below, the LED stays on and blinks off for 1 second every loop. At 10% and below, the on/off control signal to the video card is pulsed to momentarily turn off the display and get the users attention. This will happen again every 30 seconds until the charger is plugged in. If the SOC goes down to 8%, the program issues a safe shutdown with the system command:
sudo shutdown -h now.
If the status bits show the battery is charging, the blue LED will blink twice. If the SOC shows it is fully charged, it will blink 3 times. The code could be modified to blink the LED in various ways (such as Morse Code) to give the SOC value.
The code uses the state of charge value but it may take a few charge/discharge cycles to train the BMS so the algorithm is accurate. If your battery does not give an accurate SOC, the code can be changed to watch the battery voltage but this can also be inaccurate as described by Battery University.
Cairo Code Displays the Battery Fuel Gauge and SOC% on Desktop


Ideally I would like to display the battery charge as a GUI panel applet like a typical laptop but this proved to be difficult. Thanks to rricharz and his GitHub repo "Raspberry Pi easy drawing with c and cairo", I was able to create a small window with a battery fuel gauge showing the SOC percentage. The rricharz files were forked to my repo and modified by adding my SMBus code to the application.c file. The application.h header file was changed to make a minimal size window (see screen grab above) with a fuel gauge and SOC percentage that is updated every 5 seconds. The main.c code and main.h header files are unmodified. The makefile has been modified to add a link to wiringPi. The battery symbol, "bat_icon.png" and the Battery_SOC.desktop file can be downloaded from my repo. A desktop icon is used to run the code instead of using a terminal window. The file, Battery_SOC.desktop was placed in the /home/pi/Desktop folder.
USB to SMBus Bridge With CP2112




The CP2112 USB to SMBus bridge from Silicon Labs provides a clean way to access the status registers in the battery without bit-banging (see schematic above). The chip receives commands over USB from the host computer (i.e. PC or Pi) and retransmits as an SM Bus master to the battery. Then the chip reads the SM Bus results from the battery and sends everything back to the host over USB. Nick D'Ademo has a GitHub repo with demo code for a PC to interface with a laptop battery using a CP2112. I forked his code to my repo and modified it to change some of the text in the terminal window and read more registers. The results of the register reads are shown above. You can download and modify the code using Visual Studio C++. If no modifications are needed, download the executable code "cp2112_demo.exe" for a 64 bit Windows 10 PC, along with the two dynamic link library files, "SLABHIDDevice.dll" and "SLABHIDtoSMBus.dll" found here. Put these 3 files in a folder and double click the .exe file to run it.
The Eagle board and schematic files are available at my repo. I used OSH Park's CAM processor to translate the slotted holes needed by the micro USB connector. The resulting file "USB_SMBus_2021-04-28.zip" can be uploaded to OSH Park for fabrication. This .zip file is needed instead of a .brd file because Eagle does not directly support slotted holes.
The 1" x 0.6" circuit board shown above costs $3 to fabricate at OSH Park (for 3 boards).
The parts list is:
CP2112-F03-GMR USB to SMBus Bridge $1.56
10118193-0001LF Micro B USB Connector $0.43
USBLC6-2SC6 TVS Diode Array $0.65
Three 0603 size resistors to pull up the clock, data, and reset. I used 5.62K (because I had extra).
Three 0805 size caps for power bypass. Values are 4.7uf, 1.0uf, and 0.1uf
Silicon Labs offers a CP2112EK evaluation kit for $29 for those that don't want to solder a leadless quad flat pack.
Conclusion


It can seem like stuffing the genie back in the bottle when you try to put all the pieces inside the laptop case. The plastic snaps that hold the top and bottom together will wear out so you should minimize the number of times you take the laptop apart. Get everything working first with the case open to allow for access while you debug the connections.
I hope you find this Instructable useful for making a portable Raspberry Pi laptop. I will make updates as I learn more and invite you to add questions, comments, or corrections below.
Good Luck