mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 06:12:43 +01:00
sys/arduino: add Wire (I2C) library implementation
This commit is contained in:
parent
1657606092
commit
3fc2c60f20
@ -1,3 +1,7 @@
|
||||
ifneq (,$(filter arduino,$(USEMODULE)))
|
||||
FEATURES_OPTIONAL += periph_i2c
|
||||
endif
|
||||
|
||||
ifneq (,$(filter eepreg,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_eeprom
|
||||
endif
|
||||
|
37
sys/arduino/include/Wire.h
Normal file
37
sys/arduino/include/Wire.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_arduino
|
||||
* @brief Wrapper to keep source code compatibility for Wire.h
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @file
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef WIRE_H
|
||||
#define WIRE_H
|
||||
|
||||
#ifndef MODULE_PERIPH_I2C
|
||||
#error "No I2C support on your board"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "wireport.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WIRE_H */
|
||||
/** @} */
|
297
sys/arduino/include/wireport.hpp
Normal file
297
sys/arduino/include/wireport.hpp
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_arduino_api
|
||||
* @{
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @file
|
||||
*
|
||||
* @brief Definition of the Arduino 'Wire Library' for TwoWire interfaces
|
||||
*
|
||||
* This library is the implementation of the [Arduino Wire Library]
|
||||
* (https://www.arduino.cc/en/Reference/Wire) for the I2C peripheral
|
||||
* interfaces in RIOT. It supports only I2C master mode and the functions
|
||||
* that are documented in the official [Arduino Reference]
|
||||
* (https://www.arduino.cc/en/Reference/Wire) of this library.
|
||||
*
|
||||
* The implementation is an adaptation of the original Arduino Wire Library
|
||||
* which is published under the following copyright:
|
||||
*
|
||||
* ```
|
||||
* TwoWire.h - TWI/I2C library for Arduino & Wiring
|
||||
* Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
||||
* ```
|
||||
*
|
||||
* The documentation in this file is partially extracted from the original
|
||||
* [Arduino Reference](https://www.arduino.cc/en/Reference/Wire) of this
|
||||
* library which is published under the
|
||||
* [Creative Commons Attribution-ShareAlike 3.0 License]
|
||||
* (https://creativecommons.org/licenses/by-sa/3.0/).
|
||||
*/
|
||||
|
||||
#ifndef WIREPORT_HPP
|
||||
#define WIREPORT_HPP
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Default Arduino I2C interface */
|
||||
#ifndef ARDUINO_I2C_DEV
|
||||
#define ARDUINO_I2C_DEV (I2C_DEV(0))
|
||||
#endif
|
||||
|
||||
/** Buffer length used by the Arduino Wire library implementation */
|
||||
#define WIREPORT_BUFFER_LENGTH 32
|
||||
|
||||
/** Class definition for the Arduino Wire library implementation */
|
||||
class TwoWire
|
||||
{
|
||||
private:
|
||||
|
||||
static uint8_t rxBuffer[]; /**< RX buffer */
|
||||
static uint8_t rxBufferIndex; /**< index for RX buffer read */
|
||||
static uint8_t rxBufferLength; /**< number of bytes in RX buffer */
|
||||
|
||||
static uint8_t txAddress; /**< adress for transfer */
|
||||
static uint8_t txBuffer[]; /**< TX buffer */
|
||||
static uint8_t txBufferIndex; /**< index for TX buffer write */
|
||||
static uint8_t txBufferLength; /**< number of bytes in TX buffer */
|
||||
static uint8_t txError; /**< error code in write operations */
|
||||
|
||||
static uint8_t transmitting; /**< set by #beginTransmission and reset
|
||||
by #endTransmission to indicate an
|
||||
ongoing transmission */
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
TwoWire(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the I2C device defined by #ARDUINO_I2C_DEV as master
|
||||
*/
|
||||
void begin(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the I2C device defined by #ARDUINO_I2C_DEV as slave
|
||||
*
|
||||
* @note Since slave mode is not yet supported by the RIOT port of the
|
||||
* Arduino Wire library, calling this method leads to a core panic.
|
||||
*
|
||||
* @param[in] addr Address of the device initialized as slave
|
||||
*/
|
||||
void begin(uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Set the clock speed of the I2C device defined by
|
||||
* #ARDUINO_I2C_DEV.
|
||||
*
|
||||
* @note In RIOT, the I2C bus clock speed is determined by the board
|
||||
* definition. This method does therefore nothing. It is just realized
|
||||
* for compatibility reasons.
|
||||
*
|
||||
* @param[in] clk I2C clock speed in Hz
|
||||
*/
|
||||
void setClock(uint32_t clk);
|
||||
|
||||
/**
|
||||
* @brief Begin a transmission to a I2C slave device
|
||||
*
|
||||
* This method begins a transmission to the I2C slave device with the
|
||||
* given address. Subsequently, queue bytes for transmission with the
|
||||
* #write method and transmit them by calling #endTransmission.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireBeginTransmission
|
||||
*
|
||||
* @param[in] addr Address of the slave device
|
||||
*/
|
||||
void beginTransmission(uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief End a transmission to a I2C slave device
|
||||
*
|
||||
* Ends a transmission to a slave device that was begun by
|
||||
* #beginTransmission() and transmits the bytes that were queued by #write.
|
||||
* Sends always a STOP condition after the request.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireEndTransmission
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval 1 data too long to fit in transmit buffer
|
||||
* @retval 2 received NACK on transmit of address
|
||||
* @retval 3 received NACK on transmit of data
|
||||
* @retval 4 other error
|
||||
*/
|
||||
uint8_t endTransmission(void);
|
||||
|
||||
/**
|
||||
* @brief End a transmission to a I2C slave device
|
||||
*
|
||||
* Ends a transmission to a slave device that was begun by
|
||||
* #beginTransmission() and transmits the bytes that were queued by #write.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireEndTransmission
|
||||
*
|
||||
* @param stop Send STOP condition after transmission if true or
|
||||
* nothing if false.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval 1 data too long to fit in transmit buffer
|
||||
* @retval 2 received NACK on transmit of address
|
||||
* @retval 3 received NACK on transmit of data
|
||||
* @retval 4 other error
|
||||
*/
|
||||
uint8_t endTransmission(uint8_t stop);
|
||||
|
||||
/**
|
||||
* @brief Request bytes from a I2C slave device
|
||||
*
|
||||
* Used by the master to request bytes from a slave device. The bytes may
|
||||
* then be retrieved with the #available and #read methods. Sends always
|
||||
* a STOP condition after the request.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireRequestFrom
|
||||
*
|
||||
* @param[in] addr 7-bit address of the device to request bytes from
|
||||
* @param[in] size Number of bytes to request
|
||||
*
|
||||
* @return number of bytes returned from the slave device
|
||||
*/
|
||||
uint8_t requestFrom(uint8_t addr, uint8_t size);
|
||||
|
||||
/**
|
||||
* @brief Request bytes from a I2C slave device
|
||||
*
|
||||
* Used by the master to request bytes from a slave device. The bytes may
|
||||
* then be retrieved with the #available and #read methods.
|
||||
*
|
||||
* @param[in] addr 7-bit address of the device to request bytes from
|
||||
* @param[in] size Number of bytes to request
|
||||
* @param[in] stop Send STOP condition after the request if true or
|
||||
* nothing if false.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireRequestFrom
|
||||
*
|
||||
* @return number of bytes returned from the slave device
|
||||
*/
|
||||
uint8_t requestFrom(uint8_t addr, uint8_t size, uint8_t stop);
|
||||
|
||||
/**
|
||||
* @brief Queue a byte for transmission from a master to slave device
|
||||
*
|
||||
* The method queues a byte for transmission from a master to slave device
|
||||
* in-between calls to #beginTransmission and #endTransmission.
|
||||
*
|
||||
* @param[in] data Data byte
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireWrite
|
||||
*
|
||||
* @return number of bytes queued
|
||||
*/
|
||||
virtual size_t write(uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Queue bytes for transmission from a master to slave device
|
||||
*
|
||||
* The method queues bytes for transmission from a master to slave device
|
||||
* in-between calls to #beginTransmission and #endTransmission.
|
||||
*
|
||||
* @param[in] data Array of data to send as bytes
|
||||
* @param[in] size Number of bytes to transmit
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireWrite
|
||||
*
|
||||
* @return number of bytes queued
|
||||
*/
|
||||
virtual size_t write(const uint8_t *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Return the number of bytes available for retrieval
|
||||
*
|
||||
* Returns the number of bytes available for retrieval with #read. This
|
||||
* should be called on a master device after a call to #requestFrom.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireAvailable
|
||||
*
|
||||
* @return number of bytes available for retrieval
|
||||
*/
|
||||
virtual int available(void);
|
||||
|
||||
/**
|
||||
* @brief Reads one byte transmitted from slave device to the master
|
||||
*
|
||||
* Reads a byte that was transmitted from a slave device to the master after
|
||||
* a call to #requestFrom and removes it from receive buffer.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireRead
|
||||
*
|
||||
* @return next byte received, or -1 if none is available.
|
||||
*/
|
||||
virtual int read(void);
|
||||
|
||||
/**
|
||||
* @brief Read bytes transmitted from slave device to the master
|
||||
*
|
||||
* Reads a number of bytes that were transmitted from a slave device to the
|
||||
* master after a call to #requestFrom and removes them from receive buffer.
|
||||
*
|
||||
* @param[out] buffer buffer to store the bytes
|
||||
* @param[in] length number of bytes to read
|
||||
*
|
||||
* @return number of bytes placed in the buffer
|
||||
*/
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length);
|
||||
/**
|
||||
* @brief Peeks one byte transmitted from slave device to the master
|
||||
*
|
||||
* Reads a byte that was transmitted from a slave device to the master after
|
||||
* a call to #requestFrom without advancing to the next one. That is,
|
||||
* successive calls to #peek will return the same value, as will the
|
||||
* next call to read.
|
||||
*
|
||||
* Copied from https://www.arduino.cc/en/Reference/WireRead and
|
||||
* https://www.arduino.cc/en/Reference/StreamPeek
|
||||
*
|
||||
* @return next byte received, or -1 if none is available.
|
||||
*/
|
||||
virtual int peek(void);
|
||||
|
||||
/**
|
||||
* @brief Flush the RX and TX buffer
|
||||
*
|
||||
* This method clears the RX as well as the TX buffer. It is not necessary
|
||||
* to call this method explicitly. RX buffer is flushed implicitly when
|
||||
* method #requestFrom is called. Tx buffer is flushed implicitly when
|
||||
* method #beginTransmission is called.
|
||||
*/
|
||||
virtual void flush(void);
|
||||
};
|
||||
|
||||
extern TwoWire Wire;
|
||||
|
||||
#endif /* WIREPORT_HPP */
|
||||
/** @} */
|
258
sys/arduino/wireport.cpp
Normal file
258
sys/arduino/wireport.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Gunar Schorcht
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_arduino_api
|
||||
* @{
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @file
|
||||
*
|
||||
* @brief Definition of the Arduino 'Wire Library' for TwoWire interfaces
|
||||
* @}
|
||||
*/
|
||||
|
||||
#if MODULE_PERIPH_I2C
|
||||
|
||||
extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
}
|
||||
|
||||
#include "Wire.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "panic.h"
|
||||
#include "periph/i2c.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define WIRE_PORT_OK (0)
|
||||
#define WIRE_PORT_ERROR_DATA_TO_LONG (1)
|
||||
#define WIRE_PORT_ERROR_ADDR_NACK (2)
|
||||
#define WIRE_PORT_ERROR_DATA_NACK (3)
|
||||
#define WIRE_PORT_ERROR_OTHER (4)
|
||||
|
||||
/* Initialize Class Variables */
|
||||
|
||||
uint8_t TwoWire::rxBuffer[WIREPORT_BUFFER_LENGTH];
|
||||
uint8_t TwoWire::rxBufferIndex = 0;
|
||||
uint8_t TwoWire::rxBufferLength = 0;
|
||||
|
||||
uint8_t TwoWire::txAddress = 0;
|
||||
uint8_t TwoWire::txBuffer[WIREPORT_BUFFER_LENGTH];
|
||||
uint8_t TwoWire::txBufferIndex = 0;
|
||||
uint8_t TwoWire::txBufferLength = 0;
|
||||
uint8_t TwoWire::txError = 0;
|
||||
|
||||
uint8_t TwoWire::transmitting = 0;
|
||||
|
||||
/* Constructors */
|
||||
|
||||
TwoWire::TwoWire(void)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
}
|
||||
|
||||
/* Public Methods */
|
||||
|
||||
void TwoWire::begin(void)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
|
||||
rxBufferIndex = 0;
|
||||
rxBufferLength = 0;
|
||||
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
|
||||
i2c_init(ARDUINO_I2C_DEV);
|
||||
}
|
||||
|
||||
void TwoWire::begin(uint8_t addr)
|
||||
{
|
||||
(void)addr;
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
core_panic(PANIC_GENERAL_ERROR, "[wire] slave mode is not supported");
|
||||
}
|
||||
|
||||
void TwoWire::setClock(uint32_t clk)
|
||||
{
|
||||
(void)clk;
|
||||
/* not possible, bus speed is defined by the board definition */
|
||||
DEBUG("[wire] %s: clock is defined by board definition\n", __func__);
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t size, uint8_t stop)
|
||||
{
|
||||
DEBUG("[wire] %s: addr %02x, size %d, stop %d\n", __func__, addr, size, stop);
|
||||
|
||||
if (size > WIREPORT_BUFFER_LENGTH) {
|
||||
size = WIREPORT_BUFFER_LENGTH;
|
||||
}
|
||||
|
||||
uint8_t read = 0;
|
||||
|
||||
if (i2c_acquire(ARDUINO_I2C_DEV) == 0) {
|
||||
if (i2c_read_bytes(ARDUINO_I2C_DEV, addr, rxBuffer, size,
|
||||
stop ? 0 : I2C_NOSTOP) == 0) {
|
||||
read = size;
|
||||
}
|
||||
i2c_release(ARDUINO_I2C_DEV);
|
||||
}
|
||||
|
||||
rxBufferIndex = 0;
|
||||
rxBufferLength = read;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t size) {
|
||||
return requestFrom(addr, size, 1);
|
||||
}
|
||||
|
||||
void TwoWire::beginTransmission(uint8_t addr)
|
||||
{
|
||||
DEBUG("[wire] %s: addr %02x\n", __func__, addr);
|
||||
transmitting = 1;
|
||||
txAddress = addr;
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
}
|
||||
|
||||
uint8_t TwoWire::endTransmission(uint8_t stop)
|
||||
{
|
||||
DEBUG("[wire] %s: stop %d\n", __func__, stop);
|
||||
|
||||
if (txError) {
|
||||
return txError;
|
||||
}
|
||||
|
||||
if (i2c_acquire(ARDUINO_I2C_DEV) != 0) {
|
||||
return WIRE_PORT_ERROR_OTHER;
|
||||
}
|
||||
|
||||
int res = i2c_write_bytes(ARDUINO_I2C_DEV,
|
||||
txAddress, txBuffer, txBufferLength,
|
||||
stop ? 0 : I2C_NOSTOP);
|
||||
switch (res) {
|
||||
case 0: break;
|
||||
case ENXIO: res = WIRE_PORT_ERROR_ADDR_NACK;
|
||||
break;
|
||||
case EIO: res = WIRE_PORT_ERROR_DATA_NACK;
|
||||
break;
|
||||
default: res = WIRE_PORT_ERROR_OTHER;
|
||||
}
|
||||
|
||||
i2c_release(ARDUINO_I2C_DEV);
|
||||
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
txError = 0;
|
||||
transmitting = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t TwoWire::endTransmission(void)
|
||||
{
|
||||
return endTransmission(true);
|
||||
}
|
||||
|
||||
size_t TwoWire::write(uint8_t data)
|
||||
{
|
||||
DEBUG("[wire] %s: data %02x\n", __func__, data);
|
||||
|
||||
if (!transmitting || txBufferLength >= WIREPORT_BUFFER_LENGTH) {
|
||||
txError = WIRE_PORT_ERROR_DATA_TO_LONG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
txBuffer[txBufferIndex++] = data;
|
||||
txBufferLength = txBufferIndex;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t TwoWire::write(const uint8_t *data, size_t size)
|
||||
{
|
||||
DEBUG("[wire] %s: data %p, size %d\n", __func__, data, size);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (!write(data[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int TwoWire::available(void)
|
||||
{
|
||||
DEBUG("[wire] %s: return %d\n", __func__, rxBufferLength - rxBufferIndex);
|
||||
return rxBufferLength - rxBufferIndex;
|
||||
}
|
||||
|
||||
int TwoWire::read(void)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
|
||||
int value = -1;
|
||||
if (rxBufferIndex < rxBufferLength) {
|
||||
value = rxBuffer[rxBufferIndex];
|
||||
++rxBufferIndex;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
size_t TwoWire::readBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
int byte = read();
|
||||
if (byte == -1) {
|
||||
return i;
|
||||
}
|
||||
buffer[i] = byte;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int TwoWire::peek(void)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
|
||||
int value = -1;
|
||||
if (rxBufferIndex < rxBufferLength) {
|
||||
value = rxBuffer[rxBufferIndex];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void TwoWire::flush(void)
|
||||
{
|
||||
DEBUG("[wire] %s\n", __func__);
|
||||
|
||||
rxBufferIndex = 0;
|
||||
rxBufferLength = 0;
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
}
|
||||
|
||||
/* single instance */
|
||||
|
||||
TwoWire Wire;
|
||||
|
||||
#else /* MODULE_PERIPH_I2C */
|
||||
|
||||
typedef int dont_be_pedantic;
|
||||
|
||||
#endif /* MODULE_PERIPH_I2C */
|
Loading…
Reference in New Issue
Block a user