Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
На главную   | Карта сайта | Пишите нам | В избранное
Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс.
e-mail:jobsmp@pochta.ru

Телесистемы | Электроника | Конференция «Микроконтроллеры и их применение»

и мой вариант работы с TWI для AVR [+] (Все работает в прерывании, и по факту окончания передачи вызывается функция пользователя)

Отправлено MegaJohn 02 марта 2009 г. 16:04
В ответ на: Вот мой иср. отправлено пользователем 1111 02 марта 2009 г. 15:36


#include "i2c.h"

#define START_COND_TRANSMITTED 0x08 // 0000 1000
#define REPEATED_START_COND_TRANSMITTED 0x10 // 0001 0000
#define SLA_W_TRANSMITTED_ACK_RECEIVED 0x18 // 0001 1000
#define SLA_W_TRANSMITTED_NACK_RECEIVED 0x20 // 0010 0000
#define DATA_TRANSMITTED_ACK_RECEIVED 0x28 // 0010 1000
#define DATA_TRANSMITTED_NACK_RECEIVED 0x30 // 0011 0000
#define ARBITRATION_LOST 0x38 // 0011 1000
#define SLA_R_TRANSMITTED_ACK_RECEIVED 0x40 // 0100 0000
#define SLA_R_TRANSMITTED_NACK_RECEIVED 0x48 // 0100 1000
#define DATA_RECEIVED_ACK_RETURNED 0x50 // 0101 0000
#define DATA_RECEIVED_NACK_RETURNED 0x58 // 0101 1000

#define COMMON ((1 << TWINT) | (1 << TWEN) | (1 << TWIE))

#define NOTDEF 0
#define START 1
#define START_REP 2
#define STOP 3
#define SLA_W 4
#define SLA_R 5
#define DATA_R 6
#define DATA_W 7
#define ADDR 8

static u8 cmd_sequence[ 8 ], cmd_sequence_i = 0;

enum
{
e_idle,
e_busy,
e_busy_wait_stop,
e_error,
}volatile eMode = e_idle;

u8 i2c_addr_slave = 0;
u8 *pData;
u8 DataLen;
u8 DataAddr;
u8 *bytes_transfer_cnt;
u8 bytes_transfer_cnt_local;
u8 skip_1st_byte_on_read = false;

i2c_errors status = e_i2c_no_err;

static i2c_callback_on_finish f_ptr;

//////////////////////////////////////
//
void i2c_init( void )
{
TWSR = ( 1 << TWPS1 ) | ( 1 << TWPS0 ); // prescaller = 64
TWBR = 180;

TWCR = COMMON;
}

//////////////////////////////////////
//
void i2c_set_addr_slave( u8 addr )
{
i2c_addr_slave = addr;
}

//////////////////////////////////////
#pragma inline
void terminate( i2c_errors state )
{
TWCR = COMMON | (1 << TWSTO); //send stop condition

if( state == e_i2c_transfer_ok )
eMode = e_busy_wait_stop;
else
eMode = e_error;

status = state;
if (f_ptr) f_ptr();
}

//////////////////////////////////////
#pragma inline
void data_transfer( void )
{
if( DataLen-- )
{
if( cmd_sequence[ cmd_sequence_i ] == DATA_R )
{
if( skip_1st_byte_on_read )
skip_1st_byte_on_read = false;
else
*pData++ = TWDR;

if( DataLen )
TWCR = COMMON | (1 << TWEA);
else
TWCR = COMMON; // на последнем байте не выдавать ACK ( то есть выдать NACK )
}
else
{
TWDR = *pData++;
TWCR = COMMON;
}

(*bytes_transfer_cnt)++;
}
else
{
if( cmd_sequence[ cmd_sequence_i ] == DATA_R )
*pData++ = TWDR;

if( cmd_sequence[ ++cmd_sequence_i ] == STOP )
terminate( e_i2c_transfer_ok );
}
}

//////////////////////////////////////
#pragma inline
void send_start_condition( void )
{
if( cmd_sequence[ cmd_sequence_i ] == START )
{
eMode = e_busy;
TWCR = COMMON | (1 << TWSTA);
status = e_i2c_no_err;
}
}

///////////////////////////////////////////////////////////////////////////////////////
#pragma vector = TWI_vect
__interrupt void twi_vect_interrupt( void )
{
switch( cmd_sequence[ cmd_sequence_i ] )
{
///////////////////
case START:
if( (TWSR & 0xF8) != START_COND_TRANSMITTED )
{
terminate( e_i2c_err_start_condition );
return;
}

switch( cmd_sequence[ ++cmd_sequence_i ] )
{
case SLA_R: TWDR = i2c_addr_slave + (1 << 0); TWCR = COMMON; /* clear TWSTA */; break;
case SLA_W: TWDR = i2c_addr_slave; TWCR = COMMON; /* clear TWSTA */; break;
default: terminate( e_i2c_err_internal_soft ); return;
}
break;

///////////////////
case START_REP:
if( (TWSR & 0xF8) != REPEATED_START_COND_TRANSMITTED )
{
terminate( e_i2c_err_start_condition );
return;
}

if( cmd_sequence[ ++cmd_sequence_i ] == SLA_R )
{
TWDR = i2c_addr_slave + (1 << 0);
TWCR = COMMON; // clear TWSTA
}
else
{
terminate( e_i2c_err_internal_soft );
return;
}
break;

///////////////////
case SLA_R:
if( (TWSR & 0xF8) != SLA_R_TRANSMITTED_ACK_RECEIVED )
{
terminate( e_i2c_err_sla );
return;
}

if( cmd_sequence[ ++cmd_sequence_i ] != DATA_R )
{
terminate( e_i2c_err_internal_soft );
return;
}

data_transfer();
break;

///////////////////
case SLA_W:
if( (TWSR & 0xF8) != SLA_W_TRANSMITTED_ACK_RECEIVED )
{
terminate( e_i2c_err_sla );
return;
}

switch( cmd_sequence[ ++cmd_sequence_i ] )
{
case DATA_W: data_transfer(); break;
case ADDR: TWDR = DataAddr; TWCR = COMMON; break;
default: terminate( e_i2c_err_internal_soft ); return;
}
break;

///////////////////
case DATA_R:
if( DataLen )
{
if( (TWSR & 0xF8) != DATA_RECEIVED_ACK_RETURNED )
{
terminate( e_i2c_err_data );
return;
}
}
else
{
if( (TWSR & 0xF8) != DATA_RECEIVED_NACK_RETURNED )
{
terminate( e_i2c_err_data );
return;
}
}

data_transfer();
break;

///////////////////
case DATA_W:
if( (TWSR & 0xF8) != DATA_TRANSMITTED_ACK_RECEIVED )
{
terminate( e_i2c_err_data );
return;
}

data_transfer();
break;

///////////////////
case ADDR:
if( (TWSR & 0xF8) != DATA_TRANSMITTED_ACK_RECEIVED )
{
terminate( e_i2c_err_data );
return;
}


switch( cmd_sequence[ ++cmd_sequence_i ] )
{
case START_REP: TWCR = COMMON | (1 << TWSTA); break;
case DATA_W: data_transfer(); break;
default: terminate( e_i2c_err_internal_soft ); return;
}
break;
}
}

///////////////////////////////////////////////////////////////////////////////////////
i2c_errors i2c_get_last_err( void )
{
return status;
}

///////////////////////////////////////////////////////////////////////////////////////
void i2c_set_callback_func( i2c_callback_on_finish f_ptr_in )
{
f_ptr = f_ptr_in;
}

///////////////////////////////////////////////////////////////////////////////////////
#pragma inline
u8 test_is_stop( void )
{
if( eMode == e_busy_wait_stop )
{
if( !(TWCR & (1 << TWSTO) ) )
{ // если бит снялся, значит СТОП-условие на шине прошло успешно и шина свободна
eMode = e_idle;
return true;
}
else
return false;
}
return false;
}

///////////////////////////////////////////////////////////////////////////////////////
void i2c_reset( void )
{
TWCR = COMMON | (1 << TWSTO); //send stop condition
eMode = e_idle;
cmd_sequence[ 0 ] = NOTDEF;
cmd_sequence_i = 0;
while( TWCR & (1 << TWSTO) );
}

///////////////////////////////////////////////////////////////////////////////////////
u8 i2c_write( u8 *from, u8 len, u8 *bytes_transfer_cnt_in )
{
if( bytes_transfer_cnt_in )
{
*bytes_transfer_cnt_in = 0;
bytes_transfer_cnt = bytes_transfer_cnt_in;
}
else
bytes_transfer_cnt = &bytes_transfer_cnt_local;


if( eMode == e_error ) i2c_reset();
else
if( eMode == e_idle || test_is_stop() )
{
cmd_sequence[ 0 ] = START;
cmd_sequence[ 1 ] = SLA_W;
cmd_sequence[ 2 ] = DATA_W;
cmd_sequence[ 3 ] = STOP;
cmd_sequence_i = 0;

bytes_transfer_cnt = bytes_transfer_cnt_in;
pData = from;
DataLen = len;

send_start_condition();
return true;
}
return false;
}

///////////////////////////////////////////////////////////////////////////////////////
u8 i2c_write_to( u8 *from, u8 len, u8 addr, u8 *bytes_transfer_cnt_in )
{
if( bytes_transfer_cnt_in )
{
*bytes_transfer_cnt_in = 0;
bytes_transfer_cnt = bytes_transfer_cnt_in;
}
else
bytes_transfer_cnt = &bytes_transfer_cnt_local;

if( eMode == e_error ) i2c_reset();
else
if( eMode == e_idle || test_is_stop() )
{
cmd_sequence[ 0 ] = START;
cmd_sequence[ 1 ] = SLA_W;
cmd_sequence[ 2 ] = ADDR;
cmd_sequence[ 3 ] = DATA_W;
cmd_sequence[ 4 ] = STOP;
cmd_sequence_i = 0;

bytes_transfer_cnt = bytes_transfer_cnt_in;
pData = from;
DataLen = len;
DataAddr = addr;

send_start_condition();
return true;
}
return false;
}

///////////////////////////////////////////////////////////////////////////////////////
u8 i2c_read( u8 *dest, u8 len, u8 *bytes_transfer_cnt_in )
{
if( bytes_transfer_cnt_in )
{
*bytes_transfer_cnt_in = 0;
bytes_transfer_cnt = bytes_transfer_cnt_in;
}
else
bytes_transfer_cnt = &bytes_transfer_cnt_local;


if( eMode == e_error ) i2c_reset();
else
if( eMode == e_idle || test_is_stop() )
{
cmd_sequence[ 0 ] = START;
cmd_sequence[ 1 ] = SLA_R;
cmd_sequence[ 2 ] = DATA_R;
cmd_sequence[ 3 ] = STOP;
cmd_sequence_i = 0;

bytes_transfer_cnt = bytes_transfer_cnt_in;
pData = dest;
DataLen = len;
skip_1st_byte_on_read = true;

send_start_condition();
return true;
}
return false;
}

///////////////////////////////////////////////////////////////////////////////////////
u8 i2c_read_from( u8 *dest, u8 len, u8 addr, u8 *bytes_transfer_cnt_in )
{

if( bytes_transfer_cnt_in )
{
*bytes_transfer_cnt_in = 0;
bytes_transfer_cnt = bytes_transfer_cnt_in;
}
else
bytes_transfer_cnt = &bytes_transfer_cnt_local;

if( eMode == e_error ) i2c_reset();
else
if( eMode == e_idle || test_is_stop() )
{
cmd_sequence[ 0 ] = START;
cmd_sequence[ 1 ] = SLA_W;
cmd_sequence[ 2 ] = ADDR;
cmd_sequence[ 3 ] = START_REP;
cmd_sequence[ 4 ] = SLA_R;
cmd_sequence[ 5 ] = DATA_R;
cmd_sequence[ 6 ] = STOP;
cmd_sequence_i = 0;


pData = dest;
DataLen = len;
DataAddr = addr;
skip_1st_byte_on_read = true;

send_start_condition();
return true;
}
return false;
}


///////////////////////////////////////////////////////////////////////////////////////
u8 i2c_is_busy( void )
{
if( eMode == e_busy ) return true;
else
return false;
}




Составить ответ | Вернуться на конференцию.

Ответы


Отправка ответа
Имя*: 
Пароль: 
E-mail: 
Тема*:

Сообщение:

Ссылка на URL: 
URL изображения: 

если вы незарегистрированный на форуме пользователь, то
для успешного добавления сообщения заполните поле, как указано ниже:
введите число 69:

Перейти к списку ответов | Конференция | Раздел "Электроника" | Главная страница | Карта сайта

Rambler's Top100 Рейтинг@Mail.ru
 
Web telesys.ru