elbear_arduino_bsp/libraries/Wire/src/Wire.cpp
klassents 766b7b32ea Обновление до версии 0.3.0
- обновлен elbear_fw_bootloader - добавлена проверка контрольной суммы каждой строки hex файла.
- в модуль работы с АЦП добавлена функция analogReadResolution(). Функция analogRead() теперь возвращает усредненное по 10 измерениям значение.
- общая функция обработки прерываний перенесена в память RAM. Обработчики прерываний модулей External Interrupts и Advanced I/O (функция tone()) так же перенесены в память RAM для увеличения скорости выполнения кода.
- в пакет добавлены библиотеки EEPROM, Servo, SoftSerial, NeoPixel, MFRC522 адаптированные для работы с платой Elbear Ace-Uno.
- добавлено описание особенностей работы с пакетом
2024-10-17 08:27:39 +03:00

319 lines
7.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern "C"
{
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "utility/twi.h"
}
#include "Wire.h"
// Initialize Class Variables
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
uint8_t TwoWire::rxBufferIndex = 0;
uint8_t TwoWire::rxBufferLength = 0;
uint8_t TwoWire::txAddress = 0; // 7 bits without shift
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
uint8_t TwoWire::txBufferIndex = 0;
uint8_t TwoWire::txBufferLength = 0;
uint8_t TwoWire::transmitting = 0;
uint8_t TwoWire::slaveAddress = 0; // 7 bits without shift in slave mode
void (*TwoWire::user_onRequest)(void);
void (*TwoWire::user_onReceive)(int);
// Constructors
TwoWire::TwoWire()
{
}
// --------------------------- Public Methods --------------------------- //
void TwoWire::begin(void)
{
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
twi_init(slaveAddress);
twi_attachSlaveTxEvent(onRequestService); // default callback must exist
twi_attachSlaveRxEvent(onReceiveService); // default callback must exist
}
void TwoWire::begin(uint8_t address)
{
slaveAddress = address;
begin();
}
void TwoWire::begin(int address)
{
begin((uint8_t)address);
}
void TwoWire::end(void)
{
flush(); // wait for transmission complete
twi_deinit();
slaveAddress = 0;
}
void TwoWire::setClock(uint32_t clock)
{
if (twi_setFrequency(clock, false) != I2C_OK)
ErrorMsgHandler("Wire.setClock(): invalid frequency or Wire was not begin");
}
// ----------------------------- request ----------------------------- //
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop)
{
if (isize > 0)
{
// send internal register address if needed
beginTransmission(address); // save slave address
// the maximum size of internal address is 3 bytes
if (isize > 3) isize = 3;
// write internal register address - most significant byte first
while (isize-- > 0)
write((uint8_t)(iaddress >> (isize*8))); // write data to txBuf
endTransmission(false); // transmit data without stop generation
}
// clamp to buffer length
if(quantity > BUFFER_LENGTH)
quantity = BUFFER_LENGTH;
// perform blocking read into buffer
uint8_t read = twi_masterReadFrom(address, rxBuffer, quantity, sendStop);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop);
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
}
// ----------------------------- Transmission ----------------------------- //
void TwoWire::beginTransmission(uint8_t address)
{
// indicate that we are transmitting
transmitting = 1;
// set address of targeted slave whithout shift
txAddress = address;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::beginTransmission(int address)
{
beginTransmission((uint8_t)address);
}
// Calling endTransmission(false) allows a sketch to
// perform a repeated start.
// WARNING: Nothing in the library keeps track of whether
// the bus tenure has been properly ended with a STOP. It
// is very possible to leave the bus in a hung state if
// no call to endTransmission(true) is made. Some I2C
// devices will behave oddly if they do not see a STOP.
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
uint8_t ret = I2C_ERROR;
if (transmitting)
{
// transmit buffer (blocking)
ret = twi_masterWriteTo(txAddress, txBuffer, txBufferLength, sendStop);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
}
return ret;
}
// This provides backwards compatibility with the original
// definition, and expected behaviour, of endTransmission
uint8_t TwoWire::endTransmission(void)
{
return endTransmission((uint8_t)true);
}
// ----------------------------- Write ----------------------------- //
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
size_t TwoWire::write(uint8_t data)
{
size_t ret = 1;
if (transmitting)
{
// in master transmitter mode
// don't bother if buffer is full
if(txBufferLength >= BUFFER_LENGTH)
{
setWriteError();
return 0;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
}
else
{
// in slave send mode - reply to master
if (twi_slaveWrite(&data, 1) != I2C_OK)
ret = 0;
}
return ret;
}
/**
* @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 ret = quantity;
if (transmitting)
{
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i)
write(data[i]);
}
else
{
// in slave send mode - reply to master
if (twi_slaveWrite((uint8_t *)data, quantity) != I2C_OK)
ret = 0;
}
return ret;
}
// ----------------------------- Stream func ----------------------------- //
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::available(void)
{
return rxBufferLength - rxBufferIndex;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::read(void)
{
int value = -1;
// get each successive byte on each call
if (rxBufferIndex < rxBufferLength)
{
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::peek(void)
{
int value = -1;
if (rxBufferIndex < rxBufferLength)
value = rxBuffer[rxBufferIndex];
return value;
}
void TwoWire::flush(void)
{
// we use blocking transactions, so we won't get here until the reception/transmission is complete
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
txAddress = 0;
}
// ----------------------------- Events ----------------------------- //
// behind the scenes function that is called when data is received
void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
{
// don't bother if user hasn't registered a callback
if(!user_onReceive)
return;
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
memcpy(rxBuffer, inBytes, numBytes);
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);
}
// behind the scenes function that is called when data is requested
void TwoWire::onRequestService(void)
{
// don't bother if user hasn't registered a callback
if(user_onRequest)
user_onRequest(); // alert user program
}
// sets function called on slave write
void TwoWire::onReceive( void (*function)(int) )
{
user_onReceive = function;
}
// sets function called on slave read
void TwoWire::onRequest( void (*function)(void) )
{
user_onRequest = function;
}
// С function for trap handler
extern "C" void __attribute__((optimize("O3"))) wire_interrupt_handler(void)
{
twi_interruptHandler();
}
// ----------------------------- Preinstantiate Objects ----------------------------- //
TwoWire Wire = TwoWire( );