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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> STM32F030 проблема с I2C, Непонятное поведение I2C периферии контроллера
p_kav
сообщение Nov 7 2015, 23:52
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466



Здравствуйте.

Использую контроллер STM32F030F4P6. К нему по I2C подключен 1-Wire Master DS2482-100, а к нему, в свою очередь, по 1-Wire подключен термометр DS1820.

В Keil 5 написан следующий код.

Инициализация I2C:

CODE
void i2c1_init(void)
{
GPIO_InitTypeDef PORT;
I2C_InitTypeDef I2C_INIT;

I2C_StructInit(&I2C_INIT);

I2C_INIT.I2C_Ack = I2C_Ack_Disable;
I2C_INIT.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_INIT.I2C_Mode = I2C_Mode_I2C;
I2C_INIT.I2C_OwnAddress1 = 0xAA;
I2C_INIT.I2C_AnalogFilter = I2C_AnalogFilter_Disable;
I2C_INIT.I2C_DigitalFilter = 0;
I2C_INIT.I2C_Timing = 0x20000A0D; // Расчитано в Excel-таблице I2C_Timing_Configuration_V1.0.1.xls от ST

I2C_DeInit(I2C1);

PORT.GPIO_Mode = GPIO_Mode_AF;
PORT.GPIO_OType = GPIO_OType_OD;
PORT.GPIO_PuPd = GPIO_PuPd_NOPULL;
PORT.GPIO_Speed = GPIO_Speed_2MHz;
PORT.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;

GPIO_Init(GPIOA, &PORT);

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_4);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_4);

I2C_Init(I2C1, &I2C_INIT);
I2C_Cmd(I2C1, ENABLE);

}


Работа с DS2482-100:

CODE
t1 = 0;
t2 = 0;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xF0);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xB4);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

do
{
I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
} while (I2C_ReceiveData(I2C1) & 0x01);

I2C_TransferHandling(I2C1, DS2482A_Addr, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET); // Зависает здесь
I2C_SendData(I2C1, 0xA5);
I2C_SendData(I2C1, 0xCC);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

do
{
I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
} while (I2C_ReceiveData(I2C1) & 0x01);

/*
I2C_TransferHandling(I2C1, DS2482A_Addr, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xA5);
I2C_SendData(I2C1, 0x44);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
while(I2C_ReceiveData(I2C1) & 0x01) {}
*/

I2C_TransferHandling(I2C1, DS2482A_Addr, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xA5);
I2C_SendData(I2C1, 0xBE);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

do
{
I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
} while (I2C_ReceiveData(I2C1) & 0x01);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0x96);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

I2C_TransferHandling(I2C1, DS2482A_Addr, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xE1);
I2C_SendData(I2C1, 0xE1);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
t1 = I2C_ReceiveData(I2C1);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0x96);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

do
{
I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Read);
} while (I2C_ReceiveData(I2C1) & 0x01);

I2C_TransferHandling(I2C1, DS2482A_Addr, 2, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);
I2C_SendData(I2C1, 0xE1);
I2C_SendData(I2C1, 0xE1);
while(I2C_GetFlagStatus(I2C1, I2C_ISR_TC) == RESET);

I2C_TransferHandling(I2C1, DS2482A_Addr, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
t2 = I2C_ReceiveData(I2C1);

while(I2C_GetFlagStatus(I2C1, I2C_ISR_STOPF) == RESET);
I2C_ClearFlag(I2C1, I2C_ICR_STOPCF);


Если данный код вручную прошагать в отладчике, то никаких проблем не проявляется и в переменных t1 и t2 будут 0x05 и 0x50, как и указано в даташите на DS18B20.
Однако при обычном запуске программа зависает на четвертом блоке кода на проверке флага TXIS (отмечено комментарием). Флаг TXIS действительно не установлен, при этом флаг TXE установлен, хотя как я понял из даташита, в данном случае они должны подниматься вместе. Также установлен флаг TC, а NACKF, ARLO и другие сняты.
Если установить Breakpoint на строчку выше (I2C_TransferHandling) и выполнить Step Over, то TXIS будет установлен и работа продолжится.

Перепробовал множество вариантов, итог всегда один - пошагово работает, при обычном запуске виснет на проверке флага. У кого-нибудь было такое поведение I2C периферии STM32F0?

Сообщение отредактировал IgorKossak - Nov 8 2015, 17:52
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
etoja
сообщение Nov 8 2015, 17:16
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 121
Регистрация: 14-01-05
Из: Москва
Пользователь №: 1 952



Цитата(p_kav @ Nov 8 2015, 03:52) *
Использую контроллер STM32F030F4P6. К нему по I2C подключен 1-Wire Master ...


I2C и 1-Wire - совсем разные интерфейсы.
Я работаю с 32F050/030/040. Могу дать фрагменты кода для I2C.
Go to the top of the page
 
+Quote Post
p_kav
сообщение Nov 8 2015, 17:36
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466



Цитата(etoja @ Nov 8 2015, 22:16) *
I2C и 1-Wire - совсем разные интерфейсы.


Всё верно, поэтому я и использую DS2482, который, по сути, является преобразователем между I2C и 1-Wire.

Цитата(etoja @ Nov 8 2015, 22:16) *
Я работаю с 32F050/030/040. Могу дать фрагменты кода для I2C.


Да, хотелось бы взглянуть.
Хотя, мой код хорошо работает пошагово в отладчике.
Go to the top of the page
 
+Quote Post
Alechek
сообщение Nov 9 2015, 06:45
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



Цитата(p_kav @ Nov 8 2015, 22:36) *
Всё верно, поэтому я и использую DS2482, который, по сути, является преобразователем между I2C и 1-Wire.

bb-offtopic.gif
Так, к сведению, на STM32 1-wire очень хорошо эмулируется через SPI. И никакие прослойки не нужны.
Go to the top of the page
 
+Quote Post
p_kav
сообщение Nov 9 2015, 07:04
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466



Alechek
Что-то не могу найти ни одной статьи о такой реализации. Можете подсказать как это правильно сделать?
Я так понимаю, нужно замкнуть ножки MOSI и MISO, настроить как Open Drain и подключить к датчику, формировать единицу по MOSI как 0b00010111, ноль как 0b00010001, сброс как 0b00000101, при этом после каждой отправки байта в принятых по MISO данных будет ответ датчика. Я правильно понял?

Хотя, мне бы хотелось понять что не так с I2C. Ведь пошагово работает, а при обычном запуске виснет. wacko.gif
Я так понимаю, если я ставлю Breakpoint и процессор на него попадает, то останавливается всё, включая периферию, или же останавливается только ядро, а периферия продолжает тактоваться и работать?
Go to the top of the page
 
+Quote Post
scifi
сообщение Nov 9 2015, 07:08
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Alechek @ Nov 9 2015, 09:45) *
Так, к сведению, на STM32 1-wire очень хорошо эмулируется через SPI. И никакие прослойки не нужны.

+1. Кстати, я эмулировал 1-wire при помощи UART, как описано здесь.
Каждый раз, когда соприкасался с I2C у ST, оставалось стойкое ощущение его кривизны. Очень может быть, что сделать эмуляцию 1-wire будет проще, чем пытаться победить этот I2C.
Go to the top of the page
 
+Quote Post
adnega
сообщение Nov 9 2015, 08:04
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(scifi @ Nov 9 2015, 10:08) *
+1. Кстати, я эмулировал 1-wire при помощи UART.
Очень может быть, что сделать эмуляцию 1-wire будет проще, чем пытаться победить этот I2C.

+1. А я делал и мастера, и слейва 1-wire на таймере (+DMA для слейва).
В общем, 1-wire можно подключить множеством способов, но только не через преобразователь I2C ))
Go to the top of the page
 
+Quote Post
Alechek
сообщение Nov 9 2015, 08:05
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



Цитата(p_kav @ Nov 9 2015, 12:04) *
Что-то не могу найти ни одной статьи о такой реализации. Можете подсказать как это правильно сделать?

Я тоже ни одной статьи не видел, но если подумать, то ничем не хуже UART. Причем, даже лучше, так можно прикрутить аппаратно Strong Pullup к /CS.
Для более точного тайминга SPI лучше запустить в 16 бит режиме.

Некоторые констаты с проекта
Цитата
#define DATABIT_0 0x801F // 80 us LOW
#define DATABIT_1 0xBFFF // 8 us LOW

static const INT16U _reset_sequence[] = {0x0000, 0x0000, 0x0000, 0x0000,
0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF};


PS Особенность STM - SPI CLK должны быть выведены наружу. Иначе не работат прием данных!!! cranky.gif
Go to the top of the page
 
+Quote Post
adnega
сообщение Nov 9 2015, 08:07
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



По теме: флаги под отладчиком могут меняться, если какие-нить регистры считываются для просмотра.
Go to the top of the page
 
+Quote Post
scifi
сообщение Nov 9 2015, 08:15
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(adnega @ Nov 9 2015, 11:07) *
По теме: флаги под отладчиком могут меняться, если какие-нить регистры считываются для просмотра.

Тоже хотел об этом упомянуть. Чтение некоторых регистров I2C приводит к изменению состояния периферии. А отладчик как раз может услужливо их читать. Сам сталкивался с тем, что годный код глючил, если в отладчике включен просмотр регистров.
И не только это, конечно. Скорость исполнения кода легко может иметь значение (если код ошибочный). Всё-таки процессы внутри I2C не мгновенно происходят.
Go to the top of the page
 
+Quote Post
p_kav
сообщение Nov 9 2015, 08:28
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466



scifi
Я пробовал вставлять задержки, не помогает.
Также перед рестартом пробовал добавлять I2C_ReceiveData(I2C1), чтобы прочитать регистр, но флаг RXNE продолжает висеть.
К тому же, мне кажется, что отладчик читает регистры своим способом, не вызывая никаких событий у периферии, иначе при включенной отладке у меня бы в программу не поступали данные из UART, регистры которого тоже видны на панели.

Вот тут человек вставил костыль и у него заработало. Думаю, нужно тоже будет попробовать сбрасывать I2C перед каждым стартом/рестартом.
Go to the top of the page
 
+Quote Post
scifi
сообщение Nov 9 2015, 08:41
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(p_kav @ Nov 9 2015, 11:28) *
мне кажется, что отладчик читает регистры своим способом, не вызывая никаких событий у периферии

Может быть, не стану утверждать. Но сильно в этом сомневаюсь.

Цитата(p_kav @ Nov 9 2015, 11:28) *
Я пробовал вставлять задержки, не помогает.
Также перед рестартом пробовал добавлять I2C_ReceiveData(I2C1), чтобы прочитать регистр, но флаг RXNE продолжает висеть.

Танцы с бубном.

Цитата(p_kav @ Nov 9 2015, 11:28) *
Вот тут человек вставил костыль и у него заработало. Думаю, нужно тоже будет попробовать сбрасывать I2C перед каждым стартом/рестартом.

Снова танцы с бубном.

I2C у СТ сделан криво. Там нужно внимательно вчитываться в мануал, обращая внимание на все мелочи, чтобы всё это заработало. И вот эта "библиотека", которая прячет обращение к регистрам внутри своих функций, только мешает. Может быть, им удалось спрятать эту кривизну в функциях - не проверял. Но ваши мучения намекают на то, что никуда эта кривизна не делась. Поэтому мой совет такой: работайте с регистрами напрямую и внимательно читайте мануал. А ещё проще было бы сделать I2C ногодрыгом.
Go to the top of the page
 
+Quote Post
p_kav
сообщение Nov 9 2015, 08:47
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466



Цитата(scifi @ Nov 9 2015, 13:41) *
А ещё проще было бы сделать I2C ногодрыгом.


Вот, наверное, так и поступлю, скорость мне не важна и памяти ещё много.
В STM32L1, кстати, I2C совсем другой, другие регистры. И там всё работает нормально. Видимо, осознали и починили.
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Nov 9 2015, 09:03
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(p_kav @ Nov 9 2015, 15:28) *
К тому же, мне кажется, что отладчик читает регистры своим способом, не вызывая никаких событий у периферии

Фига, режим отладки может и должен сбрасывать флаги при чтении. Потому как реакция флага на чтение/изменение - это выборка его адреса.
Стандартная фраза как в поликлинике - "я только спросить" - тут не канает.
Закрывайте ветки регистров в отладчике, для того чтобы они не опрашивались, и тогда, возможно, с пятого раза, и десяти перезапусках - оно и заработает.
Go to the top of the page
 
+Quote Post
vet
сообщение Nov 9 2015, 09:10
Сообщение #15


Знающий
****

Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32



Пытался работать с I2C-периферией и на STM32F, и на STM32L, на F она откровенно не работала, на L получше, но всё равно застревала в ошибочных состояниях, помогало только отключение периферии, остановка тактирования и её перезапуск со сбросом.


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post

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

 


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


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