/* twi_master.c */ /* avr.twi.master - TWI master module. {{{ * * Copyright (C) 2005 Clément Demonchy * * Robot APB Team/Efrei 2006. * Web: http://assos.efrei.fr/robot/ * Email: robot AT efrei DOT fr * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * }}} */ #include "common.h" #include "twi_master.h" #include "io.h" #include enum { TWI_SUCCESS, TWI_BUSY, TWI_FREE, TWI_FAILURE }; #if 0 #define TWI_DEBUG(x) uart0_putc (x) #else #define TWI_DEBUG(x) #endif #define NB_RETRY 5 static uint8_t *buffer; static uint8_t twi_dest_addr; static uint8_t twi_len; static uint8_t twi_idx; static uint8_t twi_nb_retry; volatile uint8_t twi_state = TWI_FREE; void twi_master_init (void) { /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ #if defined(TWPS0) TWSR = 0; #endif TWBR = (AC_FREQ / 100000UL - 16) / 2; TWCR = _BV (TWEN) | _BV (TWIE); } int8_t twi_master_is_finished () { if (twi_state == TWI_SUCCESS || twi_state == TWI_FAILURE) { twi_state = TWI_FREE; return 1; } else return 0; } int8_t twi_master_send (uint8_t addr, uint8_t *data, uint8_t len) { if (twi_state == TWI_FREE) { TWI_DEBUG ('a'); twi_state = TWI_BUSY; twi_nb_retry = 0; twi_dest_addr = addr & 0xfe; twi_len = len; buffer = data; /* envoie du start */ TWCR |= _BV(TWSTA); TWCR |= _BV(TWINT); return 0; } else { TWI_DEBUG ('x'); return -1; } } int8_t twi_master_read (uint8_t addr, uint8_t *data, uint8_t len) { if (twi_state == TWI_FREE) { TWI_DEBUG ('a'); twi_state = TWI_BUSY; twi_nb_retry = 0; twi_dest_addr = addr | 0x01; twi_len = len; buffer = data; TWCR |= _BV(TWSTA) | _BV (TWINT); return 0; } else return -1; } SIGNAL (SIG_2WIRE_SERIAL) { TWI_DEBUG ('y'); switch (TW_STATUS) { /* Master */ case TW_START: case TW_REP_START: /* start transmis, on envoie l'adresse */ TWI_DEBUG ('d'); TWCR &= ~ (_BV (TWSTA) | _BV (TWSTO) | _BV (TWINT)); TWDR = twi_dest_addr; twi_idx = 0; break; case TW_MT_ARB_LOST: /* valable pour le receiver aussi */ /* todo */ TWI_DEBUG ('e'); break; /* Master Transmitter */ case TW_MT_DATA_ACK: case TW_MT_SLA_ACK: /* slave ok * On envoi des données si il en reste */ if (twi_idx < twi_len) { TWI_DEBUG ('f'); TWDR = buffer[twi_idx ++]; } else { TWCR |= _BV (TWSTO); TWI_DEBUG ('g'); twi_state = TWI_SUCCESS; } break; case TW_MT_SLA_NACK: /* le slave ne repond plus * on essaye NB_RETRY avant d'arreter */ if (twi_nb_retry < NB_RETRY) { TWI_DEBUG ('h'); TWCR |= _BV (TWSTA); twi_nb_retry ++; } else { TWI_DEBUG ('i'); TWCR |= _BV (TWSTO); twi_state = TWI_FAILURE; } break; case TW_MT_DATA_NACK: /* le slave ne veut plus de donnée */ TWI_DEBUG ('j'); TWCR |= _BV (TWSTO); twi_state = TWI_SUCCESS; break; /* Master Receiver */ case TW_MR_SLA_ACK: TWI_DEBUG ('p'); if (twi_len > 1) /* on recoit plusieurs octet */ { TWI_DEBUG ('k'); TWCR |= _BV (TWEA); } break; case TW_MR_SLA_NACK: if (twi_nb_retry < NB_RETRY) { TWI_DEBUG ('l'); TWCR |= _BV (TWEA); } else { TWI_DEBUG ('m'); TWCR |= _BV (TWSTO); twi_state = TWI_FAILURE; } break; case TW_MR_DATA_ACK: buffer[twi_idx ++] = TWDR; TWI_DEBUG ('n'); if (twi_idx == (twi_len - 1)) TWCR &= ~ _BV (TWEA); break; case TW_MR_DATA_NACK: /* dernier byte */ twi_state = TWI_SUCCESS; TWI_DEBUG ('o'); buffer[twi_idx ++] = TWDR; TWCR |= _BV (TWSTO); break; } TWCR |= _BV (TWINT); }