1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-02-17 06:29:15 +01:00

IO_VL53L0X: Some bug fixes.

Modify state model, and improve recovery after <D HAL RESET>.
This commit is contained in:
Neil McKechnie 2023-02-10 15:32:41 +00:00
parent 5f9705d1b7
commit f358880f30

View File

@ -48,7 +48,7 @@
* using a distinct I2C address. The process is described in ST Microelectronics application * using a distinct I2C address. The process is described in ST Microelectronics application
* note AN4846. * note AN4846.
* *
* WARNING: If the device's XSHUT pin is not connected, then it is very prone to noise, * WARNING: If the device's XSHUT pin is not connected, then it may be prone to noise,
* and the device may reset spontaneously or when handled and the device will stop responding * and the device may reset spontaneously or when handled and the device will stop responding
* on its allocated address. If you're not using XSHUT, then tie it to +5V via a resistor * on its allocated address. If you're not using XSHUT, then tie it to +5V via a resistor
* (should be tied to +2.8V strictly). Some manufacturers (Adafruit and Polulu for example) * (should be tied to +2.8V strictly). Some manufacturers (Adafruit and Polulu for example)
@ -112,16 +112,15 @@ private:
// State machine states. // State machine states.
enum : uint8_t { enum : uint8_t {
STATE_INIT = 0, STATE_INIT,
STATE_RESTARTMODULE = 1, STATE_RESTARTMODULE,
STATE_CONFIGUREADDRESS = 2, STATE_CONFIGUREADDRESS,
STATE_SKIP = 3, STATE_CONFIGUREDEVICE,
STATE_CONFIGUREDEVICE = 4, STATE_INITIATESCAN,
STATE_INITIATESCAN = 5, STATE_CHECKSTATUS,
STATE_CHECKSTATUS = 6, STATE_GETRESULTS,
STATE_GETRESULTS = 7, STATE_DECODERESULTS,
STATE_DECODERESULTS = 8, STATE_FAILED,
STATE_FAILED = 9,
}; };
// Register addresses // Register addresses
@ -156,24 +155,25 @@ protected:
// the device will not respond on its default address if it has // the device will not respond on its default address if it has
// already been changed. Therefore, we skip the address configuration if the // already been changed. Therefore, we skip the address configuration if the
// desired address is already responding on the I2C bus. // desired address is already responding on the I2C bus.
if (_xshutPin == VPIN_NONE && I2CManager.exists(_I2CAddress)) { _nextState = STATE_INIT;
// Device already present on this address, so skip the address initialisation. _addressConfigInProgress = false;
_nextState = STATE_CONFIGUREDEVICE;
} else
_nextState = STATE_INIT;
} }
void _loop(unsigned long currentMicros) override { void _loop(unsigned long currentMicros) override {
uint8_t status; uint8_t status;
switch (_nextState) { switch (_nextState) {
case STATE_INIT: case STATE_INIT:
// On first entry to loop, reset this module by pulling XSHUT low. Each module if (I2CManager.exists(_I2CAddress)) {
// will be addressed in turn, until all are in the reset state. // Device already present on the nominated address, so skip the address initialisation.
// If no XSHUT pin is configured, then only one device is supported. _nextState = STATE_CONFIGUREDEVICE;
if (_xshutPin != VPIN_NONE) IODevice::write(_xshutPin, 0); } else {
_nextState = STATE_RESTARTMODULE; // On first entry to loop, reset this module by pulling XSHUT low. Each module
delayUntil(currentMicros+10000); // will be addressed in turn, until all are in the reset state.
// If no XSHUT pin is configured, then only one device is supported.
if (_xshutPin != VPIN_NONE) IODevice::write(_xshutPin, 0);
_nextState = STATE_RESTARTMODULE;
delayUntil(currentMicros+10000);
}
break; break;
case STATE_RESTARTMODULE: case STATE_RESTARTMODULE:
// On second entry, set XSHUT pin high to allow this module to restart. // On second entry, set XSHUT pin high to allow this module to restart.
@ -183,13 +183,14 @@ protected:
// instead of driving the output directly. // instead of driving the output directly.
// Ensure XSHUT is set for only one module at a time by using a // Ensure XSHUT is set for only one module at a time by using a
// shared flag accessible to all device instances. // shared flag accessible to all device instances.
if (_addressConfigInProgress) return; if (!_addressConfigInProgress) {
_addressConfigInProgress = true; _addressConfigInProgress = true;
// Set XSHUT pin (if connected) to bring the module out of sleep mode. // Set XSHUT pin (if connected) to bring the module out of sleep mode.
if (_xshutPin != VPIN_NONE) IODevice::write(_xshutPin, 1); if (_xshutPin != VPIN_NONE) IODevice::configureInput(_xshutPin, true);
// Allow the module time to restart // Allow the module time to restart
delayUntil(currentMicros+10000); delayUntil(currentMicros+10000);
_nextState = STATE_CONFIGUREADDRESS; _nextState = STATE_CONFIGUREADDRESS;
}
break; break;
case STATE_CONFIGUREADDRESS: case STATE_CONFIGUREADDRESS:
// Then write the desired I2C address to the device, while this is the only // Then write the desired I2C address to the device, while this is the only
@ -198,12 +199,16 @@ protected:
#if defined(I2C_EXTENDED_ADDRESS) #if defined(I2C_EXTENDED_ADDRESS)
// Add subbus reference for desired address to the device default address. // Add subbus reference for desired address to the device default address.
I2CAddress defaultAddress = {_I2CAddress, VL53L0X_I2C_DEFAULT_ADDRESS}; I2CAddress defaultAddress = {_I2CAddress, VL53L0X_I2C_DEFAULT_ADDRESS};
I2CManager.write(defaultAddress, 2, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS, _I2CAddress.deviceAddress()); status = I2CManager.write(defaultAddress, 2, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS, _I2CAddress.deviceAddress());
#else #else
I2CManager.write(VL53L0X_I2C_DEFAULT_ADDRESS, 2, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS, _I2CAddress); status = I2CManager.write(VL53L0X_I2C_DEFAULT_ADDRESS, 2, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS, _I2CAddress);
#endif #endif
if (status != I2C_STATUS_OK) {
reportError(status);
}
} }
delayUntil(currentMicros+10000); delayUntil(currentMicros+10000);
_nextState = STATE_CONFIGUREDEVICE;
break; break;
case STATE_CONFIGUREDEVICE: case STATE_CONFIGUREDEVICE:
// Allow next VL53L0X device to be configured // Allow next VL53L0X device to be configured
@ -214,9 +219,12 @@ protected:
_display(); _display();
#endif #endif
// Set 2.8V mode // Set 2.8V mode
write_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV, status = write_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
read_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); read_reg(VL53L0X_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01);
_nextState = STATE_INITIATESCAN; if (status != I2C_STATUS_OK) {
reportError(status);
} else
_nextState = STATE_INITIATESCAN;
} else { } else {
DIAG(F("VL53L0X I2C:%s device not responding"), _I2CAddress.toString()); DIAG(F("VL53L0X I2C:%s device not responding"), _I2CAddress.toString());
_deviceState = DEVSTATE_FAILED; _deviceState = DEVSTATE_FAILED;
@ -235,7 +243,6 @@ protected:
if (status == I2C_STATUS_PENDING) return; // try next time if (status == I2C_STATUS_PENDING) return; // try next time
if (status != I2C_STATUS_OK) { if (status != I2C_STATUS_OK) {
reportError(status); reportError(status);
_nextState = STATE_FAILED;
} else } else
_nextState = STATE_GETRESULTS; _nextState = STATE_GETRESULTS;
delayUntil(currentMicros + 95000); // wait for 95 ms before checking. delayUntil(currentMicros + 95000); // wait for 95 ms before checking.
@ -244,7 +251,6 @@ protected:
// Ranging completed. Request results // Ranging completed. Request results
_outBuffer[0] = VL53L0X_REG_RESULT_RANGE_STATUS; _outBuffer[0] = VL53L0X_REG_RESULT_RANGE_STATUS;
I2CManager.read(_I2CAddress, _inBuffer, 12, _outBuffer, 1, &_rb); I2CManager.read(_I2CAddress, _inBuffer, 12, _outBuffer, 1, &_rb);
_nextState = 3;
delayUntil(currentMicros + 5000); // Allow 5ms to get data delayUntil(currentMicros + 5000); // Allow 5ms to get data
_nextState = STATE_DECODERESULTS; _nextState = STATE_DECODERESULTS;
break; break;
@ -269,7 +275,6 @@ protected:
_nextState = STATE_INITIATESCAN; _nextState = STATE_INITIATESCAN;
} else { } else {
reportError(status); reportError(status);
_nextState = STATE_FAILED;
} }
break; break;
case STATE_FAILED: case STATE_FAILED:
@ -281,7 +286,7 @@ protected:
} }
} }
// Function to report a failed I2C operation. Put the device off-line. // Function to report a failed I2C operation.
void reportError(uint8_t status) { void reportError(uint8_t status) {
DIAG(F("VL53L0X I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status)); DIAG(F("VL53L0X I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status));
_deviceState = DEVSTATE_FAILED; _deviceState = DEVSTATE_FAILED;