Solar MPPT Charger for 24/7 "IOT" devices

An inexpensive charge controller and 2A 5V power supply designed to supply remote power for devices ranging from Arduino to Pi 3 class.

Similar projects worth following
Starting from
globoy has 36 orders / 0 reviews
Ships from Boulder, US
Feedback from an earlier project, the Solar Pi Platter, showed me there was interest in a smart charger/power supply for single-board computer devices operating 24/7 from solar power. This project documents my efforts to bring this charger to the maker/hobby market, including the decisions behind its features and some of the stuff I learned along the way that might be useful to other people designing their own systems.

Cost was the primary design factor which led me to a firmware-controlled approach (instead of using a dedicated IC). The availability of inexpensive 12V AGM batteries (e.g. UPS batteries) and 36-cell ("12V") solar panels, as well as the battery's operation over an extended temperature range led to their choice as the power elements.

There are a lot of chargers like this one, including some very cheap units from China, so I am taking advantage of the micro-controller to provide a good set of features and a lot of software support.

I did a lot of online research when I started this project and pored over earlier efforts by Julian Ilett, Debasish Dutta, Lukas Fässler, kjoehass and Ant.  I appreciate their efforts to document their work and their great designs, and sometimes failures.  It's in that spirit that I've created this project entry.  The actual technical documentation is in my github repository.  Currently it has supporting documentation and software.

The MPPT Solar Charger is a combination solar battery charger and 5V power supply. It manages charging a 12V AGM lead acid battery from common 36-cell 12V solar panels.  It provides 5V power output at up to 2A for systems that include sensors or communication radios (although designed for average power consumption of 500 mA or less).  Optimal charging is provided through a dynamic perturb-and-observe maximum power-point transfer converter (MPPT) and a 3-stage (BULK, ABSORPTION, FLOAT) charging algorithm.  A removable temperature sensor provides temperature compensation.  Operation is plug&play although additional information and configuration may be obtained through a digital interface.

  • Optimized for commonly available batteries in the 7-18 AHr range and solar panels in the 10-35 Watt range (larger panels will work)
  • Reverse Polarity protected solar panel input with press-to-open terminal block
  • Fused battery input with press-to-open terminal block
  • Maximum 2A at 5V output on USB Type A power output jack and solder header
  • Automatic low-battery disconnect and auto-restart on recharged battery
  • Temperature compensation sensor with internal sensor fallback
  • Status LED indicating charge and power conditions, fault information
  • I2C interface for detailed operation condition readout and configuration parameter access
  • Configurable battery charge parameters
  • Status signals for Night detection and pre-power-down alert
  • Night-only operating mode (switch 5V output on only at night)
  • Watchdog functionality to power-cycle connected device if it crashes

Software support for the MPPT Solar Charger includes an arduino library (which also compiles on Raspberry Pi), a daemon program designed to run on the Pi enabling other software to communicate with the charger and also to log data, a desktop application for monitoring and graphing log data.  Eventually I'd like to also add a simple web-server to allow easy remote access.

I envision this device being useful for all manner of remote sensing or monitor applications, or for remote webcams, or even to power a set of garden lights or provide solar USB charging power.

Initial PWM prototype + Teensy LC sketches for PWM and MPPT hack to board

Zip Archive - 54.92 kB - 09/21/2018 at 16:07


  • Firmware on github

    Dan Julio08/31/2019 at 17:17 0 comments

    New Feature

    With firmware v1.2, the watchdog functionality has been extended to allow a new capability.  A new 16-bit unsigned register called WDPWROFF is added that controls the length of time power is disabled when the watchdog timer expires.  It specifies time in units of seconds allowing power to be disabled for up to 65535 seconds (18 hours, 12 minutes, 15 seconds).  This means that the watchdog function can also be used to switch off power for a period of time, for example to turn off the user's system overnight.  The default value of WDPWROFF is 10 seconds like the previous firmware versions and the default value is restored every time the watchdog timer expires or is disabled.

    Documentation and the arduino library have been updated.

    Firmware Release

    The v1.2 firmware source has also been uploaded to github.  This is the intended production release code.  I used Silicon Lab's Simplicity Studio as the IDE and compilation environment.  This code runs on the EFM8SB10F8 micro-controller and currently requires 7904 bytes (almost full!) and uses 140 bytes of xdata memory and 86.1 bytes of data memory.

    Campaign Status

    The Crowd Supply campaign is almost finished.  The parts are in China but unfortunately being held in customs.  My Contract Manufacturer is attempting to get them released.  I am exploring some options in case this becomes a long-term problem.

  • Campaign launched

    Dan Julio07/30/2019 at 16:57 0 comments

    It has taken far longer than I hoped but the crowd funding campaign has finally launched at Crowd Supply.  I have parts for 250 boards in my possession and will be sending them to my CM in China this week.  This was a worry because of ongoing parts shortages.  The plan is to build an initial run of 50 boards and send them to me for testing on the manufacturing test fixture to work out any remaining issues with it.  Then the fixture will go to the CM for use on the remainder of the boards.  After the campaign ends I will write-up my experiences with this crowd funding effort.

  • Slow progress - but a new name

    Dan Julio04/25/2019 at 17:52 0 comments

    Introducing "makerPower MPPT Solar Charger"

    Engaging with Crowd Supply has been interesting.  They see this device from a fresh perspective and that has resulted in some changes.  One is the name.  To me "Solar MPPT Charger" (or "MPPT Solar Charger" as I changed to over time) made a lot of sense since it describes what the device does fairly succinctly.  Of course from the perspective of a product to be searched for and found by prospective buyers, its generic nature it is almost useless.  They suggested a picking a new name.  They would brainstorm and I would brainstorm.  Lots of ideas revolved around words like  "Pi" and "Solar" and "Sun" were proposed.  Although this device is very well paired with Raspberry Pi SBCs I don't want to limit its appeal to just those devices so I proposed "makerPower" as either a stand-alone name or in conjunction with "MPPT Solar Charger".  Slowly I have been updating various references.

    Bundles and searching China

    My idea was to sell only the board but Crowd Supply also encouraged the creation of bundles to make putting together a system easier.   This is still a work-in-progress but I am thinking of three bundles.

    1. Board only (along with a 6-pin header and spare fuse).
    2. Board plus 4-wire female-female cable for 5V+I2C connection and 2-wire battery cable with spade connectors.
    3. Board plus cables + 9 Ah battery + 35W solar panel.

    I guess I already knew that making a system easy to put together will make it easier to buy but it is a pain to source all the other parts.  I have huge numbers of tabs open to Alibaba, AliExpress and Global Sources product pages and feel almost paralyzed by the choices and possible risks.  Boulder CO USA feels very far away from these choices.

    Test Fixture

    The test fixtures are ready to go.  It tests, programs and calibrates a charger in about 8 seconds per board.  The printer prints out a failure record that also identifies the parts of the circuit being tested to help a technician fix failing boards.  The idea is that the print-out will accompany any board that fails to the bone pile and eventually repair bench.

    Coding was reasonably straight-forward and I 3D printed some components to make testing efficient (and to hold a photo-transistor for the charger LED verification).  The big issue I had was the resistance of solder flux.  These boards were hand-built by yours truly.  I use a little flux to help reflow the SMT parts and this caused a lot of problems.  I clean my boards using pure isopropyl alcohol and/or a quick soapy wash using a soft toothbrush, rinse and dry.  However I still had problems making the two test fixture accurately measure voltages from the device-under-test (DUT).

    The test fixture measures voltages using the Teensy 3.5's ADC and an external precision 1.25 V reference.  Higher voltages from the DUT are scaled using a voltage divider made up of two precision resistors.  These resistors had to be fairly high resistance to not impact the circuitry under test.

    Unfortunately flux under the resistors and between the soldered headers on the teensy and testfixture added measurable resistance and threw the resistance ratio off.  The boards looked clean to me but still didn't measure correctly.   It took a while before I found every source of error and managed to clean it up.

    The test fixture also sports a simple command interface to enable manual control of the test fixture or running of individual tests.  The command interface is not used during normal operation (no computer is connected to the test fixture).  

  • Pre-production units!

    Dan Julio03/19/2019 at 20:15 0 comments

    The last couple of weeks have been productive.  I executed the final firmware validation testing and released v1.0, and completed the user manual and uploaded that to the github repository.  The manufacturing programming/test fixture is also up and running.  This project is ready to go!

    Edit: I've also now listed them on tindie.

    Edit 2: The day after I put them on tindie I heard from Crowdsupply that they were interested in running this device as a crowd-funding campaign.  I had originally submitted it to them in the fall of 2018.  One of their requirements is that the device not be for sale anywhere else until the campaign ends.  So I have temporarily taken it down from tindie and here. If you think you might be a good beta customer then let me know.  it may be possible for you to get a board if you will commit to sharing information about its use.

  • Quickie: working on manufacturing fixture

    Dan Julio03/05/2019 at 22:37 0 comments

    The manufacturing programming/test fixture is a fair bit of code running on a PJRC Teensy 3.5.  Over the last few weeks I have worked on various subsystems

    1. Arduino library for the test fixture hardware itself
    2. Silicon Labs C2 programmer for the Teensy
    3. Hex File utilities
    4. Simple display support for the cap touch control LCD screen
    5. A custom test firmware to first program on the Charger's SI EFM8 micro-controller to allow detailed testing and calibration

    And finally I have gotten them all stitched together along with a test sequencer and am writing test code.  It's tedious because for every test I have to figure out what's right and what the limits for valid measurements may be.  But I see the light at the end of the tunnel now.

  • Some winter testing data

    Dan Julio02/19/2019 at 04:11 0 comments

    Two systems have been braving the [not so bad] Colorado winters for a couple of months now with good success while my progress on the test fixture has been very slow due to other project commitments. 

    The system above the house with the 25 watt panel with no obstructions has remained up pretty much non-stop with only a couple of low-battery shut-downs.  I even try to run the Christmas lights on it most nights for an hour or two.

     The system near the house, sitting on the ground in the trees, with a 40 watt panel and oldish battery, has gone down with a low-battery four times since Christmas and rebooted, if only for part of a day the next day in all cases.

    Both systems require about 2.6-2.9 AH per day and seem to be able to remain operational even in mostly overcast days when panel production is pretty low.  Snow on the panels is the worst and results in almost no solar production at all.  The graph below shows a typical overcast week with low production that resulted in a low-battery shutdown.  The X-axis shows days.  As you can see the charge cycle was often not able to complete the Bulk charging phase (terminated with the battery reaches the higher threshold value).

    Zooming in on a typical low-production day shows the system barely holding its own during the day (X-axis in units of hours).

    However a sunny day can produce a lot of power as shown below where the system (40 watt panel) started off shut-down and was able to fully charge the battery in about four hours.  This graph shows the system limiting current taken from the panel to 2A.  The step in the battery and threshold voltage at about hour 1056 is the transition from Absorption charge to Float charge when the battery was fully charged.

    The MPPT algorithm holds the panel voltage lower when it can't supply enough current (for example the system in Bulk charge phase but there isn't much light) and it lets it float higher when limiting solar input (for example when in Absorption charge phase and the buck is limiting).  This makes sense and looking over days of output shows the algorithm behaving.

    Now to finish the test fixture and start building this damn thing...

  • Bugs and Corner Cases

    Dan Julio12/28/2018 at 06:55 0 comments

    My choice of an inexpensive micro-controller has a cost.  This product has firmware that will probably never be upgraded since there is no facility to easily load new code (no interface and not much space left over for a bootloader).  So the release firmware needs to be pretty close to perfect.  It helps that this isn't a very complex device and I tried to make architectural decisions to mitigate entire classes of problems.  Still, with about 4300 lines of C, there are bound to be bugs.  And there have been.  Initially, of course, I found lots of simple bugs that were also pretty easy to find and fix.  After the system was pretty functional I executed a test plan to verify all major functionality under the main operating conditions.  This found a few more issues, things like incorrect status bits in a register.  Then I started testing as much as possible in real-world conditions - which for this system meant devices running for extended periods on solar power in as many different conditions as possible.

    That's when things got interesting.  Throwing wildly varying solar conditions, battery voltages and conditions, temperatures and loads into the mix started uncovering the corner cases.  Slowly.  The best tool I have had is the ability to log all the main parameters via the daemon running on a Pi because some of the corner cases didn't crash or harm anything, they just made the system less efficient.

    Recent winter testing just uncovered one of these corner cases.  It was exposed because the desired MPPT voltage was less than the desired charge voltage for the battery.  I found it looking through data from a cold overcast day.

    The firmware periodically executes a scan to find the current maximum power-point because there is a slight risk of the P&O MPPT algorithm wandering off from the ideal maximum power-point (less risk in a design like this with one small solar panel than with a large-scale system with larger or multiple panels where shading can cause local power minima and maxima).  After one of these scans I saw that the buck regulator was not operating correctly, in fact barely operating at all, and was not tracking the MPPT which then caused the MPPT algorithm to fail because there was no change in power as it adjusted the MPPT voltage goal.  In absolute terms, this bug was not severe because it occurred at a point where the system was producing relatively small power and was corrected by the next scan ten minutes later.  I hadn't seen it before (although it may have happened) because it would only manifest when the light was low leading to a low MPPT power-point for the panel and the battery charge threshold was high because the charger was in the Bulk/Absorption phase and the low temperatures caused the compensated charge voltage to be high (15.33 volts in this case).  The actual bug occurred because at the end of the scan the charger attempts to initialize the buck converter PWM value based on a simple CCM calculation representing the fraction of the output voltage to input voltage:

       pwm = MAX_PWM_VAL * OutputVoltage / InputVoltage

    where the MAX_PWM_VAL is 1023, the OutputVoltage is the desired charge voltage and the InputVoltage is the MPPT goal.  The buck control logic will then, over time, adjust the PWM value to the actual ideal value but this is a good starting point for most cases.  My problem was that the InputVoltage was less than the OutputVoltage and I didn't check for that.  The 16-bit variable holding the 10-bit PWM value overflowed 10-bits.  The actual PWM peripheral only looked at the 10-bits so was set to a small value.  However the code worked on the 16-bits and the buck logic wouldn't allow a change because it was already over the maximum PWM value.  The fix is easy.  In this case the PWM should be set to the maximum value essentially directly connecting...

    Read more »

  • Winter testing

    Dan Julio12/22/2018 at 18:49 0 comments

    I finally overcame inertia, took advantage of some reasonably nice weather and built up two frames so I could do some testing during the winter season.  Testing in summer, at least here in Colorado, is easy.  Weather is fine and there is an abundance of sunlight.  One just has to make sure the solar panel won't blow away in a high wind.  Its orientation is less critical.  Winter, especially where I live in a valley at the base of the Rocky Mountains, is more challenging.  There are only a few hours of sunlight a day and temperatures are often freezing or below.  It's definitely a good test environment for a charger that is to keep a device running 24/7.

    I loaded the current firmware on my original outdoor prototype and built a simple wooden frame to hold the panel.  This device has an old 40W panel, Rev 1 charger, an old-ish 9Ah battery and a Raspberry Pi Zero with camera module and USB WiFi dongle as the load.  It's located near the house so it can talk to the local WiFi.  It is logging using the mpptChgD daemon and I can monitor it in real-time using mppt_dashboard.  Once in a while I log into the motion-based webcam server to see the side of my house and down-valley.  Not a particularly exciting image but it does consume an extra 10-15 mA...

    The other test platform is a little more ambitious.  It's based on a pair of openwrt-based 8devices Carambola 2 modules with directional antennas in order to operate at a larger distance powered by a 25W panel, a newer, but still used, 9 Ah battery and a Rev 2 charger PCB.  It's the kind of device I envisioned when I started designing the charger.  It sits a ways up the hill above the house and sports a camera, an external temperature sensor and a couple of Auxiliary power channels - one controlling a bright white LED light for the camera and the other a string of 12V Christmas lights for a more useful load test.  Hopefully the rocks you see piled on the base will keep it stable in the sometimes 60 MPH winds we have.  It uses a DF Robot Beetle arduino Leonardo clone to communicate with the charger (and control the loads).  The Beetle uses I2C to talk to the charger and a TTL serial port to communicate with the Carambola 2.  I'm running ser2net on Carambola to remotely access the system.  I want to write a simple data recording program running on a local server to log data from the charger.  The Carambola and Beetle present about a 90 mA continuous load to the battery (less than 200 mA @ 5V).  The Christmas lights are pretty frugal, only adding another 110-120 mA when switched on.  The bright white LEDs are more power hungry at 420 mA.  I'm planning to run the Christmas lights for a few hours ever night during the holiday.

    I expect that there will be many days where the panels don't produce.  It will be interesting to see how the systems hold-up.


    Here's a typical output from the first system on an overcast day showing a few watts from the panel.  The charger state machine is in Absorption Charge (it hit the Bulk limit earlier in the day when there was full sun for a while) but it doesn't have enough energy to hold the battery at the desired Absorption charge level (temperature compensated at 15.32 volts) so the system is effectively operating as a float charger at this time.  You can the MPPT algorithm at work too.  The Vmpp from the panel is lower with lower light and in this 60 second interval the light increased some and the Vmpp rose to follow (green VM in the top graph - yellow VS is the system holding the solar panel output to match).

  • Onward toward manufacturing

    Dan Julio12/06/2018 at 03:28 0 comments

    Got the manufacturing test fixture designed, boards back and built.  Now to write code.  The test fixture will program code into the on-board micro (actually program two programs, the first used to find the micro's calibration value) and perform a functional verification of the electronics via pogo-pin connections with test points on the bottom of the PCB.  I am using a PJRC Teensy 3.5 as the test fixture controller.  The technician will interact with the controller to initiate programming and testing via a capacitive touch LCD screen (one thing I learned from Sparkfun's production line as a collaborator was that mechanical switches quickly wear out).  For boards that fail the programming and test procedure a small thermal printer will print out a diagnostic output to go along with the failing board for later repair.  I hope to be able to have the print out identify portions of the circuit to focus on.

    You can see some power resistors that act as a load when switched onto various subsystem outputs by a N-Channel MOSFET.  If you look closely you can also see that I forgot to send them milling gerber layer to the PCB vendor for the non-round power connector contacts...

    The test fixture, a power supply and printer will go on a base.  I'm not sure if I'll ask that the board be secured using screws or if I'll try to build something to press the board down onto the pogo pins.  In addition I also want to figure out an optical sensor to verify the on-board LED.  I bought some photo transistors that have sensitivity in the green range.  Just have to figure out how to have them see only the light from the LED and not ambient light.

    Not just for Solar Power!

    Have an old laptop power supply?  It can turn the charger into a long-lived UPS for small computers like Raspberry Pi file servers or a 5V router or WiFi access point.  I hooked an old Dell 19V 3.5A laptop supply to the solar input and the system worked flawlessly as a UPS.

    The charger will initiate charging once the solar panel voltage exceeds 18VDC.  Many laptop supplies put out between 19 - 21 volts.  This is perfect as a source of power to both keep a battery charged and power a load through the 5VDC output (or even the direct battery connections although there won't be automatic low-battery shut down without extra circuitry).  The MPPT algorithm will find the power supply's set point and the charger will keep the battery charged without damaging with it's FLOAT charge state.  The battery will take over the load if the AC power fails and the existing auto-shutoff software support can ensure a controlled system shutdown if necessary if the battery is ever exhausted.  Depending on the load, this UPS can keep a load running for many hours or even days without AC power.  Even with a 10 watt 5V load (taking about 1 A from the battery/PSU) there will be at least an amp available for recharging the battery when power is restored.  The system will get warm under heavy load so some kind of cooling might be necessary, especially if it's in an enclosure.  Easiest would be to connect a 5VDC fan to the board so that it's also shut down for low battery cut-off.

  • Characterizing the Buck Converter

    Dan Julio11/03/2018 at 20:40 0 comments

    First up, the latest revision.  Small changes from the last version including tightening up various current loops in the buck converter and moving the battery-side transient TVS diode to the anode side of the reverse-polarity protection diode to reduce the transient generated when the battery is reverse connected before the fuse blows.  Looks like a good candidate for production but some more testing to finish.  New schematic in the repository.

    One measurement available through the I2C interface is an estimated battery charge current (IC).  It is also used as part of a calculation to determine when the Absorption charge phase is finished and the charger should move to Float charge (battery charge current falls off).  It is estimated instead of measured because unlike all other paths in the charger where current flows one way, current can flow into or out of the battery and it would take a more complex (and expensive) circuit to measure a bi-directional current than the TI INA180 current amplifiers I am using.

    The calculation is straightforward but requires an estimate of the buck converter efficiency.

    EstimateBuckOutputCurrent = MeasuredSolarInputCurrent * (BUCK_INPUT_V / BUCK_OUTPUT_V) * BuckEfficiency
    BatteryChargeCurrent = EstimateBuckOutputCurrent - MeasuredLoadCurrent

    I had done some measurements with an early prototype and found an efficiency of about 90% at a mid-range current so I hardcoded this into the calculation.  However the buck efficiency is dependent on the power level and falls off very quickly for low power levels making the calculation inaccurate.  I finally got around to characterizing it more fully which resulted in the addition of a fast piece-wise lookup table in the code translating solar power (VS * IS) into an efficiency value for the calculation.  I hacked the firmware so the buck converter regulated on the output voltage (VB) instead of attempting to hold the input voltage (VS).  Then made a series of measurements (efficiency vs. input power) for five sets of conditions (varying VS between 15V, 18V and 21V and VB between 13.65 for float and 14.7 for bulk/absorption).  As expected the converter is most efficient when the difference between input and output voltage is the smallest and reaches 90% efficiency at about 5 watts.  Peak efficiency reaches 93-94% at between 10-20 watts.  Not bad for an asynchronous converter.

    To make the efficiency table, I played around unsuccessfully for a bit with curve fitting before giving up and just hand-picking points that represented reasonable piece-wise values in a graph of all the measurements.  I centered the values around the VS=18V curve since that was the middle measurement and hopefully where an MPPT charger will spend time.  The highlighted graph are my hand-picked values.  The X-axis is solar power (W) and Y-axis converter efficiency (%).

    The code is then pretty easy and efficient on an 8-bit micro.

    // Efficiency lookup table - efficiency (percent) as a function of input power (mW)
    //   determined via hardware measurement
    #define BUCK_NUM_EFF_ENTRIES 22
    code const uint16_t buckEffPowerPoints[BUCK_NUM_EFF_ENTRIES] = {
        250, 375, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000, 3250, 3500, 4000, 5000, 6000, 7500, 11500, 25000, 35000
    code const uint8_t buffEffValues[BUCK_NUM_EFF_ENTRIES] = {
        5662677175,   77,   78,   80,   81,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,    93,    92
    uint8_t BUCK_GetEfficiency(uint16_t ps)
        uint8_t i = 0;
    Read more »

View all 13 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

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