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. */
589622static 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
593630static 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 */
9661041void 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 */
10151163void 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
0 commit comments