Skip to content

Commit fc3053b

Browse files
authored
Merge pull request #2497 from particle-iot/fix/p2_i2c
[rtl872x] hal: implement i2c sleep and fix the reset APIs
2 parents 3c3b8b1 + 4820869 commit fc3053b

File tree

10 files changed

+137
-57
lines changed

10 files changed

+137
-57
lines changed

hal/inc/hal_dynalib_i2c.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ DYNALIB_FN(13, hal_i2c, hal_i2c_is_enabled, bool(hal_i2c_interface_t, void*))
5858
DYNALIB_FN(14, hal_i2c, hal_i2c_set_callback_on_received, void(hal_i2c_interface_t, void(*)(int), void*))
5959
DYNALIB_FN(15, hal_i2c, hal_i2c_set_callback_on_requested, void(hal_i2c_interface_t, void(*)(void), void*))
6060
DYNALIB_FN(16, hal_i2c, hal_i2c_init, int(hal_i2c_interface_t, const hal_i2c_config_t*))
61-
DYNALIB_FN(17, hal_i2c, hal_i2c_reset, uint8_t(hal_i2c_interface_t, uint32_t, void*))
61+
DYNALIB_FN(17, hal_i2c, hal_i2c_reset, int(hal_i2c_interface_t, uint32_t, void*))
6262
DYNALIB_FN(18, hal_i2c, hal_i2c_lock, int32_t(hal_i2c_interface_t, void*))
6363
DYNALIB_FN(19, hal_i2c, hal_i2c_unlock, int32_t(hal_i2c_interface_t, void*))
6464
DYNALIB_FN(20, hal_i2c, hal_i2c_request_ex, int32_t(hal_i2c_interface_t, const hal_i2c_transmission_config_t*, void*))

hal/inc/i2c_hal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void hal_i2c_flush(hal_i2c_interface_t i2c, void* reserved);
105105
bool hal_i2c_is_enabled(hal_i2c_interface_t i2c, void* reserved);
106106
void hal_i2c_set_callback_on_received(hal_i2c_interface_t i2c, void (*function)(int), void* reserved);
107107
void hal_i2c_set_callback_on_requested(hal_i2c_interface_t i2c, void (*function)(void), void* reserved);
108-
uint8_t hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserve1);
108+
int hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserve1);
109109
int hal_i2c_sleep(hal_i2c_interface_t i2c, bool sleep, void* reserved);
110110
int32_t hal_i2c_lock(hal_i2c_interface_t i2c, void* reserved);
111111
int32_t hal_i2c_unlock(hal_i2c_interface_t i2c, void* reserved);

hal/src/nRF52840/i2c_hal.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -643,14 +643,14 @@ void hal_i2c_enable_dma_mode(hal_i2c_interface_t i2c, bool enable,void* reserved
643643
// use DMA to send data by default
644644
}
645645

646-
uint8_t hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1) {
646+
int hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1) {
647647
if (i2c >= HAL_PLATFORM_I2C_NUM) {
648-
return 1;
648+
return SYSTEM_ERROR_NOT_FOUND;
649649
}
650650

651651
I2cLock lk(i2c);
652652
if (!hal_i2c_is_enabled(i2c, nullptr) || (i2cMap[i2c].mode != I2C_MODE_MASTER)) {
653-
return 1;
653+
return SYSTEM_ERROR_INVALID_STATE;
654654
}
655655

656656
// Important: we keep GPIO configuration intact
@@ -700,7 +700,8 @@ uint8_t hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved
700700
hal_pin_set_function(i2cMap[i2c].scl_pin, PF_I2C);
701701

702702
hal_i2c_begin(i2c, i2cMap[i2c].mode, i2cMap[i2c].address, nullptr);
703-
return !hal_i2c_is_enabled(i2c, nullptr);
703+
CHECK_TRUE(hal_i2c_is_enabled(i2c, nullptr), SYSTEM_ERROR_INTERNAL);
704+
return SYSTEM_ERROR_NONE;
704705
}
705706

706707
int32_t hal_i2c_lock(hal_i2c_interface_t i2c, void* reserved) {

hal/src/rtl872x/gpio_hal.cpp

+32-11
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,19 @@ int hal_gpio_configure(hal_pin_t pin, const hal_gpio_config_t* conf, void* reser
141141
GPIO_InitStruct.GPIO_Pin = rtlPin;
142142

143143
switch (mode) {
144-
case OUTPUT:
145-
case OUTPUT_OPEN_DRAIN: {
144+
case OUTPUT: {
146145
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
147146
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
148147
break;
149148
}
150-
case INPUT: {
149+
case INPUT:
150+
case OUTPUT_OPEN_DRAIN: {
151151
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
152152
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
153153
break;
154154
}
155-
case INPUT_PULLUP: {
155+
case INPUT_PULLUP:
156+
case OUTPUT_OPEN_DRAIN_PULLUP: {
156157
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
157158
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
158159
break;
@@ -162,11 +163,6 @@ int hal_gpio_configure(hal_pin_t pin, const hal_gpio_config_t* conf, void* reser
162163
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
163164
break;
164165
}
165-
case OUTPUT_OPEN_DRAIN_PULLUP: {
166-
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
167-
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
168-
break;
169-
}
170166
case PIN_MODE_SWD: {
171167
if (isSwdPin(pinInfo)) {
172168
//"Pinmux_Swdon"
@@ -188,6 +184,10 @@ int hal_gpio_configure(hal_pin_t pin, const hal_gpio_config_t* conf, void* reser
188184
}
189185
}
190186

187+
if ((mode == OUTPUT_OPEN_DRAIN || mode == OUTPUT_OPEN_DRAIN_PULLUP) && conf->set_value && conf->value == 0) {
188+
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
189+
}
190+
191191
GPIO_Init(&GPIO_InitStruct);
192192
pinInfo->pin_mode = mode;
193193

@@ -233,12 +233,33 @@ void hal_gpio_write(hal_pin_t pin, uint8_t value) {
233233
#if HAL_PLATFORM_IO_EXTENSION && MODULE_FUNCTION != MOD_FUNC_BOOTLOADER
234234
if (pinInfo->type == HAL_PIN_TYPE_MCU) {
235235
#endif
236-
uint32_t rtlPin = hal_pin_to_rtl_pin(pin);
237236
// TODO: PWM have conflict with GPIO OUTPUT mode on Realtek
238237
if (pinInfo->pin_func == PF_PWM) {
239238
hal_gpio_mode(pin, OUTPUT);
240239
}
241-
GPIO_WriteBit(rtlPin, value);
240+
241+
auto mode = hal_gpio_get_mode(pin);
242+
hal_pin_info_t* pin_info = hal_pin_map() + pin;
243+
GPIO_TypeDef * gpiobase = ((pin_info->gpio_port == RTL_PORT_A) ? GPIOA_BASE : GPIOB_BASE);
244+
// Dirty hack: As per the description of EXT_PORT register in the user manual,
245+
// "When Port A is configured as Input, then reading this location reads
246+
// the values on the signal. When the data direction of Port A is set as
247+
// Output, reading this location reads the data register for Port A."
248+
if (value) {
249+
if (mode == OUTPUT_OPEN_DRAIN || mode == OUTPUT_OPEN_DRAIN_PULLUP) {
250+
// Output 1, it should read back 1 if idle or 0 if it is pulled down by external signal
251+
// Configure it as input meets the requirements.
252+
gpiobase->PORT[0].DDR &= (~(1 << pin_info->gpio_pin));
253+
} else {
254+
gpiobase->PORT[0].DR |= (1 << pin_info->gpio_pin);
255+
}
256+
} else {
257+
// Output 0, it should always read back 0.
258+
// Configure it as output, despite of the output mode
259+
gpiobase->PORT[0].DR &= ~(1 << pin_info->gpio_pin);
260+
gpiobase->PORT[0].DDR |= (1 << pin_info->gpio_pin);
261+
}
262+
242263
if (isCachePin(pin) && isCachePinSetToOutput(pin)) {
243264
setCachePinState(pin, value);
244265
}

hal/src/rtl872x/i2c_hal.cpp

+65-19
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ class I2cClass {
163163

164164
int end() {
165165
if (isEnabled()) {
166+
hal_gpio_config_t conf = {};
167+
conf.size = sizeof(conf);
168+
conf.version = HAL_GPIO_VERSION;
169+
conf.mode = OUTPUT_OPEN_DRAIN_PULLUP;
170+
conf.set_value = true;
171+
conf.value = 1;
172+
hal_gpio_configure(sclPin_, &conf, nullptr);
173+
hal_gpio_configure(sdaPin_, &conf, nullptr);
166174
if (i2cInitStruct_.I2CMaster == I2C_SLAVE_MODE) {
167175
InterruptDis(I2C0_IRQ_LP);
168176
InterruptUnRegister(I2C0_IRQ_LP);
@@ -174,11 +182,25 @@ class I2cClass {
174182
// RCC_PeriphClockCmd(APBPeriph_I2C0, APBPeriph_I2C0_CLOCK, DISABLE);
175183
Pinmux_Config(hal_pin_to_rtl_pin(sdaPin_), PINMUX_FUNCTION_GPIO);
176184
Pinmux_Config(hal_pin_to_rtl_pin(sclPin_), PINMUX_FUNCTION_GPIO);
185+
txBuffer_.reset();
186+
rxBuffer_.reset();
177187
}
178188
return SYSTEM_ERROR_NONE;
179189
}
180190

181-
void reset() {
191+
int suspend() {
192+
CHECK_TRUE(state_ = HAL_I2C_STATE_ENABLED, SYSTEM_ERROR_INVALID_STATE);
193+
CHECK(end());
194+
state_ = HAL_I2C_STATE_SUSPENDED;
195+
return SYSTEM_ERROR_NONE;
196+
}
197+
198+
int restore() {
199+
CHECK_TRUE(state_ = HAL_I2C_STATE_SUSPENDED, SYSTEM_ERROR_INVALID_STATE);
200+
return begin((i2cInitStruct_.I2CMaster == I2C_MASTER_MODE) ? I2C_MODE_MASTER : I2C_MODE_SLAVE, i2cInitStruct_.I2CAckAddr);
201+
}
202+
203+
int reset() {
182204
end();
183205

184206
// Just in case make sure that the pins are correctly configured (they should anyway be at this point)
@@ -188,15 +210,16 @@ class I2cClass {
188210
conf.mode = OUTPUT_OPEN_DRAIN_PULLUP;
189211
conf.set_value = true;
190212
conf.value = 1;
191-
hal_gpio_configure(sdaPin_, &conf, nullptr);
192-
conf.value = hal_gpio_read(sclPin_);
193213
hal_gpio_configure(sclPin_, &conf, nullptr);
214+
hal_gpio_configure(sdaPin_, &conf, nullptr);
215+
216+
// Check if slave is stretching the SCL
217+
if (!WAIT_TIMED(HAL_I2C_DEFAULT_TIMEOUT_MS, hal_gpio_read(sclPin_) == 0)) {
218+
return SYSTEM_ERROR_I2C_BUS_BUSY;
219+
}
194220

195221
// Generate up to 9 pulses on SCL to tell slave to release the bus
196222
for (int i = 0; i < 9; i++) {
197-
hal_gpio_write(sdaPin_, 1);
198-
HAL_Delay_Microseconds(50);
199-
200223
if (hal_gpio_read(sdaPin_) == 0) {
201224
hal_gpio_write(sclPin_, 0);
202225
HAL_Delay_Microseconds(50);
@@ -222,6 +245,8 @@ class I2cClass {
222245

223246
hal_i2c_mode_t mode = (i2cInitStruct_.I2CMaster == I2C_MASTER_MODE) ? I2C_MODE_MASTER : I2C_MODE_SLAVE;
224247
begin(mode, i2cInitStruct_.I2CAckAddr);
248+
CHECK_TRUE(isEnabled(), SYSTEM_ERROR_INTERNAL);
249+
return SYSTEM_ERROR_NONE;
225250
}
226251

227252
int setSpeed(uint32_t speed) {
@@ -344,6 +369,28 @@ class I2cClass {
344369
setAddress(transConfig_.address);
345370

346371
uint32_t quantity = txBuffer_.data();
372+
if (quantity == 0) {
373+
// Clear flags
374+
uint32_t temp = i2cDev_->IC_CLR_TX_ABRT;
375+
temp = i2cDev_->IC_CLR_STOP_DET;
376+
(void)temp;
377+
if ((i2cDev_->IC_TX_ABRT_SOURCE & BIT_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK)
378+
|| (i2cDev_->IC_RAW_INTR_STAT & BIT_IC_RAW_INTR_STAT_STOP_DET)) {
379+
return SYSTEM_ERROR_I2C_ABORT;
380+
}
381+
// Send the slave address only
382+
i2cDev_->IC_DATA_CMD = (transConfig_.address << 1) | BIT_CTRL_IC_DATA_CMD_NULLDATA | BIT_CTRL_IC_DATA_CMD_STOP;
383+
// If slave is not detected, the STOP_DET bit won't be set, and the TX_ABRT is set instead.
384+
if (!WAIT_TIMED(transConfig_.timeout_ms, ((i2cDev_->IC_TX_ABRT_SOURCE & BIT_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK) == 0)
385+
&& ((i2cDev_->IC_RAW_INTR_STAT & BIT_IC_RAW_INTR_STAT_STOP_DET) == 0))) {
386+
return SYSTEM_ERROR_I2C_TX_ADDR_TIMEOUT;
387+
}
388+
if (i2cDev_->IC_TX_ABRT_SOURCE & BIT_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK) {
389+
return SYSTEM_ERROR_I2C_ABORT;
390+
}
391+
return SYSTEM_ERROR_NONE;
392+
}
393+
347394
for (uint32_t i = 0; i < quantity; i++) {
348395
if (!WAIT_TIMED(transConfig_.timeout_ms, I2C_CheckFlagState(i2cDev_, BIT_IC_STATUS_TFNF) == 0)) {
349396
reset();
@@ -356,10 +403,10 @@ class I2cClass {
356403
if(i >= quantity - 1) {
357404
if (stop) {
358405
// Generate stop signal
359-
i2cDev_->IC_DATA_CMD = data | (1 << 9);
406+
i2cDev_->IC_DATA_CMD = data | BIT_CTRL_IC_DATA_CMD_STOP;
360407
} else {
361408
// Generate restart signal
362-
i2cDev_->IC_DATA_CMD = data | (1 << 10);
409+
i2cDev_->IC_DATA_CMD = data | BIT_CTRL_IC_DATA_CMD_RESTART;
363410
}
364411
} else {
365412
// The address will be sent before sending the first data byte
@@ -684,11 +731,10 @@ void hal_i2c_enable_dma_mode(hal_i2c_interface_t i2c, bool enable, void* reserve
684731
// use DMA to send data by default
685732
}
686733

687-
uint8_t hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1) {
688-
auto instance = CHECK_TRUE_RETURN(I2cClass::getInstance(i2c), 1);
734+
int hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1) {
735+
auto instance = CHECK_TRUE_RETURN(I2cClass::getInstance(i2c), SYSTEM_ERROR_NOT_FOUND);
689736
I2cLock lk(instance);
690-
instance->reset();
691-
return 0;
737+
return instance->reset();
692738
}
693739

694740
int32_t hal_i2c_lock(hal_i2c_interface_t i2c, void* reserved) {
@@ -702,12 +748,12 @@ int32_t hal_i2c_unlock(hal_i2c_interface_t i2c, void* reserved) {
702748
}
703749

704750
int hal_i2c_sleep(hal_i2c_interface_t i2c, bool sleep, void* reserved) {
705-
// auto instance = CHECK_TRUE_RETURN(I2cClass::getInstance(i2c), SYSTEM_ERROR_NOT_FOUND);
706-
// I2cLock lk(i2c);
707-
// if (sleep) {
708-
// Suspend I2C
709-
// } else {
710-
// Restore I2C
711-
// }
751+
auto instance = CHECK_TRUE_RETURN(I2cClass::getInstance(i2c), SYSTEM_ERROR_NOT_FOUND);
752+
I2cLock lk(instance);
753+
if (sleep) {
754+
return instance->suspend();
755+
} else {
756+
return instance->restore();
757+
}
712758
return SYSTEM_ERROR_NONE;
713759
}

hal/src/template/i2c_hal.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void hal_i2c_enable_dma_mode(hal_i2c_interface_t i2c, bool enable,void* reserved
134134
{
135135
}
136136

137-
uint8_t hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1)
137+
int hal_i2c_reset(hal_i2c_interface_t i2c, uint32_t reserved, void* reserved1)
138138
{
139139
return SYSTEM_ERROR_NONE;
140140
}

user/tests/wiring/no_fixture/gpio.cpp

+22-14
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ test(GPIO_01_PinModeSetResultsInCorrectMode) {
3939
INPUT_PULLUP,
4040
INPUT_PULLDOWN,
4141
OUTPUT_OPEN_DRAIN,
42+
OUTPUT_OPEN_DRAIN_PULLUP,
4243
#if !HAL_PLATFORM_NRF52840 && !HAL_PLATFORM_RTL872X
4344
// AF_OUTPUT_PUSHPULL,
4445
// AN_INPUT,
@@ -48,7 +49,7 @@ test(GPIO_01_PinModeSetResultsInCorrectMode) {
4849
};
4950
int n = sizeof(mode) / sizeof(mode[0]);
5051
hal_pin_t pin = A0;//pin under test
51-
for(int i=0;i<n;i++)
52+
for (int i = 0; i < n; i++)
5253
{
5354
// when
5455
pinMode(pin, mode[i]);
@@ -81,19 +82,26 @@ test(GPIO_03_NoDigitalWriteWhenPinSelectedIsOutOfRange) {
8182

8283
test(GPIO_04_DigitalWriteOnPinResultsInCorrectDigitalRead) {
8384
hal_pin_t pin = A0;//pin under test
84-
// when
85-
pinMode(pin, OUTPUT);
86-
digitalWrite(pin, HIGH);
87-
PinState pinState = (PinState)digitalRead(pin);
88-
// then
89-
assertEqual(pinState, HIGH);
90-
delay(100);
91-
// when
92-
digitalWrite(pin, LOW);
93-
pinState = (PinState)digitalRead(pin);
94-
// then
95-
assertEqual(pinState, LOW);
96-
//To Do : Add test for remaining pins if required
85+
PinMode mode[] = {
86+
OUTPUT,
87+
OUTPUT_OPEN_DRAIN_PULLUP,
88+
};
89+
int n = sizeof(mode) / sizeof(mode[0]);
90+
for (int i = 0; i < n; i++) {
91+
// when
92+
pinMode(pin, mode[i]);
93+
digitalWrite(pin, HIGH);
94+
PinState pinState = (PinState)digitalRead(pin);
95+
// then
96+
assertEqual(pinState, HIGH);
97+
delay(100);
98+
// when
99+
digitalWrite(pin, LOW);
100+
pinState = (PinState)digitalRead(pin);
101+
// then
102+
assertEqual(pinState, LOW);
103+
//To Do : Add test for remaining pins if required
104+
}
97105
}
98106

99107
#if !HAL_PLATFORM_RTL872X

wiring/inc/fast_pin.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ inline void pinSetFast(hal_pin_t _pin)
8585
pinConfigure(pin_info);
8686

8787
GPIO_TypeDef* gpiobase = ((pin_info.gpio_port == RTL_PORT_A) ? GPIOA_BASE : GPIOB_BASE);
88-
gpiobase->PORT[0].DDR |= (1 << pin_info.gpio_pin);
89-
gpiobase->PORT[0].DR |= (1 << pin_info.gpio_pin);
88+
if (pin_info.pin_mode == OUTPUT_OPEN_DRAIN || pin_info.pin_mode == OUTPUT_OPEN_DRAIN_PULLUP) {
89+
gpiobase->PORT[0].DDR &= (~(1 << pin_info.gpio_pin));
90+
} else {
91+
gpiobase->PORT[0].DR |= (1 << pin_info.gpio_pin);
92+
gpiobase->PORT[0].DDR |= (1 << pin_info.gpio_pin);
93+
}
9094
}
9195

9296
inline void pinResetFast(hal_pin_t _pin)
@@ -95,8 +99,8 @@ inline void pinResetFast(hal_pin_t _pin)
9599
pinConfigure(pin_info);
96100

97101
GPIO_TypeDef* gpiobase = ((pin_info.gpio_port == RTL_PORT_A) ? GPIOA_BASE : GPIOB_BASE);
98-
gpiobase->PORT[0].DDR |= (1 << pin_info.gpio_pin);
99102
gpiobase->PORT[0].DR &= (0 << pin_info.gpio_pin);
103+
gpiobase->PORT[0].DDR |= (1 << pin_info.gpio_pin);
100104
}
101105

102106
inline int32_t pinReadFast(hal_pin_t _pin)

wiring/inc/spark_wiring_i2c.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class TwoWire : public Stream
131131
/**
132132
* Attempts to reset this I2C bus.
133133
*/
134-
void reset();
134+
int reset();
135135

136136
hal_i2c_interface_t interface() const {
137137
return _i2c;

wiring/src/spark_wiring_i2c.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ bool TwoWire::isEnabled()
199199
return hal_i2c_is_enabled(_i2c, NULL);
200200
}
201201

202-
void TwoWire::reset()
202+
int TwoWire::reset()
203203
{
204-
hal_i2c_reset(_i2c, 0, NULL);
204+
return hal_i2c_reset(_i2c, 0, NULL);
205205
}
206206

207207
bool TwoWire::lock()

0 commit comments

Comments
 (0)