2

I tried to connect an Arduino Uno with my Raspberry using the i2c bus, with code and wiring suggested here. This example is sending only one byte from RPi to Arduino and back, and everything works fine.

Now, since I need to send a larger number (which is a value from the ultrasonic sensor on Arduino) to RPi, I edited the code, but I just receive zeros. I was reading on the documentation of the Wire.h library (Arduino side) and the smbus python module (RPi side) but I haven't spotted anything helpful. What I try to do is to send 4 bytes one by one and then read them using struct.unpack

This is the code on Arduino

/*
 i2c
  pin A4   SDA (raspi pin3)
  pin A5   SCL (raspi pin5)

 */
#include <Wire.h>
#define SLAVE_ADDRESS 0x04

void setup() {
  Serial.begin (9600); // start serial for output

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(requestEvent); // register event
  Serial.println("Ready!");
}

void loop() {     
  delay(500);
}

void requestEvent()
{
  long d;
  d=10; // mockup value, in the real script is acquired by the sensor
  Serial.println(d);
  Wire.write((const uint8_t*)&d, sizeof(long));
}

And this is the script on RPi

import smbus
import time
import struct
# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

def readLong():
   #number = bus.read_byte(address)
   number=""
   for i in xrange(4):
      number += chr(bus.read_byte(address))
   return struct.unpack('l', number)

while True:
   time.sleep(1)
   number = readLong()
   print "[Arduino]", number, "mm"
  • Why use the Arduino at all the Pi is capable of reading the sensor directly? – Steve Robillard Apr 5 '16 at 8:20
  • It is a requirement, being part of a larger university project, I cannot change this design choice. – gtatr Apr 5 '16 at 8:26
  • 1
    The Arduino must act as a slave. You can't just call Wire.write every half a second. You must only write in response to a read request from the Pi. – joan Apr 5 '16 at 10:41
  • @joan I fixed the Arduino code, it is now acting as a slave, but I still didn't solve the problem – gtatr Apr 8 '16 at 22:21
1

You can't afford to waste time in an interrupt service routine. Especially with a protocol like I2C or SPI as a slave where you must respond at the master's clock rate.

Either remove Serial.println or at the very least move it to after the Wire.write

void requestEvent()
{
  long d;
  d=10; // mockup value, in the real script is acquired by the sensor
  Serial.println(d);
  Wire.write((const uint8_t*)&d, sizeof(long));
}

I think you need to read 4 bytes in 1 I2C transaction. You probably need to use the read_i2c_block_data call. Doing it as 4 separate calls probably triggers 4 separate requestEvent on the Arduino.

for i in xrange(4):
   number += chr(bus.read_byte(address))
1

I have an ugly solution, but working.

On Arduino:

long n;
int req=0;
void sendData(){
  if(req==0){
    n = 300; //mockup
    //n = readDistance();
  }
  Serial.print(n);
  Serial.println(" xx");
  Wire.write(n);
  n = n>>8;
  req = (req+1)%4;
}

On Raspberry

def readLong():
   number=""
   for _ in xrange(4):
      number += chr(bus.read_byte(address))
   return struct.unpack('<l', number)[0]

I know it can be improved and I am open to suggestions

1

The following solution uses read_i2c_block_data, triggering only one request event for the slave. Code for the slave (Arduino):

void sendData(){
  long n;
  n = 300; //mockup
  //n = readDistance();
  Wire.write((const uint8_t*)&n, sizeof(long));
  //Serial.print(n);
  //Serial.println(" mm");
}

Code for the master (RPi):

def readLong():
   block = bus.read_i2c_block_data(address, 0) #second arg is 'cmd'. It is andatory but not used in this case. It may be used by the higher level protocol
   # block is a list of 32 elements (int)
   #return block
   n = struct.unpack('<l', ''.join([chr(i) for i in block[:4]]))[0]
   return n

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.