PsiSwarm Library  0.8
i2c_setup.cpp
1 /* University of York Robotics Laboratory PsiSwarm Library: I2C Setup Source File
2  *
3  * Copyright 2016 University of York
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
7  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS
8  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9  * See the License for the specific language governing permissions and limitations under the License.
10  *
11  * File: i2c_setup.cpp
12  *
13  * (C) Dept. Electronics & Computer Science, University of York
14  * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis
15  *
16  * PsiSwarm Library Version: 0.8
17  *
18  * October 2016
19  *
20  *
21  */
22 
23 #include "psiswarm.h"
24 
25 char gpio_byte0;
26 char gpio_byte1;
27 char user_id_set = 0;
28 char wheel_enc_set = 0;
29 char switch_set = 0;
30 
31 char emitter_byte = 0x00;
32 
33 Timeout update_timeout;
34 
35 char test;
36 
37 char Setup::get_dc_status()
38 {
39  IF_read_aux_ic_data();
40  return status_dc_in;
41 }
42 
43 void Setup::IF_set_IR_emitter_output(char emitter, char state)
44 {
45  if(emitter <3) {
46  if(state == 0) {
47  char shift = 1 << emitter;
48  emitter_byte &= (0xFF - shift);
49  }
50  if(state == 1) {
51  char shift = 1 << emitter;
52  emitter_byte |= shift;
53  }
54  char data[2];
55  data [0] = 0x0A; //Write to OLAT register
56  data [1] = emitter_byte; //GP0-3 are outputs on aux expansion IC
57  //pc.printf("%c\n", emitter_byte);
58  primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
59  }
60 }
61 
62 void Setup::IF_set_base_LED(char state)
63 {
64  if(state == 0) {
65  emitter_byte &= 0xF7;
66  } else emitter_byte |= 0x08;
67  char data[2];
68  data [0] = 0x0A; //Write to OLAT register
69  data [1] = emitter_byte; //GP0-3 are outputs on aux expansion IC
70  primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
71 
72 }
73 
74 unsigned short Setup::IF_read_IR_adc_value(char adc, char index)
75 {
76  char address = ADC1_ADDRESS;
77  if(adc == 2) address=ADC2_ADDRESS;
78  // Returns the raw sensor value for the IR sensor defined by index (range 0-7).
79  short value = 0;
80  // Read a single value from the ADC
81  if(index<8) {
82  char apb[1];
83  char data[2];
84  switch(index) {
85  case 0:
86  apb[0]=0x80;
87  break;
88  case 1:
89  apb[0]=0x90;
90  break;
91  case 2:
92  apb[0]=0xA0;
93  break;
94  case 3:
95  apb[0]=0xB0;
96  break;
97  case 4:
98  apb[0]=0xC0;
99  break;
100  case 5:
101  apb[0]=0xD0;
102  break;
103  case 6:
104  apb[0]=0xE0;
105  break;
106  case 7:
107  apb[0]=0xF0;
108  break;
109  }
110  primary_i2c.write(address,apb,1,false);
111  primary_i2c.read(address,data,2,false);
112  value=((data[0] % 16)<<8)+data[1];
113  if(value > 4096) value=4096;
114  value=4096-value;
115  }
116  return value;
117 }
118 
119 char Setup::IF_setup_led_expansion_ic(void)
120 {
121  //LED expansion IC is PCA9555
122  //Address is 0100 001x (0x42) {defined by LED_IC_ADDRESS}
123  //All 16 entries are outputs as they drive LEDs; the relevant registers are 2&3 (output port registers) and 6&7 (config. registers: a 0=output)
124  //Message structure: {Address-RW}{Command}{Port 0}{Port 1}
125  //Command bytes: 00000010 (0x02) = Write to output port
126  //Command bytes: 00000110 (0x06) = Write to config registers
127  //Note that for the LEDs, 0 = on, 1 = off
128  //Port 0 = LED 1:4 Red:Green
129  //Port 1 = LED 5:8 Red:Green
130  char data [3];
131  data [0] = 0x06; //Write config registers
132  data [1] = 0x00; //All 8 pins in port 0 are outputs (0)
133  data [2] = 0x00; //All 8 pins in port 1 are outputs (0)
134  primary_i2c.write(LED_IC_ADDRESS,data,3,false);
135 
136  //Turn all LEDs on
137  data [0] = 0x02; //Write to output port
138  data [1] = 0x00; //Enable LED1-4 (both colours)
139  data [2] = 0x00; //Enable LED5-8 (both colours)
140  primary_i2c.write(LED_IC_ADDRESS,data,3,false);
141 
142  wait(0.05);
143  //Turn all LEDs off
144  data [0] = 0x02; //Write to output port
145  data [1] = 0xFF; //Enable LED1-4 (both colours)
146  data [2] = 0xFF; //Enable LED5-8 (both colours)
147  return primary_i2c.write(LED_IC_ADDRESS,data,3,false);
148 }
149 
150 //Returns 0 if successful, 1 if test mode button pressed
151 void Setup::IF_setup_gpio_expansion_ic(void)
152 {
153  //Main GPIO expansion IC is PCA9555
154  //Address is 0100 000x (0x40) {defined by GPIO_IC_ADDRESS}
155  //All 16 entries are inputs; the relevant registers are 0&1 (input port registers), 4&5 (polarity inv. registers) and 6&7 (config. registers: a 0=output)
156  //Message structure: {Address-RW}{Command}{Port 0}{Port 1}
157  //Command bytes: 00000010 (0x02) = Write to output port
158  //Command bytes: 00000110 (0x06) = Write to config registers
159  //Note that for the LEDs, 0 = on, 1 = off
160  //Port 0 = PGDL; PGDR; PGDIR; UP; DOWN; LEFT; RIGHT; CENTER
161  //Port 1 = ENC_LA; ENC_LB; ENC_RA; ENC_RB; ID0; ID1; ID2; ID3
162  char data [3];
163  char okay = 1;
164  data [0] = 0x06; //Write config registers
165  data [1] = 0xFF; //All 8 pins in port 0 are inputs (1)
166  data [2] = 0xFF; //All 8 pins in port 1 are inputs (1)
167  if(primary_i2c.write(GPIO_IC_ADDRESS,data,3,false) != 0) {
168  system_warnings += 2;
169  okay = 0;
170  psi.debug("- WARNING: No I2C acknowledge for main GPIO IC\n");
171  if(HALT_ON_GPIO_ERROR){
172  psi.debug("- PROGRAM HALTED. Check that robot is switched on!\n");
173  while(1){
174  mbed_led1=1;
175  mbed_led2=1;
176  mbed_led3=0;
177  mbed_led4=0;
178  wait(0.25);
179  mbed_led1=0;
180  mbed_led2=0;
181  mbed_led3=1;
182  mbed_led4=1;
183  wait(0.25);
184  }
185  }
186  }
187  //Set all inputs to polarity-inverted (so a logic low = 1)
188  data [0] = 0x04; //Write to polarity inversion ports
189  data [1] = 0xF8; //Invert polarity of all switch input bits in input port 0 [but not power-good inputs]
190  data [2] = 0xFF; //Invert polarity of all bits in input port 1
191  primary_i2c.write(GPIO_IC_ADDRESS,data,3,false);
192 
193  wait(0.01);
194 
195  //Read data
196  char read_data[2];
197  char command[1]; //Command to read from input port 0
198  command[0]=0;
199  primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
200  primary_i2c.read(GPIO_IC_ADDRESS,read_data,2,false);
201  gpio_byte0 = read_data[0];
202  //char ret_val = (gpio_byte0 & 0xF8) >> 3; //Returns a >0 value if a button is being pushed
203  gpio_byte1 = read_data[1];
204  if(okay && testing_voltage_regulators_flag)psi.debug("- Checking 3.3V voltage regulators\n");
205  IF_parse_gpio_byte0(gpio_byte0);
206  IF_parse_gpio_byte1(gpio_byte1);
207  testing_voltage_regulators_flag = 0;
208  //Setup interrupt handler for GPIO interrupts
209  gpio_interrupt.mode(PullUp);
210  gpio_interrupt.rise(this,&Setup::IF_handle_gpio_interrupt);
211  //pc.printf("%c %c",gpio_byte0,gpio_byte1);
212 
213  //Secondary GPIO expansion IC is MCP23009
214  //Address is 0100 111 (0x4E) {defined by AUX_IC_ADDRESS}
215  //GP0,1,2,3 are outputs for driving infrared emitters and the base LED
216  //IODIR register wants to be 0xF0 (1=input, 0=output)
217  data [0] = 0x00; //Write to IODIR register
218  data [1] = 0xF0; //Set GP0-3 as outputs
219  primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
220 
221  if(primary_i2c.write(AUX_IC_ADDRESS,data,2,false) != 0) {
222  system_warnings += 4;
223  psi.debug("- WARNING: No I2C acknowledge for aux GPIO IC\n");
224  }
225  data [0] = 0x06; //Write to GPPU register
226  data [1] = 0x3F; //Set GP0-3 as active pull-up outputs and P4,P5 as pull-up inputs
227  primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
228 
229  //My interrupt is not so reliable: poll with a 50ms timeout in case interrupts aren't handled
230  update_timeout.attach_us(this,&Setup::IF_update_gpio_inputs,50000);
231  //return ret_val;
232 }
233 
234 void Setup::IF_read_aux_ic_data()
235 {
236  //Read the values of the input pins on the auxilliary GPIO expander
237  char write_data [1];
238  char read_data [1];
239  write_data[0] = 0x09;
240  primary_i2c.write(AUX_IC_ADDRESS,write_data,1,false);
241  primary_i2c.read(AUX_IC_ADDRESS,read_data,1,false);
242  char old_charging_state = status_dc_in;
243  status_dc_in = 1-((read_data[0] & 0x10) >> 4);
244  if(status_dc_in!=old_charging_state){
245  if(status_dc_in == 0)psi.debug("No DC input\n");
246  else psi.debug("DC input to charge pins\n");
247  }
248  //pc.printf("Aux IC Data:%X Charge:%d\n",read_data[0],charge_in);
249 }
250 
251 void Setup::IF_parse_gpio_byte0(char byte)
252 {
253  gpio_byte0 = byte;
254  //GPIO byte zero contains the power line traces and the switch states
255  char current_switch = ((gpio_byte0 & 0xF8) >> 3);
256  if(switch_set == 1) {
257  if(current_switch != switch_byte) {
258  previous_switch_byte = switch_byte;
259  switch_byte = current_switch;
260  event++;
261  switch_event = 1;
262  }
263  } else {
264  switch_byte = current_switch;
265  switch_set = 1;
266  }
267  if(((gpio_byte0 & 0x01)) != power_good_motor_left){
268  power_good_motor_left = (gpio_byte0 & 0x01);
269  if(!power_good_motor_left){
270  if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator left motor low\n");
271  }
272  else if(testing_voltage_regulators_flag)psi.debug("- Power good left motor v.reg\n");
273  }
274  if(((gpio_byte0 & 0x02) >> 1) != power_good_motor_right){
275  power_good_motor_right = (gpio_byte0 & 0x02) >> 1;
276  if(!power_good_motor_right){
277  if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator right motor low\n");
278  }
279  else if(testing_voltage_regulators_flag)psi.debug("- Power good right motor v.reg\n");
280  }
281  if(((gpio_byte0 & 0x04) >> 2) != power_good_infrared){
282  power_good_infrared = (gpio_byte0 & 0x04) >> 2;
283  if(!power_good_infrared){
284  if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator infrared low\n");
285  }
286  else if(testing_voltage_regulators_flag)psi.debug("- Power good infrared and aux v.reg\n");
287  }
288  if(USE_LED4_FOR_VR_WARNINGS){
289  mbed_led4 = (!power_good_motor_left || !power_good_motor_right || !power_good_infrared);
290  }
291  //Halt the system if settings flag is set and all v-regs are bad [usually this means robot is switched off!]
292  if(HALT_ON_ALL_VREGS_LOW && !power_good_motor_left && !power_good_motor_right && !power_good_infrared){
293  psi.debug("- PROGRAM HALTED. Check that robot is switched on!\n");
294  while(1){
295  mbed_led1=1;
296  mbed_led2=0;
297  mbed_led3=1;
298  mbed_led4=0;
299  wait(0.25);
300  mbed_led1=0;
301  mbed_led2=1;
302  mbed_led3=0;
303  mbed_led4=1;
304  wait(0.25);
305  }
306  }
307 }
308 
309 void Setup::IF_parse_gpio_byte1(char byte)
310 {
311  gpio_byte1 = byte;
312  //GPIO byte one contains the wheel encoders and the ID switch
313  char current_id = ((gpio_byte1 & 0xF0)>> 4);
314  if(user_id_set == 1) {
315  if(robot_id != current_id) {
316  previous_robot_id = robot_id;
317  robot_id = current_id;
318  event++;
319  change_id_event = 1;
320  }
321  } else {
322  robot_id = current_id;
323  user_id_set = 1;
324  }
325  char current_encoder = (gpio_byte1 & 0x0F);
326  if(wheel_enc_set == 1) {
327  if(wheel_encoder_byte != current_encoder) {
328  previous_wheel_encoder_byte = wheel_encoder_byte;
329  wheel_encoder_byte = current_encoder;
330  event++;
331  encoder_event = 1;
332  }
333  } else {
334  wheel_encoder_byte = current_encoder;
335  wheel_enc_set = 1;
336  }
337 }
338 
339 void Setup::IF_handle_gpio_interrupt()
340 {
341  test = 1-test;
342  if(USE_LED3_FOR_INTERRUPTS) mbed_led3 = test;
343  IF_update_gpio_inputs();
344 }
345 
346 char Setup::IF_is_switch_pressed()
347 {
348  //Read data
349  char data[1];
350  char command[1] = {0}; //Command to read from input port 0
351  primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
352  primary_i2c.read(GPIO_IC_ADDRESS,data,1,false);
353  return (data[0] & 0x80); //Returns a 1 if the center button is being pushed
354 }
355 
356 
357 char Setup::IF_get_switch_state()
358 {
359  //Read data
360  char data[1];
361  char command[1] = {0}; //Command to read from input port 0
362  primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
363  primary_i2c.read(GPIO_IC_ADDRESS,data,1,false);
364  return (data[0] & 0xF8) >> 3; //Returns the current switch state
365 }
366 
367 void Setup::IF_update_gpio_inputs()
368 {
369  update_timeout.detach();
370  //Read data
371  char data[2];
372  char command[1] = {0}; //Command to read from input port 0
373  primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
374  primary_i2c.read(GPIO_IC_ADDRESS,data,2,false);
375  if(data[0]!=gpio_byte0) {
376  IF_parse_gpio_byte0(data[0]);
377  }
378  if(data[1]!=gpio_byte1) {
379  IF_parse_gpio_byte1(data[1]);
380  }
381  update_timeout.attach_us(this,&Setup::IF_update_gpio_inputs,50000);
382 }
383 
384 
385 void Setup::IF_write_to_led_ic(char byte_0, char byte_1)
386 {
387  //Set LEDs
388  char data[3];
389  data [0] = 0x02; //Write to output port
390  data [1] = byte_0;
391  data [2] = byte_1;
392  primary_i2c.write(LED_IC_ADDRESS,data,3,false);
393 }
394 
395 
396 void Setup::IF_setup_temperature_sensor()
397 {
398  char data[3];
399  data[0] = 0x04; //Set critical temp limit
400  data[1] = TEMPERATURE_CRITICAL_HI;
401  data[2] = TEMPEARTURE_CRITICAL_LO;
402  primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
403  data[0] = 0x02; //Set high temp limit
404  data[1] = TEMPERATURE_HIGH_HI;
405  data[2] = TEMPEARTURE_HIGH_LO;
406  primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
407  data[0] = 0x03; //Set low temp limit
408  data[1] = TEMPERATURE_LOW_HI;
409  data[2] = TEMPEARTURE_LOW_LO;
410  primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
411 }
412 
413 float Setup::IF_read_from_temperature_sensor()
414 {
415  char command[1] = {0x05}; //Write to Ta Register
416  char data[3];
417  signed int temp;
418  float temperature;
419  primary_i2c.write(TEMPERATURE_ADDRESS,command,1,false);
420  primary_i2c.read(TEMPERATURE_ADDRESS,data,2,false);
421 
422  //Convert the temperature data
423  //First Check flag bits
424  char UpperByte = data[0];
425  char LowerByte = data[1];
426  if ((UpperByte & 0x80) == 0x80) {
427  psi.debug("- WARNING: Temperature sensor reports critical temperature\n");
428  }
429  if ((UpperByte & 0x40) == 0x40) {
430  psi.debug("- WARNING: Temperature sensor reports above upper limit\n");
431  }
432  if ((UpperByte & 0x20) == 0x20) {
433  psi.debug("- WARNING: Temperature sensor reports below lower limit\n");
434  }
435  UpperByte = UpperByte & 0x1F; //Clear flag bits
436  if ((UpperByte & 0x10) == 0x10) {
437  UpperByte = UpperByte & 0x0F; //Clear SIGN
438  temp = (UpperByte * 256) + LowerByte;
439  temperature = - (temp / 16.0f);
440  } else {
441  temp = (UpperByte * 256) + LowerByte;
442  temperature = (temp / 16.0f);
443  }
444  return temperature;
445 }
void debug(const char *format,...)
Definition: psiswarm.cpp:325