Merge pull request #40 from earlephilhower/i2c0
Fix INPUT_PULLUP/DOWN, I2C 0-len probes, timeout
This commit is contained in:
commit
33dc16d033
3 changed files with 97 additions and 24 deletions
|
|
@ -21,6 +21,8 @@
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include <hardware/gpio.h>
|
#include <hardware/gpio.h>
|
||||||
|
|
||||||
|
static PinMode _pm[30];
|
||||||
|
|
||||||
extern "C" void pinMode( pin_size_t ulPin, PinMode ulMode ) {
|
extern "C" void pinMode( pin_size_t ulPin, PinMode ulMode ) {
|
||||||
switch (ulMode) {
|
switch (ulMode) {
|
||||||
case INPUT:
|
case INPUT:
|
||||||
|
|
@ -31,11 +33,13 @@ extern "C" void pinMode( pin_size_t ulPin, PinMode ulMode ) {
|
||||||
gpio_init(ulPin);
|
gpio_init(ulPin);
|
||||||
gpio_set_dir(ulPin, false);
|
gpio_set_dir(ulPin, false);
|
||||||
gpio_pull_up(ulPin);
|
gpio_pull_up(ulPin);
|
||||||
|
gpio_put(ulPin, 0);
|
||||||
break;
|
break;
|
||||||
case INPUT_PULLDOWN:
|
case INPUT_PULLDOWN:
|
||||||
gpio_init(ulPin);
|
gpio_init(ulPin);
|
||||||
gpio_set_dir(ulPin, false);
|
gpio_set_dir(ulPin, false);
|
||||||
gpio_pull_down(ulPin);
|
gpio_pull_down(ulPin);
|
||||||
|
gpio_put(ulPin, 1);
|
||||||
break;
|
break;
|
||||||
case OUTPUT:
|
case OUTPUT:
|
||||||
gpio_init(ulPin);
|
gpio_init(ulPin);
|
||||||
|
|
@ -43,16 +47,23 @@ extern "C" void pinMode( pin_size_t ulPin, PinMode ulMode ) {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Error
|
// Error
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
_pm[ulPin] = ulMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void digitalWrite( pin_size_t ulPin, PinStatus ulVal ) {
|
extern "C" void digitalWrite( pin_size_t ulPin, PinStatus ulVal ) {
|
||||||
if (!gpio_is_dir_out(ulPin)) {
|
if (_pm[ulPin] == INPUT_PULLDOWN) {
|
||||||
if (ulVal == LOW) {
|
if (ulVal == LOW) {
|
||||||
gpio_pull_down(ulPin);
|
gpio_set_dir(ulPin, false);
|
||||||
} else {
|
} else {
|
||||||
gpio_pull_up(ulPin);
|
gpio_set_dir(ulPin, true);
|
||||||
|
}
|
||||||
|
} else if (_pm[ulPin] == INPUT_PULLUP) {
|
||||||
|
if (ulVal == HIGH) {
|
||||||
|
gpio_set_dir(ulPin, false);
|
||||||
|
} else {
|
||||||
|
gpio_set_dir(ulPin, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gpio_put(ulPin, ulVal == LOW ? 0 : 1);
|
gpio_put(ulPin, ulVal == LOW ? 0 : 1);
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t byteRead = 0;
|
size_t byteRead = 0;
|
||||||
_buffLen = i2c_read_blocking(_i2c, address, _buff, quantity, !stopBit);
|
_buffLen = i2c_read_blocking_until(_i2c, address, _buff, quantity, !stopBit, make_timeout_time_ms(50));
|
||||||
_buffOff = 0;
|
_buffOff = 0;
|
||||||
return _buffLen;
|
return _buffLen;
|
||||||
}
|
}
|
||||||
|
|
@ -189,6 +189,63 @@ size_t TwoWire::requestFrom(uint8_t address, size_t quantity) {
|
||||||
return requestFrom(address, quantity, true);
|
return requestFrom(address, quantity, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _clockStretch(pin_size_t pin) {
|
||||||
|
auto end = time_us_64() + 100;
|
||||||
|
while ((time_us_64() < end) && (!digitalRead(pin))) { /* noop */ }
|
||||||
|
return digitalRead(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _probe(int addr, pin_size_t sda, pin_size_t scl, int freq) {
|
||||||
|
int delay = (1000000 / freq) / 2;
|
||||||
|
bool ack = false;
|
||||||
|
|
||||||
|
pinMode(sda, INPUT_PULLUP);
|
||||||
|
pinMode(scl, INPUT_PULLUP);
|
||||||
|
gpio_set_function(scl, GPIO_FUNC_SIO);
|
||||||
|
gpio_set_function(sda, GPIO_FUNC_SIO);
|
||||||
|
|
||||||
|
digitalWrite(sda, HIGH);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, HIGH);
|
||||||
|
if (!_clockStretch(scl)) goto stop;
|
||||||
|
digitalWrite(sda, LOW);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, LOW);
|
||||||
|
sleep_us(delay);
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
addr <<= 1;
|
||||||
|
digitalWrite(sda, (addr & (1<<7)) ? HIGH : LOW);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, HIGH);
|
||||||
|
sleep_us(delay);
|
||||||
|
if (!_clockStretch(scl)) goto stop;
|
||||||
|
digitalWrite(scl, LOW);
|
||||||
|
sleep_us(5); // Ensure we don't change too close to clock edge
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(sda, HIGH);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, HIGH);
|
||||||
|
if (!_clockStretch(scl)) goto stop;
|
||||||
|
|
||||||
|
ack = digitalRead(sda) == LOW;
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, LOW);
|
||||||
|
|
||||||
|
stop:
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(sda, LOW);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(scl, HIGH);
|
||||||
|
sleep_us(delay);
|
||||||
|
digitalWrite(sda, HIGH);
|
||||||
|
sleep_us(delay);
|
||||||
|
gpio_set_function(scl, GPIO_FUNC_I2C);
|
||||||
|
gpio_set_function(sda, GPIO_FUNC_I2C);
|
||||||
|
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
// Errors:
|
// Errors:
|
||||||
// 0 : Success
|
// 0 : Success
|
||||||
// 1 : Data too long
|
// 1 : Data too long
|
||||||
|
|
@ -196,14 +253,19 @@ size_t TwoWire::requestFrom(uint8_t address, size_t quantity) {
|
||||||
// 3 : NACK on transmit of data
|
// 3 : NACK on transmit of data
|
||||||
// 4 : Other error
|
// 4 : Other error
|
||||||
uint8_t TwoWire::endTransmission(bool stopBit) {
|
uint8_t TwoWire::endTransmission(bool stopBit) {
|
||||||
if (!_running || !_txBegun || !_buffLen) {
|
if (!_running || !_txBegun) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
auto len = _buffLen;
|
|
||||||
auto ret = i2c_write_blocking(_i2c, _addr, _buff, _buffLen, !stopBit);
|
|
||||||
_buffLen = 0;
|
|
||||||
_txBegun = false;
|
_txBegun = false;
|
||||||
return (ret == len) ? 0 : 4;
|
if (!_buffLen) {
|
||||||
|
// Special-case 0-len writes which are used for I2C probing
|
||||||
|
return _probe(_addr, _sda, _scl, _clkHz) ? 0 : 2;
|
||||||
|
} else {
|
||||||
|
auto len = _buffLen;
|
||||||
|
auto ret = i2c_write_blocking_until(_i2c, _addr, _buff, _buffLen, !stopBit, make_timeout_time_ms(50));
|
||||||
|
_buffLen = 0;
|
||||||
|
return (ret == len) ? 0 : 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t TwoWire::endTransmission() {
|
uint8_t TwoWire::endTransmission() {
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,11 @@ public:
|
||||||
TwoWire(i2c_inst_t *i2c, pin_size_t sda, pin_size_t scl);
|
TwoWire(i2c_inst_t *i2c, pin_size_t sda, pin_size_t scl);
|
||||||
|
|
||||||
// Start as Master
|
// Start as Master
|
||||||
void begin();
|
void begin() override;
|
||||||
// Start as Slave
|
// Start as Slave
|
||||||
void begin(uint8_t address);
|
void begin(uint8_t address) override;
|
||||||
// Shut down the I2C interface
|
// Shut down the I2C interface
|
||||||
void end();
|
void end() override;
|
||||||
|
|
||||||
// Select IO pins to use. Call before ::begin()
|
// Select IO pins to use. Call before ::begin()
|
||||||
bool setSDA(pin_size_t sda);
|
bool setSDA(pin_size_t sda);
|
||||||
|
|
@ -52,20 +52,20 @@ public:
|
||||||
|
|
||||||
void setClock(uint32_t freqHz) override;
|
void setClock(uint32_t freqHz) override;
|
||||||
|
|
||||||
void beginTransmission(uint8_t);
|
void beginTransmission(uint8_t) override;
|
||||||
uint8_t endTransmission(bool stopBit);
|
uint8_t endTransmission(bool stopBit) override;
|
||||||
uint8_t endTransmission(void);
|
uint8_t endTransmission(void) override;
|
||||||
|
|
||||||
size_t requestFrom(uint8_t address, size_t quantity, bool stopBit);
|
size_t requestFrom(uint8_t address, size_t quantity, bool stopBit) override;
|
||||||
size_t requestFrom(uint8_t address, size_t quantity);
|
size_t requestFrom(uint8_t address, size_t quantity) override;
|
||||||
|
|
||||||
size_t write(uint8_t data);
|
size_t write(uint8_t data) override;
|
||||||
size_t write(const uint8_t * data, size_t quantity);
|
size_t write(const uint8_t * data, size_t quantity) override;
|
||||||
|
|
||||||
virtual int available(void);
|
virtual int available(void) override;
|
||||||
virtual int read(void);
|
virtual int read(void) override;
|
||||||
virtual int peek(void);
|
virtual int peek(void) override;
|
||||||
virtual void flush(void);
|
virtual void flush(void) override;
|
||||||
void onReceive(void(*)(int));
|
void onReceive(void(*)(int));
|
||||||
void onRequest(void(*)(void));
|
void onRequest(void(*)(void));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue