diff --git a/hardware/sam/libraries/Wire/Wire.cpp b/hardware/sam/libraries/Wire/Wire.cpp index ce4621447..28533abdc 100644 --- a/hardware/sam/libraries/Wire/Wire.cpp +++ b/hardware/sam/libraries/Wire/Wire.cpp @@ -19,45 +19,66 @@ extern "C" { #include -#include #include "twi.h" } #include "Wire.h" -static inline void TWI_WaitTransferComplete(Twi *_twi) { - while (!TWI_TransferComplete(_twi)) - ; +static inline bool TWI_FailedAcknowledge(Twi *pTwi) { + return pTwi->TWI_SR & TWI_SR_NACK; } -static inline void TWI_WaitByteSent(Twi *_twi) { - while (!TWI_ByteSent(_twi)) - ; +static inline bool TWI_WaitTransferComplete(Twi *_twi, uint32_t _timeout) { + while (!TWI_TransferComplete(_twi)) { + if (TWI_FailedAcknowledge(_twi)) + return false; + if (--_timeout == 0) + return false; + } + return true; } -static inline void TWI_WaitByteReceived(Twi *_twi) { - while (!TWI_ByteReceived(_twi)) - ; +static inline bool TWI_WaitByteSent(Twi *_twi, uint32_t _timeout) { + while (!TWI_ByteSent(_twi)) { + if (TWI_FailedAcknowledge(_twi)) + return false; + if (--_timeout == 0) + return false; + } + return true; +} + +static inline bool TWI_WaitByteReceived(Twi *_twi, uint32_t _timeout) { + while (!TWI_ByteReceived(_twi)) { + if (TWI_FailedAcknowledge(_twi)) + return false; + if (--_timeout == 0) + return false; + } + return true; } static inline bool TWI_STATUS_SVREAD(uint32_t status) { return (status & TWI_SR_SVREAD) == TWI_SR_SVREAD; } -DueWire::DueWire(Twi *_twi) : +DueWire::DueWire(Twi *_twi, void(*_beginCb)(void)) : twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0), txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status( - UNINITIALIZED) { + UNINITIALIZED), onBeginCallback(_beginCb) { // Empty } void DueWire::begin(void) { - // TODO: correct clock values - TWI_ConfigureMaster(twi, 200000, 200000); + if (onBeginCallback) + onBeginCallback(); + TWI_ConfigureMaster(twi, TWI_CLOCK, VARIANT_MCK); status = MASTER_IDLE; } void DueWire::begin(uint8_t address) { + if (onBeginCallback) + onBeginCallback(); TWI_ConfigureSlave(twi, address); status = SLAVE_IDLE; TWI_EnableIt(twi, TWI_IER_RXRDY | TWI_IER_TXRDY | TWI_IER_TXCOMP); @@ -75,14 +96,14 @@ uint8_t DueWire::requestFrom(uint8_t address, uint8_t quantity) { int readed = 0; TWI_StartRead(twi, address, 0, 0); do { - // Stop condition must be set during the receprion of last byte + // Stop condition must be set during the reception of last byte if (readed + 1 == quantity) TWI_SendSTOPCondition( twi); - TWI_WaitByteReceived( twi); + TWI_WaitByteReceived(twi, RECV_TIMEOUT); rxBuffer[readed++] = TWI_ReadByte(twi); } while (readed < quantity); - TWI_WaitTransferComplete( twi); + TWI_WaitTransferComplete(twi, RECV_TIMEOUT); // set rx buffer iterator vars rxBufferIndex = 0; @@ -110,14 +131,14 @@ void DueWire::beginTransmission(int address) { uint8_t DueWire::endTransmission(void) { // transmit buffer (blocking) TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]); - TWI_WaitByteSent( twi); + TWI_WaitByteSent(twi, XMIT_TIMEOUT); int sent = 1; while (sent < txBufferLength) { TWI_WriteByte(twi, txBuffer[sent++]); - TWI_WaitByteSent(twi); + TWI_WaitByteSent(twi, XMIT_TIMEOUT); } - TWI_Stop(twi); - TWI_WaitTransferComplete(twi); + TWI_Stop( twi); + TWI_WaitTransferComplete(twi, XMIT_TIMEOUT); // empty buffer txBufferLength = 0; @@ -175,7 +196,8 @@ int DueWire::peek(void) { } void DueWire::flush(void) { - // XXX: to be implemented. + // Do nothing, use endTransmission(..) to force + // data transfer. } void DueWire::onReceive(void(*function)(int)) { @@ -190,8 +212,9 @@ void DueWire::onService(void) { // Retrieve interrupt status uint32_t sr = TWI_GetMaskedStatus(twi); - // Detect if we should go into RECV or SEND status + // SLAVE_IDLE status if (status == SLAVE_IDLE) { + // Detect if we should go into RECV or SEND status srvBufferLength = 0; if (TWI_STATUS_SVREAD(sr)) { status = SLAVE_RECV; @@ -200,15 +223,15 @@ void DueWire::onService(void) { status = SLAVE_SEND; // Alert calling program to generate a response ASAP - if (onRequestCallback != NULL) + if (onRequestCallback) onRequestCallback(); else - // default response + // create a default 1-byte response write((uint8_t) 0); } } - // Receive packet + // SLAVE_RECV status: receiving packet if (status == SLAVE_RECV) { if (TWI_STATUS_RXRDY(sr)) { if (srvBufferLength < BUFFER_LENGTH) @@ -219,7 +242,7 @@ void DueWire::onService(void) { status = SLAVE_IDLE; // Alert calling program - if (onReceiveCallback != NULL) { + if (onReceiveCallback) { // Copy data into rxBuffer // (allows to receive another packet while // the main application reads actual data) @@ -233,7 +256,7 @@ void DueWire::onService(void) { } } - // Send packet + // SLAVE_SEND status: sending packet if (status == SLAVE_SEND) { if (TWI_STATUS_TXRDY(sr)) { uint8_t c = 0; @@ -249,13 +272,42 @@ void DueWire::onService(void) { } } -DueWire Wire = DueWire(TWI0); -DueWire Wire2 = DueWire(TWI1); - -void TWI0_IrqHandler(void) { - Wire.onService(); +#if WIRE_INTERFACES_COUNT > 0 +static void Wire_Init(void) { + PMC_EnablePeripheral( WIRE_INTERFACE_ID); + PIO_Configure(g_APinDescription[PIN_WIRE_SDA].pPort, + g_APinDescription[PIN_WIRE_SDA].ulPinType, + g_APinDescription[PIN_WIRE_SDA].ulPin, + g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration); + PIO_Configure(g_APinDescription[PIN_WIRE_SCL].pPort, + g_APinDescription[PIN_WIRE_SCL].ulPinType, + g_APinDescription[PIN_WIRE_SCL].ulPin, + g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration); } +DueWire Wire = DueWire(WIRE_INTERFACE, Wire_Init); + void TWI1_IrqHandler(void) { - Wire2.onService(); + Wire.onService(); } +#endif + +#if WIRE_INTERFACES_COUNT > 1 +static void Wire1_Init(void) { + PMC_EnablePeripheral( WIRE1_INTERFACE_ID); + PIO_Configure(g_APinDescription[PIN_WIRE1_SDA].pPort, + g_APinDescription[PIN_WIRE1_SDA].ulPinType, + g_APinDescription[PIN_WIRE1_SDA].ulPin, + g_APinDescription[PIN_WIRE1_SDA].ulPinConfiguration); + PIO_Configure(g_APinDescription[PIN_WIRE1_SCL].pPort, + g_APinDescription[PIN_WIRE1_SCL].ulPinType, + g_APinDescription[PIN_WIRE1_SCL].ulPin, + g_APinDescription[PIN_WIRE1_SCL].ulPinConfiguration); +} + +DueWire Wire1 = DueWire(WIRE1_INTERFACE, Wire1_Init); + +void TWI0_IrqHandler(void) { + Wire1.onService(); +} +#endif diff --git a/hardware/sam/libraries/Wire/Wire.h b/hardware/sam/libraries/Wire/Wire.h index 7e31856a6..f0b633f79 100644 --- a/hardware/sam/libraries/Wire/Wire.h +++ b/hardware/sam/libraries/Wire/Wire.h @@ -21,15 +21,15 @@ #ifndef DueWire_h #define DueWire_h -#include #include "Stream.h" #include "twi.h" +#include "variant.h" #define BUFFER_LENGTH 32 class DueWire: public Stream { public: - DueWire(Twi *); + DueWire(Twi *twi, void(*begin_cb)(void)); void begin(); void begin(uint8_t); void begin(int); @@ -70,22 +70,38 @@ private: void (*onRequestCallback)(void); void (*onReceiveCallback)(int); + // Called before initialization + void (*onBeginCallback)(void); + // 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; + enum DueWireStatus { + UNINITIALIZED, + MASTER_IDLE, + MASTER_SEND, + MASTER_RECV, + SLAVE_IDLE, + SLAVE_RECV, + SLAVE_SEND + }; + DueWireStatus status; + + // TWI clock frequency + static const uint32_t TWI_CLOCK = 100000; + + // Timeouts ( + static const uint32_t RECV_TIMEOUT = 100000; + static const uint32_t XMIT_TIMEOUT = 100000; }; +#if WIRE_INTERFACES_COUNT > 0 extern DueWire Wire; -extern DueWire Wire2; +#endif +#if WIRE_INTERFACES_COUNT > 1 +extern DueWire Wire1; +#endif #endif diff --git a/hardware/sam/variants/arduino_due/variant.h b/hardware/sam/variants/arduino_due/variant.h index 53265acd2..1882f463d 100644 --- a/hardware/sam/variants/arduino_due/variant.h +++ b/hardware/sam/variants/arduino_due/variant.h @@ -24,8 +24,10 @@ *----------------------------------------------------------------------------*/ #include "Arduino.h" +#ifdef __cplusplus #include "UARTClass.h" #include "USARTClass.h" +#endif /** * Libc porting layers @@ -69,6 +71,18 @@ #define PIN_LED2 PIN_LED_RXL #define PIN_LED3 PIN_LED_TXL +#define WIRE_INTERFACES_COUNT 2 + +#define PIN_WIRE_SDA (20u) +#define PIN_WIRE_SCL (21u) +#define WIRE_INTERFACE TWI1 +#define WIRE_INTERFACE_ID ID_TWI1 + +#define PIN_WIRE1_SDA (68u) +#define PIN_WIRE1_SCL (69u) +#define WIRE1_INTERFACE TWI0 +#define WIRE1_INTERFACE_ID ID_TWI0 + #define PINS_UART (80u) #define PINS_USART0 (81u)