From 6dd0447c12d1b75611ad8f205890913378635719 Mon Sep 17 00:00:00 2001 From: Michael Janssen Date: Tue, 6 Aug 2013 23:33:06 -0500 Subject: [PATCH] Bugfixes with the protocol. - Bitmasks need to be equal, not just result in non-zero - Only read status once in case it changes under us - Logical and not binary and when checking for acks on sending - We need to stop the bus when receiving the last byte - Force the bus into idle mode when we are Initing --- LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.c | 26 ++++++++++++++--------- LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.h | 7 ++++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.c b/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.c index 166427943f..81fbd0784b 100644 --- a/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.c +++ b/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.c @@ -34,6 +34,10 @@ #define __INCLUDE_FROM_TWI_C #include "../TWI.h" +static inline bool bitmask_is_set(uint8_t byte, uint8_t mask) { + return (byte & mask) == mask; +} + uint8_t TWI_StartTransmission(TWI_t *twi, const uint8_t SlaveAddress, const uint8_t TimeoutMS) @@ -45,22 +49,25 @@ uint8_t TWI_StartTransmission(TWI_t *twi, TimeoutRemaining = (TimeoutMS * 100); while (TimeoutRemaining) { - if (twi->MASTER.STATUS & (TWI_MASTER_WIF_bm | TWI_MASTER_ARBLOST_bm)) + uint8_t status = twi->MASTER.STATUS; + if (bitmask_is_set(status, TWI_MASTER_WIF_bm | TWI_MASTER_ARBLOST_bm)) { // Case 1: Arbitration lost. Try again. (or error) twi->MASTER.ADDR = SlaveAddress; } - else if (twi->MASTER.STATUS & (TWI_MASTER_WIF_bm | TWI_MASTER_RXACK_bm)) + else if (bitmask_is_set(status, TWI_MASTER_WIF_bm | TWI_MASTER_RXACK_bm)) { // Case 2: No response from slave. + // We need to release the bus. + TWI_StopTransmission(twi); return TWI_ERROR_SlaveResponseTimeout; } - else if (twi->MASTER.STATUS & (TWI_MASTER_WIF_bm)) + else if (status & TWI_MASTER_WIF_bm) { // Case 3: Slave ACK the Write. Ready! return TWI_ERROR_NoError; } - else if (twi->MASTER.STATUS & (TWI_MASTER_RIF_bm)) + else if (status & TWI_MASTER_RIF_bm) { // Case 4: Slave ACK the Read. Ready! (a byte will be read) return TWI_ERROR_NoError; @@ -73,7 +80,7 @@ uint8_t TWI_StartTransmission(TWI_t *twi, if (!(TimeoutRemaining)) { if (twi->MASTER.STATUS & TWI_MASTER_CLKHOLD_bm) { // Release the bus if we're holding it. - twi->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + TWI_StopTransmission(twi); } } return TWI_ERROR_BusCaptureTimeout; @@ -84,20 +91,20 @@ bool TWI_SendByte(TWI_t *twi, const uint8_t Byte) // We assume we're ready to write! twi->MASTER.DATA = Byte; while (!(twi->MASTER.STATUS & TWI_MASTER_WIF_bm)); - return (twi->MASTER.STATUS & TWI_MASTER_WIF_bm) & !(twi->MASTER.STATUS & TWI_MASTER_RXACK_bm); + return (twi->MASTER.STATUS & TWI_MASTER_WIF_bm) && !(twi->MASTER.STATUS & TWI_MASTER_RXACK_bm); } bool TWI_ReceiveByte(TWI_t *twi, uint8_t* const Byte, const bool LastByte) { // If we're here, we should already be reading. Wait if we haven't read yet. - if (twi->MASTER.STATUS & (TWI_MASTER_BUSERR_bm | TWI_MASTER_ARBLOST_bm)) { + if (bitmask_is_set(twi->MASTER.STATUS, TWI_MASTER_BUSERR_bm | TWI_MASTER_ARBLOST_bm)) { return false; } while (!(twi->MASTER.STATUS & TWI_MASTER_RIF_bm)); *Byte = twi->MASTER.DATA; if (LastByte) - twi->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_RECVTRANS_gc; + twi->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc; else twi->MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc; return true; @@ -137,8 +144,8 @@ uint8_t TWI_ReadPacket(TWI_t *twi, } } - TWI_StopTransmission(twi); } + TWI_StopTransmission(twi); } return ErrorCode; @@ -153,7 +160,6 @@ uint8_t TWI_WritePacket(TWI_t *twi, uint8_t Length) { uint8_t ErrorCode; - if ((ErrorCode = TWI_StartTransmission(twi, (SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_WRITE, TimeoutMS)) == TWI_ERROR_NoError) { diff --git a/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.h b/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.h index eb8c6a5f10..0a5d477b2f 100644 --- a/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.h +++ b/LUFA/Drivers/Peripheral/XMEGA/TWI_XMEGA.h @@ -184,8 +184,11 @@ static inline void TWI_Init(TWI_t *twi, const uint8_t Baud) ATTR_ALWAYS_INLINE ATTR_NON_NULL_PTR_ARG(1); static inline void TWI_Init(TWI_t *twi, const uint8_t Baud) { + twi->CTRL = 0x00; twi->MASTER.BAUD = Baud; - twi->MASTER.CTRLA |= TWI_MASTER_ENABLE_bm; + twi->MASTER.CTRLA = TWI_MASTER_ENABLE_bm; + twi->MASTER.CTRLB = 0; + twi->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc; } /** Turns off the TWI driver hardware. If this is called, any further TWI operations will require a call to @@ -206,7 +209,7 @@ static inline void TWI_StopTransmission(TWI_t *twi) ATTR_ALWAYS_INLINE ATTR_NON_NULL_PTR_ARG(1); static inline void TWI_StopTransmission(TWI_t *twi) { - twi->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + twi->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc; } /* Function Prototypes: */