Go to most recent revision | 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;
}