├── .gitattributes ├── documents ├── AD7680.pdf └── drv5053.pdf ├── hardware ├── Magnetic-Imaging-Tile-Schematic.pdf └── Production │ ├── magarray-halleffect-Panel.zip │ ├── ordering_instructions.txt │ ├── magarray-halleffect-Panel.dri │ ├── magarray-halleffect-Panel.gpi │ ├── magarray-halleffect-Panel.GBP │ ├── magarray-halleffect-Panel.TXT │ ├── magarray-halleffect-Panel.GBS │ └── magarray-halleffect-Panel.GKO ├── .gitignore ├── LICSENSE.md ├── README.md ├── software ├── arduino │ └── Example1_BasicReadings │ │ └── Example1_BasicReadings.ino ├── chipkit │ └── magtile2d_chipkit.pde └── processing │ └── magtile_processing_visualization │ └── magtile_processing_visualization.pde └── CC-BY-SA.TXT /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /documents/AD7680.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfunX/Magnetic_Imaging_Tile/HEAD/documents/AD7680.pdf -------------------------------------------------------------------------------- /documents/drv5053.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfunX/Magnetic_Imaging_Tile/HEAD/documents/drv5053.pdf -------------------------------------------------------------------------------- /hardware/Magnetic-Imaging-Tile-Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfunX/Magnetic_Imaging_Tile/HEAD/hardware/Magnetic-Imaging-Tile-Schematic.pdf -------------------------------------------------------------------------------- /hardware/Production/magarray-halleffect-Panel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfunX/Magnetic_Imaging_Tile/HEAD/hardware/Production/magarray-halleffect-Panel.zip -------------------------------------------------------------------------------- /hardware/Production/ordering_instructions.txt: -------------------------------------------------------------------------------- 1 | panel size, 105x104mm 2 | PCB thickness, 1.6mm 3 | number of layers, 2 4 | soldermask color, Black 5 | silkscreen color, white 6 | oz copper, 1oz 7 | finish, HASL lead free 8 | stencils, top+bottom 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | #Eagle Backup files 6 | *.s#? 7 | *.b#? 8 | *.l#? 9 | *.lck 10 | 11 | # Folder config file 12 | Desktop.ini 13 | 14 | # Recycle Bin used on file shares 15 | $RECYCLE.BIN/ 16 | 17 | # Windows Installer files 18 | *.cab 19 | *.msi 20 | *.msm 21 | *.msp 22 | 23 | # ========================= 24 | # Operating System Files 25 | # ========================= 26 | 27 | # OSX 28 | # ========================= 29 | 30 | .DS_Store 31 | .AppleDouble 32 | .LSOverride 33 | 34 | # Icon must ends with two \r. 35 | Icon 36 | 37 | # Thumbnails 38 | ._* 39 | 40 | # Files that might appear on external disk 41 | .Spotlight-V100 42 | .Trashes 43 | -------------------------------------------------------------------------------- /hardware/Production/magarray-halleffect-Panel.dri: -------------------------------------------------------------------------------- 1 | Generated by EAGLE CAM Processor 7.7.0 2 | 3 | Drill Station Info File: C:/Users/nathan.seidle/Dropbox/Projects/magneticimager/hardware/version3r0/Production/magarray-halleffect-Panel.dri 4 | 5 | Date : 3/2/2018 9:28 AM 6 | Drills : generated 7 | Device : Excellon drill station, coordinate format 2.4 inch 8 | 9 | Parameter settings: 10 | 11 | Tolerance Drill + : 0.00 % 12 | Tolerance Drill - : 0.00 % 13 | Rotate : no 14 | Mirror : no 15 | Optimize : yes 16 | Auto fit : yes 17 | OffsetX : 0inch 18 | OffsetY : 0inch 19 | Layers : Drills Holes 20 | 21 | Drill File Info: 22 | 23 | Data Mode : Absolute 24 | Units : 1/10000 Inch 25 | 26 | Drills used: 27 | 28 | Code Size used 29 | 30 | T01 0.0120inch 792 31 | T02 0.0150inch 6 32 | T03 0.0400inch 48 33 | T04 0.1300inch 12 34 | 35 | Total number of drills: 858 36 | 37 | Plotfiles: 38 | 39 | C:/Users/nathan.seidle/Dropbox/Projects/magneticimager/hardware/version3r0/Production/magarray-halleffect-Panel.TXT 40 | -------------------------------------------------------------------------------- /hardware/Production/magarray-halleffect-Panel.gpi: -------------------------------------------------------------------------------- 1 | Generated by EAGLE CAM Processor 7.7.0 2 | 3 | Photoplotter Info File: C:/Users/nathan.seidle/Dropbox/Projects/magneticimager/hardware/version3r0/Production/magarray-halleffect-Panel.gpi 4 | 5 | Date : 3/2/2018 9:28 AM 6 | Plotfile : C:/Users/nathan.seidle/Dropbox/Projects/magneticimager/hardware/version3r0/Production/magarray-halleffect-Panel.GBP 7 | Apertures : generated: 8 | Device : Gerber RS-274-X photoplotter, coordinate format 2.5 inch 9 | 10 | Parameter settings: 11 | 12 | Emulate Apertures : no 13 | Tolerance Draw + : 0.00 % 14 | Tolerance Draw - : 0.00 % 15 | Tolerance Flash + : 0.00 % 16 | Tolerance Flash - : 0.00 % 17 | Rotate : no 18 | Mirror : yes 19 | Optimize : yes 20 | Auto fit : yes 21 | OffsetX : 0inch 22 | OffsetY : 0inch 23 | 24 | Plotfile Info: 25 | 26 | Coordinate Format : 2.5 27 | Coordinate Units : Inch 28 | Data Mode : Absolute 29 | Zero Suppression : None 30 | End Of Block : * 31 | 32 | Apertures used: 33 | 34 | Code Shape Size used 35 | 36 | D10 rectangle 0.0550inch x 0.0137inch 576 37 | 38 | -------------------------------------------------------------------------------- /LICSENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2016 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Magnetic Imaging Tile 2 | ====== 3 | 4 | ![SparkFun Magnetic Imaging Tile](https://cdn.sparkfun.com//assets/parts/1/2/8/3/9/Magnetic-Imager-Fan.gif) 5 | 6 | [*SparkFun Magnetic Imaging Tile (SPX-14652)*](https://www.sparkfun.com/products/14652) 7 | 8 | The Magnetic Imaging Tile uses an array of 64 hall effect sensors to convert magnetic fields to the visual spectrum. That's right! You can now see magnetic fields in real time! As is to be expected, there are caveats: the magnetic sensors used on the tile are some of the most sensitive on the market but you need to be within 1 to 2 centimeters of the tile to get a good image. 9 | 10 | This is a board intended to function as a "magnetic field camera" to visualize magnetic fields. 11 | 12 | This is an endorsed fork and collaboration of [Peter Jansen's work](https://hackaday.io/project/18518-iteration-8/log/91551-a-third-high-speed-magnetic-imager-tile). All credit goes to him! SparkX has re-designed the PCB for DFM and simiplified some of the platform interfacing code. 13 | 14 | ### Version 3.0 15 | 16 | The major advancement of v3.0 is a dramatic increase in the speed with which the tile data can be read out. ~2000 frames per second (fps) can be achieved which allows visualizing even quickly varying fields (e.g. those in a 60Hz transformer, or a moving motor). Version 3.0 reduces the size of the tile to an 8x8 grid of hall effect sensors (64 total), arrayed in a 4mm grid. The boards is tile-able with up to 4 of the boards tileable with minimal borders to create a 16x16 array. 17 | 18 | For more information (and a video of the v3.0 tile in use), please see: 19 | https://hackaday.io/project/18518-iteration-8/log/91551-a-third-high-speed-magnetic-imager-tile-draft 20 | 21 | Repository Contents 22 | ------------------- 23 | 24 | * **/Documents** - Datasheets for the RV-1805-C3 and super capacitor 25 | * **/Hardware** - Eagle design files (.brd, .sch) 26 | 27 | License Information 28 | ------------------- 29 | 30 | This product is _**open source**_! 31 | 32 | Please review the LICENSE.md file for license information. 33 | 34 | If you have any questions or concerns on licensing, please contact techsupport@sparkfun.com. 35 | 36 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release any derivative under the same license. 37 | 38 | Disclaimer 39 | ------------------- 40 | 41 | **DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY.** 42 | 43 | UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 44 | 45 | TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 46 | 47 | THE DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY PROVIDED ABOVE SHALL BE INTERPRETED IN A MANNER THAT, TO THE EXTENT POSSIBLE, MOST CLOSELY APPROXIMATES AN ABSOLUTE DISCLAIMER AND WAIVER OF ALL LIABILITY. 48 | 49 | -------------------------------------------------------------------------------- /software/arduino/Example1_BasicReadings/Example1_BasicReadings.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This basic example shows how to interface with the Magnetic Imaging Tile V3 3 | with a Chipkit MAX32, with data displayed via the serial port. 4 | Simple serial commands allow viewing the data in a serial console, or 5 | sending the data to a program on a host system (such as the accompanying 6 | Processing example) for display. 7 | 8 | The code primarily uses the internal ADC of the Chipkit MAX32, but 9 | (slow) code is also provided for using the AD7940 on the tile as 10 | well. The speed of the ADC and I/O clocking is essentially the 11 | limiting factor in framerate, and this should be kept in mind 12 | when porting to other platforms (e.g. the Arduino Uno). 13 | 14 | The Chipkit MAX32 provides ~128K of RAM, which is enough for a 15 | short framebuffer (up to about 500 frames) when recording 16 | high-speed data. 17 | 18 | This code was written in MPIDE 0023-windows-20140316 . 19 | */ 20 | 21 | //Define where to pipe serial print statements 22 | //#define terminal Serial //Use with Uno and Chipkit 23 | #define terminal SerialUSB //Use with SAMD21 24 | 25 | #define CS_INACTIVE 1 26 | #define CS_ACTIVE 0 27 | 28 | //Hardware connections 29 | const byte PIN_ANALOG = A1; 30 | 31 | //On Arduino Unos and Red Boards this is the SPI pinout 32 | const byte PIN_CLR = 8; 33 | const byte PIN_CLK = 9; 34 | const byte AD7940_SPI_MISO = 12; 35 | const byte AD7940_SPI_CS = 10; 36 | const byte AD7940_SPI_CLK = 13; 37 | 38 | // Frames 39 | #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) 40 | 41 | //We have very limited RAM 42 | #define MAX_BASE_FRAMES 2 43 | 44 | #else 45 | 46 | //Platforms like SAMD21, ChipKit, and Teensy have far more RAM 47 | //#define MAX_BASE_FRAMES 500 48 | //#define MAX_BASE_FRAMES 250 49 | #define MAX_BASE_FRAMES 100 50 | //#define _8BIT 51 | 52 | #endif 53 | 54 | #ifdef _8BIT 55 | #define MAX_FRAMES MAX_BASE_FRAMES*2 56 | uint8_t frames[MAX_FRAMES][64]; 57 | #else 58 | #define MAX_FRAMES MAX_BASE_FRAMES 59 | uint16_t frames[MAX_FRAMES][64]; 60 | #endif 61 | 62 | // Frame variables 63 | // Magnetic tile reading 64 | int pixelOrder[] = {26, 27, 18, 19, 10, 11, 2, 3, 1, 0, 9, 8, 17, 16, 25, 24}; 65 | int subtileOrder[] = {0, 2, 1, 3}; 66 | int subtileOffset[] = {0, 4, 32, 36}; 67 | uint16_t frame[64]; 68 | 69 | int numFrames = 0; 70 | int curFrame = 0; 71 | 72 | #define MODE_IDLE 0 73 | #define MODE_LIVE 1 74 | #define MODE_HIGHSPEED1 2 75 | #define MODE_HIGHSPEED2 3 76 | #define MODE_HIGHSPEED3 4 77 | #define MODE_HIGHSPEED4 5 78 | #define MODE_PIXEL 6 79 | 80 | int curMode = MODE_IDLE; 81 | 82 | /* 83 | Analog Read 84 | */ 85 | int readMagnetometer() { 86 | //return 0; 87 | //return analogRead(PIN_ANALOG); 88 | //return readInternalADC(); 89 | return readAD7940(); 90 | //return read_ad7940(); 91 | } 92 | 93 | // Take one measurement form the internal ADC 94 | int readInternalADC() { 95 | int numSamples = 2; 96 | float sum = 0.0f; 97 | for (int i = 0; i < numSamples; i++) { 98 | int sensorValue = analogRead(PIN_ANALOG); 99 | sum += sensorValue; 100 | } 101 | sum /= numSamples; 102 | 103 | //return sensorValue; 104 | return int(floor(sum)); 105 | } 106 | 107 | 108 | // Take one measurement from an external AD7940 14-bit ADC (SPI) 109 | uint16_t readAD7940() { 110 | uint16_t value = 0; 111 | //uint16_t delay_time = 2; 112 | 113 | // Idle 114 | digitalWrite(AD7940_SPI_CS, HIGH); 115 | digitalWrite(AD7940_SPI_CLK, HIGH); 116 | 117 | // Enable 118 | digitalWrite(AD7940_SPI_CS, LOW); 119 | 120 | // Read 16 bits 121 | for (int i = 0; i < 16; i++) { 122 | char bit = digitalRead(AD7940_SPI_MISO); 123 | digitalWrite(AD7940_SPI_CLK, LOW); 124 | // delayMicroseconds(delay_time); 125 | 126 | value = value << 1; 127 | value = value + (bit & 0x01); 128 | digitalWrite(AD7940_SPI_CLK, HIGH); 129 | // delayMicroseconds(delay_time); 130 | } 131 | // Disable 132 | digitalWrite(AD7940_SPI_CS, HIGH); 133 | // delayMicroseconds(delay_time); 134 | 135 | return value; 136 | } 137 | 138 | /* 139 | Magnetic Sensors 140 | */ 141 | void clearCounter() { 142 | digitalWrite(PIN_CLR, 0); 143 | //delay(10); 144 | digitalWrite(PIN_CLR, 1); 145 | //delay(10); 146 | } 147 | 148 | void incrementCounter() { 149 | digitalWrite(PIN_CLK, 1); 150 | //delay(1); 151 | digitalWrite(PIN_CLK, 0); 152 | //delay(1); 153 | } 154 | 155 | /* 156 | Capture one frame from imaging array 157 | */ 158 | void readTileFrame() { 159 | 160 | clearCounter(); 161 | incrementCounter(); 162 | 163 | for (int curSubtileIdx = 0; curSubtileIdx < 4; curSubtileIdx++) { 164 | for (int curIdx = 0; curIdx < 16; curIdx++) { 165 | // Read value 166 | int value = readMagnetometer(); 167 | 168 | //terminal.println(value); 169 | //delay(10); 170 | 171 | // Store value in correct frame location 172 | int frameOffset = pixelOrder[curIdx] + subtileOffset[subtileOrder[curSubtileIdx]]; 173 | //terminal.println(frameOffset); 174 | //delay(25); 175 | frame[frameOffset] = value; 176 | 177 | // Increment to next pixel 178 | incrementCounter(); 179 | } 180 | } 181 | } 182 | 183 | // Display current frame on serial console 184 | void displayCurrentFrame() { 185 | // Display frame 186 | // terminal.println ("\nCurrent Frame"); 187 | int idx = 0; 188 | for (int i = 0; i < 8; i++) { 189 | for (int j = 0; j < 8; j++) { 190 | terminal.print( frame[idx] ); 191 | terminal.print( " " ); 192 | idx += 1; 193 | } 194 | terminal.println(""); 195 | } 196 | terminal.println("*"); 197 | } 198 | 199 | // Record MAX_FRAMES, as fast as possible 200 | void recordHighSpeedFrames(int frameDelayTime) { 201 | long startTime = millis(); 202 | 203 | for (int curFrame = 0; curFrame < MAX_FRAMES; curFrame++) { 204 | // Read one frame 205 | readTileFrame(); 206 | 207 | // Store frame 208 | #ifdef _8BIT 209 | for (int a = 0; a < 64; a++) { 210 | frames[curFrame][a] = frame[a] >> 2; 211 | } 212 | #else 213 | for (int a = 0; a < 64; a++) { 214 | frames[curFrame][a] = frame[a]; 215 | } 216 | #endif 217 | 218 | if (frameDelayTime > 0) { 219 | delay(frameDelayTime); 220 | } 221 | } 222 | 223 | long endTime = millis(); 224 | terminal.print("Framerate: "); 225 | terminal.println((float)MAX_FRAMES / ((float)(endTime - startTime) / 1000.0f)); 226 | } 227 | 228 | // Playback the high speed frames stored 229 | void playbackHighSpeedFrames() { 230 | 231 | for (int curFrame = 0; curFrame < MAX_FRAMES; curFrame++) { 232 | // Display frame 233 | // terminal.print ("\nFrame "); 234 | // terminal.println (curFrame); 235 | 236 | int idx = 0; 237 | for (int i = 0; i < 8; i++) { 238 | for (int j = 0; j < 8; j++) { 239 | terminal.print( frames[curFrame][idx] ); 240 | terminal.print( " " ); 241 | idx += 1; 242 | } 243 | terminal.println(""); 244 | } 245 | terminal.println("*"); 246 | delay(50); 247 | } 248 | } 249 | 250 | long startTime = 0; 251 | 252 | void setup() { 253 | // Setup pin modes 254 | pinMode(PIN_CLR, OUTPUT); 255 | pinMode(PIN_CLK, OUTPUT); 256 | 257 | // AD7940 ADC Pin modes 258 | pinMode(AD7940_SPI_CS, OUTPUT); 259 | pinMode(AD7940_SPI_CLK, OUTPUT); 260 | pinMode(AD7940_SPI_MISO, INPUT); 261 | 262 | // Setup initial states 263 | incrementCounter(); 264 | clearCounter(); 265 | 266 | // initialize serial: 267 | terminal.begin(115200); 268 | while(!terminal); //Wait for user to open this terminal. Useful for SAMD21 and boards that use CDC. 269 | 270 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 271 | 272 | clearCounter(); 273 | incrementCounter(); 274 | delay(100); 275 | 276 | startTime = millis(); 277 | } 278 | 279 | void loop() { 280 | 281 | //Parse serial data (if any) 282 | if(terminal.available()) 283 | { 284 | byte incoming = terminal.read(); 285 | 286 | if (incoming == 'L') { 287 | terminal.println("Live"); 288 | curMode = MODE_LIVE; 289 | 290 | } else if (incoming == 'H' || incoming == '1') { 291 | terminal.println("High-speed Save1"); 292 | curMode = MODE_HIGHSPEED1; 293 | 294 | } else if (incoming == '2') { 295 | terminal.println("High-speed Save2 (1000hz)"); 296 | curMode = MODE_HIGHSPEED2; 297 | 298 | } else if (incoming == '3') { 299 | terminal.println("High-speed Save3 (500hz)"); 300 | curMode = MODE_HIGHSPEED3; 301 | 302 | } else if (incoming == '4') { 303 | terminal.println("High-speed Save4 (250hz)"); 304 | curMode = MODE_HIGHSPEED4; 305 | 306 | } else if (incoming == 'S') { 307 | terminal.println("Idle"); 308 | curMode = MODE_IDLE; 309 | 310 | } else if (incoming == 'P') { 311 | terminal.println("Read Pixel 0,0"); 312 | curMode = MODE_PIXEL; 313 | } 314 | } 315 | 316 | /* 317 | Take action based on current mode 318 | */ 319 | if (curMode == MODE_LIVE) { 320 | readTileFrame(); 321 | displayCurrentFrame(); 322 | 323 | } else if (curMode == MODE_HIGHSPEED1) { 324 | // Full/maximum speed 325 | recordHighSpeedFrames(0); 326 | playbackHighSpeedFrames(); 327 | curMode = MODE_IDLE; 328 | 329 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 330 | 331 | } else if (curMode == MODE_HIGHSPEED2) { 332 | // ~1000Hz 333 | recordHighSpeedFrames(1); 334 | playbackHighSpeedFrames(); 335 | curMode = MODE_IDLE; 336 | 337 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 338 | 339 | } else if (curMode == MODE_HIGHSPEED3) { 340 | // ~500Hz 341 | recordHighSpeedFrames(2); 342 | playbackHighSpeedFrames(); 343 | curMode = MODE_IDLE; 344 | 345 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 346 | 347 | } else if (curMode == MODE_HIGHSPEED4) { 348 | // ~250Hz 349 | recordHighSpeedFrames(4); 350 | playbackHighSpeedFrames(); 351 | curMode = MODE_IDLE; 352 | 353 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 354 | 355 | } else if (curMode == MODE_PIXEL) { 356 | //Read single pixel. Good for testing. 357 | 358 | curMode = MODE_IDLE; 359 | 360 | terminal.println ("Initializing.... Press L (live) or H (high speed), 1, 2, 3, or S (idle)"); 361 | } 362 | 363 | //delay(10); 364 | } 365 | 366 | -------------------------------------------------------------------------------- /software/chipkit/magtile2d_chipkit.pde: -------------------------------------------------------------------------------- 1 | // This basic example shows how to interface with the Magnetic Imaging Tile V3 2 | // with a Chipkit MAX32, with data displayed via the serial port. 3 | // Simple serial commands allow viewing the data in a serial console, or 4 | // sending the data to a program on a host system (such as the accompanying 5 | // Processing example) for display. 6 | // 7 | // The code primarily uses the internal ADC of the Chipkit MAX32, but 8 | // (slow) code is also provided for using the AD7940 on the tile as 9 | // well. The speed of the ADC and I/O clocking is essentially the 10 | // limiting factor in framerate, and this should be kept in mind 11 | // when porting to other platforms (e.g. the Arduino Uno). 12 | // 13 | // The Chipkit MAX32 provides ~128K of RAM, which is enough for a 14 | // short framebuffer (up to about 500 frames) when recording 15 | // high-speed data. 16 | // 17 | // This code was written in MPIDE 0023-windows-20140316 . 18 | 19 | 20 | char inputString[80]; // a String to hold incoming data 21 | boolean stringComplete = false; // whether the string is complete 22 | int curStrIdx = 0; 23 | 24 | 25 | int PIN_CLR = 8; 26 | int PIN_CLK = 9; 27 | 28 | #define PIN_ANALOG A1 29 | 30 | #define CS_INACTIVE 1 31 | #define CS_ACTIVE 0 32 | 33 | // AD7940 pinout 34 | #define AD7940_SPI_MISO 5 35 | #define AD7940_SPI_CS 6 36 | #define AD7940_SPI_CLK 7 37 | 38 | 39 | // Frames 40 | //#define MAX_BASE_FRAMES 500 41 | //#define MAX_BASE_FRAMES 250 42 | #define MAX_BASE_FRAMES 100 43 | //#define _8BIT 44 | 45 | #ifdef _8BIT 46 | #define MAX_FRAMES MAX_BASE_FRAMES*2 47 | uint8_t frames[MAX_FRAMES][64]; 48 | #else 49 | #define MAX_FRAMES MAX_BASE_FRAMES 50 | uint16_t frames[MAX_FRAMES][64]; 51 | #endif 52 | 53 | 54 | // Frame variables 55 | // Magnetic tile reading 56 | int pixelOrder[] = {26, 27, 18, 19, 10, 11, 2, 3, 1, 0, 9, 8, 17, 16, 25, 24}; 57 | int subtileOrder[] = {0, 2, 1, 3}; 58 | int subtileOffset[] = {0, 4, 32, 36}; 59 | uint16_t frame[64]; 60 | 61 | int numFrames = 0; 62 | int curFrame = 0; 63 | 64 | #define MODE_IDLE 0 65 | #define MODE_LIVE 1 66 | #define MODE_HIGHSPEED1 2 67 | #define MODE_HIGHSPEED2 3 68 | #define MODE_HIGHSPEED3 4 69 | #define MODE_HIGHSPEED4 5 70 | 71 | int curMode = MODE_IDLE; 72 | 73 | 74 | 75 | /* 76 | * Analog Read 77 | */ 78 | 79 | int readMagnetometer() { 80 | //return 0; 81 | return analogRead(PIN_ANALOG); 82 | //return readInternalADC(); 83 | //return readAD7940(); 84 | //return read_ad7940(); 85 | } 86 | 87 | // Take one measurement form the internal ADC 88 | int readInternalADC() { 89 | int numSamples = 2; 90 | float sum = 0.0f; 91 | for (int i=0; i> 2; 210 | } 211 | #else 212 | for (int a=0; a<64; a++) { 213 | frames[curFrame][a] = frame[a]; 214 | } 215 | #endif 216 | 217 | if (frameDelayTime > 0) { 218 | delay(frameDelayTime); 219 | } 220 | } 221 | 222 | long endTime = millis(); 223 | Serial.print("Framerate: "); 224 | Serial.println((float)MAX_FRAMES / ((float)(endTime-startTime)/1000.0f)); 225 | 226 | } 227 | 228 | 229 | // Playback the high speed frames stored 230 | void playbackHighSpeedFrames() { 231 | 232 | for (int curFrame=0; curFrame= MAX_SIZE) { 85 | curDataIdx = 0; 86 | 87 | if (calibrationEnabled == 1) { 88 | numCalibFrames += 1; 89 | 90 | if (numCalibFrames > maxCalibFrames) { 91 | calibrationEnabled = 0; 92 | calibration(); 93 | } 94 | } 95 | } 96 | 97 | // Helpful debug message: Display serial data after parsing. 98 | //println ("Parsed x:" + x + " y:" + y); 99 | } 100 | } 101 | 102 | /* 103 | // Mask 104 | for (int i=0; i<12; i++) { 105 | for (int j=0; j<12; j++) { 106 | if ((i >= 2) && (i<= 7) && (j >= 2) && (j <= 9)) { 107 | if (j == 9) { 108 | data[i][j] = 400 - data[i][j]; 109 | } 110 | // keep existing data 111 | } else { 112 | data[i][j] = 200; 113 | } 114 | } 115 | } 116 | */ 117 | 118 | } 119 | 120 | 121 | void calibration() { 122 | 123 | println("Calibration Data:"); 124 | for (int i=0; i: Save screenshot to file. 288 | if (key == ' ') { 289 | saveFrame("screenshot-" + screenshot_number + ".png"); 290 | screenshot_number += 1; 291 | } 292 | 293 | // Press 'a': Clear data array 294 | if (key == 'a') { 295 | for (int i=0; i