Skip to content

Commit 907ae1b

Browse files
committed
Implement I2CSLAVE in the i2c_api for nRF52 targets
1 parent 85a1729 commit 907ae1b

File tree

2 files changed

+195
-29
lines changed

2 files changed

+195
-29
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/i2c_api.c

Lines changed: 189 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
#include "app_util_platform.h"
6060
#include "prs/nrfx_prs.h"
6161

62+
#if DEVICE_I2CSLAVE
63+
#include "nrfx_twis.h"
64+
#endif
65+
6266
#define TWI_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \
6367
NRF_GPIO_PIN_DIR_INPUT, \
6468
NRF_GPIO_PIN_INPUT_CONNECT, \
@@ -91,6 +95,18 @@ typedef enum {
9195
NORDIC_TWI_STATE_BUSY
9296
} nordic_nrf5_twi_state_t;
9397

98+
#if DEVICE_I2CSLAVE
99+
100+
/* To properly uninitialize the last-used driver, we need to know if
101+
* it was a master (nrfx_twi_...) or a slave (nrfx_twis_...)
102+
*/
103+
typedef enum {
104+
NORDIC_TWI_INITIALIZED_AS_MASTER,
105+
NORDIC_TWI_INITIALIZED_AS_SLAVE,
106+
NORDIC_TWI_UNINITIALIZED
107+
} nordic_nrf5_twi_slave_state_t;
108+
#endif
109+
94110
/* Forward declaration. These functions are implemented in the driver but not
95111
* set up in the NVIC due to it being relocated.
96112
*/
@@ -135,6 +151,15 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
135151
config->mask = 0;
136152
#endif
137153

154+
#if DEVICE_I2CSLAVE
155+
/** was_slave is used to decide which driver call we need
156+
* to use when uninitializing a given instance
157+
*/
158+
config->was_slave = false;
159+
config->is_slave = false;
160+
config->slave_addr = 0;
161+
#endif
162+
138163
/* Force reconfiguration */
139164
config->update = true;
140165

@@ -164,6 +189,14 @@ void i2c_frequency(i2c_t *obj, int hz)
164189
struct i2c_s *config = obj;
165190
#endif
166191

192+
193+
#if DEVICE_I2CSLAVE
194+
/* Slaves automatically get frequency from master, may be 100kHz or 400kHz */
195+
if(config->is_slave) {
196+
return;
197+
}
198+
#endif
199+
167200
/* Round down to nearest valid frequency. */
168201
nrf_twi_frequency_t new_frequency;
169202

@@ -588,6 +621,10 @@ void i2c_reset(i2c_t *obj)
588621
/* Global array holding driver configuration for easy access. */
589622
static const nrfx_twi_t nordic_nrf5_instance[2] = { NRFX_TWI_INSTANCE(0), NRFX_TWI_INSTANCE(1) };
590623

624+
#if DEVICE_I2CSLAVE
625+
static const nrfx_twis_t nordic_nrf5_twis_instance[2] = { NRFX_TWIS_INSTANCE(0), NRFX_TWIS_INSTANCE(1) };
626+
#endif
627+
591628
/* Forward declare interrupt handler. */
592629
#if DEVICE_I2C_ASYNCH
593630
static void nordic_nrf5_twi_event_handler(nrfx_twi_evt_t const *p_event, void *p_context);
@@ -632,51 +669,90 @@ static void i2c_configure_driver_instance(i2c_t *obj)
632669

633670
/* If the peripheral is already running, then disable it and use the driver API to uninitialize it.*/
634671
if (nordic_nrf5_instance[instance].p_twi->ENABLE) {
672+
#if DEVICE_I2CSLAVE
673+
/* If it was a slave, we should disable it with the appropriate driver */
674+
if(config->was_slave) {
675+
nrfx_twis_disable(&nordic_nrf5_twis_instance[instance]);
676+
nrfx_twis_uninit(&nordic_nrf5_twis_instance[instance]);
677+
}
678+
else {
635679
nrfx_twi_disable(&nordic_nrf5_instance[instance]);
636680
nrfx_twi_uninit(&nordic_nrf5_instance[instance]);
637681
}
638682

683+
#else
684+
nrfx_twi_disable(&nordic_nrf5_instance[instance]);
685+
nrfx_twi_uninit(&nordic_nrf5_instance[instance]);
686+
#endif
687+
688+
}
689+
639690
/* Force resource release. This is necessary because mbed drivers don't
640691
* deinitialize on object destruction.
641692
*/
642693
NRFX_IRQ_DISABLE((nrfx_get_irq_number((void const *)nordic_nrf5_twi_register[instance])));
643694

644-
/* Configure driver with new settings. */
645-
nrfx_twi_config_t twi_config = {
646-
.scl = config->scl,
647-
.sda = config->sda,
648-
.frequency = config->frequency,
649-
.interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
650-
.hold_bus_uninit = false
651-
};
695+
#if DEVICE_I2CSLAVE
696+
if(config->is_slave) {
697+
/* Configure driver as slave with new settings. */
698+
nrfx_twis_config_t twis_config = {
699+
.addr = { (config->slave_addr >> 1), 0 },
700+
.scl = config->scl,
701+
.sda = config->sda,
702+
.scl_pull = NRF_GPIO_PIN_NOPULL,
703+
.sda_pull = NRF_GPIO_PIN_NOPULL,
704+
.interrupt_priority = APP_IRQ_PRIORITY_LOWEST
705+
};
706+
/* Initialze driver in blocking mode. */
707+
nrfx_twis_init(&nordic_nrf5_twis_instance[instance],
708+
&twis_config,
709+
NULL);
652710

653-
#if DEVICE_I2C_ASYNCH
654-
/* Set callback handler in asynchronous mode. */
655-
if (config->handler) {
711+
/* Enable peripheral (nrfx_twi_t and nrfx_twis_t are interchangeable). */
712+
nrfx_twis_enable(&nordic_nrf5_twis_instance[instance]);
713+
}
714+
else {
715+
#endif
656716

657-
/* Initialze driver in non-blocking mode. */
658-
nrfx_twi_init(&nordic_nrf5_instance[instance],
659-
&twi_config,
660-
nordic_nrf5_twi_event_handler,
661-
obj);
662-
} else {
717+
/* Configure driver with new settings. */
718+
nrfx_twi_config_t twi_config = {
719+
.scl = config->scl,
720+
.sda = config->sda,
721+
.frequency = config->frequency,
722+
.interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
723+
.hold_bus_uninit = false
724+
};
663725

726+
#if DEVICE_I2C_ASYNCH
727+
/* Set callback handler in asynchronous mode. */
728+
if (config->handler) {
729+
730+
/* Initialze driver in non-blocking mode. */
731+
nrfx_twi_init(&nordic_nrf5_instance[instance],
732+
&twi_config,
733+
nordic_nrf5_twi_event_handler,
734+
obj);
735+
} else {
736+
737+
/* Initialze driver in blocking mode. */
738+
nrfx_twi_init(&nordic_nrf5_instance[instance],
739+
&twi_config,
740+
NULL,
741+
NULL);
742+
}
743+
#else
664744
/* Initialze driver in blocking mode. */
665745
nrfx_twi_init(&nordic_nrf5_instance[instance],
666746
&twi_config,
667747
NULL,
668748
NULL);
669-
}
670-
#else
671-
/* Initialze driver in blocking mode. */
672-
nrfx_twi_init(&nordic_nrf5_instance[instance],
673-
&twi_config,
674-
NULL,
675-
NULL);
676749
#endif
677750

678-
/* Enable peripheral. */
679-
nrfx_twi_enable(&nordic_nrf5_instance[instance]);
751+
/* Enable peripheral. */
752+
nrfx_twi_enable(&nordic_nrf5_instance[instance]);
753+
#if DEVICE_I2CSLAVE
754+
}
755+
#endif
680756
}
681757
}
682758

@@ -945,7 +1021,6 @@ void i2c_abort_asynch(i2c_t *obj)
9451021
#endif // DEVICE_I2C_ASYNCH
9461022

9471023
#if DEVICE_I2CSLAVE
948-
#warning DEVICE_I2CSLAVE
9491024

9501025
/***
9511026
* _____ ___ _____ _____ _
@@ -965,6 +1040,25 @@ void i2c_abort_asynch(i2c_t *obj)
9651040
*/
9661041
void i2c_slave_mode(i2c_t *obj, int enable_slave)
9671042
{
1043+
#if DEVICE_I2C_ASYNCH
1044+
struct i2c_s *config = &obj->i2c;
1045+
#else
1046+
struct i2c_s *config = obj;
1047+
#endif
1048+
1049+
/* Reconfigure this instance as an I2C slave */
1050+
1051+
/* Not configured yet, so this instance is and was a slave */
1052+
if(config->state == NRFX_DRV_STATE_UNINITIALIZED) {
1053+
config->was_slave = enable_slave;
1054+
} else {
1055+
config->was_slave = config->is_slave;
1056+
}
1057+
config->is_slave = enable_slave;
1058+
config->update = true;
1059+
1060+
i2c_configure_driver_instance(obj);
1061+
9681062
DEBUG_PRINTF("i2c_slave_mode\r\n");
9691063
}
9701064

@@ -977,6 +1071,22 @@ int i2c_slave_receive(i2c_t *obj)
9771071
{
9781072
DEBUG_PRINTF("i2c_slave_receive\r\n");
9791073

1074+
#if DEVICE_I2C_ASYNCH
1075+
struct i2c_s *config = &obj->i2c;
1076+
#else
1077+
struct i2c_s *config = obj;
1078+
#endif
1079+
1080+
const nrfx_twis_t* twis_instance = &nordic_nrf5_twis_instance[config->instance];
1081+
1082+
if(nrfx_twis_is_waiting_rx_buff(twis_instance)) {
1083+
return 3;
1084+
}
1085+
1086+
if(nrfx_twis_is_waiting_tx_buff(twis_instance)) {
1087+
return 1;
1088+
}
1089+
9801090
return 0;
9811091
}
9821092

@@ -990,7 +1100,26 @@ int i2c_slave_read(i2c_t *obj, char *data, int length)
9901100
{
9911101
DEBUG_PRINTF("i2c_slave_read\r\n");
9921102

993-
return 0;
1103+
#if DEVICE_I2C_ASYNCH
1104+
struct i2c_s *config = &obj->i2c;
1105+
#else
1106+
struct i2c_s *config = obj;
1107+
#endif
1108+
1109+
const nrfx_twis_t* twis_instance = &nordic_nrf5_twis_instance[config->instance];
1110+
1111+
/* Wait until the master is trying to write data */
1112+
while(!nrfx_twis_is_waiting_rx_buff(twis_instance)) { }
1113+
1114+
/* Master is attempting to write, now we prepare the rx buffer */
1115+
nrfx_twis_rx_prepare(twis_instance,
1116+
data,
1117+
length);
1118+
1119+
/* Wait until the transaction is over */
1120+
while(nrfx_twis_is_pending_rx(twis_instance)) { }
1121+
1122+
return nrfx_twis_rx_amount(twis_instance);
9941123
}
9951124

9961125
/** Configure I2C as slave or master.
@@ -1003,7 +1132,26 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length)
10031132
{
10041133
DEBUG_PRINTF("i2c_slave_write\r\n");
10051134

1006-
return 0;
1135+
#if DEVICE_I2C_ASYNCH
1136+
struct i2c_s *config = &obj->i2c;
1137+
#else
1138+
struct i2c_s *config = obj;
1139+
#endif
1140+
1141+
const nrfx_twis_t* twis_instance = &nordic_nrf5_twis_instance[config->instance];
1142+
1143+
/* Wait until the master is trying to read data */
1144+
while(!nrfx_twis_is_waiting_tx_buff(twis_instance)) { }
1145+
1146+
/* Master is attempting to read, now we prepare the tx buffer */
1147+
nrfx_twis_tx_prepare(twis_instance,
1148+
data,
1149+
length);
1150+
1151+
/* Wait until the transaction is over */
1152+
while(nrfx_twis_is_pending_tx(twis_instance)) { }
1153+
1154+
return nrfx_twis_tx_amount(twis_instance);
10071155
}
10081156

10091157
/** Configure I2C address.
@@ -1014,6 +1162,18 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length)
10141162
*/
10151163
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
10161164
{
1165+
#if DEVICE_I2C_ASYNCH
1166+
struct i2c_s *config = &obj->i2c;
1167+
#else
1168+
struct i2c_s *config = obj;
1169+
#endif
1170+
1171+
/* Reconfigure this instance as an I2C slave with given address */
1172+
config->update = true;
1173+
config->slave_addr = (uint8_t) address;
1174+
1175+
i2c_configure_driver_instance(obj);
1176+
10171177
DEBUG_PRINTF("i2c_slave_address\r\n");
10181178
}
10191179

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ struct i2c_s {
128128
uint32_t mask;
129129
uint32_t event;
130130
#endif
131+
132+
#if DEVICE_I2CSLAVE
133+
bool was_slave;
134+
bool is_slave;
135+
uint8_t slave_addr;
136+
#endif
131137
};
132138

133139
struct analogin_s {

0 commit comments

Comments
 (0)