C++ Library for the PsiSwarm Robot - Version 0.8
Dependents: PsiSwarm_V8_Blank_CPP Autonomia_RndmWlk
Fork of PsiSwarmV7_CPP by
i2c_setup.cpp
- Committer:
- JessicaGao
- Date:
- 2017-07-14
- Revision:
- 15:be92991621b4
- Parent:
- 12:878c6e9d9e60
File content as of revision 15:be92991621b4:
/* University of York Robotics Laboratory PsiSwarm Library: I2C Setup Source File * * Copyright 2016 University of York * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. * * File: i2c_setup.cpp * * (C) Dept. Electronics & Computer Science, University of York * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis * * PsiSwarm Library Version: 0.8 * * October 2016 * * */ #include "psiswarm.h" char gpio_byte0; char gpio_byte1; char user_id_set = 0; char wheel_enc_set = 0; char switch_set = 0; char emitter_byte = 0x00; Timeout update_timeout; char test; char Setup::get_dc_status() { IF_read_aux_ic_data(); return status_dc_in; } void Setup::IF_set_IR_emitter_output(char emitter, char state) { if(emitter <3) { if(state == 0) { char shift = 1 << emitter; emitter_byte &= (0xFF - shift); } if(state == 1) { char shift = 1 << emitter; emitter_byte |= shift; } char data[2]; data [0] = 0x0A; //Write to OLAT register data [1] = emitter_byte; //GP0-3 are outputs on aux expansion IC //pc.printf("%c\n", emitter_byte); primary_i2c.write(AUX_IC_ADDRESS,data,2,false); } } void Setup::IF_set_base_LED(char state) { if(state == 0) { emitter_byte &= 0xF7; } else emitter_byte |= 0x08; char data[2]; data [0] = 0x0A; //Write to OLAT register data [1] = emitter_byte; //GP0-3 are outputs on aux expansion IC primary_i2c.write(AUX_IC_ADDRESS,data,2,false); } unsigned short Setup::IF_read_IR_adc_value(char adc, char index) { char address = ADC1_ADDRESS; if(adc == 2) address=ADC2_ADDRESS; // Returns the raw sensor value for the IR sensor defined by index (range 0-7). short value = 0; // Read a single value from the ADC if(index<8) { char apb[1]; char data[2]; switch(index) { case 0: apb[0]=0x80; break; case 1: apb[0]=0x90; break; case 2: apb[0]=0xA0; break; case 3: apb[0]=0xB0; break; case 4: apb[0]=0xC0; break; case 5: apb[0]=0xD0; break; case 6: apb[0]=0xE0; break; case 7: apb[0]=0xF0; break; } primary_i2c.write(address,apb,1,false); primary_i2c.read(address,data,2,false); value=((data[0] % 16)<<8)+data[1]; if(value > 4096) value=4096; value=4096-value; } return value; } char Setup::IF_setup_led_expansion_ic(void) { //LED expansion IC is PCA9555 //Address is 0100 001x (0x42) {defined by LED_IC_ADDRESS} //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) //Message structure: {Address-RW}{Command}{Port 0}{Port 1} //Command bytes: 00000010 (0x02) = Write to output port //Command bytes: 00000110 (0x06) = Write to config registers //Note that for the LEDs, 0 = on, 1 = off //Port 0 = LED 1:4 Red:Green //Port 1 = LED 5:8 Red:Green char data [3]; data [0] = 0x06; //Write config registers data [1] = 0x00; //All 8 pins in port 0 are outputs (0) data [2] = 0x00; //All 8 pins in port 1 are outputs (0) primary_i2c.write(LED_IC_ADDRESS,data,3,false); //Turn all LEDs on data [0] = 0x02; //Write to output port data [1] = 0x00; //Enable LED1-4 (both colours) data [2] = 0x00; //Enable LED5-8 (both colours) primary_i2c.write(LED_IC_ADDRESS,data,3,false); wait(0.05); //Turn all LEDs off data [0] = 0x02; //Write to output port data [1] = 0xFF; //Enable LED1-4 (both colours) data [2] = 0xFF; //Enable LED5-8 (both colours) return primary_i2c.write(LED_IC_ADDRESS,data,3,false); } //Returns 0 if successful, 1 if test mode button pressed void Setup::IF_setup_gpio_expansion_ic(void) { //Main GPIO expansion IC is PCA9555 //Address is 0100 000x (0x40) {defined by GPIO_IC_ADDRESS} //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) //Message structure: {Address-RW}{Command}{Port 0}{Port 1} //Command bytes: 00000010 (0x02) = Write to output port //Command bytes: 00000110 (0x06) = Write to config registers //Note that for the LEDs, 0 = on, 1 = off //Port 0 = PGDL; PGDR; PGDIR; UP; DOWN; LEFT; RIGHT; CENTER //Port 1 = ENC_LA; ENC_LB; ENC_RA; ENC_RB; ID0; ID1; ID2; ID3 char data [3]; char okay = 1; data [0] = 0x06; //Write config registers data [1] = 0xFF; //All 8 pins in port 0 are inputs (1) data [2] = 0xFF; //All 8 pins in port 1 are inputs (1) if(primary_i2c.write(GPIO_IC_ADDRESS,data,3,false) != 0) { system_warnings += 2; okay = 0; psi.debug("- WARNING: No I2C acknowledge for main GPIO IC\n"); if(HALT_ON_GPIO_ERROR){ psi.debug("- PROGRAM HALTED. Check that robot is switched on!\n"); while(1){ mbed_led1=1; mbed_led2=1; mbed_led3=0; mbed_led4=0; wait(0.25); mbed_led1=0; mbed_led2=0; mbed_led3=1; mbed_led4=1; wait(0.25); } } } //Set all inputs to polarity-inverted (so a logic low = 1) data [0] = 0x04; //Write to polarity inversion ports data [1] = 0xF8; //Invert polarity of all switch input bits in input port 0 [but not power-good inputs] data [2] = 0xFF; //Invert polarity of all bits in input port 1 primary_i2c.write(GPIO_IC_ADDRESS,data,3,false); wait(0.01); //Read data char read_data[2]; char command[1]; //Command to read from input port 0 command[0]=0; primary_i2c.write(GPIO_IC_ADDRESS,command,1,false); primary_i2c.read(GPIO_IC_ADDRESS,read_data,2,false); gpio_byte0 = read_data[0]; //char ret_val = (gpio_byte0 & 0xF8) >> 3; //Returns a >0 value if a button is being pushed gpio_byte1 = read_data[1]; if(okay && testing_voltage_regulators_flag)psi.debug("- Checking 3.3V voltage regulators\n"); IF_parse_gpio_byte0(gpio_byte0); IF_parse_gpio_byte1(gpio_byte1); testing_voltage_regulators_flag = 0; //Setup interrupt handler for GPIO interrupts gpio_interrupt.mode(PullUp); gpio_interrupt.rise(this,&Setup::IF_handle_gpio_interrupt); //pc.printf("%c %c",gpio_byte0,gpio_byte1); //Secondary GPIO expansion IC is MCP23009 //Address is 0100 111 (0x4E) {defined by AUX_IC_ADDRESS} //GP0,1,2,3 are outputs for driving infrared emitters and the base LED //IODIR register wants to be 0xF0 (1=input, 0=output) data [0] = 0x00; //Write to IODIR register data [1] = 0xF0; //Set GP0-3 as outputs primary_i2c.write(AUX_IC_ADDRESS,data,2,false); if(primary_i2c.write(AUX_IC_ADDRESS,data,2,false) != 0) { system_warnings += 4; psi.debug("- WARNING: No I2C acknowledge for aux GPIO IC\n"); } data [0] = 0x06; //Write to GPPU register data [1] = 0x3F; //Set GP0-3 as active pull-up outputs and P4,P5 as pull-up inputs primary_i2c.write(AUX_IC_ADDRESS,data,2,false); //My interrupt is not so reliable: poll with a 50ms timeout in case interrupts aren't handled update_timeout.attach_us(this,&Setup::IF_update_gpio_inputs,50000); //return ret_val; } void Setup::IF_read_aux_ic_data() { //Read the values of the input pins on the auxilliary GPIO expander char write_data [1]; char read_data [1]; write_data[0] = 0x09; primary_i2c.write(AUX_IC_ADDRESS,write_data,1,false); primary_i2c.read(AUX_IC_ADDRESS,read_data,1,false); char old_charging_state = status_dc_in; status_dc_in = 1-((read_data[0] & 0x10) >> 4); if(status_dc_in!=old_charging_state){ if(status_dc_in == 0)psi.debug("No DC input\n"); else psi.debug("DC input to charge pins\n"); } //pc.printf("Aux IC Data:%X Charge:%d\n",read_data[0],charge_in); } void Setup::IF_parse_gpio_byte0(char byte) { gpio_byte0 = byte; //GPIO byte zero contains the power line traces and the switch states char current_switch = ((gpio_byte0 & 0xF8) >> 3); if(switch_set == 1) { if(current_switch != switch_byte) { previous_switch_byte = switch_byte; switch_byte = current_switch; event++; switch_event = 1; } } else { switch_byte = current_switch; switch_set = 1; } if(((gpio_byte0 & 0x01)) != power_good_motor_left){ power_good_motor_left = (gpio_byte0 & 0x01); if(!power_good_motor_left){ if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator left motor low\n"); } else if(testing_voltage_regulators_flag)psi.debug("- Power good left motor v.reg\n"); } if(((gpio_byte0 & 0x02) >> 1) != power_good_motor_right){ power_good_motor_right = (gpio_byte0 & 0x02) >> 1; if(!power_good_motor_right){ if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator right motor low\n"); } else if(testing_voltage_regulators_flag)psi.debug("- Power good right motor v.reg\n"); } if(((gpio_byte0 & 0x04) >> 2) != power_good_infrared){ power_good_infrared = (gpio_byte0 & 0x04) >> 2; if(!power_good_infrared){ if(testing_voltage_regulators_flag || SHOW_VR_WARNINGS)psi.debug("- WARNING: Voltage regulator infrared low\n"); } else if(testing_voltage_regulators_flag)psi.debug("- Power good infrared and aux v.reg\n"); } if(USE_LED4_FOR_VR_WARNINGS){ mbed_led4 = (!power_good_motor_left || !power_good_motor_right || !power_good_infrared); } //Halt the system if settings flag is set and all v-regs are bad [usually this means robot is switched off!] if(HALT_ON_ALL_VREGS_LOW && !power_good_motor_left && !power_good_motor_right && !power_good_infrared){ psi.debug("- PROGRAM HALTED. Check that robot is switched on!\n"); while(1){ mbed_led1=1; mbed_led2=0; mbed_led3=1; mbed_led4=0; wait(0.25); mbed_led1=0; mbed_led2=1; mbed_led3=0; mbed_led4=1; wait(0.25); } } } void Setup::IF_parse_gpio_byte1(char byte) { gpio_byte1 = byte; //GPIO byte one contains the wheel encoders and the ID switch char current_id = ((gpio_byte1 & 0xF0)>> 4); if(user_id_set == 1) { if(robot_id != current_id) { previous_robot_id = robot_id; robot_id = current_id; event++; change_id_event = 1; } } else { robot_id = current_id; user_id_set = 1; } char current_encoder = (gpio_byte1 & 0x0F); if(wheel_enc_set == 1) { if(wheel_encoder_byte != current_encoder) { previous_wheel_encoder_byte = wheel_encoder_byte; wheel_encoder_byte = current_encoder; event++; encoder_event = 1; } } else { wheel_encoder_byte = current_encoder; wheel_enc_set = 1; } } void Setup::IF_handle_gpio_interrupt() { test = 1-test; if(USE_LED3_FOR_INTERRUPTS) mbed_led3 = test; IF_update_gpio_inputs(); } char Setup::IF_is_switch_pressed() { //Read data char data[1]; char command[1] = {0}; //Command to read from input port 0 primary_i2c.write(GPIO_IC_ADDRESS,command,1,false); primary_i2c.read(GPIO_IC_ADDRESS,data,1,false); return (data[0] & 0x80); //Returns a 1 if the center button is being pushed } char Setup::IF_get_switch_state() { //Read data char data[1]; char command[1] = {0}; //Command to read from input port 0 primary_i2c.write(GPIO_IC_ADDRESS,command,1,false); primary_i2c.read(GPIO_IC_ADDRESS,data,1,false); return (data[0] & 0xF8) >> 3; //Returns the current switch state } void Setup::IF_update_gpio_inputs() { update_timeout.detach(); //Read data char data[2]; char command[1] = {0}; //Command to read from input port 0 primary_i2c.write(GPIO_IC_ADDRESS,command,1,false); primary_i2c.read(GPIO_IC_ADDRESS,data,2,false); if(data[0]!=gpio_byte0) { IF_parse_gpio_byte0(data[0]); } if(data[1]!=gpio_byte1) { IF_parse_gpio_byte1(data[1]); } update_timeout.attach_us(this,&Setup::IF_update_gpio_inputs,50000); } void Setup::IF_write_to_led_ic(char byte_0, char byte_1) { //Set LEDs char data[3]; data [0] = 0x02; //Write to output port data [1] = byte_0; data [2] = byte_1; primary_i2c.write(LED_IC_ADDRESS,data,3,false); } void Setup::IF_setup_temperature_sensor() { char data[3]; data[0] = 0x04; //Set critical temp limit data[1] = TEMPERATURE_CRITICAL_HI; data[2] = TEMPEARTURE_CRITICAL_LO; primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false); data[0] = 0x02; //Set high temp limit data[1] = TEMPERATURE_HIGH_HI; data[2] = TEMPEARTURE_HIGH_LO; primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false); data[0] = 0x03; //Set low temp limit data[1] = TEMPERATURE_LOW_HI; data[2] = TEMPEARTURE_LOW_LO; primary_i2c.write(TEMPERATURE_ADDRESS,data,3,false); } float Setup::IF_read_from_temperature_sensor() { char command[1] = {0x05}; //Write to Ta Register char data[3]; signed int temp; float temperature; primary_i2c.write(TEMPERATURE_ADDRESS,command,1,false); primary_i2c.read(TEMPERATURE_ADDRESS,data,2,false); //Convert the temperature data //First Check flag bits char UpperByte = data[0]; char LowerByte = data[1]; if ((UpperByte & 0x80) == 0x80) { psi.debug("- WARNING: Temperature sensor reports critical temperature\n"); } if ((UpperByte & 0x40) == 0x40) { psi.debug("- WARNING: Temperature sensor reports above upper limit\n"); } if ((UpperByte & 0x20) == 0x20) { psi.debug("- WARNING: Temperature sensor reports below lower limit\n"); } UpperByte = UpperByte & 0x1F; //Clear flag bits if ((UpperByte & 0x10) == 0x10) { UpperByte = UpperByte & 0x0F; //Clear SIGN temp = (UpperByte * 256) + LowerByte; temperature = - (temp / 16.0f); } else { temp = (UpperByte * 256) + LowerByte; temperature = (temp / 16.0f); } return temperature; }