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.
pull/1469/head
Dean Camera 13 years ago
parent dc9133ad21
commit 88d022a752

@ -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, uint8_t TWI_ReadPacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS, const uint8_t TimeoutMS,
const uint8_t* InternalAddress, const uint8_t* InternalAddress,
const uint8_t InternalAddressLen, uint8_t InternalAddressLen,
uint8_t* Buffer, uint8_t* Buffer,
uint8_t Length) uint8_t Length)
{ {
uint8_t ErrorCode; uint8_t ErrorCode;
if ((ErrorCode = TWI_WritePacket(SlaveAddress, TimeoutMS, InternalAddress, InternalAddressLen, if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_WRITE,
NULL, 0)) != TWI_ERROR_NoError) TimeoutMS)) == TWI_ERROR_NoError)
{
return ErrorCode;
}
if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_READ,
TimeoutMS)) == TWI_ERROR_NoError)
{ {
while (Length--) while (InternalAddressLen--)
{ {
if (!(TWI_ReceiveByte(Buffer++, (Length == 1)))) if (!(TWI_SendByte(*(InternalAddress++))))
{ {
ErrorCode = TWI_ERROR_SlaveNAK; ErrorCode = TWI_ERROR_SlaveNAK;
break; 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; return ErrorCode;
@ -145,7 +180,7 @@ uint8_t TWI_WritePacket(const uint8_t SlaveAddress,
while (InternalAddressLen--) while (InternalAddressLen--)
{ {
if (!(TWI_SendByte(*(InternalAddress++)))) if (!(TWI_SendByte(*(InternalAddress++))))
{ {
ErrorCode = TWI_ERROR_SlaveNAK; ErrorCode = TWI_ERROR_SlaveNAK;
break; break;
} }

@ -99,14 +99,14 @@
* uint8_t WritePacket[3] = {0x01, 0x02, 0x03}; * uint8_t WritePacket[3] = {0x01, 0x02, 0x03};
* *
* TWI_WritePacket(0xA0, 10, &InternalWriteAddress, sizeof(InternalWriteAddress), * 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 * // Start a read session to device at address 0xA0, internal address 0xDC with a 10ms timeout
* uint8_t InternalReadAddress = 0xDC; * uint8_t InternalReadAddress = 0xDC;
* uint8_t ReadPacket[3]; * uint8_t ReadPacket[3];
* *
* TWI_ReadPacket(0xA0, 10, &InternalReadAddress, sizeof(InternalReadAddress), * TWI_ReadPacket(0xA0, 10, &InternalReadAddress, sizeof(InternalReadAddress),
* ReadPacket, sizeof(ReadPacket); * &ReadPacket, sizeof(ReadPacket);
* \endcode * \endcode
* *
* @{ * @{
@ -215,20 +215,24 @@
TWCR = ((1 << TWINT) | (1 << TWSTO) | (1 << TWEN)); 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. /** Sends a byte to the currently addressed device on the TWI bus.
* *
* \param[in] Byte Byte to send to the currently addressed device * \param[in] Byte Byte to send to the currently addressed device
* *
* \return Boolean \c true if the recipient ACKed the byte, \c false otherwise * \return Boolean \c true if the recipient ACKed the byte, \c false otherwise
*/ */
static inline bool TWI_SendByte(const uint8_t Byte) 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);
}
/** Receives a byte from the currently addressed device on the TWI bus. /** 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. * \return Boolean \c true if the byte reception successfully completed, \c false otherwise.
*/ */
static inline bool TWI_ReceiveByte(uint8_t* const Byte, bool TWI_ReceiveByte(uint8_t* const Byte,
const bool LastByte) const bool LastByte) ATTR_NON_NULL_PTR_ARG(1);
{ bool TWI_ReceiveByte(uint8_t* const Byte,
uint8_t TWCRMask = ((1 << TWINT) | (1 << TWEN)); const bool LastByte);
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);
/** High level function to perform a complete packet transfer over the TWI bus to the specified /** High level function to perform a complete packet transfer over the TWI bus to the specified
* device. * device.
* *
@ -278,7 +261,7 @@
uint8_t TWI_ReadPacket(const uint8_t SlaveAddress, uint8_t TWI_ReadPacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS, const uint8_t TimeoutMS,
const uint8_t* InternalAddress, const uint8_t* InternalAddress,
const uint8_t InternalAddressLen, uint8_t InternalAddressLen,
uint8_t* Buffer, uint8_t* Buffer,
uint8_t Length) ATTR_NON_NULL_PTR_ARG(3); uint8_t Length) ATTR_NON_NULL_PTR_ARG(3);

Loading…
Cancel
Save