haker_fox
Sep 22 2011, 09:32
QUOTE (Дима 128 @ Sep 22 2011, 13:16)

Ну эта задержка уже так для эксперимента =)))
Для какого эксперимента? Шина I2C до нескольких сотен килобит работает)
QUOTE (Дима 128 @ Sep 22 2011, 13:16)

функцией avrlib пользоваться раз она там есть уж =)))
У меня нет avrlib( Если речь об avrlibc из WinAVR, то не могу найти указанные функции. У меня WinAVR20071221.
QUOTE (Дима 128 @ Sep 22 2011, 13:16)

Или AVR Studio + avrlib не наш метод?
Да это-то тут при чем?

Используйте то, что Вам удобнее.
Попробуйте посмотреть на форуме
подобные темы.Народ не одну сотню DS1307 запустил)))
Я тоже с ней работал, но это было давно ( 5 лет назад ). Исходников не осталось, к сожалению, иначе бы с удовольствием поделился бы)))
haker_fox
Sep 23 2011, 11:47
QUOTE (Дима 128 @ Sep 23 2011, 17:07)

Ну не писать же библиотеку I2C С нуля если она там есть просто не совсем ясно как пользоваться ей =)))
А чего там писать?

Аппаратный модуль сам все сделает. Почитайте документацию, придет понимание, потом и библиотеку прикрутите)))
Вот писать программный I2C - это да, трудно! Хотя, если честно, тоже просто

Я где-то в прикрепленной теме (библиотеки полезных программ) лет 5 назад выкладывал библиотеку, которая и аппаратный TWI использует, и позволяет программно шину реализовать.
Если же хочется использовать именно avrlib, то читайте документацию. Там все должно быть.
Ну, а для полного понимания - спецификацию на шину I2C. Я уже Вам это советовал. Когда-то все равно придется это сделать.
Дима 128
Sep 23 2011, 18:30
Вы про бит чтения.запись? Там получается что у устройства адрес 1101000 семи разрядный + бит этот получается 11010000=0xd0 Я на основе примера из CodeVisin пытался сделать там часы работают
i2c_start();
i2c_write(0xd0);
i2c_write(0);
i2c_start();
i2c_write(0xd1);
*sec=bcd2bin(i2c_read(1));
*min=bcd2bin(i2c_read(1));
*hour=bcd2bin(i2c_read(0));
i2c_stop();
А вот как это с функциями из avrlib это проделать не знаю что то упускаю пробовал вот так
i2cSetBitrate(100);
i2cInit();
i2cSendStart();
i2cSendByte(0xD0);
i2cSendByte(0);
i2cSendStop();
i2cSendStart();
i2cSendByte(0xD1);
sek=i2cGetReceivedByte();
i2cSendStop();
Но где то ошибка есть =(((
Вот функции которые есть в avrlib
// functions
//! Initialize I2C (TWI) interface
void i2cInit(void);
//! Set the I2C transaction bitrate (in KHz)
void i2cSetBitrate(u16 bitrateKHz);
// I2C setup and configurations commands
//! Set the local (AVR processor's) I2C device address
void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn);
//! Set the user function which handles receiving (incoming) data as a slave
void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(u08 receiveDataLength, u08* recieveData));
//! Set the user function which handles transmitting (outgoing) data as a slave
void i2cSetSlaveTransmitHandler(u08 (*i2cSlaveTx_func)(u08 transmitDataLengthMax, u08* transmitData));
// Low-level I2C transaction commands
//! Send an I2C start condition in Master mode
void i2cSendStart(void);
//! Send an I2C stop condition in Master mode
void i2cSendStop(void);
//! Wait for current I2C operation to complete
void i2cWaitForComplete(void);
//! Send an (address|R/W) combination or a data byte over I2C
void i2cSendByte(u08 data);
//! Receive a data byte over I2C
// ackFlag = TRUE if recevied data should be ACK'ed
// ackFlag = FALSE if recevied data should be NACK'ed
void i2cReceiveByte(u08 ackFlag);
//! Pick up the data that was received with i2cReceiveByte()
u08 i2cGetReceivedByte(void);
//! Get current I2c bus status from TWSR
u08 i2cGetStatus(void);
// high-level I2C transaction commands
//! send I2C data to a device on the bus
void i2cMasterSend(u08 deviceAddr, u08 length, u08 *data);
//! receive I2C data from a device on the bus
void i2cMasterReceive(u08 deviceAddr, u08 length, u08* data);
//! send I2C data to a device on the bus (non-interrupt based)
u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data);
//! receive I2C data from a device on the bus (non-interrupt based)
u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data);
//! Get the current high-level state of the I2C interface
eI2cStateType i2cGetState(void);
#endif
Дима 128
Sep 25 2011, 16:27
Вот функции из сишного файла
#include <avr/io.h>
#include <avr/interrupt.h>
#include "i2c.h"
#include "rprintf.h" // include printf function library
#include "uart2.h"
// Standard I2C bit rates are:
// 100KHz for slow speed
// 400KHz for high speed
//#define I2C_DEBUG
// I2C state and address variables
static volatile eI2cStateType I2cState;
static u08 I2cDeviceAddrRW;
// send/transmit buffer (outgoing data)
static u08 I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
static u08 I2cSendDataIndex;
static u08 I2cSendDataLength;
// receive buffer (incoming data)
static u08 I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
static u08 I2cReceiveDataIndex;
static u08 I2cReceiveDataLength;
// function pointer to i2c receive routine
//! I2cSlaveReceive is called when this processor
// is addressed as a slave for writing
static void (*i2cSlaveReceive)(u08 receiveDataLength, u08* recieveData);
//! I2cSlaveTransmit is called when this processor
// is addressed as a slave for reading
static u08 (*i2cSlaveTransmit)(u08 transmitDataLengthMax, u08* transmitData);
// functions
void i2cInit(void)
{
// set pull-up resistors on I2C bus pins
// TODO: should #ifdef these
sbi(PORTC, 0); // i2c SCL on ATmega163,323,16,32,etc
sbi(PORTC, 1); // i2c SDA on ATmega163,323,16,32,etc
sbi(PORTD, 0); // i2c SCL on ATmega128,64
sbi(PORTD, 1); // i2c SDA on ATmega128,64
// clear SlaveReceive and SlaveTransmit handler to null
i2cSlaveReceive = 0;
i2cSlaveTransmit = 0;
// set i2c bit rate to 100KHz
i2cSetBitrate(100);
// enable TWI (two-wire interface)
sbi(TWCR, TWEN);
// set state
I2cState = I2C_IDLE;
// enable TWI interrupt and slave address ACK
sbi(TWCR, TWIE);
sbi(TWCR, TWEA);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// enable interrupts
sei();
}
void i2cSetBitrate(u16 bitrateKHz)
{
u08 bitrate_div;
// set i2c bitrate
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
// for processors with additional bitrate division (mega128)
// SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
// set TWPS to zero
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
#endif
// calculate bitrate division
bitrate_div = ((F_CPU/1000l)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
outb(TWBR, bitrate_div);
}
void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn)
{
// set local device address (used in slave mode only)
outb(TWAR, ((deviceAddr&0xFE) | (genCallEn?1:0)) );
}
void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(u08 receiveDataLength, u08* recieveData))
{
i2cSlaveReceive = i2cSlaveRx_func;
}
void i2cSetSlaveTransmitHandler(u08 (*i2cSlaveTx_func)(u08 transmitDataLengthMax, u08* transmitData))
{
i2cSlaveTransmit = i2cSlaveTx_func;
}
inline void i2cSendStart(void)
{
// send start condition
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
}
inline void i2cSendStop(void)
{
// transmit stop condition
// leave with TWEA on for slave receiving
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)|BV(TWSTO));
}
inline void i2cWaitForComplete(void)
{
// wait for i2c interface to complete operation
while( !(inb(TWCR) & BV(TWINT)) );
}
inline void i2cSendByte(u08 data)
{
// save data to the TWDR
outb(TWDR, data);
// begin send
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
inline void i2cReceiveByte(u08 ackFlag)
{
// begin receive over i2c
if( ackFlag )
{
// ackFlag = TRUE: ACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// ackFlag = FALSE: NACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
}
inline u08 i2cGetReceivedByte(void)
{
// retieve received data byte from i2c TWDR
return( inb(TWDR) );
}
inline u08 i2cGetStatus(void)
{
// retieve current i2c status from i2c TWSR
return( inb(TWSR) );
}
void i2cMasterSend(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_TX;
// save data
I2cDeviceAddrRW = (deviceAddr & 0xFE); // RW cleared: write operation
for(i=0; i<length; i++)
I2cSendData[i] = *data++;
I2cSendDataIndex = 0;
I2cSendDataLength = length;
// send start condition
i2cSendStart();
}
void i2cMasterReceive(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_RX;
// save data
I2cDeviceAddrRW = (deviceAddr|0x01); // RW set: read operation
I2cReceiveDataIndex = 0;
I2cReceiveDataLength = length;
// send start condition
i2cSendStart();
// wait for data
while(I2cState);
// return data
for(i=0; i<length; i++)
*data++ = I2cReceiveData[i];
}
u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with write
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MT_SLA_ACK)
{
// send data
while(length)
{
i2cSendByte( *data++ );
i2cWaitForComplete();
length--;
}
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
while( !(inb(TWCR) & BV(TWSTO)) );
// enable TWI interrupt
sbi(TWCR, TWIE);
return retval;
}
u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with read
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MR_SLA_ACK)
{
// accept receive data and ack it
while(length > 1)
{
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
// decrement length
length--;
}
// accept receive data and nack it (last-byte signal)
i2cReceiveByte(FALSE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
// enable TWI interrupt
sbi(TWCR, TWIE);
return retval;
}
/*
void i2cMasterTransferNI(u08 deviceAddr, u08 sendlength, u08* senddata, u08 receivelength, u08* receivedata)
{
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// if there's data to be sent, do it
if(sendlength)
{
// send device address with write
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// send data
while(sendlength)
{
i2cSendByte( *senddata++ );
i2cWaitForComplete();
sendlength--;
}
}
// if there's data to be received, do it
if(receivelength)
{
// send repeated start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with read
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// accept receive data and ack it
while(receivelength > 1)
{
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*receivedata++ = i2cGetReceivedByte();
// decrement length
receivelength--;
}
// accept receive data and nack it (last-byte signal)
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*receivedata++ = i2cGetReceivedByte();
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
while( !(inb(TWCR) & BV(TWSTO)) );
// enable TWI interrupt
sbi(TWCR, TWIE);
}
*/
//! I2C (TWI) interrupt service routine
SIGNAL(SIG_2WIRE_SERIAL)
{
// read status bits
u08 status = inb(TWSR) & TWSR_STATUS_MASK;
switch(status)
{
// Master General
case TW_START: // 0x08: Sent start condition
case TW_REP_START: // 0x10: Sent repeated start condition
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: M->START\r\n");
rprintfInit(uart1SendByte);
#endif
// send device address
i2cSendByte(I2cDeviceAddrRW);
break;
// Master Transmitter & Receiver status codes
case TW_MT_SLA_ACK: // 0x18: Slave address acknowledged
case TW_MT_DATA_ACK: // 0x28: Data acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MT->SLA_ACK or DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
if(I2cSendDataIndex < I2cSendDataLength)
{
// send data
i2cSendByte( I2cSendData[I2cSendDataIndex++] );
}
else
{
// transmit stop condition, enable SLA ACK
i2cSendStop();
// set state
I2cState = I2C_IDLE;
}
break;
case TW_MR_DATA_NACK: // 0x58: Data received, NACK reply issued
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// store final received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// continue to transmit STOP condition
case TW_MR_SLA_NACK: // 0x48: Slave address not acknowledged
case TW_MT_SLA_NACK: // 0x20: Slave address not acknowledged
case TW_MT_DATA_NACK: // 0x30: Data not acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MTR->SLA_NACK or MT->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// transmit stop condition, enable SLA ACK
i2cSendStop();
// set state
I2cState = I2C_IDLE;
break;
case TW_MT_ARB_LOST: // 0x38: Bus arbitration lost
//case TW_MR_ARB_LOST: // 0x38: Bus arbitration lost
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MT->ARB_LOST\r\n");
rprintfInit(uart1SendByte);
#endif
// release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
// set state
I2cState = I2C_IDLE;
// release bus and transmit start when bus is free
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
break;
case TW_MR_DATA_ACK: // 0x50: Data acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// store received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// fall-through to see if more bytes will be received
case TW_MR_SLA_ACK: // 0x40: Slave address acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
// data byte will be received, reply with ACK (more bytes in transfer)
i2cReceiveByte(TRUE);
else
// data byte will be received, reply with NACK (final byte in transfer)
i2cReceiveByte(FALSE);
break;
// Slave Receiver status codes
case TW_SR_SLA_ACK: // 0x60: own SLA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_SLA_ACK: // 0x68: own SLA+W has been received, ACK has been returned
case TW_SR_GCALL_ACK: // 0x70: GCA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: GCA+W has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// we are being addressed as slave for writing (data will be received from master)
// set state
I2cState = I2C_SLAVE_RX;
// prepare buffer
I2cReceiveDataIndex = 0;
// receive data byte and return ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
break;
case TW_SR_DATA_ACK: // 0x80: data byte has been received, ACK has been returned
case TW_SR_GCALL_DATA_ACK: // 0x90: data byte has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// get previously received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// check receive buffer status
if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
{
// receive data byte and return ACK
i2cReceiveByte(TRUE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// receive data byte and return NACK
i2cReceiveByte(FALSE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
break;
case TW_SR_DATA_NACK: // 0x88: data byte has been received, NACK has been returned
case TW_SR_GCALL_DATA_NACK: // 0x98: data byte has been received, NACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// receive data byte and return NACK
i2cReceiveByte(FALSE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_SR_STOP: // 0xA0: STOP or REPEATED START has been received while addressed as slave
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->SR_STOP\r\n");
rprintfInit(uart1SendByte);
#endif
// switch to SR mode with SLA ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// i2c receive is complete, call i2cSlaveReceive
if(i2cSlaveReceive) i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
// set state
I2cState = I2C_IDLE;
break;
// Slave Transmitter
case TW_ST_SLA_ACK: // 0xA8: own SLA+R has been received, ACK has been returned
case TW_ST_ARB_LOST_SLA_ACK: // 0xB0: GCA+R has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// we are being addressed as slave for reading (data must be transmitted back to master)
// set state
I2cState = I2C_SLAVE_TX;
// request data from application
if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
// reset data index
I2cSendDataIndex = 0;
// fall-through to transmit first data byte
case TW_ST_DATA_ACK: // 0xB8: data byte has been transmitted, ACK has been received
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// transmit data byte
outb(TWDR, I2cSendData[I2cSendDataIndex++]);
if(I2cSendDataIndex < I2cSendDataLength)
// expect ACK to data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
else
// expect NACK to data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_ST_DATA_NACK: // 0xC0: data byte has been transmitted, NACK has been received
case TW_ST_LAST_DATA: // 0xC8:
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->DATA_NACK or LAST_DATA\r\n");
rprintfInit(uart1SendByte);
#endif
// all done
// switch to open slave
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
// Misc
case TW_NO_INFO: // 0xF8: No relevant state information
// do nothing
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: NO_INFO\r\n");
rprintfInit(uart1SendByte);
#endif
break;
case TW_BUS_ERROR: // 0x00: Bus error due to illegal start or stop condition
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: BUS_ERROR\r\n");
rprintfInit(uart1SendByte);
#endif
// reset internal hardware and release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
}
}
eI2cStateType i2cGetState(void)
{
return I2cState;
}
Вот функции из сишного файла
#include <avr/io.h>
#include <avr/interrupt.h>
#include "i2c.h"
#include "rprintf.h" // include printf function library
#include "uart2.h"
// Standard I2C bit rates are:
// 100KHz for slow speed
// 400KHz for high speed
//#define I2C_DEBUG
// I2C state and address variables
static volatile eI2cStateType I2cState;
static u08 I2cDeviceAddrRW;
// send/transmit buffer (outgoing data)
static u08 I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
static u08 I2cSendDataIndex;
static u08 I2cSendDataLength;
// receive buffer (incoming data)
static u08 I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
static u08 I2cReceiveDataIndex;
static u08 I2cReceiveDataLength;
// function pointer to i2c receive routine
//! I2cSlaveReceive is called when this processor
// is addressed as a slave for writing
static void (*i2cSlaveReceive)(u08 receiveDataLength, u08* recieveData);
//! I2cSlaveTransmit is called when this processor
// is addressed as a slave for reading
static u08 (*i2cSlaveTransmit)(u08 transmitDataLengthMax, u08* transmitData);
// functions
void i2cInit(void)
{
// set pull-up resistors on I2C bus pins
// TODO: should #ifdef these
sbi(PORTC, 0); // i2c SCL on ATmega163,323,16,32,etc
sbi(PORTC, 1); // i2c SDA on ATmega163,323,16,32,etc
sbi(PORTD, 0); // i2c SCL on ATmega128,64
sbi(PORTD, 1); // i2c SDA on ATmega128,64
// clear SlaveReceive and SlaveTransmit handler to null
i2cSlaveReceive = 0;
i2cSlaveTransmit = 0;
// set i2c bit rate to 100KHz
i2cSetBitrate(100);
// enable TWI (two-wire interface)
sbi(TWCR, TWEN);
// set state
I2cState = I2C_IDLE;
// enable TWI interrupt and slave address ACK
sbi(TWCR, TWIE);
sbi(TWCR, TWEA);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// enable interrupts
sei();
}
void i2cSetBitrate(u16 bitrateKHz)
{
u08 bitrate_div;
// set i2c bitrate
// SCL freq = F_CPU/(16+2*TWBR))
#ifdef TWPS0
// for processors with additional bitrate division (mega128)
// SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
// set TWPS to zero
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
#endif
// calculate bitrate division
bitrate_div = ((F_CPU/1000l)/bitrateKHz);
if(bitrate_div >= 16)
bitrate_div = (bitrate_div-16)/2;
outb(TWBR, bitrate_div);
}
void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn)
{
// set local device address (used in slave mode only)
outb(TWAR, ((deviceAddr&0xFE) | (genCallEn?1:0)) );
}
void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(u08 receiveDataLength, u08* recieveData))
{
i2cSlaveReceive = i2cSlaveRx_func;
}
void i2cSetSlaveTransmitHandler(u08 (*i2cSlaveTx_func)(u08 transmitDataLengthMax, u08* transmitData))
{
i2cSlaveTransmit = i2cSlaveTx_func;
}
inline void i2cSendStart(void)
{
// send start condition
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
}
inline void i2cSendStop(void)
{
// transmit stop condition
// leave with TWEA on for slave receiving
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)|BV(TWSTO));
}
inline void i2cWaitForComplete(void)
{
// wait for i2c interface to complete operation
while( !(inb(TWCR) & BV(TWINT)) );
}
inline void i2cSendByte(u08 data)
{
// save data to the TWDR
outb(TWDR, data);
// begin send
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
inline void i2cReceiveByte(u08 ackFlag)
{
// begin receive over i2c
if( ackFlag )
{
// ackFlag = TRUE: ACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// ackFlag = FALSE: NACK the recevied data
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
}
inline u08 i2cGetReceivedByte(void)
{
// retieve received data byte from i2c TWDR
return( inb(TWDR) );
}
inline u08 i2cGetStatus(void)
{
// retieve current i2c status from i2c TWSR
return( inb(TWSR) );
}
void i2cMasterSend(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_TX;
// save data
I2cDeviceAddrRW = (deviceAddr & 0xFE); // RW cleared: write operation
for(i=0; i<length; i++)
I2cSendData[i] = *data++;
I2cSendDataIndex = 0;
I2cSendDataLength = length;
// send start condition
i2cSendStart();
}
void i2cMasterReceive(u08 deviceAddr, u08 length, u08* data)
{
u08 i;
// wait for interface to be ready
while(I2cState);
// set state
I2cState = I2C_MASTER_RX;
// save data
I2cDeviceAddrRW = (deviceAddr|0x01); // RW set: read operation
I2cReceiveDataIndex = 0;
I2cReceiveDataLength = length;
// send start condition
i2cSendStart();
// wait for data
while(I2cState);
// return data
for(i=0; i<length; i++)
*data++ = I2cReceiveData[i];
}
u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with write
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MT_SLA_ACK)
{
// send data
while(length)
{
i2cSendByte( *data++ );
i2cWaitForComplete();
length--;
}
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
while( !(inb(TWCR) & BV(TWSTO)) );
// enable TWI interrupt
sbi(TWCR, TWIE);
return retval;
}
u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data)
{
u08 retval = I2C_OK;
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with read
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// check if device is present and live
if( inb(TWSR) == TW_MR_SLA_ACK)
{
// accept receive data and ack it
while(length > 1)
{
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
// decrement length
length--;
}
// accept receive data and nack it (last-byte signal)
i2cReceiveByte(FALSE);
i2cWaitForComplete();
*data++ = i2cGetReceivedByte();
}
else
{
// device did not ACK it's address,
// data will not be transferred
// return error
retval = I2C_ERROR_NODEV;
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
// enable TWI interrupt
sbi(TWCR, TWIE);
return retval;
}
/*
void i2cMasterTransferNI(u08 deviceAddr, u08 sendlength, u08* senddata, u08 receivelength, u08* receivedata)
{
// disable TWI interrupt
cbi(TWCR, TWIE);
// send start condition
i2cSendStart();
i2cWaitForComplete();
// if there's data to be sent, do it
if(sendlength)
{
// send device address with write
i2cSendByte( deviceAddr & 0xFE );
i2cWaitForComplete();
// send data
while(sendlength)
{
i2cSendByte( *senddata++ );
i2cWaitForComplete();
sendlength--;
}
}
// if there's data to be received, do it
if(receivelength)
{
// send repeated start condition
i2cSendStart();
i2cWaitForComplete();
// send device address with read
i2cSendByte( deviceAddr | 0x01 );
i2cWaitForComplete();
// accept receive data and ack it
while(receivelength > 1)
{
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*receivedata++ = i2cGetReceivedByte();
// decrement length
receivelength--;
}
// accept receive data and nack it (last-byte signal)
i2cReceiveByte(TRUE);
i2cWaitForComplete();
*receivedata++ = i2cGetReceivedByte();
}
// transmit stop condition
// leave with TWEA on for slave receiving
i2cSendStop();
while( !(inb(TWCR) & BV(TWSTO)) );
// enable TWI interrupt
sbi(TWCR, TWIE);
}
*/
//! I2C (TWI) interrupt service routine
SIGNAL(SIG_2WIRE_SERIAL)
{
// read status bits
u08 status = inb(TWSR) & TWSR_STATUS_MASK;
switch(status)
{
// Master General
case TW_START: // 0x08: Sent start condition
case TW_REP_START: // 0x10: Sent repeated start condition
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: M->START\r\n");
rprintfInit(uart1SendByte);
#endif
// send device address
i2cSendByte(I2cDeviceAddrRW);
break;
// Master Transmitter & Receiver status codes
case TW_MT_SLA_ACK: // 0x18: Slave address acknowledged
case TW_MT_DATA_ACK: // 0x28: Data acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MT->SLA_ACK or DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
if(I2cSendDataIndex < I2cSendDataLength)
{
// send data
i2cSendByte( I2cSendData[I2cSendDataIndex++] );
}
else
{
// transmit stop condition, enable SLA ACK
i2cSendStop();
// set state
I2cState = I2C_IDLE;
}
break;
case TW_MR_DATA_NACK: // 0x58: Data received, NACK reply issued
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// store final received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// continue to transmit STOP condition
case TW_MR_SLA_NACK: // 0x48: Slave address not acknowledged
case TW_MT_SLA_NACK: // 0x20: Slave address not acknowledged
case TW_MT_DATA_NACK: // 0x30: Data not acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MTR->SLA_NACK or MT->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// transmit stop condition, enable SLA ACK
i2cSendStop();
// set state
I2cState = I2C_IDLE;
break;
case TW_MT_ARB_LOST: // 0x38: Bus arbitration lost
//case TW_MR_ARB_LOST: // 0x38: Bus arbitration lost
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MT->ARB_LOST\r\n");
rprintfInit(uart1SendByte);
#endif
// release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
// set state
I2cState = I2C_IDLE;
// release bus and transmit start when bus is free
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
break;
case TW_MR_DATA_ACK: // 0x50: Data acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// store received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// fall-through to see if more bytes will be received
case TW_MR_SLA_ACK: // 0x40: Slave address acknowledged
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: MR->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
// data byte will be received, reply with ACK (more bytes in transfer)
i2cReceiveByte(TRUE);
else
// data byte will be received, reply with NACK (final byte in transfer)
i2cReceiveByte(FALSE);
break;
// Slave Receiver status codes
case TW_SR_SLA_ACK: // 0x60: own SLA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_SLA_ACK: // 0x68: own SLA+W has been received, ACK has been returned
case TW_SR_GCALL_ACK: // 0x70: GCA+W has been received, ACK has been returned
case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: GCA+W has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// we are being addressed as slave for writing (data will be received from master)
// set state
I2cState = I2C_SLAVE_RX;
// prepare buffer
I2cReceiveDataIndex = 0;
// receive data byte and return ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
break;
case TW_SR_DATA_ACK: // 0x80: data byte has been received, ACK has been returned
case TW_SR_GCALL_DATA_ACK: // 0x90: data byte has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// get previously received data byte
I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
// check receive buffer status
if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
{
// receive data byte and return ACK
i2cReceiveByte(TRUE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
}
else
{
// receive data byte and return NACK
i2cReceiveByte(FALSE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
}
break;
case TW_SR_DATA_NACK: // 0x88: data byte has been received, NACK has been returned
case TW_SR_GCALL_DATA_NACK: // 0x98: data byte has been received, NACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->DATA_NACK\r\n");
rprintfInit(uart1SendByte);
#endif
// receive data byte and return NACK
i2cReceiveByte(FALSE);
//outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_SR_STOP: // 0xA0: STOP or REPEATED START has been received while addressed as slave
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: SR->SR_STOP\r\n");
rprintfInit(uart1SendByte);
#endif
// switch to SR mode with SLA ACK
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// i2c receive is complete, call i2cSlaveReceive
if(i2cSlaveReceive) i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
// set state
I2cState = I2C_IDLE;
break;
// Slave Transmitter
case TW_ST_SLA_ACK: // 0xA8: own SLA+R has been received, ACK has been returned
case TW_ST_ARB_LOST_SLA_ACK: // 0xB0: GCA+R has been received, ACK has been returned
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->SLA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// we are being addressed as slave for reading (data must be transmitted back to master)
// set state
I2cState = I2C_SLAVE_TX;
// request data from application
if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
// reset data index
I2cSendDataIndex = 0;
// fall-through to transmit first data byte
case TW_ST_DATA_ACK: // 0xB8: data byte has been transmitted, ACK has been received
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->DATA_ACK\r\n");
rprintfInit(uart1SendByte);
#endif
// transmit data byte
outb(TWDR, I2cSendData[I2cSendDataIndex++]);
if(I2cSendDataIndex < I2cSendDataLength)
// expect ACK to data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
else
// expect NACK to data byte
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
break;
case TW_ST_DATA_NACK: // 0xC0: data byte has been transmitted, NACK has been received
case TW_ST_LAST_DATA: // 0xC8:
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: ST->DATA_NACK or LAST_DATA\r\n");
rprintfInit(uart1SendByte);
#endif
// all done
// switch to open slave
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
// Misc
case TW_NO_INFO: // 0xF8: No relevant state information
// do nothing
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: NO_INFO\r\n");
rprintfInit(uart1SendByte);
#endif
break;
case TW_BUS_ERROR: // 0x00: Bus error due to illegal start or stop condition
#ifdef I2C_DEBUG
rprintfInit(uart1AddToTxBuffer);
rprintf("I2C: BUS_ERROR\r\n");
rprintfInit(uart1SendByte);
#endif
// reset internal hardware and release bus
outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
// set state
I2cState = I2C_IDLE;
break;
}
}
eI2cStateType i2cGetState(void)
{
return I2cState;
}