Примерно так: <c>
#include <stdint.h>
#include "Hardware.h"
#include <FreeRTOS.h>
#include <semphr.h>
#include <task.h>
#include "I2C.h"
#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;
I2C.DeviceID = 0xA;
I2C.SlaveAddr = EE_Addr >> 8;
I2C.Read = 0;
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;
}
__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++;
} 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
}
</c>
-
- Разобрался. Большое спасибо - kgv63(09.07.2007 18:24, )