Hi,
I have been playing with a Spider board for some time, and even managed to create a basic module for 2x16 LCD. Now I am trying to get a more complicated setup going where I have another Microprocessor communicate with the Spider on i2c. I have no experience with i2c, but this is sort of the aim - to learn something new. For the other Microprocessor I am using a Arduino NANO.
On the Arduino NANO (my “module”) I have created a basic sketch that does the following:
- initialise i2c slave mode with an address of “50”
- define, initialise a LED on pin 13
- define pin 14 as an interrupt pin from the Arduino to the Spider (to indicate to the Spider that data is ready from the “module”)
- initialise Serial on 9600
- the main program consist out of a delay and creates an interupt every 4 seconds (similating data is ready to be read)
- when a request comes in from the Mainbord (Spider) on the i2c bus, then the Arduino will flash the LED once. Read the byte coming in on the i2c bus, and echo it back on the i2c and also send the same byte out on the Serial (so I can see in a terminal program, what the Arduino receives).
Here is my Arduino code:
#include <Wire.h>
int led=13; //pin 13 has an led connected on most Arduino boards.
int datardy=12; //pin 12 is connected to pin 3 (interrupt) on the socket
int rdy=0; //counter to create a delay to simulate some sensor readings
byte inByte;
void setup()
{
Wire.begin(50); //join i2c bus with address #2
Wire.onRequest(requestEvent); //fires when theres a request from i2c master
pinMode(led, OUTPUT); //initialize digital pin 13 as an output
pinMode(datardy, OUTPUT); //initialize digital pin 12 as an output
Serial.begin(9600); // start serial for output
Serial.println("Aduino NANO: ok");
}
void loop()
{
delay(100); //pauses for 100 ms
rdy=rdy+1; //inc counter to simulate data that is ready to be read
if(rdy==40)
{
digitalWrite(datardy, LOW); //pin down indicating data is ready to be read
delay(1); //pauses for 1 ms
digitalWrite(datardy, HIGH);//pin up, resetting pin
rdy=0; //reset rdy counter value
}
}
void requestEvent()
{
//test 1
//Wire.write("x"); //send the characted "hello" to master i2c device
digitalWrite(led, HIGH); //turn the LED on (HIGH is the voltage level)
delay(200);
digitalWrite(led, LOW); //turn the LED off by making the voltage LOW
byte c = Wire.read(); //read byte as a character
Wire.write(inByte); //echo received char back
Serial.println(c, HEX); // print the character in HEX
}
For the .NET Gadgeteer Module, I have used the standard template, and also tried to implement the recommended structure (according to the “.NET Gadgeteer Module Builder’s Guide version 1.9”). I also tried to make sense of some of the other existing modules software. I must be honest, I am hacker-together and not a programmer, so I can not 100% why this structure is the way to go, and there are just not that many step-by-step explanations that I could get hold of yet to explain thing in more layman’s terms.
My module does the following:
- sets the socket up
- defines an interrupt on pin 3 of that socket (that is connected to pin 14 of the Arduino NANO)
- initialises the i2c at 100kHz
- when an interrupt happens on pin 3, then the module routine will send the value “0x40” on i2c to the Arduino, and then also read from the Arduino “slave i2c” with address “50”.
Here is my code:
using System;
using Microsoft.SPOT;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;
namespace Gadgeteer.Modules.JLR
{
/// <summary>
/// A rcdec module for Microsoft .NET Gadgeteer
/// </summary>
public class rcdecmeas : GTM.Module
{
private GTI.I2CBus _i2c;
private byte[] tx_data = { 0x40 }; //slave i2c tx data (arduino)
private byte[] rx_data = { 0 }; //slave i2c rx data (arduino)
/// <summary>The RC Decoder and Distance Measurement module</summary>
/// <param name="socketNumber">The socket that this module is plugged in to.</param>
public rcdecmeas(int socketNumber)
{
Socket socket = Socket.GetSocket(socketNumber, true, this, null);
//slave address "50" (arduino)
//speed 100kHz
_i2c = new GTI.I2CBus(socket, 50, 100, this);
//interrupt on pin 3 of the socket
//interrupts on falling edge
this.input = new GTI.InterruptInput(socket, Socket.Pin.Three, GTI.GlitchFilterMode.On, GTI.ResistorMode.Disabled, GTI.InterruptMode.FallingEdge, this);
this.input.Interrupt += new GTI.InterruptInput.InterruptEventHandler(input_Interrupt);
}
private GTI.InterruptInput input;
void input_Interrupt(GTI.InterruptInput sender, bool value)
{
this.rcdecmeasEvent(this); //raises this rcdecmeasEvent (Get the ball rolling!)
}
/// <summary>
/// Represents the delegate that is used to handle the "dataready" event.
/// </summary>
/// <param name="sender">The <see cref="rcdecmeas"/> object that raised the event</param>
public delegate void rcdecmeasEventHandler(rcdecmeas sender);
/// <summary>
/// Raised when <see cref="rcdecmeas"/> has data measurements ready for reading
/// </summary>
public event rcdecmeasEventHandler DataReady;
private rcdecmeasEventHandler _DataReady;
/// <summary>
/// Raises the <see cref="DataReady"/> event
/// </summary>
/// <param name="sender">The <see cref="rcdecmeas"/> that raised the event</param>
protected virtual void rcdecmeasEvent(rcdecmeas sender)
{
if (_DataReady == null)
{
_DataReady = new rcdecmeasEventHandler(rcdecmeasEvent);
}
if (Program.CheckAndInvoke(DataReady, _DataReady, sender))
{
//_i2c.WriteRead(tx_data, rx_data, 1000);
_i2c.Write(tx_data, 100);
_i2c.Read(rx_data, 100);
}
}
/// <summary>
/// Returns the data that was received from the module
/// </summary>
/// <returns>Returns the rx_data train</returns>
public byte[] GetRxData()
{
return rx_data;
}
}
}
Now here is what I will really appreciate some advise and feedback on:
- interrupt sequence works fine. Arduino sends interrupt simulating that data is ready. The “module” routine receives the interrupt and sends the value 0x40 to the Arduino slave with address 50. Arduino receives this and flashes the LED. But there is no result that ends up back in the “module”. On the serial/terminal is shows “FF”. This is achieve with the _i2c.Write and _i2c.Read commands.
- If I just send a predefined value such as “hi” instead of echoing the value back, then the value “hi” is received in the “module” via the i2c bus from the Arduino.
- If I use the _i2c.WriteRead command, then nothing happens. The Arduino does not receive anything, and it does not transmits anything back.
Some further information:
- Since the Spider is a 3v3 device and the Arduino is 5v, I have included a voltage divider on ouput pin 12 (Arduino) towards socket pin 3 (Gadgeteer).
- I did not put any voltage divider between the Arduino and Spider for the i2c pins (SDA and SCL) as I have read that the Spider is 5v tolerant.
Any advise on what I can test, or try will be really appreciated. If there are any further tutorials or blogs that explains why the specific coding patterns are recommended for modules and how to implement i2c and spi between the Gadgeteer any other device will really be welcome.
Apologies for the long winded post - I am really stuck at this point and have run out of google-searches to try for futher tests to get this working.
Thanks in advance!