Skip to content

Commit

Permalink
libraries/Wire: Multiple instance support.
Browse files Browse the repository at this point in the history
Signed-off-by: IFX-Anusha <[email protected]>
  • Loading branch information
IFX-Anusha committed Jan 31, 2025
1 parent c460332 commit c892489
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 107 deletions.
193 changes: 134 additions & 59 deletions libraries/Wire/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,48 @@ extern "C" {
#include "Wire.h"

#define I2C_DEFAULT_FREQ 100000
#define MAX_I2C_INSTANCES 10

TwoWire::TwoWire(cyhal_gpio_t sda, cyhal_gpio_t scl) : sda_pin(sda), scl_pin(scl) {
TwoWire *TwoWire::instances[MAX_I2C_INSTANCES] = {nullptr};
cyhal_i2c_t TwoWire::i2c_objs[MAX_I2C_INSTANCES];

TwoWire::TwoWire(cyhal_gpio_t sda, cyhal_gpio_t scl, uint8_t instance) : sda_pin(sda), scl_pin(scl), instance(instance) {
if (instance < MAX_I2C_INSTANCES) {
instances[instance] = this;
}
}

void TwoWire::_begin() {

rxBufferIndex = 0;
rxBufferLength = 0;

txBufferIndex = 0;
txBufferLength = 0;

if (is_master) {
i2c_config= {
.is_slave = is_master ? false : true,
0,
i2c_config = {
.is_slave = CYHAL_I2C_MODE_MASTER,
.address = 0,
.frequencyhal_hz = I2C_DEFAULT_FREQ
};
}
else {
} else {
i2c_config = {
.is_slave = is_master ? false : true,
slave_address,
.is_slave = CYHAL_I2C_MODE_SLAVE,
.address = slave_address,
.frequencyhal_hz = I2C_DEFAULT_FREQ
};
}
cyhal_i2c_init(&i2c_obj, sda_pin, scl_pin, NULL);
cyhal_i2c_configure(&i2c_obj, &i2c_config);
cyhal_i2c_register_callback(&i2c_obj, i2c_event_handler, this);

cyhal_i2c_init(&i2c_objs[instance], sda_pin, scl_pin, NULL);
cyhal_i2c_configure(&i2c_objs[instance], &i2c_config);

if (!is_master) {
// Configure the read and write buffers for the I2C slave
cyhal_i2c_slave_config_read_buffer(&i2c_objs[instance], rxBuffer, BUFFER_LENGTH);
cyhal_i2c_slave_config_write_buffer(&i2c_objs[instance], txBuffer, BUFFER_LENGTH);
}

cyhal_i2c_register_callback(&i2c_objs[instance], i2c_event_handler, this);
}

void TwoWire::begin() {
Expand All @@ -60,57 +73,123 @@ void TwoWire::begin(uint8_t address) {
}

void TwoWire::end() {
cyhal_i2c_free(&i2c_obj);
cyhal_i2c_free(&i2c_objs[instance]);
}

void TwoWire::setClock(uint32_t freq) {
if(is_master) {
if (is_master) {
i2c_config = {
.is_slave = false,
0,
.address = 0,
.frequencyhal_hz = freq
};
}
else {
} else {
i2c_config = {
.is_slave = true,
slave_address,
.address = slave_address,
.frequencyhal_hz = freq
};
}
cyhal_i2c_configure(&i2c_obj, &i2c_config);
cyhal_i2c_configure(&i2c_objs[instance], &i2c_config);
}

void TwoWire:: beginTransmission(uint8_t address) {
void TwoWire::beginTransmission(uint8_t address) {
txAddress = address;
txBufferIndex = 0;
txBufferLength = 0;
}

uint8_t TwoWire::endTransmission(bool sendStop) {
cy_rslt_t result = cyhal_i2c_master_write(&i2c_obj, slave_address, txBuffer, txBufferLength, timeout, sendStop);

txBufferIndex = 0;
txBufferLength = 0;
cy_rslt_t result;
if (txBufferLength == 0) {
result = cyhal_i2c_master_write(&i2c_objs[instance], txAddress, txBuffer, 0, timeout, sendStop);
if (result != 0xAA2004 && result != 0xAA2005) {
return 1;
} else {
return 0;
}
} else {
result = cyhal_i2c_master_write(&i2c_objs[instance], txAddress, txBuffer, txBufferLength, timeout, sendStop);
txBufferIndex = 0;
txBufferLength = 0;
}

return (result == CY_RSLT_SUCCESS) ? 0 : 1; // Return 0 on success, 1 on failure
if (result != CY_RSLT_SUCCESS) {
// Handle specific error codes
switch (result) {
case 0xAA2004:
Serial.println("Error: No device attached to SDA/SCL, but they are pulled-up.");
break;
case 0xAA2003:
Serial.println("Error: No device attached to SDA/SCL, and they are not pulled-up.");
break;
case CYHAL_I2C_RSLT_ERR_INVALID_PIN:
Serial.println("Error: Invalid pin.");
break;
case CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR:
Serial.println("Error: Cannot reach desired data rate.");
break;
case CYHAL_I2C_RSLT_ERR_INVALID_ADDRESS_SIZE:
Serial.println("Error: Invalid address size.");
break;
case CYHAL_I2C_RSLT_ERR_TX_RX_BUFFERS_ARE_EMPTY:
Serial.println("Error: TX/RX buffers are empty.");
break;
case CYHAL_I2C_RSLT_ERR_PREVIOUS_ASYNCH_PENDING:
Serial.println("Error: Previous async operation is pending.");
break;
case CYHAL_I2C_RSLT_ERR_PM_CALLBACK:
Serial.println("Error: Failed to register I2C PM callback.");
break;
case CYHAL_I2C_RSLT_ERR_ABORT_ASYNC_TIMEOUT:
Serial.println("Error: Abort async operation timed out.");
break;
case CYHAL_I2C_RSLT_ERR_BAD_ARGUMENT:
Serial.println("Error: Bad argument provided.");
break;
case CYHAL_I2C_RSLT_ERR_UNSUPPORTED:
Serial.println("Error: Unsupported by this device.");
break;
case CYHAL_I2C_RSLT_ERR_NO_ACK:
Serial.println("Error: No ACK received.");
break;
case CYHAL_I2C_RSLT_ERR_CMD_ERROR:
Serial.println("Error: Command error.");
break;
case CYHAL_I2C_RSLT_ERR_BUFFERS_NULL_PTR:
Serial.println("Error: RX or TX buffer is not initialized.");
break;
case CYHAL_I2C_RSLT_WARN_TIMEOUT:
Serial.println("Warning: Timeout.");
break;
case CYHAL_I2C_RSLT_WARN_DEVICE_BUSY:
Serial.println("Warning: Device busy.");
break;
default:
Serial.print("I2C transfer failed with return code: ");
Serial.println(result, HEX);
break;
}
return 1; // Return 1 on failure
}

return 0; // Return 0 on success
}

uint8_t TwoWire::endTransmission(void) {
return endTransmission(true);
}

size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) {
if(quantity > BUFFER_LENGTH){
if (quantity > BUFFER_LENGTH) {
quantity = BUFFER_LENGTH;
}
cy_rslt_t result = cyhal_i2c_master_read(&i2c_obj, address, rxBuffer, quantity, timeout, stopBit);
if(result == CY_RSLT_SUCCESS){
cy_rslt_t result = cyhal_i2c_master_read(&i2c_objs[instance], address, rxBuffer, quantity, timeout, stopBit);
if (result == CY_RSLT_SUCCESS) {
rxBufferIndex = 0;
rxBufferLength = quantity;
return quantity;
}
else{
} else {
return 0; // Return 0 on failure of read operation
}
}
Expand All @@ -120,74 +199,70 @@ size_t TwoWire::requestFrom(uint8_t address, size_t len) {
}

size_t TwoWire::write(uint8_t data) {
/* Check if buffer is full */
if(txBufferLength >= BUFFER_LENGTH){
return 0;
}
/* Check if buffer is full */
if (txBufferLength >= BUFFER_LENGTH) {
return 0;
}

/* Put byte in txBuffer */
txBuffer[txBufferIndex] = data;
txBufferIndex++;
/* Put byte in txBuffer */
txBuffer[txBufferIndex] = data;
txBufferIndex++;

/* Update buffer length */
txBufferLength = txBufferIndex;
return 1;
/* Update buffer length */
txBufferLength = txBufferIndex;
return 1;
}

size_t TwoWire::write(const uint8_t * data, size_t quantity) {
for(size_t i = 0; i < quantity; i++){
write(*(data + i));
}
for (size_t i = 0; i < quantity; i++) {
write(*(data + i));
}

return quantity;
return quantity;
}

int TwoWire::available(void) {

return rxBufferLength - rxBufferIndex;
}

int TwoWire::read(void) {
if(rxBufferIndex < rxBufferLength)
{
if (rxBufferIndex < rxBufferLength) {
return rxBuffer[rxBufferIndex++];
}
return -1;
}

int TwoWire::peek(void) {
if(rxBufferIndex < rxBufferLength)
{
if (rxBufferIndex < rxBufferLength) {
return rxBuffer[rxBufferIndex];
}
return -1;
}

void TwoWire::onReceive(void (*function)(int)) {
user_onReceive = function;
cyhal_i2c_enable_event(&i2c_obj, CYHAL_I2C_SLAVE_READ_EVENT, 7, true);
user_onReceive = function;
cyhal_i2c_enable_event(&i2c_objs[instance], CYHAL_I2C_SLAVE_WRITE_EVENT, 7, true);
}

void TwoWire::onRequest(void (*function)(void)) {
user_onRequest = function;
cyhal_i2c_enable_event(&i2c_obj, CYHAL_I2C_SLAVE_WRITE_EVENT, 7, true);
cyhal_i2c_enable_event(&i2c_objs[instance], CYHAL_I2C_SLAVE_READ_EVENT, 7, true);
}

void TwoWire::i2c_event_handler(void *callback_arg, cyhal_i2c_event_t event) {
TwoWire *instance = static_cast<TwoWire*>(callback_arg);
if (event == CYHAL_I2C_SLAVE_READ_EVENT && instance->user_onReceive) {
if (event == CYHAL_I2C_SLAVE_WRITE_EVENT && instance->user_onReceive) {
instance->user_onReceive(instance->available());
} else if (event == CYHAL_I2C_SLAVE_WRITE_EVENT && instance->user_onRequest) {
} else if (event == CYHAL_I2C_SLAVE_READ_EVENT && instance->user_onRequest) {
instance->user_onRequest();
}
}

#if I2C_HOWNMANY > 0
TwoWire Wire = TwoWire(I2C1_SDA_PIN, I2C1_SCL_PIN);
TwoWire Wire = TwoWire(I2C1_SDA_PIN, I2C1_SCL_PIN, 0);
#endif

#if I2C_HOWNMANY > 1
TwoWire Wire1 = TwoWire(I2C2_SDA_PIN, I2C2_SCL_PIN);
#endif

TwoWire Wire1 = TwoWire(I2C2_SDA_PIN, I2C2_SCL_PIN, 1);
#endif
Loading

0 comments on commit c892489

Please sign in to comment.