[SOLVED] I2C2 on STM32F103C8T6 and HWire

Generic boards that are not Maple or Maple mini clones, and don't contain the additional USB reset hardware
luca_stm32
Posts: 17
Joined: Wed Apr 26, 2017 12:39 pm

[SOLVED] I2C2 on STM32F103C8T6 and HWire

Post by luca_stm32 » Mon Jun 12, 2017 7:50 pm

This is my first post in the forum :-)
I'm trying to use HWire on I2C2 of my Bluepill to read/wire an external EEprom (24LC128).
I connected the EEprom on PB10 (SCL) and PB11 (SDA): if I use software version of I2C it works. If I use HWire it doesn't work.
Bye the way: I downloaded last version of repository and I found an error on line 79 of Arduino_STM32/STM32F1/libraries/Wire/HardWire.cpp file: missing a ":" in void HardWire:end().

I used this code commenting the right lines (hardware or software I2C)... sorry for my bad engish:

Code: Select all

//#include <Wire.h>
#include <HardWire.h>
 
#define EEPROM_ADDRESS 0x50    //Address of 24LC256 eeprom chip
//Declare the instance that the users of the library can use
//TwoWire Wire(SCL, SDA, SOFT_STANDARD);  
//TwoWire Wire2(PB10, PB11, SOFT_STANDARD);

HardWire HWire(2, I2C_FAST_MODE); // I2C2
void setup(void)
{
  Serial.begin(115200);
  delay(10000);
  Serial.println("EEPROM Test");
  //Wire2.begin();
  HWire.begin();
 
  unsigned int address = 0;
 
  writeEEPROM(EEPROM_ADDRESS, address, 0x55);
  while(1){
  Serial.print(readEEPROM(EEPROM_ADDRESS, address), HEX);
  Serial.print(" ");
  address++;
  delay(1000);    
  }

}
 
void loop(){}
 
void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) 
{
//  Wire2.beginTransmission(deviceaddress);
//  Wire2.write((int)(eeaddress >> 8));   // MSB
//  Wire2.write((int)(eeaddress & 0xFF)); // LSB
//  Wire2.write(data);
//  Wire2.endTransmission();
  HWire.beginTransmission(deviceaddress);
  HWire.write((int)(eeaddress >> 8));   // MSB
  HWire.write((int)(eeaddress & 0xFF)); // LSB
  HWire.write(data);
  HWire.endTransmission();
 
  delay(5);
}
 
byte readEEPROM(int deviceaddress, unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
 
//  Wire2.beginTransmission(deviceaddress);
//  Wire2.write((int)(eeaddress >> 8));   // MSB
//  Wire2.write((int)(eeaddress & 0xFF)); // LSB
//  Wire2.endTransmission();
// 
//  Wire2.requestFrom(deviceaddress,1);

  HWire.beginTransmission(deviceaddress);
  HWire.write((int)(eeaddress >> 8));   // MSB
  HWire.write((int)(eeaddress & 0xFF)); // LSB
  HWire.endTransmission();
 
  HWire.requestFrom(deviceaddress,1);
 
//  if (Wire2.available()) rdata = Wire2.read();
  if (HWire.available()) rdata = HWire.read();

  return rdata;
}
Software I2C implementation works, so I'm sure hardware is ok.
Has anyone tried hardware I2C2?
I2C2 is on the same pins of USART3: could this be the problem?

In my design, I can't connect I2C1 with EEprom, I need I2C2 and I would like to use hardware implementation.

Thanks for your time.
Regards.
Luca.
Last edited by luca_stm32 on Mon Jun 26, 2017 7:20 pm, edited 1 time in total.

stevestrong
Posts: 1521
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: I2C2 on STM32F103C8T6 and HWire

Post by stevestrong » Mon Jun 12, 2017 8:11 pm

And what exactly does not work?
Please give detailed error description.

User avatar
Pito
Posts: 1502
Joined: Sat Mar 26, 2016 3:26 pm
Location: Rapa Nui

Re: I2C2 on STM32F103C8T6 and HWire

Post by Pito » Mon Jun 12, 2017 8:42 pm

HWire on I2C2 works here at least with MapleM, so it has to with BP.
Look at an existing eeprom library how the stuff works.
Pukao Hats Cleaning Services Ltd.

luca_stm32
Posts: 17
Joined: Wed Apr 26, 2017 12:39 pm

Re: I2C2 on STM32F103C8T6 and HWire

Post by luca_stm32 » Tue Jun 13, 2017 8:35 am

Hi Stevestrong.
The code writes a welcome message on termianl (EEPROM Test), then writes 0x55 on location 0 of EEPROM, then write on terminal window all the values of EERPOM locations starting from location 0 with a delay of one second.
With "software" version on terminal I can see the welcome message and then 0x55 0xFF 0xFF....
With "hardware" version I can see only welcome message.
I used a scope to see the activity on SCL line, but with the "hardware" code version nothing happens (it is fixed at 3.3V and no clock activity appears).

@Pito.
In an your previous post I saw that you used I2C2 with hardware implementation. My concern is the error I found in HardWire.cpp file. Mybe your version of Hwire library is slightly different... I could make a test using a previous version of repository.
Just to be sure: I2C2 is on PB10 (SCL2) and PB11 (SDA2), correct?

Thanks again for your support.
Luca

luca_stm32
Posts: 17
Joined: Wed Apr 26, 2017 12:39 pm

Re: I2C2 on STM32F103C8T6 and HWire

Post by luca_stm32 » Tue Jun 13, 2017 8:07 pm

Hi everybody.
Another little step.
In file HardWire.cpp I modified HardWire::process in this way:

Code: Select all

uint8 HardWire::process() {
	Serial.println("1");
    int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0);
	Serial.println("2");
    if (res == I2C_ERROR_PROTOCOL) {
        if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */
            res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : 
                                                          ENACKTRNS);
        } else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */
            res = EDATA;
        } else { /* Bus or Arbitration error */
            res = EOTHER;
        }
        i2c_disable(sel_hard);
        i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags));
    }
    return res;
}
On terminal I can see 1 but not 2. The 4th argument of i2c_master_xfer function is timeout and it is set to 0 (no timeout).

zmemw16
Posts: 1380
Joined: Wed Jul 08, 2015 2:09 pm
Location: St Annes, Lancs,UK

Re: I2C2 on STM32F103C8T6 and HWire

Post by zmemw16 » Tue Jun 13, 2017 8:55 pm

timeouts can be strange, setting to zero usually means wait for infinity, not go back immediately :D

Winnie_The_Pooh
Posts: 5
Joined: Mon Oct 24, 2016 10:31 am

Re: I2C2 on STM32F103C8T6 and HWire

Post by Winnie_The_Pooh » Thu Jun 15, 2017 6:40 am

Hi!

A year ago I've tested I2C second channel using HARDWIRE lib and after massive testing with logic analyzer and test points after every operator found out that I must use correct var size using I2C2.

I.e. instead of int you should use int16_t or uint8_t.

I2C1 works without it, but I2C2 works only with strict and correct var size int16_t or uint8_t

Including working example #1:

Code: Select all

//#include <Wire.h>
#include <HardWire.h> 
#define START PB0


HardWire HWire(2, I2C_FAST_MODE); // I2c1 , I2C_FAST_MODE SOFT_STANDARD 


void setup() {
  
  HWire.begin();
  Serial.begin(115200);

  pinMode(START, OUTPUT); //синхроимпульс для лог анализатора
    digitalWrite(START,HIGH);
    delay(1);
    digitalWrite(START,LOW);
 
}
 
void loop() {
 

 Serial.print("Light (lux):    ");
 Serial.println(get_lux());
 delay(1000);

}

uint8_t read_register(uint8_t addr) {

uint8_t ret;

    digitalWrite(START,HIGH);
    delay(1);
    digitalWrite(START,LOW);
 
  HWire.beginTransmission(0x4A);
  HWire.write(addr);
  HWire.endTransmission();
   
  HWire.requestFrom(0x4A,1);
ret =   HWire.read();
digitalWrite(START,HIGH);

  return ret;
}


float get_lux(void)
{
  int luxHigh = read_register(0x03);
  
  int luxLow = read_register(0x04);
  
  int exponent = (luxHigh & 0xf0) >> 4;
  
  int mant = (luxHigh & 0x0f) << 4 | luxLow;
  
  
  return (float)(((0x00000001 << exponent) * (float)mant) * 0.045);
  //return (float)((pow(2,exponent) * mant) * 0.045);
 
}
and example #2:

Code: Select all

#define BMP085_I2CADDR 0x77

#define BMP085_ULTRALOWPOWER 0
#define BMP085_STANDARD      1
#define BMP085_HIGHRES       2
#define BMP085_ULTRAHIGHRES  3
#define BMP085_CAL_AC1           0xAA  // R   Calibration data (16 bits)
#define BMP085_CAL_AC2           0xAC  // R   Calibration data (16 bits)
#define BMP085_CAL_AC3           0xAE  // R   Calibration data (16 bits)    
#define BMP085_CAL_AC4           0xB0  // R   Calibration data (16 bits)
#define BMP085_CAL_AC5           0xB2  // R   Calibration data (16 bits)
#define BMP085_CAL_AC6           0xB4  // R   Calibration data (16 bits)
#define BMP085_CAL_B1            0xB6  // R   Calibration data (16 bits)
#define BMP085_CAL_B2            0xB8  // R   Calibration data (16 bits)
#define BMP085_CAL_MB            0xBA  // R   Calibration data (16 bits)
#define BMP085_CAL_MC            0xBC  // R   Calibration data (16 bits)
#define BMP085_CAL_MD            0xBE  // R   Calibration data (16 bits)

#define BMP085_CONTROL           0xF4 
#define BMP085_TEMPDATA          0xF6
#define BMP085_PRESSUREDATA      0xF6
#define BMP085_READTEMPCMD          0x2E
#define BMP085_READPRESSURECMD            0x34


#include <HardWire.h>

HardWire H2Wire(2, I2C_FAST_MODE); // I2c1
//#include <Wire.h>

#define DAC1 0x77
#define DAC2 0x63
#define START PB0
//#define BMP085_I2CADDR 0x77

void write_dac(int d, byte i2c_dac_addr)
{

//#define MCP4726_CMD_WRITEDAC            (0x40)  // Writes data to the DAC
//#define MCP4726_CMD_WRITEDACEEPROM      (0x60)  // Writes data to the DAC and the EEPROM (persisting the assigned value after reset)

//  Serial.println();
//  Serial.println(d);
  
  
  H2Wire.begin();

  H2Wire.beginTransmission(i2c_dac_addr);
 
  H2Wire.write(0x40);
  H2Wire.write(d / 16);                   // Upper data bits          (D11.D10.D9.D8.D7.D6.D5.D4)
  H2Wire.write((d % 16) << 4);            // Lower data bits          (D3.D2.D1.D0.x.x.x.x)
  
  byte error=H2Wire.endTransmission();

Serial.println(error, HEX);
  
  
  }


void setup()
{
  H2Wire.begin();
  Serial.begin(115200);
  
  pinMode(PC13, OUTPUT);
  digitalWrite(PC13, 1);
  delay(2500);
  digitalWrite(PC13, 0);
  
  pinMode(START, OUTPUT); //синхроимпульс для лог анализатора
  digitalWrite(START,HIGH);
  Serial.print("TP0 ");
 
}

void loop()
{
  //Serial.println(millis());
digitalWrite(START,LOW);

//for(int i=0; i<4096; i++)
//  {
// 
//int i = 127;
//  write_dac(i, DAC1);
//      digitalWrite(PC13, !digitalRead(PC13));
//
//    }

//Serial.print (read8(0xD0));// != 0x55
Serial.print(millis());

Serial.print(" TP1 ");
  H2Wire.begin();
Serial.print(" TP2 ");

  H2Wire.beginTransmission(0x77);
Serial.print(" TP3 ");
 
  H2Wire.write(0xD0);

  Serial.print(" TP4 ");
//  H2Wire.write(d / 16);                   // Upper data bits          (D11.D10.D9.D8.D7.D6.D5.D4)
//  H2Wire.write((d % 16) << 4);            // Lower data bits          (D3.D2.D1.D0.x.x.x.x)
  
  byte error=H2Wire.endTransmission();

Serial.print(error, HEX);
  

  H2Wire.beginTransmission(0x77); // start transmission to device 
  Serial.print(" TP5 ");
  H2Wire.requestFrom(0x77, 1);// send data n-bytes read
  Serial.print("TP6 ");

  int ret = H2Wire.read(); // receive DATA
  
  Serial.print(ret, HEX);
  Serial.print(" TP7 ");
  error = H2Wire.endTransmission(); // end transmission
  Serial.print(error, HEX);
  Serial.print(" TP8 ");

///

 /* read calibration data */
  int ac1 = read16(BMP085_CAL_AC1);
  int ac2 = read16(BMP085_CAL_AC2);
  int ac3 = read16(BMP085_CAL_AC3);
  int ac4 = read16(BMP085_CAL_AC4);
  int ac5 = read16(BMP085_CAL_AC5);
  int ac6 = read16(BMP085_CAL_AC6);

  int b1 = read16(BMP085_CAL_B1);
  int b2 = read16(BMP085_CAL_B2);

  int mb = read16(BMP085_CAL_MB);
  int mc = read16(BMP085_CAL_MC);
  int md = read16(BMP085_CAL_MD);

  Serial.println();

  Serial.print("ac1 = "); Serial.println(ac1, DEC);
  Serial.print("ac2 = "); Serial.println(ac2, DEC);
  Serial.print("ac3 = "); Serial.println(ac3, DEC);
  Serial.print("ac4 = "); Serial.println(ac4, DEC);
  Serial.print("ac5 = "); Serial.println(ac5, DEC);
  Serial.print("ac6 = "); Serial.println(ac6, DEC);

  Serial.print("b1 = "); Serial.println(b1, DEC);
  Serial.print("b2 = "); Serial.println(b2, DEC);

  Serial.print("mb = "); Serial.println(mb, DEC);
  Serial.print("mc = "); Serial.println(mc, DEC);
  Serial.print("md = "); Serial.println(md, DEC);

///

  Serial.println();

   digitalWrite(START,HIGH);
}

uint8_t read8(uint8_t a) {
  uint8_t ret;
Serial.print("TP1 ");
  H2Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
Serial.print("TP2 ");
  H2Wire.write(a); // sends register address to read from
  Serial.print("TP3 ");
  H2Wire.endTransmission(); // end transmission
  Serial.print("TP4 ");
  H2Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Serial.print("TP5 ");
  H2Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
  Serial.print("TP6 ");

  ret = H2Wire.read(); // receive DATA
Serial.print("TP7 ");
  H2Wire.endTransmission(); // end transmission
Serial.print("TP8 ");
  return ret;
}

int read16(int a) {
  int ret;

  H2Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 

  H2Wire.write(a); // sends register address to read from

  H2Wire.endTransmission(); // end transmission
  
  H2Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  H2Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read

  ret = H2Wire.read(); // receive DATA
  ret <<= 8;
  ret |= H2Wire.read(); // receive DATA

  H2Wire.endTransmission(); // end transmission

  return ret;
}


luca_stm32
Posts: 17
Joined: Wed Apr 26, 2017 12:39 pm

Re: I2C2 on STM32F103C8T6 and HWire

Post by luca_stm32 » Thu Jun 15, 2017 11:47 am

Hi Winni_The_Pooh
Thanks for your replay.
Today I tested the same code (hardware I2C version) on I2C1 and I can confirm that it works.

So I tried to correct var size as you suggested, and tested on I2C1: works OK.
Changed to I2C2 and doesn't work. I will recheck var declarations.

My code now is:

Code: Select all

//#include <Wire.h>
#include <HardWire.h>
 
#define EEPROM_ADDRESS 0x50    //Address of 24LC256 eeprom chip

HardWire HWire(2, I2C_FAST_MODE); // I2C2
void setup(void)
{
  Serial.begin(115200);
  delay(10000);
  Serial.println("EEPROM Test");
  HWire.begin();
 
  uint16_t address = 0;
 
  writeEEPROM(EEPROM_ADDRESS, address, 0x55);
  while(1){
  Serial.print(readEEPROM(EEPROM_ADDRESS, address), HEX);
  Serial.print(" ");
  address++;
  delay(1000);    
  }

}
 
void loop(){}
 
void writeEEPROM(int16_t deviceaddress, int16_t eeaddress, uint8_t data ) 
{
  uint16_t temp = 0;

  HWire.beginTransmission(deviceaddress);
  temp = eeaddress >> 8;
  HWire.write((uint8_t)temp);   // MSB
  temp = eeaddress & 0xFF;
  HWire.write((uint8_t)temp); // LSB
  HWire.write(data);
  HWire.endTransmission();
 
  delay(5);
}
 
uint8_t readEEPROM(uint16_t deviceaddress, uint16_t eeaddress ) 
{
  uint8_t rdata = 0xFF;
  uint16_t temp;

  HWire.beginTransmission(deviceaddress);
  temp = eeaddress >> 8;
  HWire.write((uint8_t)temp);   // MSB
  temp = eeaddress & 0xFF;
  HWire.write((uint8_t)temp); // LSB
  HWire.endTransmission();
 
  HWire.requestFrom(deviceaddress,1);

  if (HWire.available()) rdata = HWire.read();

  return rdata;
}
Just a confirm: is I2C2 on pin PB10 (SCL) and PB11 (SDA)?

Another question: have your tried your examples code with last repository files?

Thaks again for your suggestions.
Luca.

Winnie_The_Pooh
Posts: 5
Joined: Mon Oct 24, 2016 10:31 am

Re: I2C2 on STM32F103C8T6 and HWire

Post by Winnie_The_Pooh » Thu Jun 15, 2017 12:17 pm

Hi, Luca!

Yes, PB10 == SCL2 and PB11 == SDA2

No, I have not try my code with last repository. Testing was done approx. a year ago in October 2016.

Can suggest you to do the following: use test points like serial.print(" TP1 "); before and after each wire operator to find bad line.

Then try to use different size var one after another - I succeed that way :)

May be some old code for second i2c was not carefully checked and wrong size variable leads to memory problems.

luca_stm32
Posts: 17
Joined: Wed Apr 26, 2017 12:39 pm

Re: I2C2 on STM32F103C8T6 and HWire

Post by luca_stm32 » Thu Jun 15, 2017 8:03 pm

Hi Winni_The_Pooh.
I tries as you suggested, but no luck (tried uint8_t, int ....).

I used this code:

Code: Select all

#include <HardWire.h>
 
#define EEPROM_ADDRESS 0x50    //Address of 24LC256 eeprom chip


HardWire HWire(2, I2C_FAST_MODE); // I2C2
void setup(void)
{
  Serial.begin(115200);
  delay(10000);
  Serial.println("EEPROM Test");
  HWire.begin();
 
  uint16_t address = 0;
 
  writeEEPROM(EEPROM_ADDRESS, address, 0x55);
  while(1){
  Serial.print(readEEPROM(EEPROM_ADDRESS, address), HEX);
  Serial.print(" ");
  address++;
  delay(1000);    
  }

}
 
void loop(){}
 
void writeEEPROM(int deviceaddress, uint16_t eeaddress, int data ) 
{

  HWire.beginTransmission(deviceaddress);
  HWire.write((int)(eeaddress >> 8));   // MSB
  HWire.write((int)(eeaddress & 0xFF)); // LSB
  HWire.write(data);
  Serial.print(" TP1 ");
  HWire.endTransmission();
  Serial.print(" TP2 ");
 
  delay(5);
}
 
int readEEPROM(int deviceaddress, uint16_t eeaddress ) 
{
  int rdata = 0xFF;

  HWire.beginTransmission(deviceaddress);
  HWire.write((int)(eeaddress >> 8));   // MSB
  HWire.write((int)(eeaddress & 0xFF)); // LSB
  Serial.print(" TP3 ");
  HWire.endTransmission();
  Serial.print(" TP4 ");
  
  HWire.requestFrom(deviceaddress,1);
 
  if (HWire.available()) rdata = HWire.read();

  return rdata;
}
In particular, on terminal appares only TP1: TP2 never appares. It seems HWire.endTransmission() function doesn't work.
Opening Hardwire.cpp and WireBase.cpp files, I saw that HWire.endTransmission() is the function make I2C sequence start. Infact, it calls process() that calls i2c_master_xfer (in i2c.c).
I tried also to use Serial.print inside HardWire::process and I noticed that i2c_master_xfer functions never exit (see some post ago where I described the problem with timeout).

I'm sure about hardware because if I connect EEPROM with I2C1 it works.

Can you kindly tell me or send me te version of the repository you used in your sketchs?

Thanks again.
Luca.

Post Reply