|
STM32F030 проблема с I2C, Непонятное поведение I2C периферии контроллера |
|
|
|
Nov 7 2015, 23:52
|
Местный
  
Группа: Участник
Сообщений: 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] - для короткого!!!
|
|
|
|
|
Nov 8 2015, 17:36
|
Местный
  
Группа: Участник
Сообщений: 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. Да, хотелось бы взглянуть. Хотя, мой код хорошо работает пошагово в отладчике.
|
|
|
|
|
Nov 9 2015, 07:04
|
Местный
  
Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466

|
AlechekЧто-то не могу найти ни одной статьи о такой реализации. Можете подсказать как это правильно сделать? Я так понимаю, нужно замкнуть ножки MOSI и MISO, настроить как Open Drain и подключить к датчику, формировать единицу по MOSI как 0b00010111, ноль как 0b00010001, сброс как 0b00000101, при этом после каждой отправки байта в принятых по MISO данных будет ответ датчика. Я правильно понял? Хотя, мне бы хотелось понять что не так с I2C. Ведь пошагово работает, а при обычном запуске виснет. Я так понимаю, если я ставлю Breakpoint и процессор на него попадает, то останавливается всё, включая периферию, или же останавливается только ядро, а периферия продолжает тактоваться и работать?
|
|
|
|
|
Nov 9 2015, 07:08
|
Гуру
     
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Nov 9 2015, 08:05
|
Профессионал
    
Группа: Свой
Сообщений: 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 должны быть выведены наружу. Иначе не работат прием данных!!!
|
|
|
|
|
Nov 9 2015, 08:28
|
Местный
  
Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466

|
scifiЯ пробовал вставлять задержки, не помогает. Также перед рестартом пробовал добавлять I2C_ReceiveData(I2C1), чтобы прочитать регистр, но флаг RXNE продолжает висеть. К тому же, мне кажется, что отладчик читает регистры своим способом, не вызывая никаких событий у периферии, иначе при включенной отладке у меня бы в программу не поступали данные из UART, регистры которого тоже видны на панели. Вот тут человек вставил костыль и у него заработало. Думаю, нужно тоже будет попробовать сбрасывать I2C перед каждым стартом/рестартом.
|
|
|
|
|
Nov 9 2015, 08:41
|
Гуру
     
Группа: Свой
Сообщений: 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 ногодрыгом.
|
|
|
|
|
Nov 9 2015, 08:47
|
Местный
  
Группа: Участник
Сообщений: 294
Регистрация: 5-08-14
Из: Ярославль
Пользователь №: 82 466

|
Цитата(scifi @ Nov 9 2015, 13:41)  А ещё проще было бы сделать I2C ногодрыгом. Вот, наверное, так и поступлю, скорость мне не важна и памяти ещё много. В STM32L1, кстати, I2C совсем другой, другие регистры. И там всё работает нормально. Видимо, осознали и починили.
|
|
|
|
|
Nov 9 2015, 09:03
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(p_kav @ Nov 9 2015, 15:28)  К тому же, мне кажется, что отладчик читает регистры своим способом, не вызывая никаких событий у периферии Фига, режим отладки может и должен сбрасывать флаги при чтении. Потому как реакция флага на чтение/изменение - это выборка его адреса. Стандартная фраза как в поликлинике - "я только спросить" - тут не канает. Закрывайте ветки регистров в отладчике, для того чтобы они не опрашивались, и тогда, возможно, с пятого раза, и десяти перезапусках - оно и заработает.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|