Moving code from Arduino to Raspberry Pi

Photo: Hello world, using the wiringPi library to control an LED display.
Photo: Hello world, using the WiringPi library to control an LED display.
Photo 1: Hello world, using the WiringPi library to control an LED display.

To celebrate getting the GPIO working using WiringPi from Gordon Henderson I thought I’d have a quick look at the difference between running some code on an Arduino compared to running almost the same code on a Raspberry Pi (RasPi).

It is worth noting now that the setups I’ve been using to test with are all powered from a separate 3.3V supply with the grounds linked. Nothing is being powered via the RasPi itself to avoid drawing too much current should I make a mistake. When working with the RasPi you should be careful as the RasPi will not take kindly to static discharge, connecting things backwards or the wrong voltage levels.

The really great thing about Gordon’s library is that by using it I am able to transfer Arduino code to the RasPi with only a few simple changes. Obviously not everything in the Arduino libraries are present, but the basic I/O manipulation is plenty for some simple applications.

MAX6675 thermocouple interface example

The MAX6675 from Maxim is an SPI Bus based thermocouple convertor that I built a breakout board for a while back. You can find out more information about that project in this earlier post.

As a simple test I took the basic example from the MAX6675 thermocouple interface library and adapted it to run with the WiringPi library on the RasPi.

I initially ported the example and library to C as the WiringPi was in C and I had a couple of issues compiling mixed C and C++ properly. After a bit of investigation I found that when explicitly including the libraries as C the compiling problems go away. Below is an example of how to modify the wiringPi.h file to ensure it is included as C and not C++. Gordon has said he will make this change to the library on the next release. Once I had sorted out the makefile to use g++ rather than gcc I was able to compile and link successfully.

Listing 1: Explicitly declaring a header file as C


 #ifdef __cplusplus
 extern "C" {
 #endif
  
 // wiringPi.h Code goes Here 
 //  or 
 // #include <wiringPi.h>

 #ifdef __cplusplus
 }
 #endif

While compiling and linking of the example was now okay, the next problem was that when run, the program just exited with a “Segmentation Fault” (segfault). I didn’t even see the error message when running as root with sudo, it was only when running as the standard user (pi) that it became apparent that something was wrong with the software rather than the hardware.

When I had run previous examples as the standard user I would see a permissions related error complaining that the program could not access the “/dev/mem/” device. This error comes from the part of the WiringPi library that sets up memory access to the hardware registers in the Broadcom BCM2835. This clue told me that the wiringPiSetup routine was not being run. This in turn showed me that the global object representing the temperature sensor was being constructed before the WiringPi library was being setup.

The solution to this particular problem was simple enough. I edited the MAX6675 library so that it calls wiringPiSetup directly when initialising. I also set an internal flag if this succeeds. In addition to this I modified the methods to exit with an error if the flag has not been set. This means that none of the MAX6675 library methods should ever call WiringPi functions without the appropriate initialisation having taken place and succeeded beforehand. My code for this example is here. A more general solution might be to add this flag to the WiringPi library itself.

LED Display (MLMC) and Temperature Combined Example

Following my success with the temperature sensor I decided to push the boat out a little further and try to interface to my MLMC LED display system.

The MLMC LED display is a set of LED dot matrix control PCBs I designed to use up some unusual LED modules I had lying about. You can get the full story in this blog post or on the website.

Photo:  Using the WiringPi library to control an LED display and Thermocouple interface
Photo 2: Using the WiringPi library to control an LED display and thermocouple interface

This was a simple demonstration with the RasPi reading from the thermocouple interface and then displaying the temperature on the display. For this example I wrote everything in C. The MLMC interface is very simple and involves clocking 16 bit words of data using two pins, one for data and one for clock. Each word represents a single column on the LED display. This low speed (~5Kbps) synchronous protocol was originally implemented by directly manipulating the digital I/O pins on the Arduino and so was very simple to port to the RasPi with the WiringPi library.

While the ported program functions very well, the waveforms obtained from the RasPi are quite different to those achieved with the Arduino. This is a good example of how the same simple code can be quite different when ported between platforms.

MLMC Clock Waveforms

The function used to send serial data to the MLMC is shown below. This code has a 75µs delay between switching the level of the clock and this gave uniform pulses on both systems. The pulses also appeared consistent from one run to another.

Listing 2: MLMC serial data sending routine


const int spidelay_us =75;

void Send_byte( char data ///< 8 bit data to be sent
			   ) {
    uint8_t temp;	// local copy of the data to be shifted out
    uint8_t i;					
	
    temp = data;	
    for (i=0; i<8; i++) {
		// start the cycle with the clock pin low
        digitalWrite(clockPin, LOW);

		// clock out a single byte
        if (temp & (1<<7)) {
            digitalWrite(dataPin, HIGH);
        } else {
            digitalWrite(dataPin, LOW);
        }
        
		// wait for data bit to be set up
		delayMicroseconds(spidelay_us);
        
		// clock the data out by producing a rising edge
        digitalWrite(clockPin,HIGH); 
		
		// wait for mlmc to read the data bit in 
        delayMicroseconds(spidelay_us);
		
        // shift data along by one
        temp <<= 1;
    }
	
	// leave both pins low when idle 
    digitalWrite(clockPin, LOW);
    digitalWrite(dataPin, LOW);
}

The following scope traces are the result of executing Listing 2 on the Arduino:

Clock pulses from the Arduino to the MLMC modules
Figure 1: Clock pulses from the Arduino to the MLMC modules
Single clock pulse from the Arduino to the MLMC modules
Figure 2: Single clock pulse from the Arduino to the MLMC modules

Arduino has a total pulse time of approximately 80µs for the first clock pulse to MLMC. This extra 5µs I assign to the time taken to call the digitalWrite function, a single shift operation and iterating the for-loop.

The next two traces in figure 3 and figure 4 are produced when running the same code on the RasPi:

Clock pulses from the Raspberry Pi to the MLMC modules
Figure 3: Clock pulses from the Raspberry Pi to the MLMC modules
Single clock pulse from the Raspberry Pi to the MLMC modules
Figure 4: Single clock pulse from the Raspberry Pi to the MLMC modules

You can notice that while the pulses look identical at a quick glance the RasPi has 150µs pulse width; almost double that of the Arduino. I assume that the delayMicroseconds function, which only guarantees that a minimum of the given microseconds have elapsed before returning, is releasing control to the operating system and coming back a lot later than expected. As the delay implementation in the WiringPi library simply calls nanosleep I am surprised this operation takes twice as long. There may be a number of causes for this behaviour:

  • There might be a bug in the way the delay function is implemented.
  • The shift and for-loop iteration might have compiled in a very inefficient way.
  • The operating system simply cannot schedule other tasks quickly enough to return from nanosleep and meet our expectations.

MAX6675 thermocouple interface

This loop was clocking data in from the MAX6675 chip via a “bit-banged” interface. The main loop did not have a delay and was toggling bits as quickly as possible while shifting in the value via a single GPIO pin.

Listing 3: SPI send section from the MAX6675 library


digitalWrite(_CS_pin,LOW); // Enable device

/* Cycle the clock for dummy bit 15 */
digitalWrite(_SCK_pin,HIGH);
digitalWrite(_SCK_pin,LOW);

/* Read bits 14-3 from MAX6675 for the Temp 
 Loop for each bit reading the value and 
 storing the final value in 'temp' 
 */
for (int bit=11; bit>=0; bit--){
	digitalWrite(_SCK_pin,HIGH);  // Set Clock to HIGH
	value += digitalRead(_SO_pin) << bit;  // Read data and add it to our variable
	digitalWrite(_SCK_pin,LOW);  // Set Clock to LOW
}

/* Read the TC Input inp to check for TC Errors */
digitalWrite(_SCK_pin,HIGH); // Set Clock to HIGH
error_tc = digitalRead(_SO_pin); // Read data

digitalWrite(_SCK_pin,LOW);  // Set Clock to LOW
digitalWrite(_CS_pin, HIGH); // Disable Device

The following traces in figure 5 and figure 6 show the results on the Arduino.

Clock pulses from the Arduino to the MAX6675 modules
Figure 5: Clock pulses from the Arduino to the MAX6675
Single clock pulse from the Arduino to the MAX6675 modules
Figure 6: Single clock pulse from the Arduino to the MAX6675

On the Arduino this code gave a uniform pulse train with the pulse widths measuring approximately 6-7µs. As the Arduino is running at 16Mhz I would like to think this could be optimised a lot more to get something like 120ns if I used some assembly or bypassed the Wiring/Arduino API, but that is an exercise for another blog post. 🙂

Clock pulses from the Raspberry Pi to the MAX6675 modules
Figure 7: Clock pulses from the Raspberry Pi to the MAX6675
Close-up clock pulses from the Raspberry Pi to the MAX6675 modules
Figure 8: Close-up clock pulses from the Raspberry Pi to the MAX6675

The RasPi on the other hand gave a very non-uniform pulse train. As this is synchronous communication, the clock does not need to be uniform, it dictates when the data line is read. The average pulse in this waveform is only 150ns wide which is approximately 48 times faster than the Arduino. Given that the RasPi clock speed of 700MHz is roughly 44 times faster then the Arduino clock speed of 16MHz, this makes sense.

The RasPi would vary any individual pulse length by up to a factor of two (from observation) but did not seem to be effected by increasing the load (multiple ssh sessions and running an openssl speed test). The RasPi would also continue to run the MLMC scrolling display and reading the temperature sensor without issues while another process was also reading the temperature sensor at the same time (single_temp.cpp from first example above). Even while openssl was doing speed testing (cpu usage at 98-99%) the visible operation of the screen was not effected.

Investigating Further

The long delay and changing pulse widths could be investigated further with a couple of short programs.

I could investigate the long delay further by looking at repeating the test with the system under different loads and noting the effect on the width and consistency of the pulses. To vary the workload on the RasPi I could use a tool like stress.

We could also step through many values while keeping the system load constant. This would give us an idea if their was a minimum overhead experienced by the delay function or if their was some sort of error in the calibration.

I will leave these as an exercise for another day as plenty of work has already been done on this sort thing before, although not specifically on the RasPi.

Conclusions

This was a very quick look into porting code from Arduino to Raspberry Pi. I found that it was not so difficult to port some very simple applications, the majority of the code would simply run unchanged.

While the code may compile and run, the actual operation of the code will always need to be checked carefully for timing issues and other unexpected behaviour when switching hardware and using new library implementations.

As these systems were using synchronous serial communication the exact shape of the waveforms did not actually need to be uniform for the system to work.

On review of the MAX6675 data sheet the timings slighty exceed the stated maximum clock freq of 4.3Mhz. So If I was intending to use this further I would introduce a short delay into the MAX6675 clock routine to ensure it complies with the data sheet.

The MLMC module operates perfectly with the timings achieved but we are operating at half the throughput we expected due to the delay function not operating identically to the same function on the Arduino. While this didn’t cause a problem in this simple test it could easily have done so in a slightly more complicated system.

USB Microscope

I have just purchased a Veho USB microscope and am quite pleased with the result. I was hoping to use this as a very cheap replacement for a good binocular microscope. When soldering very fine pitch surface mount devices for prototype or repair a good binocular scope is fantastic for soldering under.

Below is a video test of me upgrading the ATtiny261 to ATtiny861 on my MLMC controller PCB. While the system is reasonably good for soldering it is excellent for inspecting finished the finished work.

Microscope Video Test at 22x magnification

I took a couple of test pictures using the windows software (Microcapture). These are shown below. The software lets you draw in measurements based on the magnification which is entered manually. It’s not the greatest but it is nice and functional.

Microscope Photo Test at 22x magnification

This shows the mm scale on my steel ruler.

Microscope Test at 400x Magnification
Microscope Photo Test at 400x Magnification

This shows the 0.5mm scale elsewhere on the same ruler.

High Resolution Photo Test at 20x magnification
High Resolution Photo Test at 20x magnification

I have tested the device on Windows XP, MacOS 10.7, Fedora15. On linux I had a few issues that later turned out to be a faulty USB hub. In playing around to get the scope to work on Linux I discovered the great GTK+ UVC Viewer program. As all three operating systems have “USB Video Class” drivers everything worked out of the box (hub issues aside).

If Linux does give you any grief you may need to do a modprobe uvcvideo. I didn’t need to do this as I have another webcam plugged in as well that uses the same driver.

I’m not sure what tricks the windows driver uses to get the higher resolution as these modes did not seem to work on other platforms. If anyone knows how to get the high resolution modes working on Linux I would love to hear from you.

Modular LED Matrix Controller version 1.0

 An Arduino driving 5 MLMC modules displaying the current temperature
An Arduino driving five MLMC modules displaying the current temperature

I have finally motivated myself to publish my firmware and PCB designs for the MLMC on github. The design is functional and I have a set of five modules chained together sitting on my workbench. They happily display the current temperature via an Arduino and the MAX6675 based Thermocouple board I designed previously.

All the files for the project are currently published on github at https://github.com/brokentoaster/MLMC.

Bottom view of the controller PCBs.
Bottom view of the controller PCBs.

This Modular LED Matrix Controller (MLMC) all started about 3 years ago and you can find all the info and a demonstration video at the project web page.

Once a couple of initial glitches in the system had been worked out the modules turned out to be both reliable and easy to drive.

The power consumption as on average 12mA per module while displaying scrolling text. The current consumption is reasonably nicely distributed about the average without any large peaks in current. Each module’s refresh rate is slightly out of sync with its neighbour due to the differences in each of the AVRs on-board oscillators. This has the side effect that all columns switch on at a slightly time and avoids causing a large spike in the current. While not deliberately designed to act this way it is a benefit of the multiple controller modular design.

Trying to drive 1280 LEDs from just 4 wires was not without its problems, the three main problems are covered in greater detail in later posts but in brief they were as follows:

  • Synchronisation issues caused by jitter, noise and missing bits
  • Clocking out the last word from one module to the next
  • PCB design error – SPI pins are not always the same as the ISP serial programming pins.
  • Component Choice. Not enough memory for desired bit depth or bandwidth to achieve original functionality
  • USI in SPI mode is not the same as hardware SPI

Building a new extruder driver.

While I am reasonably happy with my initial prints I have decided to build Adrians geared extruder driver to improve the consistency of the extrusion.

The three photos show my new extruder driver.  Although the printed parts look good enough to work in this situation a close inspection of the print show the extrusion tends to “bead” a little and on some prints just stop altogether.  I’m hoping a driver with more “torque” will improve this as well as better spool management.  I’m also building a new extruder head as well to improve the temperature stability.

If anyone has other ideas on how to better improve the print quality of my reprap I’d love to hear about them.

Reprap first print!

Mendel livesReprap Steper motor driver

After four months of soldering and mucking about with screws and metal things I finally have a working 3D printer.

This was built using Makerbot electronics and aluminium versions of the printed parts. I will publish the drawings of the machined parts as soon as I have 1) tidied them up, 2) fixed the mistakes I put on them and 3) confirmed the design actually works. I made a few changes from the designs released in November in order to make them machine-able, but for the most part they are true to the original designs and taken from the STEP files or the STL files converted back into CAD files.

I’ve deliberately mounted the electronics in an open fashion on standoffs on an aluminium base plate to facilitate testing as I plan to improve and refine the design. I’d like to improve the electronics, PCB design and location of boards with an eye towards EMC and proper shielding, but for moment they are open to allow scope and multimeter access. I hope to tidy up all the cables into tidy looms and things a bit once I’m happier with the performance and reliability. I had an opto-interrupter board fail on me which resulted in a couple of crashes so I’ve temporarily replaced them with some very cheap push buttons. Probably a short circuit on the veroboard versions I built up, that’ll teach me for being too cheap to pay $1 for a decent PCB.

Repraped Lego brick gear, brick and gear

I am reasonably happy with these prints as a first attempt. I think I really need to tweak the settings and the operation of the extruder to get things working better. (The part designs are from Thingiverse parametric spur gears, Thingiverse parametric Lego block)

I’m quite glad to notice the latest version of host software is functioning on OS X, it saves me having to boot up windows every time I want to print. I say functioning and not working as it doesn’t quite fit all the controls on the screen nicely and does odd things every now and then. But it is better than it was a couple of months ago and so it is looking good for the future.

Sadly I’m off home to NZ for a few weeks so wont get a decent chance to to get it all going properly till the end of the month. On the other hand the software may have moved forward another step by then as well and I might even take the time to read the instructions.

Arduino MP3 Rev B v0.0

Last week I managed to have some luck with my Arduino MP3 shield. The big hold up was caused by not having enough power from the FT232RL chip to supply the decoder and the memory card at the same time (50mA max d-oh). I also had a software issue, I had not altered the code to deal with the 16Mhz clock speed of the arduino from the 8Mhz I was using on the ButterflyMP3 project. The SPI clock was running at 8Mhz where it needed to be slower than 6MHz (to comply with the VS1011E datasheet). Once I had that sorted everything just popped into place and started working reliably.

I apologise in advance for the poor integration of the library examples. I have simply and quite roughly ported the minimal parts of my buterflymp3 project over to the arduino and this hardware. The examples will test reading FAT16 file system on the MMC/SD card, test the VS1011E decoder chip, and play the first mp3 file found on the memory card. I hope to get these tidied up later but have not had any time to do so lately.

The PCB has not actually been tested yet so I’d hold off building a million of these until after a successful test. There is unlikely to be much wrong with it though as I have simply added a voltage regulator and re routed a couple of signals to fix my earlier mistakes. ( I’d forgotten that I/O lines 0 and 1 are used by the uart on the arduino)

I have embedded the BOM below. ( The bom is here if you don’t see it below)

Here are all the files so far. These are all released under a Creative Commons 2.5 license .

EAGLE files are here

GERBER files are here

Arduino Library files are here

PDF of the schematic is here

To use the library simply put the “mp3” folder from the zip file inside the “libraries” folder in your arduino folder (create one if it doesn’t exist). Restart Arduino 018 or later and you should have “mp3” entries in the menus under examples and import libraries.

The BOM references a 2.8V LDO voltage regulator but the schematic shows a 3.3V. Either will work fine but the 2.8 will give you slightly lower power usage.

If you are interested in PCBs or kits, drop me a line at buy_pcbs@brokentoaster.com
As always any comments, suggestions or ideas are welcome.

Reprap extruder heater

My cheap polymide tape arrived from Hong-Kong yesterday so I was able to get the heater built on the extruder for the reprap. No problems with the construction of the heater itself, although after running some tests I discovered the thermistor I had chosen is only rated to 155 degreees Celcius. I obviously wasn’t looking very hard when I ordered it or perhaps it was just the fact that it was one tenth the cost of a more suitable device that convinced me to buy it. I should have a new thermistor in this week and replace this one.

Before going too far with my heater I wanted to test the system and check that the temperature measured was accurate. I ran three sets of tests. Using the Butterfly Logger with some DS18B20’s and a SHT71 I logged the temperature of the barrel at the edge of the extruder (see close up above). The SHT-71 was used to monitor the extruder temperature with the DS18B20’s monitoring ambient. The first test was logged at 10 second intervals with the later two logged each second.

TEST 1
The first test was a 0.2 deg C/s ramp from near ambient up to 75 deg C and then a step change to 100 deg C and then passive cooling. This is shown in the plot below. The period of 10 seconds seemed too slow to give me a good idea of the stability so n the following tests it was decreased to 1 second. This did show rough correlation between the set temperatures and the measured temperatures although not really as accurate as I had hoped.

TEST 2
This test was a controlled ramp of 0.2 deg C/s from near ambient up to 100 deg C. After holding at 100 deg C the system is passively cooled to 50 deg C. The system holds at 50 deg C momentarily before being given a step change to 100 deg C, after which the system is allowed to cool to ambient.
The better time resolution allows the system stability to be better assessed. The system looks reasonably stable at the 100 deg hold mark. Here it is cycling around 5 deg around the set point. The ‘stable’ temperature is slowly rising which I attribute to the thermal mass of the barrel and thermal barrier warming up. It is not 100 deg C as it is not measuring at the same point where the control thermistor is measuring. Looking at this initially lead me to check the characteristics of the thermistor I was using and is what lead me to discover that it was only rated at 155 deg C. In checking the data sheet I also noticed a diference in the Beta value fromt he look up table used in the extruder firmware. I recalculated the look up table accordingly and repeated the tests in test 3.

TEST 3
This was a repeat of the previous tests with the new lookup table ( Beta = 4400). This seemed to give a ramp rate twice of what was programmed (0.45 deg C/s compared to 0.2 deg C/s). The temperatures seemed hotter which is expected given the change in thermistor table for the control firmware.

The next test will of course be to see how the system performs when loaded i.e. extruding some plastic.

Reprap Electronics build

I ran out of time this weekend to get anything done on the MP3 shield or the MLMC projects. I did however manage to find time to solder up the electronics for my reprap I’m building. After a couple of hitches I also got the firmware on and up and running.I had to download the latest from SVN else I got a clash between the stepper-motor drivers and the servo motor drivers in the firmware for the extruder.

I built the mother board to use a standard PC power connector even though I’m building a reprap. It just seemed silly to power this PCB via USB and then rig the power-supply to power all the other boards. I temporarily used the USB 5V to power the PCB via a pin on the JTAG connector during programming the firmware. Before the firmware on the mother board was programmed the PC PSU wouldn’t fire up so I needed a temporary power supply.

I managed to test the extruder board with some test software I found at http://objects.reprap.org/wiki/Microcontroller_Firmware_Hints#Driving_Steppers_with_the_Extruder_Controller_V2.2_.28Arduino_inside….29. But I haven’t managed to get it working through the mendel firmware via the host software yet. The thermistor was working so I know the RS485 link is functioning properly. Probably just a configuration.h option I’ve over looked.

It took a couple of hours to get the three boards all soldered up and tested. I’ll post more when I have more done. I’ll probably be focusing on the mechanical side of building the Cartesian robot for now so not much electronics left to do, although I still have the firmware to sort through…

[EDIT] It turns out that I had overlooked the I2C connection between the motherboard and the extruder board. I should really have read the instruction.