Sunday, November 24, 2013

UDOO - RaspberryPI Talks to Arduino

Communication Schemes

There are two loosely coupled components in UDOO device - one is built around  Atmel's SAM3X8E processor and the second one around ARM v7 Cortex A9, i.MX6 series processor. Since the first one resembles traditional Arduino's  functionality and the second one is very similar to RaspberryPI, it would be fair to say that we're dealing with Arduino + RaspberryPI hybrid here.

It would be interesting to learn, of course, how these two loosely coupled components can talk to each other. One of the obvious way of doing this would be by utilizing GPIO's available on both sides.

Possible connectivity scenarios are provided by UDOO in their "UDOO Starting Manual":


It's obvious from this diagram that I could take a signal from i.MX6's output GPIO and feed it to an SAM3X8E's input GPIO.

Since UDOO has only one green led, which simply stays on and never blinks, I've decided to add my own custom led on SAM3X8E that would monitor a status and network activity on i.MX6 side. If i.MX6 is running, it will send a pulse signal every few seconds to GPIO 134. Network activity signals will be sent to the same GPIO when a TCP packet received or send by i.MX6's wireless card. I monitor wireless interface because it's my primary one, but it can be easily changed to wired or any other network interface if necessary.

Solution Details


This is the final hardware solution:

  
GPIO 134 is connected to Arduino's A6, light diode's cathode is connected to the ground on J8 and anode to Arduino's DAC0.

The rest of that is coding. You'll need an activity monitor running on i.MX6 and a code for Arduino's controller that reads A6 and sends an analog signal to DAC0.

I've "demonized" my activity monitor by creating an init script and storing it in /etc/init.d/udoo-activity file:
 
#!/bin/bash
### BEGIN INIT INFO
# Provides: udoo-activity
# Required-Start: $remote_fs $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Sends TCP activity and udoo pulse to a GPIO 134
### END INIT INFO

. /lib/lsb/init-functions

PATH=/sbin:/usr/sbin:/bin:/usr/bin
ACTIVITYPID=/var/run/udoo-activity.pid
PULSEPID=/var/run/udoo-pulse.pid
GPIODIR=/sys/class/gpio/gpio134



[ -f ${GPIODIR}/direction ] || exit 0
[ -f ${GPIODIR}/value ] || exit 0


echo out >${GPIODIR}/directionu
echo 0 >${GPIODIR}/value

do_stop () {

log_daemon_msg "Stopping UDOO activity monitors" "udoo-activity"
if [ -f "$PULSEPID" ]; then
kill -9 `cat $PULSEPID` >/dev/null 2>&1
fi
if [ -f "$ACTIVITYPID" ]; then
kill -9 `cat $ACTIVITYPID` >/dev/null 2>&1
fi
log_end_msg $?
echo 0 >${GPIODIR}/value
}

do_start () {

# Pulse Loop
while true; do
sleep 5
echo 1 >${GPIODIR}/value
sleep 0.0015
echo 0 >${GPIODIR}/value
done &
echo $! >$PULSEPID

# TCP Dump Loop
while true; do
echo 0 >${GPIODIR}/value
tcpdump -q -i wlan6 -n tcp -c 1 >/dev/null 2>&1
echo 1 >${GPIODIR}/value
sleep 1
done &

echo $! >$ACTIVITYPID

}

case "$1" in
start)
do_start
;;
stop)
do_stop
;;
force-reload|restart)
$0 stop
$0 start
;;
*)
echo "Usage: /etc/init.d/udoo-activity {start|stop|restart|force-reload}"
exit 1
;;
esac

exit 0


To start the monitor at i.MX6's boot, you'll need to update your init.d scripts:

update-rc.d udoo-activity defaults

Finally, the code for controlling Arduino's part:



// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  analogWriteResolution(12);
  analogWrite(6, 0);
  pinMode(6, INPUT);
  analogWrite(6, 0);
  pinMode(DAC0, OUTPUT);
  analogWrite(DAC0, 0);
}

int BLINK_DURATION=50;
int IDLE_DURATION=2500;
int IDLE_DURATION_LIGHT=100;
int PULSE_DURATION=5500;
int LOOP_DURATION=10;
int idle_count = 0;
int light_on = 0;
int pulse_count = 0;


// the loop routine runs over and over again forever:

void loop() {
 
  int level = analogRead(6);
  if (level >= 900) {
     blink(BLINK_DURATION);
     pulse_count = 0;
     idle_count = 0;
     Serial.println(level);
  }
  else {
    idle_count += 1;
    if (pulse_count*LOOP_DURATION >= PULSE_DURATION) {
         analogWrite(DAC0,0);
         idle_count = 0;
         light_on = 0;
    }
    else {
      pulse_count += 1;
      if (idle_count*LOOP_DURATION >= IDLE_DURATION && !light_on) {
        analogWrite(DAC0,2048);
        light_on = 1;
        idle_count = 0;
      }
      else {
        if (idle_count*LOOP_DURATION >= IDLE_DURATION_LIGHT && light_on) {
           analogWrite(DAC0,0);
           idle_count = 0;
           light_on = 0;
        }
      }
    }
  }
 
  // print out the value you read:
  //Serial.println(sensorValue);
  delay(LOOP_DURATION);        // delay in between reads for stability
}

void blink(int duration) {
  analogWrite(DAC0, 2048);
  delay(duration);
  analogWrite(DAC0, 0);
}


When there is no any network activity, the led will be slowly blinking, when the packets are received or sent  by wlan6, it will blink fast. If i.MX6 is off or doesn't send a pulse, the led will be turned off. An apparent benefit of the last state (led is off) is that it can be used to determine when shutdown on i.MX6 is complete and when it's safe to turn the power off.

Yet another interesting thing that I've learned about UDOO is that even if you completely shut down i.MX6 9 (e.g. by running 'init 0') Arduino part of it will still be running.

Demo

At the video below you can see the led in two states: during the boot when the wireless interface is active trying to acquire a connection and after the boot is completed (starting @ 15th second) when there is no network activity and the led is blinking slowly because of the pulse signal sent by the i.MX6 board once in a few seconds.

 


No comments:

Post a Comment