UKESF Headstart Summer School / PsiSwarm-Headstart

Dependents:   UKESF_Lab

Fork of PsiSwarmLibrary by James Hilder

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers i2c.cpp Source File

i2c.cpp

00001 /* University of York Robotics Laboratory PsiSwarm Library: I2C Source File
00002  *
00003  * File: i2c.cpp
00004  *
00005  * (C) Dept. Electronics & Computer Science, University of York
00006  * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis
00007  *
00008  * PsiSwarm Library Version: 0.41
00009  *
00010  * March 2016
00011  *
00012  *
00013  */
00014 
00015 #include "psiswarm.h"
00016 
00017 char gpio_byte0;
00018 char gpio_byte1;
00019 char user_id_set = 0;
00020 char wheel_enc_set = 0;
00021 char switch_set = 0;
00022 
00023 char emitter_byte = 0x00;
00024 
00025 Timeout update_timeout;
00026 
00027 char test;
00028 
00029 char get_dc_status()
00030 {
00031     IF_read_aux_ic_data();
00032     return status_dc_in;
00033 }
00034 
00035 void IF_set_IR_emitter_output(char emitter, char state)
00036 {
00037     if(emitter <3) {
00038         if(state == 0) {
00039             char shift = 1 << emitter;
00040             emitter_byte &= (0xFF - shift);
00041         }
00042         if(state == 1) {
00043             char shift = 1 << emitter;
00044             emitter_byte |= shift;
00045         }
00046         char data[2];
00047         data [0] = 0x0A;  //Write to OLAT register
00048         data [1] = emitter_byte;  //GP0-3 are outputs on aux expansion IC
00049         //pc.printf("%c\n", emitter_byte);
00050         primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
00051     }
00052 }
00053 
00054 void IF_set_base_LED(char state)
00055 {
00056     if(state == 0) {
00057         emitter_byte &= 0xF7;
00058     } else emitter_byte |= 0x08;
00059     char data[2];
00060     data [0] = 0x0A;  //Write to OLAT register
00061     data [1] = emitter_byte;  //GP0-3 are outputs on aux expansion IC
00062     primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
00063 
00064 }
00065 
00066 unsigned short IF_read_IR_adc_value(char adc, char index)
00067 {
00068     char address = ADC1_ADDRESS;
00069     if(adc == 2) address=ADC2_ADDRESS;
00070     // Returns the raw sensor value for the IR sensor defined by index (range 0-7).
00071     short value = 0;
00072     // Read a single value from the ADC
00073     if(index<8) {
00074         char apb[1];
00075         char data[2];
00076         switch(index) {
00077             case 0:
00078                 apb[0]=0x80;
00079                 break;
00080             case 1:
00081                 apb[0]=0x90;
00082                 break;
00083             case 2:
00084                 apb[0]=0xA0;
00085                 break;
00086             case 3:
00087                 apb[0]=0xB0;
00088                 break;
00089             case 4:
00090                 apb[0]=0xC0;
00091                 break;
00092             case 5:
00093                 apb[0]=0xD0;
00094                 break;
00095             case 6:
00096                 apb[0]=0xE0;
00097                 break;
00098             case 7:
00099                 apb[0]=0xF0;
00100                 break;
00101         }
00102         primary_i2c.write(address,apb,1,false);
00103         primary_i2c.read(address,data,2,false);
00104         value=((data[0] % 16)<<8)+data[1];
00105         if(value > 4096) value=4096;
00106         value=4096-value;
00107     }
00108     return value;
00109 }
00110 
00111 char IF_setup_led_expansion_ic(void)
00112 {
00113     //LED expansion IC is PCA9555
00114     //Address is 0100 001x (0x42) {defined by LED_IC_ADDRESS}
00115     //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)
00116     //Message structure: {Address-RW}{Command}{Port 0}{Port 1}
00117     //Command bytes: 00000010 (0x02) = Write to output port
00118     //Command bytes: 00000110 (0x06) = Write to config registers
00119     //Note that for the LEDs, 0 = on, 1 = off
00120     //Port 0 = LED 1:4 Red:Green
00121     //Port 1 = LED 5:8 Red:Green
00122     char data [3];
00123     data [0] = 0x06;    //Write config registers
00124     data [1] = 0x00;    //All 8 pins in port 0 are outputs (0)
00125     data [2] = 0x00;    //All 8 pins in port 1 are outputs (0)
00126     primary_i2c.write(LED_IC_ADDRESS,data,3,false);
00127 
00128     //Turn all LEDs on
00129     data [0] = 0x02;    //Write to output port
00130     data [1] = 0x00;    //Enable LED1-4 (both colours)
00131     data [2] = 0x00;    //Enable LED5-8 (both colours)
00132     primary_i2c.write(LED_IC_ADDRESS,data,3,false);
00133 
00134     wait(0.05);
00135     //Turn all LEDs off
00136     data [0] = 0x02;    //Write to output port
00137     data [1] = 0xFF;    //Enable LED1-4 (both colours)
00138     data [2] = 0xFF;    //Enable LED5-8 (both colours)
00139     return primary_i2c.write(LED_IC_ADDRESS,data,3,false);
00140 }
00141 
00142 //Returns 0 if successful, 1 if test mode button pressed
00143 void IF_setup_gpio_expansion_ic(void)
00144 {
00145     //Main GPIO expansion IC is PCA9555
00146     //Address is 0100 000x (0x40) {defined by GPIO_IC_ADDRESS}
00147     //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)
00148     //Message structure: {Address-RW}{Command}{Port 0}{Port 1}
00149     //Command bytes: 00000010 (0x02) = Write to output port
00150     //Command bytes: 00000110 (0x06) = Write to config registers
00151     //Note that for the LEDs, 0 = on, 1 = off
00152     //Port 0 = PGDL; PGDR; PGDIR; UP; DOWN; LEFT; RIGHT; CENTER
00153     //Port 1 = ENC_LA; ENC_LB; ENC_RA; ENC_RB; ID0; ID1; ID2; ID3
00154     char data [3];
00155     char okay = 1;
00156     data [0] = 0x06;    //Write config registers
00157     data [1] = 0xFF;    //All 8 pins in port 0 are inputs (1)
00158     data [2] = 0xFF;    //All 8 pins in port 1 are inputs (1)
00159     if(primary_i2c.write(GPIO_IC_ADDRESS,data,3,false) != 0) {
00160         system_warnings += 2;
00161         okay = 0;
00162         debug("- WARNING: No I2C acknowledge for main GPIO IC\n");
00163         if(HALT_ON_GPIO_ERROR){
00164             debug("- PROGRAM HALTED.  Check that robot is switched on!\n");
00165             while(1){
00166                mbed_led1=1;
00167                mbed_led2=1;
00168                mbed_led3=0;
00169                mbed_led4=0;
00170                wait(0.25); 
00171                mbed_led1=0;
00172                mbed_led2=0;
00173                mbed_led3=1;
00174                mbed_led4=1;
00175                wait(0.25);   
00176             }   
00177         }
00178     }
00179     //Set all inputs to polarity-inverted (so a logic low = 1)
00180     data [0] = 0x04;    //Write to polarity inversion ports
00181     data [1] = 0xF8;    //Invert polarity of all switch input bits in input port 0 [but not power-good inputs]
00182     data [2] = 0xFF;    //Invert polarity of all bits in input port 1
00183     primary_i2c.write(GPIO_IC_ADDRESS,data,3,false);
00184 
00185     wait(0.01);
00186 
00187     //Read data
00188     char read_data[2];
00189     char command[1]; //Command to read from input port 0
00190     command[0]=0;
00191     primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
00192     primary_i2c.read(GPIO_IC_ADDRESS,read_data,2,false);
00193     gpio_byte0 = read_data[0];
00194     //char ret_val = (gpio_byte0 & 0xF8) >> 3;  //Returns a >0 value if a button is being pushed
00195     gpio_byte1 = read_data[1];
00196     if(okay && testing_voltage_regulators_flag)debug("- Checking 3.3V voltage regulators\n");
00197     IF_parse_gpio_byte0(gpio_byte0);
00198     IF_parse_gpio_byte1(gpio_byte1);
00199     testing_voltage_regulators_flag = 0;
00200     //Setup interrupt handler for GPIO interrupts
00201     gpio_interrupt.mode(PullUp);
00202     gpio_interrupt.rise(&IF_handle_gpio_interrupt);
00203     //pc.printf("%c %c",gpio_byte0,gpio_byte1);
00204 
00205     //Secondary GPIO expansion IC is MCP23009
00206     //Address is 0100 111 (0x4E) {defined by AUX_IC_ADDRESS}
00207     //GP0,1,2,3 are outputs for driving infrared emitters and the base LED
00208     //IODIR register wants to be 0xF0 (1=input, 0=output)
00209     data [0] = 0x00;  //Write to IODIR register
00210     data [1] = 0xF0;  //Set GP0-3 as outputs
00211     primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
00212 
00213     if(primary_i2c.write(AUX_IC_ADDRESS,data,2,false) != 0) {
00214         system_warnings += 4;
00215         debug("- WARNING: No I2C acknowledge for aux GPIO IC\n");
00216     }
00217     data [0] = 0x06;  //Write to GPPU register
00218     data [1] = 0x3F;  //Set GP0-3 as active pull-up outputs and P4,P5 as pull-up inputs
00219     primary_i2c.write(AUX_IC_ADDRESS,data,2,false);
00220 
00221     //My interrupt is not so reliable: poll with a 50ms timeout in case interrupts aren't handled
00222     update_timeout.attach_us(&IF_update_gpio_inputs,50000);
00223     //return ret_val;
00224 }
00225 
00226 void IF_read_aux_ic_data()
00227 {
00228     //Read the values of the input pins on the auxilliary GPIO expander
00229     char write_data [1];
00230     char read_data [1];
00231     write_data[0] = 0x09;
00232     primary_i2c.write(AUX_IC_ADDRESS,write_data,1,false);
00233     primary_i2c.read(AUX_IC_ADDRESS,read_data,1,false);
00234     char old_charging_state = status_dc_in;
00235     status_dc_in = 1-((read_data[0] & 0x10) >> 4);
00236     if(status_dc_in!=old_charging_state){
00237         if(status_dc_in == 0)debug("No DC input\n");
00238         else debug("DC input to charge pins\n");
00239     }
00240     //pc.printf("Aux IC Data:%X Charge:%d\n",read_data[0],charge_in);
00241 }
00242 
00243 void IF_parse_gpio_byte0(char byte)
00244 {
00245     gpio_byte0 = byte;
00246     //GPIO byte zero contains the power line traces and the switch states
00247     char current_switch = ((gpio_byte0 & 0xF8) >> 3);
00248     if(switch_set == 1) {
00249         if(current_switch != switch_byte) {
00250             previous_switch_byte = switch_byte;
00251             switch_byte = current_switch;
00252             event++;
00253             switch_event = 1;
00254         }
00255     } else {
00256         switch_byte = current_switch;
00257         switch_set = 1;
00258     }
00259     if(((gpio_byte0 & 0x01)) != power_good_motor_left){
00260         power_good_motor_left = (gpio_byte0 & 0x01);
00261         if(!power_good_motor_left){
00262             if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)debug("- WARNING: Voltage regulator left motor low\n");    
00263         }
00264         else if(testing_voltage_regulators_flag)debug("- Power good left motor v.reg\n");
00265     } 
00266     if(((gpio_byte0 & 0x02) >> 1) != power_good_motor_right){
00267         power_good_motor_right = (gpio_byte0 & 0x02) >> 1;
00268         if(!power_good_motor_right){
00269             if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)debug("- WARNING: Voltage regulator right motor low\n");
00270         }
00271         else if(testing_voltage_regulators_flag)debug("- Power good right motor v.reg\n");
00272     } 
00273     if(((gpio_byte0 & 0x04) >> 2) != power_good_infrared){
00274         power_good_infrared = (gpio_byte0 & 0x04) >> 2;
00275         if(!power_good_infrared){
00276             if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)debug("- WARNING: Voltage regulator infrared low\n");
00277         }
00278         else if(testing_voltage_regulators_flag)debug("- Power good infrared and aux v.reg\n");
00279     } 
00280     if(USE_LED4_FOR_VR_WARNINGS){
00281          mbed_led4 = (!power_good_motor_left || !power_good_motor_right || !power_good_infrared);
00282     }
00283     //Halt the system if settings flag is set and all v-regs are bad [usually this means robot is switched off!]
00284     if(HALT_ON_ALL_VREGS_LOW && !power_good_motor_left && !power_good_motor_right && !power_good_infrared){
00285         debug("- PROGRAM HALTED.  Check that robot is switched on!\n");
00286         while(1){
00287              mbed_led1=1;
00288              mbed_led2=0;
00289              mbed_led3=1;
00290              mbed_led4=0;
00291              wait(0.25); 
00292              mbed_led1=0;
00293              mbed_led2=1;
00294              mbed_led3=0;
00295              mbed_led4=1;
00296              wait(0.25); 
00297         }
00298     }
00299 }
00300 
00301 void IF_parse_gpio_byte1(char byte)
00302 {
00303     gpio_byte1 = byte;
00304     //GPIO byte one contains the wheel encoders and the ID switch
00305     char current_id = ((gpio_byte1 & 0xF0)>> 4);
00306     if(user_id_set == 1) {
00307         if(robot_id != current_id) {
00308             previous_robot_id = robot_id;
00309             robot_id = current_id;
00310             event++;
00311             change_id_event = 1;
00312         }
00313     } else {
00314         robot_id = current_id;
00315         user_id_set = 1;
00316     }
00317     char current_encoder = (gpio_byte1 & 0x0F);
00318     if(wheel_enc_set == 1) {
00319         if(wheel_encoder_byte != current_encoder) {
00320             previous_wheel_encoder_byte = wheel_encoder_byte;
00321             wheel_encoder_byte = current_encoder;
00322             event++;
00323             encoder_event = 1;
00324         }
00325     } else {
00326         wheel_encoder_byte = current_encoder;
00327         wheel_enc_set = 1;
00328     }
00329 }
00330 
00331 void IF_handle_gpio_interrupt()
00332 {
00333     test = 1-test;
00334     if(USE_LED3_FOR_INTERRUPTS) mbed_led3 = test;
00335     IF_update_gpio_inputs();
00336 }
00337 
00338 char IF_is_switch_pressed()
00339 {
00340     //Read data
00341     char data[1];
00342     char command[1] = {0}; //Command to read from input port 0
00343     primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
00344     primary_i2c.read(GPIO_IC_ADDRESS,data,1,false);
00345     return (data[0] & 0x80);  //Returns a 1 if the center button is being pushed
00346 }
00347 
00348 
00349 char IF_get_switch_state()
00350 {
00351     //Read data
00352     char data[1];
00353     char command[1] = {0}; //Command to read from input port 0
00354     primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
00355     primary_i2c.read(GPIO_IC_ADDRESS,data,1,false);
00356     return (data[0] & 0xF8) >> 3;  //Returns the current switch state
00357 }
00358 
00359 void IF_update_gpio_inputs()
00360 {
00361     update_timeout.detach();
00362     //Read data
00363     char data[2];
00364     char command[1] = {0}; //Command to read from input port 0
00365     primary_i2c.write(GPIO_IC_ADDRESS,command,1,false);
00366     primary_i2c.read(GPIO_IC_ADDRESS,data,2,false);
00367     if(data[0]!=gpio_byte0) {
00368         IF_parse_gpio_byte0(data[0]);
00369     }
00370     if(data[1]!=gpio_byte1) {
00371         IF_parse_gpio_byte1(data[1]);
00372     }
00373     update_timeout.attach_us(&IF_update_gpio_inputs,50000);
00374 }
00375 
00376 
00377 void IF_write_to_led_ic(char byte_0, char byte_1)
00378 {
00379     //Set LEDs
00380     char data[3];
00381     data [0] = 0x02;    //Write to output port
00382     data [1] = byte_0;
00383     data [2] = byte_1;
00384     primary_i2c.write(LED_IC_ADDRESS,data,3,false);
00385 }
00386 
00387 
00388 void IF_setup_temperature_sensor()
00389 {
00390     char data[3];
00391     data[0] = 0x04; //Set critical temp limit
00392     data[1] = TEMPERATURE_CRITICAL_HI;
00393     data[2] = TEMPEARTURE_CRITICAL_LO;
00394     primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
00395     data[0] = 0x02; //Set high temp limit
00396     data[1] = TEMPERATURE_HIGH_HI;
00397     data[2] = TEMPEARTURE_HIGH_LO;
00398     primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
00399     data[0] = 0x03; //Set low temp limit
00400     data[1] = TEMPERATURE_LOW_HI;
00401     data[2] = TEMPEARTURE_LOW_LO;
00402     primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false);
00403 }
00404 
00405 float IF_read_from_temperature_sensor()
00406 {
00407     char command[1] = {0x05};  //Write to Ta Register
00408     char data[3];
00409     signed int temp;
00410     float temperature;
00411     primary_i2c.write(TEMPERATURE_ADDRESS,command,1,false);
00412     primary_i2c.read(TEMPERATURE_ADDRESS,data,2,false);
00413 
00414     //Convert the temperature data
00415     //First Check flag bits
00416     char UpperByte = data[0];
00417     char LowerByte = data[1];
00418     if ((UpperByte & 0x80) == 0x80) {
00419         debug("- WARNING: Temperature sensor reports critical temperature\n");
00420     }
00421     if ((UpperByte & 0x40) == 0x40) {
00422         debug("- WARNING: Temperature sensor reports above upper limit\n");
00423     }
00424     if ((UpperByte & 0x20) == 0x20) {
00425         debug("- WARNING: Temperature sensor reports below lower limit\n");
00426     }
00427     UpperByte = UpperByte & 0x1F;       //Clear flag bits
00428     if ((UpperByte & 0x10) == 0x10) {
00429         UpperByte = UpperByte & 0x0F;   //Clear SIGN
00430         temp = (UpperByte * 256) + LowerByte;
00431         temperature = - (temp / 16.0f);
00432     } else   {
00433         temp = (UpperByte * 256) + LowerByte;
00434         temperature = (temp / 16.0f);
00435     }
00436     return temperature;
00437 }