From 7fd0a31df85c69e1293d4e208e233cca8b38158f Mon Sep 17 00:00:00 2001 From: batt Date: Fri, 5 Sep 2008 16:08:42 +0000 Subject: [PATCH] Refactor AVR twi driver to supply twi_get; add ATMega32 support. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1790 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/avr/drv/twi_avr.c | 77 +++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/bertos/cpu/avr/drv/twi_avr.c b/bertos/cpu/avr/drv/twi_avr.c index 0ce1a1ee..270efe45 100644 --- a/bertos/cpu/avr/drv/twi_avr.c +++ b/bertos/cpu/avr/drv/twi_avr.c @@ -45,9 +45,11 @@ #include "cfg/cfg_twi.h" #include #include // BV() +#include #include #include +#include #include @@ -91,6 +93,7 @@ bool twi_start_w(uint8_t id) * 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 (twi_start()) { TWDR = id & ~READ_BIT; @@ -104,6 +107,11 @@ bool twi_start_w(uint8_t id) 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; @@ -163,6 +171,40 @@ bool twi_put(const uint8_t data) 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 twi_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 @@ -190,6 +232,9 @@ bool twi_send(const void *_buf, size_t count) * * 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 twi_recv(void *_buf, size_t count) @@ -202,32 +247,24 @@ bool twi_recv(void *_buf, size_t count) */ while (count--) { - TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0); - WAIT_TWI_READY; + /* + * The last byte read does not has an ACK + * to stop communication. + */ + int c = twi_get(count); - if (count) - { - if (TW_STATUS != TW_MR_DATA_ACK) - { - kprintf("!TW_MR_DATA_ACK: %x\n", TWSR); - return false; - } - } + if (c == EOF) + return false; else - { - if (TW_STATUS != TW_MR_DATA_NACK) - { - kprintf("!TW_MR_DATA_NACK: %x\n", TWSR); - return false; - } - } - *buf++ = TWDR; + *buf++ = c; } return true; } +MOD_DEFINE(twi); + /** * Initialize TWI module. */ @@ -247,6 +284,9 @@ void twi_init(void) #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 @@ -265,4 +305,5 @@ void twi_init(void) TWSR = 0; TWCR = BV(TWEN); ); + MOD_INIT(twi); } -- 2.25.1