Improvements to Olieman's MODI2C library. Supports calls from IRQ.
Dependents: FreeIMU FreeIMU_external_magnetometer FreeIMU
Fork of MODI2C by
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 }
Generated on Tue Jul 12 2022 16:58:30 by
