assignment_2_herpe

Dependencies:   mbed WattBob_TextLCD MCP23017

Files at this revision

API Documentation at this revision

Comitter:
xherpe
Date:
Thu Mar 08 16:32:35 2012 +0000
Commit message:

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
MCP23017.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
WattBob_TextLCD.lib 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
diff -r 000000000000 -r aaddc17011a9 FATFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Thu Mar 08 16:32:35 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
diff -r 000000000000 -r aaddc17011a9 MCP23017.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP23017.lib	Thu Mar 08 16:32:35 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/jimherd/code/MCP23017/#d57de266cf19
diff -r 000000000000 -r aaddc17011a9 SDFileSystem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.cpp	Thu Mar 08 16:32:35 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(1000000); // Set to 1MHz 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;
+}
diff -r 000000000000 -r aaddc17011a9 SDFileSystem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.h	Thu Mar 08 16:32:35 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
diff -r 000000000000 -r aaddc17011a9 WattBob_TextLCD.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WattBob_TextLCD.lib	Thu Mar 08 16:32:35 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/jimherd/code/WattBob_TextLCD/#020722c18a8b
diff -r 000000000000 -r aaddc17011a9 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Mar 08 16:32:35 2012 +0000
@@ -0,0 +1,429 @@
+// XAVIER HERPE                                      Assignment 2
+// 5th year Robotics & Cybertronics
+// Heriot-Watt University
+
+#include "mbed.h"
+#include "MCP23017.h"
+#include "WattBob_TextLCD.h"
+#include "SDFileSystem.h"
+#include "FATFileSystem.h"
+
+#define     BACK_LIGHT_ON(INTERFACE)    INTERFACE->write_bit(1,BL_BIT)
+#define     BACK_LIGHT_OFF(INTERFACE)    INTERFACE->write_bit(0,BL_BIT)
+
+// Pointers to LCD screen and SD card
+MCP23017            *par_port;  // pointer to 16-bit parallel I/O chip
+WattBob_TextLCD     *lcd;       // pointer to 2*16 character LCD object
+FILE                *fp;        // Pointer to SD card object
+
+
+//=====================================================================================
+//  I/O ports allocation
+//=====================================================================================
+DigitalIn TTL(p17); // TTL input for frequency measurement
+DigitalIn switch_1(p18); // Switch 1 input
+DigitalIn switch_2(p19); // Switch 2 input
+DigitalIn switch_off(p11); // Switch used to close SD file and stop cyclic executive
+AnalogIn analogue_in_1(p15); // POT value
+AnalogIn analogue_in_2(p16); // LDR value
+PwmOut servo(p21); // Servo output
+DigitalOut TestPin(p20); // Pin only used to test program and measure time
+SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board
+
+
+//=====================================================================================
+// Internal objects declaration
+// ====================================================================================
+BusOut LEDs(LED4, LED3, LED2, LED1); // Address the four LEDs to a single bus
+Timer timer; // Timer used to measure frequency in task 1
+Timer DoNothing; // Timer used to measure how long the program does nothing
+Ticker ticker; // Ticker used as clock for cyclic executive program
+
+
+//=====================================================================================
+// Constants declaration
+//=====================================================================================
+const int SampFreq = 100; // Sampling frequency is 10kHz (100us)
+
+
+//=====================================================================================
+// Variables declaration
+//=====================================================================================
+
+// Variables for cyclic executive program
+long int ticks = 0; // Used to define what task to call in the cyclic executive program
+int NoTask = 0; // Used to return how long the program does nothing in ms
+int NoTaskCount = 0; // Variable incremented until one total cycle of 10 seconds is reached
+
+// Variables for tasks 1 and 2
+int period = 0; // Returned period of the TTL input signal
+int frequency = 0; // Returned frequency of the TTL signal
+
+// Varibles for task 4
+int switch_1_val = 0; // Used to return how many times the switch is high
+int switch_2_val = 0;
+bool switch_1_state = 0; // Used to define whether the debounced switch is ON or OFF
+bool switch_2_state = 0;
+
+// Variables for task 5
+float analogue_1_val = 0; // Used to return the filtered analogue input
+float analogue_2_val = 0;
+
+int analogue_1_int = 0; // Used to convert float to int (results in quicker display on LCD in task 6)
+int analogue_2_int = 0;
+
+// Variable for task 7
+int LogCount = 0; // Used to define logging number
+
+// Variable used for task 8
+int BinCount = 0; // Used to increment a binary display on LEDs. Goes from 0 to 15 and then is reset
+bool BinEnable = 0; // Used to tell task 5 to display binary pattern on LEDs every 1.5s
+int IncCheck = 0; // Check increment to see if 6 cycles have elapsed to light LEDs ( 6 * 250us = 1.5s)
+
+
+//=====================================================================================
+// Task declaration
+//=====================================================================================
+
+void CyclEx();
+
+void Task1(); // Measure TTL input frequency
+void Task2(); // Show frequency on LCD screen
+void Task3(); // Show speed on servo dial
+void Task4(); // Read and debounce two digital inputs
+void Task5(); // Read and filter two analogue inputs
+void Task6(); // Display digital and analogue inputs on LCD screen
+void Task7(); // Log speed, analogue and digital inputs on SD card
+void Task8(); // Display error message on LCD screen and display binary pattern on LEDs
+
+void WaitRisEdge(); // Subroutine to detect rising edge
+void WaitFalEdge(); // Subroutine to detect falling edge
+
+void Stop(); // Close log file and stop cyclic executive
+
+
+//=====================================================================================
+// Main program
+//=====================================================================================
+
+int main()
+{
+
+    // LCD Screen Initialisation
+    par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip
+    lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display
+    par_port->write_bit(1,BL_BIT); // turn LCD backlight ON
+    lcd->cls(); // clear display
+
+    // EXEL log file initialisation
+    fp = fopen("/sd/log.xls", "w"); // pointer to log in text file called "log". (Use "a" to not delete file)
+    fprintf(fp, "This file is the property of Xavier Herpe, the French\n\n");
+
+    // DoNothing timer reset
+    DoNothing.reset();
+    
+    // Internal ticker set to 25ms. Every 25ms, the scheduler is called and selects the task to run
+    ticker.attach(&CyclEx, 0.025); // Period set to 25ms
+    while(1)// Run until system shuts down
+    {
+         
+    } 
+}
+
+// Where tasks are scheduled based on an EXEL sheet
+void CyclEx()
+{   
+    // Stop timer when a new task starts 
+    DoNothing.stop();
+    
+    if(ticks % 80 == 4) // Occures every 80 clock cycles (2 seconds). Starts with an offset of 4 clock cycles
+    {
+        Task1(); 
+    }    
+
+    else if(ticks % 200 == 8) // Occures every 200 clock cycles (5 seconds). Starts with an offset of 8 clock cycles
+    {       
+        Task2();      
+    }
+    else if(ticks % 240 == 7) // Occures every 240 clock cycles (6 seconds). Starts with an offset of 7 clock cycles
+    {
+        Task3();    
+    }
+    else if(ticks % 4 == 0) // Occures every 4 clock cycles (0.1 seconds). Starts with an offset of 0 clock cycles
+    {
+        Task4(); 
+    }
+    else if(ticks % 10 == 1) // Occures every 10 clock cycles (0.25 seconds). Starts with an offset of 1 clock cycles
+    {   
+        Task5(); 
+    }
+    else if(ticks % 40 == 3) // Occures every 40 clock cycles (1 seconds). Starts with an offset of 3 clock cycles
+    {
+        Task6(); 
+    }
+    else if(ticks % 400 == 10) // Occures every 400 clock cycles (10 seconds). Starts with an offset of 10 clock cycles
+    {
+        Task7(); 
+    }
+    else if(ticks % 160 == 6) // Occures every 160 clock cycles (4 seconds). Starts with an offset of 6 clock cycles
+    {  
+        Task8(); 
+    }
+    
+    if (switch_off == 1) // Pin used to log data on SD card and stop Cyclic executive program
+         {
+             Stop();
+         }
+    ticks++;
+    
+    // Start timer when one task is ended 
+    DoNothing.start();
+    NoTaskCount++;
+    
+    // When one full cycle of 10 seconds is finished, return how long the program was doing nothing (lazy program)
+    if (NoTaskCount == 400)
+    {
+        NoTask = DoNothing.read_ms();
+        NoTaskCount = 0;
+        DoNothing.reset();
+    }
+}
+
+
+//=====================================================================================
+// Tasks
+//=====================================================================================
+
+// Task 1: Measure TTL input frequency
+void Task1()
+{
+    timer.reset();
+    
+    // If the input signal is low, wait for a rising edge to start counting
+    if (TTL == 0)
+    {
+        WaitRisEdge(); // Call subroutine to wait for rising edge
+        timer.start(); // Start timer
+        while(TTL == 1) // Keep counting as long as signal is high
+        {
+            wait_us(SampFreq);
+        }
+    }
+    
+    // If the input signal is high, wait for a falling edge to start counting
+    else if (TTL == 1)
+    {
+        WaitFalEdge(); // Call subroutine to wait for falling edge
+        timer.start(); // Start timer
+        while(TTL == 0) // Keep counting as long as signal is high
+        {
+            wait_us(SampFreq);
+        }
+    }
+
+    timer.stop(); // Stop counting when signal changes
+    period = timer.read_us()*2; // Convert the time into a period
+    frequency = 1000000/period; // Convert the period into a frequency
+}
+
+
+
+// Task 2: display the measured frequency on LCD screen
+void Task2()
+{
+    lcd->cls(); // clear display
+    lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+    lcd->printf("%d Hz",frequency); // print the frequency calculated in task 1
+}
+
+
+
+// Task 3: show speed on servo output dial
+void Task3()
+{
+    servo.period(0.02); // servo requires a 20ms period
+    // To rotate the servo from -90 to +90 degrees, the pulse width must varies between 600us to 2300us
+    // The pulse width is calculated from the speed measured in task one
+    // 50Hz is equivalent to -90 degrees and 100Hz is equivalent to 90 degrees
+    // 1Hz change is equal to 34us pulse width change, so pulse width = ((frequency - 50)*34) + 600
+    servo.pulsewidth_us(2300-((frequency - 50)*34));
+    wait_ms(1); // Leave the servo some time to reach its position
+}
+
+
+
+// Task 4: Read two digital inputs (debounced)
+void Task4()
+{
+    switch_1_val = 0;
+    switch_2_val = 0;
+
+    // Read each switch three consecutive times with 100us between readings
+    for(int i=0; i<3; i++)
+    {
+        if (switch_1 == 1) // Increment variable if switch 1 is pressed
+        {
+            switch_1_val++;
+        }
+
+        if (switch_2 == 1) // Increment variable if switch 2 is pressed
+        {
+            switch_2_val++;
+        }
+
+        wait_us(SampFreq);
+    }
+    // Check how many times switch 1 has been high
+    // if it has been high more than twice, then switch 1 state = 1
+    if (switch_1_val > 1)
+    {
+        switch_1_state = 1;
+    }
+    else
+    {
+        switch_1_state = 0;
+    }
+
+    // Check how many times switch 1 has been high
+    // if it has been high more than twice, then switch 2 state = 1
+    if (switch_2_val > 1)
+    {
+        switch_2_state = 1;
+    }
+
+    else
+    {
+        switch_2_state = 0;
+    }
+}
+
+
+
+// Task 5: Read two analogue inputs (filtered)
+void Task5()
+{
+    analogue_1_val = 0; // Reset variables
+    analogue_2_val = 0;
+
+    // Takes four readings of each analogue input. Readings occure every 0.1ms
+    // Because the analogue.read() function returns a value from 0 to 1,
+    // we need to multiply the readings by 3.3 to cover 0V to 3.3V
+    for(int i=0; i<4;i++)
+    {
+        analogue_1_val = analogue_1_val + (analogue_in_1*3.3);
+        analogue_2_val = analogue_2_val + (analogue_in_2*3.3);
+        wait_us(SampFreq);
+    }
+
+    analogue_1_val = (analogue_1_val / 4);
+    analogue_2_val = (analogue_2_val / 4);
+    
+    analogue_1_int = analogue_1_val * 10; // Convert floating point into an integer to reduce display delay
+    analogue_2_int = analogue_2_val * 10;
+    
+    // This section of task 5 is used to take over part of task 8.
+    // Since the LEDs pattern has to be incremented every 1.5s, the pattern is
+    // incremented every 6 cycles, which correspond to 1.5s.
+    if(BinEnable == 1)
+    {
+        IncCheck++; 
+        
+        if(IncCheck == 6) // Corresponds to 1.5s. Increment binary pattern
+        {
+            LEDs = BinCount;
+            BinCount++;
+            IncCheck = 0;
+
+            if (BinCount > 15) // Used to reset variable once maximum 4-bit binary value is reached
+            {
+                BinCount = 0;
+            }  
+        }  
+    }
+}
+
+
+
+// Task 6: Display analogue and digital values on LCD screen
+void Task6()
+{
+   // lcd->cls(); // clear display (takes too long)
+    lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+    lcd->printf("%d %d%d%d",analogue_1_int,analogue_2_int,switch_1_state,switch_2_state);
+}
+
+
+
+// Task 7: Log values on SD card
+void Task7()
+{    
+     LogCount++; //Used to print the logging number in file. Starts from 1
+     fprintf(fp, "Log:  %d,   Speed: %dHz,   Switch_1: %d,   Switch_2: %d,   POT: %.2fVolts,   LDR: %.2fVolts\n",LogCount,frequency,switch_1_state,switch_2_state,analogue_1_val,analogue_2_val);
+}
+
+
+
+// Task 8: Show error message and light LEDs
+void Task8()
+{  
+    // If switch_1 = 1 and POT value > 3V, display error message
+    if(switch_1_state == 1 && analogue_1_val > 3)
+    {
+        //lcd->cls(); // clear display
+        lcd->locate(0,0); // set cursor to location (0,0) - top left corner
+        lcd->printf(".ERREUR");
+    }
+    
+    // If switch 2 is high, return a command to task 5 to do the incrementing pattern every 1.5 seconds
+    if(switch_2_state == 1)
+    {
+        BinEnable = 1;
+    }
+    
+    // If switch 2 is low, stop sending a command to task 5 and light off LEDs
+    else
+    {
+        LEDs = 0;
+        BinEnable = 0;
+        BinCount = 0;
+    }
+}
+
+
+
+// Stop function to stop cyclic executive and close log file
+void Stop()
+{
+    ticker.detach();
+    fprintf(fp, "\n The program did nothing for %d ms, which corresponds to %d percent of the time  \n",NoTask, NoTask/100);    
+    fprintf(fp, "\n PROGRAM STOPPED");
+    fclose(fp);
+    
+}
+
+
+
+//=====================================================================================
+// Subroutines
+//=====================================================================================
+
+// Wait for rising edge
+void WaitRisEdge()
+{
+    // As soon as it gets high, the subroutine will end and the timer will start
+    while(TTL == 0)
+    {        
+            wait_us(SampFreq);        
+    }
+}
+
+
+// Wait for falling edge
+void WaitFalEdge()
+{
+    // As soon as it gets low, the subroutine will end and the timer will start
+    while(TTL == 1)
+    {
+        wait_us(SampFreq);
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r aaddc17011a9 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Mar 08 16:32:35 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4c0c40fd0593