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

Dependencies:   FPointer

Dependents:   FreeIMU FreeIMU_external_magnetometer FreeIMU

Fork of MODI2C by Erik -

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MODI2C_IRQ.cpp Source File

MODI2C_IRQ.cpp

00001 #include "MODI2C.h"
00002 
00003 //**********************************************************
00004 //*********************IRQ FUNCTIONS************************
00005 //**********************************************************
00006 
00007 void MODI2C::runUserIRQ(I2CData *Data) {
00008      
00009     if (Data->IRQOp==IRQ_I2C_BOTH)        //Always call if both
00010         Data->callback.call(Data->pass_to_irq);
00011     if ((Data->IRQOp==IRQ_I2C_READ)&&(Data->address&0x01)) //Call if read and byte was read
00012         Data->callback.call(Data->pass_to_irq);
00013     if ((Data->IRQOp==IRQ_I2C_WRITE)&&(!(Data->address&0x01))) //Call if write and byte was written
00014         Data->callback.call(Data->pass_to_irq);
00015         
00016     if (Data->monitor_addr!=NULL) *(Data->monitor_addr)=0;
00017 }
00018 
00019 void MODI2C::IRQ1Handler( void ) {
00020     IRQHandler(&Buffer1, LPC_I2C1);
00021 }
00022 
00023 void MODI2C::IRQ2Handler( void ) {
00024     IRQHandler(&Buffer2, LPC_I2C2);
00025 }
00026 
00027 void MODI2C::IRQHandler( I2CBuffer *Buffer, LPC_I2C_TypeDef *I2CMODULE) {
00028     I2CData *Data = (I2CData*)Buffer->curr;
00029 
00030     //Depending on the status register it determines next action, see datasheet
00031     //This is also pretty much copy pasting the datasheet
00032     //General options
00033     switch (I2CMODULE->I2STAT) {
00034         case(0x08):
00035         case(0x10):
00036             //Send Address
00037             I2CMODULE->I2DAT = Data->address;
00038             I2CMODULE->I2CONCLR = 1<<I2C_FLAG | 1<<I2C_START;
00039             break;
00040 
00041             //All master TX options
00042 
00043             //Address + W has been sent, ACK received
00044             //Data has been sent, ACK received
00045         case(0x18):
00046         case(0x28):
00047             if (Buffer->count==Data->length) {
00048                 *Data->status=I2CMODULE->I2STAT;
00049                 if (!Data->repeated)
00050                     _stop(I2CMODULE);
00051                 else {
00052                     I2CMODULE->I2CONSET = 1<<I2C_START;
00053                     I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
00054                 }
00055                 bufferHandler(I2CMODULE);
00056             } else {
00057                 I2CMODULE->I2DAT = Data->data[Buffer->count];
00058                 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;        //I dont see why I have to enable that bit, but datasheet says so
00059                 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
00060                 Buffer->count++;
00061             }
00062             break;
00063 
00064             //Address + W has been sent, NACK received
00065             //Data has been sent, NACK received
00066         case(0x20):
00067         case(0x30):
00068             *Data->status=I2CMODULE->I2STAT;
00069             _stop(I2CMODULE);
00070             bufferHandler(I2CMODULE);
00071             break;
00072 
00073             //Arbitration lost (situation looks pretty hopeless to me if you arrive here)
00074         case(0x38):
00075             _start(I2CMODULE);
00076             break;
00077 
00078 
00079             //All master RX options
00080 
00081             //Address + R has been sent, ACK received
00082         case(0x40):
00083             //If next byte is last one, NACK, otherwise ACK
00084             if (Data->length <= Buffer->count + 1)
00085                 I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
00086             else
00087                 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
00088             I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
00089             break;
00090 
00091             //Address + R has been sent, NACK received
00092         case(0x48):
00093             *Data->status=I2CMODULE->I2STAT;
00094             _stop(I2CMODULE);
00095             bufferHandler(I2CMODULE);
00096             break;
00097 
00098             //Data was received, ACK returned
00099         case(0x50):
00100             //Read data
00101             Data->data[Buffer->count]=I2CMODULE->I2DAT;
00102             Buffer->count++;
00103 
00104             //If next byte is last one, NACK, otherwise ACK
00105             if (Data->length == Buffer->count + 1)
00106                 I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
00107             else
00108                 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
00109 
00110             I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
00111             break;
00112 
00113             //Data was received, NACK returned (last byte)
00114         case(0x58):
00115             //Read data
00116             *Data->status=I2CMODULE->I2STAT;
00117             Data->data[Buffer->count]=I2CMODULE->I2DAT;
00118             if (!Data->repeated)
00119                 _stop(I2CMODULE);
00120             else {
00121                 I2CMODULE->I2CONSET = 1<<I2C_START;
00122                 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
00123             }
00124             bufferHandler(I2CMODULE);
00125             break;
00126 
00127         default:
00128             *Data->status=I2CMODULE->I2STAT;
00129             bufferHandler(I2CMODULE);
00130             break;
00131     }
00132 }
00133 
00134 
00135 //**********************************************************
00136 //*********************COMMAND BUFFER***********************
00137 //**********************************************************
00138 
00139 void MODI2C::bufferHandler(LPC_I2C_TypeDef *I2CMODULE) {
00140     I2CBuffer *Buffer;
00141     if (I2CMODULE == LPC_I2C1) {
00142         Buffer = &Buffer1;
00143     } else {
00144         Buffer = &Buffer2;
00145     }
00146 
00147     // Start user interrupt
00148     Buffer->curr->caller->runUserIRQ((I2CData*)Buffer->curr);
00149     // Free allocated data
00150     Buffer->pool.free((I2CData*)Buffer->curr);
00151     
00152     // Don't attempt to call startBuffer if another
00153     // thread is about to call it
00154     if (Buffer->crit_flag) return;
00155 
00156     // See if there is any other data to be written
00157     osEvent evt = Buffer->queue.get(0);
00158     if (evt.status == osEventMessage){
00159         Buffer->curr = (I2CData*)evt.value.p;
00160         startBuffer(I2CMODULE);
00161     }
00162     else{
00163         // Set curr to NULL to indicate no data being written now
00164         Buffer->curr = NULL;
00165         _clearISR(I2CMODULE);
00166     }
00167 }
00168 
00169 // Returns true if succeeded, false if buffer is full
00170 bool MODI2C::addBuffer(I2CData *Data, LPC_I2C_TypeDef *I2CMODULE) {
00171     // check if we are in an interrupt now
00172     // __get_IPSR returns 0 when in Thread Mode,
00173     // return value > 15 when in interrupt
00174     int interrupt = __get_IPSR();
00175 
00176     I2CBuffer *Buffer;
00177     if (I2CMODULE == LPC_I2C1) {
00178         Buffer = &Buffer1;
00179     } else {
00180         Buffer = &Buffer2;
00181     }
00182     
00183     // Hack to update status
00184     if(Data->status == NULL) {
00185         Data->status = &defaultStatus;
00186         wait_us(1);     // I blame the compiler that this is needed
00187     }
00188     *(Data->status) = 0;
00189     
00190     // Attempt to enqueue data to be written
00191     if (Buffer->queue.put(Data, 0)!=osOK){
00192         if (interrupt != 0)
00193             return false;   // no waiting in ISR, and buffer is full.
00194                             // no choice but to exit, return false for failure
00195         else
00196             // wait for buffer to be available (should rarely happen!!)
00197             // an interrupt will free Buffer when other write finishes
00198             while (Buffer->queue.put(Data, 0)!=osOK);
00199     }
00200     
00201     // Check for critical section in if in interrupt
00202     if (interrupt != 0){
00203         if (Buffer->crit_flag_isr) return true;
00204     } else Buffer->crit_flag_isr = true;
00205     
00206     // If no active writing
00207     if (Buffer->curr == NULL){
00208         // If we are not in an interrupt, we want to prevent
00209         // bufferHandler interrupt code from messing with Buffer.
00210         if (interrupt == 0) Buffer->crit_flag = true;
00211         
00212         // Get new data to be written
00213         osEvent evt = Buffer->queue.get(0);
00214         if (evt.status == osEventMessage){
00215             Buffer->curr = (volatile I2CData*)(evt.value.p);
00216             if (interrupt == 0) Buffer->crit_flag_isr = false;
00217             if (interrupt == 0) Buffer->crit_flag = false;
00218             startBuffer(I2CMODULE);     // start transfer
00219         } else {    // No data
00220             // "Leave" critical section
00221             if (interrupt == 0) Buffer->crit_flag_isr = false;
00222             if (interrupt == 0) Buffer->crit_flag = false;
00223         }
00224     } else {
00225         if (interrupt == 0) Buffer->crit_flag_isr = false;
00226     }
00227     
00228     
00229     return true;
00230 }
00231 
00232 //Starts new conversion
00233 void MODI2C::startBuffer(LPC_I2C_TypeDef *I2CMODULE) {
00234     I2CBuffer *Buffer;
00235     if (I2CMODULE == LPC_I2C1) {
00236         Buffer = &Buffer1;
00237     } else {
00238         Buffer = &Buffer2;
00239     }
00240 
00241     //Write settings
00242     Buffer->curr->caller->writeSettings();
00243     Buffer->count=0;
00244 
00245     //Send Start
00246     _start(I2CMODULE);
00247 
00248     //Start ISR (when buffer wasnt empty this wont do anything)
00249     _setISR(I2CMODULE);
00250 
00251 }