ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Среда
3 июля
93729 Топик полностью
Сергей Борщ (07.07.2007 02:17, просмотров: 1) ответил kgv63 на I2C для LPC2148
Примерно так: <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>