142 lines
4.6 KiB
C
142 lines
4.6 KiB
C
/***************************************************************************
|
|
* Copyright (C) 01/2009 by Olaf Rempel *
|
|
* razzor@kopf-tisch.de *
|
|
* *
|
|
* 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; version 2 of the License, *
|
|
* *
|
|
* 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 <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
|
|
#include "alix-usv.h"
|
|
#include "usi-i2c-slave.h"
|
|
|
|
#define USI_MASK 0x0F
|
|
#define USI_MASK_ACKBIT 0x10 /* one (ack)bit / 8bits */
|
|
#define USI_MASK_OUTPUT 0x20 /* SDA is output / input */
|
|
|
|
#define USI_RESET 0x00 /* wait for Start Condition */
|
|
#define USI_START 0x01 /* Start detected */
|
|
#define USI_SLA 0x02 /* wait for Slave Address */
|
|
#define USI_SLAW_ACK 0x03 /* ACK Slave Address + Write (Master writes) */
|
|
#define USI_SLAR_ACK 0x04 /* ACK Slave Address + Read (Master reads) */
|
|
#define USI_DATW 0x05 /* receive Data */
|
|
#define USI_DATW_ACK 0x06 /* transmit ACK for received Data */
|
|
#define USI_DATR 0x07 /* transmit Data */
|
|
#define USI_DATR_ACK 0x08 /* receive ACK for transmitted Data */
|
|
|
|
static uint8_t usi_state;
|
|
|
|
void usi_statemachine(void)
|
|
{
|
|
static uint8_t bcnt;
|
|
|
|
uint8_t tmp = USIDR;
|
|
uint8_t state = usi_state & USI_MASK;
|
|
|
|
/* Start Condition detected */
|
|
if (state == USI_START) {
|
|
usi_state = USI_SLA;
|
|
|
|
/* Slave Address received => prepare ACK/NACK */
|
|
} else if (state == USI_SLA) {
|
|
bcnt = 0;
|
|
if (tmp == (I2C_ADDRESS | 0x00))
|
|
usi_state = USI_SLAW_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT;
|
|
|
|
else if (tmp == (I2C_ADDRESS | 0x01))
|
|
usi_state = USI_SLAR_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT;
|
|
|
|
else
|
|
usi_state = USI_RESET;
|
|
|
|
/* ACK after SLA+W / Data received => prepare data receive */
|
|
} else if (state == USI_SLAW_ACK || state == USI_DATW_ACK) {
|
|
usi_state = USI_DATW;
|
|
|
|
/* Data received => prepare ACK transmit */
|
|
} else if (state == USI_DATW) {
|
|
usi_write(tmp, bcnt++);
|
|
usi_state = USI_DATW_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT;
|
|
|
|
/* ACK after SLA+R transmitted / ACK after Data received => prepare data transmit */
|
|
} else if (state == USI_SLAR_ACK || (state == USI_DATR_ACK && tmp == 0x00)) {
|
|
USIDR = usi_read(bcnt++);
|
|
usi_state = USI_DATR | USI_MASK_OUTPUT;
|
|
|
|
/* Data transmitted => prepare ACK receive */
|
|
} else if (state == USI_DATR) {
|
|
usi_state = USI_DATR_ACK | USI_MASK_ACKBIT;
|
|
|
|
/* NACK after Data received / default => go idle */
|
|
} else {
|
|
usi_state = USI_RESET;
|
|
}
|
|
|
|
state = usi_state & USI_MASK;
|
|
if (state == USI_RESET) {
|
|
/* input */
|
|
DDRA &= ~I2C_SDA;
|
|
|
|
/* Enable StartCondition Interrupt, TWI Mode, count both edges */
|
|
USICR = (1<<USISIE) | (1<<USIWM1) | (1<<USICS1);
|
|
|
|
/* Clear Interrupt Flags, Clear Stop Condition Flag, wait for 2 edges */
|
|
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | ((16 -2)<<USICNT0);
|
|
|
|
} else if (state == USI_SLA) {
|
|
/* Enable Overflow Interrupt, TWI Mode, extend SCL on Overflow */
|
|
USICR = (1<<USISIE) | (1<<USIOIE) | (1<<USIWM1) | (1<<USIWM0) | (1<<USICS1);
|
|
|
|
/* Clear Interrupt Flags, Clear Stop Condition Flag, wait for 16 edges */
|
|
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | ((16 -16)<<USICNT0);
|
|
|
|
} else {
|
|
if (usi_state & USI_MASK_OUTPUT) {
|
|
DDRA |= I2C_SDA;
|
|
|
|
} else {
|
|
DDRA &= ~I2C_SDA;
|
|
}
|
|
|
|
if (usi_state & USI_MASK_ACKBIT) {
|
|
USIDR = 0x00;
|
|
USISR = (1<<USIOIF) | ((16 -2)<<USICNT0);
|
|
|
|
} else {
|
|
USISR = (1<<USIOIF) | ((16 -16)<<USICNT0);
|
|
}
|
|
}
|
|
}
|
|
|
|
ISR(USI_START_vect)
|
|
{
|
|
usi_state = USI_START;
|
|
|
|
/* check for STOP Condition */
|
|
while (PINA & I2C_SCL) {
|
|
if (PINA & I2C_SDA) {
|
|
usi_state = USI_RESET;
|
|
break;
|
|
}
|
|
}
|
|
|
|
usi_statemachine();
|
|
}
|
|
|
|
ISR(USI_OVF_vect)
|
|
{
|
|
usi_statemachine();
|
|
}
|