TWI (I2C)
Добавлено: Пн мар 13, 2017 10:40:38
Здравствуйте. Посоветуйте хорошую библиотечку для организации I2C мастера. Спасибо.
Спасибо. Скачал, посмотрел. Пока что гитхабовская в проект подключена - если скомпрометирует себя, то возьмусь за Вашу.ARV писал(а):Рекомендую библиотечку Peter Fleury
Неоднократно пользовался, доволен полностью.
ARV, а как вы производите обработку ошибок ? или перезагрузку модуля ? Если произошло замыкание на линии то встала вся программа ?Неоднократно пользовался, доволен полностью.
а если случится ядерная война - устройство должно продолжать работать?pokk писал(а):а как вы производите обработку ошибок ? или перезагрузку модуля ? Если произошло замыкание на линии то встала вся программа ?
В данном случае, эти проблемы должен решать софт, который использует драйвер. Я пишу функции которые возвращают код ошибки в зависимости от того, какая функция драйвера возвратила ошибку. Допустим функция должна передать последовательность байт. Она сперва делает старт с посылкой адреса и режима. Вернула 1? Тогда делаем ретурн из нашей функции и возвращаем ошибку i2c_NO_RESPONSE, например. И так далее. Дело Вашей фантазии сколько ошибок наопределять и какие ветвления по-настраивать. Но это софтверные решения - код ждет пока байт отправится, придет аск/нот-аск. Как я уже писал выше, есть достаточно изначально запутанный драйвер на прерываниях и тот подход будет по-профессиональней. Но у меня задача попроще.pokk писал(а):а как вы производите обработку ошибок ? или перезагрузку модуля ? Если произошло замыкание на линии то встала вся программа ?
Код: Выделить всё
/*
* GccApplication1.c
*
* Created: 15.03.2017 19:38:13
* Author: user
*/
#define Giro 0b01101011
#define Accel 0b00011101
#define F_CPU 8000000
#define SCL_F 100000
#define BAUD 9600UL // Скорость обмена данными
#define UBRR ((F_CPU/(BAUD*16))-1)
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t buffer[];
volatile uint8_t size_buf;
volatile uint8_t pointer;
volatile uint8_t pointerforREAD;
volatile char buffer_read[];
volatile uint8_t writeread;
volatile uint8_t ar[];
void initUART() //задаем скорость обмена по uart
{
UBRRL = UBRR; //Младшие 8 бит UBRR
UBRRH = UBRR>>8; //Старшие 8 бит UBRR
//RXCIE - разрешаем прерывание по завершению приема данных
//TXCIE - разрешаем прерыванеи по завершению передачи
//UDRIE - разрешаем прерывание по освобождению регистра данных
//RXEN - разрешаем работу приемника
//TXEN - разрешаем работу передатчика
//UCSZ2 - указываем размер данных
UCSRB = (0<<RXCIE)|(0<<TXCIE)|(0<<UDRIE)|(1<<RXEN)|(1<<TXEN)|(0<<UCSZ2);
//URSEL - записываем UCSRC
//UMSEL - асинхронный режим передачи
//UPM1,0 -запрет париета
//USBS - 1 стоповый бит
//UCSZ1,2,3- задаем размер посылки
UCSRC = (1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(1<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
}
void send_UartChar(char strng[])// Отправка байта
{
for (int i=0; strng[i] !='\0'; i++)
{
UDR = strng[i];
while(!(UCSRA&(1<<UDRE))); // Устанавливается, когда регистр свободен
}
}
void send_UartInt(uint8_t strng[],uint8_t Tsize)// Отправка байта
{
for (int i=0; i <=Tsize; i++)
{
UDR = strng[i];
while(!(UCSRA&(1<<UDRE))); // Устанавливается, когда регистр свободен
}
}
void twi_Init(void)
{
TWBR = ( ( (F_CPU)/(SCL_F)-16 ) /2 ) ;
TWSR = 0; //Очищаются биты TWPS0 и TWPS1
}
void start()
{
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
}
void stop()
{
//формируем состояние СТОП, сбрасываем флаг, запрещаем прерывания
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO)|(0<<TWIE);
}
void not_interrupt()
{
TWCR = (1<<TWEN)|(0<<TWIE)|(0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC); //запретить прерывание
}
/*данная функция производит подготовку буффера для интерфейса TWI , после чего запускает Start
массив заполняется в соответсвии с битом записи чтения
если поступил бит чтеня , то записывается только первый байт данных
иначе записываетя весь массив до size*/
void set_array_TWI(uint8_t array_a[],uint8_t size,uint8_t wr)//в size указываем размер массива без SLA , тоесть количесво байт для приема или же передачи
{
uint8_t i;
while(TWCR & (1<<TWIE)); // ;ждем освобождения модуля TWI
//методом проверки флага разрешения прерывания , который
//сбрасывается после СТОП
writeread=wr;
buffer[0]=array_a[0] ;
size_buf=size;
if ((array_a[0]==(Accel<<1)) || (array_a[0]==(Giro<<1)))
{ //если задано ЗАПИСЬ , то сохраняем весь массив
for (i=1; i<=size;i++)
{
buffer[i]=array_a[i] ;
}
} start();}
ISR(TWI_vect)
{
switch (TWSR & 0xf8)
{
case 0x08://сигнал START передан
send_UartChar("Start ");
TWDR=buffer[0]; //передаем SLA+W or SLA+R
pointerforREAD=0;
pointer=1;
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT
break;
case 0x10://сигнал REPEATED START передан
send_UartChar("RepeatedStart ");
pointerforREAD=0;
pointer=1;//сбросили указатель массива (буффера)
TWDR=buffer[0]; //послали SLA+RW
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT
break;
case 0x30: //— Байт отправлен, ACK не получен
send_UartChar("ByteSendNACK ");
TWDR=buffer[pointer]; //повторно отпраляем бай данных
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT
break;
case 0x18://Адрес для записи передан, ответ (ACK) получен
send_UartChar("SLA+W,ACK ");
if (pointer<=size_buf)
{
TWDR=buffer[pointer];
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT
pointer++;
}
break;
case 0x28:// Байт отправлен, ACK получен
send_UartChar("ByteSend,ACK ");
if (pointer<=size_buf)
{
TWDR=buffer[pointer];
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT
pointer++;
}
else
{
switch(writeread)
{
case 1:
stop();
default:
not_interrupt();
}
}
break;
case 0x40://Адрес для чтения передан, ответ (ACK) получен
if (pointer<size_buf)
{
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);//если это не предпоследний принятый байт, формируем подтверждение
}
else {
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //если приняли предпоследний байт, подтверждение не формируем
}
send_UartChar("SendSLA+R,ACK");
break;
case 0x50: // — Данные получены, ACK передан
buffer_read[pointerforREAD]=TWDR;
pointerforREAD++;
send_UartChar("GetByteACK:");
if (pointerforREAD<size_buf-1)
{
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);//если это не предпоследний принятый байт, формируем подтверждение
}
else {
TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //если приняли предпоследний байт, подтверждение не формируем
}
break;
case 0x58:// — Данные получены, ACK не передан<
buffer_read[pointerforREAD]= TWDR;
send_UartChar("GetByteNACK:");
send_UartInt(buffer_read,pointerforREAD);
stop();
break;
case 0x48:// — Адрес для чтения передан, устройство не откликнулось
case 0x20:// — Адрес для записи передан, устройство не откликнулось
case 0x38:// — Контроллер потерял шину (вылез еще один контроллер)
default:
send_UartChar("error");
not_interrupt();
break;
}
}
int main(void)
{ twi_Init();
initUART();
sei();
ar[0]=Accel<<1;
ar[1]=0b00100100; //00011000
set_array_TWI(ar,1,0);
ar[0]=(Accel<<1)+1;
ar[1]=0x0F;
set_array_TWI(ar,2,1);
while(1)
{
//TODO:: Please write your application code
}
}