Skip to content

Commit 05a088b

Browse files
authored
Merge pull request #972 from arturo182/nrf_i2c
nrf: Rewrite the I2C common-hal using nrfx
2 parents 923ef3d + 178c089 commit 05a088b

File tree

4 files changed

+107
-134
lines changed

4 files changed

+107
-134
lines changed

ports/nrf/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ SRC_HAL = $(addprefix hal/,\
9797

9898
SRC_NRFX = $(addprefix nrfx/,\
9999
drivers/src/nrfx_spim.c \
100+
drivers/src/nrfx_twim.c \
100101
)
101102

102103
SRC_C += \

ports/nrf/common-hal/busio/I2C.c

Lines changed: 93 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*
66
* Copyright (c) 2016 Sandeep Mistry All right reserved.
77
* Copyright (c) 2017 hathach
8+
* Copyright (c) 2018 Artur Pacholec
89
*
910
* Permission is hereby granted, free of charge, to any person obtaining a copy
1011
* of this software and associated documentation files (the "Software"), to deal
@@ -29,67 +30,103 @@
2930
#include "py/mperrno.h"
3031
#include "py/runtime.h"
3132

32-
#include "pins.h"
33-
#include "nrf.h"
33+
#include "nrfx_twim.h"
34+
#include "nrf_gpio.h"
35+
36+
#define INST_NO 0
37+
38+
static uint8_t twi_error_to_mp(const nrfx_err_t err) {
39+
switch (err) {
40+
case NRFX_ERROR_DRV_TWI_ERR_ANACK:
41+
return MP_ENODEV;
42+
case NRFX_ERROR_BUSY:
43+
return MP_EBUSY;
44+
case NRFX_ERROR_DRV_TWI_ERR_DNACK:
45+
case NRFX_ERROR_INVALID_ADDR:
46+
return MP_EIO;
47+
default:
48+
break;
49+
}
50+
51+
return 0;
52+
}
3453

35-
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout ) {
36-
if (scl->pin == sda->pin) {
54+
void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) {
55+
if (scl->pin == sda->pin)
3756
mp_raise_ValueError("Invalid pins");
38-
}
3957

40-
NRF_GPIO->PIN_CNF[scl->pin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
41-
| ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
42-
| ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
43-
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
44-
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
45-
46-
NRF_GPIO->PIN_CNF[sda->pin] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
47-
| ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
48-
| ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
49-
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
50-
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
51-
52-
// 1 for I2C, 0 for SPI
53-
self->twi = NRF_TWIM1;
54-
55-
if ( frequency < 100000 ) {
56-
self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100;
57-
}else if ( frequency < 250000 ) {
58-
self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K250;
59-
}else {
60-
self->twi->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400;
58+
const nrfx_twim_t instance = NRFX_TWIM_INSTANCE(INST_NO);
59+
self->twim = instance;
60+
61+
nrfx_twim_config_t config = NRFX_TWIM_DEFAULT_CONFIG;
62+
config.scl = NRF_GPIO_PIN_MAP(scl->port, scl->pin);
63+
config.sda = NRF_GPIO_PIN_MAP(sda->port, sda->pin);
64+
65+
// change freq. only if it's less than the default 400K
66+
if (frequency < 100000) {
67+
config.frequency = NRF_TWIM_FREQ_100K;
68+
} else if (frequency < 250000) {
69+
config.frequency = NRF_TWIM_FREQ_250K;
6170
}
6271

63-
self->twi->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos);
72+
nrfx_err_t err = nrfx_twim_init(&self->twim, &config, NULL, NULL);
73+
74+
// A soft reset doesn't uninit the driver so we might end up with a invalid state
75+
if (err == NRFX_ERROR_INVALID_STATE) {
76+
nrfx_twim_uninit(&self->twim);
77+
err = nrfx_twim_init(&self->twim, &config, NULL, NULL);
78+
}
6479

65-
self->twi->PSEL.SCL = scl->pin;
66-
self->twi->PSEL.SDA = sda->pin;
80+
if (err != NRFX_SUCCESS)
81+
mp_raise_OSError(MP_EIO);
6782

83+
self->inited = true;
6884
}
6985

7086
bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
71-
return self->twi->ENABLE == 0;
87+
return !self->inited;
7288
}
7389

7490
void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
75-
if (common_hal_busio_i2c_deinited(self)) {
91+
if (common_hal_busio_i2c_deinited(self))
7692
return;
77-
}
78-
79-
uint8_t scl_pin = self->twi->PSEL.SCL;
80-
uint8_t sda_pin = self->twi->PSEL.SDA;
8193

82-
self->twi->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos);
83-
self->twi->PSEL.SCL = (TWIM_PSEL_SCL_CONNECT_Disconnected << TWIM_PSEL_SCL_CONNECT_Pos);
84-
self->twi->PSEL.SDA = (TWIM_PSEL_SDA_CONNECT_Disconnected << TWIM_PSEL_SDA_CONNECT_Pos);
94+
nrfx_twim_uninit(&self->twim);
8595

86-
reset_pin(scl_pin);
87-
reset_pin(sda_pin);
96+
self->inited = false;
8897
}
8998

99+
// nrfx_twim_tx doesn't support 0-length data so we fall back to the hal API
90100
bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
91-
// Write no data when just probing
92-
return 0 == common_hal_busio_i2c_write(self, addr, NULL, 0, true);
101+
NRF_TWIM_Type *reg = self->twim.p_twim;
102+
bool found = true;
103+
104+
nrfx_twim_enable(&self->twim);
105+
106+
nrf_twim_address_set(reg, addr);
107+
nrf_twim_tx_buffer_set(reg, NULL, 0);
108+
109+
nrf_twim_task_trigger(reg, NRF_TWIM_TASK_RESUME);
110+
111+
nrf_twim_task_trigger(reg, NRF_TWIM_TASK_STARTTX);
112+
while (nrf_twim_event_check(reg, NRF_TWIM_EVENT_TXSTARTED) == 0 &&
113+
nrf_twim_event_check(reg, NRF_TWIM_EVENT_ERROR) == 0);
114+
nrf_twim_event_clear(reg, NRF_TWIM_EVENT_TXSTARTED);
115+
116+
nrf_twim_task_trigger(reg, NRF_TWIM_TASK_STOP);
117+
while (nrf_twim_event_check(reg, NRF_TWIM_EVENT_STOPPED) == 0);
118+
nrf_twim_event_clear(reg, NRF_TWIM_EVENT_STOPPED);
119+
120+
if (nrf_twim_event_check(reg, NRF_TWIM_EVENT_ERROR)) {
121+
nrf_twim_event_clear(reg, NRF_TWIM_EVENT_ERROR);
122+
123+
nrf_twim_errorsrc_get_and_clear(reg);
124+
found = false;
125+
}
126+
127+
nrfx_twim_disable(&self->twim);
128+
129+
return found;
93130
}
94131

95132
bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) {
@@ -112,96 +149,23 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) {
112149
}
113150

114151
uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) {
115-
NRF_TWIM_Type* twi = self->twi;
116-
117-
twi->ADDRESS = addr;
118-
twi->TASKS_RESUME = 1;
119-
120-
twi->TXD.PTR = (uint32_t) data;
121-
twi->TXD.MAXCNT = len;
122-
123-
twi->TASKS_STARTTX = 1;
124-
125-
// Wait for TX started
126-
while(!twi->EVENTS_TXSTARTED && !twi->EVENTS_ERROR) {}
127-
twi->EVENTS_TXSTARTED = 0;
128-
129-
// Wait for TX complete
130-
if ( len )
131-
{
132-
while(!twi->EVENTS_LASTTX && !twi->EVENTS_ERROR) {}
133-
twi->EVENTS_LASTTX = 0x0UL;
134-
}
135-
136-
if (stopBit || twi->EVENTS_ERROR)
137-
{
138-
twi->TASKS_STOP = 0x1UL;
139-
while(!twi->EVENTS_STOPPED);
140-
twi->EVENTS_STOPPED = 0x0UL;
141-
}
142-
else
143-
{
144-
twi->TASKS_SUSPEND = 0x1UL;
145-
while(!twi->EVENTS_SUSPENDED);
146-
twi->EVENTS_SUSPENDED = 0x0UL;
147-
}
148-
149-
if (twi->EVENTS_ERROR)
150-
{
151-
twi->EVENTS_ERROR = 0x0UL;
152-
uint32_t error = twi->ERRORSRC;
153-
twi->ERRORSRC = error;
154-
155-
return error;
156-
}
157-
158-
return 0;
159-
}
160-
161-
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) {
162-
NRF_TWIM_Type* twi = self->twi;
163-
164-
if(len == 0) return 0;
165-
bool stopBit = true; // should be a parameter
152+
if(len == 0)
153+
return common_hal_busio_i2c_probe(self, addr) ? 0 : MP_ENODEV;
166154

167-
twi->ADDRESS = addr;
168-
twi->TASKS_RESUME = 0x1UL;
155+
nrfx_twim_enable(&self->twim);
156+
const nrfx_err_t err = nrfx_twim_tx(&self->twim, addr, data, len, !stopBit);
157+
nrfx_twim_disable(&self->twim);
169158

170-
twi->RXD.PTR = (uint32_t) data;
171-
twi->RXD.MAXCNT = len;
172-
173-
twi->TASKS_STARTRX = 0x1UL;
174-
175-
while(!twi->EVENTS_RXSTARTED && !twi->EVENTS_ERROR);
176-
twi->EVENTS_RXSTARTED = 0x0UL;
177-
178-
while(!twi->EVENTS_LASTRX && !twi->EVENTS_ERROR);
179-
twi->EVENTS_LASTRX = 0x0UL;
180-
181-
if (stopBit || twi->EVENTS_ERROR)
182-
{
183-
twi->TASKS_STOP = 0x1UL;
184-
while(!twi->EVENTS_STOPPED);
185-
twi->EVENTS_STOPPED = 0x0UL;
186-
}
187-
else
188-
{
189-
twi->TASKS_SUSPEND = 0x1UL;
190-
while(!twi->EVENTS_SUSPENDED);
191-
twi->EVENTS_SUSPENDED = 0x0UL;
192-
}
193-
194-
if (twi->EVENTS_ERROR)
195-
{
196-
twi->EVENTS_ERROR = 0x0UL;
197-
uint32_t error = twi->ERRORSRC;
198-
twi->ERRORSRC = error;
159+
return twi_error_to_mp(err);
160+
}
199161

200-
return error;
201-
}
162+
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) {
163+
if(len == 0)
164+
return 0;
202165

203-
// number of byte read
204-
// (void) _p_twim->RXD.AMOUNT;
166+
nrfx_twim_enable(&self->twim);
167+
const nrfx_err_t err = nrfx_twim_rx(&self->twim, addr, data, len);
168+
nrfx_twim_disable(&self->twim);
205169

206-
return 0;
170+
return twi_error_to_mp(err);
207171
}

ports/nrf/common-hal/busio/I2C.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,15 @@
2727
#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H
2828
#define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H
2929

30-
#include "common-hal/microcontroller/Pin.h"
31-
32-
//#include "hal/include/hal_i2c_m_sync.h"
30+
#include "nrfx_twim.h"
3331

3432
#include "py/obj.h"
3533

3634
typedef struct {
3735
mp_obj_base_t base;
38-
volatile bool has_lock;
39-
NRF_TWIM_Type* twi;
36+
nrfx_twim_t twim;
37+
bool inited;
38+
bool has_lock;
4039
} busio_i2c_obj_t;
4140

4241
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H

ports/nrf/nrfx_config.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef NRFX_CONFIG_H__
22
#define NRFX_CONFIG_H__
33

4+
// SPI
45
#define NRFX_SPIM_ENABLED 1
56

67
#ifdef NRF52840_XXAA
@@ -12,4 +13,12 @@
1213
#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 7
1314
#define NRFX_SPIM_MISO_PULL_CFG 1
1415

16+
// TWI aka. I2C
17+
#define NRFX_TWIM_ENABLED 1
18+
#define NRFX_TWIM0_ENABLED 1
19+
20+
#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY 7
21+
#define NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY NRF_TWIM_FREQ_400K
22+
#define NRFX_TWIM_DEFAULT_CONFIG_HOLD_BUS_UNINIT 0
23+
1524
#endif

0 commit comments

Comments
 (0)