]> git.gir.st - tmk_keyboard.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
[tmk_keyboard.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 }
Imprint / Impressum