Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Algoritmo_Fuzzy FlyBed1 FlyBedLight
Revision 0:ff579e7e8efa, committed 2012-06-30
- Comitter:
- Sissors
- Date:
- Sat Jun 30 14:55:14 2012 +0000
- Commit message:
- v1.0
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MODI2C.cpp Sat Jun 30 14:55:14 2012 +0000
@@ -0,0 +1,214 @@
+#include "MODI2C.h"
+
+MODI2C::I2CBuffer MODI2C::Buffer1 = {0,0}; //Sets the initial buffer empty and count on zero
+MODI2C::I2CBuffer MODI2C::Buffer2 = {0,0}; //Sets the initial buffer empty
+//int MODI2C::status=0;
+int MODI2C::defaultStatus=0;
+
+
+
+
+MODI2C::MODI2C(PinName sda, PinName scl) : led(LED3) {
+ //Check which connection we are using, if not correct, go to error status
+ if ((sda==p9) && (scl==p10))
+ I2CMODULE = LPC_I2C1;
+ else if ((sda==p28) && (scl==p27))
+ I2CMODULE = LPC_I2C2;
+ else
+ error("MODI2C pins not valid");
+
+ //Default settings:
+ frequency(100000);
+
+ writePinState();
+}
+
+int MODI2C::write(int address, char *data, int length, bool repeated, int *status) {
+
+ I2CData Data;
+ //Store relevant information
+ address &= 0xFE;
+ Data.caller = this;
+ Data.address = address;
+ Data.repeated = repeated;
+ Data.data = data;
+ Data.length = length;
+ Data.status = status;
+
+ while(!addBuffer(Data, I2CMODULE));
+
+ return 0;
+}
+
+int MODI2C::write(int address, char *data, int length, int *status) {
+ return write(address, data, length, false, status);
+ }
+
+int MODI2C::read_nb(int address, char *data, int length, bool repeated, int *status) {
+ //Store relevant information
+ address |= 0x01;
+
+ //isIdle check here
+ I2CData Data;
+
+
+ Data.caller = this;
+ Data.address = address;
+ Data.repeated = repeated;
+ Data.data = data;
+ Data.length = length;
+ Data.status = status;
+
+ while(!addBuffer(Data, I2CMODULE));
+
+ return 0;
+}
+
+int MODI2C::read_nb(int address, char *data, int length, int *status) {
+ return read_nb(address, data, length, false, status);
+ }
+
+int MODI2C::read(int address, char *data, int length, bool repeated) {
+ int stat;
+ //Store relevant information
+ address |= 0x01;
+
+ //isIdle check here
+ I2CData Data;
+
+
+ Data.caller = this;
+ Data.address = address;
+ Data.repeated = repeated;
+ Data.data = data;
+ Data.length = length;
+ Data.status = &stat;
+
+ while(!addBuffer(Data, I2CMODULE));
+
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer = &Buffer2;
+ }
+
+ while(Buffer->queue!=0)
+ wait_us(1);
+
+ if (stat==0x58) //Return zero if ended correctly, otherwise return return code.
+ return 0;
+ else
+ return stat;
+}
+
+
+void MODI2C::start( void ) {
+ _start(I2CMODULE);
+}
+
+void MODI2C::stop( void ) {
+ _stop(I2CMODULE);
+}
+
+void MODI2C::frequency(int hz) {
+ //The I2C clock by default runs on quarter of system clock, which is 96MHz
+ //So to calculate high/low count times, we do 96MHz/4/2/frequency
+ duty = 96000000/8/hz;
+ if (duty>65535)
+ duty=65535;
+ if (duty<4)
+ duty=4;
+}
+
+int MODI2C::getQueue( void ) {
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer = &Buffer2;
+ }
+ return Buffer->queue;
+ }
+
+
+
+//*******************************************
+//***********Internal functions**************
+//*******************************************
+
+
+void MODI2C::writeSettings( void ) {
+ I2CMODULE->I2CONSET = 1<<I2C_ENABLE; //Enable I2C
+ I2CMODULE->I2CONCLR = I2C_STOP;
+ I2CMODULE->MMCTRL = 0; //Disable monitor mode
+ I2CMODULE->I2SCLH = duty;
+ I2CMODULE->I2SCLL = duty;
+
+}
+
+void MODI2C::writePinState( void ) {
+ if (I2CMODULE == LPC_I2C1) {
+ LPC_PINCON->PINSEL0 |= 0x0000000F; //Sets pins as I2C
+ LPC_PINCON->PINMODE0 |= 0x0000000A; //Neither pull up nor pull down
+ LPC_PINCON->PINMODE_OD0 |= 0x00000003; //Open drain mode enabled
+ } else if (I2CMODULE == LPC_I2C2) {
+ LPC_PINCON->PINSEL0 |= (1<<21)|(1<<23); //Same story, different register settings
+ LPC_PINCON->PINMODE0 |= (1<<21)|(1<<23);
+ LPC_PINCON->PINMODE_OD0 |= (1<<10)|(1<<11);
+ }
+}
+
+
+
+void MODI2C::attach( void (*function)(void), int operation) {
+ IRQOp = operation;
+ callback.attach(function);
+}
+
+template<typename T>
+void MODI2C::attach(T *object, void (T::*member)(void), int operation) {
+ IRQOp = operation;
+ callback.attach(object, member);
+}
+
+void MODI2C::detach( void ) {
+ callback.attach(NULL);
+}
+
+void MODI2C::_start(LPC_I2C_TypeDef *I2CMODULE) {
+ if (!(I2CMODULE->I2CONSET & 1<<I2C_START)) //If already sent, skip
+ I2CMODULE->I2CONSET = 1<<I2C_START; //Send start condition
+}
+
+void MODI2C::_stop(LPC_I2C_TypeDef *I2CMODULE) {
+ I2CMODULE->I2CONSET = 1<<I2C_STOP; //Send stop condition
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+}
+
+//Set interrupt vector
+void MODI2C::setISR(void) {
+ _setISR(I2CMODULE);
+}
+
+void MODI2C::_setISR(LPC_I2C_TypeDef *I2CMODULE) {
+ if (I2CMODULE == LPC_I2C1) {
+ NVIC_SetVector(I2C1_IRQn, (uint32_t)&IRQ1Handler);
+ NVIC_EnableIRQ(I2C1_IRQn);
+ } else if (I2CMODULE == LPC_I2C2) {
+ NVIC_SetVector(I2C2_IRQn, (uint32_t)&IRQ2Handler);
+ NVIC_EnableIRQ(I2C2_IRQn);
+ }
+}
+
+void MODI2C::clearISR( void ) {
+ _clearISR(I2CMODULE);
+}
+
+void MODI2C::_clearISR( LPC_I2C_TypeDef *I2CMODULE ) {
+ if (I2CMODULE == LPC_I2C1) {
+ NVIC_DisableIRQ(I2C1_IRQn);
+ } else if (I2CMODULE == LPC_I2C2) {
+ NVIC_DisableIRQ(I2C2_IRQn);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MODI2C.h Sat Jun 30 14:55:14 2012 +0000
@@ -0,0 +1,248 @@
+/*
+
+ . .
+ / `. .' \
+ .---. < > < > .---.
+ | \ \ - ~ ~ - / / |
+ ~-..-~ ~-..-~
+ \~~~\.' `./~~~/
+ \__/ \__/
+ / .- . \
+ _._ _.- .-~ ~-. / } \/~~~/
+ _.-'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, ®isterAdd, 1, true);
+ * mod.read_nb(MPU6050_ADDRESS*2, ®isterResult, 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
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MODI2C_IRQ.cpp Sat Jun 30 14:55:14 2012 +0000
@@ -0,0 +1,228 @@
+#include "MODI2C.h"
+
+//**********************************************************
+//*********************IRQ FUNCTIONS************************
+//**********************************************************
+
+
+void MODI2C::runUserIRQ(I2CData Data) {
+
+ if (IRQOp==IRQ_I2C_BOTH) //Always call if both
+ callback.call();
+ if ((IRQOp==IRQ_I2C_READ)&&(Data.address&0x01)) //Call if read and byte was read
+ callback.call();
+ if ((IRQOp==IRQ_I2C_WRITE)&&(!(Data.address&0x01))) //Call if write and byte was written
+ callback.call();
+}
+
+void MODI2C::IRQ1Handler( void ) {
+ IRQHandler(&Buffer1, LPC_I2C1);
+}
+
+void MODI2C::IRQ2Handler( void ) {
+ IRQHandler(&Buffer2, LPC_I2C2);
+}
+
+void MODI2C::IRQHandler( I2CBuffer *Buffer, LPC_I2C_TypeDef *I2CMODULE) {
+ I2CData *Data = &Buffer->Data[0];
+
+ //Depending on the status register it determines next action, see datasheet
+ //This is also pretty much copy pasting the datasheet
+ //General options
+ switch (I2CMODULE->I2STAT) {
+ case(0x08):
+ case(0x10):
+ //Send Address
+ I2CMODULE->I2DAT = Data->address;
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG | 1<<I2C_START;
+ break;
+
+ //All master TX options
+
+ //Address + W has been sent, ACK received
+ //Data has been sent, ACK received
+ case(0x18):
+ case(0x28):
+ if (Buffer->count==Data->length) {
+ *Data->status=I2CMODULE->I2STAT;
+ if (!Data->repeated)
+ _stop(I2CMODULE);
+ else {
+ I2CMODULE->I2CONSET = 1<<I2C_START;
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+ }
+ bufferHandler(I2CMODULE);
+ } else {
+ I2CMODULE->I2DAT = Data->data[Buffer->count];
+ I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK; //I dont see why I have to enable that bit, but datasheet says so
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+ Buffer->count++;
+ }
+ break;
+
+ //Address + W has been sent, NACK received
+ //Data has been sent, NACK received
+ case(0x20):
+ case(0x30):
+ *Data->status=I2CMODULE->I2STAT;
+ _stop(I2CMODULE);
+ bufferHandler(I2CMODULE);
+ break;
+
+ //Arbitration lost (situation looks pretty hopeless to me if you arrive here)
+ case(0x38):
+ _start(I2CMODULE);
+ break;
+
+
+ //All master RX options
+
+ //Address + R has been sent, ACK received
+ case(0x40):
+ //If next byte is last one, NACK, otherwise ACK
+ if (Data->length <= Buffer->count + 1)
+ I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
+ else
+ I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+ break;
+
+ //Address + R has been sent, NACK received
+ case(0x48):
+ *Data->status=I2CMODULE->I2STAT;
+ _stop(I2CMODULE);
+ bufferHandler(I2CMODULE);
+ break;
+
+ //Data was received, ACK returned
+ case(0x50):
+ //Read data
+ Data->data[Buffer->count]=I2CMODULE->I2DAT;
+ Buffer->count++;
+
+ //If next byte is last one, NACK, otherwise ACK
+ if (Data->length == Buffer->count + 1)
+ I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
+ else
+ I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
+
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+ break;
+
+ //Data was received, NACK returned (last byte)
+ case(0x58):
+ //Read data
+ *Data->status=I2CMODULE->I2STAT;
+ Data->data[Buffer->count]=I2CMODULE->I2DAT;
+ if (!Data->repeated)
+ _stop(I2CMODULE);
+ else {
+ I2CMODULE->I2CONSET = 1<<I2C_START;
+ I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
+ }
+ bufferHandler(I2CMODULE);
+ break;
+
+ default:
+ *Data->status=I2CMODULE->I2STAT;
+ bufferHandler(I2CMODULE);
+ break;
+ }
+}
+
+
+//**********************************************************
+//*********************COMMAND BUFFER***********************
+//**********************************************************
+
+void MODI2C::bufferHandler(LPC_I2C_TypeDef *I2CMODULE) {
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer = &Buffer2;
+ }
+
+ //Start user interrupt
+ Buffer->Data[0].caller->runUserIRQ(Buffer->Data[0]);
+
+ removeBuffer(I2CMODULE);
+
+
+
+ if (Buffer->queue!=0)
+ startBuffer(I2CMODULE);
+ else
+ _clearISR(I2CMODULE);
+}
+
+//Returns true if succeeded, false if buffer is full
+bool MODI2C::addBuffer(I2CData Data, LPC_I2C_TypeDef *I2CMODULE) {
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer = &Buffer2;
+ }
+ if (Buffer->queue<I2C_BUFFER) {
+
+ if(Data.status == NULL) {
+ Data.status = &defaultStatus;
+ wait_us(1); //I blame the compiler that this is needed
+ }
+ *Data.status = 0;
+
+ Buffer->Data[Buffer->queue]=Data;
+ Buffer->queue++;
+
+ //If queue was empty, set I2C settings, start conversion
+ if (Buffer->queue==1) {
+ startBuffer(I2CMODULE);
+ }
+
+ return true;
+ } else
+ return false;
+
+}
+
+//Returns true if buffer still has data, false if empty
+bool MODI2C::removeBuffer(LPC_I2C_TypeDef *I2CMODULE) {
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer= &Buffer2;
+ }
+
+ if (Buffer->queue>0) {
+ for (int i =0; i<Buffer->queue-1; i++)
+ Buffer->Data[i]=Buffer->Data[i+1];
+ Buffer->queue--;
+ }
+ if (Buffer->queue>0)
+ return true;
+ else
+ return false;
+}
+
+//Starts new conversion
+void MODI2C::startBuffer(LPC_I2C_TypeDef *I2CMODULE) {
+ I2CBuffer *Buffer;
+ if (I2CMODULE == LPC_I2C1) {
+ Buffer = &Buffer1;
+ } else {
+ Buffer = &Buffer2;
+ }
+
+ //Write settings
+ Buffer->Data[0].caller->writeSettings();
+ Buffer->count=0;
+
+ //Send Start
+ _start(I2CMODULE);
+
+ //Start ISR (when buffer wasnt empty this wont do anything)
+ _setISR(I2CMODULE);
+
+}
\ No newline at end of file