Merge pull request #137 from adafruit/genericdevice
add generic device for non-standard transports
This commit is contained in:
commit
cc66c422eb
10 changed files with 491 additions and 16 deletions
|
|
@ -88,6 +88,26 @@ Adafruit_BusIO_Register::Adafruit_BusIO_Register(
|
||||||
_width = width;
|
_width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Create a register we access over a GenericDevice
|
||||||
|
* @param genericdevice Generic device to use
|
||||||
|
* @param reg_addr Register address we will read/write
|
||||||
|
* @param width Width of the register in bytes (1-4)
|
||||||
|
* @param byteorder Byte order of register data (LSBFIRST or MSBFIRST)
|
||||||
|
* @param address_width Width of the register address in bytes (1 or 2)
|
||||||
|
*/
|
||||||
|
Adafruit_BusIO_Register::Adafruit_BusIO_Register(
|
||||||
|
Adafruit_GenericDevice *genericdevice, uint16_t reg_addr, uint8_t width,
|
||||||
|
uint8_t byteorder, uint8_t address_width) {
|
||||||
|
_i2cdevice = nullptr;
|
||||||
|
_spidevice = nullptr;
|
||||||
|
_genericdevice = genericdevice;
|
||||||
|
_addrwidth = address_width;
|
||||||
|
_address = reg_addr;
|
||||||
|
_byteorder = byteorder;
|
||||||
|
_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Write a buffer of data to the register location
|
* @brief Write a buffer of data to the register location
|
||||||
* @param buffer Pointer to data to write
|
* @param buffer Pointer to data to write
|
||||||
|
|
@ -96,17 +116,14 @@ Adafruit_BusIO_Register::Adafruit_BusIO_Register(
|
||||||
* uncheckable)
|
* uncheckable)
|
||||||
*/
|
*/
|
||||||
bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
|
bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
|
||||||
|
|
||||||
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
|
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
|
||||||
(uint8_t)(_address >> 8)};
|
(uint8_t)(_address >> 8)};
|
||||||
|
|
||||||
if (_i2cdevice) {
|
if (_i2cdevice) {
|
||||||
return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
|
return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth);
|
||||||
}
|
}
|
||||||
if (_spidevice) {
|
if (_spidevice) {
|
||||||
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
|
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
|
||||||
// very special case!
|
// very special case!
|
||||||
|
|
||||||
// pass the special opcode address which we set as the high byte of the
|
// pass the special opcode address which we set as the high byte of the
|
||||||
// regaddr
|
// regaddr
|
||||||
addrbuffer[0] =
|
addrbuffer[0] =
|
||||||
|
|
@ -116,7 +133,6 @@ bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
|
||||||
// the address appears to be a byte longer
|
// the address appears to be a byte longer
|
||||||
return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
|
return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
|
if (_spiregtype == ADDRBIT8_HIGH_TOREAD) {
|
||||||
addrbuffer[0] &= ~0x80;
|
addrbuffer[0] &= ~0x80;
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +145,9 @@ bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) {
|
||||||
}
|
}
|
||||||
return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
|
return _spidevice->write(buffer, len, addrbuffer, _addrwidth);
|
||||||
}
|
}
|
||||||
|
if (_genericdevice) {
|
||||||
|
return _genericdevice->writeRegister(addrbuffer, _addrwidth, buffer, len);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,23 +211,20 @@ uint32_t Adafruit_BusIO_Register::read(void) {
|
||||||
uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
|
uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Read a buffer of data from the register location
|
@brief Read a number of bytes from a register into a buffer
|
||||||
* @param buffer Pointer to data to read into
|
@param buffer Buffer to read data into
|
||||||
* @param len Number of bytes to read
|
@param len Number of bytes to read into the buffer
|
||||||
* @return True on successful write (only really useful for I2C as SPI is
|
@return true on successful read, otherwise false
|
||||||
* uncheckable)
|
*/
|
||||||
*/
|
|
||||||
bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
|
bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
|
||||||
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
|
uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF),
|
||||||
(uint8_t)(_address >> 8)};
|
(uint8_t)(_address >> 8)};
|
||||||
|
|
||||||
if (_i2cdevice) {
|
if (_i2cdevice) {
|
||||||
return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
|
return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
|
||||||
}
|
}
|
||||||
if (_spidevice) {
|
if (_spidevice) {
|
||||||
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
|
if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) {
|
||||||
// very special case!
|
// very special case!
|
||||||
|
|
||||||
// pass the special opcode address which we set as the high byte of the
|
// pass the special opcode address which we set as the high byte of the
|
||||||
// regaddr
|
// regaddr
|
||||||
addrbuffer[0] =
|
addrbuffer[0] =
|
||||||
|
|
@ -230,6 +246,9 @@ bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) {
|
||||||
}
|
}
|
||||||
return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
|
return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len);
|
||||||
}
|
}
|
||||||
|
if (_genericdevice) {
|
||||||
|
return _genericdevice->readRegister(addrbuffer, _addrwidth, buffer, len);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#if !defined(SPI_INTERFACES_COUNT) || \
|
#if !defined(SPI_INTERFACES_COUNT) || \
|
||||||
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
|
(defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
|
||||||
|
|
||||||
|
#include <Adafruit_GenericDevice.h>
|
||||||
#include <Adafruit_I2CDevice.h>
|
#include <Adafruit_I2CDevice.h>
|
||||||
#include <Adafruit_SPIDevice.h>
|
#include <Adafruit_SPIDevice.h>
|
||||||
|
|
||||||
|
|
@ -57,6 +58,11 @@ public:
|
||||||
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
|
uint8_t width = 1, uint8_t byteorder = LSBFIRST,
|
||||||
uint8_t address_width = 1);
|
uint8_t address_width = 1);
|
||||||
|
|
||||||
|
Adafruit_BusIO_Register(Adafruit_GenericDevice *genericdevice,
|
||||||
|
uint16_t reg_addr, uint8_t width = 1,
|
||||||
|
uint8_t byteorder = LSBFIRST,
|
||||||
|
uint8_t address_width = 1);
|
||||||
|
|
||||||
bool read(uint8_t *buffer, uint8_t len);
|
bool read(uint8_t *buffer, uint8_t len);
|
||||||
bool read(uint8_t *value);
|
bool read(uint8_t *value);
|
||||||
bool read(uint16_t *value);
|
bool read(uint16_t *value);
|
||||||
|
|
@ -77,6 +83,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Adafruit_I2CDevice *_i2cdevice;
|
Adafruit_I2CDevice *_i2cdevice;
|
||||||
Adafruit_SPIDevice *_spidevice;
|
Adafruit_SPIDevice *_spidevice;
|
||||||
|
Adafruit_GenericDevice *_genericdevice;
|
||||||
Adafruit_BusIO_SPIRegType _spiregtype;
|
Adafruit_BusIO_SPIRegType _spiregtype;
|
||||||
uint16_t _address;
|
uint16_t _address;
|
||||||
uint8_t _width, _addrwidth, _byteorder;
|
uint8_t _width, _addrwidth, _byteorder;
|
||||||
|
|
|
||||||
78
Adafruit_GenericDevice.cpp
Normal file
78
Adafruit_GenericDevice.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
Written with help by Claude!
|
||||||
|
https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c (at this time
|
||||||
|
chats are not shareable :(
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Adafruit_GenericDevice.h"
|
||||||
|
|
||||||
|
/*! @brief Create a Generic device with the provided read/write functions
|
||||||
|
@param read_func Function pointer for reading raw data
|
||||||
|
@param write_func Function pointer for writing raw data
|
||||||
|
@param readreg_func Function pointer for reading registers (optional)
|
||||||
|
@param writereg_func Function pointer for writing registers (optional) */
|
||||||
|
Adafruit_GenericDevice::Adafruit_GenericDevice(
|
||||||
|
busio_genericdevice_read_t read_func,
|
||||||
|
busio_genericdevice_write_t write_func,
|
||||||
|
busio_genericdevice_readreg_t readreg_func,
|
||||||
|
busio_genericdevice_writereg_t writereg_func) {
|
||||||
|
_read_func = read_func;
|
||||||
|
_write_func = write_func;
|
||||||
|
_readreg_func = readreg_func;
|
||||||
|
_writereg_func = writereg_func;
|
||||||
|
_begun = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Initializes the device
|
||||||
|
@return true if initialization was successful, otherwise false */
|
||||||
|
bool Adafruit_GenericDevice::begin(void) {
|
||||||
|
_begun = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Write a buffer of data
|
||||||
|
@param buffer Pointer to buffer of data to write
|
||||||
|
@param len Number of bytes to write
|
||||||
|
@return true if write was successful, otherwise false */
|
||||||
|
bool Adafruit_GenericDevice::write(const uint8_t *buffer, size_t len) {
|
||||||
|
if (!_begun)
|
||||||
|
return false;
|
||||||
|
return _write_func(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Read data into a buffer
|
||||||
|
@param buffer Pointer to buffer to read data into
|
||||||
|
@param len Number of bytes to read
|
||||||
|
@return true if read was successful, otherwise false */
|
||||||
|
bool Adafruit_GenericDevice::read(uint8_t *buffer, size_t len) {
|
||||||
|
if (!_begun)
|
||||||
|
return false;
|
||||||
|
return _read_func(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Read from a register location
|
||||||
|
@param addr_buf Buffer containing register address
|
||||||
|
@param addrsiz Size of register address in bytes
|
||||||
|
@param buf Buffer to store read data
|
||||||
|
@param bufsiz Size of data to read in bytes
|
||||||
|
@return true if read was successful, otherwise false */
|
||||||
|
bool Adafruit_GenericDevice::readRegister(uint8_t *addr_buf, uint8_t addrsiz,
|
||||||
|
uint8_t *buf, uint16_t bufsiz) {
|
||||||
|
if (!_begun || !_readreg_func)
|
||||||
|
return false;
|
||||||
|
return _readreg_func(addr_buf, addrsiz, buf, bufsiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @brief Write to a register location
|
||||||
|
@param addr_buf Buffer containing register address
|
||||||
|
@param addrsiz Size of register address in bytes
|
||||||
|
@param buf Buffer containing data to write
|
||||||
|
@param bufsiz Size of data to write in bytes
|
||||||
|
@return true if write was successful, otherwise false */
|
||||||
|
bool Adafruit_GenericDevice::writeRegister(uint8_t *addr_buf, uint8_t addrsiz,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint16_t bufsiz) {
|
||||||
|
if (!_begun || !_writereg_func)
|
||||||
|
return false;
|
||||||
|
return _writereg_func(addr_buf, addrsiz, buf, bufsiz);
|
||||||
|
}
|
||||||
50
Adafruit_GenericDevice.h
Normal file
50
Adafruit_GenericDevice.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef ADAFRUIT_GENERICDEVICE_H
|
||||||
|
#define ADAFRUIT_GENERICDEVICE_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
typedef bool (*busio_genericdevice_read_t)(uint8_t *buffer, size_t len);
|
||||||
|
typedef bool (*busio_genericdevice_write_t)(const uint8_t *buffer, size_t len);
|
||||||
|
typedef bool (*busio_genericdevice_readreg_t)(uint8_t *addr_buf,
|
||||||
|
uint8_t addrsiz, uint8_t *buf,
|
||||||
|
uint16_t bufsiz);
|
||||||
|
typedef bool (*busio_genericdevice_writereg_t)(uint8_t *addr_buf,
|
||||||
|
uint8_t addrsiz,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint16_t bufsiz);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Class for communicating with a device via generic read/write functions
|
||||||
|
*/
|
||||||
|
class Adafruit_GenericDevice {
|
||||||
|
public:
|
||||||
|
Adafruit_GenericDevice(
|
||||||
|
busio_genericdevice_read_t read_func,
|
||||||
|
busio_genericdevice_write_t write_func,
|
||||||
|
busio_genericdevice_readreg_t readreg_func = nullptr,
|
||||||
|
busio_genericdevice_writereg_t writereg_func = nullptr);
|
||||||
|
|
||||||
|
bool begin(void);
|
||||||
|
|
||||||
|
bool read(uint8_t *buffer, size_t len);
|
||||||
|
bool write(const uint8_t *buffer, size_t len);
|
||||||
|
bool readRegister(uint8_t *addr_buf, uint8_t addrsiz, uint8_t *buf,
|
||||||
|
uint16_t bufsiz);
|
||||||
|
bool writeRegister(uint8_t *addr_buf, uint8_t addrsiz, const uint8_t *buf,
|
||||||
|
uint16_t bufsiz);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*! @brief Function pointer for reading raw data from the device */
|
||||||
|
busio_genericdevice_read_t _read_func;
|
||||||
|
/*! @brief Function pointer for writing raw data to the device */
|
||||||
|
busio_genericdevice_write_t _write_func;
|
||||||
|
/*! @brief Function pointer for reading a 'register' from the device */
|
||||||
|
busio_genericdevice_readreg_t _readreg_func;
|
||||||
|
/*! @brief Function pointer for writing a 'register' to the device */
|
||||||
|
busio_genericdevice_writereg_t _writereg_func;
|
||||||
|
|
||||||
|
bool _begun; ///< whether we have initialized yet (in case the function needs
|
||||||
|
///< to do something)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADAFRUIT_GENERICDEVICE_H
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Adafruit Bus IO Library [](https://github.com/adafruit/Adafruit_BusIO/actions)
|
# Adafruit Bus IO Library [](https://github.com/adafruit/Adafruit_BusIO/actions)
|
||||||
|
|
||||||
|
|
||||||
This is a helper library to abstract away I2C & SPI transactions and registers
|
This is a helper library to abstract away I2C, SPI, and 'generic transport' (e.g. UART) transactions and registers
|
||||||
|
|
||||||
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||||
|
|
||||||
|
|
|
||||||
0
examples/genericdevice_uartregtest/.uno.test.skip
Normal file
0
examples/genericdevice_uartregtest/.uno.test.skip
Normal file
246
examples/genericdevice_uartregtest/genericdevice_uartregtest.ino
Normal file
246
examples/genericdevice_uartregtest/genericdevice_uartregtest.ino
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
Advanced example of using bstracted transport for reading and writing
|
||||||
|
register data from a UART-based device such as a TMC2209
|
||||||
|
|
||||||
|
Written with help by Claude! https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c
|
||||||
|
(at this time chats are not shareable :(
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Adafruit_BusIO_Register.h"
|
||||||
|
#include "Adafruit_GenericDevice.h"
|
||||||
|
|
||||||
|
// Debugging macros
|
||||||
|
//#define DEBUG_SERIAL Serial
|
||||||
|
|
||||||
|
#ifdef DEBUG_SERIAL
|
||||||
|
#define DEBUG_PRINT(x) DEBUG_SERIAL.print(x)
|
||||||
|
#define DEBUG_PRINTLN(x) DEBUG_SERIAL.println(x)
|
||||||
|
#define DEBUG_PRINT_HEX(x) \
|
||||||
|
do { \
|
||||||
|
if (x < 0x10) \
|
||||||
|
DEBUG_SERIAL.print('0'); \
|
||||||
|
DEBUG_SERIAL.print(x, HEX); \
|
||||||
|
DEBUG_SERIAL.print(' '); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DEBUG_PRINT(x)
|
||||||
|
#define DEBUG_PRINTLN(x)
|
||||||
|
#define DEBUG_PRINT_HEX(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Add IOIN register definition
|
||||||
|
#define TMC2209_IOIN 0x06
|
||||||
|
|
||||||
|
class TMC2209_UART {
|
||||||
|
private:
|
||||||
|
static TMC2209_UART *_instance;
|
||||||
|
Stream *_uart_stream;
|
||||||
|
uint8_t _addr;
|
||||||
|
|
||||||
|
static bool uart_read_impl(uint8_t *buffer, size_t len) {
|
||||||
|
return _instance->uart_read_fn(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uart_write_impl(const uint8_t *buffer, size_t len) {
|
||||||
|
return _instance->uart_write_fn(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uart_readreg_impl(uint8_t *addr_buf, uint8_t addrsiz,
|
||||||
|
uint8_t *data, uint16_t datalen) {
|
||||||
|
return _instance->uart_readreg_fn(addr_buf, addrsiz, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uart_writereg_impl(uint8_t *addr_buf, uint8_t addrsiz,
|
||||||
|
const uint8_t *data, uint16_t datalen) {
|
||||||
|
return _instance->uart_writereg_fn(addr_buf, addrsiz, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uart_read_fn(uint8_t *buffer, size_t len) {
|
||||||
|
uint16_t timeout = 100;
|
||||||
|
while (_uart_stream->available() < len && timeout--) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
if (timeout == 0) {
|
||||||
|
DEBUG_PRINTLN("Read timeout!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINT("Reading: ");
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
buffer[i] = _uart_stream->read();
|
||||||
|
DEBUG_PRINT_HEX(buffer[i]);
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN("");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uart_write_fn(const uint8_t *buffer, size_t len) {
|
||||||
|
DEBUG_PRINT("Writing: ");
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
DEBUG_PRINT_HEX(buffer[i]);
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN("");
|
||||||
|
|
||||||
|
_uart_stream->write(buffer, len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uart_readreg_fn(uint8_t *addr_buf, uint8_t addrsiz, uint8_t *data,
|
||||||
|
uint16_t datalen) {
|
||||||
|
while (_uart_stream->available())
|
||||||
|
_uart_stream->read();
|
||||||
|
|
||||||
|
uint8_t packet[4] = {0x05, uint8_t(_addr << 1), addr_buf[0], 0x00};
|
||||||
|
|
||||||
|
packet[3] = calcCRC(packet, 3);
|
||||||
|
if (!uart_write_impl(packet, 4))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read back echo
|
||||||
|
uint8_t echo[4];
|
||||||
|
if (!uart_read_impl(echo, 4))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Verify echo
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
if (echo[i] != packet[i]) {
|
||||||
|
DEBUG_PRINTLN("Echo mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t response[8]; // sync + 0xFF + reg + 4 data bytes + CRC
|
||||||
|
if (!uart_read_impl(response, 8))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Verify response
|
||||||
|
if (response[0] != 0x05) {
|
||||||
|
DEBUG_PRINTLN("Invalid sync byte");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify 0xFF address byte
|
||||||
|
if (response[1] != 0xFF) {
|
||||||
|
DEBUG_PRINTLN("Invalid reply address");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify register address matches our request
|
||||||
|
if (response[2] != addr_buf[0]) {
|
||||||
|
DEBUG_PRINTLN("Register mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify CRC
|
||||||
|
uint8_t crc = calcCRC(response, 7); // Calculate CRC of all but last byte
|
||||||
|
if (crc != response[7]) {
|
||||||
|
DEBUG_PRINTLN("CRC mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the data bytes
|
||||||
|
memcpy(data, &response[3], 4);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uart_writereg_fn(uint8_t *addr_buf, uint8_t addrsiz, const uint8_t *data,
|
||||||
|
uint16_t datalen) {
|
||||||
|
while (_uart_stream->available())
|
||||||
|
_uart_stream->read();
|
||||||
|
|
||||||
|
uint8_t packet[8] = {0x05,
|
||||||
|
uint8_t(_addr << 1),
|
||||||
|
uint8_t(addr_buf[0] | 0x80),
|
||||||
|
data[0],
|
||||||
|
data[1],
|
||||||
|
data[2],
|
||||||
|
data[3],
|
||||||
|
0x00};
|
||||||
|
|
||||||
|
packet[7] = calcCRC(packet, 7);
|
||||||
|
if (!uart_write_impl(packet, 8))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read and verify echo
|
||||||
|
uint8_t echo[8];
|
||||||
|
if (!uart_read_impl(echo, 8))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Verify echo matches what we sent
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
if (echo[i] != packet[i]) {
|
||||||
|
DEBUG_PRINTLN("Write echo mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t calcCRC(uint8_t *data, uint8_t length) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
uint8_t currentByte = data[i];
|
||||||
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
|
if ((crc >> 7) ^ (currentByte & 0x01)) {
|
||||||
|
crc = (crc << 1) ^ 0x07;
|
||||||
|
} else {
|
||||||
|
crc = crc << 1;
|
||||||
|
}
|
||||||
|
currentByte = currentByte >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TMC2209_UART(Stream *serial, uint8_t addr)
|
||||||
|
: _uart_stream(serial), _addr(addr) {
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Adafruit_GenericDevice *createDevice() {
|
||||||
|
return new Adafruit_GenericDevice(uart_read_impl, uart_write_impl,
|
||||||
|
uart_readreg_impl, uart_writereg_impl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TMC2209_UART *TMC2209_UART::_instance = nullptr;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial)
|
||||||
|
;
|
||||||
|
delay(100);
|
||||||
|
Serial.println("TMC2209 Generic Device register read/write test!");
|
||||||
|
|
||||||
|
Serial1.begin(115200);
|
||||||
|
|
||||||
|
TMC2209_UART uart(&Serial1, 0);
|
||||||
|
Adafruit_GenericDevice *device = uart.createDevice();
|
||||||
|
device->begin();
|
||||||
|
|
||||||
|
// Create register object for IOIN
|
||||||
|
Adafruit_BusIO_Register ioin_reg(device,
|
||||||
|
TMC2209_IOIN, // device and register address
|
||||||
|
4, // width = 4 bytes
|
||||||
|
MSBFIRST, // byte order
|
||||||
|
1); // address width = 1 byte
|
||||||
|
Serial.print("IOIN = 0x");
|
||||||
|
Serial.println(ioin_reg.read(), HEX);
|
||||||
|
|
||||||
|
// Create RegisterBits for VERSION field (bits 28:24)
|
||||||
|
Adafruit_BusIO_RegisterBits version_bits(
|
||||||
|
&ioin_reg, 8, 24); // 8 bits wide, starting at bit 24
|
||||||
|
|
||||||
|
Serial.println("Reading VERSION...");
|
||||||
|
uint8_t version = version_bits.read();
|
||||||
|
|
||||||
|
Serial.print("VERSION = 0x");
|
||||||
|
Serial.println(version, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() { delay(1000); }
|
||||||
0
examples/genericdevice_uarttest/.uno.test.skip
Normal file
0
examples/genericdevice_uarttest/.uno.test.skip
Normal file
75
examples/genericdevice_uarttest/genericdevice_uarttest.ino
Normal file
75
examples/genericdevice_uarttest/genericdevice_uarttest.ino
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
Abstracted transport for reading and writing data from a UART-based
|
||||||
|
device such as a TMC2209
|
||||||
|
|
||||||
|
Written with help by Claude! https://claude.ai/chat/335f50b1-3dd8-435e-9139-57ec7ca26a3c
|
||||||
|
(at this time chats are not shareable :(
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Adafruit_GenericDevice.h"
|
||||||
|
|
||||||
|
Stream *uart_stream; // Will hold the pointer to our Stream object
|
||||||
|
|
||||||
|
Adafruit_GenericDevice *create_uart_device(Stream *serial_port) {
|
||||||
|
uart_stream = serial_port; // Store the Stream pointer
|
||||||
|
|
||||||
|
auto uart_write = [](const uint8_t *buffer, size_t len) -> bool {
|
||||||
|
uart_stream->write(buffer, len);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto uart_read = [](uint8_t *buffer, size_t len) -> bool {
|
||||||
|
uint16_t timeout = 100;
|
||||||
|
while (uart_stream->available() < len && timeout--) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
if (timeout == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
buffer[i] = uart_stream->read();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Adafruit_GenericDevice(uart_read, uart_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial)
|
||||||
|
;
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
Serial.println("Generic Device test!");
|
||||||
|
|
||||||
|
Serial1.begin(115200);
|
||||||
|
|
||||||
|
Adafruit_GenericDevice *device = create_uart_device(&Serial1);
|
||||||
|
device->begin();
|
||||||
|
|
||||||
|
uint8_t write_buf[4] = {0x5, 0x0, 0x0, 0x48};
|
||||||
|
uint8_t read_buf[8];
|
||||||
|
|
||||||
|
Serial.println("Writing data...");
|
||||||
|
if (!device->write(write_buf, 4)) {
|
||||||
|
Serial.println("Write failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Reading response...");
|
||||||
|
if (!device->read(read_buf, 8)) {
|
||||||
|
Serial.println("Read failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("Got response: ");
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
Serial.print("0x");
|
||||||
|
Serial.print(read_buf[i], HEX);
|
||||||
|
Serial.print(" ");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() { delay(1000); }
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
name=Adafruit BusIO
|
name=Adafruit BusIO
|
||||||
version=1.16.3
|
version=1.17.0
|
||||||
author=Adafruit
|
author=Adafruit
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
maintainer=Adafruit <info@adafruit.com>
|
||||||
sentence=This is a library for abstracting away I2C and SPI interfacing
|
sentence=This is a library for abstracting away UART, I2C and SPI interfacing
|
||||||
paragraph=This is a library for abstracting away I2C and SPI interfacing
|
paragraph=This is a library for abstracting away UART, I2C and SPI interfacing
|
||||||
category=Signal Input/Output
|
category=Signal Input/Output
|
||||||
url=https://github.com/adafruit/Adafruit_BusIO
|
url=https://github.com/adafruit/Adafruit_BusIO
|
||||||
architectures=*
|
architectures=*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue