Blame view

epsilon-master/ion/src/device/battery.cpp 2.49 KB
6663b6c9   adorian   projet complet av...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  #include <ion/battery.h>
  #include "battery.h"
  #include "regs/regs.h"
  
  /* To measure the battery voltage, we're using the internal ADC. The ADC works
   * by comparing the input voltage to a reference voltage. The only fixed voltage
   * we have around is 2.8V, so that's the one we're using as a refrence. However,
   * and ADC can only measure voltage that is lower than the reference voltage. So
   * we need to use a voltage divider before sampling Vbat.
   * To avoid draining the battery, we're using an high-impedence voltage divider,
   * so we need to be careful when sampling the ADC. See AN2834 for more info. */
  
  namespace Ion {
  namespace Battery {
  
  bool isCharging() {
    return !Device::ChargingGPIO.IDR()->get(Device::ChargingPin);
  }
  
  Charge level() {
    if (voltage() < 3.2f) {
      return Charge::EMPTY;
    }
    if (voltage() < 3.5f) {
      return Charge::LOW;
    }
    if (voltage() < 3.8f) {
      return Charge::SOMEWHERE_INBETWEEN;
    }
    return Charge::FULL;
  }
  
  float voltage() {
    ADC.CR2()->setSWSTART(true);
    while (ADC.SR()->getEOC() != true) {
    }
    uint16_t value = ADC.DR()->get();
  
    // The ADC is 12 bits by default
    return Device::ADCDividerBridgeRatio*(Device::ADCReferenceVoltage * value)/0xFFF;
  }
  
  }
  }
  
  namespace Ion {
  namespace Battery {
  namespace Device {
  
  void init() {
    initGPIO();
  
    /* The BAT_SNS pin is connected to Vbat through a divider bridge. It therefore
     * has a voltage of Vbat/2. We'll measure this using ADC channel 0. */
    ADCGPIO.MODER()->setMode(ADCPin, GPIO::MODER::Mode::Analog);
  
    // Step 2 - Enable the ADC
    RCC.APB2ENR()->setADC1EN(true);
    ADC.CR2()->setADON(true);
  
    // Configure the ADC channel
    ADC.SQR1()->setL(0); // Always sample the same channel
    ADC.SQR3()->setSQ1(ADCChannel);
    ADC.SMPR()->setSamplingTime(ADCChannel, ADC::SMPR::SamplingTime::Cycles480); // Use the max sampling time
  }
  
  void initGPIO() {
    /* Step 1 - Configure the GPIOs
     * The BAT_CHRG pin is connected to the Li-Po charging IC. That pin uses an
     * open-drain output. Open-drain output are either connected to ground or left
     * floating. To interact with such an output, our input must therefore be
     * pulled up. */
    ChargingGPIO.MODER()->setMode(ChargingPin, GPIO::MODER::Mode::Input);
    ChargingGPIO.PUPDR()->setPull(ChargingPin, GPIO::PUPDR::Pull::Up);
  }
  
  void shutdown() {
    ChargingGPIO.MODER()->setMode(ChargingPin, GPIO::MODER::Mode::Analog);
    ChargingGPIO.PUPDR()->setPull(ChargingPin, GPIO::PUPDR::Pull::None);
  
    // Disable the ADC
    ADC.CR2()->setADON(false);
    RCC.APB2ENR()->setADC1EN(false);
  }
  
  }
  }
  }