0,0 → 1,426 |
/**************************************************************************//** |
* \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; |
} |