From: batt Date: Thu, 11 Oct 2007 16:09:24 +0000 (+0000) Subject: Rename avr twi driver. X-Git-Tag: 1.0.0~370 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=1121818c76981217b8f9224a20cd084cc4f113a4;p=bertos.git Rename avr twi driver. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@871 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/drv/twi.c b/drv/twi.c deleted file mode 100644 index 0d03950f..00000000 --- a/drv/twi.c +++ /dev/null @@ -1,293 +0,0 @@ -/** - * \file - * - * - * \brief Driver for the AVR ATMega TWI (implementation) - * - * \version $Id$ - * - * \author Stefano Fedrigo - * \author Bernardo Innocenti - */ - -/*#* - *#* $Log$ - *#* Revision 1.8 2007/06/07 14:35:12 batt - *#* Merge from project_ks. - *#* - *#* Revision 1.7 2006/07/19 12:56:26 bernie - *#* Convert to new Doxygen style. - *#* - *#* Revision 1.6 2006/03/20 17:49:50 bernie - *#* Make the TWI driver more generic to work with devices other than EEPROMS. - *#* - *#* Revision 1.5 2005/11/27 23:33:40 bernie - *#* Use appconfig.h instead of cfg/config.h. - *#* - *#* Revision 1.4 2005/04/11 19:10:28 bernie - *#* Include top-level headers from cfg/ subdir. - *#* - *#* Revision 1.3 2005/03/01 23:26:00 bernie - *#* Header fix. - *#* - *#* Revision 1.2 2005/01/25 08:36:56 bernie - *#* CONFIG_TWI_FREQ: New config param. - *#* - *#* Revision 1.1 2005/01/06 16:09:40 aleph - *#* Split twi/eeprom functions from eeprom module in separate twi module - *#* - *#*/ - -#include "twi.h" - -#include -#include -#include // BV() -#include /* CLOCK_FREQ */ -#include - -#include - - -/* Wait for TWINT flag set: bus is ready */ -#define WAIT_TWI_READY do {} while (!(TWCR & BV(TWINT))) - -#define READ_BIT BV(0) - - -/** - * Send START condition on the bus. - * - * \return true on success, false otherwise. - */ -static bool twi_start(void) -{ - TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN); - WAIT_TWI_READY; - - if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START) - return true; - - kprintf("!TW_(REP)START: %x\n", TWSR); - return false; -} - - -/** - * Send START condition and select slave for write. - * \c id is the device id comprehensive of address left shifted by 1. - * The LSB of \c id is ignored and reset to 0 for write operation. - * - * \return true on success, false otherwise. - */ -bool twi_start_w(uint8_t id) -{ - /* - * Loop on the select write sequence: when the eeprom is busy - * writing previously sent data it will reply to the SLA_W - * control byte with a NACK. In this case, we must - * keep trying until the eeprom responds with an ACK. - */ - while (twi_start()) - { - TWDR = id & ~READ_BIT; - TWCR = BV(TWINT) | BV(TWEN); - WAIT_TWI_READY; - - if (TW_STATUS == TW_MT_SLA_ACK) - return true; - else if (TW_STATUS != TW_MT_SLA_NACK) - { - kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR); - break; - } - } - - return false; -} - - -/** - * Send START condition and select slave for read. - * \c id is the device id comprehensive of address left shifted by 1. - * The LSB of \c id is ignored and set to 1 for read operation. - * - * \return true on success, false otherwise. - */ -bool twi_start_r(uint8_t id) -{ - if (twi_start()) - { - TWDR = id | READ_BIT; - TWCR = BV(TWINT) | BV(TWEN); - WAIT_TWI_READY; - - if (TW_STATUS == TW_MR_SLA_ACK) - return true; - - kprintf("!TW_MR_SLA_ACK: %x\n", TWSR); - } - - return false; -} - - -/** - * Send STOP condition. - */ -void twi_stop(void) -{ - TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO); -} - - -/** - * Put a single byte in master transmitter mode - * to the selected slave device through the TWI bus. - * - * \return true on success, false on error. - */ -bool twi_put(const uint8_t data) -{ - TWDR = data; - TWCR = BV(TWINT) | BV(TWEN); - WAIT_TWI_READY; - if (TW_STATUS != TW_MT_DATA_ACK) - { - kprintf("!TW_MT_DATA_ACK: %x\n", TWSR); - return false; - } - return true; -} - - -/** - * Send a sequence of bytes in master transmitter mode - * to the selected slave device through the TWI bus. - * - * \return true on success, false on error. - */ -bool twi_send(const void *_buf, size_t count) -{ - const uint8_t *buf = (const uint8_t *)_buf; - - while (count--) - { - if (!twi_put(*buf++)) - return false; - } - return true; -} - - -/** - * Receive a sequence of one or more bytes from the - * selected slave device in master receive mode through - * the TWI bus. - * - * Received data is placed in \c buf. - * - * \return true on success, false on error - */ -bool twi_recv(void *_buf, size_t count) -{ - uint8_t *buf = (uint8_t *)_buf; - - /* - * When reading the last byte the TWEA bit is not - * set, and the eeprom should answer with NACK - */ - while (count--) - { - TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0); - WAIT_TWI_READY; - - if (count) - { - if (TW_STATUS != TW_MR_DATA_ACK) - { - kprintf("!TW_MR_DATA_ACK: %x\n", TWSR); - return false; - } - } - else - { - if (TW_STATUS != TW_MR_DATA_NACK) - { - kprintf("!TW_MR_DATA_NACK: %x\n", TWSR); - return false; - } - } - *buf++ = TWDR; - } - - return true; -} - - -/** - * Initialize TWI module. - */ -void twi_init(void) -{ - ATOMIC( - /* - * This is pretty useless according to AVR's datasheet, - * but it helps us driving the TWI data lines on boards - * where the bus pull-up resistors are missing. This is - * probably due to some unwanted interaction between the - * port pin and the TWI lines. - */ -#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 - PORTD |= BV(PD0) | BV(PD1); - DDRD |= BV(PD0) | BV(PD1); -#elif CPU_AVR_ATMEGA8 - PORTC |= BV(PC4) | BV(PC5); - DDRC |= BV(PC4) | BV(PC5); -#else - #error Unsupported architecture -#endif - - /* - * Set speed: - * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS) - */ - #ifndef CONFIG_TWI_FREQ - #warning Using default value of 300000L for CONFIG_TWI_FREQ - #define CONFIG_TWI_FREQ 300000L /* ~300 kHz */ - #endif - #define TWI_PRESC 1 /* 4 ^ TWPS */ - - TWBR = (CLOCK_FREQ / (2 * CONFIG_TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC); - TWSR = 0; - TWCR = BV(TWEN); - ); -} diff --git a/drv/twi.h b/drv/twi.h deleted file mode 100644 index a55cf64b..00000000 --- a/drv/twi.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * \file - * - * - * \version $Id$ - * - * \author Stefano Fedrigo - * \author Bernardo Innocenti - * - * \brief Driver for the AVR ATMega TWI (interface) - */ - -/*#* - *#* $Log$ - *#* Revision 1.5 2006/07/19 12:56:26 bernie - *#* Convert to new Doxygen style. - *#* - *#* Revision 1.4 2006/03/20 17:49:49 bernie - *#* Make the TWI driver more generic to work with devices other than EEPROMS. - *#* - *#* Revision 1.3 2005/04/11 19:10:28 bernie - *#* Include top-level headers from cfg/ subdir. - *#* - *#* Revision 1.2 2005/02/18 11:19:52 bernie - *#* Update copyright info. - *#* - *#*/ -#ifndef DRV_TWI_H -#define DRV_TWI_H - -#include - -bool twi_start_w(uint8_t id); -bool twi_start_r(uint8_t id); -void twi_stop(void); -bool twi_put(const uint8_t data); -bool twi_send(const void *_buf, size_t count); -bool twi_recv(void *_buf, size_t count); -void twi_init(void); - -#endif /* DRV_EEPROM_H */ diff --git a/drv/twi_avr.c b/drv/twi_avr.c new file mode 100644 index 00000000..0d03950f --- /dev/null +++ b/drv/twi_avr.c @@ -0,0 +1,293 @@ +/** + * \file + * + * + * \brief Driver for the AVR ATMega TWI (implementation) + * + * \version $Id$ + * + * \author Stefano Fedrigo + * \author Bernardo Innocenti + */ + +/*#* + *#* $Log$ + *#* Revision 1.8 2007/06/07 14:35:12 batt + *#* Merge from project_ks. + *#* + *#* Revision 1.7 2006/07/19 12:56:26 bernie + *#* Convert to new Doxygen style. + *#* + *#* Revision 1.6 2006/03/20 17:49:50 bernie + *#* Make the TWI driver more generic to work with devices other than EEPROMS. + *#* + *#* Revision 1.5 2005/11/27 23:33:40 bernie + *#* Use appconfig.h instead of cfg/config.h. + *#* + *#* Revision 1.4 2005/04/11 19:10:28 bernie + *#* Include top-level headers from cfg/ subdir. + *#* + *#* Revision 1.3 2005/03/01 23:26:00 bernie + *#* Header fix. + *#* + *#* Revision 1.2 2005/01/25 08:36:56 bernie + *#* CONFIG_TWI_FREQ: New config param. + *#* + *#* Revision 1.1 2005/01/06 16:09:40 aleph + *#* Split twi/eeprom functions from eeprom module in separate twi module + *#* + *#*/ + +#include "twi.h" + +#include +#include +#include // BV() +#include /* CLOCK_FREQ */ +#include + +#include + + +/* Wait for TWINT flag set: bus is ready */ +#define WAIT_TWI_READY do {} while (!(TWCR & BV(TWINT))) + +#define READ_BIT BV(0) + + +/** + * Send START condition on the bus. + * + * \return true on success, false otherwise. + */ +static bool twi_start(void) +{ + TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN); + WAIT_TWI_READY; + + if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START) + return true; + + kprintf("!TW_(REP)START: %x\n", TWSR); + return false; +} + + +/** + * Send START condition and select slave for write. + * \c id is the device id comprehensive of address left shifted by 1. + * The LSB of \c id is ignored and reset to 0 for write operation. + * + * \return true on success, false otherwise. + */ +bool twi_start_w(uint8_t id) +{ + /* + * Loop on the select write sequence: when the eeprom is busy + * writing previously sent data it will reply to the SLA_W + * control byte with a NACK. In this case, we must + * keep trying until the eeprom responds with an ACK. + */ + while (twi_start()) + { + TWDR = id & ~READ_BIT; + TWCR = BV(TWINT) | BV(TWEN); + WAIT_TWI_READY; + + if (TW_STATUS == TW_MT_SLA_ACK) + return true; + else if (TW_STATUS != TW_MT_SLA_NACK) + { + kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR); + break; + } + } + + return false; +} + + +/** + * Send START condition and select slave for read. + * \c id is the device id comprehensive of address left shifted by 1. + * The LSB of \c id is ignored and set to 1 for read operation. + * + * \return true on success, false otherwise. + */ +bool twi_start_r(uint8_t id) +{ + if (twi_start()) + { + TWDR = id | READ_BIT; + TWCR = BV(TWINT) | BV(TWEN); + WAIT_TWI_READY; + + if (TW_STATUS == TW_MR_SLA_ACK) + return true; + + kprintf("!TW_MR_SLA_ACK: %x\n", TWSR); + } + + return false; +} + + +/** + * Send STOP condition. + */ +void twi_stop(void) +{ + TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO); +} + + +/** + * Put a single byte in master transmitter mode + * to the selected slave device through the TWI bus. + * + * \return true on success, false on error. + */ +bool twi_put(const uint8_t data) +{ + TWDR = data; + TWCR = BV(TWINT) | BV(TWEN); + WAIT_TWI_READY; + if (TW_STATUS != TW_MT_DATA_ACK) + { + kprintf("!TW_MT_DATA_ACK: %x\n", TWSR); + return false; + } + return true; +} + + +/** + * Send a sequence of bytes in master transmitter mode + * to the selected slave device through the TWI bus. + * + * \return true on success, false on error. + */ +bool twi_send(const void *_buf, size_t count) +{ + const uint8_t *buf = (const uint8_t *)_buf; + + while (count--) + { + if (!twi_put(*buf++)) + return false; + } + return true; +} + + +/** + * Receive a sequence of one or more bytes from the + * selected slave device in master receive mode through + * the TWI bus. + * + * Received data is placed in \c buf. + * + * \return true on success, false on error + */ +bool twi_recv(void *_buf, size_t count) +{ + uint8_t *buf = (uint8_t *)_buf; + + /* + * When reading the last byte the TWEA bit is not + * set, and the eeprom should answer with NACK + */ + while (count--) + { + TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0); + WAIT_TWI_READY; + + if (count) + { + if (TW_STATUS != TW_MR_DATA_ACK) + { + kprintf("!TW_MR_DATA_ACK: %x\n", TWSR); + return false; + } + } + else + { + if (TW_STATUS != TW_MR_DATA_NACK) + { + kprintf("!TW_MR_DATA_NACK: %x\n", TWSR); + return false; + } + } + *buf++ = TWDR; + } + + return true; +} + + +/** + * Initialize TWI module. + */ +void twi_init(void) +{ + ATOMIC( + /* + * This is pretty useless according to AVR's datasheet, + * but it helps us driving the TWI data lines on boards + * where the bus pull-up resistors are missing. This is + * probably due to some unwanted interaction between the + * port pin and the TWI lines. + */ +#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 + PORTD |= BV(PD0) | BV(PD1); + DDRD |= BV(PD0) | BV(PD1); +#elif CPU_AVR_ATMEGA8 + PORTC |= BV(PC4) | BV(PC5); + DDRC |= BV(PC4) | BV(PC5); +#else + #error Unsupported architecture +#endif + + /* + * Set speed: + * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS) + */ + #ifndef CONFIG_TWI_FREQ + #warning Using default value of 300000L for CONFIG_TWI_FREQ + #define CONFIG_TWI_FREQ 300000L /* ~300 kHz */ + #endif + #define TWI_PRESC 1 /* 4 ^ TWPS */ + + TWBR = (CLOCK_FREQ / (2 * CONFIG_TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC); + TWSR = 0; + TWCR = BV(TWEN); + ); +} diff --git a/drv/twi_avr.h b/drv/twi_avr.h new file mode 100644 index 00000000..a55cf64b --- /dev/null +++ b/drv/twi_avr.h @@ -0,0 +1,69 @@ +/** + * \file + * + * + * \version $Id$ + * + * \author Stefano Fedrigo + * \author Bernardo Innocenti + * + * \brief Driver for the AVR ATMega TWI (interface) + */ + +/*#* + *#* $Log$ + *#* Revision 1.5 2006/07/19 12:56:26 bernie + *#* Convert to new Doxygen style. + *#* + *#* Revision 1.4 2006/03/20 17:49:49 bernie + *#* Make the TWI driver more generic to work with devices other than EEPROMS. + *#* + *#* Revision 1.3 2005/04/11 19:10:28 bernie + *#* Include top-level headers from cfg/ subdir. + *#* + *#* Revision 1.2 2005/02/18 11:19:52 bernie + *#* Update copyright info. + *#* + *#*/ +#ifndef DRV_TWI_H +#define DRV_TWI_H + +#include + +bool twi_start_w(uint8_t id); +bool twi_start_r(uint8_t id); +void twi_stop(void); +bool twi_put(const uint8_t data); +bool twi_send(const void *_buf, size_t count); +bool twi_recv(void *_buf, size_t count); +void twi_init(void); + +#endif /* DRV_EEPROM_H */