Skip to content

Commit

Permalink
some additional changes, lint and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
MX682X committed Nov 14, 2023
1 parent ecd5c8b commit 1d47bd2
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 76 deletions.
14 changes: 14 additions & 0 deletions megaavr/libraries/Wire/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ uint8_t checkPinLevels();
```
This function returns the level of the master TWI pins, depending on the used TWI module and port multiplexer settings. Bit 0 represents SDA line and bit 1 represents SCL line. This is useful on initialisation, where you want to make sure that all devices have their pins ready in open-drain mode. A value of 0x03 indicates that both lines have a HIGH level and the bus is ready.

#### `uint8_t masterTransmit()`
```c++
uint8_t masterTransmit(auto *length, uint8_t *buffer, uint8_t addr, uint8_t sendStop);
```
This functions allows to transmit a buffer of data without having to copy the data to the internal buffer of the library. This allows transmission lengths as long as the RAM size without having to define the TWI_BUFFER_SIZE in the platform.txt. The return value is the same as endTransmission(). length will be overwritten with the actual amount of written bytes.
#### `uint8_t masterReceive()`
```c++
uint8_t masterReceive(auto *length, uint8_t *buffer, uint8_t addr, uint8_t sendStop);
```
This functions allows to receive a buffer of data without having to copy the data from the internal buffer of the library. This allows transmission lengths as long as the RAM size without having to define the TWI_BUFFER_SIZE in the platform.txt. The return value is the same as endTransmission(). length will be overwritten with the actual amount of received bytes.

### Additional New Methods not available on all parts
These new methods are available exclusively for parts with certain specialized hardware; Most full-size parts support enableDualMode (but tinyAVR does not), while only the DA and DB-series parts have the second TWI interface that swapModule requires.
#### `void swapModule()`
Expand Down Expand Up @@ -323,6 +335,8 @@ When the second or third argument was used, `Wire.getIncomingAddress()` should b

If (and only if) the Master and Slave option is selected in the Tools -> Wire mode, the Wire interface can be enabled for both master and slave. Even when Dual Mode is used, the correct option must still be selected to enable acting as both master and slave.

The Arduino library defines the array lengths as `BUFFER_LENGTH`, however, this define name might create conflicts, as the name is quite arbitrary. The newest library version uses the name `TWI_BUFFER_LENGTH` instead. However, it is still backwards compatible, as the `BUFFER_LENGTH` is still applied, but a compiler warning is generated to notify about the change.

#### `void setClock()`
```c++
void setClock(uint32_t);
Expand Down
6 changes: 6 additions & 0 deletions megaavr/libraries/Wire/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#######################################
# Datatypes (KEYWORD1)
#######################################
twi_buf_index_t KEYWORD1
TWI_t KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
Expand All @@ -18,13 +20,17 @@ setClock KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
masterTransmit KEYWORD2
masterReceive KEYWORD2
onReceive KEYWORD2
onRequest KEYWORD2
getIncomingAddress KEYWORD2
getBytesRead KEYWORD2
slaveTransactionOpen KEYWORD2
checkPinLevels KEYWORD2
specialConfig KEYWORD2
enableDualMode KEYWORD2
returnError KEYWORD2
WIRE_SDA_HOLD_OFF KEYWORD2
WIRE_SDA_HOLD_50 KEYWORD2
WIRE_SDA_HOLD_300 KEYWORD2
Expand Down
2 changes: 1 addition & 1 deletion megaavr/libraries/Wire/library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Wire
version=2.0.10
version=2.0.11
author=@MX682X, with contributions by @SpenceKonde. Original library, mostly reimplemented, was by Arduino.
maintainer=Spence Konde <spencekonde@gmail.com>
sentence=This library allows you to communicate with I2C devices, acting as either a master, slave, or both master and slave.
Expand Down
93 changes: 42 additions & 51 deletions megaavr/libraries/Wire/src/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Modified 2019-2021 by Spence Konde for megaTinyCore and DxCore.
This version is part of megaTinyCore and DxCore; it is not expected
to work with other hardware or cores without modifications.
Modified extensively 2021-22 by MX682X for megaTinyCore and DxCore.
Modified extensively 2021-23 by MX682X for megaTinyCore and DxCore.
Added Support for Simultaneous host/client, dual mode and Wire1.
*/
// *INDENT-OFF* astyle wants this file to be completely unreadable with no indentation for the many preprocessor conditionals!
Expand Down Expand Up @@ -333,8 +333,8 @@ void TwoWire::begin(uint8_t address, bool receive_broadcast, uint8_t second_addr
return;
}
}


#if defined(TWI_MANDS) // Check if the user wants to use Master AND Slave
if (_bools._clientEnabled == 1) { // Master is allowed to be enabled, don't re-enable the client though
return;
Expand Down Expand Up @@ -620,39 +620,40 @@ uint8_t TwoWire::specialConfig( __attribute__ ((unused)) bool smbuslvl, __attrib
*@brief masterReceive sends a host READ with the specified client address
*
* This function will read an arbitrary number of bytes from the TWI module
* and store them into the specified buffer. This allows the user to use
* and store them into the specified buffer. This allows the user to use
* custom sized buffers and avoids extra copy operations through read.
*
*@param auto length - amount of bytes to be read (first arg so it is placed in r24:r25)
*@param uint8_t addr - the address of the client (7-bit)
*@param auto* length - pointer to a 8/16 bit variable containing the length. Will be overwritten with the amount of received bytes
*@param uint8_t* buffer - pointer to the memory area to be written upon.
*@param uint8_t addr - the address of the client (7-bit)
*@param uint8_t/bool sendStop - if the transaction should be terminated with a STOP condition
*
*@return auto (uint8_t/uint16_t) - depends on the usage
*@retval amount of bytes that were actually read. If 0, no read took place due to a bus error.
*@return uint8_t
*@retval error code, see masterTrasnmit
*/


auto TwoWire::masterReceive(auto length, uint8_t addr, uint8_t* buffer, uint8_t sendStop) {
uint8_t TwoWire::masterReceive(auto *length, uint8_t *buffer, uint8_t addr, uint8_t sendStop) {
TWI_t *module = _module;
__asm__ __volatile__("\n\t" : "+z"(module));

TWIR_INIT_ERROR; // local variable for errors
auto dataRead = 0;
auto dataToRead = *length;

uint8_t currentSM;
uint8_t currentStatus;
uint8_t state = 0;
#if defined (TWI_TIMEOUT_ENABLE)
uint16_t timeout = (F_CPU/1000);
#endif

while (true) {
currentStatus = module->MSTATUS;
currentSM = currentStatus & TWI_BUSSTATE_gm; // get the current mode of the state machine

if (currentSM == TWI_BUSSTATE_UNKNOWN_gc) {
TWIR_SET_ERROR(TWI_ERR_UNINITIALIZED);
return dataRead;
TWIR_SET_ERROR(TWI_ERR_UNINIT);
break;
}

#if defined(TWI_TIMEOUT_ENABLE)
Expand All @@ -667,13 +668,12 @@ auto TwoWire::masterReceive(auto length, uint8_t addr, uint8_t* buffer, uint8_t
break;
}
#endif

if (currentStatus & TWI_ARBLOST_bm) { // Check for Bus error
TWIR_SET_ERROR(TWI_ERR_BUS_ARB); // set error flag
break; // leave RX loop
}


if (currentSM != TWI_BUSSTATE_BUSY_gc) {
if (state == 0x00) {
module->MADDR = ADD_READ_BIT(addr); // Send Address with read bit
Expand All @@ -683,17 +683,16 @@ auto TwoWire::masterReceive(auto length, uint8_t addr, uint8_t* buffer, uint8_t
#endif
} else {
if (currentStatus & TWI_WIF_bm) {
TWIR_SET_ERROR(TWI_ERR_RXACK); // set error flag
TWIR_SET_ERROR(TWI_ERR_ACK_ADR); // set error flag
module->MCTRLB = TWI_MCMD_STOP_gc; // free the bus
break;
} else if (currentStatus & TWI_RIF_bm) {
*buffer = module->MDATA;
buffer++;
dataRead++;
#if defined (TWI_TIMEOUT_ENABLE)
timeout = (F_CPU/1000); // reset timeout
#endif
if (dataRead < length) {
if (--dataToRead != 0) {
module->MCTRLB = TWI_MCMD_RECVTRANS_gc; // send an ACK so the Slave so it can send the next byte
} else {
if (sendStop != 0) {
Expand All @@ -707,10 +706,8 @@ auto TwoWire::masterReceive(auto length, uint8_t addr, uint8_t* buffer, uint8_t
}
}
}
#if defined(TWI_READ_ERROR_ENABLED) && defined(TWI_ERROR_ENABLED)
_errors = TWIR_GET_ERROR; // save error flags
#endif
return dataRead;
*length -= dataToRead;
return TWIR_GET_ERROR;
}


Expand Down Expand Up @@ -741,11 +738,12 @@ twi_buf_index_t TwoWire::requestFrom(uint8_t address, twi_buf_index_t quantity
}

_clientAddress = address << 1;

twi_buf_index_t count = masterReceive(quantity, _clientAddress, _hostBuffer, sendStop);
_bytesToReadWrite = count; // for available/read/peek
_bytesToReadWrite = quantity; // for available/read/peek
_bytesReadWritten = 0;
return count;

masterReceive(&_bytesToReadWrite, _hostBuffer, _clientAddress, sendStop); // We ignore the error that gets returned

return _bytesToReadWrite;
}


Expand Down Expand Up @@ -805,8 +803,7 @@ void TwoWire::beginTransmission(uint8_t address) {
*/
uint8_t TwoWire::endTransmission(bool sendStop) {
// transmit (blocking)

return masterTransmit(_bytesToReadWrite, _clientAddress, _hostBuffer, sendStop);
return masterTransmit(&_bytesToReadWrite, _hostBuffer, _clientAddress, sendStop);
}


Expand All @@ -815,37 +812,38 @@ uint8_t TwoWire::endTransmission(bool sendStop) {
*@brief masterTransmit sends a host WRITE with the specified client address
*
* This function will write an arbitrary number of bytes to the TWI module
* and read the data from the specified buffer. This allows the user to use
* and read the data from the specified buffer. This allows the user to use
* custom sized buffers and avoids extra copy operations through write.
*
*@param auto length - amount of bytes to be read (first arg so it is placed in r24:r25)
*@param uint8_t addr - the address of the client (7-bit)
*@param auto* length - pointer to a 8/16 bit variable containing the length. Will be overwritten with the amount of written bytes
*@param uint8_t* buffer - pointer to the memory area to be read from.
*@param uint8_t addr - the address of the client (7-bit)
*@param uint8_t/bool sendStop - if the transaction should be terminated with a STOP condition
*
*@return uint8_t
*@retval errors (see endTransmission)
*/
uint8_t TwoWire::masterTransmit(auto length, uint8_t addr, uint8_t* buffer, uint8_t sendStop) {
uint8_t TwoWire::masterTransmit(auto *length, uint8_t *buffer, uint8_t addr, uint8_t sendStop) {
TWI_t* module = _module;
__asm__ __volatile__("\n\t" : "+z"(module));

TWI_INIT_ERROR;
uint8_t currentSM;
uint8_t currentStatus;
uint8_t stat = 0;
auto dataToWrite = *length;
#if defined (TWI_TIMEOUT_ENABLE)
uint16_t timeout = (F_CPU/1000);
#endif

if ((module->MCTRLA & TWI_ENABLE_bm) == 0x00) { // If the module is disabled, abort
return TWI_ERR_UNINIT;
}

while (true) {
currentStatus = module->MSTATUS;
currentSM = currentStatus & TWI_BUSSTATE_gm; // get the current mode of the state machine

if (currentSM == TWI_BUSSTATE_UNKNOWN_gc) { // If the bus was not initialized
return TWI_ERR_UNINIT; // abort
}
Expand All @@ -867,7 +865,7 @@ uint8_t TwoWire::masterTransmit(auto length, uint8_t addr, uint8_t* buffer, uint
TWI_SET_ERROR(TWI_ERR_BUS_ARB); // set error flag
break; // leave TX loop
}

if (currentSM != TWI_BUSSTATE_BUSY_gc) { // Undefined was excluded, so make sure it's IDLE or OWNER
if (stat == 0x00) { // At the start, we send the ADDR
module->MADDR = ADD_WRITE_BIT(addr); // clear bit 0
Expand All @@ -879,17 +877,17 @@ uint8_t TwoWire::masterTransmit(auto length, uint8_t addr, uint8_t* buffer, uint
if (currentStatus & TWI_WIF_bm) { // ADDR was sent, check for completed write
if (currentStatus & TWI_RXACK_bm) { // got a NACK, see how much was written
if (stat & 0x02) { // bit 1 set, data was already sent
if (length != 0) // the client may send an ACK at the end. If we
if (dataToWrite != 0) // the client may send an ACK at the end. If we
TWI_SET_ERROR(TWI_ERR_ACK_DAT); // transferred everything, we can ignore the NACK
} else { // otherwise, no data sent, ADDR NACK
TWI_SET_ERROR(TWI_ERR_ACK_ADR);
}
break;
} else { // No NACK on write
if (length != 0) { // check if there is data to be written
if (dataToWrite != 0) { // check if there is data to be written
module->MDATA = *buffer; // Writing to the register to send data
buffer++;
length--;
dataToWrite--;
stat |= 0x02; // remember that we've sent data
#if defined (TWI_TIMEOUT_ENABLE)
timeout = (F_CPU/1000); // reset timeout
Expand All @@ -903,7 +901,7 @@ uint8_t TwoWire::masterTransmit(auto length, uint8_t addr, uint8_t* buffer, uint
} /* currentSM != TWI_BUSSTATE_BUSY_gc */
} /* while */


*length -= dataToWrite;
if ((sendStop != 0) || (TWI_ERR_SUCCESS != TWI_GET_ERROR)) {
module->MCTRLB = TWI_MCMD_STOP_gc; // Send STOP
}
Expand Down Expand Up @@ -1285,7 +1283,7 @@ void TwoWire::deselectSlaveBuffer(void) {



void TwoWire::HandleSlaveIRQ(TwoWire* wire_s) {
void TwoWire::HandleSlaveIRQ(TwoWire *wire_s) {
if (wire_s == NULL) {
return;
}
Expand Down Expand Up @@ -1314,7 +1312,7 @@ void TwoWire::HandleSlaveIRQ(TwoWire* wire_s) {


if (clientStatus & TWI_APIF_bm) { // Address/Stop Bit set

if ((*head) > 0) { // At this point, we have either a START, REPSTART or a STOP
if (wire_s->user_onReceive != NULL) { // at START, head should be 0, as it was set so on the last STOP
wire_s->user_onReceive((*head)); // otherwise, we notify the use sketch, as we have an REPSTART/STOP
Expand Down Expand Up @@ -1345,7 +1343,7 @@ void TwoWire::HandleSlaveIRQ(TwoWire* wire_s) {
}
} else { // Stop bit set
popSleep();

(*head) = 0; // clear whatever might be left due errors
(*tail) = 0;
action = TWI_SCMD_COMPTRANS_gc; // "Wait for any Start (S/Sr) condition"
Expand Down Expand Up @@ -1416,13 +1414,6 @@ void TwoWire::onRequest(void (*function)(void)) {
}


#if defined(TWI_READ_ERROR_ENABLED) && defined(TWI_ERROR_ENABLED)
uint8_t TwoWire::returnError() {
return vars._errors;
}
#endif


/**
*@brief TWI0 Slave Interrupt vector
*/
Expand Down
Loading

0 comments on commit 1d47bd2

Please sign in to comment.