Skip to content

Add new methods to Wire library #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions cores/arduino/stm32/twi.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ void i2c_setTiming(i2c_t *obj, uint32_t frequency)
* @retval read status
*/
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address,
uint8_t *data, uint8_t size)
uint8_t *data, uint16_t size)

{
i2c_status_e ret = I2C_ERROR;
Expand All @@ -375,17 +375,24 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address,
* @param obj : pointer to i2c_t structure
* @param data: pointer to data to be write
* @param size: number of bytes to be write.
* @retval none
* @retval status
*/
void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size)
i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size)
{
uint8_t i = 0;

// Protection to not override the TxBuffer
if(size > I2C_TXRX_BUFFER_SIZE) {
return I2C_ERROR;
}

// Check the communication status
for(i = 0; i < size; i++) {
obj->i2cTxRxBuffer[i] = *(data+i);
obj->i2cTxRxBufferSize++;
}

return I2C_OK;
}

/**
Expand All @@ -396,7 +403,7 @@ void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size)
* @param size: number of bytes to be read.
* @retval read status
*/
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size)
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size)
{
i2c_status_e ret = I2C_ERROR;
uint32_t tickstart = HAL_GetTick();
Expand Down
6 changes: 3 additions & 3 deletions cores/arduino/stm32/twi.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode,
uint32_t ownAddress, uint8_t master);
void i2c_deinit(i2c_t *obj);
void i2c_setTiming(i2c_t *obj, uint32_t frequency);
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size);
void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size);
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size);
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size);
i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size);
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size);

i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr,uint32_t trials);

Expand Down
13 changes: 6 additions & 7 deletions libraries/Wire/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
# Methods and Functions (KEYWORD2)
#######################################

begin KEYWORD2
setClock KEYWORD2
begin KEYWORD2
setClock KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
onReceive KEYWORD2
onRequest KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
onReceive KEYWORD2
onRequest KEYWORD2

#######################################
# Instances (KEYWORD2)
Expand All @@ -28,4 +28,3 @@ Wire1 KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

6 changes: 3 additions & 3 deletions libraries/Wire/library.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name=Wire
version=1.0
author=Arduino
maintainer=Arduino <[email protected]>
sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For Arduino DUE only.
author=Arduino, Wi6Labs
maintainer=stm32duino
sentence=Allows the communication between devices or sensors connected via Two Wire (I2C) Interface Bus.
paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/Wire
Expand Down
97 changes: 81 additions & 16 deletions libraries/Wire/Wire.cpp → libraries/Wire/src/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ extern "C" {
#include "Wire.h"

// Initialize Class Variables //////////////////////////////////////////////////
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
uint8_t *TwoWire::rxBuffer = nullptr;
uint8_t TwoWire::rxBufferIndex = 0;
uint8_t TwoWire::rxBufferLength = 0;

uint8_t TwoWire::txAddress = 0;
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
uint8_t *TwoWire::txBuffer = nullptr;
uint8_t TwoWire::txBufferIndex = 0;
uint8_t TwoWire::txBufferLength = 0;

Expand Down Expand Up @@ -66,9 +66,11 @@ void TwoWire::begin(uint8_t address)
{
rxBufferIndex = 0;
rxBufferLength = 0;
rxBuffer = resetBuffer(rxBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if null raise en error ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error is raised later if rx/txBuffer is NULL


txBufferIndex = 0;
txBufferLength = 0;
txBuffer = resetBuffer(txBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error is raised later if rx/txBuffer is NULL


transmitting = 0;

Expand Down Expand Up @@ -97,6 +99,10 @@ void TwoWire::begin(int address)

void TwoWire::end(void)
{
free(txBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if pointer is null before free it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free() accepts null pointer

If ptr is a null pointer, the function does nothing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i've got a doubt ;)

txBuffer = nullptr;
free(rxBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

rxBuffer = nullptr;
i2c_deinit(&_i2c);
}

Expand All @@ -109,6 +115,13 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
{
UNUSED(sendStop);
if (master == true) {
rxBuffer = allocateBuffer(rxBuffer, quantity);
// error if no memory block available to allocate the buffer
if(rxBuffer == nullptr){
setWriteError();
return 0;
}

if (isize > 0) {
// send internal address; this mode allows sending a repeated start to access
// some devices' internal registers. This function is executed by the hardware
Expand All @@ -128,12 +141,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
endTransmission(false);
}

// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
// perform blocking read into buffer
//uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
uint8_t read = 0;
if(I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity))
read = quantity;
Expand Down Expand Up @@ -216,9 +224,15 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
break;
}

//Reduce buffer size to free memory in case of large memory use
if(txBufferLength > BUFFER_LENGTH) {
txBuffer = resetBuffer(txBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raise an errror if null ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be removed in my PR.

}

// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;

// indicate that we are done transmitting
transmitting = 0;
}
Expand All @@ -241,8 +255,9 @@ size_t TwoWire::write(uint8_t data)
{
if(transmitting){
// in master transmitter mode
// don't bother if buffer is full
if(txBufferLength >= BUFFER_LENGTH){
txBuffer = allocateBuffer(txBuffer, txBufferLength + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe not efficient to allocate +1 byte each time - maybe you could go by steps (allocateBuffer(txBuffer, txBufferLength + BUFFER_LENGTH) each time it is needed) because reallocation can be costly in performances?
In that way BUFFER_LENGHT would be used as the "unit" of buffer allocation.

Copy link
Member

@fpistm fpistm Nov 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly call to set first bytes of the data (ex: address).
See fpistm@c4b9f24
In this commit the min size is BUFFER_LENGTH.

// error if no memory block available to allocate the buffer
if(txBuffer == nullptr){
setWriteError();
return 0;
}
Expand All @@ -254,27 +269,38 @@ size_t TwoWire::write(uint8_t data)
}else{
// in slave send mode
// reply to master
i2c_slave_write_IT(&_i2c,&data,1);
if(i2c_slave_write_IT(&_i2c,&data,1) != I2C_OK) {
return 0;
}
}
return 1;
}

// must be called in:
// slave tx event callback
// or after beginTransmission(address)
/**
* @brief This function must be called in slave Tx event callback or after
* beginTransmission() and before endTransmission().
* @param pdata: pointer to the buffer data
* @param quantity: number of bytes to write
* @retval number of bytes ready to write.
*/
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
size_t nb = 0;

if(transmitting){
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i){
write(data[i]);
nb += write(data[i]);
}
return nb;
}else{
// in slave send mode
// reply to master
i2c_slave_write_IT(&_i2c,(uint8_t *)data,quantity);
if(i2c_slave_write_IT(&_i2c, (uint8_t *)data, quantity) == I2C_OK) {
return quantity;
}
}
return quantity;
return 0;
}

// must be called in:
Expand All @@ -296,6 +322,12 @@ int TwoWire::read(void)
if(rxBufferIndex < rxBufferLength){
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;

/* Reduce buffer size to free memory in case of large memory use when no more
data available */
if((rxBufferIndex == rxBufferLength) && (rxBufferLength > BUFFER_LENGTH)) {
rxBuffer = resetBuffer(rxBuffer);
}
}

return value;
Expand All @@ -319,8 +351,10 @@ void TwoWire::flush(void)
{
rxBufferIndex = 0;
rxBufferLength = 0;
rxBuffer = resetBuffer(rxBuffer);
txBufferIndex = 0;
txBufferLength = 0;
txBuffer = resetBuffer(txBuffer);
}

// behind the scenes function that is called when data is received
Expand Down Expand Up @@ -377,6 +411,37 @@ void TwoWire::onRequest( void (*function)(void) )
user_onRequest = function;
}

/**
* @brief Change the size of the buffer.
* @param buffer: pointer to the allocated buffer
* @param length: number of bytes to allocate
* @retval pointer to the new buffer location
*/
uint8_t *TwoWire::allocateBuffer(uint8_t *buffer, size_t length)
{
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
if(length < BUFFER_LENGTH) {
length = BUFFER_LENGTH;
}

buffer = (uint8_t *)realloc(buffer, length * sizeof(uint8_t));
return buffer;
}

/**
* @brief Reset the buffer. Reduce is size if greater than BUFFER_LENGTH.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: is size / its size
comment says that it reduce the size only if greater than BUFFER_LENGHT but code seems to do it unconditionnally

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change in the enhancement

* @param buffer: pointer to the allocated buffer
* @retval pointer to the new buffer location
*/
uint8_t *TwoWire::resetBuffer(uint8_t *buffer)
{
buffer = (uint8_t *)realloc(buffer, BUFFER_LENGTH * sizeof(uint8_t));
if(buffer != nullptr) {
memset(buffer, 0, BUFFER_LENGTH);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case of nullptr, we need to raise an error (no memory ...).
I 'm not sure this is checked after every call to resetBuffer ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked in the R/W function

return buffer;
}

// Preinstantiate Objects //////////////////////////////////////////////////////

TwoWire Wire = TwoWire(); //D14-D15
7 changes: 5 additions & 2 deletions libraries/Wire/Wire.h → libraries/Wire/src/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@
class TwoWire : public Stream
{
private:
static uint8_t rxBuffer[BUFFER_LENGTH];
static uint8_t *rxBuffer;
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;

static uint8_t txAddress;
static uint8_t txBuffer[BUFFER_LENGTH];
static uint8_t *txBuffer;
static uint8_t txBufferIndex;
static uint8_t txBufferLength;

Expand All @@ -56,6 +56,9 @@ class TwoWire : public Stream
static void onRequestService(void);
static void onReceiveService(uint8_t*, int);

uint8_t *allocateBuffer(uint8_t *buffer, size_t length);
uint8_t *resetBuffer(uint8_t *buffer);

public:
TwoWire();
TwoWire(uint8_t sda, uint8_t scl);
Expand Down