ADNS2051 Library Program Demonstration

Dependencies:   ADNS2051lib FatFileSystem mbed MI0283QTlib

Files at this revision

API Documentation at this revision

Comitter:
clemente
Date:
Mon May 28 20:50:49 2012 +0000
Commit message:

Changed in this revision

ADNS2051lib.lib Show annotated file Show diff for this revision Revisions of this file
FatFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
MI0283QTlib.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ADNS2051lib.lib	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/clemente/code/ADNS2051lib/#462017ee2a5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem.lib	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AdamGreen/code/FatFileSystem/#6ceefe1c53e4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MI0283QTlib.lib	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/clemente/code/MI0283QTlib/#7ad454fed160
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.cpp	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,457 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+#include "SDFileSystem.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            _cmd58();
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+//    printf("init card = %d\n", i);
+//    printf("OK\n");
+
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(20000000); // Set to 20MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * 512) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * 512) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+
+    int csd_structure = ext_bits(csd, 127, 126);
+    int c_size = ext_bits(csd, 73, 62);
+    int c_size_mult = ext_bits(csd, 49, 47);
+    int read_bl_len = ext_bits(csd, 83, 80);
+
+//    printf("CSD_STRUCT = %d\n", csd_structure);
+    
+    if(csd_structure != 0) {
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+        return 0;
+    }
+             
+    // memory capacity = BLOCKNR * BLOCK_LEN
+    // where
+    //  BLOCKNR = (C_SIZE+1) * MULT
+    //  MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+    //  BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)         
+                            
+    int block_len = 1 << read_bl_len;
+    int mult = 1 << (c_size_mult + 2);
+    int blocknr = (c_size + 1) * mult;
+    int capacity = blocknr * block_len;
+        
+    int blocks = capacity / 512;
+        
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.h	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,81 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs;     
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,1124 @@
+#include "mbed.h"
+#include "ADNS2051.h"
+#include "MI0283QTlib.h"
+
+
+/** Demo software for ADNS2051 optical sensor.
+ * 
+ */
+ 
+// masks type
+#define PREWITT             1
+#define KIRSCH              2
+#define SOBEL               3
+// gamma value
+#define GAMMA_25            1       // gamma value=2.5
+#define GAMMA_22            2       // gamma value=2.2
+#define GAMMA_18            3       // gamma value=1.8
+
+/** Color and Edges enhancement
+ * I took these two functions from the book: "Digital Media Processing DSP Algorithms Using C Hazarathaiah Malepati".
+ * 
+ * From the book:
+ *   Histogram equalization technique of color enhancement in the RGB domain. 
+ *   As we know, if the color component is represented with 8-bit precision, then the values 0 to 255 are used to represent a
+ *   particular color component.We say that the image colors are well represented when the color components occupy
+ *   the total range of 0 to 255. If the color components of an image do not occupy the full range (i.e., 0 to 255), then
+ *   we have the scope to enhance the colors of that image.With the histogram equalization technique, first we find
+ *   the minimum (Xmin) and maximum (Xmax) values of a particular color component, and then we translate that
+ *   color component to have minimum value at zero by subtracting the Xmin from its values, and finally, multiply the
+ *   color component by 255/(Xmax− Xmin) to obtain the maximum color component 255. This process is illustrated
+ *   in Figure 10.1. The same process is applied for all three color components of an image. This process enhances
+ *   image colors (green becomes greener, yellow becomes more yellow, etc.), 
+ */
+void color_enhancement( unsigned char *pixelmap);
+
+/**
+ * From the book:
+ *   With edge enhancement, we increase the contrast of the image along the edges. The edge enhancement is done by
+ *   strengthening the high-frequency components of an image. One way of enhancing edges is by adding weighted
+ *   high-frequency components of an image to itself.
+ */
+void edges_enhancement( unsigned char *pixelmap);
+
+/** From the book: Image processing in C Dwayne Phillips
+ * The quick edge function performs edge detection using the single 3 x 3
+ * quick mask. It performs convolution over the image array using the quick mask.
+ * It thresholds the output image if requested, and xes the edges of the output
+ * image.
+ * Geometric operations change the spatial relationships between objects in an
+ * image. They do this by moving objects around and changing the size and
+ * shape of objects. Geometric operations help rearrange an image so we can
+ * see what we want to see a little better.
+ * The three basic geometric operations are displacement, stretching, and
+ * rotation. A fourth operation is the cross product.
+ * Displacement moves or displaces an image in the vertical and horizontal
+ * directions. Stretching enlarges or reduces an image in the vertical and horizontal
+ * directions. Rotation turns or rotates an image by any angle.
+ */
+void quick_edge(unsigned char *pixelmap, unsigned char *outmap, unsigned int threshold);
+void setup_masks(unsigned int detect_type, int *mask_0, int *mask_1, int *mask_2, int *mask_3, int *mask_4, int *mask_5, int *mask_6, int *mask_7);
+void perform_convolution(unsigned char *image, unsigned char *out_image, unsigned char detect_type, unsigned char threshold);
+void geometry(unsigned char *the_image, unsigned char *out_image,
+        float x_angle,
+        float x_stretch, float y_stretch,
+        int x_displace, int y_displace,
+        float x_cross, float y_cross,
+        int bilinear,
+        int rows,
+        int cols);
+unsigned char bilinear_interpolate(unsigned char *the_image, double x, double y, int rows, int cols);
+/* I found these books very useful and instructive. Recommend them wholeheartedly. */
+
+
+/** Draw enlarged image to the x and y coordinates.
+ * The image will be enlarged by 4.
+ *
+ * @param *pxlmap the array image
+ * @param x the x position
+ * @param y the y position
+ */
+void magnify( unsigned char *pxlmap, unsigned int x, unsigned int y);
+void gammacorrection( unsigned char *pixelmap, unsigned char gammaval);
+
+//
+DigitalOut myled(LED2);
+DigitalOut DBG_LED(LED1);
+DigitalOut TS_CS(p15);
+//
+Serial pc(USBTX, USBRX);
+//
+ADNS2051 optical( p19, p20);
+//
+GLCD lcd(  p11, p12, p13, p14, p17, p26);
+
+unsigned char pxlmap[256];
+//unsigned char edgemap[256];
+unsigned char tmpmap[256];
+
+int new_hi=63, new_low=10;
+int threshold_val=50;
+float edges_val=0.5;
+
+#define COLOR_LVL  32
+
+/*
+ #define COLOR_LVL  256
+ 
+ gamma LUT generated using this formula:
+ 
+ new_pixel=(( org_pixel/COLOR_LVL)^(1/gamma))*COLOR_LVL
+ 
+    // set gamma value...
+    gammaval=2.5;
+    float f2=1/gammaval;
+    // start LUT generation...
+    for ( i=0; i<COLOR_LVL; i++) {
+            float f1=(float)i/COLOR_LVL;
+            gammaLUT[i] = pow( f1,f2)*COLOR_LVL;
+    }
+    
+*/
+
+/* LUT for gamma value: 2.5 */
+unsigned char gmm25_LUT[32]={
+    0, 7, 10, 12, 13, 15, 16, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24,
+    24, 25, 25, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31, 31, 
+};
+
+/* LUT for gamma value: 2.2 */
+unsigned char gmm22_LUT[32]={
+    0, 6, 9, 10, 12, 13, 14, 16, 17, 17, 18, 19, 20, 21, 21, 22, 23,
+    24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 29, 30, 30, 31, 31, 
+};
+
+/* LUT for gamma value: 1.8 */
+unsigned char gmm18_LUT[32]={
+    0, 4, 6, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21,
+    22, 23, 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30, 30, 31, 
+};
+
+void gammacorrection( unsigned char *pixelmap, unsigned char gammaval)
+{
+    unsigned char *pGammaLUT;
+    unsigned char x0, y0;
+    int M=16, N=16;
+    int j, i, p, q;
+    
+    switch (gammaval) {
+        case GAMMA_25:
+            pGammaLUT=(unsigned char*)gmm25_LUT;
+        break;
+        case GAMMA_22:
+            pGammaLUT=(unsigned char*)gmm22_LUT;
+        break;
+        case GAMMA_18:
+            pGammaLUT=(unsigned char*)gmm18_LUT;
+        break;
+    }
+    
+    for(j = 0;j < M;j++){
+        p = j*N;q = (j + 1)*N;
+        for(i = p;i < q; i++){
+            y0 = pixelmap[i];
+            x0 = pGammaLUT[y0];
+            pixelmap[i] = x0;
+        }
+    }
+}
+
+#define FILL    255
+
+/*******************************************
+*
+*   geometry(..
+*
+*   This routine performs geometric
+*   transformations on the pixels in an
+*   image array.  It performs basic
+*   displacement, stretching, and rotation.
+*
+*   The basic equations are:
+*
+*   new x = x.cos(a) + y.sin(a) + x_displace
+*           + x.x_stretch +x.y.x_cross
+*
+*   new y = y.cos(a) - x.sin(a) + y_displace
+*           + y.y_stretch +x.y.y_cross
+*
+*******************************************/
+void geometry(unsigned char *the_image, unsigned char *out_image,
+        float x_angle,
+        float x_stretch, float y_stretch,
+        int x_displace, int y_displace,
+        float x_cross, float y_cross,
+        int bilinear,
+        int rows,
+        int cols)
+{
+   double cosa, sina, radian_angle, tmpx, tmpy;
+   float  fi, fj, x_div, y_div, x_num, y_num;
+   int    i, j, new_i, new_j;
+
+
+      /******************************
+      *
+      *   Load the terms array with
+      *   the correct parameters.
+      *
+      *******************************/
+
+      /* the following magic number is from
+         180 degrees divided by pi */
+   radian_angle = x_angle/57.29577951;
+   cosa  = cos(radian_angle);
+   sina  = sin(radian_angle);
+
+      /************************************
+      *
+      *   NOTE: You divide by the
+      *   stretching factors. Therefore, if
+      *   they are zero, you divide by 1.
+      *   You do this with the x_div y_div
+      *   variables. You also need a
+      *   numerator term to create a zero
+      *   product.  You do this with the
+      *   x_num and y_num variables.
+      *
+      *************************************/
+
+   if(x_stretch < 0.00001){
+      x_div = 1.0;
+      x_num = 0.0;
+   }
+   else{
+      x_div = x_stretch;
+      x_num = 1.0;
+   }
+
+   if(y_stretch < 0.00001){
+      y_div = 1.0;
+      y_num = 0.0;
+   }
+   else{
+      y_div = y_stretch;
+      y_num = 1.0;
+   }
+
+      /**************************
+      *
+      *   Loop over image array
+      *
+      **************************/
+
+   for(i=0; i<rows; i++){
+      for(j=0; j<cols; j++){
+
+         fi = i;
+         fj = j;
+
+         tmpx = (double)(j)*cosa         +
+                (double)(i)*sina         +
+                (double)(x_displace)     +
+                (double)(x_num*fj/x_div) +
+                (double)(x_cross*i*j);
+
+         tmpy = (double)(i)*cosa         -
+                (double)(j)*sina         +
+                (double)(y_displace)     +
+                (double)(y_num*fi/y_div) +
+                (double)(y_cross*i*j);
+
+         if(x_stretch != 0.0)
+            tmpx = tmpx - (double)(fj*cosa + fi*sina);
+         if(y_stretch != 0.0)
+            tmpy = tmpy - (double)(fi*cosa - fj*sina);
+
+         new_j = tmpx;
+         new_i = tmpy;
+
+         if(bilinear == 0){
+            if(new_j < 0       ||
+               new_j >= cols   ||
+               new_i < 0       ||
+               new_i >= rows)
+               out_image[j+(i*rows)] = FILL;
+            else
+               out_image[j+(i*rows)] =
+                the_image[new_j+(new_i*rows)];
+         }  /* ends if bilinear */
+         else{
+            out_image[j+(i*rows)] = 
+               bilinear_interpolate(the_image,
+                                    tmpx, tmpy,
+                                    rows, cols);
+         }  /* ends bilinear if */
+
+      }  /* ends loop over j */
+   }  /* ends loop over i */
+
+}  /* ends geometry */
+
+
+
+/*******************************************
+*
+*   bilinear_interpolate(..
+*
+*   This routine performs bi-linear
+*   interpolation.
+*
+*   If x or y is out of range, i.e. less
+*   than zero or greater than rows or cols,
+*   this routine returns a zero.
+*
+*   If x and y are both in range, this
+*   routine interpolates in the horizontal
+*   and vertical directions and returns
+*   the proper gray level.
+*
+*******************************************/
+unsigned char bilinear_interpolate(unsigned char *the_image, double x, double y, int rows, int cols)
+{
+   double fraction_x, fraction_y,
+          one_minus_x, one_minus_y,
+          tmp_double;
+   int    ceil_x, ceil_y, floor_x, floor_y;
+   short  p1, p2, p3, result = FILL;
+
+      /******************************
+      *
+      *   If x or y is out of range,
+      *   return a FILL.
+      *
+      *******************************/
+
+   if(x < 0.0               ||
+      x >= (double)(cols-1)   ||
+      y < 0.0               ||
+      y >= (double)(rows-1))
+      return(result);
+
+   tmp_double = floor(x);
+   floor_x    = tmp_double;
+   tmp_double = floor(y);
+   floor_y    = tmp_double;
+   tmp_double = ceil(x);
+   ceil_x     = tmp_double;
+   tmp_double = ceil(y);
+   ceil_y     = tmp_double;
+
+   fraction_x = x - floor(x);
+   fraction_y = y - floor(y);
+
+   one_minus_x = 1.0 - fraction_x;
+   one_minus_y = 1.0 - fraction_y;
+
+   tmp_double = one_minus_x * 
+          (double)(the_image[floor_x+(floor_y*rows)]) +
+          fraction_x * 
+          (double)(the_image[ceil_x+(floor_y*rows)]);
+   p1         = tmp_double;
+
+   tmp_double = one_minus_x * 
+          (double)(the_image[floor_x+(ceil_y*rows)]) +
+          fraction_x * 
+          (double)(the_image[ceil_x+(ceil_y*rows)]);
+   p2         = tmp_double;
+
+   tmp_double = one_minus_y * (double)(p1) +
+          fraction_y * (double)(p2);
+   p3         = tmp_double;
+
+
+   return(p3);
+
+}  /* ends bilinear_interpolate */
+
+
+
+/***************************
+*
+*   Directions for the masks
+*  3 2 1
+*  4 x 0
+*  5 6 7
+*
+****************************/
+/* masks for kirsch operator */
+int kirsch_mask_0[9] =  {
+        5,  5,  5,
+       -3,  0, -3,
+       -3, -3, -3};
+
+int kirsch_mask_1[9] =  {
+       -3,  5,  5,
+       -3,  0,  5,
+       -3, -3, -3};
+
+int kirsch_mask_2[9] =  {
+       -3, -3,  5,
+       -3,  0,  5,
+       -3, -3,  5};
+
+int kirsch_mask_3[9] =  {
+       -3, -3, -3,
+       -3,  0,  5,
+       -3,  5,  5};
+
+int kirsch_mask_4[9] =  {
+       -3, -3, -3,
+       -3,  0, -3,
+        5,  5,  5};
+
+int kirsch_mask_5[9] =  {
+       -3, -3, -3,
+        5,  0, -3,
+        5,  5, -3};
+
+int kirsch_mask_6[9] =  {
+        5, -3, -3,
+        5,  0, -3,
+        5, -3, -3};
+
+int kirsch_mask_7[9] =  {
+        5,  5, -3,
+        5,  0, -3,
+       -3, -3, -3};
+
+
+   /* masks for prewitt operator */
+
+int prewitt_mask_0[9] =  {
+        1,  1,  1,
+        1, -2,  1
+       -1, -1, -1 };
+
+int prewitt_mask_1[9] =  {
+        1,  1,  1,
+        1, -2, -1,
+        1, -1, -1 };
+
+int prewitt_mask_2[9] =  {
+        1,  1, -1,
+        1, -2, -1,
+        1,  1, -1 };
+
+int prewitt_mask_3[9] =  {
+        1, -1, -1,
+        1, -2, -1,
+        1,  1,  1};
+
+int prewitt_mask_4[9] =  {
+       -1, -1, -1,
+        1, -2,  1,
+        1,  1,  1};
+
+int prewitt_mask_5[9] =  {
+       -1, -1,  1,
+       -1, -2,  1,
+        1,  1,  1};
+
+int prewitt_mask_6[9] =  {
+       -1,  1,  1,
+       -1, -2,  1,
+       -1,  1,  1};
+
+int prewitt_mask_7[9] =  {
+        1,  1,  1,
+       -1, -2,  1,
+       -1, -1,  1};
+
+
+   /* masks for sobel operator */
+
+int sobel_mask_0[9] =  {
+        1,  2,  1,
+        0,  0,  0,
+       -1, -2, -1};
+
+int sobel_mask_1[9] =  {
+        2,  1,  0,
+        1,  0, -1,
+        0, -1, -2 };
+
+int sobel_mask_2[9] =  {
+        1,  0, -1,
+        2,  0, -2,
+        1,  0, -1};
+int sobel_mask_3[9] =  {
+        0, -1, -2,
+        1,  0, -1,
+        2,  1,  0 };
+int sobel_mask_4[9] =  {
+       -1, -2, -1,
+        0,  0,  0,
+        1,  2,  1};
+
+int sobel_mask_5[9] =  {
+       -2, -1,  0,
+       -1,  0,  1,
+        0,  1,  2};
+
+int sobel_mask_6[9] =  {
+       -1,  0,  1,
+       -2,  0,  2,
+       -1,  0,  1};
+
+int sobel_mask_7[9] =  {
+        0,  1,  2,
+       -1,  0,  1,
+       -2, -1,  0};
+
+
+/***********************************************
+*
+*    setup_masks(...
+*
+*    This function copies the mask values defined
+*    at the top of this file into the mask
+*    arrays mask_0 through mask_7.
+*
+***********************************************/
+void setup_masks(unsigned int detect_type, int *mask_0, int *mask_1, int *mask_2, int *mask_3, int *mask_4, int *mask_5, int *mask_6, int *mask_7)
+{
+   int i;
+
+   if(detect_type == KIRSCH){
+    for(i=0; i<9; i++){
+        mask_0[i] = kirsch_mask_0[i];
+        mask_1[i] = kirsch_mask_1[i];
+        mask_2[i] = kirsch_mask_2[i];
+        mask_3[i] = kirsch_mask_3[i];
+        mask_4[i] = kirsch_mask_4[i];
+        mask_5[i] = kirsch_mask_5[i];
+        mask_6[i] = kirsch_mask_6[i];
+        mask_7[i] = kirsch_mask_7[i];
+    }
+   }  /* ends if detect_type == KIRSCH */
+
+
+   if(detect_type == PREWITT){
+      for(i=0; i<9; i++){
+          mask_0[i] = prewitt_mask_0[i];
+          mask_1[i] = prewitt_mask_1[i];
+          mask_2[i] = prewitt_mask_2[i];
+          mask_3[i] = prewitt_mask_3[i];
+          mask_4[i] = prewitt_mask_4[i];
+          mask_5[i] = prewitt_mask_5[i];
+          mask_6[i] = prewitt_mask_6[i];
+          mask_7[i] = prewitt_mask_7[i];
+      }
+   }  /* ends if detect_type == PREWITT */
+
+
+   if(detect_type == SOBEL){
+      for(i=0; i<9; i++){
+          mask_0[i] = sobel_mask_0[i];
+          mask_1[i] = sobel_mask_1[i];
+          mask_2[i] = sobel_mask_2[i];
+          mask_3[i] = sobel_mask_3[i];
+          mask_4[i] = sobel_mask_4[i];
+          mask_5[i] = sobel_mask_5[i];
+          mask_6[i] = sobel_mask_6[i];
+          mask_7[i] = sobel_mask_7[i];
+      }
+   }  /* ends if detect_type == SOBEL */
+
+}  /* ends setup_masks */
+
+/**********************************************************
+*
+*   perform_convolution(...
+*
+*   This function performs convolution between the input
+*   image and 8 3x3 masks.  The result is placed in
+*   the out_image.
+*
+********************************************************/
+void perform_convolution(unsigned char *image, unsigned char *out_image, unsigned char detect_type, unsigned char threshold)
+{
+
+    int b, i, j, sum, p, q, c, k;
+
+    int mask_0[9];
+    int mask_1[9];
+    int mask_2[9];
+    int mask_3[9];
+    int mask_4[9];
+    int mask_5[9];
+    int mask_6[9];
+    int mask_7[9];
+
+    int max,
+        min,
+        new_hi,
+        new_low;
+
+    int M=16, N=16;
+
+    setup_masks(detect_type, &mask_0[0], &mask_1[0],&mask_2[0], &mask_3[0], &mask_4[0], &mask_5[0],&mask_6[0], &mask_7[0]);
+
+    new_hi  = 60;
+    new_low = 10;
+
+    min = 10;
+    max = 63;
+
+    /* clear output image array */
+    for(i=0; i<N*M; i++)
+        out_image[i] = 0;
+
+    for( j = 1;j < (M-1);j++){
+        p = j*N; q = (j+1)*N;
+        for( i = (p+1);i < (q-1);i++) {
+
+         /* Convolve for all 8 directions */
+
+         /* 0 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_0[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 1 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_1[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 2 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_2[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 3 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_3[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 4 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_4[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 5 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_5[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 6 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_6[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+         /* 7 direction */
+
+        sum = 0;
+        c=0;
+        for( k=(i-N); k<=(i+N); k+=N) {
+            for(b=-1; b<2; b++){
+               sum = sum + image[k+b] * mask_7[c++];
+            }
+        }
+        if(sum < 0)   sum = 0;
+        if(sum > max) sum = max;
+        if(sum > out_image[i])
+            out_image[i] = sum;
+
+
+      }  /* ends loop over j */
+   }  /* ends loop over i */
+
+   /* if desired, threshold the output image */
+   if(threshold == 1){
+    for( j = 0;j < M;j++){
+        p = j*N; q = (j+1)*N;
+        for( i = p;i < q;i++) {
+             if(out_image[i] > 50){
+                  out_image[i] = new_hi;
+             }
+             else{
+                  out_image[i] = new_low;
+             }
+          }
+       }
+   }  /* ends if threshold == 1 */
+
+}  /* ends perform_convolution */
+
+
+/*******************************************
+ *
+ *   quick_edge(...
+ *
+ *   This function finds edges by using
+ *   a single 3x3 mask.
+ *
+ *******************************************/
+void quick_edge(unsigned char *pixelmap, unsigned char *outmap, unsigned int threshold)
+{
+    int  i, j, k, c, p, q, b;
+    int max, sum;
+
+    int M=16, N=16;
+
+    int quick_mask[9] =  {
+       -1,  0, -1,
+        0,  4,  0,
+       -1,  0, -1 };
+
+    max = 63;
+
+    /* Do convolution over image array */
+    for( j = 1;j < (M-1);j++){
+        p = j*N; q = (j+1)*N;
+        for( i = (p+1);i < (q-1);i++) {
+            sum = 0;
+            c=0;
+            for( k=(i-N); k<=(i+N); k+=N) {
+                for(b=-1; b<2; b++){
+                   sum = sum + pixelmap[k+b] * quick_mask[c++];
+                }
+             }
+            if(sum < 0)   sum = 0;
+            if(sum > max) sum = max;
+            outmap[i] = sum;
+        }  /* ends loop over i */
+    }  /* ends loop over j */
+
+   /* if desired, threshold the output image */
+   if(threshold == 1){
+    for( j = 0;j < M;j++){
+        p = j*N; q = (j+1)*N;
+        for( i = p;i < q;i++) {
+             if(outmap[i] > threshold_val){
+                  outmap[i] = new_hi;
+             }
+             else{
+                  outmap[i] = new_low;
+             }
+          }
+       }
+   }  /* ends if threshold == 1 */
+
+}  /* ends quick_edge */
+
+
+
+void edges_enhancement( unsigned char *pixelmap)
+{
+    int i, j, N, M, p, q;
+    unsigned char BufX[256];
+    int y0, x0;
+    
+    N=16;
+    M=16;
+
+    for(j = 0;j < 1;j++) { // copy top row
+        p = j*N; q = (j+1)*N;
+        for(i = p;i < q;i++)
+            BufX[i] = pixelmap[i];
+    }
+    for(j = 0;j < M;j++) { // copy left column
+        p = j*N;
+        BufX[p] = pixelmap[p];
+    }
+    for(j = 1;j < M-1;j++) {
+        p = j*N+1; q = (j+1)*N-1;
+        for(i = p;i < q;i++) {
+            x0 = pixelmap[i]; y0 = pixelmap[i-1];
+            x0 = x0 << 2;
+            x0 = x0 - y0; y0 = pixelmap[i+1];
+            x0 = x0 - y0; y0 = pixelmap[i-N-1];
+            x0 = x0 - y0; y0 = pixelmap[i+N+1];
+            x0 = x0 - y0;
+            x0 = (int) pixelmap[i] + (int) x0*edges_val;
+            if (x0 < 0) x0 = 0;
+            if (x0 > 63) x0 = 63;
+            BufX[i] = (unsigned char) x0;
+        }
+    }
+    //
+    for(j = 0;j < M;j++){
+        p = j*N; q = (j+1)*N;
+        for(i = p;i < q;i++)
+            pixelmap[i] = BufX[i];
+    }
+}
+
+void color_enhancement( unsigned char *pixelmap)
+{
+    int i, j, N, M, p, q;
+    unsigned char Hist[64];
+    int y0, x0;
+    float x;
+    
+    N=16;
+    M=16;
+    
+    for(i=0; i<64; i++)
+        Hist[i]=0;
+
+    // Starting the color enhancement
+    //
+    for(j = 0;j < M;j++){
+        p = j*N;
+        q = (j+1)*N;
+        for(i = p;i < q;i++)
+        Hist[ pixelmap[i]] += 1;
+    }
+
+    y0 = 0;
+    for(p = 0;p < 64;p++) {
+        y0+= Hist[p];
+        if (y0 > 32)
+            break;
+    }
+
+    y0=p;
+    x = 0;
+    for(j = 0;j < M;j++) {
+        p = j*N; q = (j+1)*N;
+        for(i = p;i < q;i++) {
+            x0 = (int) pixelmap[i] - y0;
+            if (x0 < 0)
+                x0 = 0;
+            if (x0 > 63)
+                x0 = 63;
+            pixelmap[i] = x0;
+        }
+    }
+
+    for(j = 63;j > 0;j--)
+        if (Hist[j] > 0) break;
+
+    x = (float) 64.0/(64-y0 + 63-j);
+
+    for(j = 0;j < M;j++) {
+        p = j*N; q = (j+1)*N;
+        for(i = p;i < q;i++)
+            pixelmap[i] = (unsigned char) ((float) pixelmap[i]*x + 0.5);
+    }
+
+}
+
+int main() {
+
+    char buf[256], c;
+    int i, ii;
+    int thrshld=0;
+    int masktype=1;
+    int gammaval=0;     // gamma OFF
+        
+    myled = 0;
+    TS_CS=1;
+    //
+    int subidx, idx;
+    
+    lcd.lcd_init();
+    lcd.lcd_clear( LCD_WHITE);
+    lcd.backlightset( 1);
+    lcd.lcd_drawstr( "Images from optical mouse: Init", 0, 0, lcd.lcd_RGB( 0, 255, 0));
+    
+    while( optical.init() );
+    optical.setframerate();
+    
+    sprintf(buf, "Images from optical mouse: PixelDump [Chip rev: 0x%X]", optical.get_revisionID());
+    lcd.lcd_drawstr( buf, 0, 0, lcd.lcd_RGB( 0, 255, 0));
+    wait( 1.0);
+    
+    //
+    while( 1) {
+    
+        // you can use the serial terminal to change some parameters:
+        // [T/t] threshold ON/OFF
+        // [V/v] threshold value inc/dec 
+        // [H/h] high value inc/dec
+        // [E/e] edge enhancement inc/dec
+        // [m]   change mask type
+        // [g]   change gamma value
+        //
+        if( pc.readable()) {
+            c = pc.getc();
+            if ( c=='t') {
+                thrshld=0;
+                printf("thrshld OFF\r\n");
+            }
+            if ( c=='T') {
+                thrshld=1;
+                printf("thrshld ON\r\n");
+            }
+            // threshold_val, new_hi, new_low
+            if ( c=='V') {
+                threshold_val++;
+                if ( threshold_val>63)
+                    threshold_val=63;
+                printf("threshold_val=%d\r\n", threshold_val);
+            }
+            if ( c=='v') {
+                threshold_val--;
+                if ( threshold_val<0)
+                    threshold_val=0;
+                printf("threshold_val=%d\r\n", threshold_val);
+            }
+            if ( c=='H') {
+                new_hi++;
+                if ( new_hi>63)
+                    new_hi=63;
+                printf("new_hi=%d\r\n", new_hi);
+            }
+            if ( c=='h') {
+                new_hi--;
+                if ( new_hi<0)
+                    new_hi=0;
+                printf("new_hi=%d\r\n", new_hi);
+            }
+            /* edges enhancement */
+            if ( c=='e') {
+                edges_val-=0.1;
+                if ( edges_val<0)
+                    edges_val=0;
+                printf("edges_val=%1.2f\r\n", edges_val);
+            }
+            if ( c=='E') {
+                edges_val+=0.1;
+                if ( edges_val>1)
+                    edges_val=1;
+                printf("edges_val=%1.2f\r\n", edges_val);
+            }                        
+            // 
+            if ( c=='m') {
+                masktype+=1;
+                if ( masktype>3)
+                    masktype=1;
+                printf("masktype=%d\r\n", masktype);
+            }            
+            // 
+            if ( c=='g') {
+                gammaval+=1;
+                if ( gammaval>3)
+                    gammaval=0;
+                printf("gammaval=%d\r\n", gammaval);
+            }                        
+        }
+        
+        unsigned char mv=optical.readmotion();
+        sprintf(buf, "SQUAL:%d, dX:%+d, dY:%+d, Motion:0x%X    ", optical.surfacequality(), optical.deltaX, optical.deltaY, mv);
+        lcd.lcd_drawstr( buf, 0, 200, lcd.lcd_RGB( 0, 255, 0));
+        
+        sprintf(buf, "AvrPxl:%d, MxPxl:%d    ", optical.averagepixel(), optical.maxpixelval() );
+        lcd.lcd_drawstr( buf, 0, 220, lcd.lcd_RGB( 0, 255, 0));
+        
+        optical.pixeldump( &tmpmap[0]);
+
+        if ( gammaval) {
+            gammacorrection( &tmpmap[0], gammaval);
+        }
+        
+        // pixelmap has the correct order: pos 0 is the left,upper image position.
+        // Refer to the DS pag:35 about how to display the array
+        c=0;
+        subidx=0xFF;
+        for( i=0;i<16;i++) {
+            idx=subidx;
+            for ( ii=0; ii<16; ii++) {
+                pxlmap[c++]=tmpmap[idx];
+                idx-=16;
+            }
+            subidx--;
+        }
+        
+        // Use the feature geometry only for implementing the bilinear better viewing.
+        geometry( &pxlmap[0], &tmpmap[0], 
+                0.0,                        // angle
+                0.0, 0.0,                   // streatch x, y
+                0.0, 0.0,                   // displace x, y
+                0.0, 0.0,                   // cross x, y
+                1,                          // bilinear ON/OFF
+                16, 16);                    // rows, cols
+        
+        // I copy the correct image in the array pxlmap to use it as a basis for successive processing.
+        for ( i=0; i<(16*16); i++)
+            pxlmap[i] = tmpmap[i];
+     
+        // 1 
+        magnify( &tmpmap[0], 20, 20);
+
+        //
+        for( i=0;i<256;i++) {
+            tmpmap[i]=pxlmap[i];
+        }
+        
+        // 2
+        color_enhancement( &tmpmap[0]);
+        magnify( &tmpmap[0], 120, 20);
+        
+        //
+        for( i=0;i<256;i++) {
+            tmpmap[i]=pxlmap[i];
+        }
+        
+        // 3
+        edges_enhancement( &tmpmap[0]);
+        magnify( &tmpmap[0], 220, 20);
+        
+        // 4
+        quick_edge( &pxlmap[0], &tmpmap[0], thrshld);
+        magnify( &tmpmap[0], 20, 100);
+        
+        // 5
+        perform_convolution( &pxlmap[0], &tmpmap[0], masktype, thrshld);
+        magnify( &tmpmap[0], 120, 100);
+
+        // 6
+        // visualizzo l'immagine originale...        
+        magnify( &pxlmap[0], 220, 100);
+
+    }
+    
+    while(1) {
+        myled = 1;
+        wait(0.2);
+        myled = 0;
+        wait(0.2);
+    }
+}
+
+/* use the geometry function to magnify the image. */
+void magnify( unsigned char *pxlmap, unsigned int x, unsigned int y)
+{
+    unsigned int r, c;
+    float xy_str=(float)64/16;
+    unsigned char tmpmap[256];
+    
+    // inizio ciclo...   
+    for ( r=0; r<16; r+=4) {
+        for ( c=0; c<16; c+=4) {
+            // eseguo lo zoom sull'immagine...
+            geometry( &pxlmap[0], &tmpmap[0], 
+                    0.0,                        // angle
+                    xy_str, xy_str,             // streatch x, y
+                    (float)c, (float)r,         // displace x, y
+                    0.0, 0.0,                   // cross x, y
+                    1,                          // bilinear ON/OFF
+                    16, 16);                    // rows, cols
+            // la visualizzo...        
+            int idx=0;
+            for( int i=0;i<16;i++) {
+                for ( int ii=0; ii<16; ii++) {
+                    lcd.lcd_drawpixel( x+((c/4)*16)+ii, y+((r/4)*16)+i, lcd.lcd_RGB( tmpmap[idx],tmpmap[idx],tmpmap[idx]) );
+                    idx++;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon May 28 20:50:49 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e