sameh4
Posts: 33
Joined: Wed Nov 29, 2017 6:58 pm

Problem connecting Rpi Zero as I2C master to Arduino Uno as I2C slave

Fri Dec 22, 2017 2:08 pm

I am not very familiar with Arduino, but I do have one Uno board and one Mega board (don't as me why :) ). I am able to get the Mega to talk to the Uno with the following the code in this link https://forum.arduino.cc/index.php?topi ... #msg776392

The value of x gets incremented and printed in the Arduino IDE's serial monitor. So far so good.

When I try to do the same from the Pi to the Uno, it seems there's no communication being made. I added some debugging as you'll see..

Please forgive the Pi code below, it's just a test as a proof of concept and needs a lot of work of course:

Code: Select all

// I am using GPIO pins 2 and 3 for SDA and SCL respectively
// Those are physical pins 3 & 5 of the 40 pins
 
#define GPIO_BASE  0x20200000
#define BSC1_BASE  0x20804000

#define GPFSEL0  (*(volatile u32 *)(GPIO_BASE + 0x0))

#define BSC1_C  (*(volatile u32 *)(BSC1_BASE + 0x00))
#define BSC1_S  (*(volatile u32 *)(BSC1_BASE + 0x01))
#define BSC1_DLEN  (*(volatile u32 *)(BSC1_BASE + 0x02))
#define BSC1_A  (*(volatile u32 *)(BSC1_BASE + 0x03))
#define BSC1_FIFO  (*(volatile u32 *)(BSC1_BASE + 0x04))

/** CONTROL REGISTER **/
#define BSC_C_I2CEN  (1 << 15)
#define BSC_C_ST  (1 << 7)
#define BSC_C_CLEAR  (1 << 4)
#define BSC_C_READ  1

// ENABLE I2C,
//START TRANSFER
#define START_WRITE  BSC_C_I2CEN | BSC_C_ST

/** STATUS REGISTER **/
#define BSC_S_CLKT  (1 << 9)
#define BSC_S_ERR  (1 << 8)
#define BSC_S_DONE  (1 << 1)

// CLEAR "CLOCK TIMEOUT", 
// CLEAR "Uno HAS NOT ACK ITS ADDRESS",
//CLEAR "TRANSFER DONE"
#define CLEAR_STATUS  BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE

MiniUART uart;
u8 x = 0;

void sleep(u8 count) {
    while (--count){
        for(u32 ra=0;ra<0x10000;ra++)
            continue;
    }
}

void i2c_test() {

    // clear the function select
    // for pin 2 and 3
    GPFSEL0 &= ~(7 << 2*3);
    GPFSEL0 &= ~(7 << 3*3);

    // setup pin 2 and pin 3 as ALT 0
    GPFSEL0 |= (1 << 8);
    GPFSEL0 |= (1 << 11);

    u8 msg[] = "Init I2C Communication\r";
    uart.send(msg);

    // Uno address, set by Uno
    BSC1_A = 0x4;

    u8 msg1[] = "Start with a write\r";
    uart.send(msg1);
    BSC1_DLEN = 5;           // five bytes
    BSC1_FIFO = x;           // value incremented
    BSC1_S = CLEAR_STATUS;
    BSC1_C = START_WRITE;

    check_uno_ack_error();
    check_uno_clock_stretch_error();
    
    u8 msg2[] = "wait for i2c done\r";
    uart.send(msg2);
    wait_i2c_done();
    sleep(10);
    x++;
}

// Function to wait for the I2C transaction to complete
void wait_i2c_done() {
    
    int timeout = 10;
    bool error = (!((BSC1_S) & BSC_S_DONE));
    while( error && --timeout) {
        error = (!((BSC1_S) & BSC_S_CLKT));
        u8 msg[] = "Uno has not yet read.\r";
        uart.send(msg);
        sleep(10);
    }
    if (timeout == 0 ) {
        u8 msg[] = "Timeout while waiting for Uno to read, let's start over.\r";
        uart.send(msg);
    }
}

void check_uno_ack_error() {
    int timeout = 10;
    bool error = (!((BSC1_S) & BSC_S_ERR));
    while( error && --timeout) {
        error = (!((BSC1_S) & BSC_S_ERR));
        u8 msg[] = "Uno has not ACK its address.\r";
        uart.send(msg);
        sleep(10);
    }
}

void check_uno_clock_stretch_error() {
    int timeout = 10;
    bool error = (!((BSC1_S) & BSC_S_CLKT));
    while( error && --timeout) {
        error = (!((BSC1_S) & BSC_S_CLKT));
        u8 msg[] = "Clock Stretch Error.\r";
        uart.send(msg);
        sleep(10);
    }
}
UART is used for debugging as you can see, and it prints the following, over and over:

Code: Select all

Start with a write
Uno has not ACK its address.
... x10
Clock Stretch Error.
... x10
wait for i2c done
Uno has not yet read.
... x10
Timeout while waiting for Uno to read, let's start over.
The i2c_test is of course being called from kernel_main in an endless loop.

Any thoughts on why it's not woking?

AlfredJingle
Posts: 55
Joined: Thu Mar 03, 2016 10:43 pm

Re: Problem connecting Rpi Zero as I2C master to Arduino Uno as I2C slave

Sat Jan 06, 2018 3:54 pm

The Raspberries (all versions) have a hardware-bug in the i2c controllers. The bug being that the rPi cannot correctly handle clock-stretching. See for instance: http://elinux.org/BCM2835_datasheet_err ... stretching. Your problem looks very much like that bug. There is no work-around OTHER than trying to run the i2c at a lower frequency. Even trying frequencies way below 100 kHz can be tried ( It would be so nice if the bug was repaired in the next version of the raspberry. Please, please, please Gert!)
going from a 6502 on an Oric-1 to an ARMv8 is quite a big step...

asandford
Posts: 1862
Joined: Mon Dec 31, 2012 12:54 pm
Location: Ealing

Re: Problem connecting Rpi Zero as I2C master to Arduino Uno as I2C slave

Sun Jan 07, 2018 1:23 am

How are you connecting the Pi to the Uno?

Return to “Bare metal”

Who is online

Users browsing this forum: No registered users and 9 guests