Arduino_Core_STM32 icon indicating copy to clipboard operation
Arduino_Core_STM32 copied to clipboard

An error occurred in the communication between the stm32f103c8t6 and python smbus

Open AITCK opened this issue 4 years ago • 14 comments

The code I tested is below. python code:

import smbus
bus = smbus.SMBus(1)
# Read a block of 6 bytes from address 0x18, offset 0
data = bus.read_i2c_block_data(0x18, 0, 6) 

arduino code:

#include <Wire.h>

#define I2C_ADDR  0x18

void setup()
{
  Wire.begin(I2C_ADDR);         // join i2c bus with address #0x18
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(115200);           // start serial for output
}

void loop()
{
  //empty loop
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(0 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read();     // receive byte as a character
    Serial.print(c);          // print the character
  }
  int x = Wire.read();        // receive byte as an integer
  Serial.println(x);          // print the integer
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.write("hello\n");  // respond with message of 6 bytes
                          // as expected by master
}

Test Results: The code was successfully uploaded to stm32 without errors. When I run the python smbus code, 6 bytes of data were successfully read, but I did not see any information on the serial monitor.

I changed my bluepill to arduino nano for testing and the code runs successfully. The difference is that I saw the print data from the serial monitor. The printed data is exactly the offset parameter in the smbus code.

bus.read_i2c_block_data(address, offset, data size) 

In other words, the problem with stm32 i2c is that the offset parameter of smbus cannot be obtained.

AITCK avatar Jul 03 '21 13:07 AITCK

Hi @timaker Do you have pull up resistor (4.7KΩ) on each I2C Line ? It is mandatory to have them.

fpistm avatar Jul 04 '21 17:07 fpistm

Hi @timaker Do you have pull up resistor (4.7KΩ) on each I2C Line ? It is mandatory to have them.

Yes, I have soldered the pull-up resistor, and I2C can communicate normally

AITCK avatar Jul 05 '21 05:07 AITCK

Yes, I have soldered the pull-up resistor, and I2C can communicate normally

Does it means it is now OK ?

fpistm avatar Jul 05 '21 07:07 fpistm

If you have always the issue please give us more information as stated in the GH template else We could not help. Arduino IDE version? Core version? Board selected? Options if not the default? Did you test the Serial before ? All relevant information.

fpistm avatar Jul 05 '21 15:07 fpistm

I mean, Bluepill and Arduino Nano are used differently in I2C slave mode, and I'm running the SMBUS code on Raspberry Pi and requesting 6 bytes of data. BluePill does not receive the parameter of offset. However, the same Arduino code burned on Arduino Nano can receive the parameter of offset. In Python code, I need to set different offset parameters so that I can read different data, but STM32 doesn't know what my offset parameter is, so the slave can't tell what the master is requesting. The master sends the offset parameter to the STM32 slave, and then the master sends a command requesting data. The STM32 can then use the offset parameter to determine what data to send to the master. However, I still hope that when my Bluepill and Arduino Nano run the same program, the result will be the same, instead of Bluepill not receiving offset parameter.

AITCK avatar Jul 05 '21 19:07 AITCK

Ok but you don't provide info requested:

If you have always the issue please give us more information as stated in the GH template else We could not help. Arduino IDE version? Core version? Board selected? Options if not the default? Did you test the Serial before ? All relevant information.

fpistm avatar Jul 05 '21 19:07 fpistm

Ok but you don't provide info requested:

If you have always the issue please give us more information as stated in the GH template else We could not help. Arduino IDE version? Core version? Board selected? Options if not the default? Did you test the Serial before ? All relevant information.

Desktop (please complete the following information):

  • OS: Windows
  • Arduino IDE version: 1.8.13
  • STM32 core version: 2.0.0
  • Tools menu settings if not the default: default
  • Upload method: SWD

Board (please complete the following information):

  • Name: Generic STM32F1 series
  • Hardware Revision: BLUEPILL_F103C8
  • Extra hardware used if any: no

Additional context Serial is ok,when i send the data to stm32,the serial monitor can see the print data.

AITCK avatar Jul 06 '21 06:07 AITCK

HI @timaker I think one issue could be the usage of Serial.println() in the ISR. Serial also used IT with higher priority. Could you try to store the read value and print them in the loop.

fpistm avatar Jul 13 '21 16:07 fpistm

HI @timaker I think one issue could be the usage of Serial.println() in the ISR. Serial also used IT with higher priority. Could you try to store the read value and print them in the loop.

I tried to store the read data and print it in the loop, but the smbus offset data was not printed. The test code and test results are as follows. Snipaste_2021-07-15_11-37-36 Snipaste_2021-07-15_11-38-07

Arduino code:

#include <Arduino.h>
#include <Wire.h>
#define I2C_ADDR 0x18
String value = "";
void setup()
{
    Serial.begin(115200);
    Wire.begin(I2C_ADDR);
    Wire.onRequest(requestEvent);
    Wire.onReceive(receiveEvent);
}
void loop()
{
    Serial.println(value);
    Serial.println("...");
    delay(1000);
}
void receiveEvent(int howMany)
{
    while (0 < Wire.available())
    {
        value += Wire.read(); // Store the offset parameter value
    }
}
void requestEvent()
{
    Wire.write("hello\n"); // Send data to master
}

Python code:

import smbus
import time

bus = smbus.SMBus(1)
addr = 0x18
data = bus.read_i2c_block_data(addr, 0, 6)
print(''.join(chr(i) for i in data))

AITCK avatar Jul 15 '21 03:07 AITCK

Hi @timaker We found an "issue" btw a Jetson nano and a STM32 with I2C. It seems the stretching cause some trouble. Could you try to change this line:

https://github.com/stm32duino/Arduino_Core_STM32/blob/25d5d1e44569ef5ef0f80148fa25ed2021124ced/libraries/Wire/src/utility/twi.c#L769

-        handle->Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
+        handle->Init.NoStretchMode   = I2C_NOSTRETCH_ENABLE;

fpistm avatar Sep 06 '21 08:09 fpistm

Hi @timaker We found an "issue" btw a Jetson nano and a STM32 with I2C. It seems the stretching cause some trouble. Could you try to change this line:

https://github.com/stm32duino/Arduino_Core_STM32/blob/25d5d1e44569ef5ef0f80148fa25ed2021124ced/libraries/Wire/src/utility/twi.c#L769

-        handle->Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;
+        handle->Init.NoStretchMode   = I2C_NOSTRETCH_ENABLE;

When I set the I2C_NOSTRETCH_ENABLE,The I2C slave cannot work properly.

I looked up some information about it.

NoStretchMode: This member is about I2C disable clock extension mode Settings, used to disable clock extension in slave mode. It must remain off in main mode.

AITCK avatar Sep 10 '21 04:09 AITCK

Have you solved your problem?

  • Pull-up resistors are necessary, we use 6.8k in both clock and data lines.
  • Disable stretching and PEC.
  • use HAL_SMBUS_Master_Transmit_IT HAL_SMBUS_Master_Receive_IT functions with Option of transfer as SMBUS_FIRST_AND_LAST_FRAME_NO_PEC

mucahitdemir avatar Apr 20 '22 11:04 mucahitdemir

thanks I used a trick and can read stm32 data normally. The method is to first send a command to stm32, stm32 will receive the command normally, process it, prepare the data I need to read, and then read the data sent by stm32. This method is cumbersome and slow, but it does work for stm32.

python code:

import smbus
import time

bus = smbus.SMBus(1)
addr = 0x18

bus.write_i2c_data(addr, 0)
time.sleep(0.05)
data = bus.read_i2c_block_data(addr, 0, 6)

print(''.join(chr(i) for i in data))

AITCK avatar Jun 16 '22 15:06 AITCK

It is the way of communication with SMBUS.

mucahitdemir avatar Jun 16 '22 15:06 mucahitdemir