Rev 17 |
Blame |
Compare with Previous |
Last modification |
View Log
| Download
| RSS feed
/**************************************************************************//**
* \brief TWI library
* \author Copyright (C) 2009 Julien Le Sech - www.idreammicro.com
* \version 1.0
* \date 20090501
*
* This file is part of the iDreamMicro library.
*
* This library is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see http://www.gnu.org/licenses/
******************************************************************************/
/**************************************************************************//**
* \file twi.c
******************************************************************************/
/******************************************************************************
* Header file inclusions.
******************************************************************************/
#include <twi/twi.h>
#include <useful/bits.h>
#include <avr/io.h>
#include <util/twi.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
/******************************************************************************
* Private macros.
******************************************************************************/
/**************************************************************************//**
* \def TWI__MAX_FREQUENCY
* \brief Max frequency of TWI bus.
******************************************************************************/
#define TWI__MAX_FREQUENCY 400000
/******************************************************************************
* Private types.
******************************************************************************/
/**************************************************************************//**
* \enum twi__prescaler_values
* \brief Available TWI bus prescaler values.
*
* \typedef twi__prescaler_value_t
* \brief TWI bus prescaler value.
******************************************************************************/
typedef enum twi__prescaler_values
{
TWI__PRESCALER_VALUE__1
,
TWI__PRESCALER_VALUE__4
,
TWI__PRESCALER_VALUE__16
,
TWI__PRESCALER_VALUE__64
,
TWI__PRESCALER_VALUE__INVALID
} twi__prescaler_value_t
;
/**************************************************************************//**
* \struct twi__prescaler_configuration
* \brief TWI bus prescaler configuration.
*
* \typedef twi__prescaler_configuration_t
* \brief TWI bus prescaler configuration.
******************************************************************************/
typedef struct twi__prescaler_configuration
{
uint8_t value
;
uint8_t bits
;
} twi__prescaler_configuration_t
;
/******************************************************************************
* Private constant definitions.
******************************************************************************/
/**************************************************************************//**
* \var prescaler_configurations
* \brief Available prescaler configurations.
******************************************************************************/
static const twi__prescaler_configuration_t prescaler_configurations
[] =
{
[TWI__PRESCALER_VALUE__1
] =
{
.
value = 1,
.
bits = 0
},
[TWI__PRESCALER_VALUE__4
] =
{
.
value = 4,
.
bits = _BV
(TWPS0
)
},
[TWI__PRESCALER_VALUE__16
] =
{
.
value = 16,
.
bits = _BV
(TWPS1
)
},
[TWI__PRESCALER_VALUE__64
] =
{
.
value = 64,
.
bits = _BV
(TWPS1
) | _BV
(TWPS0
)
}
};
/******************************************************************************
* Private function prototypes.
******************************************************************************/
/**************************************************************************//**
* \fn static inline uint8_t twi__compute_bit_rate(
* uint32_t f_scl,
* uint8_t prescaler_value)
*
* \brief
*
* \param f_scl SCL frequency.
* \param prescaler_value Prescaler value.
******************************************************************************/
static inline
uint8_t
twi__compute_bit_rate
(
uint32_t f_scl
,
uint8_t prescaler_value
);
/******************************************************************************
* Public function definitions.
******************************************************************************/
/**************************************************************************//**
* \fn void twi__initialize(uint32_t frequency)
*
* \brief Initialize TWI.
*
* \param frequency TWI frequency (up to 400 kHz).
******************************************************************************/
void twi__initialize
(
uint32_t frequency
){
// Check the preconditions.
assert(TWI__MAX_FREQUENCY
>= frequency
);
uint16_t bit_rate
= UINT16_MAX
;
twi__prescaler_value_t prescaler_value
= TWI__PRESCALER_VALUE__1
;
// Compute bit rate and prescaler value.
do
{
bit_rate
= twi__compute_bit_rate
(
frequency
,
prescaler_configurations
[prescaler_value
].
value
);
} while (UINT8_MAX
< bit_rate
&& TWI__PRESCALER_VALUE__INVALID
> prescaler_value
++);
// Set bit rate.
TWBR
= bit_rate
;
// Set prescaler value.
TWSR
= prescaler_configurations
[prescaler_value
].
bits;
}
/**************************************************************************//**
* \fn twi__error_t twi__start(void)
*
* \brief
******************************************************************************/
twi__error_t
twi__start
(
void
){
// Send start condition.
TWCR
= (1 << TWINT
) | (1 << TWSTA
) | (1 << TWEN
);
// Wait for TWINT flag set. This indicates that the START condition has
// been transmitted.
while (!(TWCR
& (1 << TWINT
)));
// Check value of TWI Status Register. Mask prescaler bits.
if (TWSR
& TW_NO_INFO
!= TW_START
)
{
// If status is different from START (TW_START), return error.
return TWI__ERROR__ERROR
;
}
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__repeat_start(void)
*
* \brief
******************************************************************************/
twi__error_t
twi__repeat_start
(
void
){
// TODO: check if TWSTO must be set.
// Send start condition.
TWCR
= (1 << TWEN
) | (1 << TWINT
) | (1 << TWSTA
) | (1 << TWSTO
);
// Wait for TWINT flag set. This indicates that the START condition has
// been transmitted.
while (!(TWCR
& (1 << TWINT
)));
// Check value of TWI Status Register. Mask prescaler bits.
if (TWSR
& TW_NO_INFO
!= TW_REP_START
)
{
// If status different from START (TW_REP_START), return error.
return TWI__ERROR__ERROR
;
}
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__send_slar(uint8_t sla)
*
* \brief
*
* \param sla
******************************************************************************/
twi__error_t
twi__send_slar
(
uint8_t sla
){
// Load SLA into TWDR register.
TWDR
= sla
| TW_READ
;
// Clear TWINT bit in TWCR to start transmission of address.
TWCR
= (1 << TWINT
) | (1 << TWEN
);
// Wait for TWINT flag set. This indicates that the SLA+W (TW_WRITE) has
// been transmitted, and ACK/NACK has been received.
while (!(TWCR
& (1 << TWINT
)));
// Check value of TWI Status Register. Mask prescaler bits. If status
// different from MT_SLA_ACK (TW_MR_SLA_ACK), return error.
if (TWSR
& TW_NO_INFO
!= TW_MR_SLA_ACK
)
{
return TWI__ERROR__ERROR
;
}
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__send_slaw(uint8_t sla)
*
* \brief
*
* \param sla
******************************************************************************/
twi__error_t
twi__send_slaw
(
uint8_t sla
){
// Load SLA into TWDR register.
TWDR
= sla
| TW_WRITE
;
// Clear TWINT bit in TWCR to start transmission of address.
TWCR
= (1 << TWINT
) | (1 << TWEN
);
// Wait for TWINT flag set. This indicates that the SLA+W (TW_WRITE) has
// been transmitted, and ACK/NACK has been received.
while (!(TWCR
& (1 << TWINT
)));
// Check value of TWI Status Register. Mask prescaler bits. If status
// different from MT_SLA_ACK (TW_MT_SLA_ACK), return error.
if (TWSR
& TW_NO_INFO
!= TW_MT_SLA_ACK
)
{
return TWI__ERROR__ERROR
;
}
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__send_data(uint8_t data)
*
* \brief
*
* \param data Data to send.
******************************************************************************/
twi__error_t
twi__send_data
(
uint8_t data
){
// Load data into TWDR register.
TWDR
= data
;
// Clear TWINT bit in TWCR to start transmission of data.
TWCR
= (1 << TWINT
) | (1 << TWEN
);
// Wait for TWINT flag set. This indicates that the data has been
// transmitted, and ACK/NACK has been receiver.
while (!(TWCR
& (1 << TWINT
)));
// Check value of TWI status register. Mask prescaler bits. If status
// different from MT_DATA_ACK (TW_MT_DATA_ACK), return error.
if (TWSR
& TW_NO_INFO
!= TW_MT_DATA_ACK
)
{
return TWI__ERROR__ERROR
;
}
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__receive_data_ack(uint8_t* p_data)
*
* \brief
*
* \param p_data
******************************************************************************/
twi__error_t
twi__receive_data_ack
(
uint8_t* p_data
){
// Check the preconditions.
assert(NULL
!= p_data
);
TWCR
= (1 << TWEN
) | (1 << TWINT
) | (1 << TWEA
);
while (!(TWCR
& (1 << TWINT
)));
if ((TWSR
& TW_NO_INFO
) != TW_MR_DATA_ACK
)
{
return TWI__ERROR__ERROR
;
}
*p_data
= TWDR
;
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn twi__error_t twi__receive_data_nack(uint8_t* p_data)
*
* \brief
*
* \param p_data
******************************************************************************/
twi__error_t
twi__receive_data_nack
(
uint8_t* p_data
){
// Check the preconditions.
assert(NULL
!= p_data
);
TWCR
= (1 << TWEN
) | (1 << TWINT
);
while (!(TWCR
& (1 << TWINT
)));
if ((TWSR
& TW_NO_INFO
) != TW_MR_DATA_NACK
)
{
return TWI__ERROR__ERROR
;
}
*p_data
= TWDR
;
return TWI__ERROR__NONE
;
}
/**************************************************************************//**
* \fn void twi__stop(void)
*
* \brief Stop TWI.
******************************************************************************/
void
twi__stop
(
void
){
// Transmit stop operation.
TWCR
= (1 << TWINT
) | (1 << TWEN
) | (1 << TWSTO
);
// Wait for stop.
while (TWCR
& (1 << TWSTO
));
}
/******************************************************************************
* Private function definitions.
******************************************************************************/
/**************************************************************************//**
* \fn static inline uint8_t twi__compute_bit_rate(
* uint32_t f_scl,
* uint8_t prescaler_value)
*
* \brief
*
* \param f_scl SCL frequency.
* \param prescaler_value Prescaler value.
******************************************************************************/
static inline
uint8_t
twi__compute_bit_rate
(
uint32_t f_scl
,
uint8_t prescaler_value
){
uint8_t bit_rate
= (F_CPU
- 16 * f_scl
) / (2 * f_scl
* prescaler_value
);
return bit_rate
;
}