Improvements to Olieman's MODI2C library. Supports calls from IRQ.

Dependencies:   FPointer

Dependents:   FreeIMU FreeIMU_external_magnetometer FreeIMU

Fork of MODI2C by Erik -

MODI2C.h

Committer:
Sissors
Date:
2012-06-30
Revision:
0:ff579e7e8efa
Child:
1:eed116eb680a

File content as of revision 0:ff579e7e8efa:

/* 

                            .       .
                           / `.   .' \
                   .---.  <    > <    >  .---.
                   |    \  \ - ~ ~ - /  /    |
                    ~-..-~             ~-..-~
                \~~~\.'                    `./~~~/
                 \__/                        \__/
                  /                  .-    .  \
           _._ _.-    .-~ ~-.       /       }   \/~~~/
       _.-'q  }~     /       }     {        ;    \__/
      {'__,  /      (       /      {       /      `. ,~~|   .     .
       `''''='~~-.__(      /_      |      /- _      `..-'   \\   //
                   / \   =/  ~~--~~{    ./|    ~-.     `-..__\\_//_.-'
                  {   \  +\         \  =\ (        ~ - . _ _ _..---~
                  |  | {   }         \   \_\
                 '---.o___,'       .o___,'     "Stegosaurus"


Face it, dinos much cooler than copyright notices.*/

#include "mbed.h"


#ifndef MODI2C_H
#define MODI2C_H


#define I2C_ENABLE          6
#define I2C_START           5
#define I2C_STOP            4
#define I2C_FLAG            3
#define I2C_ASSERT_ACK      2

#define IRQ_I2C_BOTH        0
#define IRQ_I2C_READ        1
#define IRQ_I2C_WRITE       2



#ifndef I2C_BUFFER
#define I2C_BUFFER          10
#endif


/** Library that allows interrupt driven communication with I2C devices
  *
  * For now this is all in beta, so if you got weird results while the mbed I2C library works, it is probably my fault.
  * Similar to googles definition of beta, it is unlikely it will ever come out of beta.
  *
  * Example:
  * @code
  * #include "mbed.h"
  * #include "MODI2C.h"
  * #include "MPU6050.h"
  * 
  * Serial pc(USBTX, USBRX); // tx, rx
  * MODI2C mod(p9, p10);
  * 
  * int main() {
  *     char registerAdd = MPU6050_WHO_AM_I_REG;
  *     char registerResult;
  *     int status;
  * 
  *     while (1) {
  *         mod.write(MPU6050_ADDRESS*2, &registerAdd, 1, true);
  *         mod.read_nb(MPU6050_ADDRESS*2, &registerResult, 1, &status);
  * 
  *         while (!status) wait_us(1);
  *         pc.printf("Register holds 0x%02X\n\r", registerResult);
  *         wait(2);
  *     }
  * }
  * @endcode
  */
class MODI2C {
public:
    /**
    * Constructor.
    *
    * @param sda - mbed pin to use for the SDA I2C line.
    * @param scl - mbed pin to use for the SCL I2C line.
    */
    MODI2C(PinName sda, PinName scl);

    /**
    * Write data on the I2C bus.
    *
    * This function should generally be a drop-in replacement for the standard mbed write function.
    * However this function is completely non-blocking, so it barely takes time. This can cause different behavior.
    * Everything else is similar to read_nb.
    *
    * @param address - I2C address of the slave (7 bit address << 1).
    * @param data - pointer to byte array that holds the data
    * @param length - amount of bytes that need to be sent
    * @param repeated - determines if it should end with a stop condition (default false)
    * @param status - (optional) pointer to integer where the final status code of the I2C transmission is placed. (0x28 is success)
    * @param return - returns zero
    */
    int write(int address, char *data, int length, bool repeated = false, int *status = NULL);
    int write(int address, char *data, int length, int *status);

    /**
    * Read data non-blocking from the I2C bus.
    *
    * Reads data from the I2C bus, completely non-blocking. Aditionally it will always return zero, since it does
    * not wait to see how the transfer goes. A pointer to an integer can be added as argument which returns the status.
    *
    * @param address - I2C address of the slave (7 bit address << 1).
    * @param data - pointer to byte array where the data will be stored
    * @param length - amount of bytes that need to be received
    * @param repeated - determines if it should end with a stop condition
    * @param status - (optional) pointer to integer where the final status code of the I2C transmission is placed. (0x58 is success)
    * @param return - returns zero
    */
    int read_nb(int address, char *data, int length, bool repeated = false, int *status=NULL);
    int read_nb(int address, char *data, int length, int *status);
    
    /**
    * Read data from the I2C bus.
    *
    * This function should should be a drop-in replacement for the standard mbed function.
    *
    * @param address - I2C address of the slave (7 bit address << 1).
    * @param data - pointer to byte array where the data will be stored
    * @param length - amount of bytes that need to be received
    * @param repeated - determines if it should end with a stop condition
    * @param return - returns zero on success, LPC status code on failure
    */
    int read(int address, char *data, int length, bool repeated = false);

    /**
    * Sets the I2C bus frequency
    *
    * @param hz - the bus frequency in herz
    */
    void frequency(int hz);

    /**
    * Creates a start condition on the I2C bus
    *
    * If you use this function you probably break something (but mbed also had it public)
    */
    void start ( void );

    /**
    * Creates a stop condition on the I2C bus
    *
    * If you use this function you probably break something (but mbed also had it public)
    */
    void stop ( void );
    
    /**
    * Removes attached function
    */
    void detach( void );
    
    /**
    * Calls user function when I2C command is finished
    *
    * @param function - the function to call.
    * @param operation - when to call IRQ: IRQ_I2C_BOTH (default) - IRQ_I2C_READ - IRQ_I2C_WRITE
    */
    void attach(void (*function)(void), int operation = IRQ_I2C_BOTH);
    
    /**
    * Calls user function when I2C command is finished
    *
    * @param object - the object to call the function on.
    * @param member - the function to call
    * @param operation - when to call IRQ: IRQ_I2C_BOTH (default) - IRQ_I2C_READ - IRQ_I2C_WRITE
    */
    template<typename T>
        void attach(T *object, void (T::*member)(void), int operation = IRQ_I2C_BOTH);
        
    /**
    * Returns the current number of commands in the queue (including one currently being processed)
    *
    * Note that this is the number of commands, not the number of bytes
    *
    * @param return - number of commands in queue
    */
    int getQueue( void );


private:

    struct I2CData {
        MODI2C *caller;
        char address;
        char *data;
        int  length;
        bool repeated;
        int *status;
    };
    
    struct I2CBuffer {
        int queue;
        int count;
        I2CData Data[I2C_BUFFER];
        };
        
    //Settings:
    int duty;
    
    FunctionPointer callback;
    int IRQOp;   
    void runUserIRQ( I2CData Data );

    //Remove later:
    LPC_I2C_TypeDef *I2CMODULE;

    

    //Whole bunch of static stuff, pretty much everything that is ever called from ISR
    static I2CBuffer Buffer1;
    static I2CBuffer Buffer2;
    
    static void IRQHandler(I2CBuffer *Buffer, LPC_I2C_TypeDef *I2CMODULE);
    static void IRQ1Handler(void);
    static void IRQ2Handler(void);
    
    static void bufferHandler(LPC_I2C_TypeDef *I2CMODULE);
    static bool addBuffer(I2CData Data, LPC_I2C_TypeDef *I2CMODULE);
    static bool removeBuffer(LPC_I2C_TypeDef *I2CMODULE);
    static void startBuffer(LPC_I2C_TypeDef *I2CMODULE);

    static int defaultStatus;
    
    static void _start(LPC_I2C_TypeDef *I2CMODULE);
    static void _stop(LPC_I2C_TypeDef *I2CMODULE);
    static void _clearISR( LPC_I2C_TypeDef *I2CMODULE );
    static void _setISR( LPC_I2C_TypeDef *I2CMODULE );


    void writeSettings( void );
    void writePinState( void );
    void setISR( void );
    void clearISR( void );


    DigitalOut led;

};


#endif