Improvements to Olieman's MODI2C library. Supports calls from IRQ.
Dependents: FreeIMU FreeIMU_external_magnetometer FreeIMU
Fork of MODI2C by
MODI2C.cpp@1:eed116eb680a, 2013-11-09 (annotated)
- Committer:
- tyftyftyf
- Date:
- Sat Nov 09 08:59:02 2013 +0000
- Revision:
- 1:eed116eb680a
- Parent:
- 0:ff579e7e8efa
- Child:
- 2:22f93d992c83
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?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sissors | 0:ff579e7e8efa | 1 | #include "MODI2C.h" |
Sissors | 0:ff579e7e8efa | 2 | |
tyftyftyf | 1:eed116eb680a | 3 | MODI2C::I2CBuffer MODI2C::Buffer1; |
tyftyftyf | 1:eed116eb680a | 4 | MODI2C::I2CBuffer MODI2C::Buffer2; |
tyftyftyf | 1:eed116eb680a | 5 | |
Sissors | 0:ff579e7e8efa | 6 | //int MODI2C::status=0; |
Sissors | 0:ff579e7e8efa | 7 | int MODI2C::defaultStatus=0; |
Sissors | 0:ff579e7e8efa | 8 | |
Sissors | 0:ff579e7e8efa | 9 | |
Sissors | 0:ff579e7e8efa | 10 | |
Sissors | 0:ff579e7e8efa | 11 | |
tyftyftyf | 1:eed116eb680a | 12 | MODI2C::MODI2C(PinName sda, PinName scl) : led(LED3){ |
Sissors | 0:ff579e7e8efa | 13 | //Check which connection we are using, if not correct, go to error status |
Sissors | 0:ff579e7e8efa | 14 | if ((sda==p9) && (scl==p10)) |
Sissors | 0:ff579e7e8efa | 15 | I2CMODULE = LPC_I2C1; |
Sissors | 0:ff579e7e8efa | 16 | else if ((sda==p28) && (scl==p27)) |
Sissors | 0:ff579e7e8efa | 17 | I2CMODULE = LPC_I2C2; |
Sissors | 0:ff579e7e8efa | 18 | else |
Sissors | 0:ff579e7e8efa | 19 | error("MODI2C pins not valid"); |
Sissors | 0:ff579e7e8efa | 20 | |
Sissors | 0:ff579e7e8efa | 21 | //Default settings: |
tyftyftyf | 1:eed116eb680a | 22 | frequency(400000); |
Sissors | 0:ff579e7e8efa | 23 | |
Sissors | 0:ff579e7e8efa | 24 | writePinState(); |
Sissors | 0:ff579e7e8efa | 25 | } |
Sissors | 0:ff579e7e8efa | 26 | |
tyftyftyf | 1:eed116eb680a | 27 | int MODI2C::write(int address, char *data, int length, uint32_t(*function)(uint32_t), void* pass_to_irq, bool repeated, int *status) { |
Sissors | 0:ff579e7e8efa | 28 | |
Sissors | 0:ff579e7e8efa | 29 | I2CBuffer *Buffer; |
Sissors | 0:ff579e7e8efa | 30 | if (I2CMODULE == LPC_I2C1) { |
Sissors | 0:ff579e7e8efa | 31 | Buffer = &Buffer1; |
Sissors | 0:ff579e7e8efa | 32 | } else { |
Sissors | 0:ff579e7e8efa | 33 | Buffer = &Buffer2; |
Sissors | 0:ff579e7e8efa | 34 | } |
Sissors | 0:ff579e7e8efa | 35 | |
tyftyftyf | 1:eed116eb680a | 36 | I2CData *Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 37 | if (Data == NULL){ |
tyftyftyf | 1:eed116eb680a | 38 | if (__get_IPSR() != 0) |
tyftyftyf | 1:eed116eb680a | 39 | return -1; //no waiting in ISR |
tyftyftyf | 1:eed116eb680a | 40 | else |
tyftyftyf | 1:eed116eb680a | 41 | while (Data == NULL) Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 42 | } |
tyftyftyf | 1:eed116eb680a | 43 | |
tyftyftyf | 1:eed116eb680a | 44 | //Store relevant information |
tyftyftyf | 1:eed116eb680a | 45 | address &= 0xFE; |
tyftyftyf | 1:eed116eb680a | 46 | Data->caller = this; |
tyftyftyf | 1:eed116eb680a | 47 | Data->address = address; |
tyftyftyf | 1:eed116eb680a | 48 | Data->repeated = repeated; |
tyftyftyf | 1:eed116eb680a | 49 | Data->data = data; |
tyftyftyf | 1:eed116eb680a | 50 | Data->length = length; |
tyftyftyf | 1:eed116eb680a | 51 | Data->status = status; |
tyftyftyf | 1:eed116eb680a | 52 | Data->pass_to_irq = (uint32_t)pass_to_irq; |
tyftyftyf | 1:eed116eb680a | 53 | Data->monitor_addr = NULL; |
tyftyftyf | 1:eed116eb680a | 54 | |
tyftyftyf | 1:eed116eb680a | 55 | if (function!=NULL){ |
tyftyftyf | 1:eed116eb680a | 56 | Data->IRQOp = IRQ_I2C_WRITE; |
tyftyftyf | 1:eed116eb680a | 57 | Data->callback.attach(function); |
tyftyftyf | 1:eed116eb680a | 58 | }else{ |
tyftyftyf | 1:eed116eb680a | 59 | Data->IRQOp = NULL; |
tyftyftyf | 1:eed116eb680a | 60 | } |
tyftyftyf | 1:eed116eb680a | 61 | |
tyftyftyf | 1:eed116eb680a | 62 | addBuffer(Data, I2CMODULE); |
tyftyftyf | 1:eed116eb680a | 63 | |
tyftyftyf | 1:eed116eb680a | 64 | return 0; |
tyftyftyf | 1:eed116eb680a | 65 | } |
tyftyftyf | 1:eed116eb680a | 66 | |
tyftyftyf | 1:eed116eb680a | 67 | int MODI2C::write(int address, char *data, int length, int *status) { |
tyftyftyf | 1:eed116eb680a | 68 | return write(address, data, length, NULL, NULL, false, status); |
tyftyftyf | 1:eed116eb680a | 69 | } |
tyftyftyf | 1:eed116eb680a | 70 | |
tyftyftyf | 1:eed116eb680a | 71 | int MODI2C::write(int address, char *data, int length, bool repeated) { |
tyftyftyf | 1:eed116eb680a | 72 | return write(address, data, length, NULL, NULL, repeated); |
tyftyftyf | 1:eed116eb680a | 73 | } |
tyftyftyf | 1:eed116eb680a | 74 | |
tyftyftyf | 1:eed116eb680a | 75 | int MODI2C::read_nb(int address, char *data, int length, uint32_t(*function)(uint32_t), void* pass_to_irq, bool repeated, int *status) { |
tyftyftyf | 1:eed116eb680a | 76 | //Store relevant information |
tyftyftyf | 1:eed116eb680a | 77 | address |= 0x01; |
tyftyftyf | 1:eed116eb680a | 78 | |
tyftyftyf | 1:eed116eb680a | 79 | I2CBuffer *Buffer; |
tyftyftyf | 1:eed116eb680a | 80 | if (I2CMODULE == LPC_I2C1) { |
tyftyftyf | 1:eed116eb680a | 81 | Buffer = &Buffer1; |
tyftyftyf | 1:eed116eb680a | 82 | } else { |
tyftyftyf | 1:eed116eb680a | 83 | Buffer = &Buffer2; |
tyftyftyf | 1:eed116eb680a | 84 | } |
tyftyftyf | 1:eed116eb680a | 85 | |
tyftyftyf | 1:eed116eb680a | 86 | I2CData *Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 87 | if (Data == NULL){ |
tyftyftyf | 1:eed116eb680a | 88 | if (__get_IPSR() != 0) |
tyftyftyf | 1:eed116eb680a | 89 | return -1; //no waiting in ISR |
tyftyftyf | 1:eed116eb680a | 90 | else |
tyftyftyf | 1:eed116eb680a | 91 | while (Data == NULL) Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 92 | } |
tyftyftyf | 1:eed116eb680a | 93 | |
tyftyftyf | 1:eed116eb680a | 94 | Data->caller = this; |
tyftyftyf | 1:eed116eb680a | 95 | Data->address = address; |
tyftyftyf | 1:eed116eb680a | 96 | Data->repeated = repeated; |
tyftyftyf | 1:eed116eb680a | 97 | Data->data = data; |
tyftyftyf | 1:eed116eb680a | 98 | Data->length = length; |
tyftyftyf | 1:eed116eb680a | 99 | Data->status = status; |
tyftyftyf | 1:eed116eb680a | 100 | Data->IRQOp = IRQ_I2C_READ; |
tyftyftyf | 1:eed116eb680a | 101 | Data->pass_to_irq = (uint32_t)pass_to_irq; |
tyftyftyf | 1:eed116eb680a | 102 | Data->callback.attach(function); |
tyftyftyf | 1:eed116eb680a | 103 | Data->monitor_addr = NULL; |
tyftyftyf | 1:eed116eb680a | 104 | |
tyftyftyf | 1:eed116eb680a | 105 | addBuffer(Data, I2CMODULE); |
tyftyftyf | 1:eed116eb680a | 106 | |
tyftyftyf | 1:eed116eb680a | 107 | return 0; |
tyftyftyf | 1:eed116eb680a | 108 | } |
tyftyftyf | 1:eed116eb680a | 109 | |
tyftyftyf | 1:eed116eb680a | 110 | int MODI2C::read(int address, char *data, int length, bool repeated) { |
tyftyftyf | 1:eed116eb680a | 111 | int stat; |
tyftyftyf | 1:eed116eb680a | 112 | //Store relevant information |
tyftyftyf | 1:eed116eb680a | 113 | address |= 0x01; |
tyftyftyf | 1:eed116eb680a | 114 | |
tyftyftyf | 1:eed116eb680a | 115 | I2CBuffer *Buffer; |
tyftyftyf | 1:eed116eb680a | 116 | if (I2CMODULE == LPC_I2C1) { |
tyftyftyf | 1:eed116eb680a | 117 | Buffer = &Buffer1; |
tyftyftyf | 1:eed116eb680a | 118 | } else { |
tyftyftyf | 1:eed116eb680a | 119 | Buffer = &Buffer2; |
tyftyftyf | 1:eed116eb680a | 120 | } |
tyftyftyf | 1:eed116eb680a | 121 | |
tyftyftyf | 1:eed116eb680a | 122 | I2CData *Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 123 | if (Data == NULL){ |
tyftyftyf | 1:eed116eb680a | 124 | if (__get_IPSR() != 0) |
tyftyftyf | 1:eed116eb680a | 125 | return -1; //no waiting in ISR |
tyftyftyf | 1:eed116eb680a | 126 | else |
tyftyftyf | 1:eed116eb680a | 127 | while (Data == NULL) Data = Buffer->pool.calloc(); |
tyftyftyf | 1:eed116eb680a | 128 | } |
tyftyftyf | 1:eed116eb680a | 129 | |
tyftyftyf | 1:eed116eb680a | 130 | Data->caller = this; |
tyftyftyf | 1:eed116eb680a | 131 | Data->address = address; |
tyftyftyf | 1:eed116eb680a | 132 | Data->repeated = repeated; |
tyftyftyf | 1:eed116eb680a | 133 | Data->data = data; |
tyftyftyf | 1:eed116eb680a | 134 | Data->length = length; |
tyftyftyf | 1:eed116eb680a | 135 | Data->status = &stat; |
tyftyftyf | 1:eed116eb680a | 136 | Data->IRQOp = NULL; |
tyftyftyf | 1:eed116eb680a | 137 | |
tyftyftyf | 1:eed116eb680a | 138 | volatile char monitor = 1; |
tyftyftyf | 1:eed116eb680a | 139 | Data->monitor_addr = &monitor; |
tyftyftyf | 1:eed116eb680a | 140 | |
tyftyftyf | 1:eed116eb680a | 141 | addBuffer(Data, I2CMODULE); |
tyftyftyf | 1:eed116eb680a | 142 | |
tyftyftyf | 1:eed116eb680a | 143 | while(monitor!=0) wait_us(1); |
Sissors | 0:ff579e7e8efa | 144 | |
Sissors | 0:ff579e7e8efa | 145 | if (stat==0x58) //Return zero if ended correctly, otherwise return return code. |
Sissors | 0:ff579e7e8efa | 146 | return 0; |
Sissors | 0:ff579e7e8efa | 147 | else |
Sissors | 0:ff579e7e8efa | 148 | return stat; |
Sissors | 0:ff579e7e8efa | 149 | } |
Sissors | 0:ff579e7e8efa | 150 | |
Sissors | 0:ff579e7e8efa | 151 | |
Sissors | 0:ff579e7e8efa | 152 | void MODI2C::start( void ) { |
Sissors | 0:ff579e7e8efa | 153 | _start(I2CMODULE); |
Sissors | 0:ff579e7e8efa | 154 | } |
Sissors | 0:ff579e7e8efa | 155 | |
Sissors | 0:ff579e7e8efa | 156 | void MODI2C::stop( void ) { |
Sissors | 0:ff579e7e8efa | 157 | _stop(I2CMODULE); |
Sissors | 0:ff579e7e8efa | 158 | } |
Sissors | 0:ff579e7e8efa | 159 | |
Sissors | 0:ff579e7e8efa | 160 | void MODI2C::frequency(int hz) { |
Sissors | 0:ff579e7e8efa | 161 | //The I2C clock by default runs on quarter of system clock, which is 96MHz |
Sissors | 0:ff579e7e8efa | 162 | //So to calculate high/low count times, we do 96MHz/4/2/frequency |
tyftyftyf | 1:eed116eb680a | 163 | duty = 120000000/8/hz; |
Sissors | 0:ff579e7e8efa | 164 | if (duty>65535) |
Sissors | 0:ff579e7e8efa | 165 | duty=65535; |
Sissors | 0:ff579e7e8efa | 166 | if (duty<4) |
Sissors | 0:ff579e7e8efa | 167 | duty=4; |
Sissors | 0:ff579e7e8efa | 168 | } |
Sissors | 0:ff579e7e8efa | 169 | |
Sissors | 0:ff579e7e8efa | 170 | //******************************************* |
Sissors | 0:ff579e7e8efa | 171 | //***********Internal functions************** |
Sissors | 0:ff579e7e8efa | 172 | //******************************************* |
Sissors | 0:ff579e7e8efa | 173 | |
Sissors | 0:ff579e7e8efa | 174 | |
Sissors | 0:ff579e7e8efa | 175 | void MODI2C::writeSettings( void ) { |
Sissors | 0:ff579e7e8efa | 176 | I2CMODULE->I2CONSET = 1<<I2C_ENABLE; //Enable I2C |
Sissors | 0:ff579e7e8efa | 177 | I2CMODULE->I2CONCLR = I2C_STOP; |
Sissors | 0:ff579e7e8efa | 178 | I2CMODULE->MMCTRL = 0; //Disable monitor mode |
Sissors | 0:ff579e7e8efa | 179 | I2CMODULE->I2SCLH = duty; |
Sissors | 0:ff579e7e8efa | 180 | I2CMODULE->I2SCLL = duty; |
Sissors | 0:ff579e7e8efa | 181 | |
Sissors | 0:ff579e7e8efa | 182 | } |
Sissors | 0:ff579e7e8efa | 183 | |
Sissors | 0:ff579e7e8efa | 184 | void MODI2C::writePinState( void ) { |
Sissors | 0:ff579e7e8efa | 185 | if (I2CMODULE == LPC_I2C1) { |
Sissors | 0:ff579e7e8efa | 186 | LPC_PINCON->PINSEL0 |= 0x0000000F; //Sets pins as I2C |
Sissors | 0:ff579e7e8efa | 187 | LPC_PINCON->PINMODE0 |= 0x0000000A; //Neither pull up nor pull down |
Sissors | 0:ff579e7e8efa | 188 | LPC_PINCON->PINMODE_OD0 |= 0x00000003; //Open drain mode enabled |
Sissors | 0:ff579e7e8efa | 189 | } else if (I2CMODULE == LPC_I2C2) { |
Sissors | 0:ff579e7e8efa | 190 | LPC_PINCON->PINSEL0 |= (1<<21)|(1<<23); //Same story, different register settings |
Sissors | 0:ff579e7e8efa | 191 | LPC_PINCON->PINMODE0 |= (1<<21)|(1<<23); |
Sissors | 0:ff579e7e8efa | 192 | LPC_PINCON->PINMODE_OD0 |= (1<<10)|(1<<11); |
Sissors | 0:ff579e7e8efa | 193 | } |
Sissors | 0:ff579e7e8efa | 194 | } |
Sissors | 0:ff579e7e8efa | 195 | |
Sissors | 0:ff579e7e8efa | 196 | void MODI2C::_start(LPC_I2C_TypeDef *I2CMODULE) { |
Sissors | 0:ff579e7e8efa | 197 | if (!(I2CMODULE->I2CONSET & 1<<I2C_START)) //If already sent, skip |
Sissors | 0:ff579e7e8efa | 198 | I2CMODULE->I2CONSET = 1<<I2C_START; //Send start condition |
Sissors | 0:ff579e7e8efa | 199 | } |
Sissors | 0:ff579e7e8efa | 200 | |
Sissors | 0:ff579e7e8efa | 201 | void MODI2C::_stop(LPC_I2C_TypeDef *I2CMODULE) { |
Sissors | 0:ff579e7e8efa | 202 | I2CMODULE->I2CONSET = 1<<I2C_STOP; //Send stop condition |
Sissors | 0:ff579e7e8efa | 203 | I2CMODULE->I2CONCLR = 1<<I2C_FLAG; |
Sissors | 0:ff579e7e8efa | 204 | } |
Sissors | 0:ff579e7e8efa | 205 | |
Sissors | 0:ff579e7e8efa | 206 | //Set interrupt vector |
Sissors | 0:ff579e7e8efa | 207 | void MODI2C::setISR(void) { |
Sissors | 0:ff579e7e8efa | 208 | _setISR(I2CMODULE); |
Sissors | 0:ff579e7e8efa | 209 | } |
Sissors | 0:ff579e7e8efa | 210 | |
Sissors | 0:ff579e7e8efa | 211 | void MODI2C::_setISR(LPC_I2C_TypeDef *I2CMODULE) { |
Sissors | 0:ff579e7e8efa | 212 | if (I2CMODULE == LPC_I2C1) { |
Sissors | 0:ff579e7e8efa | 213 | NVIC_SetVector(I2C1_IRQn, (uint32_t)&IRQ1Handler); |
Sissors | 0:ff579e7e8efa | 214 | NVIC_EnableIRQ(I2C1_IRQn); |
Sissors | 0:ff579e7e8efa | 215 | } else if (I2CMODULE == LPC_I2C2) { |
Sissors | 0:ff579e7e8efa | 216 | NVIC_SetVector(I2C2_IRQn, (uint32_t)&IRQ2Handler); |
Sissors | 0:ff579e7e8efa | 217 | NVIC_EnableIRQ(I2C2_IRQn); |
Sissors | 0:ff579e7e8efa | 218 | } |
Sissors | 0:ff579e7e8efa | 219 | } |
Sissors | 0:ff579e7e8efa | 220 | |
Sissors | 0:ff579e7e8efa | 221 | void MODI2C::clearISR( void ) { |
Sissors | 0:ff579e7e8efa | 222 | _clearISR(I2CMODULE); |
Sissors | 0:ff579e7e8efa | 223 | } |
Sissors | 0:ff579e7e8efa | 224 | |
Sissors | 0:ff579e7e8efa | 225 | void MODI2C::_clearISR( LPC_I2C_TypeDef *I2CMODULE ) { |
Sissors | 0:ff579e7e8efa | 226 | if (I2CMODULE == LPC_I2C1) { |
Sissors | 0:ff579e7e8efa | 227 | NVIC_DisableIRQ(I2C1_IRQn); |
Sissors | 0:ff579e7e8efa | 228 | } else if (I2CMODULE == LPC_I2C2) { |
Sissors | 0:ff579e7e8efa | 229 | NVIC_DisableIRQ(I2C2_IRQn); |
Sissors | 0:ff579e7e8efa | 230 | } |
Sissors | 0:ff579e7e8efa | 231 | } |