Firmware SDK
twr_module_battery.c
1 #include <stm32l0xx.h>
2 #include <twr_module_battery.h>
3 #include <twr_gpio.h>
4 #include <twr_adc.h>
5 #include <twr_scheduler.h>
6 #include <twr_timer.h>
7 
8 #define _TWR_MODULE_BATTERY_CELL_VOLTAGE 1.5f
9 
10 #define _TWR_MODULE_BATTERY_STANDATD_DEFAULT_LEVEL_LOW (1.2 * 4)
11 #define _TWR_MODULE_BATTERY_DEFAULT_DEFAULT_LEVEL_CRITICAL (1.0 * 4)
12 
13 #define _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_LOW (1.2 * 2)
14 #define _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_CRITICAL (1.0 * 2)
15 
16 #define _TWR_MODULE_BATTERY_MINI_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(__VOLTAGE__) ((100. * ((__VOLTAGE__) - _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_CRITICAL)) / ((_TWR_MODULE_BATTERY_CELL_VOLTAGE * 2) - _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_CRITICAL))
17 #define _TWR_MODULE_BATTERY_STANDARD_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(__VOLTAGE__) ((100. * ((__VOLTAGE__) - _TWR_MODULE_BATTERY_DEFAULT_DEFAULT_LEVEL_CRITICAL)) / ((_TWR_MODULE_BATTERY_CELL_VOLTAGE * 4) - _TWR_MODULE_BATTERY_DEFAULT_DEFAULT_LEVEL_CRITICAL))
18 
19 #define _TWR_MODULE_BATTERY_MINI_CALIBRATION(__VOLTAGE__) ((__VOLTAGE__) * 1.095f + 0.0069f)
20 #define _TWR_MODULE_BATTERY_STANDARD_CALIBRATION(__VOLTAGE__) ((__VOLTAGE__) * 1.1068f + 0.0212f)
21 
22 #define _TWR_MODULE_BATTERY_MINI_RESULT_TO_VOLTAGE(__RESULT__) ((__RESULT__) * (1 / (5.0 / (5.0 + 10.0))))
23 #define _TWR_MODULE_BATTERY_STANDARD_RESULT_TO_VOLTAGE(__RESULT__) ((__RESULT__) * (1 / 0.13))
24 
25 typedef enum
26 {
27  TWR_MODULE_STATE_DETECT_PRESENT = 0,
28  TWR_MODULE_STATE_DETECT_FORMAT = 1,
29  TWR_MODULE_STATE_MEASURE = 2,
30  TWR_MODULE_STATE_READ = 3,
31  TWR_MODULE_STATE_UPDATE = 4
32 
33 } _twr_module_battery_state_t;
34 
35 static struct
36 {
37  float voltage;
38  float valid_min;
39  float valid_max;
41  void (*event_handler)(twr_module_battery_event_t, void *);
42  void *event_param;
43  bool measurement_active;
44  float level_low_threshold;
45  float level_critical_threshold;
46  twr_tick_t update_interval;
47  twr_tick_t next_update_start;
49  float adc_value;
50  _twr_module_battery_state_t state;
51 
52 } _twr_module_battery;
53 
54 static bool _twr_module_battery_present_test(void);
55 static void _twr_module_battery_task(void *param);
56 static void _twr_module_battery_adc_event_handler(twr_adc_channel_t channel, twr_adc_event_t event, void *param);
57 static void _twr_module_battery_measurement(int state);
58 
60 {
61  memset(&_twr_module_battery, 0, sizeof(_twr_module_battery));
62 
63  _twr_module_battery.voltage = NAN;
64  _twr_module_battery.adc_value = NAN;
65  _twr_module_battery.update_interval = TWR_TICK_INFINITY;
66  _twr_module_battery.task_id = twr_scheduler_register(_twr_module_battery_task, NULL, TWR_TICK_INFINITY);
67 
70 
72 }
73 
74 void twr_module_battery_set_event_handler(void (*event_handler)(twr_module_battery_event_t, void *), void *event_param)
75 {
76  _twr_module_battery.event_handler = event_handler;
77  _twr_module_battery.event_param = event_param;
78 }
79 
81 {
82  _twr_module_battery.update_interval = interval;
83 
84  if (_twr_module_battery.update_interval == TWR_TICK_INFINITY)
85  {
86  if (!_twr_module_battery.measurement_active)
87  {
88  twr_scheduler_plan_absolute(_twr_module_battery.task_id, TWR_TICK_INFINITY);
89  }
90  }
91  else
92  {
94  }
95 }
96 
97 void twr_module_battery_set_threshold_levels(float level_low_threshold, float level_critical_threshold)
98 {
99  _twr_module_battery.level_low_threshold = level_low_threshold;
100  _twr_module_battery.level_critical_threshold = level_critical_threshold;
101 }
102 
104 {
105  return _twr_module_battery.format;
106 }
107 
109 {
110  if ((_twr_module_battery.measurement_active) ||
111  (_twr_module_battery.state == TWR_MODULE_STATE_DETECT_FORMAT) ||
112  (_twr_module_battery.state == TWR_MODULE_STATE_READ))
113  {
114  return false;
115  }
116 
117  _twr_module_battery.measurement_active = true;
118 
119  twr_scheduler_plan_now(_twr_module_battery.task_id);
120 
121  return true;
122 }
123 
124 bool twr_module_battery_get_voltage(float *voltage)
125 {
126  *voltage = _twr_module_battery.voltage;
127 
128  return !isnan(_twr_module_battery.voltage);
129 }
130 
132 {
133  float voltage;
134 
135  if (twr_module_battery_get_voltage(&voltage))
136  {
137  // Calculate the percentage of charge
138  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
139  {
140  *percentage = _TWR_MODULE_BATTERY_MINI_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(voltage);
141  }
142  else
143  {
144  *percentage = _TWR_MODULE_BATTERY_STANDARD_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(voltage);
145  }
146 
147  if (*percentage > 100)
148  {
149  *percentage = 100;
150  }
151  else if (*percentage < 0)
152  {
153  *percentage = 0;
154  }
155 
156  return true;
157  }
158 
159  return false;
160 }
161 
163 {
164  if (_twr_module_battery.state != TWR_MODULE_STATE_DETECT_PRESENT)
165  {
166  return true;
167  }
168 
169  return _twr_module_battery_present_test();
170 }
171 
172 static bool _twr_module_battery_present_test(void)
173 {
174  twr_system_pll_enable();
175 
177 
179 
181 
183 
185 
187 
188  __NOP();
189 
190  int value = twr_gpio_get_input(TWR_GPIO_P0);
191 
192  twr_system_pll_disable();
193 
194  return value != 0;
195 }
196 
197 static void _twr_module_battery_task(void *param)
198 {
199  (void) param;
200 
201 start:
202 
203  switch (_twr_module_battery.state)
204  {
205 
206  case TWR_MODULE_STATE_DETECT_PRESENT:
207  {
208  if (_twr_module_battery.update_interval == TWR_TICK_INFINITY)
209  {
210  _twr_module_battery.next_update_start = TWR_TICK_INFINITY;
211  }
212  else
213  {
214  _twr_module_battery.next_update_start = twr_tick_get() + _twr_module_battery.update_interval;
215  }
216 
217  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_UNKNOWN;
218 
219  if (!_twr_module_battery_present_test())
220  {
221  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
222 
223  if (_twr_module_battery.next_update_start == TWR_TICK_INFINITY)
224  {
225  _twr_module_battery.measurement_active = false;
226  }
227 
228  if (_twr_module_battery.event_handler != NULL)
229  {
230  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_ERROR, _twr_module_battery.event_param);
231  }
232 
233  return;
234  }
235 
236  _twr_module_battery_measurement(ENABLE);
237 
238  twr_adc_init();
240  twr_adc_set_event_handler(TWR_ADC_CHANNEL_A0, _twr_module_battery_adc_event_handler, NULL);
241 
243 
244  _twr_module_battery.state = TWR_MODULE_STATE_DETECT_FORMAT;
245 
246  break;
247  }
248  case TWR_MODULE_STATE_DETECT_FORMAT:
249  {
250  float voltage = _TWR_MODULE_BATTERY_STANDARD_CALIBRATION(_TWR_MODULE_BATTERY_STANDARD_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
251 
252  if ((voltage > 3.8) && (voltage < 7.0))
253  {
254  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_STANDARD;
255  _twr_module_battery.level_low_threshold = _TWR_MODULE_BATTERY_STANDATD_DEFAULT_LEVEL_LOW;
256  _twr_module_battery.level_critical_threshold = _TWR_MODULE_BATTERY_DEFAULT_DEFAULT_LEVEL_CRITICAL;
257  _twr_module_battery.valid_min = 3.8;
258  _twr_module_battery.valid_max = 7.0;
259  }
260  else
261  {
262  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_MINI;
263  _twr_module_battery.level_low_threshold = _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_LOW;
264  _twr_module_battery.level_critical_threshold = _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_CRITICAL;
265  _twr_module_battery.valid_min = 1.8;
266  _twr_module_battery.valid_max = 3.8;
267  }
268 
269  _twr_module_battery.state = TWR_MODULE_STATE_MEASURE;
270 
271  if (_twr_module_battery.measurement_active)
272  {
274  }
275  else
276  {
277  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
278  }
279 
280  break;
281  }
282  case TWR_MODULE_STATE_MEASURE:
283  {
284  _twr_module_battery.measurement_active = true;
285 
286  if (_twr_module_battery.update_interval == TWR_TICK_INFINITY)
287  {
288  _twr_module_battery.next_update_start = TWR_TICK_INFINITY;
289  }
290  else
291  {
292  _twr_module_battery.next_update_start = twr_tick_get() + _twr_module_battery.update_interval;
293  }
294 
295  _twr_module_battery_measurement(ENABLE);
296 
297  twr_adc_set_event_handler(TWR_ADC_CHANNEL_A0, _twr_module_battery_adc_event_handler, NULL);
298 
300 
301  _twr_module_battery.state = TWR_MODULE_STATE_READ;
302 
303  break;
304  }
305  case TWR_MODULE_STATE_READ:
306  {
307  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
308  {
309  _twr_module_battery.voltage = _TWR_MODULE_BATTERY_MINI_CALIBRATION(_TWR_MODULE_BATTERY_MINI_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
310  }
311  else
312  {
313  _twr_module_battery.voltage = _TWR_MODULE_BATTERY_STANDARD_CALIBRATION(_TWR_MODULE_BATTERY_STANDARD_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
314  }
315 
316  _twr_module_battery.measurement_active = false;
317 
318  if ((_twr_module_battery.voltage < _twr_module_battery.valid_min) || (_twr_module_battery.voltage > _twr_module_battery.valid_max))
319  {
320  _twr_module_battery.voltage = NAN;
321 
322  _twr_module_battery.state = TWR_MODULE_STATE_DETECT_PRESENT;
323 
324  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
325 
326  if (_twr_module_battery.event_handler != NULL)
327  {
328  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_ERROR, _twr_module_battery.event_param);
329  }
330 
331  return;
332  }
333 
334  _twr_module_battery.state = TWR_MODULE_STATE_UPDATE;
335 
336  goto start;
337  }
338  case TWR_MODULE_STATE_UPDATE:
339  {
340  if (_twr_module_battery.event_handler != NULL)
341  {
342  // Notify event based on calculated percentage
343  if (_twr_module_battery.voltage <= _twr_module_battery.level_critical_threshold)
344  {
345  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_LEVEL_CRITICAL, _twr_module_battery.event_param);
346  }
347  else if (_twr_module_battery.voltage <= _twr_module_battery.level_low_threshold)
348  {
349  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_LEVEL_LOW, _twr_module_battery.event_param);
350  }
351 
352  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_UPDATE, _twr_module_battery.event_param);
353  }
354 
355  _twr_module_battery.state = TWR_MODULE_STATE_MEASURE;
356 
357  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
358 
359  break;
360  }
361  default:
362  {
363  return;
364  }
365  }
366 }
367 
368 static void _twr_module_battery_adc_event_handler(twr_adc_channel_t channel, twr_adc_event_t event, void *param)
369 {
370  (void) channel;
371  (void) param;
372 
373  if (event == TWR_ADC_EVENT_DONE)
374  {
375 
376  if (!twr_adc_async_get_voltage(TWR_ADC_CHANNEL_A0, &_twr_module_battery.adc_value))
377  {
378  _twr_module_battery.adc_value = NAN;
379  }
380 
381  _twr_module_battery_measurement(DISABLE);
382 
383  twr_scheduler_plan_now(_twr_module_battery.task_id);
384  }
385 }
386 
387 static void _twr_module_battery_measurement(int state)
388 {
389  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
390  {
392  }
393  else
394  {
396  }
397 
398  if (state == ENABLE)
399  {
400  twr_timer_start();
401 
402  twr_timer_delay(100);
403 
404  twr_timer_stop();
405  }
406 }
407 
bool twr_adc_async_measure(twr_adc_channel_t channel)
Begins reading the ADC channel voltage in asynchronous mode.
Definition: twr_adc.c:234
void twr_adc_oversampling_set(twr_adc_channel_t channel, twr_adc_oversampling_t oversampling)
Set ADC oversampling for specific channel.
Definition: twr_adc.c:101
bool twr_adc_set_event_handler(twr_adc_channel_t channel, void(*event_handler)(twr_adc_channel_t, twr_adc_event_t, void *), void *event_param)
Set callback function.
Definition: twr_adc.c:218
bool twr_adc_async_get_voltage(twr_adc_channel_t channel, float *result)
Get asynchronous measurement result in volts.
Definition: twr_adc.c:280
twr_adc_event_t
ADC event.
Definition: twr_adc.h:92
twr_adc_channel_t
ADC channel.
Definition: twr_adc.h:14
void twr_adc_init()
Initialize ADC converter.
Definition: twr_adc.c:66
@ TWR_ADC_OVERSAMPLING_256
ADC 256x oversampling.
Definition: twr_adc.h:67
@ TWR_ADC_EVENT_DONE
ADC event.
Definition: twr_adc.h:94
@ TWR_ADC_CHANNEL_A0
ADC channel A0.
Definition: twr_adc.h:16
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_INPUT
GPIO channel operates as input.
Definition: twr_gpio.h:105
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
Definition: twr_gpio.h:108
@ TWR_GPIO_MODE_ANALOG
GPIO channel operates in analog mode.
Definition: twr_gpio.h:114
@ TWR_GPIO_P1
GPIO channel P1, A1, RXD0.
Definition: twr_gpio.h:18
@ TWR_GPIO_P0
GPIO channel P0, A0, TXD0.
Definition: twr_gpio.h:15
@ TWR_GPIO_PULL_DOWN
GPIO channel has pull-down.
Definition: twr_gpio.h:96
void twr_module_battery_set_event_handler(void(*event_handler)(twr_module_battery_event_t, void *), void *event_param)
Set callback function.
void twr_module_battery_init(void)
Initialize Battery Module.
bool twr_module_battery_is_present(void)
Get Battery Module is pressent, can use without twr_module_battery_init.
twr_module_battery_format_t twr_module_battery_get_format()
Get Battery Module format.
bool twr_module_battery_get_voltage(float *voltage)
Get Battery Module voltage.
twr_module_battery_event_t
Battery Module event.
void twr_module_battery_set_update_interval(twr_tick_t interval)
Set update interval.
twr_module_battery_format_t
Battery Module format.
void twr_module_battery_set_threshold_levels(float level_low_threshold, float level_critical_threshold)
Set voltage levels.
bool twr_module_battery_get_charge_level(int *percentage)
Get Battery Module charge in percents.
bool twr_module_battery_measure(void)
Start mesurement.
@ TWR_MODULE_BATTERY_EVENT_LEVEL_LOW
Event low level.
@ TWR_MODULE_BATTERY_EVENT_ERROR
Event error.
@ TWR_MODULE_BATTERY_EVENT_UPDATE
Event update.
@ TWR_MODULE_BATTERY_EVENT_LEVEL_CRITICAL
Event critical level.
@ TWR_MODULE_BATTERY_FORMAT_UNKNOWN
Format is unknown.
@ TWR_MODULE_BATTERY_FORMAT_STANDARD
Format is standard 4xAAA.
@ TWR_MODULE_BATTERY_FORMAT_MINI
Format is mini 2xAAA.
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_timer_init(void)
Initialize timer.
Definition: twr_timer.c:23
void twr_timer_delay(uint16_t microseconds)
Relative delay.
Definition: twr_timer.c:59
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28