From: batt Date: Mon, 6 Oct 2008 17:21:40 +0000 (+0000) Subject: Merged from external project: X-Git-Tag: 2.0.0~64 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=1d0283ddb3ec3cf273e03207e7c6066897771e5c;p=bertos.git Merged from external project: ********** r22401 | batt | 2008-10-02 11:24:17 +0200 (Thu, 02 Oct 2008) | 1 line Rename avr driver. ********** git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1870 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/avr/drv/i2c_avr.c b/bertos/cpu/avr/drv/i2c_avr.c new file mode 100644 index 00000000..80b97ad6 --- /dev/null +++ b/bertos/cpu/avr/drv/i2c_avr.c @@ -0,0 +1,309 @@ +/** + * \file + * + * + * \brief Driver for the AVR ATMega TWI (implementation) + * + * \version $Id$ + * + * \author Stefano Fedrigo + * \author Bernie Innocenti + */ + +#include "i2c_avr.h" + +#include "hw/hw_cpu.h" /* CLOCK_FREQ */ + +#include "cfg/cfg_i2c.h" +#include +#include // BV() +#include + +#include +#include +#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 i2c_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 i2c_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. + */ + ticks_t start = timer_clock(); + while (i2c_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; + } + else if (timer_clock() - start > ms_to_ticks(CONFIG_TWI_START_TIMEOUT)) + { + kprintf("Timeout on TWI_MT_START\n"); + 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 i2c_start_r(uint8_t id) +{ + if (i2c_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 i2c_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 i2c_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; +} + +/** + * Get 1 byte from slave in master transmitter mode + * to the selected slave device through the TWI bus. + * If \a ack is true issue a ACK after getting the byte, + * otherwise a NACK is issued. + * + * \return the byte read if ok, EOF on errors. + */ +int i2c_get(bool ack) +{ + TWCR = BV(TWINT) | BV(TWEN) | (ack ? BV(TWEA) : 0); + WAIT_TWI_READY; + + if (ack) + { + if (TW_STATUS != TW_MR_DATA_ACK) + { + kprintf("!TW_MR_DATA_ACK: %x\n", TWSR); + return EOF; + } + } + else + { + if (TW_STATUS != TW_MR_DATA_NACK) + { + kprintf("!TW_MR_DATA_NACK: %x\n", TWSR); + return EOF; + } + } + + /* avoid sign extension */ + return (int)(uint8_t)TWDR; +} + + +/** + * 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 i2c_send(const void *_buf, size_t count) +{ + const uint8_t *buf = (const uint8_t *)_buf; + + while (count--) + { + if (!i2c_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. + * + * \note a NACK is automatically given on the last received + * byte. + * + * \return true on success, false on error + */ +bool i2c_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--) + { + /* + * The last byte read does not has an ACK + * to stop communication. + */ + int c = i2c_get(count); + + if (c == EOF) + return false; + else + *buf++ = c; + } + + return true; +} + + +MOD_DEFINE(i2c); + +/** + * Initialize TWI module. + */ +void i2c_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); +#elif CPU_AVR_ATMEGA32 + PORTC |= BV(PC1) | BV(PC0); + DDRC |= BV(PC1) | BV(PC0); +#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); + ); + MOD_INIT(i2c); +} diff --git a/bertos/cpu/avr/drv/i2c_avr.h b/bertos/cpu/avr/drv/i2c_avr.h new file mode 100644 index 00000000..2d496df7 --- /dev/null +++ b/bertos/cpu/avr/drv/i2c_avr.h @@ -0,0 +1,55 @@ +/** + * \file + * + * + * \version $Id$ + * + * \author Stefano Fedrigo + * \author Bernie Innocenti + * + * \brief Driver for the AVR ATMega TWI (interface) + */ + +#ifndef DRV_I2C_H +#define DRV_I2C_H + +#include + +bool i2c_start_w(uint8_t id); +bool i2c_start_r(uint8_t id); +void i2c_stop(void); +bool i2c_put(const uint8_t data); +bool i2c_send(const void *_buf, size_t count); +int i2c_get(bool ack); +bool i2c_recv(void *_buf, size_t count); +void i2c_init(void); + +#endif /* DRV_I2C_H */ diff --git a/bertos/cpu/avr/drv/twi_avr.c b/bertos/cpu/avr/drv/twi_avr.c deleted file mode 100644 index 80b97ad6..00000000 --- a/bertos/cpu/avr/drv/twi_avr.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * \file - * - * - * \brief Driver for the AVR ATMega TWI (implementation) - * - * \version $Id$ - * - * \author Stefano Fedrigo - * \author Bernie Innocenti - */ - -#include "i2c_avr.h" - -#include "hw/hw_cpu.h" /* CLOCK_FREQ */ - -#include "cfg/cfg_i2c.h" -#include -#include // BV() -#include - -#include -#include -#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 i2c_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 i2c_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. - */ - ticks_t start = timer_clock(); - while (i2c_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; - } - else if (timer_clock() - start > ms_to_ticks(CONFIG_TWI_START_TIMEOUT)) - { - kprintf("Timeout on TWI_MT_START\n"); - 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 i2c_start_r(uint8_t id) -{ - if (i2c_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 i2c_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 i2c_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; -} - -/** - * Get 1 byte from slave in master transmitter mode - * to the selected slave device through the TWI bus. - * If \a ack is true issue a ACK after getting the byte, - * otherwise a NACK is issued. - * - * \return the byte read if ok, EOF on errors. - */ -int i2c_get(bool ack) -{ - TWCR = BV(TWINT) | BV(TWEN) | (ack ? BV(TWEA) : 0); - WAIT_TWI_READY; - - if (ack) - { - if (TW_STATUS != TW_MR_DATA_ACK) - { - kprintf("!TW_MR_DATA_ACK: %x\n", TWSR); - return EOF; - } - } - else - { - if (TW_STATUS != TW_MR_DATA_NACK) - { - kprintf("!TW_MR_DATA_NACK: %x\n", TWSR); - return EOF; - } - } - - /* avoid sign extension */ - return (int)(uint8_t)TWDR; -} - - -/** - * 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 i2c_send(const void *_buf, size_t count) -{ - const uint8_t *buf = (const uint8_t *)_buf; - - while (count--) - { - if (!i2c_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. - * - * \note a NACK is automatically given on the last received - * byte. - * - * \return true on success, false on error - */ -bool i2c_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--) - { - /* - * The last byte read does not has an ACK - * to stop communication. - */ - int c = i2c_get(count); - - if (c == EOF) - return false; - else - *buf++ = c; - } - - return true; -} - - -MOD_DEFINE(i2c); - -/** - * Initialize TWI module. - */ -void i2c_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); -#elif CPU_AVR_ATMEGA32 - PORTC |= BV(PC1) | BV(PC0); - DDRC |= BV(PC1) | BV(PC0); -#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); - ); - MOD_INIT(i2c); -} diff --git a/bertos/cpu/avr/drv/twi_avr.h b/bertos/cpu/avr/drv/twi_avr.h deleted file mode 100644 index 2d496df7..00000000 --- a/bertos/cpu/avr/drv/twi_avr.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * \file - * - * - * \version $Id$ - * - * \author Stefano Fedrigo - * \author Bernie Innocenti - * - * \brief Driver for the AVR ATMega TWI (interface) - */ - -#ifndef DRV_I2C_H -#define DRV_I2C_H - -#include - -bool i2c_start_w(uint8_t id); -bool i2c_start_r(uint8_t id); -void i2c_stop(void); -bool i2c_put(const uint8_t data); -bool i2c_send(const void *_buf, size_t count); -int i2c_get(bool ack); -bool i2c_recv(void *_buf, size_t count); -void i2c_init(void); - -#endif /* DRV_I2C_H */