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

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

У меня кажется проще получилось (2119), но в документации голову тоже ломал.

Отправлено Сергей Борщ 20 февраля 2007 г. 16:37
В ответ на: Если что -> отправлено scorpion 20 февраля 2007 г. 13:23


#define I2C_TIMEOUT (50 RTOS_MS)
#define EEPROM_PAGE_SIZE 16
#include
#include
#include

#define I2C_EN (1<<6)
#define I2C_START (1<<5)
#define I2C_STOP (1<<4)
#define I2C_INT (1<<3)
#define I2C_ACK (1<<2)

enum {IDLE, SEND_START, SEND_DEV_ADDR, SEND_ADDR, EXCHG_DATA, SEND_STOP};

struct {
union {
struct {
uint8_t Read:1;
uint8_t SlaveAddr:3;
uint8_t DeviceID:4;
};
uint8_t DevAddr;
};
uint8_t Addr;
uint16_t Counter;
uint8_t *pData;
xSemaphoreHandle Busy;
portTickType Time;
volatile uint8_t flag;
} I2C;

static uint_fast8_t I2C_Lock (void) {
if(I2C.Busy == NULL) {
vSemaphoreCreateBinary(I2C.Busy);
if( I2C.Busy == NULL ) return 0; // unable to create semaphore
}
if( xSemaphoreTake(I2C.Busy, I2C_TIMEOUT * 2) == pdFALSE )
return 0; // timeout expired
I2C.flag = 1;
return 1;
}

static void I2C_UnLock(void) {
vTaskDelay( I2C_TIMEOUT );
if(I2C.flag) { // Error
VICIntEnClear = (1UL << VIC_I2C);
I2CONCLR = ( I2C_ACK | I2C_START | I2C_STOP | I2C_INT );
I2CONSET = ( I2C_EN );
}
xSemaphoreGive(I2C.Busy); // release semaphore
}

uint_fast8_t I2C_EEPROM_Read (uint_fast16_t EE_Addr, uint8_t *pDest, uint_fast16_t bytes) {
if(!I2C_Lock()) return 0; // unable to get access to bus;

I2C.DeviceID = 0xA;
I2C.SlaveAddr = EE_Addr >> 8;
I2C.Read = 1;
I2C.Addr = EE_Addr;
I2C.pData = pDest;
I2C.Counter = bytes;
I2CONCLR = ( I2C_ACK | I2C_START | I2C_STOP | I2C_INT );

VICIntEnable = (1UL << VIC_I2C);
I2CONSET = ( I2C_EN | I2C_START );

I2C_UnLock();
return I2C.Counter == 0;
}
uint_fast8_t I2C_EEPROM_Write (uint_fast16_t EE_Addr, uint8_t *pDest, uint_fast16_t bytes) {
if(!I2C_Lock()) return 0; // unable to get access to bus;

uint_fast16_t BytesToWrite;
{
uint_fast16_t AddrOffset = EE_Addr & (EEPROM_PAGE_SIZE - 1); // offset in page;

if( AddrOffset + bytes > EEPROM_PAGE_SIZE ) // page boundary
BytesToWrite = EEPROM_PAGE_SIZE - AddrOffset;
}

do {
if(BytesToWrite > bytes)
BytesToWrite = bytes;

I2C.DeviceID = 0xA;
I2C.SlaveAddr = EE_Addr >> 8;
I2C.Read = 0;
I2C.Addr = EE_Addr;
I2C.pData = pDest;
I2C.Counter = BytesToWrite;
I2CONCLR = ( I2C_ACK | I2C_START | I2C_STOP | I2C_INT );

VICIntEnable = (1UL << VIC_I2C);
I2CONSET = ( I2C_EN | I2C_START );

I2C_UnLock();
if(I2C.Counter) return 0; // error
bytes -= BytesToWrite;
EE_Addr += BytesToWrite;
pDest += BytesToWrite;
BytesToWrite = EEPROM_PAGE_SIZE;
} while(bytes);
return 1;
}

__arm __irq void I2C_handler(void) {
switch(I2STAT) {
case 0x08: // Start done
I2DAT = I2C.DevAddr & ~(1<<0); // SEND SLA+W
I2CONCLR = (I2C_INT | I2C_START);
break;
case 0x20: // Slave addr NACK
I2CONSET = I2C_STOP | I2C_START; // generate stop
I2CONCLR = I2C_INT;
break;
case 0x18: // Slave addr ACK
I2DAT = I2C.Addr;
I2CONCLR = I2C_INT;
break;
case 0x28: // Byte transfer ACK
if(I2C.Read) {
I2CONSET = I2C_START; // generate repeated start
I2CONCLR = I2C_INT;
} else { // Write
if(I2C.Counter) {
I2DAT = *I2C.pData++;
I2C.Counter--;
} else {
I2CONSET = I2C_STOP;
I2C.flag = 0;
}
I2CONCLR = I2C_INT;
}
break;
case 0x10: // Repeated start done
I2DAT = I2C.DevAddr; // SEND SLA+R
I2CONCLR = (I2C_INT | I2C_START);
break;
case 0x40: // Slave ACKed SLA+R
if(I2C.Counter != 1) //
I2CONSET = I2C_ACK; // send ACK if not last byte
I2CONCLR = I2C_INT;
break;
case 0x50: // Byte received with ACK
*I2C.pData++ = I2DAT;
I2C.Counter--;
if(I2C.Counter == 1)
I2CONCLR = I2C_ACK; // send NACK after last byte
I2CONCLR = I2C_INT;
break;
case 0x58: // Last byte received
*I2C.pData++ = I2DAT;
I2C.Counter--;
I2CONSET = I2C_STOP;
I2C.flag = 0;
I2CONCLR = I2C_INT;
break;

default: // unexpected status
I2CONCLR = I2C_EN | I2C_INT;
I2C.flag = 0;
I2CONSET = I2C_EN;
__no_operation();
}
VICVectAddr = 0; // Reset VIC logic
}




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

Ответы


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

Сообщение:

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

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

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

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