Interrupt based I2C functionality for the LPC1768. (If you want the other one, send a PM and I might make it). Also adds buffer functionality to the I2C bus.
Dependents: Algoritmo_Fuzzy FlyBed1 FlyBedLight
MODI2C
MODI2C is an interrupt based (master) I2C library for the LPC1768 (if there is interest in using it for the other mbed variant I can look at it, but since I cannot compile for it there is no way I can test anything). It provided basic functionality that is similar to MODSERIAL, but it is not in any way connected and I am not in any way connected to the author of MODSERIAL, I am just very bad at making original names.
The default mbed I2C library works fine, but it is completely blocking. Since I2C access is fairly slow (100kbit/s in normal mode, 400kbit/s in fast mode), it can severely limit performance when a significant amount of I2C data needs to be received. For example in the case of a 9DOF IMU you will generally need to send three times a device address + register address, send device address again, and receive 6 bytes. Add overhead and you are at roughly 250 bits that need to be sent/received. In normal mode that would take 2.5ms, an mbed can do alot in that time.
MODI2C library offers interrupt based and buffered sending/receiving of I2C messages. Because I2C is not asynchronous, it cannot receive messages without a specific command to do so, unlike MODSERIAL. Instead of that, you have to tell it to receive a certain number of bytes, and when it is finished it will report back. When transmitting it will simply put the message in the buffer.
Usage
In most cases you can directly replace the standard I2C library with this one, although you will then not be able to use the advantages of interrupts and its buffer.
Write
int write(int address, char *data, int length, bool repeated = false, int *status = NULL);
The write statement is almost the same as the default write statements. There are however a few differences that need to be taken into account. The write staement is completely non-blocking. So when you want to write a byte it will not know if it receives an ACK or a NACK. The write command will always return zero, to make it compatible with standard mbed library, but this means it cannot be used to check if there is a device on a certain address. Easiest to do that is by using the read statement instead.
Aditionally there is an optional 5th parameter (the repeated parameter stays optional, you can use the 5th parameter without having supplied a repeated value). This tracks the current status of the write action. It stays zero until finished, when finished it will report back the status from the LPC1768's status register. This allows for example to see if an ACK has been received (0x28), but it is also an easy way to check if the command is finished.
Read
int read(int address, char *data, int length, bool repeated = false);
One on one replacement for the standard mbed command. It is also blocking, and returns zero on success, otherwise it will return the LPC's status code. So this can be used to check if there is a device at a specific address.
Read_nb
int read_nb(int address, char *data, int length, bool repeated = false, int *status=NULL);
This is the non-blocking read variant, and here is where it gets interesting. It works pretty much exactly the same as the write command, however in the case of the read command you usually want to know if the data has been updated. The status point can be used for this, the default way would be:
mod.write(MPU6050_ADDRESS*2, ®isterAdd, 1, true); mod.read_nb(MPU6050_ADDRESS*2, ®isterResult, 1, &status); //Do other calculations. //Check if the read command has finished. while (!status) wait_us(1); pc.printf("Register holds 0x%02X\n\r", registerResult);
Without the wait_us(1) after the while it has the nasty tendency to freeze, so it is required.
Interrupts
An interrupt handler can be attached the same way as in for example the default Ticker library.
void attach(void (*function)(void), int operation = IRQ_I2C_BOTH); template<typename T> void attach(T *object, void (T::*member)(void), int operation = IRQ_I2C_BOTH);
Operation specifies when to call the interrupt. By default it will do it always when an I2C operation is finished, but you can also supply IRQ_I2C_READ and IRQ_I2C_WRITE to only let it happen when read or write actions are completed.
Buffer
Both I2C periferals have a seperate buffer with as default size 10 commands (a read command that requests 100 bytes is still one command). This will generally be sufficient for I2C, but you can easily change it at compile time by defining something else.
#define I2C_BUFFER 50
When a new command is added while the buffer is full, it will block until there is again space in the buffer. The getQueue() command returns the current number of commands in the buffer. Take into account the buffer is shared between all MODI2C objects that use that periferal. So if you have two objects using both I2C busses they both will have a buffer of 10 commands, but if you have 100 MODI2C objects on a single I2C bus, they will have to share their buffer.
Performance
Compared to the default I2C library it is *slightly* faster at 100kbit/s, and *slightly* slower at 400kbit/s, but these differences are completely negligible. While testing I could access a fast mode devices (400kbit/s) at up to 1mbit/s with both the default I2C library and MODI2C. For both the overhead however becomes significant, MODI2C has slightly more overhead at these rates, but still it is not alot and the majority of its time it can still run user content.
During normal mode I2C transfers there is an overhead of roughly 6% by MODI2C, so 94% of the time it can run user content. Fast mode I2C roughly multiplies the overhead by a factor 4 (which was expected), so 25% of the time is taken by MODI2C, leaving 75% of the CPU cycles for user content.
Known issues and compatibility
In principle MODI2C and default mbed I2C can be used together without issues. However there are a few small issues and some common sense is needed.
After a normal I2C command is finished, do not immediatly send a MODI2C message. It results in some reliability issues, which I would have looked into if it is not so easily fixed by a very small delay. Adding delay_us(1); already fixes the issue. If you have some calculations between the two commands it is also fine, only a very short delay is required.
When a MODI2C command is finished you may immediatly send a normal I2C command. The common sense part: I assume we are talking here about a read command, so a blocking command. Then you are immediatly allowed to send a normal I2C command. If however the buffer is not empty yet and you will send a normal I2C message it will not work. Normal I2C will not care that MODI2C is still sending.
Finally there is the issue that mbed I2C and MODI2C handle repeated start conditions slightly different. I think the mbed library sends a repeated start condition during the next command, while the MODI2C library sends repeated start at the end of its current command. So if you are addressing a device where you need to send a repeated start, do not send it with one library while sending the next command with the other library. I cannot possibly imagine why you would want to do that anyway.
The end
My C++ knowledge was quite limitted until I made this library (and probably still), just like my knowledge of the LPC1768 registers/hardware. In the end it looks like everything works fairly well, but if it works with the default mbed library, but not with MODI2C, you should probably blame me.
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
diff -r 000000000000 -r ff579e7e8efa MODI2C.cpp --- /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); + } +}
diff -r 000000000000 -r ff579e7e8efa MODI2C.h --- /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
diff -r 000000000000 -r ff579e7e8efa MODI2C_IRQ.cpp --- /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