diff --git a/README.md b/README.md index 527e371..cee5c1b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ For the most basic example, please take look at [basic_polling] example. * Write register value to the module. -Disclaimer: some part of the code is based on https://github.com/mrjohnk/PMW3360DM-T2QU +Notice: some part of the code is based on https://github.com/mrjohnk/PMW3360DM-T2QU +Disclaimer: This is not a PixArt official library. USE AT YOUR OWN RISK. # License @@ -58,6 +59,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * v1.0.0 * Initial release -# v1.0.1 +* v1.0.1 * Bug fix on register reading (timing stabilized) * Sensor initialization check routine added. (begin() will return false if failed) + +* v1.1.0 + * Raw frame capture functions are updated (prepareImage, readImagePixel, endImage). + * 'Camera' example is added + diff --git a/examples/Camera/Camera.ino b/examples/Camera/Camera.ino new file mode 100644 index 0000000..dbb0c15 --- /dev/null +++ b/examples/Camera/Camera.ino @@ -0,0 +1,131 @@ +#include +/* +Frame capture (=Camera) mode: +This mode disables navigation and overwrites any downloaded firmware. +A hardware reset is required to restore navigation, and the firmware must be reloaded. + +# PIN CONNECTION + * MI = MISO + * MO = MOSI + * SS = Slave Select / Chip Select + * SC = SPI Clock + * MT = Motion (active low interrupt line) + * RS = Reset + * GD = Ground + * VI = Voltage in up to +5.5V + +Module Arduino + RS --- (NONE) + GD --- GND + MT --- (NONE) + SS --- Pin_10 (use this pin to initialize a PMW3360 instance) + SC --- SCK + MO --- MOSI + MI --- MISO + VI --- 5V + */ + +#define SS 10 // Slave Select pin. Connect this to SS on the module. + +PMW3360 sensor; + +void setup() { + Serial.begin(9600); + while(!Serial); + + if(sensor.begin(SS)) // 10 is the pin connected to SS of the module. + Serial.println("Sensor initialization successed"); + else + Serial.println("Sensor initialization failed"); + + // wait for 250 ms for frame capture. + delay(250); +} + +void loop() { + // The following routine shoud be alwyas performed together. + // BEGIN ------------------------------------------------- + sensor.prepareImage(); + for(int i=0;i<36*36;i++) + { + byte pixel = sensor.readImagePixel(); + Serial.print(pixel, DEC); + Serial.print(' '); + } + sensor.endImage(); + // END ---------------------------------------------------- + + delay(50); + + // optional: Surface quality report + int squal = sensor.readReg(REG_SQUAL); + Serial.println(squal); + + delay(10); +} + +/* Processing code for visualization (http://processing.org to downlaod) + +import processing.serial.*; + +Serial myPort; +int[] val = null; +boolean sync = false; +int lf = 10; + +void setup() +{ + size(360, 380); + String[] sList = Serial.list(); + String portName = sList[sList.length - 1]; + myPort = new Serial(this, portName, 9600); +} + +void draw() +{ + if(myPort.available() > 0) + { + String s = myPort.readStringUntil(lf); + + if(s != null) + { + int[] nums = int(split(trim(s), ' ')); + + if(nums.length == 36*36+1) + { + val = nums; + } + } + } + + if(val == null) + { + background(0); + return; + } + + background(0); + + noStroke(); + for(int i=0;i<36;i++) + { + for(int j=0;j<36;j++) + { + int pixel = val[i*36+j]; + fill(pixel); + rect(i*10, (35-j)*10, 10, 10); + } + } + + int squal = val[36*36]; + + fill(255); + text("SQUAL = "+squal, 10, 375); +} + +void keyPressed() +{ + if(key == 's') + save("frame.png"); +} +*/ \ No newline at end of file diff --git a/examples/basic_interrupt/basic_interrupt.ino b/examples/basic_interrupt/basic_interrupt.ino index ba799f5..fc6acd6 100644 --- a/examples/basic_interrupt/basic_interrupt.ino +++ b/examples/basic_interrupt/basic_interrupt.ino @@ -41,7 +41,7 @@ Module Arduino #define SS 10 // Slave Select pin. Connect this to SS on the module. PMW3360 sensor; -bool motion = false; +volatile bool motion = false; void setup() { Serial.begin(9600); diff --git a/keywords.txt b/keywords.txt index c9c4afd..bcea1b3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -17,6 +17,9 @@ getCPI KEYWORD2 readBurst KEYWORD2 readReg KEYWORD2 writeReg KEYWORD2 +prepareImage KEYWORD2 +readImagePixel KEYWORD2 +endImage KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/library.properties b/library.properties index 382b9bf..9e22558 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=PMW3360 Module -version=1.0.1 +version=1.1.0 author=Sunjun Kim maintainer=Sunjun Kim -sentence=This library allows an Arduino/Genuino board to interface with PixArt PMW3360 module -paragraph=Set parameters and get motion data from PMW3360 motion sensor module +sentence=This library allows an Arduino/Genuino board to interface with PixArt PMW3360 motion sensor module. +paragraph=You can set/get parameters, get motion data, get raw camer image from PMW3360 module. category=Sensors url=https://github.com/SunjunKim/PMW3360 architectures=* diff --git a/src/PMW3360.cpp b/src/PMW3360.cpp index 08a1d64..7c28c2f 100644 --- a/src/PMW3360.cpp +++ b/src/PMW3360.cpp @@ -304,11 +304,19 @@ const unsigned char firmware_data[] PROGMEM = { // SROM 0x04 //================================================================================ // PMW3360 Motion Sensor Module +// bascially do nothing here PMW3360::PMW3360() { } // public +/* +begin: initalize variables, prepare the sensor to be init. + +# parameter +ss_pin: The arduino pin that is connected to slave select on the module. +CPI: initial CPI. optional. +*/ bool PMW3360::begin(unsigned int ss_pin, unsigned int CPI) { _ss = ss_pin; @@ -357,6 +365,12 @@ bool PMW3360::begin(unsigned int ss_pin, unsigned int CPI) } // public +/* +setCPI: set CPI level of the motion sensor. + +# parameter +cpi: Count per Inch value +*/ void PMW3360::setCPI(unsigned int cpi) { int cpival = constrain((cpi/100)-1, 0, 0x77); // limits to 0--119 @@ -368,6 +382,12 @@ void PMW3360::setCPI(unsigned int cpi) } // public +/* +getCPI: get CPI level of the motion sensor. + +# retrun +cpi: Count per Inch value +*/ unsigned int PMW3360::getCPI() { SPI_BEGIN; @@ -378,6 +398,12 @@ unsigned int PMW3360::getCPI() } // public +/* +readBurst: get one frame of motion data. + +# retrun +type: PMW3360_DATA +*/ PMW3360_DATA PMW3360::readBurst() { unsigned long fromLast = micros() - _lastBurst; @@ -438,6 +464,14 @@ PMW3360_DATA PMW3360::readBurst() } // public +/* +readReg: get one byte value from the given reg_addr. + +# parameter +reg_addr: the register address +# retrun +byte value on the register. +*/ byte PMW3360::readReg(byte reg_addr) { SPI_BEGIN; @@ -447,6 +481,13 @@ byte PMW3360::readReg(byte reg_addr) } // public +/* +writeReg: write one byte value to the given reg_addr. + +# parameter +reg_addr: the register address +data: byte value to be pass to the register. +*/ void PMW3360::writeReg(byte reg_addr, byte data) { SPI_BEGIN; @@ -454,6 +495,9 @@ void PMW3360::writeReg(byte reg_addr, byte data) SPI_END; } +/* +adns_read_reg: write one byte value to the given reg_addr. +*/ byte PMW3360::adns_read_reg(byte reg_addr) { if(reg_addr != REG_Motion_Burst) { @@ -473,6 +517,9 @@ byte PMW3360::adns_read_reg(byte reg_addr) { return data; } +/* +adns_write_reg: write one byte value to the given reg_addr +*/ void PMW3360::adns_write_reg(byte reg_addr, byte data) { if(reg_addr != REG_Motion_Burst) { @@ -490,6 +537,9 @@ void PMW3360::adns_write_reg(byte reg_addr, byte data) { delayMicroseconds(100); // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound } +/* +adns_upload_firmware: load SROM content to the motion sensor +*/ void PMW3360::adns_upload_firmware() { //Write 0 to Rest_En bit of Config2 register to disable Rest mode. adns_write_reg(REG_Config2, 0x00); @@ -526,6 +576,11 @@ void PMW3360::adns_upload_firmware() { END_COM; } +/* +check_signature: check whether SROM is successfully loaded + +return: true if the rom is loaded correctly. +*/ bool PMW3360::check_signature() { SPI_BEGIN; @@ -536,4 +591,39 @@ bool PMW3360::check_signature() { SPI_END; return (pid==0x42 && iv_pid == 0xBD && SROM_ver == 0x04); // signature for SROM 0x04 +} + +/* +prepareImage: prepare a raw image capture from the snesor +*/ +void PMW3360::prepareImage() +{ + SPI_BEGIN; + + adns_write_reg(REG_Config2, 0x00); + + adns_write_reg(REG_Frame_Capture, 0x83); + adns_write_reg(REG_Frame_Capture, 0xc5); + + delay(20); + + BEGIN_COM; + SPI.transfer(REG_Raw_Data_Burst & 0x7f); + delayMicroseconds(20); +} +/* +readImagePixel: prepare a raw image capture from the snesor +*/ +byte PMW3360::readImagePixel() +{ + byte pixel = SPI.transfer(0); + delayMicroseconds(20); + + return pixel; +} + +void PMW3360::endImage() +{ + END_COM; + SPI_END; } \ No newline at end of file diff --git a/src/PMW3360.h b/src/PMW3360.h index 5a6054a..9f1aa6c 100644 --- a/src/PMW3360.h +++ b/src/PMW3360.h @@ -129,12 +129,18 @@ class PMW3360 { public: PMW3360(); // set CPI to 800 by default. - bool begin(unsigned int ss_pin, unsigned int CPI = 800); + // begin: initialize the module, ss_pin: slave select pin, CPI: initial Count Per Inch + bool begin(unsigned int ss_pin, unsigned int CPI = 800); + // setCPI: set Count Per Inch value void setCPI(unsigned int newCPI); + // setCPI: get CPI value (it does read CPI register from the module) unsigned int getCPI(); PMW3360_DATA readBurst(); byte readReg(byte reg_addr); void writeReg(byte reg_addr, byte data); + void prepareImage(); + byte readImagePixel(); + void endImage(); private: unsigned int _ss;