Notes About Working with Various Arduino & Netduino Microcontroller Boards

Friday, February 1, 2013

Connecting an uM-FPU64 Math Co-Processor to an Arduino Due via I2C

Last November, I made a couple posts about using the Micromega uM-FPU (32-bit) floating point unit with an Arduino. There is also a 64-bit version of the uM-FPU co-processor. I don't really need such mathematical precision for my projects, but the 64-bit version does have some nice additional features. The uM-FPU64 is also  3.3 volt (rather than 5V, but the datasheet indicates that the I2C & SPI interfaces tolerate 5V). The 64-bit chip seems harder to find. I ended up getting mine from Solarbotics in Calgary. 

Both the 32- and 64-bit versions of the chip can be connected to an Arduino using I2C, but the Arduino libraries and examples provided by Micromega are restricted to SPI connectivity. In this post, I show how to use I2C to connect the uM-FPU64 to an Arduino Due. The sample code prints the square roots of the integers from 1 to 127 to the serial console.

Connections:

The pins on the FPU are numbered counterclockwise from the notch (starting with pin 1).

uM-FPU64  --->  Arduino Due
 1 (/MCLR)       3V3
 8 (VSS)         GND
 9 (SEL)         3V3  (3V3 = I2C mode, GND = SPI)
13 (VDD)         3V3  (with 0.1uF capacitor to GND on breadboard)
14 (SERIN)       GND
17 (SCL)         Digital 21 SCL (with 4k7 pull-up resistor to 3V3) 
18 (SDA)         Digital 20 SDA (with 4k7 pull-up resistor to 3V3)
19 (VSS)         GND
20 (VCAP)        GND via 4.7uF capacitor on breadboard
27 (AVSS)        GND 
28 (AVDD)        3V3 (with 0.1uF capacitor between 27 & 28 on breadboard)

Code:

#include <Wire.h>

#define FPU_ADDR   0x64
#define FSETI 0x32 // reg[A] = float(bb)
#define FTOA 0x1F // Convert float to ASCII
#define SELECTA 0x01 // Select register A
#define SQRT 0x41 // reg[A] = sqrt(reg[A])
#define READSTR 0xF2 // Read string from string buffer



#define SYNC 0xF0 // Get synchronization byte
#define SYNC_CHAR 0x5C // sync character

#define RESET_REG  0x01
#define RESET_CMD  0x00
#define DATA_REG   0x00

void setup() {
  Serial.begin(19200);
  while(!Serial) { ; }
  Wire.begin();

  // Reset FPU by writing 0 to I2C register addr. 1
  Wire.beginTransmission(FPU_ADDR);
  Wire.write(RESET_REG);
  Wire.write(RESET_CMD);
  Wire.endTransmission();
  // Recommended delay after reset
  delayMicroseconds(15);

  // Check FPU communication
  Wire.beginTransmission(FPU_ADDR);
  Wire.write(DATA_REG);
  Wire.write(SYNC);
  Wire.endTransmission();
  delay(10);
  Wire.requestFrom(FPU_ADDR, 1);
  while(Wire.available())    
  { 
    char c = Wire.read();    
    if(!c == SYNC_CHAR) {
      Serial.println("uM-FPU64 not responding.");
      while(1); 
    }      
  }
}

void loop() {
  for(int i = 1; i <= 127; i++) {
    String answer = "Sqrt of ";
    (answer += i) += " is ";
    Wire.beginTransmission(FPU_ADDR);
    Wire.write(DATA_REG);
    Wire.write(SELECTA);
    Wire.write(129); // FPU registers 128 & above are 64 bit
    Wire.write(FSETI);
    Wire.write(i);
    Wire.write(SQRT);
    Wire.write(FTOA);
    Wire.write(0x00);
    Wire.write(READSTR);
    Wire.endTransmission();
    Wire.requestFrom(FPU_ADDR, 32);
    while(Wire.available())    
    { 
      char c = Wire.read();    
      answer += c;         
    }
    Serial.println(answer);
  }
  while(1);
}

See the FPU64.h file in the FPU64 library from MicroMega (and include it in your sketch) for the complete list of functions.