1

I'm pretty new in the world of Raspberry and Arduino (especially together with Windows IoT). My plan is, to readout different sensors (temp and pressure) with the Arduino and then sending the values to my RP2 where I can use them on a GUI.

So, it's not a problem to readout the sensors. I receive the correct values. Afterwards I'm sending them to the I²C bus (based on the requirements of the Wire.h lib).

For my RP2 I found two similar projects and my code in C# is based on those.

So far, so good, but when I start both devices I don't get any data on my RP. My RP finds the Arduino.

To localize the problem I'm using a Wire.h sample sketch for sending random values to my RP. But there is still the same problem, so I guess there is a problem with my C# code. Also I set a breakpoint at place where my RP should write the values into a array. But it looks like, there are no incoming values.

I attached both codes. Hope somebody can help me. I'm stuck pretty bad...

Thank you very much! Thiemo

Arduino code:

#include <Wire.h>
  #define SLAVE_ADDRESS 0x40


byte val = 0;
byte val_2 = 100;

void setup()
{
  Wire.begin(SLAVE_ADDRESS); // join i2c bus
  Serial.begin(9600);
}

void loop()
{
  Wire.beginTransmission(SLAVE_ADDRESS); // transmit to master device
                              // device address is specified in datasheet
  Wire.write(val);             // sends value byte  
  Wire.write (val_2);
 // Serial.write(val);
//  Serial.write(val_2);
  Wire.endTransmission();     // stop transmitting

  val++;        // increment value
  val_2++;
  if(val == 64) // if reached 64th position (max)
  {
    val = 0;    // start over from lowest value
  }

  if (val_2 == 164)
  {
    val = 100;  
  }
  delay(500);
}

C# code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// i2c Libs
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using System.Diagnostics;
using System.Threading;


// Die Vorlage "Leere Seite" ist unter http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 dokumentiert.

namespace _007_Test7_I2C
{
    /// <summary>
    /// Eine leere Seite, die eigenständig verwendet werden kann oder auf die innerhalb eines Rahmens navigiert werden kann.
    /// </summary>

    public sealed partial class MainPage : Page
    {

        private I2cDevice Device;
        private Timer periodicTimer;


        public MainPage()
        {
            this.InitializeComponent();
            initcomunica();
        }

        private async void initcomunica()

        {

            var settings = new I2cConnectionSettings(0x40); // Arduino address
            settings.BusSpeed = I2cBusSpeed.StandardMode;
            string aqs = I2cDevice.GetDeviceSelector("I2C1");
            var dis = await DeviceInformation.FindAllAsync(aqs);
            Device = await I2cDevice.FromIdAsync(dis[0].Id, settings);
            periodicTimer = new Timer(this.TimerCallback, null, 0, 1000); // Create a timer

        }

        private void TimerCallback(object state)
        {

            byte[] RegAddrBuf = new byte[] { 0x40 };
            byte[] ReadBuf = new byte[7];

            try
            {
                Device.Read(ReadBuf);
             //   Debug.WriteLine(ReadBuf);
            }
            catch (Exception f)
            {
                Debug.WriteLine(f.Message);
            }


            char[] cArray = System.Text.Encoding.UTF8.GetString(ReadBuf, 0, 7).ToCharArray();  // Converte  Byte to Char
            String c = new String(cArray);
            Debug.WriteLine(c);
            // refresh the screen, note Im using a textbock @ UI

            var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            { Temp_2.Text = c; });

        }

    }
}
TRS
  • 228
  • 4
  • 15

1 Answers1

3

Your code must be synchronized on both side. Arduino is I2C Slave and can only send bytes on request by the master which is RPi2 (Windows IoT).

There are following errors in your Arduino Sketch:

  • Slave device can't initiate write request on the bus (except Master requests for it)
  • To parse valid character or string at Windows IoT side, Arduino must send byte(s) in valid ASCII format

I'm attaching basic Arduino Sketch and RPi2 UWP Code:

Arduino Sketch (I2C Slave) that responds with a byte on requested by master:

#include <Wire.h>
#define MyAddress 0x40

byte DataToBeSend[1];
byte ReceivedData;

void setup()
{
    /* Initialize I2C Slave & assign call-back function 'onReceive' on 'I2CReceived'*/
    Wire.begin(MyAddress);
    Wire.onReceive(I2CReceived);
    Wire.onRequest(I2CRequest);
}

void loop()
{
    /* Increment DataToBeSend every second and make sure it ranges between 0 and 99 */
    DataToBeSend[0] = (DataToBeSend[0] >= 99) ? 0 : DataToBeSend[0] + 1;
    delay(1000);
}

/* This function will automatically be called when RPi2 sends data to this I2C slave */
void I2CReceived(int NumberOfBytes)
{
    /* WinIoT have sent data byte; read it */
    ReceivedData = Wire.read();
}

/* This function will automatically be called when RPi2 requests for data from this I2C slave */
void I2CRequest()
{
    /*Send data to WinIoT */
    Wire.write(DataToBeSend,1);
}

Windows IoT UWP - I2C Master Code Snippet:

using System;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;

namespace Windows_10_I2C_Demo
{
    public class I2cHelper
    {
        private static string AQS;
        private static DeviceInformationCollection DIS;

        public static async System.Threading.Tasks.Task<byte> WriteRead_OneByte(byte ByteToBeSend)
        {
            byte[] ReceivedData = new byte[1];

            /* Arduino Nano's I2C SLAVE address */
            int SlaveAddress = 64;              // 0x40

            try
            {
                // Initialize I2C
                var Settings = new I2cConnectionSettings(SlaveAddress);
                Settings.BusSpeed = I2cBusSpeed.StandardMode;

                if (AQS == null || DIS == null)
                {
                    AQS = I2cDevice.GetDeviceSelector("I2C1");
                    DIS = await DeviceInformation.FindAllAsync(AQS);
                }


                using (I2cDevice Device = await I2cDevice.FromIdAsync(DIS[0].Id, Settings))
                {
                    /* Send byte to Arduino Nano */
                    Device.Write(new byte[] { ByteToBeSend });

                    /* Read byte from Arduino Nano */
                    Device.Read(ReceivedData);
                }
            }
            catch (Exception)
            {
                // SUPPRESS ANY ERROR
            }

            /* Return received data or ZERO on error */
            return ReceivedData[0];
        }
    }
}

How to use above Windows IoT UWP - I2C Master Code Snippet?

public async void TestFunction()
{
    byte DataToBeSend = 100;
    byte ReceivedData;
    ReceivedData = await I2cHelper.WriteRead_OneByte(DataToBeSend);
}


Before you go further, you should have clear idea about I2C communinication. Refer the following article to get clear idea about Master-Slave communication between Arduino: http://www.instructables.com/id/I2C-between-Arduinos/?ALLSTEPS

To get into more deeper, refer following projects:
Arduino I2C communication with Raspi 2 WIOT
Windows IoT (RPi2) - I2C Accelerometer

Anurag Vasanwala
  • 486
  • 3
  • 12
  • Hi Anurag, thanks for your help and the lecture! So far, I've understood the Arduino part. I tried your code and now I receive one value (128). And it seems like, that the Arduino doesn't get a request (I've checked it with Serial.write()). Is that correct that I go into the TestFunction() with a Task? Like: "Task Task1 = new Task(TestFunction);" I'm sorry for my ignorace! – TRS Dec 16 '15 at 08:16
  • "TestFunction" mentioned above only send a byte to I2C Slave and receive a byte from it. You need to call this function whenever you are going to request slave. You need to modify code on both side if you need to transmit multiple bytes. The above code is just a sample to give you a clear idea how you can communicate over I2C. – Anurag Vasanwala Dec 16 '15 at 09:46
  • I have modified Arduino Sketch (provided above) and included another I2C callback which will be called when RPi2 requests for the data (by Device.Read(ReceivedData) method). Check with that and let me know if you won't get desired result. – Anurag Vasanwala Dec 16 '15 at 13:54
  • 1
    Thanks buddy!! Now it works! I definitely owe you something! – TRS Dec 17 '15 at 19:15
  • Anurag, thanks so much for the great answer. I have a related question - can the Windows RPi poll for slaves on I2C? In other words, can I add an Arduino, with a unique ID, and the Windows device find it, without having to hard code the ID of the Arduino? I'm creating a door lock system, with RFID access, and I'd like to be able to add another door without having to modify the RPi, which will be the central controlling unit (an Arduino at each door). Does that make sense? I was also hoping to find an EasyTransferI2C library for Windows, but I haven't found that yet... It doesn't seem to exist. – Rich Hopkins Aug 09 '16 at 07:06