Skip to content

Commit 5e01b52

Browse files
Merge pull request #18 from microbit-foundation/i2c-target
Update configure and add example if I2C Target operation
2 parents 6527072 + adf4801 commit 5e01b52

File tree

3 files changed

+313
-18
lines changed

3 files changed

+313
-18
lines changed

TARGET_NRF52_MICROBIT_V2/PinNames.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,13 @@ typedef enum {
270270
#endif
271271

272272
#if defined(TARGET_NRF52_MICROBIT_V2_IF_833)
273-
// TODO: Include the internal I2C pins
273+
// Internal I2C
274+
I2C_SDA0 = P0_28,
275+
I2C_SCL0 = P0_29,
274276
#elif defined(TARGET_NRF52_MICROBIT_V2_IF_820)
275-
// TODO: Include the internal I2C pins
277+
// Internal I2C
278+
I2C_SDA0 = P0_30,
279+
I2C_SCL0 = P0_28,
276280
#else
277281
// Internal I2C
278282
I2C_SDA0 = P0_16,

custom_targets.json

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,29 @@
77
"MCU_NRF52833"
88
],
99
"static_memory_defines": false,
10+
"device_has_add": [
11+
"I2CSLAVE"
12+
],
1013
"macros_add": [
14+
"NRF52833_XXAA",
15+
"TARGET_NRF52833",
1116
"TARGET_MCU_NRF52833",
17+
"NRFX_TWIS_ENABLED=1",
1218
"NRFX_RNG_ENABLED=1",
1319
"RNG_ENABLED=1",
14-
"NRF_QUEUE_ENABLED=1"
20+
"NRF_QUEUE_ENABLED=1",
21+
"NRF52_PAN_20"
1522
],
1623
"features_remove": [
1724
"CRYPTOCELL310"
1825
],
26+
"device_has_remove": [
27+
"QSPI",
28+
"I2C_ASYNCH"
29+
],
30+
"components_remove": [
31+
"QSPIF"
32+
],
1933
"macros_remove": [
2034
"MBEDTLS_CONFIG_HW_SUPPORT"
2135
]
@@ -33,20 +47,6 @@
3347
"inherits": ["MCU_NRF52833"],
3448
"macros_add": [
3549
"WSF_MAX_HANDLERS=10",
36-
"NRF52_PAN_12",
37-
"NRF52_PAN_15",
38-
"NRF52_PAN_20",
39-
"NRF52_PAN_30",
40-
"NRF52_PAN_31",
41-
"NRF52_PAN_36",
42-
"NRF52_PAN_51",
43-
"NRF52_PAN_53",
44-
"NRF52_PAN_54",
45-
"NRF52_PAN_55",
46-
"NRF52_PAN_58",
47-
"NRF52_PAN_62",
48-
"NRF52_PAN_63",
49-
"NRF52_PAN_64",
5050
"CONFIG_NFCT_PINS_AS_GPIOS",
5151
"MICROBIT_TARGET"
5252
],
@@ -72,8 +72,14 @@
7272
},
7373
"NRF52_MICROBIT_V2_IF_820": {
7474
"inherits": ["NRF52_MICROBIT_V2"],
75-
"core": "Cortex-M4",
75+
"device_has_remove": [
76+
"ANALOGIN",
77+
"PWMOUT"
78+
],
7679
"extra_labels_remove": [
80+
"CORDIO",
81+
"CORDIO_LL",
82+
"NORDIC_CORDIO"
7783
],
7884
"macros_add": [
7985
"MICROBIT_IF"

examples/i2c_target_controller.cpp

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*
2+
* Copyright 2022 Micro:bit Educational Foundation and contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
/**
18+
* Programme Description
19+
* ---------------------
20+
*
21+
* This is an single I2C programme, which is compiled twice, to exemplify
22+
* I2C communication between an I2C controller and I2C target.
23+
*
24+
* As the micro:bit V2.20 has an nRF52 Interface MCU connected to the internal
25+
* I2C bus controlled by the Target nRF52 MCU, this project has been configured
26+
* to be run with a single micro:bit and compiled for two Mbed targets:
27+
* - `nrf52_microbit_v2`: This will be the I2C Controller programme running
28+
* in the Target MCU.
29+
* - `nrf52_microbit_v2_if_833`: This will be the I2C Target programme running
30+
* in the Interface MCU.
31+
*
32+
*
33+
* Instructions
34+
* ------------
35+
*
36+
* As it currently stands, this example can only be run with a micro:bit V2.2.
37+
*
38+
* - First build the I2C Controller programme
39+
* $ mbed compile -m nrf52_microbit_v2
40+
* - Flash the I2C Controller hex file into the MICROBIT drive.
41+
* - Then build the I2C Target programme:
42+
* $ mbed compile -m nrf52_microbit_v2_if_833
43+
* - Enter MAITENANCE mode by unplugging the USB cable and pressing the reset
44+
* button while reattaching the USB cable.
45+
* - And flash the I2C Target hex file into the MAINTENANCE drive.
46+
* - At the end, to restore the MICROBIT drive flash a "Firmware" hex file
47+
* to the MAITNENANCE drive as indicated in https://microbit.org/firmware
48+
*
49+
* Now both programmes should be running on the same micro:bit V2.2.
50+
*
51+
* When power is applied to the board these LEDs will flash twice:
52+
* - The USB orange and the USB red LEDs
53+
* - These two LEDs are controlled by the Interface MCU as the I2C Target
54+
* - The LED matrix LEDs (0,0) and (1,0)
55+
* - The LED matrix is controlled by the Target MCU as the I2C Controller
56+
*
57+
* Then the USB orange LED will stay ON, that means the I2C Target is awaiting.
58+
* And the LED (0,0) in the matrix will be flashing, this means the I2C
59+
* Controller is awaiting for user input before starting to run.
60+
*
61+
* Press button A to start executing I2C write and read transaction.
62+
* Now the USB orange LED and LED (0,0) in the matrix should be steady ON.
63+
*
64+
* As the transactions complete successful LED (1,0) in the matrix and the
65+
* USB red LED will be flashing. This indicates both programmes are running
66+
* successfully.
67+
*
68+
* If an error is encountered both LEDs for both microcontrollers will start
69+
* flashing.
70+
*
71+
*
72+
* Using two micro:bits instead of a single V2.2 micro:bit
73+
* -------------------------------------------------------
74+
*
75+
* This programme can be adapted to be used with two micro:bits V2 (including
76+
* V2.00, which does not have an nRF52 Interface MCU) and to use the external
77+
* I2C bus accessible via the edge connector instead of the internal bus.
78+
*
79+
* To do this you'll need to build twice for the `nrf52_microbit_v2` target
80+
* and manually change the `#define BUILD_I2C_CONTROLLER` line to
81+
* `#define BUILD_I2C_TARGET` for the second build.
82+
* Every `I2C_SDA0` and `I2C_SCL0` instance must also be changed to `I2C_SDA1`
83+
* and `I2C_SCL1` to select the external I2C bus.
84+
*
85+
* This has been tested with a micro:bit V2.00 and V2.20 connected via jumper
86+
* cables (pins 19, 20, and ground) and works.
87+
* ***************************************************************************/
88+
#include "mbed.h"
89+
90+
/*****************************************************************************/
91+
/* Define roles */
92+
/*****************************************************************************/
93+
#if defined(MICROBIT_TARGET)
94+
#define BUILD_I2C_CONTROLLER
95+
#elif defined(MICROBIT_IF)
96+
#define BUILD_I2C_TARGET
97+
#endif
98+
99+
/*****************************************************************************/
100+
/* I2C data to send between devices */
101+
/*****************************************************************************/
102+
#define I2C_ADDR_8BIT_ (0x2E << 1)
103+
char MSG_CONTROLLER_TO_TARGET[] = "Hello world!";
104+
const uint8_t MSG_C2T_LEN = 13;
105+
char MSG_TARGET_TO_CONTROLLER[] = "Hi back!";
106+
const uint8_t MSG_T2C_LEN = 9;
107+
108+
#if defined(BUILD_I2C_CONTROLLER)
109+
#define test_i2c test_controller
110+
#elif defined(BUILD_I2C_TARGET)
111+
#define test_i2c test_target
112+
#endif
113+
114+
/*****************************************************************************/
115+
/* Serial */
116+
/*****************************************************************************/
117+
#ifdef MICROBIT_TARGET
118+
UnbufferedSerial pc(CONSOLE_TX, CONSOLE_RX, 115200);
119+
120+
FileHandle *mbed::mbed_override_console(int fd) {
121+
return &pc;
122+
}
123+
#endif
124+
125+
/*****************************************************************************/
126+
/* LEDs & Buttons */
127+
/*****************************************************************************/
128+
#define BUTTON_PRESSED 0
129+
#ifdef MICROBIT_TARGET
130+
DigitalOut col1(COL_1, 0);
131+
DigitalOut led1(ROW_1, 0);
132+
DigitalOut led2(ROW_2, 0);
133+
#else
134+
DigitalOut led1(LED1, 0);
135+
DigitalOut led2(LED2, 0);
136+
#endif
137+
138+
/*****************************************************************************/
139+
/* I2C functions */
140+
/*****************************************************************************/
141+
uint8_t test_controller() {
142+
printf("I2C Controller test running...\n");
143+
144+
I2C controller(I2C_SDA0, I2C_SCL0);
145+
146+
uint8_t error_return = 0;
147+
int i2c_error = 0;
148+
while (true) {
149+
i2c_error = controller.write(
150+
I2C_ADDR_8BIT_, MSG_CONTROLLER_TO_TARGET, MSG_C2T_LEN, false
151+
);
152+
if (i2c_error) {
153+
printf("Error: I2C write (tx): %d\n", i2c_error);
154+
error_return |= 1 << 0;
155+
} else {
156+
printf("I2C write, TX data: %s\n", MSG_CONTROLLER_TO_TARGET);
157+
}
158+
159+
led2 = !led2;
160+
wait_us(250 * 1000);
161+
162+
char rx_data[MSG_T2C_LEN] = { 0 };
163+
i2c_error = controller.read(I2C_ADDR_8BIT_, &rx_data[0], MSG_T2C_LEN, false);
164+
if (i2c_error) {
165+
printf("Error: I2C read (rx): %d\n", i2c_error);
166+
error_return |= 1 << 1;
167+
} else {
168+
printf("I2C read, rx data: %s\n", rx_data);
169+
for (int i = 0; i < MSG_T2C_LEN; i++) {
170+
if (rx_data[i] != MSG_TARGET_TO_CONTROLLER[i]) {
171+
printf("Message unexpected at chacter %d\n", i);
172+
error_return |= 1 << 2;
173+
break;
174+
}
175+
}
176+
}
177+
178+
led2 = !led2;
179+
wait_us(250 * 1000);
180+
181+
if (error_return) {
182+
return error_return;
183+
}
184+
}
185+
}
186+
187+
uint8_t test_target() {
188+
printf("I2C Target test running...\n");
189+
190+
I2CSlave target(I2C_SDA0, I2C_SCL0);
191+
target.address(I2C_ADDR_8BIT_);
192+
193+
int error = 0;
194+
while (true) {
195+
int status = target.receive();
196+
switch (status) {
197+
case I2CSlave::ReadAddressed:
198+
led2 = !led2;
199+
error = target.write(MSG_TARGET_TO_CONTROLLER, MSG_T2C_LEN);
200+
if (error) {
201+
printf("Error: I2C read (tx): %d\n", error);
202+
return 1;
203+
}
204+
printf("I2C read, TX data: %s\n", MSG_TARGET_TO_CONTROLLER);
205+
break;
206+
case I2CSlave::WriteGeneral:
207+
case I2CSlave::WriteAddressed:
208+
led2 = !led2;
209+
char rx_buf[MSG_C2T_LEN] = { 0 };
210+
error = target.read(rx_buf, MSG_C2T_LEN);
211+
if (error) {
212+
printf("Error: I2C write (rx): %d\n", error);
213+
return 2;
214+
}
215+
printf("I2C write, RX data: %s\n", rx_buf);
216+
for (int i = 0; i < MSG_C2T_LEN; i++) {
217+
if (rx_buf[i] != MSG_CONTROLLER_TO_TARGET[i]) {
218+
printf("Error: Message unexpected at chacter %d\n", i);
219+
return 3;
220+
}
221+
}
222+
target.stop();
223+
break;
224+
}
225+
}
226+
return 0;
227+
}
228+
229+
/*****************************************************************************/
230+
/* main */
231+
/*****************************************************************************/
232+
int main(void) {
233+
uint8_t error_code = 0;
234+
DigitalIn button(BUTTON1);
235+
236+
printf("I2C programme starting.\r\n");
237+
238+
// Blink the two LEDs twice show the programme is running
239+
for (int i = 0; i < 4; i++) {
240+
led1 = !led1;
241+
led2 = !led2;
242+
wait_us(250 * 1000);
243+
}
244+
245+
while (true) {
246+
#ifdef BUILD_I2C_CONTROLLER
247+
// If this is the I2C controller wait (blinking) until a button press
248+
if (button != BUTTON_PRESSED)
249+
{
250+
led1 = !led1;
251+
wait_us(500 * 1000);
252+
}
253+
else
254+
#endif
255+
{
256+
led1 = true;
257+
error_code = test_i2c();
258+
break;
259+
}
260+
}
261+
262+
// Reaching this point indicates an error indicated in the flashing LEDs
263+
printf("Error code %d detected :(\n", error_code);
264+
while (true) {
265+
// First toggle the two LEDs alternatively and stop for a second
266+
for (int i = 0; i < 3; i++) {
267+
led1 = true;
268+
led2 = false;
269+
wait_us(250 * 1000);
270+
led1 = false;
271+
led2 = true;
272+
wait_us(250 * 1000);
273+
}
274+
led1 = false;
275+
led2 = false;
276+
wait_us(1000 * 1000);
277+
// Then flash both LEDs as many times as indicated by the error code
278+
for (int i = 0; i < (error_code * 2); i++) {
279+
led1 = !led1;
280+
led2 = !led2;
281+
wait_us(500 * 1000);
282+
}
283+
wait_us(500 * 1000);
284+
}
285+
}

0 commit comments

Comments
 (0)