/* twi_master.c */ #include "twi_master.h" #include #include #include #include #include enum { TWI_SUCCESS, TWI_BUSY, TWI_FREE, TWI_ECHEC }; #if 0 #define TWI_DEBUG(x) rs232_putc (x) #else #define TWI_DEBUG(x) #endif #define NB_ITER_WAIT 40000 #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; #define SYSCLK 14745600UL /* compteur 10 ms pour attente du bus 40 000 iterations */ /* compteur x essais y ms secondes d'attende */ void twi_master_init (void) { /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ #if defined(TWPS0) TWSR = 0; #endif TWBR = (SYSCLK / 100000UL - 16) / 2; TWCR = _BV (TWEN) | _BV (TWIE); } int8_t twi_master_is_finished () { if (twi_state == TWI_SUCCESS || twi_state == TWI_ECHEC) { 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 (TWSTO); 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_ECHEC; } 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_ECHEC; } 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); }