From d66490787b138a8731eb21436bdf59ea170fe6bc Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 25 Oct 2011 14:33:40 +0200 Subject: [PATCH] Added Wire lib for ARM --- hardware/sam/libraries/Wire/Wire.cpp | 261 +++++++++++++++++++++++++++ hardware/sam/libraries/Wire/Wire.h | 91 ++++++++++ 2 files changed, 352 insertions(+) create mode 100644 hardware/sam/libraries/Wire/Wire.cpp create mode 100644 hardware/sam/libraries/Wire/Wire.h diff --git a/hardware/sam/libraries/Wire/Wire.cpp b/hardware/sam/libraries/Wire/Wire.cpp new file mode 100644 index 000000000..ce4621447 --- /dev/null +++ b/hardware/sam/libraries/Wire/Wire.cpp @@ -0,0 +1,261 @@ +/* + * DueWire.cpp - TWI/I2C library Arduino Due + * Copyright (c) 2011 Cristian Maglie. 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 + */ + +extern "C" { +#include +#include +#include "twi.h" +} + +#include "Wire.h" + +static inline void TWI_WaitTransferComplete(Twi *_twi) { + while (!TWI_TransferComplete(_twi)) + ; +} + +static inline void TWI_WaitByteSent(Twi *_twi) { + while (!TWI_ByteSent(_twi)) + ; +} + +static inline void TWI_WaitByteReceived(Twi *_twi) { + while (!TWI_ByteReceived(_twi)) + ; +} + +static inline bool TWI_STATUS_SVREAD(uint32_t status) { + return (status & TWI_SR_SVREAD) == TWI_SR_SVREAD; +} + +DueWire::DueWire(Twi *_twi) : + twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0), + txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status( + UNINITIALIZED) { + // Empty +} + +void DueWire::begin(void) { + // TODO: correct clock values + TWI_ConfigureMaster(twi, 200000, 200000); + status = MASTER_IDLE; +} + +void DueWire::begin(uint8_t address) { + TWI_ConfigureSlave(twi, address); + status = SLAVE_IDLE; + TWI_EnableIt(twi, TWI_IER_RXRDY | TWI_IER_TXRDY | TWI_IER_TXCOMP); +} + +void DueWire::begin(int address) { + begin((uint8_t) address); +} + +uint8_t DueWire::requestFrom(uint8_t address, uint8_t quantity) { + if (quantity > BUFFER_LENGTH) + quantity = BUFFER_LENGTH; + + // perform blocking read into buffer + int readed = 0; + TWI_StartRead(twi, address, 0, 0); + do { + // Stop condition must be set during the receprion of last byte + if (readed + 1 == quantity) + TWI_SendSTOPCondition( twi); + + TWI_WaitByteReceived( twi); + rxBuffer[readed++] = TWI_ReadByte(twi); + } while (readed < quantity); + TWI_WaitTransferComplete( twi); + + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = readed; + + return readed; +} + +uint8_t DueWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t) address, (uint8_t) quantity); +} + +void DueWire::beginTransmission(uint8_t address) { + status = MASTER_SEND; + + // save address of target and empty buffer + txAddress = address; + txBufferLength = 0; +} + +void DueWire::beginTransmission(int address) { + beginTransmission((uint8_t) address); +} + +uint8_t DueWire::endTransmission(void) { + // transmit buffer (blocking) + TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]); + TWI_WaitByteSent( twi); + int sent = 1; + while (sent < txBufferLength) { + TWI_WriteByte(twi, txBuffer[sent++]); + TWI_WaitByteSent(twi); + } + TWI_Stop(twi); + TWI_WaitTransferComplete(twi); + + // empty buffer + txBufferLength = 0; + + status = MASTER_IDLE; + return sent; +} + +void DueWire::write(uint8_t data) { + if (status == MASTER_SEND) { + if (txBufferLength >= BUFFER_LENGTH) + return; + txBuffer[txBufferLength++] = data; + } else { + if (srvBufferLength >= BUFFER_LENGTH) + return; + srvBuffer[srvBufferIndex++] = data; + } +} + +void DueWire::write(const uint8_t *data, size_t quantity) { + if (status == MASTER_SEND) { + for (size_t i = 0; i < quantity; ++i) { + if (txBufferLength >= BUFFER_LENGTH) + return; + txBuffer[txBufferLength++] = data[i]; + } + } else { + for (size_t i = 0; i < quantity; ++i) { + if (srvBufferLength >= BUFFER_LENGTH) + return; + srvBuffer[srvBufferLength++] = data[i]; + } + } +} + +void DueWire::write(const char *data) { + write((uint8_t*) data, strlen(data)); +} + +int DueWire::available(void) { + return rxBufferLength - rxBufferIndex; +} + +int DueWire::read(void) { + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex++]; + return -1; +} + +int DueWire::peek(void) { + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex]; + return -1; +} + +void DueWire::flush(void) { + // XXX: to be implemented. +} + +void DueWire::onReceive(void(*function)(int)) { + onReceiveCallback = function; +} + +void DueWire::onRequest(void(*function)(void)) { + onRequestCallback = function; +} + +void DueWire::onService(void) { + // Retrieve interrupt status + uint32_t sr = TWI_GetMaskedStatus(twi); + + // Detect if we should go into RECV or SEND status + if (status == SLAVE_IDLE) { + srvBufferLength = 0; + if (TWI_STATUS_SVREAD(sr)) { + status = SLAVE_RECV; + } else { + srvBufferIndex = 0; + status = SLAVE_SEND; + + // Alert calling program to generate a response ASAP + if (onRequestCallback != NULL) + onRequestCallback(); + else + // default response + write((uint8_t) 0); + } + } + + // Receive packet + if (status == SLAVE_RECV) { + if (TWI_STATUS_RXRDY(sr)) { + if (srvBufferLength < BUFFER_LENGTH) + srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); + } + if (TWI_STATUS_TXCOMP(sr)) { + // Receive completed + status = SLAVE_IDLE; + + // Alert calling program + if (onReceiveCallback != NULL) { + // Copy data into rxBuffer + // (allows to receive another packet while + // the main application reads actual data) + for (uint8_t i = 0; i < srvBufferLength; ++i) + rxBuffer[i] = srvBuffer[i]; + rxBufferIndex = 0; + rxBufferLength = srvBufferLength; + + onReceiveCallback( rxBufferLength); + } + } + } + + // Send packet + if (status == SLAVE_SEND) { + if (TWI_STATUS_TXRDY(sr)) { + uint8_t c = 0; + if (srvBufferIndex < srvBufferLength) + c = srvBuffer[srvBufferIndex++]; + TWI_WriteByte(twi, c); + } + + if (TWI_STATUS_TXCOMP(sr)) { + // Transmission complete + status = SLAVE_IDLE; + } + } +} + +DueWire Wire = DueWire(TWI0); +DueWire Wire2 = DueWire(TWI1); + +void TWI0_IrqHandler(void) { + Wire.onService(); +} + +void TWI1_IrqHandler(void) { + Wire2.onService(); +} diff --git a/hardware/sam/libraries/Wire/Wire.h b/hardware/sam/libraries/Wire/Wire.h new file mode 100644 index 000000000..7e31856a6 --- /dev/null +++ b/hardware/sam/libraries/Wire/Wire.h @@ -0,0 +1,91 @@ +/* + * DueWire.h - TWI/I2C library for Arduino Due + * Copyright (c) 2011 Cristian Maglie . + * 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 + */ + +#ifndef DueWire_h +#define DueWire_h + +#include +#include "Stream.h" +#include "twi.h" + +#define BUFFER_LENGTH 32 + +class DueWire: public Stream { +public: + DueWire(Twi *); + void begin(); + void begin(uint8_t); + void begin(int); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(int, int); + virtual void write(uint8_t); + virtual void write(const char *); + virtual void write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive(void(*)(int)); + void onRequest(void(*)(void)); + + void onService(void); + +private: + // RX Buffer + uint8_t rxBuffer[BUFFER_LENGTH]; + uint8_t rxBufferIndex; + uint8_t rxBufferLength; + + // TX Buffer + uint8_t txAddress; + uint8_t txBuffer[BUFFER_LENGTH]; + uint8_t txBufferLength; + + // Service buffer + uint8_t srvBuffer[BUFFER_LENGTH]; + uint8_t srvBufferIndex; + uint8_t srvBufferLength; + + // Callback user functions + void (*onRequestCallback)(void); + void (*onReceiveCallback)(int); + + // TWI instance + Twi *twi; + + // TWI state + static const uint8_t UNINITIALIZED = 0; + static const uint8_t MASTER_IDLE = 1; + static const uint8_t MASTER_SEND = 2; + static const uint8_t MASTER_RECV = 3; + static const uint8_t SLAVE_IDLE = 4; + static const uint8_t SLAVE_RECV = 5; + static const uint8_t SLAVE_SEND = 6; + uint8_t status; +}; + +extern DueWire Wire; +extern DueWire Wire2; + +#endif +