From 88d022a75245e7492ecd11a5e1ea5c553acf0b2c Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Wed, 31 Aug 2011 07:17:33 +0000 Subject: Make TWI_ReadPacket() use a repeated start condition rather than a full bus release/recapture after the read address has been sent. Fix TWI_ReadPacket() not releasing the bus correctly after all data transferred. Make TWI_SendByte() and TWI_ReceiveByte() non-inline to reduce compiled binary size. --- LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c | 63 +++++++++++++++++++++++++-------- LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.h | 57 +++++++++++------------------ 2 files changed, 69 insertions(+), 51 deletions(-) (limited to 'LUFA') diff --git a/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c b/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c index d4f594f3b..d6db37d6e 100644 --- a/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c +++ b/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c @@ -97,34 +97,69 @@ uint8_t TWI_StartTransmission(const uint8_t SlaveAddress, } } +bool TWI_SendByte(const uint8_t Byte) +{ + TWDR = Byte; + TWCR = ((1 << TWINT) | (1 << TWEN)); + while (!(TWCR & (1 << TWINT))); + + return ((TWSR & TW_STATUS_MASK) == TW_MT_DATA_ACK); +} + +bool TWI_ReceiveByte(uint8_t* const Byte, + const bool LastByte) +{ + uint8_t TWCRMask; + + if (LastByte) + TWCRMask = ((1 << TWINT) | (1 << TWEN)); + else + TWCRMask = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA)); + + TWCR = TWCRMask; + while (!(TWCR & (1 << TWINT))); + *Byte = TWDR; + + uint8_t Status = (TWSR & TW_STATUS_MASK); + + return ((LastByte) ? (Status == TW_MR_DATA_NACK) : (Status == TW_MR_DATA_ACK)); +} + uint8_t TWI_ReadPacket(const uint8_t SlaveAddress, const uint8_t TimeoutMS, const uint8_t* InternalAddress, - const uint8_t InternalAddressLen, + uint8_t InternalAddressLen, uint8_t* Buffer, uint8_t Length) { uint8_t ErrorCode; - if ((ErrorCode = TWI_WritePacket(SlaveAddress, TimeoutMS, InternalAddress, InternalAddressLen, - NULL, 0)) != TWI_ERROR_NoError) - { - return ErrorCode; - } - - if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_READ, - TimeoutMS)) == TWI_ERROR_NoError) + if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_WRITE, + TimeoutMS)) == TWI_ERROR_NoError) { - while (Length--) + while (InternalAddressLen--) { - if (!(TWI_ReceiveByte(Buffer++, (Length == 1)))) - { + if (!(TWI_SendByte(*(InternalAddress++)))) + { ErrorCode = TWI_ERROR_SlaveNAK; break; } } - TWI_StopTransmission(); + if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_READ, + TimeoutMS)) == TWI_ERROR_NoError) + { + while (Length--) + { + if (!(TWI_ReceiveByte(Buffer++, (Length == 0)))) + { + ErrorCode = TWI_ERROR_SlaveNAK; + break; + } + } + + TWI_StopTransmission(); + } } return ErrorCode; @@ -145,7 +180,7 @@ uint8_t TWI_WritePacket(const uint8_t SlaveAddress, while (InternalAddressLen--) { if (!(TWI_SendByte(*(InternalAddress++)))) - { + { ErrorCode = TWI_ERROR_SlaveNAK; break; } diff --git a/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.h b/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.h index 63b9f03c6..705ef530c 100644 --- a/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.h +++ b/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.h @@ -99,14 +99,14 @@ * uint8_t WritePacket[3] = {0x01, 0x02, 0x03}; * * TWI_WritePacket(0xA0, 10, &InternalWriteAddress, sizeof(InternalWriteAddress), - * WritePacket, sizeof(WritePacket); + * &WritePacket, sizeof(WritePacket); * * // Start a read session to device at address 0xA0, internal address 0xDC with a 10ms timeout * uint8_t InternalReadAddress = 0xDC; * uint8_t ReadPacket[3]; * * TWI_ReadPacket(0xA0, 10, &InternalReadAddress, sizeof(InternalReadAddress), - * ReadPacket, sizeof(ReadPacket); + * &ReadPacket, sizeof(ReadPacket); * \endcode * * @{ @@ -215,20 +215,24 @@ TWCR = ((1 << TWINT) | (1 << TWSTO) | (1 << TWEN)); } + /* Function Prototypes: */ + /** Begins a master mode TWI bus communication with the given slave device address. + * + * \param[in] SlaveAddress Address of the slave TWI device to communicate with. + * \param[in] TimeoutMS Timeout period within which the slave must respond, in milliseconds. + * + * \return A value from the \ref TWI_ErrorCodes_t enum. + */ + uint8_t TWI_StartTransmission(const uint8_t SlaveAddress, + const uint8_t TimeoutMS); + /** Sends a byte to the currently addressed device on the TWI bus. * * \param[in] Byte Byte to send to the currently addressed device * * \return Boolean \c true if the recipient ACKed the byte, \c false otherwise */ - static inline bool TWI_SendByte(const uint8_t Byte) - { - TWDR = Byte; - TWCR = ((1 << TWINT) | (1 << TWEN)); - while (!(TWCR & (1 << TWINT))); - - return ((TWSR & TW_STATUS_MASK) == TW_MT_DATA_ACK); - } + bool TWI_SendByte(const uint8_t Byte); /** Receives a byte from the currently addressed device on the TWI bus. * @@ -237,32 +241,11 @@ * * \return Boolean \c true if the byte reception successfully completed, \c false otherwise. */ - static inline bool TWI_ReceiveByte(uint8_t* const Byte, - const bool LastByte) - { - uint8_t TWCRMask = ((1 << TWINT) | (1 << TWEN)); - - if (!(LastByte)) - TWCRMask |= (1 << TWEA); - - TWCR = TWCRMask; - while (!(TWCR & (1 << TWINT))); - *Byte = TWDR; - - return ((TWSR & TW_STATUS_MASK) == TW_MR_DATA_ACK); - } - - /* Function Prototypes: */ - /** Begins a master mode TWI bus communication with the given slave device address. - * - * \param[in] SlaveAddress Address of the slave TWI device to communicate with. - * \param[in] TimeoutMS Timeout period within which the slave must respond, in milliseconds. - * - * \return A value from the \ref TWI_ErrorCodes_t enum. - */ - uint8_t TWI_StartTransmission(const uint8_t SlaveAddress, - const uint8_t TimeoutMS); - + bool TWI_ReceiveByte(uint8_t* const Byte, + const bool LastByte) ATTR_NON_NULL_PTR_ARG(1); + bool TWI_ReceiveByte(uint8_t* const Byte, + const bool LastByte); + /** High level function to perform a complete packet transfer over the TWI bus to the specified * device. * @@ -278,7 +261,7 @@ uint8_t TWI_ReadPacket(const uint8_t SlaveAddress, const uint8_t TimeoutMS, const uint8_t* InternalAddress, - const uint8_t InternalAddressLen, + uint8_t InternalAddressLen, uint8_t* Buffer, uint8_t Length) ATTR_NON_NULL_PTR_ARG(3); -- cgit v1.2.3