@@ -30,6 +30,10 @@ extern "C" {
3030
3131#include " Wire.h"
3232
33+ /* Max cycles approximately to wait on RXDREADY and TXDREADY event,
34+ * This is optimized way instead of using timers, this is not power aware. */
35+ #define MAX_TIMEOUT_LOOPS (20000UL ) /* *< MAX while loops to wait for RXD/TXD event */
36+
3337TwoWire::TwoWire (NRF_TWI_Type * p_twi, IRQn_Type IRQn, uint8_t pinSDA, uint8_t pinSCL)
3438{
3539 this ->_p_twi = p_twi;
@@ -55,14 +59,17 @@ void TwoWire::begin(void) {
5559 | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
5660 | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
5761
58- _p_twi->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 ;
59- _p_twi->ENABLE = (TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos) ;
62+ _p_twi->EVENTS_RXDREADY = 0 ;
63+ _p_twi->EVENTS_TXDSENT = 0 ;
6064 _p_twi->PSELSCL = _uc_pinSCL;
6165 _p_twi->PSELSDA = _uc_pinSDA;
66+ _p_twi->ENABLE = (TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos);
6267
6368 NVIC_ClearPendingIRQ (_IRQn);
6469 NVIC_SetPriority (_IRQn, 2 );
6570 NVIC_EnableIRQ (_IRQn);
71+
72+ clear ();
6673}
6774
6875void TwoWire::setClock (uint32_t baudrate) {
@@ -91,56 +98,87 @@ void TwoWire::end() {
9198 _p_twi->ENABLE = (TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos);
9299}
93100
94- uint8_t TwoWire::requestFrom (uint8_t address, size_t quantity , bool stopBit )
101+ uint8_t TwoWire::requestFrom (uint8_t address, size_t data_length , bool issue_stop_condition )
95102{
96- if (quantity == 0 )
97- {
98- return 0 ;
99- }
100-
101- size_t byteRead = 0 ;
103+ uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for RXDREADY event*/
102104 rxBuffer.clear ();
103105
104106 _p_twi->ADDRESS = address;
105107
106- _p_twi->TASKS_RESUME = 0x1UL ;
107- _p_twi->TASKS_STARTRX = 0x1UL ;
108-
109- for (size_t i = 0 ; i < quantity; i++)
108+ if (data_length == 0 )
110109 {
111- while (!_p_twi->EVENTS_RXDREADY && !_p_twi->EVENTS_ERROR );
112-
113- if (_p_twi->EVENTS_ERROR )
114- {
115- break ;
116- }
117-
118- _p_twi->EVENTS_RXDREADY = 0x0UL ;
119-
120- rxBuffer.store_char (_p_twi->RXD );
121-
122- _p_twi->TASKS_RESUME = 0x1UL ;
110+ /* Return false for requesting data of size 0 */
111+ _p_twi->SHORTS = 0 ; // short are not enabled yet, may not be necessary
112+ return false ;
123113 }
124-
125- if (stopBit || _p_twi->EVENTS_ERROR )
114+ else if (data_length == 1 )
126115 {
127- _p_twi->TASKS_STOP = 0x1UL ;
128- while (!_p_twi->EVENTS_STOPPED );
129- _p_twi->EVENTS_STOPPED = 0x0UL ;
116+ _p_twi->SHORTS = TWI_SHORTS_BB_STOP_Enabled << TWI_SHORTS_BB_STOP_Pos;
130117 }
131118 else
132119 {
133- _p_twi->TASKS_SUSPEND = 0x1UL ;
134- while (!_p_twi->EVENTS_SUSPENDED );
135- _p_twi->EVENTS_SUSPENDED = 0x0UL ;
120+ _p_twi->SHORTS = TWI_SHORTS_BB_SUSPEND_Enabled << TWI_SHORTS_BB_SUSPEND_Pos;
121+ }
122+
123+ _p_twi->EVENTS_RXDREADY = 0 ;
124+ _p_twi->TASKS_STARTRX = 1 ;
125+
126+ /* * @snippet [TWI HW master read] */
127+ while (true )
128+ {
129+ while (_p_twi->EVENTS_RXDREADY == 0 && _p_twi->EVENTS_ERROR == 0 && (--timeout))
130+ {
131+ // Do nothing.
132+ }
133+ _p_twi->EVENTS_RXDREADY = 0 ;
134+
135+ if (timeout == 0 || _p_twi->EVENTS_ERROR != 0 )
136+ {
137+ // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
138+ // Product Anomaly Notification document found at
139+ // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
140+ _p_twi->EVENTS_ERROR = 0 ;
141+ _p_twi->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
142+ _p_twi->POWER = 0 ;
143+ nrf_delay_us (5 );
144+ _p_twi->POWER = 1 ;
145+ _p_twi->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
146+
147+ clear ();
148+
149+ _p_twi->SHORTS = 0 ;
150+ return false ;
151+ }
152+
153+ rxBuffer.store_char (_p_twi->RXD );
154+
155+ if (--data_length == 1 )
156+ {
157+ _p_twi->SHORTS = TWI_SHORTS_BB_STOP_Enabled << TWI_SHORTS_BB_STOP_Pos;
158+ }
159+
160+ if (data_length == 0 )
161+ {
162+ break ;
163+ }
164+
165+ // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
166+ // Product Anomaly Notification document found at
167+ // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
168+ nrf_delay_us (20 );
169+ _p_twi->TASKS_RESUME = 1 ;
136170 }
171+ /* * @snippet [TWI HW master read] */
137172
138- if (_p_twi->EVENTS_ERROR )
173+ /* Wait until stop sequence is sent */
174+ while (_p_twi->EVENTS_STOPPED == 0 )
139175 {
140- _p_twi-> EVENTS_ERROR = 0x0UL ;
176+ // Do nothing.
141177 }
178+ _p_twi->EVENTS_STOPPED = 0 ;
142179
143- return byteRead;
180+ _p_twi->SHORTS = 0 ;
181+ return rxBuffer.available ();
144182}
145183
146184uint8_t TwoWire::requestFrom (uint8_t address, size_t quantity)
@@ -153,6 +191,8 @@ void TwoWire::beginTransmission(uint8_t address) {
153191 txAddress = address;
154192 txBuffer.clear ();
155193
194+ _p_twi->ADDRESS = address;
195+
156196 transmissionBegun = true ;
157197}
158198
@@ -162,66 +202,90 @@ void TwoWire::beginTransmission(uint8_t address) {
162202// 2 : NACK on transmit of address
163203// 3 : NACK on transmit of data
164204// 4 : Other error
165- uint8_t TwoWire::endTransmission (bool stopBit )
205+ uint8_t TwoWire::endTransmission (bool issue_stop_condition )
166206{
167- transmissionBegun = false ;
168-
169- // Start I2C transmission
170- _p_twi->ADDRESS = txAddress;
207+ uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for EVENTS_TXDSENT event*/
171208
172- _p_twi->TASKS_RESUME = 0x1UL ;
173- _p_twi->TASKS_STARTTX = 0x1UL ;
174-
175- while (txBuffer.available ())
209+ if (txBuffer.available () == 0 )
176210 {
177- _p_twi->TXD = txBuffer.read_char ();
178-
179- while (!_p_twi->EVENTS_TXDSENT && !_p_twi->EVENTS_ERROR );
180-
181- if (_p_twi->EVENTS_ERROR )
182- {
183- break ;
184- }
185-
186- _p_twi->EVENTS_TXDSENT = 0x0UL ;
211+ /* Return false for requesting data of size 0 */
212+ return false ;
187213 }
188214
189- if (stopBit || _p_twi->EVENTS_ERROR )
190- {
191- _p_twi->TASKS_STOP = 0x1UL ;
192- while (!_p_twi->EVENTS_STOPPED );
193- _p_twi->EVENTS_STOPPED = 0x0UL ;
194- }
195- else
215+ _p_twi->ADDRESS = txAddress;
216+ _p_twi->TXD = txBuffer.read_char ();
217+ _p_twi->TASKS_STARTTX = 1 ;
218+
219+ /* * @snippet [TWI HW master write] */
220+ while (true )
196221 {
197- _p_twi->TASKS_SUSPEND = 0x1UL ;
198- while (!_p_twi->EVENTS_SUSPENDED );
199- _p_twi->EVENTS_SUSPENDED = 0x0UL ;
222+ while (_p_twi->EVENTS_TXDSENT == 0 && _p_twi->EVENTS_ERROR == 0 && (--timeout))
223+ {
224+ // Do nothing.
225+ }
226+
227+ if (timeout == 0 || _p_twi->EVENTS_ERROR != 0 )
228+ {
229+ // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
230+ // Product Anomaly Notification document found at
231+ // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
232+ _p_twi->EVENTS_ERROR = 0 ;
233+ _p_twi->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
234+ _p_twi->POWER = 0 ;
235+ nrf_delay_us (5 );
236+ _p_twi->POWER = 1 ;
237+ _p_twi->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
238+
239+ begin ();
240+
241+ return false ;
242+ }
243+ _p_twi->EVENTS_TXDSENT = 0 ;
244+ if (txBuffer.available () == 0 )
245+ {
246+ break ;
247+ }
248+
249+ _p_twi->TXD = txBuffer.read_char ();
200250 }
251+ /* * @snippet [TWI HW master write] */
201252
202- if (_p_twi-> EVENTS_ERROR )
253+ if (issue_stop_condition )
203254 {
204- _p_twi->EVENTS_ERROR = 0x0UL ;
205-
206- uint32_t error = _p_twi->ERRORSRC ;
207-
208- _p_twi->ERRORSRC = error;
209-
210- if (error == TWI_ERRORSRC_ANACK_Msk)
211- {
212- return 2 ;
213- }
214- else if (error == TWI_ERRORSRC_DNACK_Msk)
215- {
216- return 3 ;
217- }
218- else
219- {
220- return 4 ;
221- }
255+ _p_twi->EVENTS_STOPPED = 0 ;
256+ _p_twi->TASKS_STOP = 1 ;
257+ /* Wait until stop sequence is sent */
258+ while (_p_twi->EVENTS_STOPPED == 0 )
259+ {
260+ // Do nothing.
261+ }
262+ _p_twi->EVENTS_STOPPED = 0 ;
222263 }
223-
224- return 0 ;
264+ return true ;
265+
266+ // if (_p_twi->EVENTS_ERROR)
267+ // {
268+ // _p_twi->EVENTS_ERROR = 0x0UL;
269+
270+ // uint32_t error = _p_twi->ERRORSRC;
271+
272+ // _p_twi->ERRORSRC = error;
273+
274+ // if (error == TWI_ERRORSRC_ANACK_Msk)
275+ // {
276+ // return 2;
277+ // }
278+ // else if (error == TWI_ERRORSRC_DNACK_Msk)
279+ // {
280+ // return 3;
281+ // }
282+ // else
283+ // {
284+ // return 4;
285+ // }
286+ // }
287+
288+ // return 0;
225289}
226290
227291uint8_t TwoWire::endTransmission ()
@@ -281,6 +345,65 @@ void TwoWire::onService(void)
281345{
282346}
283347
348+ bool TwoWire::clear () {
349+ bool bus_clear;
350+
351+ // Save and disable TWI hardware so software can take control over the pins.
352+ uint32_t twi_state = _p_twi->ENABLE ;
353+ _p_twi->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
354+
355+ uint32_t clk_pin_config = NRF_GPIO->PIN_CNF [_uc_pinSCL];
356+ NRF_GPIO->PIN_CNF [_uc_pinSCL] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
357+ | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
358+ | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
359+ | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
360+ | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
361+
362+ uint32_t data_pin_config = NRF_GPIO->PIN_CNF [_uc_pinSDA];
363+ NRF_GPIO->PIN_CNF [_uc_pinSDA] = ((uint32_t )GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
364+ | ((uint32_t )GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
365+ | ((uint32_t )GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
366+ | ((uint32_t )GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
367+ | ((uint32_t )GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
368+
369+ NRF_GPIO->OUTSET = (1UL << _uc_pinSDA);
370+ NRF_GPIO->OUTSET = (1UL << _uc_pinSCL);
371+ nrf_delay_us (4 );
372+
373+ if ( ((NRF_GPIO->IN >> _uc_pinSDA) & 1UL ) && ((NRF_GPIO->IN >> _uc_pinSCL) & 1UL ) )
374+ {
375+ bus_clear = true ;
376+ }
377+ else
378+ {
379+ uint_fast8_t i;
380+ bus_clear = false ;
381+
382+ // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9
383+ // for slave to respond) to SCL line and wait for SDA come high.
384+ for (i=18 ; i--;)
385+ {
386+ NRF_GPIO->OUTCLR = (1UL << _uc_pinSCL);
387+ nrf_delay_us (4 );
388+ NRF_GPIO->OUTSET = (1UL << _uc_pinSCL);
389+ nrf_delay_us (4 );
390+
391+ if (((NRF_GPIO->IN >> _uc_pinSDA) & 1UL ) == 1 )
392+ {
393+ bus_clear = true ;
394+ break ;
395+ }
396+ }
397+ }
398+
399+ NRF_GPIO->PIN_CNF [_uc_pinSCL] = clk_pin_config;
400+ NRF_GPIO->PIN_CNF [_uc_pinSDA] = data_pin_config;
401+
402+ _p_twi->ENABLE = twi_state;
403+
404+ return bus_clear;
405+ }
406+
284407#if WIRE_INTERFACES_COUNT > 0
285408TwoWire Wire (NRF_TWI1, SPI1_TWI1_IRQn, PIN_WIRE_SDA, PIN_WIRE_SCL);
286409
0 commit comments