The dark side of porting Arduino sketches on Intel Galileo (part two)

Hi geek friends ( female & male)!

This is the post of the “real dark side” of porting external hardware control from Arduino to Intel Galileo. And, it’s just an example, a little sketch of the real work.

…Are you ready? Before starting this dangerous “trip” I want you send a first warning: unfortunately the x86 (the architecture of Intel Quark, the CPU inside the Intel Galileo) is very different from the architecture of the AVR (the Arduino MCU). So, registers, memory spaces etc. are completely different (Monty Python docet!).

My (insane, very insane 🙂 ) idea was to port some “lower level” code from Arduino Mega to Intel Galileo, in order to verify on my skin the real hardware differences between the two platforms and also in order to compare the “hardware level” performances.

I opened the “Arduino on Android kit” (a very appreciated gift from Monica! ;-)) and I found two very interesting hardware components: two ht1632c bicolor (red/green) led displays.

What a cool find! 😉 I love the shifting dysplays in the chinese stuff stores! 😀

So… I googled for already working driver on Arduino for these devices. I found some very interesting solution. The first one library is here, and it is very powerful and fast in my little opinion.

I tried on the Arduino Mega all the library demo sketches and I verified the correct work for my two displays. Looking inside the code I saw that all the library is based on AVR registers programming (using in every instruction all the possible bit-field functions, bit masks, bitwise operators and so on…).

Weahhhh…ok, I know this is the correct mode to write a driver, and it’s true that I wanted to go to a “lower level”…. but not so low! 😀

Indeed, once ported the code inside the Intel Galileo IDE, a so high number of “undefined references”  gave me the real proof that NOT ALL the AVR architecture has been ported by the Intel team in the Galileo development environment…. so we have two natural choices: the first one is to rewrite all the library using the Quark registers instead the AVR registers (but we are inside a Linux environment, it’s no so simple to manipulate the low level hardware without interact with the Linux kernel) or, the second choice is try to write a library at an higher level, using only the basic functionalities  (so using the native APIs) of Arduino.

I preferred the second oprion (…you suspected it, I know! :-)), so  I started looking for a little simpler (and without too many functionalities) library working directly on Arduino GPIOs, in order to simplify the porting phases (and possibly without losing my love in microelectronics 😉 )

I found the code  and the circuit reported on Arduino Playground (I love this site…because it’s a made in Italy product. You know, we don’t have only corruption, not-so-effordable persons & politicants… and soccer 😉 )….and -oh, oh- it was exactly what I was looking for. 😀

I took all the code and, after I removed the parts (code and hardware) related to the real time clock (because actually I don’t have a RTC!), I compiled the code in the Arduino IDE and I flashed it on my Arduino Mega. I obtained a “fixed hours and day” red and green clock on my two led displays. The draw of the displays is very fast (approx. immediate).

Ok, I ported the same code in the Galileo IDE and I obtained some compilation errors, tied to the hardware differences between Arduino and Galileo. This is the pinout for display I used:

ht1632_pinout

Mainly Galileo IDE doesn’t have the <avr/pgmspace.h>… it’s natural since it’s a x86 CPU…but it is also a problem, because the great majority of third party lins use this file and its definitions (especially to declare some variable directly in the program flash, since Arduino doesn’t have so much RAM).

But since Galileo has a lot of RAM, it isn’t necessary to save data in the flash program space.

So, following the defines reported in avr/pgmspace.h , I changed in the file font1.h definitions:

PGM_P CHL[] PROGMEM= [...]

in a simple

char* CHL[] = [...] .

After this, I removed the #include <avr/pgmspace.h> in the main .ino file,  and in the same file (function set_buffer()) I changed the line :

memcpy_P(buffer[j], (PGM_P)pgm_read_word(&(CHL[j+pos])), 8);

in

memcpy(buffer[j], (const char *)(&(CHL[j+pos])), 8);

Once resolved the errors, I compiled and flashed the code on Galileo.

I obtained a strange behavior: instead of the clock some strange character appeared on the two displays, with a very very (very! 😦 ) slow draw rate.

Ok, I think the strange characters are tied on a non perfect alignment on the memory in the x86 respect to the AVR  or to different sizes of some data type, especially due to the above memcpy porting  (but I didn’t investigated so much because I was worried by the displays slow draw rate). So, I changed the initial code in order to write a text on display pixel by pixel (note that this is the same approach of the original code), starting from drawing a single pixel in a certain (x,y) coordinate.

The differences between the initial code and my modified code can be easily found comparing the code in the page of Arduino Playground and the attached the zip file.

I attach the complete code as zip file since the code is too long for a blog post…and I think this post is already too long. But remember this is a “difficult” post. It MUST be long! 😉 Please excuse any commented code and some commentsin Italian…I know this is a lab “spaghetti code” . 😉

Ok, using this code the text is shown in the correct way on Intel Galileo (….to be investigated the strange drawing with the original code! 😉 ), but using Galileo the draw process took approx. 20 seconds (versus the Arduino result, which is minor than 1 second!!!) and with some different delay times between one pixel draw and the subsequent.

This is the final result (sorry for the up-down text, but I have very short wires between Galileo and the display…;-) ). In the background of the photo you can see two beautiful italian progressive rock cds by Maurizio di Tollo and by La Maschera di Cera (both my good friends), which have been the inspiration for my porting work. 🙂

20140330_104925

Any ideas for this behavior (the slow drawing process)? I have one…but I don’t know if it is the correct idea.

As you know, Intel Galileo runs the Arduino sketches as Linux user processes (so, all kernel calls, interrupts, threads etc. have a higher priority  than a user process and so they can interrupt the execution of the Arduino skecth), whereas in Arduino no operating system is used (the sketch is a well-known “bare metal” code), so a real time behavior is a “true real time” behavior, and the sketch runs at the highest speed without interruptions.

So… what can I say? Intel Galileo is a really fast machine (compared to Arduino Mega or UNO) but in my little opinion it has some little “real time” problem when using the Arduino IOs (also I know my code is not optimized at all!!! 😉 ). And you? What do you think? 😉

Please, express your geek thinkings, and find al my errors! I will appreciate each contribution, especially  tied to my errors….the knowledge is always a mindstorm! 😉

Bye bye folks, now I go on my sofa to drink my brandy.

Another day is passed…another post is written. 🙂

ML

 

Advertisements

The dark side of porting Arduino sketches on Intel Galileo (part one)

….Hi folks, here we are again!

As promised in my last post, this time we start to talk about the porting procedures (and issues) from Arduino UNO/Mega ADK to Intel Galileo.

One can think the porting is painless (since Intel Galileo is born from a “collaboration” between Intel and Arduino guys), but unfortunately the truth is different. My experience tell me that’s the naked reality behind the embedded world…but this is a sad

Ok, the first thing you will notice porting a sketch from Arduino IDE to Galileo IDE is that NOT ALL Arduino libraries have been ported correctly in the Galileo environment (do you remember my old post? The String class is one of these examples…), so you could encounter a great number of “undeclared” variable or function errors. Someone told me that also TFT library doesn’t work correctly in Galileo….I’m a little sad…. 😦

But today we talk about some “working” library, in order to gain some succesful result before the “real  battles”! 😉

For example, the I2C library seems to work in the same way in Arduino environment and in the Galileo environment. The I2C is a serial communication protocol used to connect Arduino (and in general all processors) with external devices.

An exampre of therse devices are EEPROMs of 24cXX series. I used these EEPROMs for maaaaaaany years, because simply they use the I2C protocol, so they are serial (=slower, I know it)….but they use few wires to be commanded. And it isn’t a little thing when using Arduino UNO! 🙂

…The parallel EEPROMs such as 28cXX are much faster but they use too much electrical links (and Arduino UNO doesn’t have so many GPIOs!).

Right, let’s go ahead. In order to read/write from/to the 24cXX EEPROM I used a very nice library found on Arduino Playground .

Then I designed a little circuit (with Fritzing) in order to use one 24c64 (64kbytes) EEPROM and one 24c256 (256 kbytes). This is the circuit (please…use Intel Galileo instead Arduino UNO, with a pin-to-pin correspondance, and all should be work correctly! 😉 ):

EEPROM_doppia_v2_bb

Then I wrote a very simple “dummy” sketch in order to execute some basic operation on the EEPROMs.

#include <Wire.h> //Arduino I2C library...which works also on Intel Galileo!

//////LIBRARY functions taken from http://playground.arduino.cc/Code/I2CEEPROM

  void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
    int rdata = data;
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.write(rdata);
    Wire.endTransmission();
  }

  // WARNING: address is a page address, 6-bit end will wrap around
  // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
  void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddresspage >> 8)); // MSB
    Wire.write((int)(eeaddresspage & 0xFF)); // LSB
    byte c;
    for ( c = 0; c < length; c++)
      Wire.write(data[c]);
    Wire.endTransmission();
  }

  byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
    byte rdata = 0xFF;
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,1);
    if (Wire.available()) rdata = Wire.read();
    return rdata;
  }

  // maybe let's not read more than 30 or 32 bytes at a time!
  void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ )
      if (Wire.available()) buffer[c] = Wire.read();
  }

///////////end of I2C EEPROM library

  void setup() 
  {
    //pinMode(9, INPUT); 
    pinMode(10, OUTPUT); //used to power on/off 24C256 EEPROM
    pinMode(11, OUTPUT); //used to power on/off 24C64 EEPROM

    //power off EEPROMs
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);

    Wire.begin(); // initialise the connection
    Serial.begin(115200);

  }

  void loop() 
  {
    byte incomingCommand='F';
    int selected =-1;
     char somedata256[] = "BANK 1: ML test writing to 256K EEPROM"; // data to write
    char somedata64[] = "BANK 2: ML test writing to 64K EEPROM"; // data to write

    // see if there's incoming serial data:
    if (Serial.available() > 0) {

      // read the contetnt of the serial buffer:
      incomingCommand = Serial.read();

    if (incomingCommand == '1') { //write on Bank 1
      digitalWrite(10, HIGH);
      digitalWrite(11, LOW);
      selected=256;
    } 
    else if (incomingCommand == '2') { //write on Bank 2
      digitalWrite(10, LOW);
      digitalWrite(11, HIGH);
      selected=64;
    }
    else if (incomingCommand == '0') //erase the Bank 1 and 2
    {
      digitalWrite(10, LOW);
      digitalWrite(11, LOW);
      selected=0;
    }
    else if (incomingCommand == '3') { //read Bank 1
      digitalWrite(10, HIGH);
      digitalWrite(11, LOW);
      selected=2561;
    }

   else if (incomingCommand == '4') { //read Bank 2
      digitalWrite(11, HIGH);
      digitalWrite(10, LOW);
      selected=641;
    }

  }

////depending on command received on serial terminal, execute some action on EEPROMs

    if (selected==256)
    {
      Serial.println("256K Memory writing...");
      for (int i=0;i<sizeof(somedata256);i++)
      {
        i2c_eeprom_write_byte(0x50,i,somedata256[i]);
        delay(10); 
      }
     Serial.println("256K Memory written!");
     Serial.println("256K Memory reading...");
     int addr=0; //first address
     byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory
     while (b!=0) 
        {
          Serial.print((char)b); //print content to serial port
          addr++; //increase address
          b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
        }
    Serial.println(" ");
    Serial.println("256K memory read finished!");
    delay(2000);
    digitalWrite(10,LOW);
    }

    else if (selected==64)
    {
       Serial.println("64K Memory writing...");
      for (int i=0;i<sizeof(somedata64);i++)
      {
        i2c_eeprom_write_byte(0x50,i,somedata64[i]);
        delay(10); 
      }
     Serial.println("64K Memory written");
     Serial.println("64K Memory reading...");
     int addr=0; //first address
     byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory
     while (b!=0) 
        {
          Serial.print((char)b); //print content to serial port
          addr++; //increase address
          b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
        }
      Serial.println(" ");
      Serial.println("64K memory read finished!");
      delay(2000);
      digitalWrite(11,LOW);
    }

    else if (selected==0)
    {
      digitalWrite(11, HIGH);
      delay(10);
      Serial.println("64K Memory erasing...");
      for (int i=0;i<100;i++)
      {
        i2c_eeprom_write_byte(0x50,i,'0');
        delay(10); 
      }
     Serial.println("64K Memory erased");
     digitalWrite(11, LOW);
     digitalWrite(10, HIGH);
     delay(10);
     Serial.println("256K Memory erasing...");
      for (int i=0;i<100;i++)
      {
        i2c_eeprom_write_byte(0x50,i,'0');
        delay(10); 
      }
     Serial.println("256K Memory erased");
     digitalWrite(10, LOW);
    }

    else if (selected==641)
    {
      Serial.println("64K Memory reading...");
     int addr=0; //first address
     byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory
     while (b!=0) 
        {
          Serial.print((char)b); //print content to serial port
          addr++; //increase address
          b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
        }
      Serial.println(" ");
      Serial.println("64K memory read finished!");
      delay(2000);
      digitalWrite(11,LOW);
    }
    else if (selected==2561)
    {
       Serial.println("256K Memory reading...");
       int addr=0; //first address
       byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory
       while (b!=0) 
        {
          Serial.print((char)b); //print content to serial port
          addr++; //increase address
          b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
        }
      Serial.println(" ");
      Serial.println("256K memory read finished!");
      delay(2000);
      digitalWrite(10,LOW);
    }
  }

Well, once the code will be downloaded on the Galileo, open the IDE serial monitor and use the following commands in order to read/write the EEPROMs:

  • <1+Enter> will write a fixed pattern (somedata256[]) on the 24c256
  • <2+Enter> will write a pattern (somedata64[])on the 24c64
  • <0+Enter> will erase both EEPROMs
  • <3+Enter> will read content from the 24c256 and write it on the serial monitor
  • <4+Enter> will read content from the 24c64 and write it on the serial monitor

You can see the behavior of the code and the access times looking at the ON/OFF status of the two leds present in the circuit . I know this project is a toy-example…but it can be a good simple step to start using I2C interface (and Arduino I2C library) on Intel Galileo.

Ok. This time we joked dear guys ;-), because in the next episode… we will encounter the real “dark side” of the porting from Arduino to Galileo. Cross your fingers, drink a beer and ….relax!

…Bye bye!