реклама на сайте
подробности

 
 
> STM32 Вопрос про I2C, непонимаю даташит или что-то не то
Vladimir Prokofi...
сообщение Aug 25 2011, 10:22
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Пытаюсь послать два байта слейву по I2C:
1. Выставляем СТАРТ
2. Получаем в прерывании что старт прошел (Событие 5 ) I2C_EVENT_MASTER_MODE_SELECT:
Шлем 7битный адрес слейва по этому прерыванию
3. Получаем прерывание что отослан адрес. Игнорируем, так как должно сразу придти прерывание TxE
4. По прерыванию о пустоте буфера ( События 8 и 8_2 )
case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
Если первый раз пришло, то шлем БАЙТ1.
Если второй раз пришло, то шлем БАЙТ2.
Если третий раз пришло то:


Вот тут хочется послать стоп. Но это прерывание пришло так как TxE = 1. Реально байт еще не ушел. Когда он уйдет, то, судя по эрате, должен выставиться битик BTF. Поэтому я считаю что его надо ждать. Я бы написал так:
Если третий раз пришло то:
Если BTF == 1 то шлем СТОП
Но этот бит не устанавливается. Прерывания приходят и приходят, БТФ = 0. Почему?


В принципе в эрате написано что СТОП следует выставлять когдв либо TxE = 1 либо BTF = 1;
Если я пошлю СТОП когда TxE = 1 а BTF = 0 то не получится ли так, что СТОП оборвет последний байт?

PS

И непонятно еще такая штука, у меня сложилось понимание, что:
когда срабатывает прерывание TxE, байт начинает слаться. Если ничего не кинуть в буфер, то прерывание не сбросится, и будет постоянно вызываться, пока не установится бит BTF?
Т.е. контроллер будет ждать пока уйдет последний байт в любом случае...


Сообщение отредактировал Vladimir Prokofiev - Aug 25 2011, 10:31
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
DmitryDI
сообщение Aug 25 2011, 14:14
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 70
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 789



Ну и как получилось завести I2C? Может есть вариант правильной инициации?
Go to the top of the page
 
+Quote Post
Vladimir Prokofi...
сообщение Aug 25 2011, 15:22
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Цитата(DmitryDI @ Aug 25 2011, 18:14) *
Ну и как получилось завести I2C? Может есть вариант правильной инициации?



Инициализация вроде понятная, тут вопрос в странном поведении флагов и событий. Все работало (вроде) -- два датчика по i2C опрашивались. Добавил в проект СД карточку (изменив при этом частоты ) и перестало работать и то и другое. Даже не то чтобы перестало, а перебрасывается каким-то количеством пакетов и получает странные события, типо, например
lastEvent = 1;

Код инициализации
CODE

void API2C_Init( void ){
I2C_InitTypeDef I2C_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_ClocksTypeDef RCC_Clocks;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
//I2C Peripheral clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
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_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);


/* NVIC configuration */
/* Configure the Priority Group to 1 bit */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/* Configure the I2C event priority */
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Configure I2C error interrupt to have the higher priority */
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
NVIC_Init(&NVIC_InitStructure);


RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);


//#define I2C_SPEED 340000
#define I2C_SPEED 1000
#define I2C_DUTYCYCLE I2C_DutyCycle_16_9

/* I2C De-initialize */
I2C_DeInit(I2C1);

/*!< I2C Struct Initialize */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DUTYCYCLE;
I2C_InitStructure.I2C_OwnAddress1 = 0xA0;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;

I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

/*!< I2C Initialize */
I2C_Init(I2C1, &I2C_InitStructure);

/* Enable Error Interrupt */
I2C_ITConfig(I2C1, I2C_IT_ERR , ENABLE);

/* I2C ENABLE */
I2C_Cmd(I2C1, ENABLE);


/* Enable Error and Buffer Interrupts */
I2C_ITConfig(I2C1, (I2C_IT_EVT | I2C_IT_BUF), ENABLE);

API2C_SendCmd( I2CCMD_WRITE, LIS_ADDRESS, LIS_REG_CTRL1, LIS_REG_CTRL1_POWERON );

while( API2C_IsTransferDone() == 0);

}



Сообщение отредактировал Vladimir Prokofiev - Aug 25 2011, 15:23
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Aug 29 2011, 08:59
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Vladimir Prokofiev @ Aug 25 2011, 17:22) *
Инициализация вроде понятная, тут вопрос в странном поведении флагов и событий. Все работало (вроде) -- два датчика по i2C опрашивались. Добавил в проект СД карточку (изменив при этом частоты ) и перестало работать и то и другое. Даже не то чтобы перестало, а перебрасывается каким-то количеством пакетов и получает странные события...

I2C в STM32F сделан настолько паршиво, что требуется либо запрет прерываний при обработке некоторых событий I2C, либо присвоение прерыванию от I2C наивысшего приоритета. Я предполагаю, что как только Вы добавили SD карточку, у Вас начали прерываться критические фрагменты I2C. Посмотрите внимательно мануал. Особенно хреново дело обстоит при транзакциях с приемо-передачей 1-го или 2-х байтов: это особый случай для данного I2C. Похвастаюсь, что я-таки разобрался со всей хренотенью I2C STM32F и написал своего рода библиотечку, которая предлагает более-менее высокоуровневые процедуры обмена по I2C, а приемо-передача может осуществляться в том числе с использованием DMA. Выборы режима происходят на этапе трансляции путем определений в *.H файле. Если очень нужно, выложу код. Сразу не могу, т.к. там у меня многое завязано на мои общие проектные макросы, и надо бы изолировать I2C от них.
Go to the top of the page
 
+Quote Post
Vladimir Prokofi...
сообщение Aug 29 2011, 11:19
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Цитата(KnightIgor @ Aug 29 2011, 12:59) *
I2C в STM32F сделан настолько паршиво, что требуется либо запрет прерываний при обработке некоторых событий I2C, либо присвоение прерыванию от I2C наивысшего приоритета. Я предполагаю, что как только Вы добавили SD карточку, у Вас начали прерываться критические фрагменты I2C. Посмотрите внимательно мануал. Особенно хреново дело обстоит при транзакциях с приемо-передачей 1-го или 2-х байтов: это особый случай для данного I2C. Похвастаюсь, что я-таки разобрался со всей хренотенью I2C STM32F и написал своего рода библиотечку, которая предлагает более-менее высокоуровневые процедуры обмена по I2C, а приемо-передача может осуществляться в том числе с использованием DMA. Выборы режима происходят на этапе трансляции путем определений в *.H файле. Если очень нужно, выложу код. Сразу не могу, т.к. там у меня многое завязано на мои общие проектные макросы, и надо бы изолировать I2C от них.

Основной обмен как раз 2-байтовый)
Конечно, хотелось бы увидеть код. Тем более что сам пытаюсь написать такую библиотечку...
Если даже и не использовать, то очень бы хотелось посмотреть на правильный и рабочий код.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Aug 29 2011, 12:15
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Vladimir Prokofiev @ Aug 29 2011, 13:19) *
Конечно, хотелось бы увидеть код. Тем более что сам пытаюсь написать такую библиотечку...
Если даже и не использовать, то очень бы хотелось посмотреть на правильный и рабочий код.

Намек понял. Я постараюсь на неделе СОБИРАЮЩИЙСЯ код выложить. Сейчас Вы можете глянуть в код, чтобы понять основные ходы обработки I2C и особых случаев.
Код насыщен макросами. Причина их применения - не захламлять текст сложными конструкциями обращений к регистрам или библиотечным функциям. Имена самих макросов достаточно прозрачно говорят об их назначении. Это мой стиль, критиковать бесполезно, т.к. о вкусах не спорят; важен результат. Кроме того, применяются некоторые собственные функции, которые пока не приводятся.

Нужно учитывать следующее:

1). Сделано под KEIL, с применением его Configuration Wizzard для настроек определений в *.H файле.
2). По причине выше попытки гарантировать собираемость другими компиляторами не делались;
3). Библиотека в нынешнем виде может работать только с одним из I2C (в продвинутых STM32F имеется несколько I2C), выбор которого осуществляется перед трансляцией через заголовки;
4). Коммуникация только с 7-битной I2C периферией (ADDR10 не поддерживается).
5). Есть аппаратно-независимый заголовочный файл HAL_I2C.h и аппаратно-зависимый stm32f10x_iic.h.
6). Библиотека использует как функции из STM32F Peripheral Library (когда надо удобно), так и регистровый доступ (когда хочется по-быстрее), а также некоторые собственные функции
(HAL_Proc.h и stm32f10x_proc.h).

void I2Cx_EV_IRQHandler(void) это то, куда смотреть в первую очередь, чтобы понять алгоритм.

Разбирайтесь, спрашивайте.

Сообщение отредактировал KnightIgor - Aug 29 2011, 12:26
Прикрепленные файлы
Прикрепленный файл  STM32F_I2C_SOLUTIONS.zip ( 13.12 килобайт ) Кол-во скачиваний: 309
 
Go to the top of the page
 
+Quote Post
Vladimir Prokofi...
сообщение Aug 30 2011, 08:31
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Большое спасибо! Скачал, пошел смотреть!
Go to the top of the page
 
+Quote Post
Vladimir Prokofi...
сообщение Aug 30 2011, 15:25
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Вроде заработало, но, кажется, основная ошибка была совсем в другом...
Я посылал один пакет в след за другим сразу. Гипотеза, что слейв не успевал поймать старт после стопа. Может такое быть?
Поэтому он не подтверждал прием, срабатывало прерывание на ошибку. ошибка сбрасывалась, но что при этом с передачей происходит дальше я не знаю.
Поставил паузу перед отправкой. Но как то это стремно, контроллер тратит свеё время на ожидание...
Хотя меня тревожат сомненья что это не причина. Может просто условия изменились и пока ошибки не возникает...

Разобрался с BTF. Он не приходит после отправки адреса. Вроде, я даже это где-то читал.

Осталась пока одна странность, MASTER_BYTE_TRANSMITTED приходит лишний раз уже после STOP. При этом если его ловить и смотреть регистры, то они нулевые. Т.е. запоздалое прерывание какое-то приходит...

PS
Прочитал у Вас в коде, а потом в эррате, про то, когда читать или не читать SR2 чтобы не сбросить ADDR. У меня 215 контроллер, там другая эррата, и ничего про это явно не написано. Я сейчас не проверяю, уже 10 минут работает sm.gif Но это не показатель... Надо ли в 2xx серии заниматься этим, не знаете?

В любом случае, прогресс налицо, большое спасибо за помощь!

Сообщение отредактировал Vladimir Prokofiev - Aug 30 2011, 15:27
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Aug 30 2011, 16:49
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Vladimir Prokofiev @ Aug 30 2011, 17:25) *
Вроде заработало, но, кажется, основная ошибка была совсем в другом...
Я посылал один пакет в след за другим сразу. Гипотеза, что слейв не успевал поймать старт после стопа. Может такое быть?

Думаю, такое вполне возможно: slave имеет конечный автомат, и как и насколько быстро он там работает, знает только разработчик чипа, если вообще тестировал такую последовательность. Гляньте для Вашего slave, может там есть описание минимально допустимых времен указанной последовательности.

Цитата
Разобрался с BTF. Он не приходит после отправки адреса. Вроде, я даже это где-то читал.


Не приходит, потому как "они" понимают под "byte transferred" именно байт данных, а завершение передачи первого байта после старта, - то есть байта адреса, - сигнализируется битом ADDR в SR2. Отвечая на Ваш PS здесь скажу, что как там с 2xx серией дело обстоит, я не знаю, еще не работал, но уверен, что I2C там такой же. Хотя бы для совместимости.

Суть "не сбрасывать" ADDR состоит в том, что при приеме байтов от slave надо заранее подготовить ему ACK/NACK или STOP еще перед тем, как автомат начнет тактирование приема. Тактирование же приема начинается аппаратно сразу, как только ADDR был сброшен. И если сбросить ADDR (чтением SR2) уже при входе в обработчик прерывания, то нет гарантии, что тут же не "рванет" другое прерывание более высокого уровня, и процессор, вернувшись оттуда, уже не успеет подготовить ACK/NACK/STOP, а байт от slave будет аппаратно уже в пути или еще хуже - уже принят. Поэтому я задерживаю сброс ADDR, не считывая SR2, этим самым предотвращаю начало тактирования очередного байта от slave, спокойно готовлю ACK/NACK/STOP, и лишь после этого "отпускаю" аппаратуру I2С.

Цитата
Осталась пока одна странность, MASTER_BYTE_TRANSMITTED приходит лишний раз уже после STOP. При этом если его ловить и смотреть регистры, то они нулевые. Т.е. запоздалое прерывание какое-то приходит...


Может у меня такое было вначале, но мой автомат запрещает прерывание сразу после выдачи STOP (см. последний else ветви case I2C_EVENT_MASTER_BYTE_TRANSMITTED, где вызывается I2C_SUCCESS_HANDLER, который и запрещает прерывание). А перед началом очередной транзакции вызывается INIT_I2C_FLAGS, который там все возможно висящие флаги прочищает.

Цитата
В любом случае, прогресс налицо, большое спасибо за помощь!


Был рад посодействовать!

Сообщение отредактировал KnightIgor - Aug 30 2011, 20:54
Go to the top of the page
 
+Quote Post
Vladimir Prokofi...
сообщение Sep 15 2011, 10:47
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 47
Регистрация: 9-03-11
Пользователь №: 63 481



Уже считал что все получилось, но тут опять столкнулся с проблемой.
На слейве есть набор регистров, поэтому бывает нужно отправить слейву 2 байта:
Адрес слейва + Адрес регистра + Новое значение регистра.

Если вызвать два раза функцию записи, то после второго старта прерывание приходит, шлем адрес а дальше все встает. прерывания больше не приходят, флага BUSY нету.

Идешь по шагам -- все ок)

Методом научного тыка получилось заставить работать -- вставить маленькую задержку после генерации стопа. Код обработки прерывания стал такой:
CODE
lastEvent = I2C_Event( isReadSR2 );
#define E_ADDR (2) // SR1_1
#define E_SB (1) // SR1_0
#define E_BTF (4) // SR1_2
#define E_TxE (128) // SR1_2
#define E_RxNE (64) // SR1_2
if( CheckBit( lastEvent, E_SB ) ){
I2C_Send7bitAddress(I2C1, (uint8_t)curCmd.devAddr, I2C_Direction_Transmitter);
i2cstate = STATE_START;
isReadSR2 = 1;
return;
}
// Àäðåñ îòîñëàí è ñëåéâ ïîäòâåðäèë. Ïðîñòî ñáðàñûâàåì, æäåì TxE
if( CheckBit( lastEvent, E_ADDR ) ){
i2cstate = STATE_DATA1;
isReadSR2 = 1;
return;
}
// TxE -- áóôåð íà îòïðàâêó ïóñò, çàïîëíÿåì åãî ïåðâûì èëè âòîðûì áàéòîì.
if( CheckBit( lastEvent, E_TxE ) ){
if( i2cstate == STATE_DATA1 ){
I2C_SendData( I2C1, curCmd.regAddr );
i2cstate = STATE_DATA2;
isReadSR2 = 1;
return;
} else if( i2cstate == STATE_DATA2 ){
I2C_SendData( I2C1, curCmd.regVal );
i2cstate = STATE_NOTBUSY;
isReadSR2 = 1;
return;
}
}
if( CheckBit( lastEvent, E_BTF ) ){
if( i2cstate == STATE_NOTBUSY ){
I2C_GenerateSTOP(I2C1, ENABLE);
for( i = 0; i < 100; i++ );
isTransferDone = 1;
}
isReadSR2 = 1;
return;
}


Ну и отправляется это так:

API2C_SendCmd( I2CCMD_WRITE, LIS_ADDRESS, LIS_REG_CTRL1, LIS_REG_CTRL1_POWERON );
while( API2C_IsTransferDone() == 0);
API2C_SendCmd( I2CCMD_WRITE, LIS_ADDRESS, LIS_REG_CTRL1, LIS_REG_CTRL1_POWERON );
while( API2C_IsTransferDone() == 0);

сразу после инита I2C. Функция отправки заполняет структурку curCmd и генерирует СТАРТ последней командой.

Тык вот работает только так, с дурацкой задержкой в прерывании. Вынести эту задержку в API2C_SendCmd не получается -- не работает, хотя на осциллографе одно и тоже получается...
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Vladimir Prokofiev   STM32 Вопрос про I2C   Aug 25 2011, 10:22
- - dfyz.s   Здравствуйте! Сейчас разбираюсь с похожей проб...   Feb 5 2013, 18:28
|- - KnightIgor   Цитата(dfyz.s @ Feb 5 2013, 19:28) Сейчас...   Feb 5 2013, 21:41
- - dfyz.s   Большое спасибо за подробное описание! Не могл...   Feb 6 2013, 05:40
|- - KnightIgor   Цитата(dfyz.s @ Feb 6 2013, 06:40) Не мог...   Feb 6 2013, 12:05
|- - KnightIgor   Цитата(dfyz.s @ Feb 6 2013, 06:40) Большо...   Feb 6 2013, 20:20
- - dfyz.s   Да, какая то фигня с личными сообщениями, хотя в н...   Feb 8 2013, 17:10
- - polyname   Непонятно что они курили когда разрабатывали I2C ?...   Feb 8 2013, 17:47
- - dfyz.s   )))) Согласен. Но это не решает проблемы. Сейчас ...   Feb 8 2013, 18:04
|- - KnightIgor   Цитата(dfyz.s @ Feb 8 2013, 19:04) Сейчас...   Feb 8 2013, 20:25
- - dfyz.s   Игорь, большое спасибо за ваши обяснения! Мне...   Feb 10 2013, 19:31
|- - _Артём_   Цитата(dfyz.s @ Feb 10 2013, 21:31) отлад...   Feb 10 2013, 20:07
|- - KnightIgor   Цитата(dfyz.s @ Feb 10 2013, 20:31) Мне с...   Feb 11 2013, 11:02
- - dfyz.s   Да, скорее всего я где-то напортачил. Надо протест...   Feb 11 2013, 12:46
|- - KnightIgor   Цитата(dfyz.s @ Feb 11 2013, 13:46) Пробе...   Feb 12 2013, 08:39
- - dfyz.s   Да, с схемотехнической точки зрения похоже все хор...   Feb 13 2013, 06:34


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th July 2025 - 08:34
Рейтинг@Mail.ru


Страница сгенерированна за 0.01512 секунд с 7
ELECTRONIX ©2004-2016