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

Dependencies:   FPointer

Dependents:   FreeIMU FreeIMU_external_magnetometer FreeIMU

Fork of MODI2C by Erik -

Committer:
tyftyftyf
Date:
Sat Nov 09 08:59:02 2013 +0000
Revision:
1:eed116eb680a
Parent:
0:ff579e7e8efa
Child:
5:fa0cca8e28b6
Based on Olieman's MODI2C library. Enables per-request interrupt config. The library can now be used in an interrupt.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 0:ff579e7e8efa 1 #include "MODI2C.h"
Sissors 0:ff579e7e8efa 2
Sissors 0:ff579e7e8efa 3 //**********************************************************
Sissors 0:ff579e7e8efa 4 //*********************IRQ FUNCTIONS************************
Sissors 0:ff579e7e8efa 5 //**********************************************************
Sissors 0:ff579e7e8efa 6
tyftyftyf 1:eed116eb680a 7 void MODI2C::runUserIRQ(I2CData *Data) {
Sissors 0:ff579e7e8efa 8
tyftyftyf 1:eed116eb680a 9 if (Data->IRQOp==IRQ_I2C_BOTH) //Always call if both
tyftyftyf 1:eed116eb680a 10 Data->callback.call(Data->pass_to_irq);
tyftyftyf 1:eed116eb680a 11 if ((Data->IRQOp==IRQ_I2C_READ)&&(Data->address&0x01)) //Call if read and byte was read
tyftyftyf 1:eed116eb680a 12 Data->callback.call(Data->pass_to_irq);
tyftyftyf 1:eed116eb680a 13 if ((Data->IRQOp==IRQ_I2C_WRITE)&&(!(Data->address&0x01))) //Call if write and byte was written
tyftyftyf 1:eed116eb680a 14 Data->callback.call(Data->pass_to_irq);
tyftyftyf 1:eed116eb680a 15
tyftyftyf 1:eed116eb680a 16 if (Data->monitor_addr!=NULL) *(Data->monitor_addr)=0;
Sissors 0:ff579e7e8efa 17 }
Sissors 0:ff579e7e8efa 18
Sissors 0:ff579e7e8efa 19 void MODI2C::IRQ1Handler( void ) {
Sissors 0:ff579e7e8efa 20 IRQHandler(&Buffer1, LPC_I2C1);
Sissors 0:ff579e7e8efa 21 }
Sissors 0:ff579e7e8efa 22
Sissors 0:ff579e7e8efa 23 void MODI2C::IRQ2Handler( void ) {
Sissors 0:ff579e7e8efa 24 IRQHandler(&Buffer2, LPC_I2C2);
Sissors 0:ff579e7e8efa 25 }
Sissors 0:ff579e7e8efa 26
Sissors 0:ff579e7e8efa 27 void MODI2C::IRQHandler( I2CBuffer *Buffer, LPC_I2C_TypeDef *I2CMODULE) {
tyftyftyf 1:eed116eb680a 28 I2CData *Data = (I2CData*)Buffer->curr;
Sissors 0:ff579e7e8efa 29
Sissors 0:ff579e7e8efa 30 //Depending on the status register it determines next action, see datasheet
Sissors 0:ff579e7e8efa 31 //This is also pretty much copy pasting the datasheet
Sissors 0:ff579e7e8efa 32 //General options
Sissors 0:ff579e7e8efa 33 switch (I2CMODULE->I2STAT) {
Sissors 0:ff579e7e8efa 34 case(0x08):
Sissors 0:ff579e7e8efa 35 case(0x10):
Sissors 0:ff579e7e8efa 36 //Send Address
Sissors 0:ff579e7e8efa 37 I2CMODULE->I2DAT = Data->address;
Sissors 0:ff579e7e8efa 38 I2CMODULE->I2CONCLR = 1<<I2C_FLAG | 1<<I2C_START;
Sissors 0:ff579e7e8efa 39 break;
Sissors 0:ff579e7e8efa 40
Sissors 0:ff579e7e8efa 41 //All master TX options
Sissors 0:ff579e7e8efa 42
Sissors 0:ff579e7e8efa 43 //Address + W has been sent, ACK received
Sissors 0:ff579e7e8efa 44 //Data has been sent, ACK received
Sissors 0:ff579e7e8efa 45 case(0x18):
Sissors 0:ff579e7e8efa 46 case(0x28):
Sissors 0:ff579e7e8efa 47 if (Buffer->count==Data->length) {
Sissors 0:ff579e7e8efa 48 *Data->status=I2CMODULE->I2STAT;
Sissors 0:ff579e7e8efa 49 if (!Data->repeated)
Sissors 0:ff579e7e8efa 50 _stop(I2CMODULE);
Sissors 0:ff579e7e8efa 51 else {
Sissors 0:ff579e7e8efa 52 I2CMODULE->I2CONSET = 1<<I2C_START;
Sissors 0:ff579e7e8efa 53 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
Sissors 0:ff579e7e8efa 54 }
Sissors 0:ff579e7e8efa 55 bufferHandler(I2CMODULE);
Sissors 0:ff579e7e8efa 56 } else {
Sissors 0:ff579e7e8efa 57 I2CMODULE->I2DAT = Data->data[Buffer->count];
Sissors 0:ff579e7e8efa 58 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK; //I dont see why I have to enable that bit, but datasheet says so
Sissors 0:ff579e7e8efa 59 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
Sissors 0:ff579e7e8efa 60 Buffer->count++;
Sissors 0:ff579e7e8efa 61 }
Sissors 0:ff579e7e8efa 62 break;
Sissors 0:ff579e7e8efa 63
Sissors 0:ff579e7e8efa 64 //Address + W has been sent, NACK received
Sissors 0:ff579e7e8efa 65 //Data has been sent, NACK received
Sissors 0:ff579e7e8efa 66 case(0x20):
Sissors 0:ff579e7e8efa 67 case(0x30):
Sissors 0:ff579e7e8efa 68 *Data->status=I2CMODULE->I2STAT;
Sissors 0:ff579e7e8efa 69 _stop(I2CMODULE);
Sissors 0:ff579e7e8efa 70 bufferHandler(I2CMODULE);
Sissors 0:ff579e7e8efa 71 break;
Sissors 0:ff579e7e8efa 72
Sissors 0:ff579e7e8efa 73 //Arbitration lost (situation looks pretty hopeless to me if you arrive here)
Sissors 0:ff579e7e8efa 74 case(0x38):
Sissors 0:ff579e7e8efa 75 _start(I2CMODULE);
Sissors 0:ff579e7e8efa 76 break;
Sissors 0:ff579e7e8efa 77
Sissors 0:ff579e7e8efa 78
Sissors 0:ff579e7e8efa 79 //All master RX options
Sissors 0:ff579e7e8efa 80
Sissors 0:ff579e7e8efa 81 //Address + R has been sent, ACK received
Sissors 0:ff579e7e8efa 82 case(0x40):
Sissors 0:ff579e7e8efa 83 //If next byte is last one, NACK, otherwise ACK
Sissors 0:ff579e7e8efa 84 if (Data->length <= Buffer->count + 1)
Sissors 0:ff579e7e8efa 85 I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
Sissors 0:ff579e7e8efa 86 else
Sissors 0:ff579e7e8efa 87 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
Sissors 0:ff579e7e8efa 88 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
Sissors 0:ff579e7e8efa 89 break;
Sissors 0:ff579e7e8efa 90
Sissors 0:ff579e7e8efa 91 //Address + R has been sent, NACK received
Sissors 0:ff579e7e8efa 92 case(0x48):
Sissors 0:ff579e7e8efa 93 *Data->status=I2CMODULE->I2STAT;
Sissors 0:ff579e7e8efa 94 _stop(I2CMODULE);
Sissors 0:ff579e7e8efa 95 bufferHandler(I2CMODULE);
Sissors 0:ff579e7e8efa 96 break;
Sissors 0:ff579e7e8efa 97
Sissors 0:ff579e7e8efa 98 //Data was received, ACK returned
Sissors 0:ff579e7e8efa 99 case(0x50):
Sissors 0:ff579e7e8efa 100 //Read data
Sissors 0:ff579e7e8efa 101 Data->data[Buffer->count]=I2CMODULE->I2DAT;
Sissors 0:ff579e7e8efa 102 Buffer->count++;
Sissors 0:ff579e7e8efa 103
Sissors 0:ff579e7e8efa 104 //If next byte is last one, NACK, otherwise ACK
Sissors 0:ff579e7e8efa 105 if (Data->length == Buffer->count + 1)
Sissors 0:ff579e7e8efa 106 I2CMODULE->I2CONCLR = 1<<I2C_ASSERT_ACK;
Sissors 0:ff579e7e8efa 107 else
Sissors 0:ff579e7e8efa 108 I2CMODULE->I2CONSET = 1<<I2C_ASSERT_ACK;
Sissors 0:ff579e7e8efa 109
Sissors 0:ff579e7e8efa 110 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
Sissors 0:ff579e7e8efa 111 break;
Sissors 0:ff579e7e8efa 112
Sissors 0:ff579e7e8efa 113 //Data was received, NACK returned (last byte)
Sissors 0:ff579e7e8efa 114 case(0x58):
Sissors 0:ff579e7e8efa 115 //Read data
Sissors 0:ff579e7e8efa 116 *Data->status=I2CMODULE->I2STAT;
Sissors 0:ff579e7e8efa 117 Data->data[Buffer->count]=I2CMODULE->I2DAT;
Sissors 0:ff579e7e8efa 118 if (!Data->repeated)
Sissors 0:ff579e7e8efa 119 _stop(I2CMODULE);
Sissors 0:ff579e7e8efa 120 else {
Sissors 0:ff579e7e8efa 121 I2CMODULE->I2CONSET = 1<<I2C_START;
Sissors 0:ff579e7e8efa 122 I2CMODULE->I2CONCLR = 1<<I2C_FLAG;
Sissors 0:ff579e7e8efa 123 }
Sissors 0:ff579e7e8efa 124 bufferHandler(I2CMODULE);
Sissors 0:ff579e7e8efa 125 break;
Sissors 0:ff579e7e8efa 126
Sissors 0:ff579e7e8efa 127 default:
Sissors 0:ff579e7e8efa 128 *Data->status=I2CMODULE->I2STAT;
Sissors 0:ff579e7e8efa 129 bufferHandler(I2CMODULE);
Sissors 0:ff579e7e8efa 130 break;
Sissors 0:ff579e7e8efa 131 }
Sissors 0:ff579e7e8efa 132 }
Sissors 0:ff579e7e8efa 133
Sissors 0:ff579e7e8efa 134
Sissors 0:ff579e7e8efa 135 //**********************************************************
Sissors 0:ff579e7e8efa 136 //*********************COMMAND BUFFER***********************
Sissors 0:ff579e7e8efa 137 //**********************************************************
Sissors 0:ff579e7e8efa 138
Sissors 0:ff579e7e8efa 139 void MODI2C::bufferHandler(LPC_I2C_TypeDef *I2CMODULE) {
Sissors 0:ff579e7e8efa 140 I2CBuffer *Buffer;
Sissors 0:ff579e7e8efa 141 if (I2CMODULE == LPC_I2C1) {
Sissors 0:ff579e7e8efa 142 Buffer = &Buffer1;
Sissors 0:ff579e7e8efa 143 } else {
Sissors 0:ff579e7e8efa 144 Buffer = &Buffer2;
Sissors 0:ff579e7e8efa 145 }
Sissors 0:ff579e7e8efa 146
Sissors 0:ff579e7e8efa 147 //Start user interrupt
tyftyftyf 1:eed116eb680a 148 Buffer->curr->caller->runUserIRQ((I2CData*)Buffer->curr);
tyftyftyf 1:eed116eb680a 149
tyftyftyf 1:eed116eb680a 150 Buffer->pool.free((I2CData*)Buffer->curr);
tyftyftyf 1:eed116eb680a 151
tyftyftyf 1:eed116eb680a 152 if (Buffer->crit_flag) return;
tyftyftyf 1:eed116eb680a 153
tyftyftyf 1:eed116eb680a 154 osEvent evt = Buffer->queue.get(0);
tyftyftyf 1:eed116eb680a 155 if (evt.status == osEventMessage){
tyftyftyf 1:eed116eb680a 156 Buffer->curr = (I2CData*)evt.value.p;
Sissors 0:ff579e7e8efa 157 startBuffer(I2CMODULE);
tyftyftyf 1:eed116eb680a 158 }
tyftyftyf 1:eed116eb680a 159 else{
tyftyftyf 1:eed116eb680a 160 Buffer->curr = NULL;
Sissors 0:ff579e7e8efa 161 _clearISR(I2CMODULE);
tyftyftyf 1:eed116eb680a 162 }
Sissors 0:ff579e7e8efa 163 }
Sissors 0:ff579e7e8efa 164
Sissors 0:ff579e7e8efa 165 //Returns true if succeeded, false if buffer is full
tyftyftyf 1:eed116eb680a 166 bool MODI2C::addBuffer(I2CData *Data, LPC_I2C_TypeDef *I2CMODULE) {
tyftyftyf 1:eed116eb680a 167
tyftyftyf 1:eed116eb680a 168 int interrupt = __get_IPSR();
tyftyftyf 1:eed116eb680a 169
Sissors 0:ff579e7e8efa 170 I2CBuffer *Buffer;
Sissors 0:ff579e7e8efa 171 if (I2CMODULE == LPC_I2C1) {
Sissors 0:ff579e7e8efa 172 Buffer = &Buffer1;
Sissors 0:ff579e7e8efa 173 } else {
Sissors 0:ff579e7e8efa 174 Buffer = &Buffer2;
Sissors 0:ff579e7e8efa 175 }
tyftyftyf 1:eed116eb680a 176
tyftyftyf 1:eed116eb680a 177 if(Data->status == NULL) {
tyftyftyf 1:eed116eb680a 178 Data->status = &defaultStatus;
tyftyftyf 1:eed116eb680a 179 wait_us(1); //I blame the compiler that this is needed
tyftyftyf 1:eed116eb680a 180 }
tyftyftyf 1:eed116eb680a 181 *(Data->status) = 0;
tyftyftyf 1:eed116eb680a 182
tyftyftyf 1:eed116eb680a 183 if (Buffer->queue.put(Data, 0)!=osOK){
tyftyftyf 1:eed116eb680a 184 if (interrupt!=0)
tyftyftyf 1:eed116eb680a 185 return false; //no waiting in ISR
tyftyftyf 1:eed116eb680a 186 else
tyftyftyf 1:eed116eb680a 187 while (Buffer->queue.put(Data, 0)!=osOK);
tyftyftyf 1:eed116eb680a 188 }
tyftyftyf 1:eed116eb680a 189
tyftyftyf 1:eed116eb680a 190 if (interrupt!=0){
tyftyftyf 1:eed116eb680a 191 if (Buffer->crit_flag_isr) return true;
tyftyftyf 1:eed116eb680a 192 }else Buffer->crit_flag_isr = true;
tyftyftyf 1:eed116eb680a 193
tyftyftyf 1:eed116eb680a 194 if (Buffer->curr == NULL){
tyftyftyf 1:eed116eb680a 195 if (interrupt==0) Buffer->crit_flag = true;
tyftyftyf 1:eed116eb680a 196 osEvent evt = Buffer->queue.get(0);
tyftyftyf 1:eed116eb680a 197 if (evt.status == osEventMessage){
tyftyftyf 1:eed116eb680a 198 Buffer->curr = (volatile I2CData*)(evt.value.p);
tyftyftyf 1:eed116eb680a 199 if (interrupt==0) Buffer->crit_flag_isr = false;
tyftyftyf 1:eed116eb680a 200 if (interrupt==0) Buffer->crit_flag = false;
Sissors 0:ff579e7e8efa 201 startBuffer(I2CMODULE);
tyftyftyf 1:eed116eb680a 202 }else{
tyftyftyf 1:eed116eb680a 203 if (interrupt==0) Buffer->crit_flag_isr = false;
tyftyftyf 1:eed116eb680a 204 if (interrupt==0) Buffer->crit_flag = false;
Sissors 0:ff579e7e8efa 205 }
tyftyftyf 1:eed116eb680a 206 }else{
tyftyftyf 1:eed116eb680a 207 if (interrupt==0) Buffer->crit_flag_isr = false;
Sissors 0:ff579e7e8efa 208 }
tyftyftyf 1:eed116eb680a 209
tyftyftyf 1:eed116eb680a 210
tyftyftyf 1:eed116eb680a 211 return true;
Sissors 0:ff579e7e8efa 212 }
Sissors 0:ff579e7e8efa 213
Sissors 0:ff579e7e8efa 214 //Starts new conversion
Sissors 0:ff579e7e8efa 215 void MODI2C::startBuffer(LPC_I2C_TypeDef *I2CMODULE) {
Sissors 0:ff579e7e8efa 216 I2CBuffer *Buffer;
Sissors 0:ff579e7e8efa 217 if (I2CMODULE == LPC_I2C1) {
Sissors 0:ff579e7e8efa 218 Buffer = &Buffer1;
Sissors 0:ff579e7e8efa 219 } else {
Sissors 0:ff579e7e8efa 220 Buffer = &Buffer2;
Sissors 0:ff579e7e8efa 221 }
Sissors 0:ff579e7e8efa 222
Sissors 0:ff579e7e8efa 223 //Write settings
tyftyftyf 1:eed116eb680a 224 Buffer->curr->caller->writeSettings();
Sissors 0:ff579e7e8efa 225 Buffer->count=0;
Sissors 0:ff579e7e8efa 226
Sissors 0:ff579e7e8efa 227 //Send Start
Sissors 0:ff579e7e8efa 228 _start(I2CMODULE);
Sissors 0:ff579e7e8efa 229
Sissors 0:ff579e7e8efa 230 //Start ISR (when buffer wasnt empty this wont do anything)
Sissors 0:ff579e7e8efa 231 _setISR(I2CMODULE);
Sissors 0:ff579e7e8efa 232
Sissors 0:ff579e7e8efa 233 }