Skip to content

Wire (I2C) library: support 10 bits address mode #2468

Closed
@blazej222

Description

@blazej222

Describe the bug
When STM32 is I2C master, any beginTransmission(x) call for x like 0b1111 0xxx without write() call in between will cause subsequent endTransmission() call to return I2C_NACK, despite slave device sending ACK on SDA line.

This is due to the fact that STM32 automatically detects addresses starting with 0b1111 0xxx as 10 bit addresses, and in that case, does not set I2C_FLAG_ADDR flag which is being checked after sending the first byte of address.

hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress);
/* Wait until ADDR or AF flag are set */
/* Get tick */
tickstart = HAL_GetTick();
tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR);
tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);
while ((hi2c->State != HAL_I2C_STATE_TIMEOUT) && (tmp1 == RESET) && (tmp2 == RESET))
{
if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
{
hi2c->State = HAL_I2C_STATE_TIMEOUT;
}
tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR);
tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);
}
hi2c->State = HAL_I2C_STATE_READY;
/* Check if the ADDR flag has been set */
if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET)
{
/* Generate Stop */
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
/* Clear ADDR Flag */
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);

To Reproduce

I2C master code:

#include <Arduino.h>
#include <Wire.h>

HardwareSerial Serial1(PA10,PA9);
 
void setup() {
    Serial1.begin(115200);
    Wire.begin();    

}
 
void loop() {
        Wire.beginTransmission(0x79); 
        //Wire.write(1); //uncomment to receive ACK, but receive garbage on the other end
        int result = Wire.endTransmission();   
        Serial1.println(result);
        delay(1000);
 }

I2C slave code:

#include <Arduino.h>
#include <Wire.h>

HardwareSerial Serial1(PA10,PA9); //remove when testing on Arduino

void handleData(int bytes){
  byte data = Wire.read();
  Serial1.println(data); //change to Serial if testing on Arduino
}


void setup() {
  Serial1.begin(115200);  //change to Serial if testing on Arduino
  Wire.begin(0x79);
  Wire.onReceive(handleData);
  Serial1.println("Starting");  //change to Serial if testing on Arduino
}


void loop() {
}

Steps to reproduce the behavior:

  1. Connect STM32F103C8T6 (I2C Master) to another STM32F103C8T6/Arduino (I2C slave). (GND,SDA,SCL, RX/TX lines)
  2. Program STM32F103C8T6 as I2C master, another one/arduino as I2C slave.
  3. I2C master will report NACK despite having received ACK from slave device.

Additionally, if you uncomment Wire.write(1) call in I2C master code, I2C slave will report receiving a 242 byte, but only once and won't report again until reset.

This causes a simple example of I2C scanner ineffective for those addresses and ultimately makes communciation with those addresses impossible without modifying underlying framework's core code.

Expected behavior
I2C master should report ACK. With additional Wire.write() call uncommented, a slave device should report receiving 1 every one second.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions