How to port an Arduino library to ChipKit MPIDE

Post Reply
thinkpeace
Posts: 27
Joined: Tue Nov 05, 2013 6:27 am

How to port an Arduino library to ChipKit MPIDE

Post by thinkpeace » Sun Jan 19, 2014 5:56 am

Porting a library from Arduino to ChipKit MPIDE

The following are things I learned when porting the RFM12B library to run on a ChipKit WF32. The RFM12B library I ported I got from http://lowpowerlab.com/blog/2012/12/28/ ... o-library/

When porting a library from Arduino AVR to ChipKit MPIDE you should try to use Arduino library calls whenever possible rather than PIC32 or AVR specific code. Using PIC32 specific calls for efficiency is not typically needed because the PIC32 processor runs so much faster than the Arduino AVR. Also by using Arduino library calls, the code is easier to maintain and port to other boards.

I found it very useful to test everything on an Arduino while incrementally eliminating all the AVR specific code. Once it is working on the Arduino, compile and run the library on the ChipKit board. If it fails to compile, correct the incompatible code, and test again on the Arduino. Once it compiles on successfully for both the ChipKit, and for the Arduino, and runs succfully on the Arduino, it is time to test and debug the library on the ChipKit board.

The following are some of the changes that will need to be made to port Arduino code to the ChipKit.


AVR SPECIFIC INCLUDE FILES

To quickly find the AVR specific code while testing on an Arduino, remove #include <avr/io.h>, #include <avr/eeprom.h> and #include <avr/sleep.h>. Then compile to see all the missing references to AVR code.


AVR IO REGISTERS
Replace references to DDRB, PORTB and other AVR registers with pinMode() and digitalRead() and digitalWrite() calls.


SPI PORT
Replace references to SPCR and SPDR to SPI library calls:

Code: Select all

			#include <SPI.h>
			SPI.begin();
			SPI.setClockDivider( SPI_CLOCK_DIV4);
                        digitalWrite( spi_cs, LOW );
			in = SPI.transfer(out);
                        digitalWrite( spi_cs, HIGH );
INTERRUPTS
Refer to the documentation for the ChipKit board to see what pins each external interrupt uses.

Any interrupt routines that use level LOW need to be changed to FALLING, and in in the interrupt routine, a test for the IRQ pin being low needs to be added.

Code: Select all

        attachInterrupt( 0, InterruptHandler, LOW );
}

void InterruptHandler() {
// Interrupt code here
}
Would be replaced with

Code: Select all

        attachInterrupt( 0, InterruptHandler, FALLING );
}

void InterruptHandler() {
    do   {
          // Interrupt codehere
    } while( digitalRead( IRQ_PIN ) == 0 );
}
Replace references to EIMSK, EICRA and EICRB with attachInterrupt(), noInterrupts() and interrupts().


PROGRAM SPACE VARIABLES

In the RFM12B example from http://lowpowerlab.com/, LED_Control_Gateway, there was a variable declared as follows:

Code: Select all

char * sendBuf="x:y"; //format is MODE:SPEED
For it to work on the ChipKit, I had to change it to the following

Code: Select all

char sendBuf[4]
This is because on the ChipKit it was put into program space rather than in RAM.

The PROGMEM keyword is not needed. Constant variables will be put in flash without this keyword. It can be removed or defined as follows
#define PROGMEM
On the ChipKit boards, constant variables are located in flash and can be read directly. No special functions like pgm_read_word() are needed.


CRC16_UPDATE

if _crc16_update() is called, an equivalent function needs to be added. Currently the MPIDE port of the Arduino library doesn't have this function. Below is a replacement written in C which I found here: http://www.nongnu.org/avr-libc/user-man ... __crc.html.

Code: Select all

			uint16_t
			crc16update(uint16_t crc, uint8_t a)
			{
				int i;

				crc ^= a;
				for (i = 0; i < 8; ++i)
				{
					if (crc & 1)
					crc = (crc >> 1) ^ 0xA001;
					else
					crc = (crc >> 1);
				}

				return crc;
			}
SLEEP MODE

if sleep_mode() is used, instead of sleeping, use a while loop which loops until a varible set by an interrupt routine indicates that processing can continue. Example:

Code: Select all

  while(!timeToWakeup)
				 ;
If you are running from battery, and really need to put the processor to sleep, an equivalent function would need to be written.

CONDITIONAL COMPILATION

Use conditional compilation to include code specific to different board types.

Code: Select all

#ifdef defined(__AVR__)
#include	<avr/io.h>
#endif

#if defined(__PIC32MX__)
#include	<something>
#endif

#if defined(_BOARD_WF32_)
#define IRQ_PIN 3
#elif defined(_BOARD_UNO_)
#define IRQ_PIN 38
#endif
My next project will be to port the LowPowerLab RFM69 library. It should take a fraction of the time with what I've learned so far.

Post Reply