Coulomb Counter API
Description
Coulomb Counter Driver API.
Introduction
DCDC converters use pulse-frequency modulation (PFM) to drive outputs. The Coulomb counter counts the number of PFM pulses delivered to each output. In order to get the total charge from an output, the charge-per-pulse (CPP) must be determined, then the total charge is computed like so: total_charge = CPP * Num_pulses.
Currently, only EFP's DCDC are supported by this driver. The Coulomb counter driver provides an abstraction on top of the EFP registers to make the calibration and reading the counters easier.
Calibration
The goal of the calibration is to compute the charge-per-pulse value for each output. In order to achieve that, known loads are applied to outputs and the number of pulses are counted. More details can be found in application note AN1188: EFP01 Coulomb Counting.
One of the main assumption that is made to compute the CPP is that the system load current remains relatively constant during calibration, that means the application should not switch energy mode, start radio transmissions, etc. This is critical for calibration accuracy. If this is not followed, the driver will return inaccurate results.
Hardware is capable of calibrating only one output at a time. For each output, there are at least two measurements, one with low current and one with high current. In the worst case scenario, a measurement can take up to 6.5ms (that is 2^16, the size of the counter, divided by 10MHz, the oscillator frequency). So if several outputs are to be calibrated, it will happen sequentially, that means the calibration time is proportional to the number of outputs.
EM2 Output
EFP's VOB output has different voltage and peak current configuration for EM0 and EM2 energy modes. This output can be used to power the DECOUPLE line of the MCU. It also has different Coulomb counters for these two energy modes. As peak current and output voltage are some of the parameters that determine the CPP, the output must be calibrated for each energy mode.
Typically, EM2 peak current and voltage are lower than those of EM0 for improved efficiency. In order to accurately compute the CPP, the Coulomb counter driver will request at some point during the calibration that the EM2 peak current configuration is applied. Application should take care of limiting actions that draw too much current during that time.
Recalibration
A number of conditions can affect the CPP. Due to the following changes, a recalibraiton might be necessary for accurate results:
- Significant change in input voltage
- Change of output voltage
- Change of output peak current
- Change in energy mode
- Change of DCDC operating mode
For the latter, the driver will report when such event is detected, to let the application know a recalibration must occur.
Configuration
The Coulomb counter can be configured by using the configuration tool within Simplicity Studio. From there one can select the number of the EFP instance to use, which output to measure, prescaler and threshold values.
Usage
The expected flow of execution is:
- initialize the driver
- calibrate
- start the counters
- periodically or interrupt-based event to read the counters
Initialization is done by calling sl_coulomb_counter_init() . It will prepare internal structure and setup communication with Coulomb counter device.
Calibration is the next step and is done in two folds, first the calibration is initialized by calling sl_coulomb_counter_calibrate_init() and then sl_coulomb_counter_calibrate() is called repeatedly until it reports an error or completion.
When calibration is done successfully, counters can be started by calling sl_coulomb_counter_start() .
Then, periodically counters be read by calling sl_coulomb_counter_read() . This function has an output parameter to notify if some outputs must be recalibrated. That will happen in the output operates in a different DCDC mode than when it was calibrated. Note that when counters are read, they are cleared afterwards, so if the function is called too often, it will keep reading zeroes. This might be an issue for output that have a slowly increasing count of pulses, like VOB in EM2. To prevent that, one can wait for the interrupt threshold to be raised before reading registers.
Finally, to get the value of all outputs in Coulomb, call sl_coulomb_counter_get_total_charge() . If interested in only one or more outputs, use sl_coulomb_counter_get_charge() instead.
Here is a complete example:
Functions |
|
sl_status_t | sl_coulomb_counter_int_enable (uint8_t flag) |
Enable interrupt.
|
|
sl_status_t | sl_coulomb_counter_int_disable (uint8_t flag) |
Disable interrupt.
|
|
sl_status_t | sl_coulomb_counter_int_is_set (uint8_t flag, bool *is_set) |
Check if interrupt flag is set.
|
|
sl_status_t | sl_coulomb_counter_int_clear (uint8_t flag) |
Clear interrupt flag.
|
|
sl_status_t | sl_coulomb_counter_init (void) |
Initialize Coulomb counter peripheral.
|
|
sl_status_t | sl_coulomb_counter_start (void) |
Start counting coulombs.
|
|
sl_status_t | sl_coulomb_counter_stop (void) |
Stop counting coulombs.
|
|
sl_status_t | sl_coulomb_counter_read ( sl_coulomb_counter_output_mask_t *outputs_need_calibration_mask) |
Read coulomb counters.
|
|
float | sl_coulomb_counter_get_charge ( sl_coulomb_counter_output_mask_t outputs_mask) |
Return total charge only for selected outputs.
|
|
float | sl_coulomb_counter_get_total_charge (void) |
Return total charge.
|
|
sl_coulomb_counter_output_mask_t | sl_coulomb_counter_outputs_available (void) |
Return available outputs.
|
|
sl_coulomb_counter_output_mask_t | sl_coulomb_counter_outputs_need_calibration (void) |
Return outputs that must be recalibrated.
|
|
sl_coulomb_counter_calibration_status_t | sl_coulomb_counter_calibrate_init ( sl_coulomb_counter_output_mask_t outputs_mask) |
Setup calibration for selected outputs.
|
|
sl_coulomb_counter_calibration_status_t | sl_coulomb_counter_calibrate_wait (void) |
Wait for current step of the calibration routine to complete.
|
|
sl_coulomb_counter_calibration_status_t | sl_coulomb_counter_calibrate (void) |
Step function for calibration.
|
|
Typedefs |
|
typedef uint32_t | sl_coulomb_counter_output_mask_t |
Bitmask of outputs to operate on.
|
|
Enumerations |
|
enum |
sl_coulomb_counter_prescaler_t
{
SL_COULOMB_COUNTER_PRESCALER_ZERO , SL_COULOMB_COUNTER_PRESCALER_ONE , SL_COULOMB_COUNTER_PRESCALER_TWO , SL_COULOMB_COUNTER_PRESCALER_THREE } |
Coulomb counter prescaler enum.
|
|
enum |
sl_coulomb_counter_threshold_t
{
SL_COULOMB_COUNTER_THRESHOLD_50 , SL_COULOMB_COUNTER_THRESHOLD_62 , SL_COULOMB_COUNTER_THRESHOLD_75 , SL_COULOMB_COUNTER_THRESHOLD_87 } |
Coulomb counter threshold for counter full interrupt enum.
|
|
enum |
sl_coulomb_counter_calibration_status_t
{
SL_COULOMB_COUNTER_CALIBRATION_ERROR , SL_COULOMB_COUNTER_CALIBRATION_IN_PROGRESS , SL_COULOMB_COUNTER_CALIBRATION_PEAK_CURRENT_EM0 , SL_COULOMB_COUNTER_CALIBRATION_PEAK_CURRENT_EM2 , SL_COULOMB_COUNTER_CALIBRATION_DONE } |
Coulomb counter calibration status enum.
|
|
Function Documentation
◆ sl_coulomb_counter_int_enable()
sl_status_t sl_coulomb_counter_int_enable | ( | uint8_t |
flag
|
) |
Enable interrupt.
- Parameters
-
[in] flag
Interrupt flag to be enabled.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_int_disable()
sl_status_t sl_coulomb_counter_int_disable | ( | uint8_t |
flag
|
) |
Disable interrupt.
- Parameters
-
[in] flag
Interrupt flag to be disabled.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_int_is_set()
sl_status_t sl_coulomb_counter_int_is_set | ( | uint8_t |
flag,
|
bool * |
is_set
|
||
) |
Check if interrupt flag is set.
- Parameters
-
[in] flag
Interrupt flag to be checked. [out] is_set
Boolean with result.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_int_clear()
sl_status_t sl_coulomb_counter_int_clear | ( | uint8_t |
flag
|
) |
Clear interrupt flag.
- Parameters
-
[in] flag
Interrupt flag to be checked.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_init()
sl_status_t sl_coulomb_counter_init | ( | void |
|
) |
Initialize Coulomb counter peripheral.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_start()
sl_status_t sl_coulomb_counter_start | ( | void |
|
) |
Start counting coulombs.
This starts the coulomb counter. Outputs selected for measurements must be calibrated when this function is called, or it will fail. When counting, calibration is not permitted.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_stop()
sl_status_t sl_coulomb_counter_stop | ( | void |
|
) |
Stop counting coulombs.
This stops the coulomb counter. Note that the counter must be stopped before calling sl_coulomb_counter_calibrate() .
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_read()
sl_status_t sl_coulomb_counter_read | ( | sl_coulomb_counter_output_mask_t * |
outputs_need_calibration_mask
|
) |
Read coulomb counters.
Read coulomb counters for all outputs selected via configuration header. Note that all outputs must be read at once, as counters are automatically cleared after reading. Values read are accumulated into internal counters. Each count in the counters represents 2^(16 - 2 * prescaler) PFM pulses. This function only reads the counters registers and accumulate these values with counters stored in the driver, to get the charge, one must call sl_coulomb_counter_get_charge() or sl_coulomb_counter_get_total_charge() .
- Warning
- Some counters increment slowly, especially when counting in EM2 mode, so if this function is called in a tight loop, it is possible that it keeps reading 0 because the number of PFM pulses is never high enough to reach 2^(16 - 2 * prescaler) and because counters are cleared after being read. That can lead to some PFM cycles not being counted, thus inaccurate results.
- Note
- Outputs' modes of operation can change between two reads. If that happens, counters will be accumulated with current calibration settings, and outputs will be set in the out parameter. Subsequent reads of these outputs will be skipped until they are recalibrated.
- Parameters
-
[out] outputs_need_calibration_mask
Will contain mask of outputs that need to be recalibrated.
- Returns
- 0 if successful, error code otherwise.
◆ sl_coulomb_counter_get_charge()
float sl_coulomb_counter_get_charge | ( | sl_coulomb_counter_output_mask_t |
outputs_mask
|
) |
Return total charge only for selected outputs.
- Parameters
-
[in] outputs_mask
Mask of outputs.
Return total charge that has flown through selected outputs. This is computed using values accumulated via sl_coulomb_counter_read() and calibration settings.
- Returns
- Returns total charge for selected outputs.
◆ sl_coulomb_counter_get_total_charge()
float sl_coulomb_counter_get_total_charge | ( | void |
|
) |
Return total charge.
Return total charge for all outputs that were selected during initialization.
- Returns
- Returns total charge for selected outputs.
◆ sl_coulomb_counter_outputs_available()
sl_coulomb_counter_output_mask_t sl_coulomb_counter_outputs_available | ( | void |
|
) |
Return available outputs.
Depending on the configuration option, this driver use different peripherals for Coulomb counting. This function returns outputs that are available on the selected peripheral.
- Returns
- Returns a mask of available outputs for the selected peripheral.
◆ sl_coulomb_counter_outputs_need_calibration()
sl_coulomb_counter_output_mask_t sl_coulomb_counter_outputs_need_calibration | ( | void |
|
) |
Return outputs that must be recalibrated.
Some events might require an output to be recalibrated to correctly measure the charge, for instance, if a DCDC changes its operating mode.
- Returns
- Returns a mask of outputs that needs to be recalibrated.
◆ sl_coulomb_counter_calibrate_init()
sl_coulomb_counter_calibration_status_t sl_coulomb_counter_calibrate_init | ( | sl_coulomb_counter_output_mask_t |
outputs_mask
|
) |
Setup calibration for selected outputs.
Calibrate, or recalibrate, selected outputs. The counter must be off for calibration to be possible.
- Warning
- During calibration, power consumption of the system must remain stable.
- Parameters
-
[in] outputs_mask
A mask of outputs to be calibrated.
- Returns
- SL_COULOMB_COUNTER_CALIBRATION_IN_PROGRESS if successful, SL_COULOMB_COUNTER_CALIBRATION_ERROR otherwise.
◆ sl_coulomb_counter_calibrate_wait()
sl_coulomb_counter_calibration_status_t sl_coulomb_counter_calibrate_wait | ( | void |
|
) |
Wait for current step of the calibration routine to complete.
This routine waits for the current calibration step to complete before returning. When calibrating in polling mode, this function must be called when sl_coulomb_counter_calibrate() returns SL_COULOMB_COUNTER_CALIBRATION_IN_PROGRESS. When calibrating in interrupt mode, this function is not used.
- Returns
- SL_COULOMB_COUNTER_CALIBRATION_IN_PROGRESS if successful, SL_COULOMB_COUNTER_CALIBRATION_ERROR otherwise.
◆ sl_coulomb_counter_calibrate()
sl_coulomb_counter_calibration_status_t sl_coulomb_counter_calibrate | ( | void |
|
) |
Step function for calibration.
This function is to be called repeatedly either from a loop or from interrupt handler (when STATUS_G.CCC_ISDONE is set) to iterate over the calibration process.
- Warning
- During calibration, power consumption of the system must remain stable.
- Returns
- SL_COULOMB_COUNTER_CALIBRATION_DONE when calibration is complete; or SL_COULOMB_COUNTER_CALIBRATION_ERROR in case of error; or SL_COULOMB_COUNTER_CALIBRATION_PEAK_CURRENT_EM0 or SL_COULOMB_COUNTER_CALIBRATION_PEAK_CURRENT_EM2 if the peak current must be changed; or SL_COULOMB_COUNTER_CALIBRATION_IN_PROGRESS. In last three cases, sl_coulomb_counter_calibrate() must be called again to continue the calibration process.
Macro Definition Documentation
◆ SL_COULOMB_COUNTER_OUTPUT_EFP_VOA
#define SL_COULOMB_COUNTER_OUTPUT_EFP_VOA (( sl_coulomb_counter_output_mask_t )0x01) |
EFP's Output VOA.
◆ SL_COULOMB_COUNTER_OUTPUT_EFP_VOB_EM0
#define SL_COULOMB_COUNTER_OUTPUT_EFP_VOB_EM0 (( sl_coulomb_counter_output_mask_t )0x02) |
EFP's Output VOB in EM0 mode.
◆ SL_COULOMB_COUNTER_OUTPUT_EFP_VOB_EM2
#define SL_COULOMB_COUNTER_OUTPUT_EFP_VOB_EM2 (( sl_coulomb_counter_output_mask_t )0x04) |
EFP's Output VOB in EM2 mode.
◆ SL_COULOMB_COUNTER_OUTPUT_EFP_VOC
#define SL_COULOMB_COUNTER_OUTPUT_EFP_VOC (( sl_coulomb_counter_output_mask_t )0x08) |
EFP's Output VOC.
◆ SL_COULOMB_COUNTER_OUTPUT_ALL [1/2]
#define SL_COULOMB_COUNTER_OUTPUT_ALL (( sl_coulomb_counter_output_mask_t )0x0F) |
All Outputs.
◆ SL_COULOMB_COUNTER_OUTPUT_ALL [2/2]
#define SL_COULOMB_COUNTER_OUTPUT_ALL (( sl_coulomb_counter_output_mask_t )0x03) |
All Outputs.
◆ SL_COULOMB_COUNTER_OUTPUT_DCDC_EM0
#define SL_COULOMB_COUNTER_OUTPUT_DCDC_EM0 (( sl_coulomb_counter_output_mask_t )0x01) |
DCDC's Output VOB in EM0 mode.
◆ SL_COULOMB_COUNTER_OUTPUT_DCDC_EM2
#define SL_COULOMB_COUNTER_OUTPUT_DCDC_EM2 (( sl_coulomb_counter_output_mask_t )0x02) |
DCDC's Output VOB in EM2 mode.
◆ SL_COULOMB_COUNTER_INT_CALIBRATION_DONE
#define SL_COULOMB_COUNTER_INT_CALIBRATION_DONE 0x1 |
Calibration done interrupt flag.
◆ SL_COULOMB_COUNTER_INT_COUNTER_FULL
#define SL_COULOMB_COUNTER_INT_COUNTER_FULL 0x2 |
Counter full interrupt flag.
Typedef Documentation
◆ sl_coulomb_counter_output_mask_t
typedef uint32_t sl_coulomb_counter_output_mask_t |
Bitmask of outputs to operate on.
Enumeration Type Documentation
◆ sl_coulomb_counter_prescaler_t
Coulomb counter prescaler enum.
Each count in the counter results registers represents 2^(16 - 2 * prescaler).
◆ sl_coulomb_counter_threshold_t
Coulomb counter threshold for counter full interrupt enum.
Expressed in percentage, the interrupt full interrupt will be raised (if unmasked) when at least one of the counters reaches that threshold.
◆ sl_coulomb_counter_calibration_status_t
Coulomb counter calibration status enum.