Commit 88d022a7 authored by Dean Camera's avatar Dean Camera
Browse files

Make TWI_ReadPacket() use a repeated start condition rather than a full bus...

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.
parent dc9133ad
......@@ -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;
}
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment