I2C hang recover function added
Dependencies: UniGraphic mbed vt100
In this version, check_i2c_pins function was added in edge_mgr.cpp.
プログラムの起動時、I2Cモジュールを初期化する前に、I2Cに使用するピンの電位を確認し
もし一方でも Low に張り付いていた場合、SCL を GPIO 出力に設定して
所定回数 (I2C_UNLOCK_TRIAL_CYCLE) 反転させることにより、疑似リセットクロックを生成します。
その後は、通常の起動手順に復帰し、以降はこれまでと同様の動作をします。
edge_utils/edge_mgr.cpp
- Committer:
- gaku_miyagawa
- Date:
- 2018-06-18
- Revision:
- 2:de22987be9ba
- Parent:
- 1:1af1fd910340
File content as of revision 2:de22987be9ba:
#include "mbed.h" #include "edge_mgr.h" #include "af_attributes.h" #include "edge_time.h" #include "edge_pin.h" #include "MMA8451Q.h" #include "VEML6040.h" #include "LM75B.h" #include "SMTC502AT.h" #include "PSE530.h" #include <ILI9341.h> #include "Arial12x12.h" #include "Arial24x23.h" #include "Arial28x28.h" #include "edge_sensor.h" #include "edge_accel.h" #include "edge_color.h" #include "edge_temp.h" #include "edge_pressure.h" #include "edge_reset_mgr.h" #include "edge_chart.h" #define MMA8451Q_I2C_ADDRESS 0x1C #define VEML6040_I2C_ADDRESS 0x10 #define LM75B_I2C_ADDRESS 0x48 #define SO1602A_I2C_ADDRESS 0x3C #define NUM_MAX_SENSOR 5 uint16_t attr_to_set[] = { ATTR_ACCEL_PRESENT, ATTR_COLOR0_PRESENT, ATTR_COLOR1_PRESENT, ATTR_TEMP0_PRESENT, ATTR_GAS_PRESENT, } ; uint16_t attr_to_get[] = { // accel ATTR_ACCEL_ENABLE, ATTR_ACCEL_INTERVAL, // Color0 ATTR_COLOR0_ENABLE, ATTR_COLOR0_INTERVAL, ATTR_COLOR0_ITIME, ATTR_COLOR0_PWM_PERIOD, ATTR_COLOR0_PWM_TARGET, ATTR_COLOR0_PWM_R, ATTR_COLOR0_PWM_G, ATTR_COLOR0_PWM_B, // Color1 ATTR_COLOR1_ENABLE, ATTR_COLOR1_INTERVAL, ATTR_COLOR1_ITIME, ATTR_COLOR1_PWM_PERIOD, ATTR_COLOR1_PWM_TARGET, ATTR_COLOR1_PWM_R, ATTR_COLOR1_PWM_G, ATTR_COLOR1_PWM_B, // Temp ATTR_TEMP0_INTERVAL, ATTR_TEMP0_ENABLE, // Gas Pressure ATTR_GAS_ENABLE, ATTR_GAS_INTERVAL, ATTR_GAS_THR_MODE, ATTR_GAS_THR_HIGH, ATTR_GAS_THR_LOW, 0 } ; bool verbos = true ; edge_sensor *sensor[NUM_MAX_SENSOR] ; int num_sensor = 0 ; edge_accel *accel = 0 ; edge_color *color[2] = {0, 0} ; edge_temp *temp = 0 ; edge_pressure *pressure = 0 ; PwmOut *led[3] = {0, 0, 0} ; uint16_t pwm[3] = { 0x5FA2, 0xB09B, 0x83DF } ; I2C *edge_i2c0 = 0 ; I2C *edge_i2c1 = 0 ; ILI9341 *display = 0 ; MMA8451Q *mma8451q = 0 ; VEML6040 *veml6040[2] = { 0, 0 } ; LM75B *lm75b0 = 0 ; /* for temp1 */ AnalogIn *an0 = 0 ; /* for temp2 */ SMTC502AT *smtc502at0 = 0 ; AnalogIn *an1 = 0 ; /* for temp3 */ SMTC502AT *smtc502at1 = 0 ; LM75B *lm75b1 = 0 ; /* for temp4 */ AnalogIn *an2 = 0 ; /* for gas pressure */ PSE530 *pse530 = 0 ; /* gas pressure sensor */ DigitalOut *tft_reset = 0 ; DigitalOut *tft_backlight = 0 ; DigitalOut *tft_cs = 0 ; DigitalOut *pse530_en = 0 ; static int error_tolerance = 100 ; static int loop_interval = 100 ; // 1000 ; static int accel_interval = 10 ; int edge_mgr_status = EDGE_MGR_INIT ; char *reset_reason_str = 0 ; int display_mode = 1 ; bool reboot_requested = false ; void init_display(void) { reset_watch_dog() ; printf("TFT Initializing\n") ; tft_reset = new DigitalOut(PIN_RESET_TFT, 1) ; tft_backlight = new DigitalOut(PIN_BL_TFT, 0) ; tft_cs = new DigitalOut(PIN_CS_TFT, 1) ; reset_watch_dog() ; display = new ILI9341(SPI_8, 10000000, PIN_MOSI, PIN_MISO, PIN_SCK, PIN_CS_TFT, PIN_RESET_TFT, PIN_DC_TFT, "LaSuno") ; reset_watch_dog() ; display->BusEnable(true) ; display->set_orientation(1) ; reset_watch_dog() ; display->cls() ; *tft_backlight = 1 ; display->BusEnable(false) ; printf("TFT Initialized\n") ; } void edge_splash(void) { printf("Sensor loop started!\n") ; if (display) { reset_watch_dog() ; display->BusEnable(true) ; display->cls() ; display->foreground(Green) ; display->locate(40, 20) ; display->printf("Sensor Loop") ; display->locate(40, 60) ; display->printf(" Started!") ; display->BusEnable(false) ; reset_watch_dog() ; } } int init_edge_attribute(void) { static int sensor_index = 0 ; static int attr_index = 0 ; static int error_count = 0 ; int return_value = 1 ; int result ; reset_watch_dog() ; if (reset_reason_str) { result = afero->setAttribute(ATTR_MCU_RESET_REASON, reset_reason_str) ; if (result == afSUCCESS) { error_count = 0 ; reset_reason_str = 0 ; } else { error_count++ ; } reset_watch_dog() ; } if (sensor_index < NUM_MAX_SENSOR) {// for each sensor send presence // printf("Setting sensor[%d] presence\n", sensor_index) ; if (sensor_index == 3) { /* for temp lm75b0 is used */ result = afero->setAttributeBool(attr_to_set[sensor_index], lm75b0) ; } else { result = afero->setAttributeBool(attr_to_set[sensor_index], sensor[sensor_index]) ; } if (result == afSUCCESS) { error_count = 0 ; sensor_index++ ; } else { error_count++ ; } reset_watch_dog() ; } else { // all sensor presence sent, now get attributes if (attr_to_get[attr_index] != 0) { // printf("getting attribute [%d]\n", attr_index) ; result = afero->getAttribute(attr_to_get[attr_index]) ; if (result == afSUCCESS) { error_count = 0 ; attr_index++ ; } else { error_count++ ; } } reset_watch_dog() ; } if (error_count > error_tolerance) { // too many fails, trying reset reset_watch_dog() ; reboot_edge() ; } if ((sensor_index >= NUM_MAX_SENSOR)&&(attr_to_get[attr_index] == 0)) { /* all sensors attributes done */ sensor_index = 0 ; attr_index = 0 ; return_value = 0 ; } return(return_value) ; } void edge_loop(uint32_t count_robin) { static int sensor_index = 0 ; int result ; reset_watch_dog() ; if ((count_robin % accel_interval) == 0) { if (accel) { accel->accum() ; /* get and accum accel data */ } reset_watch_dog() ; } if ((count_robin % loop_interval) == 0) { reset_watch_dog() ; loop_interval = 10 ; if ((sensor[sensor_index])&&(sensor[sensor_index]->isEnabled())) { switch(sensor_index) { case SENSOR_ID_COLOR1: /* color0 */ if (((edge_color*)sensor[sensor_index])->calibration_requested()) { ((edge_color*)sensor[sensor_index])->calibrate(color0_target, color0_pwm, 10) ; reset_watch_dog() ; while((result = afero->setAttribute32(ATTR_COLOR0_PWM_R, color0_pwm[0])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } while((result = afero->setAttribute32(ATTR_COLOR0_PWM_G, color0_pwm[1])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } while((result = afero->setAttribute32(ATTR_COLOR0_PWM_B, color0_pwm[2])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } while((afero->setAttributeBool(ATTR_COLOR0_CALIBRATE, false)) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } } else { sensor[sensor_index]->runStateMachine() ; } break ; case SENSOR_ID_COLOR2: /* color1 */ if (((edge_color*)sensor[sensor_index])->calibration_requested()) { ((edge_color*)sensor[sensor_index])->calibrate(color1_target, color1_pwm, 10) ; reset_watch_dog() ; if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_R, color1_pwm[0])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_G, color1_pwm[1])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } reset_watch_dog() ; if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_B, color1_pwm[2])) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } while((afero->setAttributeBool(ATTR_COLOR1_CALIBRATE, false)) != afSUCCESS) { reset_watch_dog() ; print_af_error(result) ; wait_ms(10) ; } } else { sensor[sensor_index]->runStateMachine() ; } break ; default: sensor[sensor_index]->runStateMachine() ; break ; } } sensor_index = (sensor_index + 1) % NUM_MAX_SENSOR ; } reset_watch_dog() ; } int is_present(I2C *i2c, int address) { char t[1] = { 0 } ; char data[2] = { 0, 0 } ; int result ; address <<= 1 ; result = i2c->write(address, t, 1, true) ; if (result == 0) { result = i2c->read(address, data, 2) ; } return((result == 0)) ; } /** * check_i2c_pins * To avoid I2C dead-lock condition, * check status of SDA and SCL. * As they are supposed to be HIGH * in case one of them is/are LOW, * change SCL pin to a digital out pin and * generate forced clock for a several cycles. * and when SDA come back to High returns * or I2C_UNLOCK_TRIAL_CYCLE exceeds, give up. */ #define I2C_UNLOCK_TRIAL_CYCLE 50 void check_i2c_pins(PinName sda_pin, PinName scl_pin, int number) { DigitalIn *sda_in = 0 ; DigitalIn *scl_in = 0 ; DigitalOut *scl_out = 0 ; int count = 0 ; sda_in = new DigitalIn(sda_pin, PullUp) ; scl_in = new DigitalIn(scl_pin, PullUp) ; printf("I2C%d pin ", number) ; if ((*sda_in == 0) || (*scl_in == 0)) { /* bus hang! */ printf("hang detected, trying to clear ... ") ; delete scl_in ; scl_in = 0 ; scl_out = new DigitalOut(scl_pin) ; while((*sda_in == 0)&&(count++ > I2C_UNLOCK_TRIAL_CYCLE)) { *scl_out = 0 ; wait(0.01) ; *scl_out = 1 ; wait(0.01) ; } if (*sda_in != 0) { printf("Cleared!\n") ; } else { printf("Failed to Clear, proceeding\n") ; } } else { printf("condition OK\n") ; } if (sda_in) { delete sda_in ; } if (scl_in) { delete scl_in ; } if (scl_out) { delete scl_out ; } } void init_sensors(void) { printf("=== Initializing Sensor(s) ===\n") ; check_i2c_pins(PIN_I2C0_SDA, PIN_I2C0_SCL, 0) ; edge_i2c0 = new I2C(PIN_I2C0_SDA, PIN_I2C0_SCL) ; check_i2c_pins(PIN_I2C1_SDA, PIN_I2C1_SCL, 1) ; edge_i2c1 = new I2C(PIN_I2C1_SDA, PIN_I2C1_SCL) ; if (display) { reset_watch_dog() ; printf("printing inital string to TFT\n") ; display->BusEnable(true) ; display->background(Black) ; display->foreground(White) ; reset_watch_dog() ; display->cls() ; reset_watch_dog() ; display->set_font((unsigned char*) Arial24x23); display->foreground(Green) ; display->locate(70, 5) ; display->printf("Suntory") ; display->locate(30, 30) ; display->printf("Server Monitor") ; display->set_font((unsigned char*) Arial28x28); display->foreground(White) ; display->locate(30, 60) ; display->printf("La Suno") ; display->locate(30, 100) ; display->foreground(Red) ; display->printf("Preparing...") ; display->BusEnable(true) ; printf("Done\n") ; wait(0.1) ; reset_watch_dog() ; display->cls() ; display->foreground(Yellow) ; display->locate(40, 5) ; display->printf("Probing sensors...") ; display->foreground(Green) ; display->BusEnable(false) ; } reset_watch_dog() ; if (is_present(edge_i2c1, MMA8451Q_I2C_ADDRESS)) { printf("MMA8451Q on I2C1 is present\n") ; if (display) { display->BusEnable(true) ; display->locate(30, num_sensor * 30 + 40) ; display->printf("ACCEL is present") ; display->BusEnable(false) ; } mma8451q = new MMA8451Q(edge_i2c1, MMA8451Q_I2C_ADDRESS) ; accel = new edge_accel(mma8451q) ; sensor[SENSOR_ID_ACCEL] = accel ; sensor[SENSOR_ID_ACCEL]->setId(SENSOR_ID_ACCEL) ; num_sensor++ ; } else { sensor[SENSOR_ID_ACCEL] = 0 ; printf("MMA8451Q is absent\n") ; } reset_watch_dog() ; if (is_present(edge_i2c1, VEML6040_I2C_ADDRESS)) { printf("VEML6040 on I2C1 is present\n") ; if (display) { display->BusEnable(true) ; display->locate(30, num_sensor * 30 + 40) ; display->printf("COLOR1 is present") ; display->BusEnable(false) ; } veml6040[0] = new VEML6040(edge_i2c1, VEML6040_I2C_ADDRESS) ; led[0] = new PwmOut(PIN_LED_R) ; led[1] = new PwmOut(PIN_LED_G) ; led[2] = new PwmOut(PIN_LED_B) ; color[0] = new edge_color(veml6040[0], led, pwm) ; sensor[SENSOR_ID_COLOR1] = color[0] ; sensor[SENSOR_ID_COLOR1]->setId(SENSOR_ID_COLOR1) ; num_sensor++ ; } else { sensor[SENSOR_ID_COLOR1] = 0 ; printf("VEML6040 on I2C1 is absent\n") ; } reset_watch_dog() ; if (is_present(edge_i2c0, VEML6040_I2C_ADDRESS)) { printf("VEML6040 on I2C0 is present\n") ; if (display) { display->BusEnable(true) ; display->locate(30, num_sensor * 30 + 40) ; display->printf("COLOR2 is present") ; display->BusEnable(false) ; } veml6040[1] = new VEML6040(edge_i2c0, VEML6040_I2C_ADDRESS) ; if (led[0] == 0) { led[0] = new PwmOut(PIN_LED_R) ; led[1] = new PwmOut(PIN_LED_G) ; led[2] = new PwmOut(PIN_LED_B) ; } color[1] = new edge_color(veml6040[1], led, pwm) ; sensor[SENSOR_ID_COLOR2] = color[1] ; sensor[SENSOR_ID_COLOR2]->setId(SENSOR_ID_COLOR2) ; num_sensor++ ; } else { sensor[SENSOR_ID_COLOR2] = 0 ; printf("VEML6040 on I2C0 is absent\n") ; } reset_watch_dog() ; if (is_present(edge_i2c1, LM75B_I2C_ADDRESS)) { printf("LM75B on I2C1 is present\n") ; if (display) { display->BusEnable(true) ; display->locate(30, num_sensor * 30 + 40) ; display->printf("TEMP1 is present") ; display->BusEnable(false) ; } lm75b0 = new LM75B(edge_i2c1, LM75B_I2C_ADDRESS) ; } else { printf("LM75B on I2C1 is absent\n") ; } #if 0 if (is_present(edge_i2c0, LM75B_I2C_ADDRESS)) { printf("LM75B on I2C0 is present\n") ; lm75b1 = new LM75B(edge_i2c0, LM75B_I2C_ADDRESS) ; } else { printf("LM75B on I2C0 is absent\n") ; } #endif if (display) { /* press is present anyway */ display->BusEnable(true) ; if (lm75b0) { display->locate(30, (num_sensor+1) * 30 + 40) ; } else { display->locate(30, num_sensor * 30 + 40) ; } display->printf("PRESS is present") ; display->BusEnable(false) ; } reset_watch_dog() ; an0 = new AnalogIn(PIN_AN0) ; smtc502at0 = new SMTC502AT(an0) ; an1 = new AnalogIn(PIN_AN1) ; smtc502at1 = new SMTC502AT(an1) ; temp = new edge_temp(lm75b0, smtc502at0, smtc502at1, lm75b1) ; sensor[SENSOR_ID_TEMP] = temp ; sensor[SENSOR_ID_TEMP]->setId(SENSOR_ID_TEMP) ; num_sensor++ ; reset_watch_dog() ; an2 = new AnalogIn(PIN_AN2) ; pse530_en = new DigitalOut(PIN_PRESS_EN, 0) ; pse530 = new PSE530(an2) ; pressure = new edge_pressure(pse530, pse530_en) ; sensor[SENSOR_ID_PRESS] = pressure ; sensor[SENSOR_ID_PRESS]->setId(SENSOR_ID_PRESS) ; num_sensor++ ; reset_watch_dog() ; if (num_sensor > 0) { printf("%d edge_sensor(s) registered\n", num_sensor) ; printf("Edge is waiting for ASR to link\n") ; if (display) { display->BusEnable(true) ; display->foreground(White) ; display->locate(40, 200) ; display->printf("Waiting for ASR") ; display->BusEnable(false) ; } } reset_watch_dog() ; } void enable_sensors(void) { int i ; for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) { if (sensor[i]) { sensor[i]->enable() ; } } } void disable_sensors(void) { int i ; for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) { if (sensor[i]) { sensor[i]->disable() ; } } } void reboot_edge(void) { int i ; reset_watch_dog() ; disable_sensors() ; reset_watch_dog() ; if (display) { delete display ; display = 0 ; } for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) { if (sensor[i]) { reset_watch_dog() ; delete sensor[i] ; sensor[i] = 0 ; } } reset_watch_dog() ; software_reset() ; }