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  {
112  return false;
113  }
114 
115  _twr_module_battery.measurement_active = true;
116 
117  twr_scheduler_plan_now(_twr_module_battery.task_id);
118 
119  return true;
120 }
121 
122 bool twr_module_battery_get_voltage(float *voltage)
123 {
124  *voltage = _twr_module_battery.voltage;
125 
126  return !isnan(_twr_module_battery.voltage);
127 }
128 
130 {
131  float voltage;
132 
133  if (twr_module_battery_get_voltage(&voltage))
134  {
135  // Calculate the percentage of charge
136  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
137  {
138  *percentage = _TWR_MODULE_BATTERY_MINI_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(voltage);
139  }
140  else
141  {
142  *percentage = _TWR_MODULE_BATTERY_STANDARD_VOLTAGE_ON_BATTERY_TO_PERCENTAGE(voltage);
143  }
144 
145  if (*percentage > 100)
146  {
147  *percentage = 100;
148  }
149  else if (*percentage < 0)
150  {
151  *percentage = 0;
152  }
153 
154  return true;
155  }
156 
157  return false;
158 }
159 
161 {
162  if (_twr_module_battery.state != TWR_MODULE_STATE_DETECT_PRESENT)
163  {
164  return true;
165  }
166 
167  return _twr_module_battery_present_test();
168 }
169 
170 static bool _twr_module_battery_present_test(void)
171 {
172  twr_system_pll_enable();
173 
175 
177 
179 
181 
183 
185 
186  __NOP();
187 
188  int value = twr_gpio_get_input(TWR_GPIO_P0);
189 
190  twr_system_pll_disable();
191 
192  return value != 0;
193 }
194 
195 static void _twr_module_battery_task(void *param)
196 {
197  (void) param;
198 
199 start:
200 
201  switch (_twr_module_battery.state)
202  {
203 
204  case TWR_MODULE_STATE_DETECT_PRESENT:
205  {
206  if (_twr_module_battery.update_interval == TWR_TICK_INFINITY)
207  {
208  _twr_module_battery.next_update_start = TWR_TICK_INFINITY;
209  }
210  else
211  {
212  _twr_module_battery.next_update_start = twr_tick_get() + _twr_module_battery.update_interval;
213  }
214 
215  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_UNKNOWN;
216 
217  if (!_twr_module_battery_present_test())
218  {
219  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
220 
221  if (_twr_module_battery.next_update_start == TWR_TICK_INFINITY)
222  {
223  _twr_module_battery.measurement_active = false;
224  }
225 
226  if (_twr_module_battery.event_handler != NULL)
227  {
228  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_ERROR, _twr_module_battery.event_param);
229  }
230 
231  return;
232  }
233 
234  _twr_module_battery_measurement(ENABLE);
235 
236  twr_adc_init();
238  twr_adc_set_event_handler(TWR_ADC_CHANNEL_A0, _twr_module_battery_adc_event_handler, NULL);
239 
241 
242  _twr_module_battery.state = TWR_MODULE_STATE_DETECT_FORMAT;
243 
244  break;
245  }
246  case TWR_MODULE_STATE_DETECT_FORMAT:
247  {
248  float voltage = _TWR_MODULE_BATTERY_STANDARD_CALIBRATION(_TWR_MODULE_BATTERY_STANDARD_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
249 
250  if ((voltage > 3.8) && (voltage < 7.0))
251  {
252  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_STANDARD;
253  _twr_module_battery.level_low_threshold = _TWR_MODULE_BATTERY_STANDATD_DEFAULT_LEVEL_LOW;
254  _twr_module_battery.level_critical_threshold = _TWR_MODULE_BATTERY_DEFAULT_DEFAULT_LEVEL_CRITICAL;
255  _twr_module_battery.valid_min = 3.8;
256  _twr_module_battery.valid_max = 7.0;
257  }
258  else
259  {
260  _twr_module_battery.format = TWR_MODULE_BATTERY_FORMAT_MINI;
261  _twr_module_battery.level_low_threshold = _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_LOW;
262  _twr_module_battery.level_critical_threshold = _TWR_MODULE_BATTERY_MINI_DEFAULT_LEVEL_CRITICAL;
263  _twr_module_battery.valid_min = 1.8;
264  _twr_module_battery.valid_max = 3.8;
265  }
266 
267  _twr_module_battery.state = TWR_MODULE_STATE_MEASURE;
268 
269  if (_twr_module_battery.measurement_active)
270  {
272  }
273  else
274  {
275  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
276  }
277 
278  break;
279  }
280  case TWR_MODULE_STATE_MEASURE:
281  {
282  if (_twr_module_battery.update_interval == TWR_TICK_INFINITY)
283  {
284  _twr_module_battery.next_update_start = TWR_TICK_INFINITY;
285  }
286  else
287  {
288  _twr_module_battery.next_update_start = twr_tick_get() + _twr_module_battery.update_interval;
289  }
290 
291  _twr_module_battery_measurement(ENABLE);
292 
293  twr_adc_set_event_handler(TWR_ADC_CHANNEL_A0, _twr_module_battery_adc_event_handler, NULL);
294 
296 
297  _twr_module_battery.state = TWR_MODULE_STATE_READ;
298 
299  break;
300  }
301  case TWR_MODULE_STATE_READ:
302  {
303  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
304  {
305  _twr_module_battery.voltage = _TWR_MODULE_BATTERY_MINI_CALIBRATION(_TWR_MODULE_BATTERY_MINI_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
306  }
307  else
308  {
309  _twr_module_battery.voltage = _TWR_MODULE_BATTERY_STANDARD_CALIBRATION(_TWR_MODULE_BATTERY_STANDARD_RESULT_TO_VOLTAGE(_twr_module_battery.adc_value));
310  }
311 
312  _twr_module_battery.measurement_active = false;
313 
314  if ((_twr_module_battery.voltage < _twr_module_battery.valid_min) || (_twr_module_battery.voltage > _twr_module_battery.valid_max))
315  {
316  _twr_module_battery.voltage = NAN;
317 
318  _twr_module_battery.state = TWR_MODULE_STATE_DETECT_PRESENT;
319 
320  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
321 
322  if (_twr_module_battery.event_handler != NULL)
323  {
324  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_ERROR, _twr_module_battery.event_param);
325  }
326 
327  return;
328  }
329 
330  _twr_module_battery.state = TWR_MODULE_STATE_UPDATE;
331 
332  goto start;
333  }
334  case TWR_MODULE_STATE_UPDATE:
335  {
336  if (_twr_module_battery.event_handler != NULL)
337  {
338  // Notify event based on calculated percentage
339  if (_twr_module_battery.voltage <= _twr_module_battery.level_critical_threshold)
340  {
341  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_LEVEL_CRITICAL, _twr_module_battery.event_param);
342  }
343  else if (_twr_module_battery.voltage <= _twr_module_battery.level_low_threshold)
344  {
345  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_LEVEL_LOW, _twr_module_battery.event_param);
346  }
347 
348  _twr_module_battery.event_handler(TWR_MODULE_BATTERY_EVENT_UPDATE, _twr_module_battery.event_param);
349  }
350 
351  _twr_module_battery.state = TWR_MODULE_STATE_MEASURE;
352 
353  twr_scheduler_plan_current_absolute(_twr_module_battery.next_update_start);
354 
355  break;
356  }
357  default:
358  {
359  return;
360  }
361  }
362 }
363 
364 static void _twr_module_battery_adc_event_handler(twr_adc_channel_t channel, twr_adc_event_t event, void *param)
365 {
366  (void) channel;
367  (void) param;
368 
369  if (event == TWR_ADC_EVENT_DONE)
370  {
371 
372  if (!twr_adc_async_get_voltage(TWR_ADC_CHANNEL_A0, &_twr_module_battery.adc_value))
373  {
374  _twr_module_battery.adc_value = NAN;
375  }
376 
377  _twr_module_battery_measurement(DISABLE);
378 
379  twr_scheduler_plan_now(_twr_module_battery.task_id);
380  }
381 }
382 
383 static void _twr_module_battery_measurement(int state)
384 {
385  if (_twr_module_battery.format == TWR_MODULE_BATTERY_FORMAT_MINI)
386  {
388  }
389  else
390  {
392  }
393 
394  if (state == ENABLE)
395  {
396  twr_timer_start();
397 
398  twr_timer_delay(100);
399 
400  twr_timer_stop();
401  }
402 }
403 
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
void twr_module_battery_init(void)
Initialize Battery Module.
void twr_module_battery_set_threshold_levels(float level_low_threshold, float level_critical_threshold)
Set voltage levels.
GPIO channel P0, A0, TXD0.
Definition: twr_gpio.h:15
void twr_module_battery_set_update_interval(twr_tick_t interval)
Set update interval.
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
GPIO channel operates as output.
Definition: twr_gpio.h:108
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
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
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
GPIO channel operates in analog mode.
Definition: twr_gpio.h:114
twr_adc_event_t
ADC event.
Definition: twr_adc.h:91
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
twr_module_battery_format_t twr_module_battery_get_format()
Get Battery Module format.
twr_module_battery_format_t
Battery Module format.
bool twr_module_battery_is_present(void)
Get Battery Module is pressent, can use without twr_module_battery_init.
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
twr_module_battery_event_t
Battery Module event.
ADC channel A0.
Definition: twr_adc.h:16
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_module_battery_get_voltage(float *voltage)
Get Battery Module voltage.
ADC event.
Definition: twr_adc.h:94
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_module_battery_set_event_handler(void(*event_handler)(twr_module_battery_event_t, void *), void *event_param)
Set callback function.
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
ADC 256x oversampling.
Definition: twr_adc.h:67
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_async_measure(twr_adc_channel_t channel)
Begins reading the ADC channel voltage in asynchronous mode.
Definition: twr_adc.c:234
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_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
GPIO channel P1, A1, RXD0.
Definition: twr_gpio.h:18
twr_adc_channel_t
ADC channel.
Definition: twr_adc.h:13
GPIO channel operates as input.
Definition: twr_gpio.h:105
bool twr_module_battery_get_charge_level(int *percentage)
Get Battery Module charge in percents.
GPIO channel has pull-down.
Definition: twr_gpio.h:96
bool twr_module_battery_measure(void)
Start mesurement.
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_timer_delay(uint16_t microseconds)
Relative delay.
Definition: twr_timer.c:59
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_adc_init()
Initialize ADC converter.
Definition: twr_adc.c:66
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28
Format is standard 4xAAA.