Arduino Example
This example is located in the Magnetic Imaging Tile's Hardware Repo. To grab it, go ahead and download or clone the SparkFun Magnetic Imaging Tile hardware repo.
Upload Arduino Example
After unzipping the compressed files, navigate to the hardware repo's folder and open the example: ... SparkFun_Magnetic_Imaging_Tile > Software > arduino > Example1_Basic_Readings > Example1_Basic_Readings.ino. This sketch listens for a character before parsing the data. For users using an Arduino microcontroller, select your board in the Tools menu (in our case the SparkFun RedBoard Turbo) and the correct Port it enumerated on.
You can also copy or paste the code as shown below. Then click "Upload".
/*
This basic example shows how to interface with the Magnetic Imaging Tile V3
with a Chipkit MAX32, with data displayed via the serial port.
Simple serial commands allow viewing the data in a serial console, or
sending the data to a program on a host system (such as the accompanying
Processing example) for display.
The code primarily uses the internal ADC of the Chipkit MAX32, but
(slow) code is also provided for using the AD7940 on the tile as
well. The speed of the ADC and I/O clocking is essentially the
limiting factor in framerate, and this should be kept in mind
when porting to other platforms (e.g. the Arduino Uno).
The Chipkit MAX32 provides ~128K of RAM, which is enough for a
short framebuffer (up to about 500 frames) when recording
high-speed data.
This code was written in MPIDE 0023-windows-20140316 .
*/
////Define where to pipe serial print statements
//#define terminal Serial //Use with Uno, SAMD51, Chipkit
#define terminal SerialUSB //Use with SAMD21
#define CS_INACTIVE 1
#define CS_ACTIVE 0
//Hardware connections
const byte PIN_ANALOG = A1;
//On Arduino Unos and Red Boards this is the SPI pinout
const byte PIN_CLR = 8;
const byte PIN_CLK = 9;
const byte AD7940_SPI_MISO = 12;
const byte AD7940_SPI_CS = 10;
const byte AD7940_SPI_CLK = 13;
// Pins for SAMD51
/*
const byte PIN_CLR = 5;
const byte PIN_CLK = 9;
const byte AD7940_SPI_MISO = 22;
const byte AD7940_SPI_CS = 10;
const byte AD7940_SPI_CLK = 24;
*/
// Frames
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//We have very limited RAM
#define MAX_BASE_FRAMES 2
#else
//Platforms like SAMD21, ChipKit, and Teensy have far more RAM
//#define MAX_BASE_FRAMES 500
//#define MAX_BASE_FRAMES 250
#define MAX_BASE_FRAMES 100
//#define _8BIT
#endif
#ifdef _8BIT
#define MAX_FRAMES MAX_BASE_FRAMES*2
uint8_t frames[MAX_FRAMES][64];
#else
#define MAX_FRAMES MAX_BASE_FRAMES
uint16_t frames[MAX_FRAMES][64];
#endif
// Frame variables
// Magnetic tile reading
int pixelOrder[] = {26, 27, 18, 19, 10, 11, 2, 3, 1, 0, 9, 8, 17, 16, 25, 24};
int subtileOrder[] = {0, 2, 1, 3};
int subtileOffset[] = {0, 4, 32, 36};
uint16_t frame[64];
int numFrames = 0;
int curFrame = 0;
#define MODE_IDLE 0
#define MODE_LIVE 1
#define MODE_HIGHSPEED1 2
#define MODE_HIGHSPEED2 3
#define MODE_HIGHSPEED3 4
#define MODE_HIGHSPEED4 5
#define MODE_PIXEL 6
int curMode = MODE_IDLE;
/*
Analog Read
*/
int readMagnetometer() {
//return 0;
//return analogRead(PIN_ANALOG);
//return readInternalADC();
return readAD7940();
//return read_ad7940();
}
// Take one measurement form the internal ADC
int readInternalADC() {
int numSamples = 2;
float sum = 0.0f;
for (int i = 0; i < numSamples; i++) {
int sensorValue = analogRead(PIN_ANALOG);
sum += sensorValue;
}
sum /= numSamples;
//return sensorValue;
return int(floor(sum));
}
// Take one measurement from an external AD7940 14-bit ADC (SPI)
uint16_t readAD7940() {
uint16_t value = 0;
//uint16_t delay_time = 2;
// Idle
digitalWrite(AD7940_SPI_CS, HIGH);
digitalWrite(AD7940_SPI_CLK, HIGH);
// Enable
digitalWrite(AD7940_SPI_CS, LOW);
// Read 16 bits
for (int i = 0; i < 16; i++) {
char bit = digitalRead(AD7940_SPI_MISO);
digitalWrite(AD7940_SPI_CLK, LOW);
// delayMicroseconds(delay_time);
value = value << 1;
value = value + (bit & 0x01);
digitalWrite(AD7940_SPI_CLK, HIGH);
// delayMicroseconds(delay_time);
}
// Disable
digitalWrite(AD7940_SPI_CS, HIGH);
// delayMicroseconds(delay_time);
return value;
}
/*
Magnetic Sensors
*/
void clearCounter() {
digitalWrite(PIN_CLR, 0);
//delay(10);
digitalWrite(PIN_CLR, 1);
//delay(10);
}
void incrementCounter() {
digitalWrite(PIN_CLK, 1);
//delay(1);
digitalWrite(PIN_CLK, 0);
//delay(1);
}
/*
Capture one frame from imaging array
*/
void readTileFrame() {
clearCounter();
incrementCounter();
for (int curSubtileIdx = 0; curSubtileIdx < 4; curSubtileIdx++) {
for (int curIdx = 0; curIdx < 16; curIdx++) {
// Read value
int value = readMagnetometer();
//terminal.println(value);
//delay(10);
// Store value in correct frame location
int frameOffset = pixelOrder[curIdx] + subtileOffset[subtileOrder[curSubtileIdx]];
//terminal.println(frameOffset);
//delay(25);
frame[frameOffset] = value;
// Increment to next pixel
incrementCounter();
}
}
}
// Display current frame on serial console
void displayCurrentFrame() {
// Display frame
// terminal.println ("\nCurrent Frame");
int idx = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
terminal.print( frame[idx] );
terminal.print( " " );
idx += 1;
}
terminal.println("");
}
terminal.println("*");
}
// Record MAX_FRAMES, as fast as possible
void recordHighSpeedFrames(int frameDelayTime) {
long startTime = millis();
for (int curFrame = 0; curFrame < MAX_FRAMES; curFrame++) {
// Read one frame
readTileFrame();
// Store frame
#ifdef _8BIT
for (int a = 0; a < 64; a++) {
frames[curFrame][a] = frame[a] >> 2;
}
#else
for (int a = 0; a < 64; a++) {
frames[curFrame][a] = frame[a];
}
#endif
if (frameDelayTime > 0) {
delay(frameDelayTime);
}
}
long endTime = millis();
terminal.print("Framerate: ");
terminal.println((float)MAX_FRAMES / ((float)(endTime - startTime) / 1000.0f));
}
// Playback the high speed frames stored
void playbackHighSpeedFrames() {
for (int curFrame = 0; curFrame < MAX_FRAMES; curFrame++) {
// Display frame
// terminal.print ("\nFrame ");
// terminal.println (curFrame);
int idx = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
terminal.print( frames[curFrame][idx] );
terminal.print( " " );
idx += 1;
}
terminal.println("");
}
terminal.println("*");
delay(50);
}
}
long startTime = 0;
void setup() {
// Setup pin modes
pinMode(PIN_CLR, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
// AD7940 ADC Pin modes
pinMode(AD7940_SPI_CS, OUTPUT);
pinMode(AD7940_SPI_CLK, OUTPUT);
pinMode(AD7940_SPI_MISO, INPUT);
// Setup initial states
incrementCounter();
clearCounter();
// initialize serial:
terminal.begin(115200);
while(!terminal); //Wait for user to open this terminal. Useful for SAMD21 and boards that use CDC.
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
clearCounter();
incrementCounter();
delay(100);
startTime = millis();
}
void loop() {
//Parse serial data (if any)
if(terminal.available())
{
byte incoming = terminal.read();
if (incoming == 'L') {
terminal.println("Live");
curMode = MODE_LIVE;
} else if (incoming == 'H' || incoming == '1') {
terminal.println("High-speed Save1");
curMode = MODE_HIGHSPEED1;
} else if (incoming == '2') {
terminal.println("High-speed Save2 (1000hz)");
curMode = MODE_HIGHSPEED2;
} else if (incoming == '3') {
terminal.println("High-speed Save3 (500hz)");
curMode = MODE_HIGHSPEED3;
} else if (incoming == '4') {
terminal.println("High-speed Save4 (250hz)");
curMode = MODE_HIGHSPEED4;
} else if (incoming == 'S') {
terminal.println("Idle");
curMode = MODE_IDLE;
} else if (incoming == 'P') {
terminal.println("Read Pixel 0,0");
curMode = MODE_PIXEL;
}
}
/*
Take action based on current mode
*/
if (curMode == MODE_LIVE) {
readTileFrame();
displayCurrentFrame();
} else if (curMode == MODE_HIGHSPEED1) {
// Full/maximum speed
recordHighSpeedFrames(0);
playbackHighSpeedFrames();
curMode = MODE_IDLE;
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
} else if (curMode == MODE_HIGHSPEED2) {
// ~1000Hz
recordHighSpeedFrames(1);
playbackHighSpeedFrames();
curMode = MODE_IDLE;
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
} else if (curMode == MODE_HIGHSPEED3) {
// ~500Hz
recordHighSpeedFrames(2);
playbackHighSpeedFrames();
curMode = MODE_IDLE;
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
} else if (curMode == MODE_HIGHSPEED4) {
// ~250Hz
recordHighSpeedFrames(4);
playbackHighSpeedFrames();
curMode = MODE_IDLE;
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
} else if (curMode == MODE_PIXEL) {
//Read single pixel. Good for testing.
curMode = MODE_IDLE;
terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)");
}
//delay(10);
}
Note
There is also an example for Diligent's chipKIT Max32! For users that are interested in using the board, the example code is in the chipkit folder.
Note
For users that are using a SAMD51, you will need to adjust Serial:
#define terminal Serial //Use with Uno, SAMD51, Chipkit
//#define terminal SerialUSB //Use with SAMD21
You will also need to adjust the pin definitions:
//On Arduino Unos and Red Boards this is the SPI pinout
/*
const byte PIN_CLR = 8;
const byte PIN_CLK = 9;
const byte AD7940_SPI_MISO = 12;
const byte AD7940_SPI_CS = 10;
const byte AD7940_SPI_CLK = 13;
*/
// Pins for SAMD51
const byte PIN_CLR = 5;
const byte PIN_CLK = 9;
const byte AD7940_SPI_MISO = 22;
const byte AD7940_SPI_CS = 10;
const byte AD7940_SPI_CLK = 24;
After uploading the code, open the Serial Monitor or terminal emulator of your choice with the baud rate set to 115200. Enter a character (L , H , 1 , 2 , 3, and S ) to select the mode. In this case, we set the mode to live.
The output will then begin output the readings.
Grab a magnet and place it near the sensor. In this case, the magnet was placed over the hall effect sensor at (0,0). The magnitude of the value will depend on the orientation of the magnet and the strength of the magnet. In this case, the magnitude was greater around (0,0) whenever the south pole was near the hall effect sensors.
Tip
For those that are interested in finding the polarity of your unlabeled magnet, there are several tests to determine the polarity of each end of the magnet. One method is using a compass. If the north pole is pointing toward one end of the magnet, the end of the magnet is the south pole. If the south pole is pointing toward one end of the magnet, the end of the magnet is the north pole.
If you know where the geographic north pole is, you can also attach the magnet to a string to determine its polarity. As the magnet is dangling from the string so that the poles are horizontal with respect to the floor. The south pole of the magnet will point toward the geographic north pole. Placing the magnet on a plastic lid over a bowl of water will also have the same results.
Rotating the magnet to the other pole and place it over (0,0) again. In this case, the value was lower around (0,0) whenever the north pole was near the hall effect sensors.
Try moving the magnet to a different location near the array of hall effect sensors to track the magnetic field. In this case, we moved it to (7,7). If you inspect the values, you will notice that the magnet was also rotated so that the south pole was over the hall effect sensors. In this case, the magnitude was greater around (7,7).
Rotating the magnet back to the north pole at (7,7) will result in the opposite effect where the values were lower around (0,0). This is similar to what was observed earlier.
Looking for a more visual output? We'll use this example loaded on the Arduino to visualize the output through the Processing IDE!