The LiFePO4 cell is charged at 3.65V to attain 100% charge but when charged and rested without any load the theoretical value is 3.4V and in practical it is 3.3V
Please see post #36
You've made what should be a simple calculation quite complicated:
- In points 5,6 and 7 you are choosing a sample rate close to the maximum that the ADC can manage rather than a lower sample rate that easier to work with. I suggested 2ms but maybe for this application even that is unnecessarily high. Your code controls the sample rate and you can choose anything which does not exceed the capabilities of the ADC and gives enough precision for your application.
So what are you waiting for ? Pack your coulomb counting code into a simple framework to test it. You've been given an example in post #38. Start with fully charged battery and load it until it is depleted and see if the calculated capacity and actual capacity match.
I doubt that.
Will test that tomorrow.
Leo..
Edit: charged a cell to 3.65volt, but didn't leave it at that voltage for long.
It dropped overnight to 3.40volt.
In your code at post #38 you are waiting for 1500uS to read the new sample and I am to check if sample is ready and reading the sample as soon as it’s ready. Reason, this is for Ebike where the current drawn is not steady so trying to take the maximum samples possible to get accuracy by reading the current drawn at the smallest intervals possible.
The above looks odd. Normally you'd loop waiting while the resource is not ready. Something like:
while( !ADS.isReady()) { // note the !
// Wait for ADC to be ready before attempting to get a conversion result
}
int16_t adcRaw = ADS.getValue();
Having said that, I don't know the library so it could be correct.
Have you a waveform of the charge/discharge current through the battery to see what the optimal sampling period could be ?
while(ADS.isReady(){
That's how @robtillaart ads1115 library works.
No I don't have the waveform of the charge/discharge current. My hardware is ready and programmed. Will have to check what results I get and believe in it.
@6v6gt @dariods8474
The ADS.isReady() function works only for single shot mode, as documented in readme.md and datasheet. Behavior of the OS (operational status) bit in continuous mode is not defined.
@dariods8474 do you use continuous mode in your program?
I guess the answer is here in setup() from the OP's code in post #1 :
Wire.begin();
// Settings for ADS1115 16-Bit ADC
ADS.begin();
ADS.setGain(1); // 1 = 4.096 volts, 1 Bit = 0.125 mV
ADS.setDataRate(7); // 0 = slow 4 = medium 7 = fast
ADS.setMode(0); // 0 = continuous mode, 1 = single-shot mode(default)
ADS.readADC(0); // first read to trigger pins 0,1,2,3
FYI, as the isReady() seems to work inverted in continuous mode, I created an issue in the ADS1x15 repo to investigate this (when prio/time permits). If this is confirmed I can simply “invert” the logic if in continuous mode, so isReady works in both modi.
If this is an assumption based solely on inspection the OP's code then it may be too early to take any action.
It is not clear that the code has been tested in any detail and at least some of it has been generated by AI. If the AI "knew" about any inverted behaviour of the isReady() method in your library then either it knows more about it that you do or, much more plausible, it simply dropped the NOT operator "!" in the quoted construct.
Anyway, the OP can come back and add some more information which may help to clarify the matter.
Thanks for your advice, appreciated!
It is my assumption, but worth investigating if time / prio permits. Still if it is an undocumented feature it might work on one device and not on the other. Been there before ![]()
I repeatedly said I use AI only to optimise my code not to create one. You still want to believe that it's a AI generated code so I will live it like that, no defence regarding AI coding. The code
while(ADS.isReady)
actually means wait until ads is ready with the conversion which should have been
while(!ADS.isReady) or (ADS.isBusy)
When I used AI to optimise the code it did give me as while(!ADS.isReady). Even I believed that “!” should have been there. The esp32 keeps waiting, no further code is executed which was confirmed by Serial.print command.
Yes I use continuous mode as pointed out in my code by user @6v6gt . Thankyou user
The cells I am using shows 3.3V after resting. You may have got a very high quality cell.
Just a Duracell 18500 I grabbed from a DIY garden light that is already going for almost three years (~1000 cycles).
Leo..
Edit: Left the cell on charge at 3.65volt for a couple of hours, before disconnecting.
20 hours later the cell measured 3.60volt.
I don't think you are using a LFP cell, it's a lithium ion cell. A LFP or LiFePO4 cell will never show 3.6V after sufficient resting time. Not practically nor theoretically.
Definately a LiFePo4 18500/1Amp cell with 3.2volt writen on it.
Still is 3.59V after 30 hours.
But back to your project. I think that battery voltage can almost be ignored in your case.
There is vey little power stored in the rise between 3.3 and 3.6volt.
Leo..
I find that odd because the ADC is configured for continuous mode so the underlying flag (OS) should cycle with a period of ~1200us so any blocking should not have been noticeable. Anyway, writing potentially blocking code without handling a timeout is not good practice.
Also, you should also review whether you really need to test if a sample is ready if you are using the ADC in continuous mode. A sample will always be ready and will be replaced with a new one at the ADS's configured sampling rate.
If you get a value from the ADC at a rate higher than the ADC's sampling rate, then you may see the same sample several times. If you get a value at a lower rate than the ADC's sampling rate, then you will miss some samples. All you need to do is get values at the rate the accuracy of your application requires but there is no point in greatly exceeding the rate at which the ADC works. It does not appear to be too critical because you seem to be aggregating 86 samples in a batch.
Thanks for pointing out my mistake. I will correct it
while(ADS.isReady()) {
// Wait for ADC ready
}
to
unint32_t ConversionStartTime; // Declaration in the start of the function
for(valid_samples = 1; valid_samples < Num_Max_Samples; valid_samples++) {
ConversionStartTime = millis();
while(ADS.isReady()) {
if(millis() - ConversionStartTime > 2){ // if more than 2mSec
valid_samples--;
break;
}
}
int16_t adcRaw = ADS.getValue();
I don’t think I need mutex as task on core0 writes/updates some global variable and tasks on core1 only reads them to display on GLCD. Even if there is a delay in update vs read it would be just 100ms.