Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F100C6T6 и I2C1
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ivainc1789
По примеру в IAR EWARM написал небольшую программу инициализации интерфейса I2C для работы через прерывания:
CODE
void I2C_Ini(void){
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// I2C RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
// I2C GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);// SCL=B8,SDA=B9
PININI(SCL,GPIO_Mode_AF_OD,GPIO_Speed_50MHz);PINLOCK(SCL); // макросы проверены, ошибок нет
PININI(SDA,GPIO_Mode_AF_OD,GPIO_Speed_50MHz);PINLOCK(SDA);// макросы проверены, ошибок нет
// I2C config
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0xAA;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1,ENABLE);
// I2C NVIC
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1,I2C_IT_EVT,ENABLE); // enable event IRQ
I2C_ITConfig(I2C1,I2C_IT_ERR,ENABLE); // enable error IRQ
I2C_ITConfig(I2C1,I2C_IT_BUF,ENABLE); // enable buffer IRQ
}


Странно, но результатом ее выполнения является установка бита BUSY, хотя осцилл показывает, что линии SCL и SDA находятся в высоком уровне. По описанию этого бита, его установка свидетельствует о низком уровне хотя бы одной линии. Что же тут не так?
Дальнейшая выдача START бессмысленна, т. к. судя по всему интерфейс неправильно инициализирован...
Aaron
попробуйте поменять местами команды включения и инициализации, и добавить ещё один вызов:
Код
I2C_Cmd(I2C1,ENABLE);
I2C_Init(I2C1,&I2C_InitStructure);
I2C_AcknowledgeConfig(I2C1, ENABLE);

по крайней мере я сегодня I2C код на базе примеров написал, всё заработало с первого раза. И у меня именно так команды стоят.
KnightIgor
Цитата
I2C_Cmd(I2C1,ENABLE);
I2C_Init(I2C1,&I2C_InitStructure);


Странная последовательность. Надо бы наоборот. А то разрешается I2C, которая еще не проинициализирована.

P.S. @ivainc1789: в своем коде нашел такое замечание: // ATTENTION: some forums say, first init I2C, then GPIO... У Вас же сначала инициализируется GPIO, потом I2C. Я бы тоже так сделал по логике вещей, но мой работающий код следует-таки замечанию:
Код
    I2C_INIT(I2C_DEVICE, I2C_InitStruct); // (sets PE, too)
    GPIO_Configuration(I2CGPIOs,  sizeof(I2CGPIOs));
#ifdef I2C1_REMAPPED

    GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
#endif
    IRQ_INIT(NVIC_I2CInitStructure);
    IRQ_INIT(NVIC_I2CErrStructure);

(всякие макросы использованы, но суть остается).
ivainc1789
Цитата(KnightIgor @ Apr 13 2012, 17:06) *
Странная последовательность. Надо бы наоборот. А то разрешается I2C, которая еще не проинициализирована.
Я того же мнения, хотя в примерах от IAR именно так и сделано: разрешается работа того, что еще не настроено... )))

Цитата
в своем коде нашел такое замечание: // ATTENTION: some forums say, first init I2C, then GPIO...
вот это фундаментальное наблюдение! Я тоже сложа руки не сидел, но пришел к другому выводу. Для того, чтобы мой код из первого поста заработал, достаточно строку:
Код
// I2C RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);

опустить ниже секции инициализации GPIO - и все начинает работать! Т. е. хочется сделать вывод, что сначала все же настраиваем GPIO (в том числе ремаппинг, если есть) и только потом подаем тактирование и инициализируем переферийный модуль! Причем в примерах у IAR все работать может только потому, что не используется ремаппинг... Короче, в ref manual прямо про эти тонкости не сказано, а проблема вроде бы существует: как все же правильно инициализировать?
KnightIgor
Цитата(ivainc1789 @ Apr 13 2012, 14:32) *
как все же правильно инициализировать?

Правильно так, как заработает. Я, как уже писал, подсмотрел в форуме самого ST то самое замечание, сделал, - работает. Больше над темой не задумывался. Может правы Вы: у меня такт на GPIO подается где-то в начале всей программы (чтобы привести ноги в танцевальную позицию номер 5 максимально быстро), а уж потом в разных подмодулях начинается инициализация периферий. Кстати, что я еще себе за правило взял: перед XXX_Init() я вызываю XXX_DeInit() на случай, если вздумаю вызвать переинициализацию подмодулей изнутри уже работающей программы, а не только единожды после RESET.
Aleksandr Baranov
Я сначала инициализирую GPIO, а потом - I2C. Иначе иногда инициализированный I2C во время инициализации GPIO заклинивает
KnightIgor
Цитата(Aleksandr Baranov @ Apr 13 2012, 16:03) *
Я сначала инициализирую GPIO, а потом - I2C. Иначе иногда инициализированный I2C во время инициализации GPIO заклинивает

Попробовал и я: "наплевал" на собственное предостережение и сделал инициализацию пинов GPIO для I2C перед самим I2C (как, собственно, логика и подсказывает). Работает и так. Правда, тактирование на GPIO порт и AFIO к этому моменту уже имеется, и я лишь задаю режимы требуемых пинов в данном подмодуле. Поэтому я предположу, что автор темы прав и раскопал верную особенность: дай такт на GPIO, поставь ноги прямо и лишь потом запускай периферию.
smk
Спасибо автору, что обратил внимание на эту тонкость. У меня както так повелось, что всегда первыми инициализируются GPIO, может потому и не наступил на эти грабли.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.