I2CRTOS Driver by Helmut Schmücker. Removed included mbed-rtos library to prevent multiple definition. Make sure to include mbed-rtos library in your program!
Fork of I2cRtosDriver by
i2cRtos_api.c@16:2c6432b37cce, 2014-05-17 (annotated)
- Committer:
- pHysiX
- Date:
- Sat May 17 11:56:46 2014 +0000
- Revision:
- 16:2c6432b37cce
- Parent:
- 14:352609d395c1
Modified to make 400kHz default
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
humlet | 9:65aae53a34de | 1 | #include "i2cRtos_api.h" |
humlet | 9:65aae53a34de | 2 | |
humlet | 9:65aae53a34de | 3 | #if DEVICE_I2C |
humlet | 9:65aae53a34de | 4 | |
humlet | 13:530968937ccb | 5 | #include "us_ticker_api.h" |
humlet | 9:65aae53a34de | 6 | #include "cmsis_os.h" |
humlet | 9:65aae53a34de | 7 | #include "error.h" |
humlet | 9:65aae53a34de | 8 | |
humlet | 14:352609d395c1 | 9 | // little helpers cloned from official i2c api |
humlet | 13:530968937ccb | 10 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 9:65aae53a34de | 11 | #define I2C_CONSET(x) (x->i2c->I2CONSET) |
humlet | 9:65aae53a34de | 12 | #define I2C_CONCLR(x) (x->i2c->I2CONCLR) |
humlet | 9:65aae53a34de | 13 | #define I2C_STAT(x) (x->i2c->I2STAT) |
humlet | 9:65aae53a34de | 14 | #define I2C_DAT(x) (x->i2c->I2DAT) |
humlet | 13:530968937ccb | 15 | #elif defined(TARGET_LPC11U24) |
humlet | 13:530968937ccb | 16 | #define I2C_CONSET(x) (x->i2c->CONSET) |
humlet | 13:530968937ccb | 17 | #define I2C_CONCLR(x) (x->i2c->CONCLR) |
humlet | 13:530968937ccb | 18 | #define I2C_STAT(x) (x->i2c->STAT) |
humlet | 13:530968937ccb | 19 | #define I2C_DAT(x) (x->i2c->DAT) |
humlet | 13:530968937ccb | 20 | #endif |
humlet | 9:65aae53a34de | 21 | |
humlet | 14:352609d395c1 | 22 | //#include "gpio_api.h" |
humlet | 14:352609d395c1 | 23 | //static gpio_t gpio[2]; // evillive |
humlet | 10:e3d6c92ff222 | 24 | |
humlet | 14:352609d395c1 | 25 | // isr/thread data transfer struct |
humlet | 9:65aae53a34de | 26 | enum I2cIsrCmd { |
humlet | 9:65aae53a34de | 27 | readMst, |
humlet | 9:65aae53a34de | 28 | writeMst, |
humlet | 9:65aae53a34de | 29 | readSlv, |
humlet | 9:65aae53a34de | 30 | writeSlv, |
humlet | 9:65aae53a34de | 31 | waitSI |
humlet | 9:65aae53a34de | 32 | }; |
humlet | 9:65aae53a34de | 33 | struct I2cIsrTransfer { |
humlet | 9:65aae53a34de | 34 | i2c_t* obj; |
humlet | 9:65aae53a34de | 35 | enum I2cIsrCmd cmd; |
humlet | 9:65aae53a34de | 36 | int len; |
humlet | 9:65aae53a34de | 37 | int cnt; |
humlet | 9:65aae53a34de | 38 | int stat; |
humlet | 9:65aae53a34de | 39 | char* rData; |
humlet | 9:65aae53a34de | 40 | const char* wData; |
humlet | 9:65aae53a34de | 41 | }; |
humlet | 14:352609d395c1 | 42 | // one for each channel |
humlet | 14:352609d395c1 | 43 | // "volatile" has been omitted since ISR and thread do not run simultaneously, hopefully ok |
humlet | 14:352609d395c1 | 44 | static struct I2cIsrTransfer i2c_transfer[2]; |
humlet | 9:65aae53a34de | 45 | |
humlet | 14:352609d395c1 | 46 | // struct holding IRQ and semaphore ID |
humlet | 14:352609d395c1 | 47 | // needed for thread<->isr communication/activation |
humlet | 9:65aae53a34de | 48 | struct IsrIrqSem { |
humlet | 9:65aae53a34de | 49 | IRQn_Type irq; |
humlet | 9:65aae53a34de | 50 | osSemaphoreId sem; |
humlet | 9:65aae53a34de | 51 | }; |
humlet | 14:352609d395c1 | 52 | static struct IsrIrqSem isrIrqSem[2]; // one for each channel |
humlet | 9:65aae53a34de | 53 | |
humlet | 9:65aae53a34de | 54 | |
humlet | 9:65aae53a34de | 55 | // little helpers cloned from official i2c api |
humlet | 9:65aae53a34de | 56 | static inline void i2c_conclr(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) |
humlet | 9:65aae53a34de | 57 | { |
humlet | 9:65aae53a34de | 58 | I2C_CONCLR(obj) = (start << 5) |
humlet | 9:65aae53a34de | 59 | | (stop << 4) |
humlet | 9:65aae53a34de | 60 | | (interrupt << 3) |
humlet | 9:65aae53a34de | 61 | | (acknowledge << 2); |
humlet | 9:65aae53a34de | 62 | } |
humlet | 9:65aae53a34de | 63 | static inline void i2c_conset(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) |
humlet | 9:65aae53a34de | 64 | { |
humlet | 9:65aae53a34de | 65 | I2C_CONSET(obj) = (start << 5) |
humlet | 9:65aae53a34de | 66 | | (stop << 4) |
humlet | 9:65aae53a34de | 67 | | (interrupt << 3) |
humlet | 9:65aae53a34de | 68 | | (acknowledge << 2); |
humlet | 9:65aae53a34de | 69 | } |
humlet | 9:65aae53a34de | 70 | static inline void i2c_clear_SI(i2c_t *obj) |
humlet | 9:65aae53a34de | 71 | { |
humlet | 9:65aae53a34de | 72 | i2c_conclr(obj, 0, 0, 1, 0); |
humlet | 9:65aae53a34de | 73 | } |
humlet | 9:65aae53a34de | 74 | static inline int i2c_status(i2c_t *obj) |
humlet | 9:65aae53a34de | 75 | { |
humlet | 9:65aae53a34de | 76 | return I2C_STAT(obj); |
humlet | 9:65aae53a34de | 77 | } |
humlet | 9:65aae53a34de | 78 | |
humlet | 14:352609d395c1 | 79 | // ISR routines |
humlet | 14:352609d395c1 | 80 | // implements the same read/write sequences as the official i2c lib |
humlet | 10:e3d6c92ff222 | 81 | static void i2cRtos_isr(uint32_t ch) |
humlet | 9:65aae53a34de | 82 | { |
humlet | 11:8c1d44595620 | 83 | struct I2cIsrTransfer* tr=&(i2c_transfer[ch]); |
humlet | 12:6ddadcbbdca2 | 84 | if(tr->cmd==waitSI) { |
humlet | 14:352609d395c1 | 85 | // just waiting for an interrupt after a byte read/write or slave receive call |
humlet | 9:65aae53a34de | 86 | osSemaphoreRelease(isrIrqSem[ch].sem); |
humlet | 9:65aae53a34de | 87 | NVIC_DisableIRQ(isrIrqSem[ch].irq); |
humlet | 9:65aae53a34de | 88 | return; |
humlet | 9:65aae53a34de | 89 | } |
humlet | 9:65aae53a34de | 90 | int stat=i2c_status(tr->obj); |
humlet | 9:65aae53a34de | 91 | int stay = 0; |
humlet | 9:65aae53a34de | 92 | switch(tr->cmd) { |
humlet | 11:8c1d44595620 | 93 | case readMst: |
humlet | 11:8c1d44595620 | 94 | switch(stat) { |
humlet | 14:352609d395c1 | 95 | case 0x50: // Data byte has been received; ACK has been returned. |
humlet | 11:8c1d44595620 | 96 | (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff); |
humlet | 14:352609d395c1 | 97 | case 0x40: // SLA+R has been transmitted; ACK has been received. |
humlet | 11:8c1d44595620 | 98 | ++(tr->cnt); |
humlet | 11:8c1d44595620 | 99 | if(tr->cnt != tr->len-1) |
humlet | 10:e3d6c92ff222 | 100 | i2c_conset(tr->obj, 0, 0, 0, 1); |
humlet | 11:8c1d44595620 | 101 | else |
humlet | 14:352609d395c1 | 102 | i2c_conclr(tr->obj, 0, 0, 0, 1); // do not ack the last byte read |
humlet | 9:65aae53a34de | 103 | stay = 1; |
humlet | 11:8c1d44595620 | 104 | break; |
humlet | 14:352609d395c1 | 105 | case 0x58: // Data byte has been received; NOT ACK has been returned. |
humlet | 11:8c1d44595620 | 106 | (tr->rData)[tr->cnt] = (char)(I2C_DAT(tr->obj) & 0xff); |
humlet | 11:8c1d44595620 | 107 | stat=0; |
humlet | 11:8c1d44595620 | 108 | break; |
humlet | 9:65aae53a34de | 109 | } |
humlet | 9:65aae53a34de | 110 | break; |
humlet | 11:8c1d44595620 | 111 | case writeMst: |
humlet | 11:8c1d44595620 | 112 | switch(stat) { |
humlet | 14:352609d395c1 | 113 | case 0x18: // SLA+W has been transmitted; ACK has been received. |
humlet | 14:352609d395c1 | 114 | case 0x28: // SLA+W has been transmitted; NOT ACK has been received. |
humlet | 14:352609d395c1 | 115 | if(++(tr->cnt)!=tr->len) { |
humlet | 11:8c1d44595620 | 116 | I2C_DAT(tr->obj) = (tr->wData)[tr->cnt]; |
humlet | 11:8c1d44595620 | 117 | stay=1; |
humlet | 11:8c1d44595620 | 118 | } else { |
humlet | 11:8c1d44595620 | 119 | stat=0; |
humlet | 11:8c1d44595620 | 120 | } |
humlet | 9:65aae53a34de | 121 | } |
humlet | 9:65aae53a34de | 122 | break; |
humlet | 11:8c1d44595620 | 123 | case readSlv: |
humlet | 11:8c1d44595620 | 124 | ++(tr->cnt); |
humlet | 14:352609d395c1 | 125 | if(stat==0x80 || stat==0x90) // Previously addressed with own SLA address(0x80) or geberal call (0x90); DATA has been received; ACK has been returned. |
humlet | 11:8c1d44595620 | 126 | (tr->rData)[tr->cnt] = I2C_DAT(tr->obj) & 0xFF; |
humlet | 11:8c1d44595620 | 127 | stay = (stat==0x80 || stat==0x90 || stat==0x060 || stat==0x70) && (tr->cnt < tr->len-1); |
humlet | 14:352609d395c1 | 128 | // 60: Own SLA+W has been received; ACK has been returned. ... SLV+W??? |
humlet | 14:352609d395c1 | 129 | // 70: General Call address (0x00) has been received; ACK has been returned. |
humlet | 9:65aae53a34de | 130 | break; |
humlet | 11:8c1d44595620 | 131 | case writeSlv: |
humlet | 11:8c1d44595620 | 132 | ++(tr->cnt); |
humlet | 14:352609d395c1 | 133 | stay = tr->cnt<tr->len && stat==0xb8; // Data byte in I2DAT has been transmitted; ACK has been received. |
humlet | 14:352609d395c1 | 134 | if(stay) I2C_DAT(tr->obj) = tr->wData[tr->cnt]; |
humlet | 9:65aae53a34de | 135 | break; |
humlet | 9:65aae53a34de | 136 | } |
humlet | 9:65aae53a34de | 137 | if(stay) { |
humlet | 14:352609d395c1 | 138 | // sequence not finished => stay in ISR mode and trigger next i2c by clearing he SI bit |
humlet | 9:65aae53a34de | 139 | i2c_clear_SI(tr->obj); |
humlet | 9:65aae53a34de | 140 | } else { |
humlet | 14:352609d395c1 | 141 | // sequence finished or unexpected state has been reported |
humlet | 14:352609d395c1 | 142 | // => bail out of isr mode and return last status received |
humlet | 9:65aae53a34de | 143 | tr->stat = stat; |
humlet | 9:65aae53a34de | 144 | osSemaphoreRelease(isrIrqSem[ch].sem); |
humlet | 9:65aae53a34de | 145 | NVIC_DisableIRQ(isrIrqSem[ch].irq); |
humlet | 9:65aae53a34de | 146 | } |
humlet | 9:65aae53a34de | 147 | } |
humlet | 13:530968937ccb | 148 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 11:8c1d44595620 | 149 | static void i2cRtos_isr_ch0() |
humlet | 9:65aae53a34de | 150 | { |
humlet | 11:8c1d44595620 | 151 | //gpio_write(&gpio[0], 1); |
humlet | 9:65aae53a34de | 152 | i2cRtos_isr(0); |
humlet | 11:8c1d44595620 | 153 | //gpio_write(&gpio[0], 0); |
humlet | 9:65aae53a34de | 154 | } |
humlet | 13:530968937ccb | 155 | #endif |
humlet | 11:8c1d44595620 | 156 | static void i2cRtos_isr_ch1() |
humlet | 9:65aae53a34de | 157 | { |
humlet | 11:8c1d44595620 | 158 | //gpio_write(&gpio[1], 1); |
humlet | 9:65aae53a34de | 159 | i2cRtos_isr(1); |
humlet | 11:8c1d44595620 | 160 | //gpio_write(&gpio[1], 0); |
humlet | 9:65aae53a34de | 161 | } |
humlet | 9:65aae53a34de | 162 | |
humlet | 9:65aae53a34de | 163 | |
humlet | 9:65aae53a34de | 164 | // determine channel |
humlet | 11:8c1d44595620 | 165 | static inline uint32_t i2c_get_channel(const i2c_t *obj) |
humlet | 9:65aae53a34de | 166 | { |
humlet | 9:65aae53a34de | 167 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 9:65aae53a34de | 168 | switch((I2CName)(obj->i2c)) { |
humlet | 9:65aae53a34de | 169 | case I2C_1: |
humlet | 9:65aae53a34de | 170 | return 0; |
humlet | 9:65aae53a34de | 171 | case I2C_2: |
humlet | 9:65aae53a34de | 172 | return 1; |
humlet | 9:65aae53a34de | 173 | default: |
humlet | 9:65aae53a34de | 174 | error("Dial911 i2c_get_channel: Invaid I2CName \n"); |
humlet | 9:65aae53a34de | 175 | } |
humlet | 9:65aae53a34de | 176 | #endif |
humlet | 10:e3d6c92ff222 | 177 | return 1; |
humlet | 9:65aae53a34de | 178 | } |
humlet | 9:65aae53a34de | 179 | |
humlet | 9:65aae53a34de | 180 | |
humlet | 14:352609d395c1 | 181 | // Enable IRQ and wait for ISR sequence to be finished |
humlet | 12:6ddadcbbdca2 | 182 | static inline void i2cRtos_wait_and_see(i2c_t *obj, int ch, uint32_t tmOut) //evillive |
humlet | 9:65aae53a34de | 183 | { |
humlet | 11:8c1d44595620 | 184 | struct IsrIrqSem* iis = &(isrIrqSem[ch]); |
humlet | 14:352609d395c1 | 185 | __disable_irq(); // evil, but don't want the next three lines to be interrupted |
humlet | 9:65aae53a34de | 186 | i2c_clear_SI(obj); |
humlet | 11:8c1d44595620 | 187 | NVIC_ClearPendingIRQ(iis->irq); |
humlet | 9:65aae53a34de | 188 | NVIC_EnableIRQ(iis->irq); |
humlet | 10:e3d6c92ff222 | 189 | __enable_irq(); |
humlet | 14:352609d395c1 | 190 | if(osSemaphoreWait(iis->sem, tmOut)!=1) NVIC_DisableIRQ(iis->irq); // time out => diable the IRQ |
humlet | 11:8c1d44595620 | 191 | } |
humlet | 11:8c1d44595620 | 192 | |
humlet | 14:352609d395c1 | 193 | // just wait for a generic i2c interrupt |
humlet | 12:6ddadcbbdca2 | 194 | static inline void i2cRtos_waitSI(i2c_t *obj, uint32_t tmOut) |
humlet | 12:6ddadcbbdca2 | 195 | { |
humlet | 11:8c1d44595620 | 196 | int ch = i2c_get_channel(obj); |
humlet | 11:8c1d44595620 | 197 | i2c_transfer[ch].cmd = waitSI; |
humlet | 11:8c1d44595620 | 198 | i2cRtos_wait_and_see(obj, ch, tmOut); |
humlet | 9:65aae53a34de | 199 | } |
humlet | 9:65aae53a34de | 200 | |
humlet | 14:352609d395c1 | 201 | // master mode read sequence |
humlet | 9:65aae53a34de | 202 | int i2cRtos_read(i2c_t *obj, int address, char *data, int length, int stop) |
humlet | 9:65aae53a34de | 203 | { |
humlet | 12:6ddadcbbdca2 | 204 | //gpio_write(&gpio[1], 1); |
humlet | 11:8c1d44595620 | 205 | int stat = i2c_start(obj); |
humlet | 11:8c1d44595620 | 206 | if ((stat != 0x10) && (stat != 0x08)) { |
humlet | 14:352609d395c1 | 207 | i2cRtos_stop(obj); // use freeze free stop if the start has failed |
humlet | 11:8c1d44595620 | 208 | return stat; |
humlet | 9:65aae53a34de | 209 | } |
humlet | 12:6ddadcbbdca2 | 210 | //gpio_write(&gpio[1], 0); |
humlet | 9:65aae53a34de | 211 | int ch = i2c_get_channel(obj); |
humlet | 14:352609d395c1 | 212 | struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); |
humlet | 9:65aae53a34de | 213 | tr->obj=obj; |
humlet | 9:65aae53a34de | 214 | tr->cmd=readMst; |
humlet | 9:65aae53a34de | 215 | tr->len=length; |
humlet | 9:65aae53a34de | 216 | tr->cnt=-1; |
humlet | 9:65aae53a34de | 217 | tr->rData=data; |
humlet | 14:352609d395c1 | 218 | I2C_DAT(obj) = address | 0x01; // initiate address+R write and enter isr mode |
humlet | 11:8c1d44595620 | 219 | i2cRtos_wait_and_see(obj, ch,2+(length>>2)); // timeout (2+len/4)ms |
humlet | 11:8c1d44595620 | 220 | stat = tr->stat; |
humlet | 12:6ddadcbbdca2 | 221 | //gpio_write(&gpio[1], 1); |
humlet | 14:352609d395c1 | 222 | if(stat || stop) i2cRtos_stop(obj); |
humlet | 12:6ddadcbbdca2 | 223 | //gpio_write(&gpio[1], 0); |
humlet | 11:8c1d44595620 | 224 | return stat; |
humlet | 9:65aae53a34de | 225 | } |
humlet | 9:65aae53a34de | 226 | |
humlet | 14:352609d395c1 | 227 | // master mode write sequence |
humlet | 9:65aae53a34de | 228 | int i2cRtos_write(i2c_t *obj, int address, const char *data, int length, int stop) |
humlet | 9:65aae53a34de | 229 | { |
humlet | 12:6ddadcbbdca2 | 230 | //gpio_write(&gpio[1], 1); |
humlet | 9:65aae53a34de | 231 | int status = i2c_start(obj); |
humlet | 9:65aae53a34de | 232 | if ((status != 0x10) && (status != 0x08)) { |
humlet | 14:352609d395c1 | 233 | i2cRtos_stop(obj); // use freeze free stop if the start has failed |
humlet | 9:65aae53a34de | 234 | return status; |
humlet | 9:65aae53a34de | 235 | } |
humlet | 12:6ddadcbbdca2 | 236 | //gpio_write(&gpio[1], 0); |
humlet | 9:65aae53a34de | 237 | int ch = i2c_get_channel(obj); |
humlet | 12:6ddadcbbdca2 | 238 | struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? |
humlet | 12:6ddadcbbdca2 | 239 | tr->obj = obj; |
humlet | 12:6ddadcbbdca2 | 240 | tr->cmd = writeMst; |
humlet | 12:6ddadcbbdca2 | 241 | tr->len = length; |
humlet | 12:6ddadcbbdca2 | 242 | tr->cnt = -1; |
humlet | 12:6ddadcbbdca2 | 243 | tr->wData = data; |
humlet | 14:352609d395c1 | 244 | I2C_DAT(obj) = address & 0xfe; // initiate address+W write and enter isr mode |
humlet | 11:8c1d44595620 | 245 | i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (2+len/4)ms |
humlet | 12:6ddadcbbdca2 | 246 | //i2c_clear_SI(obj); // ... why? Also in official lib ... I guess this is the "write instead of start" bug |
humlet | 9:65aae53a34de | 247 | status = tr->stat; |
humlet | 12:6ddadcbbdca2 | 248 | //gpio_write(&gpio[1], 1); |
humlet | 14:352609d395c1 | 249 | if(status || stop) i2cRtos_stop(obj); |
humlet | 12:6ddadcbbdca2 | 250 | //gpio_write(&gpio[1], 0); |
humlet | 9:65aae53a34de | 251 | return status; |
humlet | 9:65aae53a34de | 252 | } |
humlet | 9:65aae53a34de | 253 | |
humlet | 14:352609d395c1 | 254 | // read single byte from bus (master/slave) |
humlet | 9:65aae53a34de | 255 | int i2cRtos_byte_read(i2c_t *obj, int last) |
humlet | 9:65aae53a34de | 256 | { |
humlet | 9:65aae53a34de | 257 | if(last) { |
humlet | 9:65aae53a34de | 258 | i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK |
humlet | 9:65aae53a34de | 259 | } else { |
humlet | 9:65aae53a34de | 260 | i2c_conset(obj, 0, 0, 0, 1); // send a ACK |
humlet | 9:65aae53a34de | 261 | } |
humlet | 11:8c1d44595620 | 262 | i2cRtos_waitSI(obj, 2); |
humlet | 9:65aae53a34de | 263 | return (I2C_DAT(obj) & 0xff); |
humlet | 9:65aae53a34de | 264 | } |
humlet | 9:65aae53a34de | 265 | |
humlet | 14:352609d395c1 | 266 | // write single byte to bus (master/slave) |
humlet | 9:65aae53a34de | 267 | int i2cRtos_byte_write(i2c_t *obj, int data) |
humlet | 9:65aae53a34de | 268 | { |
humlet | 9:65aae53a34de | 269 | I2C_DAT(obj) = (data & 0xff); |
humlet | 11:8c1d44595620 | 270 | i2cRtos_waitSI(obj, 2); |
humlet | 9:65aae53a34de | 271 | int stat=i2c_status(obj); |
humlet | 9:65aae53a34de | 272 | return (stat==0x18 || stat==0x28 || stat==0x40 || stat==0xb8); |
humlet | 9:65aae53a34de | 273 | } |
humlet | 9:65aae53a34de | 274 | |
humlet | 14:352609d395c1 | 275 | // freeze free i2c stop |
humlet | 14:352609d395c1 | 276 | // the busy wait without timeout of the official i2c lib |
humlet | 14:352609d395c1 | 277 | // might freeze the mbed if someone on the bus keeps the clock down |
humlet | 14:352609d395c1 | 278 | // and prevents LPC's i2c controller to create a stop condition |
humlet | 14:352609d395c1 | 279 | int i2cRtos_stop(i2c_t *obj) |
humlet | 14:352609d395c1 | 280 | { |
humlet | 13:530968937ccb | 281 | i2c_conset(obj, 0, 1, 0, 0); |
humlet | 13:530968937ccb | 282 | i2c_clear_SI(obj); |
humlet | 13:530968937ccb | 283 | uint32_t t0=us_ticker_read(); |
humlet | 13:530968937ccb | 284 | uint32_t dt=0; |
humlet | 14:352609d395c1 | 285 | while((I2C_CONSET(obj) & (1 << 4)) && dt<23) { |
humlet | 13:530968937ccb | 286 | dt = us_ticker_read() - t0; |
humlet | 13:530968937ccb | 287 | } |
humlet | 13:530968937ccb | 288 | return dt<23; |
humlet | 13:530968937ccb | 289 | } |
humlet | 13:530968937ccb | 290 | |
humlet | 13:530968937ccb | 291 | |
humlet | 9:65aae53a34de | 292 | #if DEVICE_I2CSLAVE |
humlet | 9:65aae53a34de | 293 | |
humlet | 14:352609d395c1 | 294 | // determine slave's receive mode. Blocking with timeout |
humlet | 9:65aae53a34de | 295 | int i2cRtos_slave_receive(i2c_t *obj, uint32_t tmOut) |
humlet | 9:65aae53a34de | 296 | { |
humlet | 9:65aae53a34de | 297 | int retval = i2c_slave_receive(obj); |
humlet | 9:65aae53a34de | 298 | //check for pending requests |
humlet | 9:65aae53a34de | 299 | if(retval)return retval; // there is one => bail out |
humlet | 14:352609d395c1 | 300 | // No request? Wait for it! ... with time out |
humlet | 11:8c1d44595620 | 301 | i2cRtos_waitSI(obj, tmOut); |
humlet | 9:65aae53a34de | 302 | // check again for pending requests |
humlet | 9:65aae53a34de | 303 | return i2c_slave_receive(obj); |
humlet | 9:65aae53a34de | 304 | } |
humlet | 9:65aae53a34de | 305 | |
humlet | 14:352609d395c1 | 306 | // slave mode read sequence |
humlet | 9:65aae53a34de | 307 | int i2cRtos_slave_read(i2c_t *obj, char *data, int length) |
humlet | 9:65aae53a34de | 308 | { |
humlet | 9:65aae53a34de | 309 | int ch = i2c_get_channel(obj); |
humlet | 12:6ddadcbbdca2 | 310 | struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? |
humlet | 9:65aae53a34de | 311 | tr->obj=obj; |
humlet | 9:65aae53a34de | 312 | tr->cmd=readSlv; |
humlet | 9:65aae53a34de | 313 | tr->len=length; |
humlet | 9:65aae53a34de | 314 | tr->cnt=-1; |
humlet | 9:65aae53a34de | 315 | tr->rData=data; |
humlet | 10:e3d6c92ff222 | 316 | i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms |
humlet | 9:65aae53a34de | 317 | if(tr->stat != 0xa0) { |
humlet | 14:352609d395c1 | 318 | i2cRtos_stop(obj); |
humlet | 9:65aae53a34de | 319 | } |
humlet | 14:352609d395c1 | 320 | i2c_clear_SI(obj); // stop keeping scl low |
humlet | 9:65aae53a34de | 321 | return tr->cnt; // same weird return as in official lib |
humlet | 9:65aae53a34de | 322 | } |
humlet | 9:65aae53a34de | 323 | |
humlet | 14:352609d395c1 | 324 | // slave mode write sequence |
humlet | 9:65aae53a34de | 325 | int i2cRtos_slave_write(i2c_t *obj, const char *data, int length) |
humlet | 9:65aae53a34de | 326 | { |
humlet | 9:65aae53a34de | 327 | if(length <= 0) { |
humlet | 9:65aae53a34de | 328 | return(0); |
humlet | 9:65aae53a34de | 329 | } |
humlet | 9:65aae53a34de | 330 | int ch = i2c_get_channel(obj); |
humlet | 12:6ddadcbbdca2 | 331 | struct I2cIsrTransfer* tr = &(i2c_transfer[ch]); // evilive fill it locally and then copy it in one go to (volatile) mem? |
humlet | 9:65aae53a34de | 332 | tr->obj=obj; |
humlet | 9:65aae53a34de | 333 | tr->cmd=writeSlv; |
humlet | 9:65aae53a34de | 334 | tr->len=length; |
humlet | 9:65aae53a34de | 335 | tr->cnt=0; |
humlet | 9:65aae53a34de | 336 | tr->wData=data; |
humlet | 9:65aae53a34de | 337 | I2C_DAT(obj) = data[0]; |
humlet | 11:8c1d44595620 | 338 | i2cRtos_wait_and_see(obj, ch, 2+(length>>2)); // timeout (1+len/4)ms |
humlet | 9:65aae53a34de | 339 | int status = tr->stat; |
humlet | 9:65aae53a34de | 340 | if(status!=0xC0 && status!=0xC8) { |
humlet | 14:352609d395c1 | 341 | i2cRtos_stop(obj); |
humlet | 9:65aae53a34de | 342 | } |
humlet | 14:352609d395c1 | 343 | i2c_clear_SI(obj); // stops keeping scl low |
humlet | 9:65aae53a34de | 344 | return tr->cnt; |
humlet | 9:65aae53a34de | 345 | } |
humlet | 14:352609d395c1 | 346 | #endif |
humlet | 11:8c1d44595620 | 347 | |
humlet | 11:8c1d44595620 | 348 | // setup semaphores and hook in ISRs |
humlet | 11:8c1d44595620 | 349 | void i2cRtos_init(i2c_t *obj, PinName sda, PinName scl) |
humlet | 11:8c1d44595620 | 350 | { |
humlet | 14:352609d395c1 | 351 | /*static int called=0; |
humlet | 11:8c1d44595620 | 352 | if(!called) { |
humlet | 11:8c1d44595620 | 353 | gpio_init(&gpio[0], p15, PIN_OUTPUT); |
humlet | 11:8c1d44595620 | 354 | gpio_init(&gpio[1], p16, PIN_OUTPUT); |
humlet | 11:8c1d44595620 | 355 | } |
humlet | 11:8c1d44595620 | 356 | called = 1; |
humlet | 11:8c1d44595620 | 357 | gpio_write(&gpio[0], 0); |
humlet | 14:352609d395c1 | 358 | gpio_write(&gpio[1], 0);*/ |
humlet | 13:530968937ccb | 359 | |
humlet | 11:8c1d44595620 | 360 | i2c_init(obj,sda,scl); |
humlet | 11:8c1d44595620 | 361 | uint32_t ch = i2c_get_channel(obj); |
humlet | 11:8c1d44595620 | 362 | #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) |
humlet | 11:8c1d44595620 | 363 | static osSemaphoreDef(i2cIsrDrvSem_ch0); |
humlet | 11:8c1d44595620 | 364 | static osSemaphoreDef(i2cIsrDrvSem_ch1); |
humlet | 11:8c1d44595620 | 365 | switch(ch) { |
humlet | 11:8c1d44595620 | 366 | case 0: |
humlet | 11:8c1d44595620 | 367 | isrIrqSem[ch].irq = I2C1_IRQn; |
humlet | 11:8c1d44595620 | 368 | NVIC_SetVector(I2C1_IRQn, (uint32_t)i2cRtos_isr_ch0); |
humlet | 11:8c1d44595620 | 369 | isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch0), 1); |
humlet | 11:8c1d44595620 | 370 | break; |
humlet | 11:8c1d44595620 | 371 | case 1: |
humlet | 11:8c1d44595620 | 372 | isrIrqSem[ch].irq = I2C2_IRQn; |
humlet | 11:8c1d44595620 | 373 | NVIC_SetVector(I2C2_IRQn, (uint32_t)i2cRtos_isr_ch1); |
humlet | 11:8c1d44595620 | 374 | isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); |
humlet | 11:8c1d44595620 | 375 | break; |
humlet | 11:8c1d44595620 | 376 | } |
humlet | 11:8c1d44595620 | 377 | osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); |
humlet | 11:8c1d44595620 | 378 | #elif defined(TARGET_LPC11U24) |
humlet | 11:8c1d44595620 | 379 | static osSemaphoreDef(i2cIsrDrvSem_ch1); |
humlet | 11:8c1d44595620 | 380 | isrIrqSem[ch].irq = I2C_IRQn; |
humlet | 11:8c1d44595620 | 381 | NVIC_SetVector(I2C_IRQn, (uint32_t)i2cRtos_isr_ch1); |
humlet | 11:8c1d44595620 | 382 | isrIrqSem[ch].sem = osSemaphoreCreate(osSemaphore(i2cIsrDrvSem_ch1), 1); |
humlet | 11:8c1d44595620 | 383 | osSemaphoreWait(isrIrqSem[ch].sem, osWaitForever); |
humlet | 11:8c1d44595620 | 384 | #else |
humlet | 11:8c1d44595620 | 385 | #error "Dial911 i2cRtos_init: Unsupported HW" |
humlet | 11:8c1d44595620 | 386 | #endif |
humlet | 11:8c1d44595620 | 387 | } |
humlet | 9:65aae53a34de | 388 | #endif |