Code Monkey home page Code Monkey logo

charge-controller-firmware's Introduction

Libre Solar Charge Controller Firmware

build badge

This repository contains the firmware for the different Libre Solar Charge Controllers based on Zephyr RTOS.

Coding style is described here.

Development and release model

The main branch is used for ongoing development of the firmware.

Releases are created from main after significant updates have been introduced to the firmware. Each release has to pass tests with multiple boards.

A release is tagged with a version number consisting of the release year and a release count for that year (starting at zero). For back-porting of bug-fixes, a branch named after the release followed by -branch is created, e.g. v21.0-branch.

Documentation

The firmware documentation including build instructions and API reference can be found under libre.solar/charge-controller-firmware.

In order to build the documentation locally you need to install Doxygen, Sphinx and Breathe and run make html in the docs folder.

License

This firmware is released under the Apache-2.0 License.

charge-controller-firmware's People

Contributors

azeemshatp avatar daniel-connectedenergy avatar gretel5x avatar hogthrob avatar hoijui avatar jordansilverman avatar maclow92 avatar martinjaeger avatar mulles avatar rhushabhrr avatar wschopohl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

charge-controller-firmware's Issues

Indication if solar panel is connected with reverse polarity

At least the PWM charge controller can measure the (negative) voltage of a solar panel connected with reverse polarity (if battery is already present). This could be indicated by a flashing LED. In addition to that, we could introduce an additional error flag for this.

Any suggestion for LED indication, @JordanSilverman?

I think it's nothing time critical, but nice to have for the future.

Rewrite LED module

The current LED module doesn't provide an easy way to flash the load LED to indicate a short circuit.

The module should allow to set the following state for any of the LEDs:

  • off
  • on
  • blinking (1s interval)
  • flickering (around 100ms)

Case when (solar_voltage < battery_voltage + solar_voltage_offset_stop)

I'm a bit confused on how will the solar panel behave when the voltage starts to drop and reach the minimum input voltage of the DC/DC converter. The charging process will stop, then the current will drop and the voltage of the solar panel will rise again.
You placed a 4V hysteresis to prevent charging continuous recycles. ( difference between "solar_voltage_offset_start" and "solar_voltage_offset_stop")
Can we actually change the cutoff behavior and try to squeeze more power from the panels by trying to reduce the charging current (if possible) until charging current is smaller than the minimum?

another question that's lurking in the back of my mind is: I'm new to this solar panels thing and never tested or worked with any. I'm curious to know what will I lose if I use those 40V max open voltage panels to charge a 12V li-ion battery pack. A buck converter that will shutdown the charging voltage at 12.6+5=17.6V seems an awful decision compared to a buck-boost converter (specifically I'm also studying microchips AN1521 circuit).
I want to ask you, in your opinion, will I face this condition very often? Do you think I'll regret using this circuit over a buck boost converter?
Huge respect mate... your work is more precious than gold

Rework of half bridge driver

The half bridge driver should be reworked to allow having multiple phases in parallel. This might also lead to a more generic complementary PWM signal driver that can be upstreamed to Zephyr.

Name suggestions:

  • half_bridge (as it is now)
  • sync_pwm
  • complementary_pwm (possibly the more correct term, but very long)
  • cpwm (short for complementary_pwm)

New features:

  • Synchronize multiple channels / phases for multi-phase buck converter

Improved API naming:

  • cpwm_get_period_ticks instead of half_bridge_get_arr
  • cpwm_get_pulse_ticks instead of half_bridge_get_ccr

Support different charging profiles / battery types

The new version of the MPPT hardware contains a rotary switch to select the charger operating mode. Different charging profiles for different batteries (VRLA, Gel, LiFePO4, Li-Ion, etc.) should be added in software.

DC/DC control function in interrupt to allow slow communication in main

Communications via WiFi, LoRa or GSM modules need lots of time to establish connections and wait for data. In the current software it is not possible to run these tasks from within the main function, as it would block the DC/DC control.

Two possible solutions:

  1. Use mbed RTOS and put communication into separate (lower priority) thread
  2. Move DC/DC control to interrupt function (and make it as fast as possible) to be sure that control continues during wait phases of communication subsystem.

Mbed RTOS consumes lots of additional memory (especially RAM), so this option is almost impossible with STM32F072. Option 2 should be preferred.

Firmware doesn't compile with most recent mbed version

The firmware does not compile anymore if the most recent version of mbed is used by removing the version specifier here:

platform = ststm32@~5.3.0

Error message:

src/thingset_device.cpp:44:5: error: invalid use of template-name 'ThingSetSerial' without an argument list
     ThingSetSerial ts_uart(serial, pub_channel_serial);
     ^~~~~~~~~~~~~~
src/thingset_device.cpp:44:5: note: class template argument deduction is only available with -std=c++1z or -std=gnu++1z
In file included from src/thingset_device.cpp:40:0:
src/thingset_serial.h:55:28: note: 'template<class T> class ThingSetSerial' declared here
 template<typename T> class ThingSetSerial: public ThingSetStream
                            ^~~~~~~~~~~~~~
src/thingset_device.cpp:66:6: error: 'ts_uart' was not declared in this scope
     &ts_uart,
      ^~~~~~~
src/thingset_device.cpp:74:1: error: could not convert '{<expression error>}' from '<brace-enclosed initializer list>' to 'std::vector<ThingSetDevice*>'
 };
 ^
*** [.pio/build/mppt-1210-hus-v0.7/src/thingset_device.o] Error 1
cc1: warning: command line option '-Wno-register' is valid for C++/ObjC++ but not for C

@hogthrob : Do you have an idea? Unfortunately, my C++ knowledge is too little to find a fix immediately.

Merge state machines and error flags

We are currently using one global error_flags variable stored in DeviceStatus class to report errors. This is an inflexible solution if we add more loads and if also the USB output becomes one instance of the LoadOutput class (currently working on that change) as

  1. we can't easily support different hardware configurations with less or more output switches and
  2. we might run out of flags (only 32 possible).

Suggested change: Use one int state variable in each subsystem (LoadOutput, Charger, PwmSwitch, Dcdc) which stores either the state for the state machine (positive value) or the error flag(s) of this particular sub-system as a negative value. A negative value means automatically that the subsystem is not in operational state anymore. In the code, this would be handled by the default switch case, meaning error state now. The initial state would be value 0, meaning the subsystem is in intialization or idle state. Positive means operational, but we can have different operational states, e.g. CC or CV charging, derating because limits were reached, etc..

Any arguments against this change or other ideas?

Simple adc_get_value function non-existant

When developing new functions from the already existing ones, it is very easy to get lost on the code. Simple functions, such as adc_get_value do not exist (or we have not been able to find them). Maybe a certain set of basic functions should be defined so that everyone can build their applications from them.

Power load from panel instead of battery after reaching full charge

If the battery reaches full charged state, the charging is finished and the dcdc conversion is completely stopped. Which means that a potentially connected load now discharges the battery, even if there is enough solar energy available for powering the load.

Wouldn't it be a good idea to power the load from the panel?

Technically, in a MPPT controller in buck mode, the DCDC conversion has to keep the out->current in the _dcdc_control negative and as close as possible to 0 (which means battery discharge, but only as little as possible).

For the other modes, I haven't thought through it. Before I'll do this, my question is: is there any reason not to follow the idea of trying to minimize discharge of a fully charged battery?

Development Branch: Battery Pack Configuration

Hi,
I have been thinking about a good way to break down the configuration of the system and came up with this breakdown:

We have

  • PCB configuration: These define maximum operational limits, and are considered to be constant for a given hardware. These limits must be obeyed no matter what the battery pack, solar panel or load wants us to do. Can be derived from the hardware selection during compile time (PCB).

    • max charge current
    • max load current
    • maximum input voltage
  • Cell configuration: these are fixed for a battery pack consisting of cells of a given type, but each cell type has different values, each system may use different cell types, and configuration may change over time (reconfig). A chemistry typically has fixed values for voltages, but currents and capacity is varying for each cell

    • General chemistry: Lead-Acid, LiIo, LiFePO4 ...

    • max voltage

    • min voltage

    • max charge current

    • max discharge current

    • Optionally (not required for safe operation): capacity indication

  • Battery pack configuration: these are fixed for a battery pack consisting of cells, each system may use different configurations, and configuration may change over time (reconfig).

    • how many cells in parallel
    • how many in series
  • Charge strategy information: CCCV/Trickle/Equalization { various voltages and times; strategy for charge end detection and start detection }

  • and we have operational (dynamic) data describing the state of things

So what we need is a way for the user of the firmware easily to describe at least their cell configuration and pack configuration since without this no safe operation is possible. The minimum to specify is the chemistry, the maximum charge current, the maximum discharge current and the numbers of cells in parallel/series. Voltages may be derived from the chemistry (or have these configurable as well).

The charge strategy can be selected based on cell chemistry and calculates certain parameters from the cell and pack configuration parameters. We may permit modification of the strategy's parameters by the user at some stage of future development but this is not mandatory for safe operation.

Technically I would suggest to separate the battery cell / pack information into data structures separate from strategy information and have a way to let the user specify this easily when compiling the firmware and possibly later also for a running system, if there is persistent storage for parameters available (EEPROM).

During system start this "minimal set of user configurable data" is used for deriving the actual charging algorithm operational data from. This separation makes it easier to change the charging internal data structures without having the need to change the user provided information for a given system instance when upgrading to newer versions of the software. User just pulls the newest release, recompiles and loads it.

I think something like this makes using the firmware much easier. Next step is of course to implement a way to provide this information without having to compile the values into the firmware itself. But even then it is still the same issue in general: users don't want to be forced to (re)configure with every firmware update, so we need a stable set of parameters to describe the battery pack defined which are used across version. Having these defined makes at least basic operation within safe limits possible.

If this is an acceptable proposal, I would add this to the development branch of things. Since I would go for separate data structures, this is fairly uninvasive (not entirely, of course as the data needs to be read/used when initializing the charging).

Use edge-aligned PWM for MCUs with advanced timer TIM1

This increases the resolution of the PWM duty cycle of the DC/DC converter by a factor of 2, which helps to set the ratio between input and output voltage for the MPPT algorithm more precisely.

For TIM3 (as used in STM32L0) it is necessary to use center-aligned PWM mode, as this timer does not feature a dead-time generator. Thus, the dead-time between high-side and low-side MOSFET on-states has to be added manually, which is not possible in edge-aligned mode (as far as I know).

Artificial current limit

The line below effectively halfs the current limit for battery charging:

p_dcdc->pos_current_limit = p_bat->pos_current_limit - p_bat->current + p_load->current;

Lets do the math:

p_bat->pos_current_limit = 10; // max permitted charge current
p_bat->current  = 5; // current battery charging current
p_load->current = 0; // no load connected
=> p_dcdc->pos_current_limit = 5;

So far so good, but now have a look at these lines from the dcdc current control:

else if (out->current > out->pos_current_limit)
{
// output charge current limit reached
state = DCDC_STATE_CC;
pwr_inc_goal = -1; // decrease output power
}

Here we reduce the current once we are higher than p_dcdc->pos_current_limit
which is 5 if we have 5 amps of charging current. So if we ever go over 5A the current is reduced to around 5A.
But the real limit is 10A, not 10A/2. With this code we will never reach it. I tried this with a lab power supply and the code real does limit the current in the way described above.

I think, the formula should be p_bat->pos_current_limit + p_load->current

Integrate PlatformIO check (static code analysis)

PlatformIO is just awesome. In their latest release they integrated Cppcheck and Clang-Tidy. Now it's just a matter of adding check_tool = cppcheck, clangtidy to the platformio.ini to perform automated code analysis.

Steps to include into this project:

  1. Add to platformio.ini
  2. Resolve potential issues
  3. Integrate into TravisCI to run automatically on commit / pull request.

Results of first check: The code passed both cppcheck and clangtidy 🤘

Cppcheck only finds some minor low-level warnings (unused functions, as not all functions are needed for all types of charge controllers). clangtidy outputs quite a long list of medium level warnings, so we need to decide which warnings we consider relevant and fine-tune the options.

Module and function descriptions

Can we have a module description at the beginning of each file. Also, function descriptions before each function definition.
Example: in files bat_charger.cpp, dcdc.cpp

Revisit temperature limits and report over/under-temp load shutdown correctly

If the measured battery temperature gets above 50°C (configurable setting), discharging of the battery is disabled. The load output only realizes that it is not allowed to discharge anymore and assumes it is because of low voltage, so it goes into LOAD_STATE_OFF_LOW_SOC state. This does not make much sense.

Related to this issue: If no external sensor is connected, the sensor on the charge controller PCB is used, which can get considerably much hotter than ambient temperature at high load. This should be considered, either by a model-based approach or something more simple that increases the limits if charge controller load is high.

Not charging with 24V system

I've updated my MPPT-2420-lc to the latest firmware and noticed it not starting to charge the battery.
I narrowed it down to the variable lvs->bus->sink_voltage_bound sitting at 14.4V even though it detected it as 24V system correctyl.

Due to that circumstance, the function int Dcdc::check_start_conditions() in dcdc.cpp:L131 always returns "0".
It should return 1 to start buck mode but the statement in dcdc.cpp:L144 is always false lvs->bus->voltage [24.48] < lvs->bus->sink_voltage_bound [14.4]

I think it should take port->bus->series_multiplier = 2 from bat_charger.cpp:L255 into account.

I fixed it by changing the expression in the if statement in dcdc.cpp:L144 to:
lvs->bus->voltage < lvs->bus->sink_voltage_bound * lvs->bus->series_multiplier &&
But I don't know it there are other places that need adjustments to work properly.

Improve error handling

Currently, error information is often printed to the debug console immediately after the error is identified.

Some error conditions like undervoltage may persist for a longer period of time, resulting in lots of prints to the console. Also, errors often occur / are detected in an ISR context, where printing something is not ideal.

Possible improvement: Only set an error flag and offload error reporting to a different (lower priority) thread, possibly even the main thread. The error reporting checks if a flag has changed compared to previous check and prints the information about a new (or resolved) error only once.

Firmware does not work unless UART_SERIAL_ENABLED is defined in config.h

I found the cause for this to be sleep(). If UART_SERIAL_ENABLED is not defined and subsequently the ISR is not attached, it does not return, so after 10s the watchdog gets triggered and restarts the devices.
I have no idea why sleep returns in a timely manner if we have the serial port rx interrupt attached, but it is what I found out.

Offload ThingSet processing to dedicated thread

The processing of ThingSet requests that result in a large amount of returned data (e.g. ?conf and ?rec) requires considerable amount of RAM (around 1kB). Currently, each thread that processes ThingSet messages (serial, CAN at the moment, GSM, LoRa in future extensions) needs to reserve that amount of stack memory.

Suggested improvement: Offload the processing into a dedicated processing thread that is called asynchronously from other threads that send and receive the data via comms interfaces.

Implement firmware upgrade via USB / UART interface

The STM32 microcontrollers feature an integrated bootloader that allows to update the firmware via USB or UART. The bootloader can be enabled using the BOOT0 pin or by jumping to the bootloader section in the memory. Unfortunately, the software solution does not work properly for the STM32L072 processors, as they have a dual memory layout.

So far, suggestions described here did not work: https://stackoverflow.com/questions/42020893/stm32l073rz-rev-z-iap-jump-to-bootloader-system-memory

Missing documentation on how to change battery configuration if using Platformio

I was able to build firmware using from master and develop branches using PlatformIO and provided instructions.

However, I was not able to find out by reading the documentation if changing the default battery configuration is possible using PlatformIO tooling (in VSCode) at all and what would be the approach. Maybe it just works with the native zephyr tool set. As defining the battery type/information is one of the most common adjustments, it should be documented how to do this right.

Load + USB output state machine rework needed

Currently, USB and load output are both mangled in one file and have similar state machines. However, the state machines are not exactly the same, so we have lots of duplicated code.

In addition to that, errors in the load output sometimes need to overrule also the USB output. So we have duplicated code also in the error checking mechanisms.

The load output state is currently also used to indicate errors (saying why it is off and not only that it is off). Most of these errors are also indicated in the global log_data.error_flags. So we have another redundancy and source of issues here.

Don't have a good idea for improvement yet, but want to raise the issue so that we can think about it and discuss suggestions.

MPPT 2420 LC Improvements Required

TL;DR It is impossible without workarounds to enabled OLED on the MPPT 2420 LC due to insufficient RAM. Question is if and how to integrate these workarounds into the official setup

When updating my MPPT 2420 LC to the new v21 line based on Zephyr, I noticed that it was impossible to compile my (previously working) configuration from the mbed times. I.e. when selecting CAN and Serial plus OLED, it would not fit the content in the RAM.
Reason is the meager 16k of RAM of the STM32F072 in combination with the additional requirements of multi threaded operation (mostly stack sizes).
Even my actually required configuration of OLED and Serial Thingset doesn't fit. With some adjustments, a bit of code analysis and some trial and error, it turns out that it is safe to reduce the ISR stack allocation to 1KB, and to reduce the TX buffer by half to 512. Since I don't need CAN anymore (switched to ESP32 comm) I wanted to get rid of CAN as well. Just turning of the thingset CAN part unfortunately does not turn off the Zephyr CAN driver which eats valuable RAM without any benefit.

It is now easy to solve this by adding the appropriate settings to prj.conf:

# zephyr os settings
CONFIG_CAN=n
CONFIG_ISR_STACK_SIZE=1024
# "application" settings
CONFIG_THINGSET_CAN=n
CONFIG_UEXT_OLED_DISPLAY=y
CONFIG_UEXT_OLED_BRIGHTNESS=1
CONFIG_THINGSET_SERIAL_TX_BUF_SIZE=512

Question now is, how to make this easier for others to use this knowledge. We can't just put this in prj.conf (maybe we could with the commented out, was it is already done for other settings. Most of this applies only to MPPT 2420 with its low RAM, but on the other hand, turning of the CAN driver if not being by ThingSet used makes sense for all. And reducing the default ISR stack size should be done only if necessary as it may unexpected problems e.g. if additional drivers would require more ISR stack.

My knowledge of the Zephyr eco system is not good enough to see how to accomplish this, but I guess it is possible. This would allow users of the "old" MPPT 2420 like me to upgrade more easily.

Development Branch: Defining the initial operation mode for a given pcb?

I tested t1a65442eef5a4ec2f190af2922469e6e80bb8254 on a LibreSolar board 0.10 (assumin this version is equivalent to the published board design in the 20A MPPT Charger github (which it is according to the board labels). Anyway, when I start the board in dark conditions, it seems the boots part kicks in and raises the voltage displayed on the OLED quickly to 28V, displayed current and power also increased.
Turns out the code runs the nanogrid mode and I overlooked it.

Now comes the question
How can we decide which configuration is to be activated? This is very much related to the battery config issue #13.

Are all boards able to run both the "nanogrid" mode or "solar" mode? Or is a board (at least for now) either one or the other? Then we could put it into the pcb definition (1). If both are valid choices for most boards, we should make it part of the user initial configuration (2) (which I am working on).

If one of the two modes is "safe" we could also always use this one unless the runtime configuration configures the device operation mode to the other (3).

  1. is easiest to implement. least flexible though if boards support multiple operations modes. Otherwise the way to go in my opinion.
  2. good when compiling, still would need runtime configuration for later changes
  3. similar to 2) but requires no runtime configuration or compile time configuration for users of "safe" mode.

@martinjaeger, what do you think?

Implement global debug print function

It would make sense to have a possibility to switch on / off all serial output debug messages at once. I will research if there is such a method in mbed. Otherwise we can define our own macro DEBUG_PRINT (or is there something more suitable from C++ world, @hogthrob ?) in the main.h file.

Undervoltage Condition disables charging permanently

What is the problem:

If the battery was discharged until the load disconnects, charging will never commence after it stopped e.g. due to missing sunlight.

Problem Analysis:
If the load gets disconnected, we finally set the ERR_BAT_UNDERVOLTAGE in Charger::discharge_control() here:

dev_stat.set_error(ERR_BAT_UNDERVOLTAGE);

Only place we clear the flag is this:

if (port->bus->voltage >= num_batteries *
port->bus->src_droop_voltage(bat_conf->voltage_load_reconnect)
&& bat_temperature < bat_conf->discharge_temp_max - 1
&& bat_temperature > bat_conf->discharge_temp_min + 1)
{
// discharge current is stored as absolute value in bat_conf, but defined
// as negative current for power port
port->neg_current_limit = -bat_conf->discharge_current_max;
// delete all discharge error flags
dev_stat.clear_error(ERR_BAT_DIS_OVERTEMP);
dev_stat.clear_error(ERR_BAT_DIS_UNDERTEMP);
dev_stat.clear_error(ERR_BAT_UNDERVOLTAGE);
}

Since we will now never pass the start condition check (which tests for ERR_BAT_UNDERVOLTAGE) here:

dev_stat.has_error(ERR_BAT_UNDERVOLTAGE | ERR_BAT_OVERVOLTAGE) ||

we will never clear the flag ERR_BAT_UNDERVOLTAGE unless the battery voltage increases above the bat_conf->voltage_load_reconnect. However, how should the battery voltage magically increase above the limit without being charged?

The underlying question is: What is the exact meaning of ERR_BAT_UNDERVOLTAGE?

  1. It just indicates a too low battery voltage for load driving, we should have this stopping the charging start (remove check).
  2. It is meant to indicate a dangerous condition, i.e. we discharged below a critical point and don't want to start charging because this would possibly indicate a broken battery and thus charging could be dangerous, we should remove the ERR_BAT_UNDERVOLTAGE setting from bat_charger and only keep the remaining check in adc_dma for "real" undervoltage conditions.

I tend to interpretation 2.

Rename typedef structs to avoid _t

So far, the coding style for this firmware was roughly following the Linux Kernel or K&R guidelines, but using 4 instead of 8 spaces for indentation. We didn't have a detailed coding style guide.

For typedef structs we are currently using names with _t at the end, like charger_t, dcdc_t etc. However, these names are forbidden, as they are reserved for C internal types. I actually had a name collision when trying to define a buffer_t or a port_t.

The new Libre Solar coding style is considering this issue.

The mentioned structs will be renamed to Charger, Dcdc etc. I'm already working on that change and will send an update soon.

Make HS and LS max voltage settings PCB specific

Currently, pcb.h contains the following settings:

/** Maximum voltage at battery port (V)
 */
#define LOW_SIDE_VOLTAGE_MAX    32

/** Maximum voltage at PV input port (V)
 */
#define HIGH_SIDE_VOLTAGE_MAX   55

Some PCBs don't allow 32 V at the low side. So these settings should be moved to the files in /pcb/ folder.

MPPT 2420 LC "No battery temp sensor" detection does not work anymore on v21.0

The calculated "open sensor" temperature on the MPP 2420 LC is around -32.5 and not below -50 as required for

if (bat_temp > -50) {

to do its magic. Was working with old firmware from 2019. Could not see the difference in the code easily, looks to me more or less identical, hence raising the issue here. I personally solved the problem by entirely disabling the sensor via an mppt_2420_lc.overlay file in the app directory:

/*
 * Copyright (c) The Libre Solar Project Contributors
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/ {
        pcb {
                version-str = "v0.10";
                version-num = <10>;
        };

        adc-inputs {
                // /delete-node/ temp-bat;
        };
};

but it would be nicer, if we get back the original automatic detection capability.

charger_detect_num_batteries returns always 12V battery

I'm trying to set the MTTP 2420 with an 24V battery but the controller reports only 12V battery.

I think the multiplication by 2 here

if (bus->voltage > bat->voltage_absolute_min * 2 &&
bus->voltage < bat->voltage_absolute_max * 2) {
is incorrect.

If I set BATTERY_NUM_CELLS in "config.h" to 12 as suggested for 24V systems the if statement is always false and defaults to 12V (actual values added in [brackets])

    if (bus->voltage [24.4] > bat->voltage_absolute_min * 2 [38.40] &&
        bus->voltage [24.4] < bat->voltage_absolute_max * 2 [58.80]) {
        charger->num_batteries = 2;
        printf("Detected 24V battery\n");
    }
    else {
        printf("Detected 12V battery\n");
    }

MPPT does not work if connected load is higher than power provided by panel

I noticed that a couple of times that the MPPT 2420 turned off using power from the panel in full sunshine which is strange.
It turns out that in line

float dcdc_power_new = out->voltage * out->current;

the battery charging current is used to calculate the supplied power. Which goes to negative if the connected load is drawing more power than the panel is able to supply. This forces the MPPT try to get even more power, which basically increases the PWM duty cycle to max duty cycle, and then panel voltage drops.
The fix for me was to replace "out->current" in this line with "dc->ls_current" which represents the actual power provided by the panel. Now it seems to work as expected. However, I haven't looked into all possible cases (like boost charging etc).

Maybe my fix is not suitable in all cases, but the issue as such exists.

MPPT-2420-LC support status

Hi, I tried to upgrade my MPPT2420 controller software to the latest commit from master branch (it runs with firmware from Oct 18 w/o problems). The new commit builds and uploads okay. However, nothing happens. No leds, no nothing.

The code seems not to reach main() since I successfully enabled the OLED (could see the splash screen, so the upload works) but my attempt to put anything on the screen failed by calling the oled functions right in the first line of main.
Before I get out the gdb , I'd like to know, if there is any known issue with this device and this branch?

Dead link on this Github page

Sorry for coming up with such minor thing. - Maybe even out of scope?

On the page:
https://github.com/LibreSolar/charge-controller-firmware/blob/master/docs/firmware.md

is the link to
https://libre.solar/docs/toolchain

dead.

The link is in the words "develop software", on the section:
https://github.com/LibreSolar/charge-controller-firmware/blob/master/docs/firmware.md#toolchain-and-flashing-instructions

I encountered the problem because of my interest in working with the software. I was interested in the information. Is there a new page replacing the dead link?

Cheers,

Support load by solar power if battery is discharging but not discharged "enough"

I recently added some code which keeps the solar panel delivering energy to the load even if the LiIon battery is fully charged (we simply keep the charge current as close as possible below 0). Now with an increased battery capacity I came across another "issue": This reduced discharge by using the panel to power the load (but not charging the battery) works fine until the night and the next morning comes: The solar power will not be used even if it is available until we discharge under the restart charge voltage limit.
This is cause by the check for the dcdc power transfer start, it checks if the charging is permitted (which is not, since we have not yet fallen below the limit):

&& out->chg_allowed == true

I think we can drop this line altogether. In case charging is not permitted, we should keep the charge current below zero (i.e. no transfer into the battery), but otherwise, why not transfer energy?
I opened this issue to discuss this. I would like to understand if there is a good argument for not removing this line. I know the change would work in my setup.

Check total energy calculation

The total energy should be stored in EEPROM and continued to accumulate after reset / power-down of the device.

The current implementation probably does not work as intended:

static uint32_t solar_in_total_Wh_prev = solar_in_total_Wh;

The static variables are initialized before the EEPROM content is read, so they are most probably always 0.

battery current

Hello

At the beginning i would like to congratulate You. This project is awesome. Very professional design.

I have a question for You. Why the algorithm does not include the load current? I think, battery current should be calculate based on DC/DC current and load current and then run state machine.

Best regards

Load not switching on with 24V system

I've found another bug regarding the series multiplier in 24V systems.
The Load wont switch on due to a overvoltage condition in load.cpp:L72

        if (bus->voltage [25.4] > overvoltage [14.7] || bus->voltage [25.4] >
            DT_CHARGE_CONTROLLER_PCB_LS_VOLTAGE_MAX [32])

The variable overvoltage is beeing set by

load.set_voltage_limits(bat_conf.voltage_load_disconnect [11.7], bat_conf.voltage_load_reconnect [12.6],
        bat_conf.voltage_absolute_max [14.7]);

in main.cpp:L65

These values shoud be adjusted with the series multiplier to account for 24V systems.

Interference between Zephyr ADC driver and COMP interrupt

Causes hard fault in this line:
https://github.com/zephyrproject-rtos/zephyr/blob/4700c93f3cd898645182855663d0bb5e76a5ad9b/drivers/adc/adc_stm32.c#L334

See 91d4ec4 for a workaround.

This has to be fixed properly in order to make load short circuit protection work with Zephyr.

Options:

  1. Don't use Zephyr ADC driver for L0 anymore and completely disable it.
  2. Find some way to distinguish between different interrupt sources in the ISR. Might need changes in Zephyr driver.
  3. Other?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.