Добрый день.
Появился второй вопрос (по сравнению с первым, как мне кажется более существенный).
Перешел на изучение I2C.
Конкретно работу в режиме передающий мастер.
Настроил I2C, включил в CMU синхросигнал, реализовал обработчик прерывания I2C, настроил NVIC. Передаю данные.
Вопрос по значениям состояний I2C регистра STATE.
Хочу прочитать значение данных по некому адресу из EEPROM.
После успешного выставления состояния START на шину в регистре должно (по документации) появиться значение 0x57. Но появляется 0x53 (2 бит TRANSMITTER) не возводится. В обработчике прерывания я ожидал 0x57 для продолжения работы, добавил 0x53. Дальше все согласно даташиту отрабатывает и приходит обратно в состояние. Т.е. я передаю 7 битный адрес с признаком записи и он подтверждается EEPROM (приходит ACK) состояние 0x97. Затем я передаю два байта адреса EEPROM (тут они уже идут как данные I2C) и получаю на каждый STATE= 0xD7. После этого посылаю Repeat START и в ответ опять получаю 0x53 (а не 0x57), после этого передаю адрес с признаком чтения данных и после этого вижу на шине осциллографом, что CLK отработало видимо не только передачу адреса, но еще что-то (количество клоков 17 штук). В регистре STATE лежит при этом 0xB3 и есть данные в регистре RXDATA. Видимо сразу за адресом прошел запрос и данных, но я не включал авто подтверждений и по идее должно было прийти сначала состояние 0x93, а уже затем я бы перешел в состояние принять байт. Ну даже если и принял байт, то почему на шине количество клоков не кратно 9 (17 вместо необходимых 18)? И в регистре RXDATA лежит 0xEE (EEPROM пустая и я еще туда ничего не записывал) ожидалось 0xFF.
0. Как правильно сбросить прерывание I2C шины?
1. Почему при выставлении START на шину (посыл команды в регистр CMD I2C_CMD_START) в регистре STATE 0x53, вместо 0x57?
2. Почему не выставляется бит TRANSMITTER? Как гарантированно перевести I2C в режим Master Transmitter?
3. Почему после отправки адреса микросхемы с признаком чтение (после RSTART) происходит передача адреса на шину и прием чего, то (клоков на шине 17)? Возвращается STATE не 0x97, а сразу 0xB3, Почему так?
Инициализация I2C шины.
Код
/* Настройка I2C */
// Настройка GPIO I2C
/* Pin PD14 is configured to Open-drain with pull-up and filter */
GPIO->P[3].MODEH = (GPIO->P[3].MODEH & ~_GPIO_P_MODEH_MODE14_MASK) | GPIO_P_MODEH_MODE14_WIREDANDPULLUPFILTER;
/* Pin PD15 is configured to Open-drain with pull-up and filter */
GPIO->P[3].MODEH = (GPIO->P[3].MODEH & ~_GPIO_P_MODEH_MODE15_MASK) | GPIO_P_MODEH_MODE15_WIREDANDPULLUPFILTER;
// Включаем 3 альтернативное рассположение (там в ките висит EEPROM)
I2C0->ROUTE = (I2C0->ROUTE & ~_I2C_ROUTE_LOCATION_MASK) | I2C_ROUTE_LOCATION_LOC3;
// Разрешение шины на GPIO
I2C0->ROUTE |= I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN;
// Настраиваем частоту рабоыт I2C 100кГц
// div = ((14000000 - (4 * freq)) / (n * freq)) - 1;
// freq= 100000 частота I2C
I2C0->CLKDIV;
// Настраиваем режим работы I2C
I2C0->CTRL=(I2C_CTRL_CLHR_STANDARD | I2C_CTRL_EN ) & ~I2C_CTRL_SLAVE;// | I2C_CTRL_AUTOSN;// | I2C_CTRL_AUTOACK;
// Определяем прерывания I2C
I2C0->IFC = _I2C_IFC_MASK;
I2C0->IEN = I2C_IEN_MSTOP|I2C_IEN_NACK|I2C_IEN_ACK|I2C_IEN_RSTART|I2C_IEN_BUSHOLD|I2C_IEN_ST
ART;
Инициация передачи данных
Код
if (I2C0->STATE & I2C_STATE_BUSY)
{
I2C0->CMD=I2C_CMD_ABORT;
}
I2C0->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
if (I2C0->IF & I2C_IF_RXDATAV)
{
I2C0->RXDATA;
}
I2C0->IFC = _I2C_IFC_MASK;
I2C0->CMD=I2C_CMD_START;
Обработчик прерывания
Код
// обработчик IIC прерывания
void I2C0_IRQHandler(void)
{
dword SMB0STA;
SMB0STA=I2C0->IF;
I2C0->IFC=SMB0STA;
SMB0STA=I2C0->STATUS;
SMB0STA=I2C0->STATE;
if (!iic.cycle)
{// выход на шину
if ((SMB0STA==MTM_START) || (SMB0STA==MTM_RSTART))
{
I2C0->TXDATA=*(byte *)(&iic);
//SMB0DAT=*(byte *)(&iic); // передаем адрес с признаком
//IIC_CLR_START
iic.cycle++;
iic.ptr=0;
}
else
IIC_GET_ERR_
}
else
{
if (iic.work==_WRITE)
{// цикл записи
switch (iic.cycle)
{
case 1 :
if (SMB0STA==MTM_SLAW_ACK)
{
if (iic.len--)
{
I2C0->TXDATA=iic.dat[iic.ptr++];
iic.cycle++;
}
else
IIC_STOP_
}
else
IIC_GET_ERR_
break;
case 2 :
if (SMB0STA==MTM_DATA_ACK)
{
if (iic.len--)
I2C0->TXDATA=iic.dat[iic.ptr++];
else
{
if (!iic.len_rd)
IIC_STOP_
else
{
iic.work=_READ;
iic.len=iic.len_rd;
iic.ptr=0;
iic.cycle=0;
IIC_START
}
}
}
else
IIC_GET_ERR_
break;
default :
break;
}
}
else
{// цикл чтения
switch (iic.cycle)
{
case 1 :
if (SMB0STA==MRM_SLAR_ACK)
{
if (iic.len)
{
iic.cycle++;
if (--iic.len) IIC_SEND_ACK
else IIC_SEND_NACK
}
else
IIC_STOP_
}
else
IIC_GET_ERR_
break;
case 2 :
if (SMB0STA==MRM_DATA_ACK)
{
iic.dat[iic.ptr++]=(byte)(I2C0->TXDATA);
if (--iic.len)
IIC_SEND_ACK
else
IIC_SEND_NACK
}
else
{
if (SMB0STA==MRM_DATA_NACK)
{
iic.dat[iic.ptr++]=(byte)(I2C0->TXDATA);
IIC_STOP_
}
else
IIC_GET_ERR_
}
break;
default :
break;
}
}
}
}
Макросы
Код
#define IIC_START I2C0->CMD=I2C_CMD_START; // Посыл START на линию
#define IIC_STOP I2C0->CMD=I2C_CMD_STOP; // Посыл STOP на линию
#define IIC_SEND_ACK I2C0->CMD=I2C_CMD_ACK; // Посылка подтверждения
#define IIC_SEND_NACK I2C0->CMD=I2C_CMD_NACK; // Посылка не подтверждения
#define IIC_ABORT I2C0->CMD=I2C_CMD_ABORT; // Сброс шины
Удачи.