Battery upgrade?

He said he will merge it on “Sunday”.
Where he lives it is currently Sunday morning, he probably won’t be waking up for an hour or two.


Do you have an example of this being done, even in an incomplete form?

To be honest I’m not sure if many people would use it but it might be worth experimenting with in case there is interest.

Well…
I don’t have my Arduboy right now…
Mom refuse to believe I am coding stuff even when I show her the code, and tuck the card away in a drawer in her room. Will snuck it back out when she was not there. (I and her have eternal conflict over entertainment devices, so don’t discuss anything about this anymore, and trying to help will result in failure.)
EVEN IF I AM HAVING SUMMER VACATION.
She don’t care when I am typing code, though. (since she can’t understand that anyway) That’s kind of why I am making so many progress here.

This is the original ON_RANDOMNESS by @Mr.Blinky if I am right, and I was playing with the ANPIN and see what it draws

#include <Arduboy.h>
#define ANPIN 5
Arduboy arduboy;
//char text[30];
uint16_t val[128];
uint16_t tm;
void setup() {
arduboy.begin();
arduboy.setFrameRate(30);
}

void loop() {
  if (!(arduboy.nextFrame())) return;
  arduboy.clear();
  power_adc_enable();
  uint16_t v = analogRead(ANPIN);
  power_adc_disable();
  val[(tm+127)%128] = v;
  //arduboy.setCursor(0,0);
  //sprintf(text, "%04d", v);
  //arduboy.print(text);
  arduboy.setCursor(100,0);
  arduboy.print(v);
  for(int i = 1; i < 128; i ++) {
    uint16_t v1 = val[(i-1+tm)%128];
    uint16_t v2 = val[(i+tm)%128];
    arduboy.drawLine(i - 1, 63 - v1 / 10, i, 63 - v2 / 1, 1);
  }
  arduboy.display();
  tm++;
}

So original, didn’t even squash the sprintf and char text[30] (need arduboy to verify)

This has nothing to do with measuring the battery charge.
It also isn’t random, and I believe pin 5 is one of the speakers.

Yes, it is not random (because it just read the value)
which is interesting and wonder if I changed anything…but I don’t think so.
THEY call it that, not me. I think it is during them discussing random noise.
Nope, Pin 5 is unused. Applying pressure at where the ATMega32U4 is creates a electrostatic charge (as shown on graph)
Pin 4 is also unused, and Pin 5 is more noisy. (it could be speaker, but that doesn’t matter.)
I think Pin 6 is for speaker…
Which could lead to another input…
It is basically what I used to measure the “signal” over the pin I chose, but I don’t have the Arduboy right now…
Warning: Don’t go off-topic!

And none of this has anything to do with measuring the battery.

No there isn’t. The Arduboy’s processor and display run directly from the raw battery output. (Actually there’s some protection circuitry in there but it doesn’t affect things much.)

1 Like
1 Like

Nice
Which means my Homemade Arduboy can be simplified (no longer need a fancy voltage stabilizer)
snuck the code out here. Did a little simplification.

uint16_t rawADC(uint8_t adc_bits)
{
  power_adc_enable(); // ADC on
  ADMUX = adc_bits;
  // we also need MUX5 for temperature check
  if (adc_bits == ADC_TEMP) {
    ADCSRB = _BV(MUX5);
  }
  delay(2); // Wait for ADMUX setting to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // measuring
  return ADC;
  power_adc_disable();//Xavier added this
}
voltage = 1125300L / rawADC(ADC_VOLTAGE);

@MLXXXp You didn’t do the power_adc_disable after enabling it.
Maybe because it is supposed to be used in a power_adc_enable environment?
And why is voltage = 1125300L / rawADC(ADC_VOLTAGE);?

That isn’t my code. It’s from a pull request submitted by yyyc514.

That value is actually wrong. It should be 1126400L. It would have been better if the source code showed the actual math and then let the compiler compute the constant:

voltage = (unsigned long) (1.1 * 1024 * 1000) / rawADC(ADC_VOLTAGE);

1.1 is the (expected) bandgap voltage that we’re measuring with the ADC.
1024 is the full scale resolution of the ADC.
1000 is to convert volts to millivolts.

Since we’re using the processor’s Vcc (which is the battery voltage) as the reference voltage for the ADC, by dividing the above value by the bandgap reading returned by the ACD we will get the battery voltage in millivolts.

A point to note:
If all you want to do is detect if the voltage has fallen below a single given point, you may as well pre-calculate that value in terms of a raw ADC reading, then compare directly to the returned ADC value.

However, as I’ve stated repeatedly:
If you go by the ATmega32U4 datasheet, the bandgap voltage for any given chip can actually be between 1.0 and 1.2 volts. This is a variance of +/- 9% over the nominal 1.1V. The battery discharge curve is quite flat, so the voltage indicating a low battery has to be fairly accurate. I don’t think the possible +/- 9% variance for any given Arduboy will allow a single constant to be used to indicate a low battery. I think the value will have to be calibrated for each individual Arduboy.

1 Like

This page looked interesting. But I’m unable to view more than the left hand side on my mobile to actually read it.

https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

That’s almost what the original code from the PR is equivalent to.

Code from that Article:

long readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

Code from the PR:

uint16_t Arduboy2Base::rawADC(uint8_t adc_bits)
{
  power_adc_enable(); // ADC on

  ADMUX = adc_bits;
  // we also need MUX5 for temperature check
  if (adc_bits == ADC_TEMP) {
    ADCSRB = _BV(MUX5);
  }

  delay(2); // Wait for ADMUX setting to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  return ADC;
}

bool Arduboy2Base::checkBatteryLow() {
  bool batteryLow;
  uint16_t voltage;

  voltage = rawADC(ADC_VOLTAGE);
  power_adc_disable(); // turn the ADC back off

  // some voltage values for reference
  // 4262mv - fully charged (plugged in)
  // 41??mv - fully charged
  voltage = 1125300L / voltage;
  batteryLow = voltage < 3700;

  if (batteryLow) {
    TXLED1;
  } else {
    TXLED0;
  }
  return batteryLow;
}

Note that rawADC was removed from the library at some point, so that PR couldn’t be merged automatically, it would have to be changed somewhat.


Side note:
I don’t understand why so many of the library functions predeclare their variables at the top of the function.

Yes, I removed it because it didn’t serve any useful purpose in terms of the defined API. My thought was that it, or something similar, could be added back in if it became necessary.

The Arduino environment allows users wishing to control hardware not handled in the Arduboy2 or other library to include such code in their own sketches.

1 Like

To be clear, that wasn’t a judgement about whether it was a good decision or not,
merely a statement of fact to save people the trouble of looking for it or making any general analysis of it,
and to be clear why merging the PR would be troublesome if anyone was contemplating suggesting to do so.

(My ‘Side note’ on the other hand was very slightly judgemental.)

1 Like

1.1 is the (expected) bandgap voltage that we’re measuring with the ADC.
1024 is the full scale resolution of the ADC.
1000 is to convert volts to millivolts.
Thanks :blush:

:thinking:

#define ADC_TEMP (_BV(REFS0) | _BV(REFS1) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0))
#define ADC_VOLTAGE (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
uint16_t battery;
uint16_t rawADC(uint8_t adc_bits)
{
  power_adc_enable(); // ADC on
  ADMUX = adc_bits;
  // we also need MUX5 for temperature check
  if (adc_bits == ADC_TEMP) {
    ADCSRB = _BV(MUX5);
  }
  delay(2); // Wait for ADMUX setting to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // measuring
  const uint16_t variable = ADC;
  power_adc_disable();
  return variable;
}

//somewhere else
if(arduboy.everyXFrames(30))/*check every second or so*/battery = 1126400L/*1.1 * 1024 * 1000*// rawADC(ADC_VOLTAGE)
arduboy.print(battery);

Okay…

1 Like