]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/i2c_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NORDIC / TARGET_MCU_NRF51822 / i2c_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2013 Nordic Semiconductor
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "mbed_assert.h"
17 #include "i2c_api.h"
18 #include "cmsis.h"
19 #include "pinmap.h"
20 #include "mbed_error.h"
21
22 // nRF51822's I2C_0 and SPI_0 (I2C_1, SPI_1 and SPIS1) share the same address.
23 // They can't be used at the same time. So we use two global variable to track the usage.
24 // See nRF51822 address information at nRF51822_PS v2.0.pdf - Table 15 Peripheral instance reference
25 volatile i2c_spi_peripheral_t i2c0_spi0_peripheral = {0, 0, 0, 0};
26 volatile i2c_spi_peripheral_t i2c1_spi1_peripheral = {0, 0, 0, 0};
27
28 void i2c_interface_enable(i2c_t *obj)
29 {
30     obj->i2c->ENABLE = (TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos);
31 }
32
33 void twi_master_init(i2c_t *obj, PinName sda, PinName scl, int frequency)
34 {
35     NRF_GPIO->PIN_CNF[scl] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
36                               (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
37                               (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
38                               (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
39                               (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
40
41     NRF_GPIO->PIN_CNF[sda] = ((GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
42                               (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
43                               (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
44                               (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
45                               (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos));
46
47     obj->i2c->PSELSCL = scl;
48     obj->i2c->PSELSDA = sda;
49     // set default frequency at 100k
50     i2c_frequency(obj, frequency);
51     i2c_interface_enable(obj);
52 }
53
54 void i2c_init(i2c_t *obj, PinName sda, PinName scl)
55 {
56     NRF_TWI_Type *i2c;
57   
58     if (i2c0_spi0_peripheral.usage == I2C_SPI_PERIPHERAL_FOR_I2C &&
59             i2c0_spi0_peripheral.sda_mosi == (uint8_t)sda &&
60             i2c0_spi0_peripheral.scl_miso == (uint8_t)scl) {
61         // The I2C with the same pins is already initialized
62         i2c = (NRF_TWI_Type *)I2C_0;
63         obj->peripheral = 0x1;
64     } else if (i2c1_spi1_peripheral.usage == I2C_SPI_PERIPHERAL_FOR_I2C &&
65             i2c1_spi1_peripheral.sda_mosi == (uint8_t)sda &&
66             i2c1_spi1_peripheral.scl_miso == (uint8_t)scl) {
67         // The I2C with the same pins is already initialized
68         i2c = (NRF_TWI_Type *)I2C_1;
69         obj->peripheral = 0x2;
70     } else if (i2c0_spi0_peripheral.usage == 0) {
71         i2c0_spi0_peripheral.usage = I2C_SPI_PERIPHERAL_FOR_I2C;
72         i2c0_spi0_peripheral.sda_mosi = (uint8_t)sda;
73         i2c0_spi0_peripheral.scl_miso = (uint8_t)scl;
74         
75         i2c = (NRF_TWI_Type *)I2C_0;
76         obj->peripheral = 0x1;
77     } else if (i2c1_spi1_peripheral.usage == 0) {
78         i2c1_spi1_peripheral.usage = I2C_SPI_PERIPHERAL_FOR_I2C;
79         i2c1_spi1_peripheral.sda_mosi = (uint8_t)sda;
80         i2c1_spi1_peripheral.scl_miso = (uint8_t)scl;
81         
82         i2c = (NRF_TWI_Type *)I2C_1;
83         obj->peripheral = 0x2;
84     } else {
85         // No available peripheral
86         error("No available I2C");
87     }
88
89     obj->i2c               = i2c;
90     obj->scl               = scl;
91     obj->sda               = sda;
92     obj->i2c->EVENTS_ERROR = 0;
93     obj->i2c->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
94     obj->i2c->POWER        = 0;
95
96     for (int i = 0; i<100; i++) {
97     }
98
99     obj->i2c->POWER = 1;
100     twi_master_init(obj, sda, scl, 100000);
101 }
102
103 void i2c_reset(i2c_t *obj)
104 {
105     obj->i2c->EVENTS_ERROR = 0;
106     obj->i2c->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
107     obj->i2c->POWER        = 0;
108     for (int i = 0; i<100; i++) {
109     }
110
111     obj->i2c->POWER = 1;
112     twi_master_init(obj, obj->sda, obj->scl, obj->freq);
113 }
114
115 int i2c_start(i2c_t *obj)
116 {
117     int status = 0;
118     i2c_reset(obj);
119     obj->address_set = 0;
120     return status;
121 }
122
123 int i2c_stop(i2c_t *obj)
124 {
125     int timeOut = 100000;
126     obj->i2c->EVENTS_STOPPED = 0;
127     // write the stop bit
128     obj->i2c->TASKS_STOP = 1;
129     while (!obj->i2c->EVENTS_STOPPED) {
130         timeOut--;
131         if (timeOut<0) {
132             return 1;
133         }
134     }
135     obj->address_set = 0;
136     i2c_reset(obj);
137     return 0;
138 }
139
140 int i2c_do_write(i2c_t *obj, int value)
141 {
142     int timeOut = 100000;
143     obj->i2c->TXD = value;
144     while (!obj->i2c->EVENTS_TXDSENT) {
145         timeOut--;
146         if (timeOut<0) {
147             return 1;
148         }
149     }
150     obj->i2c->EVENTS_TXDSENT = 0;
151     return 0;
152 }
153
154 int i2c_do_read(i2c_t *obj, char *data, int last)
155 {
156     int timeOut = 100000;
157
158     if (last) {
159         // To trigger stop task when a byte is received,
160         // must be set before resume task.
161         obj->i2c->SHORTS = 2;
162     }
163
164     obj->i2c->TASKS_RESUME = 1;
165
166     while (!obj->i2c->EVENTS_RXDREADY) {
167         timeOut--;
168         if (timeOut<0) {
169             return 1;
170         }
171     }
172     obj->i2c->EVENTS_RXDREADY = 0;
173     *data = obj->i2c->RXD;
174
175     return 0;
176 }
177
178 void i2c_frequency(i2c_t *obj, int hz)
179 {
180     if (hz<250000) {
181         obj->freq           = 100000;
182         obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos);
183     } else if (hz<400000) {
184         obj->freq           = 250000;
185         obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K250 << TWI_FREQUENCY_FREQUENCY_Pos);
186     } else {
187         obj->freq           = 400000;
188         obj->i2c->FREQUENCY = (TWI_FREQUENCY_FREQUENCY_K400 << TWI_FREQUENCY_FREQUENCY_Pos);
189     }
190 }
191
192 int checkError(i2c_t *obj)
193 {
194     if (obj->i2c->EVENTS_ERROR == 1) {
195         if (obj->i2c->ERRORSRC & TWI_ERRORSRC_ANACK_Msk) {
196             obj->i2c->EVENTS_ERROR = 0;
197             obj->i2c->TASKS_STOP   = 1;
198             return I2C_ERROR_BUS_BUSY;
199         }
200
201         obj->i2c->EVENTS_ERROR = 0;
202         obj->i2c->TASKS_STOP   = 1;
203         return I2C_ERROR_NO_SLAVE;
204     }
205     return 0;
206 }
207
208 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
209 {
210     int status, count, errorResult;
211     obj->i2c->ADDRESS         = (address >> 1);
212     obj->i2c->SHORTS          = 1;  // to trigger suspend task when a byte is received
213     obj->i2c->EVENTS_RXDREADY = 0;
214     obj->i2c->TASKS_STARTRX   = 1;
215
216     // Read in all except last byte
217     for (count = 0; count < (length - 1); count++) {
218         status = i2c_do_read(obj, &data[count], 0);
219         if (status) {
220             errorResult = checkError(obj);
221             i2c_reset(obj);
222             if (errorResult<0) {
223                 return errorResult;
224             }
225             return count;
226         }
227     }
228
229     // read in last byte
230     status = i2c_do_read(obj, &data[length - 1], 1);
231     if (status) {
232         i2c_reset(obj);
233         return length - 1;
234     }
235     // If not repeated start, send stop.
236     if (stop) {
237         while (!obj->i2c->EVENTS_STOPPED) {
238         }
239         obj->i2c->EVENTS_STOPPED = 0;
240     }
241     return length;
242 }
243
244 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
245 {
246     int status, errorResult;
247     obj->i2c->ADDRESS       = (address >> 1);
248     obj->i2c->SHORTS        = 0;
249     obj->i2c->TASKS_STARTTX = 1;
250
251     for (int i = 0; i<length; i++) {
252         status = i2c_do_write(obj, data[i]);
253         if (status) {
254             i2c_reset(obj);
255             errorResult = checkError(obj);
256             if (errorResult<0) {
257                 return errorResult;
258             }
259             return i;
260         }
261     }
262
263     // If not repeated start, send stop.
264     if (stop) {
265         if (i2c_stop(obj)) {
266             return I2C_ERROR_NO_SLAVE;
267         }
268     }
269     return length;
270 }
271
272 int i2c_byte_read(i2c_t *obj, int last)
273 {
274     char data;
275     int status;
276
277     status = i2c_do_read(obj, &data, last);
278     if (status) {
279         i2c_reset(obj);
280     }
281     return data;
282 }
283
284 int i2c_byte_write(i2c_t *obj, int data)
285 {
286     int status = 0;
287     if (!obj->address_set) {
288         obj->address_set  = 1;
289         obj->i2c->ADDRESS = (data >> 1);
290
291         if (data & 1) {
292             obj->i2c->EVENTS_RXDREADY = 0;
293             obj->i2c->SHORTS          = 1;
294             obj->i2c->TASKS_STARTRX   = 1;
295         } else {
296             obj->i2c->SHORTS        = 0;
297             obj->i2c->TASKS_STARTTX = 1;
298         }
299     } else {
300         status = i2c_do_write(obj, data);
301         if (status) {
302             i2c_reset(obj);
303         }
304     }
305     return (1 - status);
306 }