I2C Communication between NUCLEO-F722ZE and NUCLEO-G031K8

Hello everyone,

I’m currently working on an I2C communication project using Mbed, and I’m facing an issue where one version of my code works perfectly, while another version does not, even though the addressing and setup seem identical.

Here’s the code that works:

Master test on F722ZE:

#include "mbed.h"
#include <cstdio>
#define I2C1_SDA    PB_9
#define I2C1_SCL    PB_8
#define ADDR        0xA0

DigitalIn SCL(I2C1_SCL);
DigitalIn SDA(I2C1_SDA);
I2C i2c1(I2C1_SDA, I2C1_SCL);

void device_scanner();
void ack_test(char* data);

int main() {
    printf("................:[ I2C Device Tester ]:................\n\r");
    char data[] = {0xAA};  // Example single byte data
    char reads[3] = {0x00};
        while (true) {
            int write = i2c1.write(ADDR, data, sizeof(data));
            int read = i2c1.read(ADDR, reads, sizeof(reads));
            if (write == 0) {
                printf("\tMessage sent successfully and acknowledged\n\r");
            } else {
                printf("\tMessage not sent (No ACK from slave)\n\r");
            }  if (read == 0) {
                printf("\tMessage read: %s\n\r", reads);
            } else {
                printf("\tMessage not read\n\r");
            }
        }
} 

Slave test on G031K8:

#include "mbed.h"
#include <cstdio>
I2CSlave slave(PA_12, PA_11);
#define SLAVE_ADDR 0xA0  // Use 7-bit address
#define WAIT_TIME_MS 500
DigitalOut LED(LED1);
int main() {
    slave.address(SLAVE_ADDR);
    while (1) {
        int i2c_event = slave.receive();
        switch (i2c_event) {
            case I2CSlave::ReadAddressed:
                slave.write("ACK", 3);  // Just respond with "ACK"
                break;
            case I2CSlave::WriteAddressed:
                char received[1];  // Expecting single byte
                slave.read(received, 1);
                printf("Received: 0x%02X\n", received[0]);
                break;
        }
        LED = !LED;
    }
}

This code successfully sends and receives data over I2C without any issues. However, when I use a different version of the code (shown below), it doesn’t work, even though the addressing and pin setup are the same. The problematic code fails during communication, as it doesn’t seem to receive any acknowledgments from the slave device.

My question is: Since the addressing seems correct, and the hardware works with this version of the code, what could be causing the other version to fail? Could it be related to how I’m initializing the pins or some other setup detail? I’d appreciate any suggestions or insights on what might be going wrong.

Thanks in advance for your help!

Master Implementation on F722ZE:

#include "PinNames.h"
#include "mbed.h"
#include <chrono>
#include <cstdint>
#include <cstdio>
#include "stepper.h"
#include "roboclaw.h"
#include "sdfat.h"
#include <ratio>
#include <sstream>
#include <string.h>
#include "messages.h"
#include "current.h"
#include "MB85RSxx_SPI.h"

char buf[BUFFER_SIZE] = "ABCDE";
I2C master(PB_9, PB_8); // SDA, SCL

bool readui(int max_retries, int delay_ms);
void init();

int main() {
    init();
    queue.call_every(50ms, []{ readui(5, 50); });
    while (true) {
     // Other code.
     }
}

void init(){
    //printf( "Working\n");
    HVCTRL = 1;
    readtimer.start();
    pc.set_baud(9600);
    pc.set_format(8, BufferedSerial::None, 1);  
    nsleep1 = 1;
    nsleep2 = 1;
    
    if (!readui(5,50)) {
        printf("Use the A and D to move stepper motor 1\n Use Z and C to move stepper motor 2\n When Completed Restart System with UI plugged in");   
    }
    while(!readui(5,50));
}

bool readui(int max_retries, int delay_ms) {
    char buf[BUFFER_SIZE];
    int result;

    for (int attempt = 0; attempt < max_retries; attempt++) {
        result = master.read(SLAVE_ADDR, buf, BUFFER_SIZE);
        if (result == 0) {  // Success
            speedi = buf[0] & 7;
            isstop = (buf[0] & 8) == 8;
            return true;
        } else {
            printf("I2C read error: %d, attempt %d\n", result, attempt + 1);
            ThisThread::sleep_for(delay_ms);  // Wait before retrying
        }
    }

    // If we reach here, all attempts failed
    printf("Failed to read from slave after %d attempts.\n", max_retries);
    return false;
}

Slave implementation on G031K8

#include "ticker_api.h"
#include "mbed.h"
#include "I2CSlave.h"
#include "I2C.h"
#include <cstdint>
#include <cstdio>
#include "Timer.h"
 
#define WAIT_TIME_MS 50
#define SCL PA_11
#define SDA PA_12
 
#include <string.h>
#define SLAVE_ADDR 0xA0
#define BUFFER_SIZE 6
char buf[BUFFER_SIZE] = "ABCDE";
 
 
//SLAVE byte buttons send 8 bit [4 bits empty, isstop, 3 bits speedi (8 decimal)]
 
uint8_t speedi = 2; //speedi && 7 0b00000111  4 is stop, 5 is up 3 is down ...
int speedizero = 2;
bool isstop = 1; // 8 0b00001000
char buff = (speedi & 7) | (isstop << 3);
 
I2CSlave slave(SDA, SCL);
 
DigitalOut i2cActivityLed(D3);
DigitalOut topBarCat(PA_0);  //Initialise the cathode upper end of the LED Bar
DigitalOut midBarCat(PA_1); //Initialise the cathode middle of the LED Bar
DigitalOut botBarCat(PB_2); //Initialise the cathode bottom end of the LED Bar
 
DigitalOut REDBaruno(PA_7); //Initialise the Red of the LEDbar
DigitalOut REDBardos(PA_4); //Initialise the Red of the LEDbar
 
DigitalOut GreenBaruno(PA_6);   //Initialise the Green of the LEDbar
DigitalOut GreenBardos(PA_5);   //Initialise the Green of the LEDbar

DigitalOut led1(LED1);
 
DigitalOut LEDRED(PB_6);    // Initialise red status circle LED
DigitalOut LEDGreen(PB_7);  // Initialise green status circle LED
 
InterruptIn btndown(PA_10);
InterruptIn btnstop(PB_1);
InterruptIn btnup(PA_15);

DigitalIn SCL_pin(SCL);
DigitalIn SDA_pin(SDA);
 
// debounce
Timer upTimer, downTimer, StopTimer;
Timeout debounce_timeout;
 
volatile bool down_button_pressed_flag = false;
volatile bool stop_button_pressed_flag = false;
volatile bool up_button_pressed_flag = false;
 
int btnupPrev=0, btndownPrev=0, btnstopPrev=0;
int cbtnup,cbtndown,cbtnstop;
bool tbtnup=0,tbtndown=0,tbtnstop=0;
uint8_t LED[] = {0,1,0,1,1,0,0}; // {top, middle, bottom, red1, red2, green1, green2}
 
void upEventFunction();
void downEventFunction();
void down_button_ISR();
void up_button_ISR();
void stop_button_ISR();
void stopEventFunction();
void LEDCTRL(uint8_t* LED);
 
int main()
{
    debug("-----------:User Controller Start:-----------\n");
    slave.address(SLAVE_ADDR);
    btndown.mode(PullUp);
    btnstop.mode(PullUp);
    btnup.mode(PullUp);
    SDA_pin.mode(PullUp);
    SCL_pin.mode(PullUp);
    led1 = 1;
    
 
    // MBed Interrupt function
    btndown.fall(&down_button_ISR);
    btnstop.fall(&stop_button_ISR);
    btnup.fall(&up_button_ISR);
    
    while (true){
        LEDCTRL(LED);
        buf[0] = (speedi & 7) | (isstop << 3);
        int i = slave.receive();
        printf("I2C event: %d\n", i);  // Print the event type

 
        switch (i) {
            case I2CSlave::ReadAddressed:
                // Write back the buffer from the master
                slave.write(buf, BUFFER_SIZE);
                printf("Written to master (addressed): speedi: %d  isstop: %d\n", buf[0]&7,(buf[0]&8)==8);
                break;
            case I2CSlave::WriteGeneral:
                slave.read(buf, BUFFER_SIZE);
                printf("Read from master (general): %s\n", buf);
                break;
            case I2CSlave::WriteAddressed:
                slave.read(buf, BUFFER_SIZE);
                printf("Read from master (addressed): %s\n", buf);
                break;
        }
    printf("Sending to master: 0x%02X\n", buf[0]);
    led1 = !led1;
    }
}

Hello,

my tip are lines 45-46 and 79-80 of your slave code.

BR, Jan

Thanks, so much @JohnnyK. I was stumped on this for a while. For anyone else in the future, I initialised the SCL SDA pins as DigitalIn as well so I could setup the internal pullups, removing that made it work straight away. This was a remnant of old code from an older problem.