Цитата(jcxz @ Sep 5 2017, 13:58)

При отсутствии помех?
У меня устройство на STM32F429. Работает интенсивно по I2C (FRAM + RTC + др.). При отсутствии помех работает отлично: запускал тесты с непрерывным интенсивным обменом с FRAM-памятью длительностью до 12часов непрерывно - ни одного сбоя. Работа по прерываниям + DMA.
Но при включении мощной радиочастотной нагрузки на плате, начинаются периодические сбои по I2C (в основном - с одним из I2C-слэйвов). Некоторыми мерами удалось значительно снизить их частоту.
Так что у Вас одно из двух: или помехи по шине (проблемы в схемотехнике), или баги в ПО. А модуль I2C тут скорее всего не при чём.
Ссылка на топик, где я описывал свою проблему и процесс борьбы с ней:
https://electronix.ru/forum/index.php?showt...141285&st=0PS: Да - и если дело в помехах, то какой смысл в сбросе I2C-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.
Понимаю что это оффтоп, но раз уж заговорили, прикладываю свою библиотеку I2C. Не претендую на идеальность, но она работает на F1 и F4. И да, есть сброс. Помехи исключены, смотрели осциллом. Проблема всегда появляется именно после первой транзакции на чтение/запись. Не всегда на второй транзакции, но всегда после первой. Регистры I2C при зависоне соответствуют регистрам при нормальной работе, Первая транзакция всегда проходит идеально, ошибок нет, были бы помехи,они бы и первую портили. При зависоне, I2C не генерит никакой ошибки, просто виснет после старт-бита, притягивая линию к 0. И это проблема не слейва, т.к. проблема проявляется и при отсутствующем слейве. Резисторы по 3К, длина линии на плате не более 50-100 мм, рядом силовухи нет.
CODE
#include "globals.h"
#include "I2C3Routines.h"
volatile uint8_t AddrSlave; //адрес слейва
volatile uint32_t AddrReg; //адрес регистра слейва, с которым хотим что-либо сделать
volatile uint8_t ByteCount; //кол-во байт на чтение-запись
volatile uint8_t AddrByteCnt; //кол-во байт адреса
volatile uint8_t RxBTF; //флажок
volatile uint8_t* I2CBuffer; //указатель на буфер чтения/записи
volatile uint8_t I2CRestart; //флаг повторного старта
volatile List_I2C_Modes I2C_Mode; //режим работы I2C
volatile List_I2C_Result I2C_Res; //Результат операции I2C
xSemaphoreHandle I2C_Complete = NULL; //данные записаны/прочитаны
xSemaphoreHandle I2C3Mutex = NULL; //Мьютекс
List_I2C_Result I2C3Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef GPIO_CM3
//Тактирование
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,ENABLE );
RCC_APB2PeriphClockCmd(I2C_NUMB_GPIO_RCC ,ENABLE );
//Настройка пинов
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL | I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);
#elif defined GPIO_CM4
// Тактирование
if (I2C3Mutex != NULL) // При повторной инициализации
{
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), DISABLE);
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC, DISABLE );
//настройка прерываний
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_EV;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_ER;
NVIC_Init(&NVIC_InitStructure);
// Сбросим пины в дефолт
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
}
else // При первой
{
I2C3Mutex = xSemaphoreCreateMutex();
vSemaphoreCreateBinary(I2C_Complete);
xSemaphoreTake(I2C_Complete, 0);
RCC_AHB1PeriphClockCmd(I2C_NUMB_GPIO_SCL_RCC ,ENABLE );
RCC_AHB1PeriphClockCmd(I2C_NUMB_GPIO_SDA_RCC ,ENABLE );
}
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,ENABLE );
// Настройка пинов
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
GPIO_PinAFConfig(I2C_NUMB_GPIO_SCL, GPIO_PinSource8, GPIO_AF_I2C3); //SCL
GPIO_PinAFConfig(I2C_NUMB_GPIO_SDA, GPIO_PinSource9, GPIO_AF_I2C3); //SDA
#endif
//Настройка I2C
I2C_DeInit(I2C_NUMB);
I2C_SoftwareResetCmd(I2C_NUMB, ENABLE);
I2C_SoftwareResetCmd(I2C_NUMB, DISABLE);
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C_MY_ADDRESS;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C_NUMB, &I2C_InitStructure);
I2C_Cmd(I2C_NUMB, ENABLE);
//Проверим, что шина не зависла
if(I2C_GetFlagStatus(I2C_NUMB, I2C_FLAG_BUSY)) //шина зависла, надо подергать SCL
{
uint8_t countClk = 0;
I2C_Cmd(I2C_NUMB, DISABLE); //отключим I2C
//перенастраиваем пины
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
SCL_HI;
while(!CHECK_SDA) //дергаем SCL, пока SDA не поднимется
{
vTaskDelay(1);
SCL_LO;
vTaskDelay(1);
SCL_HI;
if (countClk++ == 100) //ничего не вышло, отключим всё, вернём ошибку
{
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA | I2C_NUMB_SCL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(I2C_NUMB_GPIO ,&GPIO_InitStructure );
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
I2C_DeInit(I2C_NUMB);
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,DISABLE );
return I2C_ERR_BUS;
}
}
//вернем настройки обратно
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL | I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_NUMB_GPIO ,&GPIO_InitStructure );
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
I2C_Cmd(I2C_NUMB, ENABLE);
}
//настройка прерываний
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_EV;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2C_NUMB_EV_IRQ_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_ER;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2C_NUMB_ER_IRQ_PRIORITY;
NVIC_Init(&NVIC_InitStructure);
vTaskDelay(3);
return I2C_CMD_OK;
}
List_I2C_Result I2C_Master_BufferRead(uint8_t SlaveAddress ,uint8_t* pBuffer ,uint8_t NumByteToRead )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_READ;
AddrSlave = (SlaveAddress << 1);
I2CBuffer = pBuffer;
ByteCount = NumByteToRead;
if (NumByteToRead == 2) I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Next);
else I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Current);
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали
if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}
List_I2C_Result I2C_Master_BufferWrite(uint8_t SlaveAddress ,uint8_t RegAddress , uint8_t* pBuffer ,uint8_t NumByteToWrite )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_WRITE;
AddrSlave = (SlaveAddress << 1);
AddrReg = RegAddress;
I2CBuffer = pBuffer;
ByteCount = NumByteToWrite;
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали
if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}
List_I2C_Result I2C_Master_BufferWriteRead(uint8_t SlaveAddress ,uint32_t RegAddress , uint8_t* pBuffer ,uint8_t NumByteToRead )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_WRITEREAD;
AddrSlave = (SlaveAddress << 1);
AddrReg = RegAddress & 0x7FFFFFFF;
AddrByteCnt = (RegAddress >> 24) & 0x03;
I2CBuffer = pBuffer;
ByteCount = NumByteToRead;
if (NumByteToRead == 2) I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Next);
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали
if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}
//IRQ Event - Method 2 (DS - Master Receive)
void I2C3_EV_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
switch (I2C_GetLastEvent(I2C_NUMB))
{
case I2C_EVENT_MASTER_MODE_SELECT: //EV5 Послали старт, теперь надо послать адрес слейва
{
if(I2CRestart || (I2C_Mode == I2C_MODE_READ))
{
I2C_NUMB->DR = AddrSlave | 0x01;
}
else
{
I2C_NUMB->DR = AddrSlave;
}
break;
}
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: //EV6 Послали SlaveAddr7bit + R
{
if (ByteCount == 1)
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
I2C_NUMB->CR1 |= I2C_CR1_STOP;
}
else if (ByteCount == 2)
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
}
RxBTF = 1;
I2C_NUMB->CR2 |= I2C_CR2_ITBUFEN; //включим RxNE/TxE для передачи байт
break;
}
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: //EV6 Послали SlaveAddr7bit + W
{
if (I2C_Mode == I2C_MODE_WRITEREAD) //если попали сюда в режиме чтения, значит делаем повторный старт
{
if(!(--AddrByteCnt)) //Адрес из одного байта, шлем повторный старт
{
I2CRestart = 1;
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи адреса (чтобы не попадать в EV8)
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
I2C_NUMB->CR1 |= I2C_CR1_START; //отправится после завершения отправки адреса
}
else //надо отправить еще байты адреса
{
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем первый байт адреса
AddrReg>>=8;
}
break;
}
if (I2C_Mode == I2C_MODE_WRITE) //если режим записи
{
if(!ByteCount) //Нет байт на отправку
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи последнего байта (чтобы не попадать в EV8)
}
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
}
break;
}
case I2C_EVENT_MASTER_MODE_ADDRESS10: //EV9 Послали SlaveAddr3bit (заголовок 10-ти битного адреса)
{
asm("nop");
break;
}
case I2C_EVENT_MASTER_BYTE_RECEIVED: //EV7 Получили байт, надо прочитать
{
if (ByteCount-- == 2) // пред-последний байт
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; // отключаем ACK после чтения
I2C_NUMB->CR1 |= I2C_CR1_STOP; // говорим Стоп
}
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
break;
}
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: //EV8 Пустой буфер на передачу (байт передается), можно кинуть еще байт в буфер
{
if(!I2CRestart) //Отправляем байты адреса только до рестарта
{
if(!(--AddrByteCnt)) // Отправляем последний байт адреса, шлем повторный старт
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи адреса (чтобы не попадать в EV8)
}
else //надо отправить еще байты адреса
{
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем следующий байт адреса
AddrReg>>=8;
}
}
if(I2C_Mode == I2C_MODE_WRITE) //байт данных ушел, шлем следующий
{
if(!(--ByteCount)) //последний байт
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи последнего байта (чтобы не попадать в EV8)
}
I2C_NUMB->DR = *I2CBuffer++;
}
break;
}
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: //EV8_2 (DR и shift регистры) FIFO пустой (при передаче) FIFO полный (при приеме)
{
if(I2C_Mode == I2C_MODE_WRITEREAD && !I2CRestart)
{
I2CRestart = 1;
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
I2C_NUMB->CR1 |= I2C_CR1_START; //отправится после завершения отправки адреса
break;
}
if(I2C_Mode == I2C_MODE_WRITE) //байт данных ушел, шлем следующий
{
if(!ByteCount) //всё отправили
{
I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
I2C_Res = I2C_CMD_OK;
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
break;
}
}
if(((I2C_Mode == I2C_MODE_WRITEREAD) || (I2C_Mode == I2C_MODE_READ)) && RxBTF) //входной буфер забит, надо читать - !!НЕ ПРОВЕРЯЛОСЬ(написано согласно ДШ)!!
{
if (ByteCount == 3) // осталось прочитать 3 байта
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
ByteCount-= 2;
}
if (ByteCount == 2) // осталось прочитать 2 байта
{
I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
ByteCount-= 2;
}
}
break;
}
default: break;
}
if (!ByteCount && ((I2C_Mode == I2C_MODE_WRITEREAD) || (I2C_Mode == I2C_MODE_READ))) //всё прочитали
{
I2C_Res = I2C_CMD_OK;
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
}
}
//IRQ Error
void I2C3_ER_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
if(I2C_GetITStatus(I2C_NUMB, I2C_FLAG_SMBALERT)) //SMBus Alert
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_FLAG_SMBALERT);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: SMB Alert\r\n");
#endif
I2C_Res = I2C_ERR_SMBALERT;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_TIMEOUT)) //Timeout/Tlow error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_TIMEOUT);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Timeout\r\n");
#endif
I2C_Res = I2C_ERR_TIMEOUT;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_PECERR)) //PEC Error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_PECERR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: PEC Error\r\n");
#endif
I2C_Res = I2C_ERR_PEC;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_OVR)) //Overrun/Underrun
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_OVR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Overrun/Underrun\r\n");
#endif
I2C_Res = I2C_ERR_OVR;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_AF)) //Acknowledge failure
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_AF);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Acknowledge failure\r\n");
#endif
I2C_Res = I2C_ERR_NAK;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_ARLO)) //Arbitration loss
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_ARLO);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Arbitration loss\r\n");
#endif
I2C_Res = I2C_ERR_ARLO;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_BERR)) //Bus error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_BERR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Bus error\r\n");
#endif
I2C_Res = I2C_ERR_BUS;
}
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken ); // отдадим
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
}
CODE
#ifndef I2C_ROUTINES_H
#define I2C_ROUTINES_H
//#define GPIO_CM3
#define GPIO_CM4
#define I2C_DEBUG_INFO // Выводить отладку в UART
#define I2C_NUMB I2C3
#define I2C_NUMB_RCC RCC_APB1Periph_I2C3
#define I2C_NUMB_IRQ_EV I2C3_EV_IRQn
#define I2C_NUMB_IRQ_ER I2C3_ER_IRQn
#define I2C_NUMB_GPIO_SCL GPIOA
#define I2C_NUMB_GPIO_SCL_RCC RCC_AHB1Periph_GPIOA
#define I2C_NUMB_SCL GPIO_Pin_8
#define I2C_NUMB_GPIO_SDA GPIOC
#define I2C_NUMB_GPIO_SDA_RCC RCC_AHB1Periph_GPIOC
#define I2C_NUMB_SDA GPIO_Pin_9
// не ставь выше ядра FreeRTOS!
#define I2C_NUMB_EV_IRQ_PRIORITY 6 //приоритет прерываний Events
#define I2C_NUMB_ER_IRQ_PRIORITY 7 //приоритет прерываний Error
#define I2C_SPEED 400000
#define I2C_MY_ADDRESS 0x7F //не используем
#define I2C_TIMEOUT 500 //Таймаут на ошибку
#define SCL_LO do \
{ \
GPIO_ResetBits(I2C_NUMB_GPIO_SCL, I2C_NUMB_SCL); \
}while(0)
#define SCL_HI do \
{ \
GPIO_SetBits(I2C_NUMB_GPIO_SCL, I2C_NUMB_SCL); \
}while(0)
#define CHECK_SDA (GPIO_ReadInputDataBit(I2C_NUMB_GPIO_SDA,I2C_NUMB_SDA))
// Режим i2c
typedef enum
{
I2C_MODE_READ=1, //чтение
I2C_MODE_WRITE, //запись
I2C_MODE_WRITEREAD, //Чтение с заносом адреса
}List_I2C_Modes;
typedef enum
{
I2C_CMD_OK = 1,
I2C_ERR_SMBALERT,
I2C_ERR_TIMEOUT,
I2C_ERR_PEC,
I2C_ERR_OVR,
I2C_ERR_NAK,
I2C_ERR_ARLO,
I2C_ERR_BUS,
I2C_ERR_UNKNOWN, //Неизвестная ошибка, возможно баг библиотеки. Семафор не отдался в течении I2C_TIMEOUT, I2Cx_ER_IRQ не вызвалось.
}List_I2C_Result;
extern List_I2C_Result I2C3Init(void);
extern List_I2C_Result I2C_Master_BufferRead(uint8_t SlaveAddress ,uint8_t* pBuffer ,uint8_t NumByteToRead );
extern List_I2C_Result I2C_Master_BufferWrite(uint8_t SlaveAddress ,uint8_t RegAddress ,uint8_t* pBuffer, uint8_t NumByteToWrite );
extern List_I2C_Result I2C_Master_BufferWriteRead(uint8_t SlaveAddress ,uint32_t RegAddress ,uint8_t* pBuffer, uint8_t NumByteToRead );
extern xSemaphoreHandle I2C3Mutex; //Мьютекс
// Для режима I2C_MODE_WRITEREAD, указываем сколько байт в адресе (байт на запись)
#define WR_1BYTE_ADDR(first_byte) (0x01000000 | (first_byte))
#define WR_2BYTE_ADDR(first_byte, second_byte) (0x02000000 | (((uint32_t)(second_byte) << 8) | (first_byte)))
#define WR_3BYTE_ADDR(first_byte, second_byte,third_byte) (0x03000000 | (((uint32_t)(third_byte) << 16) | ((uint32_t)(second_byte) << 8) | (first_byte)))
#endif
Ну и например чтение с часов DS3231:
Код
I2C_Master_BufferWriteRead(DS3231_ADDRESS ,WR_1BYTE_ADDR(SEC_ADDR) ,I2CReadBuffer , 19);