Hi,
I'm trying to fix an issue with an ARM implementation of Wire for the STM32F103 processor.
I'm using the Arduino 1.5.x IDE with the STM32F103 processor on a board similar to the LeafLabs maple-mini and most things seem to work OK (because of the original hard work put in my LeafLabs)
Wire generally works, it uses a bit-banged implementation at the moment, however the I2CScanner demo from the Arduino Playground doesn't work.
Looking at how the scanner works, it calls beginTransmission() followed straight away by endTransmission() and looks for the response
In the LeafLabs code there was a problem firstly because endTransmission was hard coded to return SUCCESS (0) all the time, so I modified this so that it passes back the response from a sub function called process e.g.
uint8 WireBase::endTransmission(void) {
uint8 retVal;
if (tx_buf_overflow) {
return EDATA;
}
retVal=process();// Changed so that the return value from process is returned by this function see also the return line below
tx_buf_idx = 0;
tx_buf_overflow = false;
return retVal;//SUCCESS;
}
Wirebase is the base class the TwoWire uses in this implementation
Process() looks like this
uint8 TwoWire::process() {
itc_msg.xferred = 0;
uint8 sla_addr = (itc_msg.addr << 1);
if (itc_msg.flags == I2C_MSG_READ) {
sla_addr |= I2C_READ;
}
i2c_start();
// shift out the address we're transmitting to
i2c_shift_out(sla_addr);
if (!i2c_get_ack()) {
return ENACKADDR;
}
// Recieving
if (itc_msg.flags == I2C_MSG_READ) {
while (itc_msg.xferred < itc_msg.length) {
itc_msg.data[itc_msg.xferred++] = i2c_shift_in();
if (itc_msg.xferred < itc_msg.length) {
i2c_send_ack();
} else {
i2c_send_nack();
}
}
}
// Sending
else {
for (uint8 i = 0; i < itc_msg.length; i++) {
i2c_shift_out(itc_msg.data[i]);
if (!i2c_get_ack()) {
return ENACKTRNS;
}
itc_msg.xferred++;
}
}
i2c_stop();
return SUCCESS;
}
and importantly to this issue, this is what checks for ack
bool TwoWire::i2c_get_ack() {
set_scl(LOW);
set_sda(HIGH);
set_scl(HIGH);
bool ret = !digitalRead(this->sda_pin);
set_scl(LOW);
return ret;
}
in process()
if (!i2c_get_ack()) {
return ENACKADDR;
}
It looks like if SDA is high after its been clocked out with a HIGH state, then thats a NACK
Now I can see in the code
pinMode(this->sda_pin, OUTPUT_OPEN_DRAIN);
So perhaps this is the issue..
I'm really not sure
Can someone tell me the correct way to check for NACK after the devce address has been clocked out, or if they can see what else is wrong with this code
Thanks
Roger
always fails and returns ENACKADDR in response to the device address being clocked out.
Now... set SDA just uses digital write.
void TwoWire::set_sda(bool state) {
I2C_DELAY(this->i2c_delay);
digitalWrite(this->sda_pin, state);
}
However I don't understand what is supposed to happen, after the device address is clocked out and then SDA is set to high and the clock toggled.