Help with Wire library for ARM board on 1.5.x IDE

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.

In case this is any use to anyone else...

I have fixed the problem.

See STM32, Maple and Maple mini port to IDE 1.5.x - #320 by rogerClark - Microcontrollers - Arduino Forum

The issue was that the Wire library written by LeafLabs was leaving SCL in the wrong state (low instead of high) if there was an error, mainly caused if an ACK was not received.