Skip to content

Commit 911d76d

Browse files
committed
Fix Wire (I2C) Lib
1 parent 7320c2a commit 911d76d

File tree

4 files changed

+230
-89
lines changed

4 files changed

+230
-89
lines changed

libraries/Wire/Wire.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class TwoWire : public Stream
6767
void onRequest(void(*)(void));
6868
#endif
6969

70+
virtual bool clear();
7071
using Print::write;
7172

7273
void onService(void);

libraries/Wire/Wire_nRF51.cpp

Lines changed: 209 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3337
TwoWire::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

6875
void 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

146184
uint8_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

227291
uint8_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
285408
TwoWire Wire(NRF_TWI1, SPI1_TWI1_IRQn, PIN_WIRE_SDA, PIN_WIRE_SCL);
286409

0 commit comments

Comments
 (0)