Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_module_infra_grid.c
1 #include <bc_module_infra_grid.h>
2 
3 // Reference registers, commands
4 // https://na.industrial.panasonic.com/sites/default/pidsa/files/downloads/files/grid-eye-high-performance-specifications.pdf
5 
6 // Adafruit Lib
7 // https://github.com/adafruit/Adafruit_AMG88xx/blob/master/Adafruit_AMG88xx.cpp
8 
9 // interrupt flags
10 // https://github.com/adafruit/Adafruit_AMG88xx/blob/master/examples/amg88xx_interrupt/amg88xx_interrupt.ino
11 
12 #define _BC_AMG88xx_ADDR 0x68 // in 7bit
13 
14 #define _BC_AMG88xx_PCLT 0x00
15 #define _BC_AMG88xx_RST 0x01
16 #define _BC_AMG88xx_FPSC 0x02
17 #define _BC_AMG88xx_INTC 0x03
18 #define _BC_AMG88xx_STAT 0x04
19 #define _BC_AMG88xx_SCLR 0x05
20 #define _BC_AMG88xx_AVE 0x07
21 #define _BC_AMG88xx_INTHL 0x08
22 #define _BC_AMG88xx_TTHL 0x0e
23 #define _BC_AMG88xx_TTHH 0x0f
24 #define _BC_AMG88xx_INT0 0x10
25 #define _BC_AMG88xx_AVG 0x1f
26 #define _BC_AMG88xx_T01L 0x80
27 
28 #define _BC_MODULE_INFRA_GRID_DELAY_RUN 50
29 #define _BC_MODULE_INFRA_GRID_DELAY_INITIALIZATION 50
30 #define _BC_MODULE_INFRA_GRID_DELAY_MEASUREMENT 5
31 
32 #define _BC_MODULE_INFRA_GRID_DELAY_MODE_CHANGE 50
33 #define _BC_MODULE_INFRA_GRID_DELAY_POWER_UP 50
34 #define _BC_MODULE_INFRA_GRID_DELAY_INITIAL_RESET 10
35 #define _BC_MODULE_INFRA_GRID_DELAY_FLAG_RESET 110
36 
37 #define _BC_MODULE_INFRA_GRID_PIN_POWER BC_TCA9534A_PIN_P7
38 
39 static void _bc_module_infra_grid_task_interval(void *param);
40 static void _bc_module_infra_grid_task_measure(void *param);
41 
43 {
44  memset(self, 0, sizeof(*self));
45 
46  self->_i2c_channel = BC_I2C_I2C0;
47  self->_i2c_address = _BC_AMG88xx_ADDR;
48  self->_cmd_sleep = true;
49 
50  self->_task_id_interval = bc_scheduler_register(_bc_module_infra_grid_task_interval, self, BC_TICK_INFINITY);
51  self->_task_id_measure = bc_scheduler_register(_bc_module_infra_grid_task_measure, self, _BC_MODULE_INFRA_GRID_DELAY_RUN);
52 
53  self->_tick_ready = _BC_MODULE_INFRA_GRID_DELAY_RUN;
54  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_100_KHZ);
55 }
56 
58 {
59  self->_event_handler = event_handler;
60  self->_event_param = event_param;
61 }
62 
64 {
65  self->_update_interval = interval;
66 
67  if (self->_update_interval >= 1000)
68  {
69  self->_cmd_sleep = true;
70  }
71 
72  if (self->_update_interval == BC_TICK_INFINITY)
73  {
74  bc_scheduler_plan_absolute(self->_task_id_interval, BC_TICK_INFINITY);
75  }
76  else
77  {
78  bc_scheduler_plan_relative(self->_task_id_interval, self->_update_interval);
80  }
81 }
82 
84 {
85  if (self->_measurement_active)
86  {
87  return false;
88  }
89 
90  self->_measurement_active = true;
91 
92  bc_scheduler_plan_absolute(self->_task_id_measure, self->_tick_ready);
93 
94  return true;
95 }
96 
98 {
99  (void) self;
100  int8_t temperature[2];
101 
102  bc_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_TTHL, (uint8_t *) &temperature[0]);
103  bc_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_TTHH, (uint8_t *) &temperature[1]);
104 
105  return (temperature[0] | temperature[1] << 8) * 0.0625f;
106 }
107 
109 {
110  bc_i2c_memory_transfer_t transfer;
111 
112  transfer.device_address = self->_i2c_address;
113  transfer.memory_address = _BC_AMG88xx_T01L;
114  transfer.buffer = self->_sensor_data;
115  transfer.length = 64 * 2;
116 
117  return bc_i2c_memory_read(self->_i2c_channel, &transfer);
118 }
119 
121 {
122  if (!self->_temperature_valid)
123  {
124  return false;
125  }
126 
127  for (int i = 0; i < 64 ;i++)
128  {
129  float temperature;
130  int16_t temporary_data = self->_sensor_data[i];
131 
132  if (temporary_data > 0x200)
133  {
134  temperature = (-temporary_data + 0xfff) * -0.25f;
135  }
136  else
137  {
138  temperature = temporary_data * 0.25f;
139  }
140 
141  values[i] = temperature;
142  }
143 
144  return true;
145 }
146 
147 static void _bc_module_infra_grid_task_interval(void *param)
148 {
149  bc_module_infra_grid_t *self = param;
151  bc_scheduler_plan_current_relative(self->_update_interval);
152 }
153 
154 static void _bc_module_infra_grid_task_measure(void *param)
155 {
156  bc_module_infra_grid_t *self = param;
157 
158  start:
159 
160  switch (self->_state)
161  {
162  case BC_MODULE_INFRA_GRID_STATE_ERROR:
163  {
164  self->_temperature_valid = false;
165 
166  self->_measurement_active = false;
167 
168  if (self->_event_handler != NULL)
169  {
170  self->_event_handler(self, BC_MODULE_INFRA_GRID_EVENT_ERROR, self->_event_param);
171  }
172 
173  self->_state = BC_MODULE_INFRA_GRID_STATE_INITIALIZE;
174 
175  return;
176  }
177  case BC_MODULE_INFRA_GRID_STATE_INITIALIZE:
178  {
179  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
180 
181  if (bc_tca9534a_init(&self->_tca9534, BC_I2C_I2C0 , 0x23))
182  {
183  self->_revision = BC_MODULE_INFRA_GRID_REVISION_R1_1;
184  }
185  else
186  {
187  self->_revision = BC_MODULE_INFRA_GRID_REVISION_R1_0;
188  }
189 
190  if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_1)
191  {
192  if (!bc_tca9534a_set_pin_direction(&self->_tca9534, _BC_MODULE_INFRA_GRID_PIN_POWER , BC_TCA9534A_PIN_DIRECTION_OUTPUT))
193  {
194  goto start;
195  }
196  if (!bc_tca9534a_write_pin(&self->_tca9534, _BC_MODULE_INFRA_GRID_PIN_POWER , 1))
197  {
198  goto start;
199  }
200  }
201 
202  // Update sleep flag
203  if (self->_enable_sleep != self->_cmd_sleep)
204  {
205  self->_enable_sleep = self->_cmd_sleep;
206  }
207 
208  if (self->_enable_sleep)
209  {
210  if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_0)
211  {
212  // Sleep mode
213  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_PCLT, 0x10))
214  {
215  goto start;
216  }
217  }
218  else if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_1)
219  {
220  // Revision 1.1 - Disconnect power to Infra Grid Module
221  if (!bc_tca9534a_write_pin(&self->_tca9534, _BC_MODULE_INFRA_GRID_PIN_POWER , 0))
222  {
223  goto start;
224  }
225  }
226  }
227  else
228  {
229  // Set 10 FPS
230  if (!bc_i2c_memory_write_8b (self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_FPSC, 0x00))
231  {
232  goto start;
233  }
234 
235  // Diff interrpt mode, INT output reactive
236  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_INTC, 0x00);
237  // Moving average output mode active
238  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x50);
239  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x45);
240  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x57);
241  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVE, 0x20);
242  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x00);
243  }
244 
245  self->_state = BC_MODULE_INFRA_GRID_STATE_MODE_CHANGE; //BC_MODULE_INFRA_GRID_STATE_MEASURE;
246 
247  self->_tick_ready = bc_tick_get() + _BC_MODULE_INFRA_GRID_DELAY_INITIALIZATION;
248 
249  if (self->_measurement_active)
250  {
251  bc_scheduler_plan_current_absolute(self->_tick_ready);
252  }
253 
254  return;
255  }
256  case BC_MODULE_INFRA_GRID_STATE_MODE_CHANGE:
257  {
258  // Skip wakeup commands in case of fast reading
259  if (!self->_enable_sleep)
260  {
261  self->_state = BC_MODULE_INFRA_GRID_STATE_READ;
262  goto start;
263  }
264 
265  if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_0)
266  {
267  // The module is already powered up
268  self->_state = BC_MODULE_INFRA_GRID_STATE_POWER_UP;
269  goto start;
270  }
271  else if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_1)
272  {
273  // Revision 1.1 - Enable power for Infra Grid Module
274  if (!bc_tca9534a_write_pin(&self->_tca9534, _BC_MODULE_INFRA_GRID_PIN_POWER , 1))
275  {
276  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
277  goto start;
278  }
279  self->_state = BC_MODULE_INFRA_GRID_STATE_POWER_UP;
280  bc_scheduler_plan_current_from_now(_BC_MODULE_INFRA_GRID_DELAY_POWER_UP);
281  }
282 
283  return;
284  }
285  case BC_MODULE_INFRA_GRID_STATE_POWER_UP:
286  {
287  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
288 
289  // Normal Mode
290  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_PCLT, 0x00))
291  {
292  goto start;
293  }
294  self->_state = BC_MODULE_INFRA_GRID_STATE_INITIAL_RESET;
295  bc_scheduler_plan_current_from_now(_BC_MODULE_INFRA_GRID_DELAY_MODE_CHANGE);
296  return;
297  }
298  case BC_MODULE_INFRA_GRID_STATE_INITIAL_RESET:
299  {
300  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
301 
302  // Write initial reset
303  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_RST, 0x3f))
304  {
305  goto start;
306  }
307 
308  self->_state = BC_MODULE_INFRA_GRID_STATE_FLAG_RESET;
309  bc_scheduler_plan_current_from_now(_BC_MODULE_INFRA_GRID_DELAY_INITIAL_RESET);
310  return;
311  }
312  case BC_MODULE_INFRA_GRID_STATE_FLAG_RESET:
313  {
314  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
315 
316  // Write flag reset
317  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_RST, 0x30))
318  {
319  goto start;
320  }
321 
322  self->_state = BC_MODULE_INFRA_GRID_STATE_MEASURE;
323  bc_scheduler_plan_current_from_now(_BC_MODULE_INFRA_GRID_DELAY_FLAG_RESET);
324  return;
325  }
326  case BC_MODULE_INFRA_GRID_STATE_MEASURE:
327  {
328  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
329 
330  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_FPSC, 0x01))
331  {
332  goto start;
333  }
334 
335  // Diff interrpt mode, INT output reactive
336  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_INTC, 0x00);
337  // Moving average output mode active
338  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x50);
339  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x45);
340  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x57);
341  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVE, 0x20);
342  bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_AVG, 0x00);
343 
344  self->_state = BC_MODULE_INFRA_GRID_STATE_READ;
345 
346  bc_scheduler_plan_current_from_now(_BC_MODULE_INFRA_GRID_DELAY_MEASUREMENT);
347 
348  return;
349  }
350  case BC_MODULE_INFRA_GRID_STATE_READ:
351  {
352  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
353 
354  bc_i2c_memory_transfer_t transfer;
355  transfer.device_address = self->_i2c_address;
356  transfer.memory_address = _BC_AMG88xx_T01L;
357  transfer.buffer = self->_sensor_data;
358  transfer.length = 64 * 2;
359 
360  if (!bc_i2c_memory_read(self->_i2c_channel, &transfer))
361  {
362  goto start;
363  }
364 
365  // Enable sleep mode
366  if (self->_enable_sleep)
367  {
368  // Sleep Mode
369  if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_0)
370  {
371  // Sleep mode
372  if (!bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _BC_AMG88xx_PCLT, 0x10))
373  {
374  goto start;
375  }
376  }
377  else if (self->_revision == BC_MODULE_INFRA_GRID_REVISION_R1_1)
378  {
379  // Revision 1.1 has power disconnect
380  bc_tca9534a_write_pin(&self->_tca9534, _BC_MODULE_INFRA_GRID_PIN_POWER , 0);
381  }
382  }
383 
384  self->_temperature_valid = true;
385  self->_state = BC_MODULE_INFRA_GRID_STATE_UPDATE;
386 
387  goto start;
388  }
389  case BC_MODULE_INFRA_GRID_STATE_UPDATE:
390  {
391  self->_measurement_active = false;
392 
393  if (self->_event_handler != NULL)
394  {
395  self->_event_handler(self, BC_MODULE_INFRA_GRID_EVENT_UPDATE, self->_event_param);
396  }
397 
398  // Update sleep flag
399  if (self->_enable_sleep != self->_cmd_sleep)
400  {
401  self->_enable_sleep = self->_cmd_sleep;
402  }
403 
404  self->_state = BC_MODULE_INFRA_GRID_STATE_MODE_CHANGE;
405  return;
406  }
407  default:
408  {
409  self->_state = BC_MODULE_INFRA_GRID_STATE_ERROR;
410  goto start;
411  }
412  }
413 }
414 
416 {
417  return self->_revision;
418 }
void * buffer
Pointer to buffer which is being written or read.
Definition: bc_i2c.h:66
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
void bc_module_infra_grid_init(bc_module_infra_grid_t *self)
Initialize Infra Grid Module.
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
bc_module_infra_grid_revision_t
Infragrid Module Revision.
bc_module_infra_grid_event_t
Callback events.
void bc_module_infra_grid_set_event_handler(bc_module_infra_grid_t *self, void(*event_handler)(bc_module_infra_grid_t *, bc_module_infra_grid_event_t, void *), void *event_param)
Set callback function.
bool bc_tca9534a_write_pin(bc_tca9534a_t *self, bc_tca9534a_pin_t pin, int state)
Write pin state.
Definition: bc_tca9534a.c:61
I2C channel I2C0.
Definition: bc_i2c.h:18
bool bc_i2c_memory_read(bc_i2c_channel_t channel, const bc_i2c_memory_transfer_t *transfer)
Memory read from I2C channel.
Definition: bc_i2c.c:365
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
bool bc_i2c_memory_read_8b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t *data)
Memory read 1 byte from I2C channel.
Definition: bc_i2c.c:431
void bc_scheduler_plan_current_absolute(bc_tick_t tick)
Schedule current task to absolute tick.
Definition: bc_scheduler.c:144
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
I2C communication speed is 100 kHz.
Definition: bc_i2c.h:33
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with BC_I2C_MEMORY_ADDRESS_16_...
Definition: bc_i2c.h:63
bool bc_module_infra_grid_read_values(bc_module_infra_grid_t *self)
Read measured data from sensor to the buffer.
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:60
bool bc_tca9534a_init(bc_tca9534a_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize TCA9534A.
Definition: bc_tca9534a.c:8
void bc_module_infra_grid_set_update_interval(bc_module_infra_grid_t *self, bc_tick_t interval)
Set measurement interval.
I2C memory transfer parameters.
Definition: bc_i2c.h:57
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
float bc_module_infra_grid_read_thermistor(bc_module_infra_grid_t *self)
Read and return thermistor temperature sensor value.
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bc_module_infra_grid_revision_t bc_module_infra_grid_get_revision(bc_module_infra_grid_t *self)
Get module revision.
size_t length
Length of buffer which is being written or read.
Definition: bc_i2c.h:69
struct bc_module_infra_grid_t bc_module_infra_grid_t
Infra Grid Module instance.
bool bc_module_infra_grid_measure(bc_module_infra_grid_t *self)
Start measurement manually.
bool bc_tca9534a_set_pin_direction(bc_tca9534a_t *self, bc_tca9534a_pin_t pin, bc_tca9534a_pin_direction_t direction)
Set pin direction.
Definition: bc_tca9534a.c:113
bool bc_module_infra_grid_get_temperatures_celsius(bc_module_infra_grid_t *self, float *values)
Get measured temperature in degrees of Celsius as a array of float numbers.
bool bc_i2c_memory_write_8b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: bc_i2c.c:402