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

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> залипает шина I2C в STM32, на МК режим slave
Метценгерштейн
сообщение Oct 6 2016, 08:51
Сообщение #1


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



STM32 подключен слейвом к другому процу АРМ на Линуксе.
Все работает, но поведение странное. Периодически отваливается шина I2C и мой STM не получает никакие команды из вне. Написана на регистрах инициализация. Подтяжки шины к +3,3 по 7,5 К.
Куда можно смотреть? Может что не проинициализировал в МК?
Go to the top of the page
 
+Quote Post
Jury093
сообщение Oct 6 2016, 10:23
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 959
Регистрация: 11-01-06
Из: Санкт-Петербург
Пользователь №: 13 050



Цитата(Метценгерштейн @ Oct 6 2016, 11:51) *
Куда можно смотреть? Может что не проинициализировал в МК?

так проведите диагностику с логированием
как на стороне линукса - диагностический выхлоп драйвера i2c в syslog
так и стороне stm32, желательно вывод транзакций с записью с консоли + дамп статусных регистров
ну и осцилл на шину

смотрите работу, фиксируете, возник дефект - изучаете картину, ловите виновного..
может слейв NAK глотает, может тайминги не держит, может машина состояния что-то не формирует
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 10:33
Сообщение #3


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Цитата(Jury093 @ Oct 6 2016, 13:23) *
так проведите диагностику с логированием
как на стороне линукса - диагностический выхлоп драйвера i2c в syslog
так и стороне stm32, желательно вывод транзакций с записью с консоли + дамп статусных регистров
ну и осцилл на шину

смотрите работу, фиксируете, возник дефект - изучаете картину, ловите виновного..
может слейв NAK глотает, может тайминги не держит, может машина состояния что-то не формирует


что значит, NAK глотает? А если тайминги не держит - что значит? Как смотреть?
Логгирование в Линуксе I2C как запустить?
Go to the top of the page
 
+Quote Post
gerber
сообщение Oct 6 2016, 10:59
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Изъездил аппаратный I2C Slave на STM32 вдоль и поперек. Сталкивался с тем, что иногда I2C Slave ловит ложное STOP-условие, то есть перепад Low->High на SDA при высоком SCL. Это может происходить, когда мастер меняет SDA близко к фронтам SCL, и учитывая емкостные свойства линий SCL/SDA, аппаратный контроллер фиксирует STOP-условие посреди посылки, что приводит к установке бита 8 (BERR - Bus Error, Misplaced Start or Stop condition) в регистре статуса. Посылка при этом, естественно, теряется, и конечный автомат ждёт снова START-условия, адреса и т. п.
Поэтому, задействуя аппаратный контроллер I2C, необходимо включать прерывания по ошибочным состояниям и корректно обрабатывать их.
Самое печальное в этом то, что отключить такое поведение (отслеживание Bus Error) нельзя, и это очень мешает нормальной работе, особенно в приложениях, где мастер "не любит" повторять запросы, и при неответе слейва тупо фиксирует ошибку.
Что касается меня, то я, изрядно повозившись с аппаратным I2C Slave на STM32, переписал драйвер таким образом, что аппаратный I2C делает для меня только START+сравнение адреса, после чего "будит" контроллер прерыванием "Address matched", после чего ноги переназначаются на GPIO, и дальнейшая работа идёт софтовой эмуляцией I2C Slave.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 11:34
Сообщение #5


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



выложу инициализацию I2C. Может у кого глаз зацепится за что-то некорректное.
Проц STM32F030
На всякий случай сейчас еще раз перевыкачал CubeMX, так с ним шину I2C Линукс даже не сканирует. Сразу глючит. HAL вообще здесь не применим.

Код
void init(void)
{
    i2c.max_rx_count = sizeof(incoming);
    i2c.state = st_idle;
    uint_fast32_t bus_clk;    
    uint_fast32_t scale;
    static const struct gpio_configuration pinconf =
    {
      .open_drain=1,
      .output=0,
      .analog=0,
      .alter=1,
      .speed=0,
      .pullup=0, // было 1
      .pulldn=0,
      .altfunc = 1, // convenient i2c
      .lock=0
    };

    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
    gpio_pin_conf(GPIOB, 6,1,&pinconf);
    gpio_pin_conf(GPIOB, 7,1,&pinconf);
    RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
    RCC->APB1RSTR ^= RCC_APB1RSTR_I2C1RST;
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    SystemCoreClockUpdate();
// get sysclk for apb1
    if((RCC->CFGR3 & RCC_CFGR3_I2C1SW) == 0) // RCC_CFGR3_I2C1SW если 1, то от SystemCoreClock
    {
        bus_clk = HSI_VALUE;
    }
    else
    {
        bus_clk = SystemCoreClock;
        if(RCC->CFGR & RCC_CFGR_PPRE_2)
        {
            uint_fast32_t factor = RCC->CFGR & (RCC_CFGR_PPRE_0 | RCC_CFGR_PPRE_1);
            if(factor & RCC_CFGR_PPRE_0) factor |= 1;
            if(factor & RCC_CFGR_PPRE_1) factor |= 2;
            factor &= 3;
            bus_clk >>= factor + 1;
        }
    }
// general scale factor to 8mhz
scale = bus_clk / (HSI_VALUE/2);
scale -= 1;    
scale &= 0x0f;
myI2C->TIMINGR = scale << 28;
// tclk = 250ns refman page 556 - place config from table 100khz
myI2C->TIMINGR |= 0x13 //scll
        |    (0x0f << 8) //sclh
        |    (0x02 << 16) //sdadel
        | (0x04 << 20); //    scldel
//conf i2c
    NVIC_EnableIRQ(I2C1_IRQn);
//set int mask
    myI2C->CR1 = I2C_CR1_ADDRIE
                        | I2C_CR1_RXIE
                          | I2C_CR1_TXIE

                        //|    I2C_CR1_NACKIE
                        |    I2C_CR1_STOPIE
                        |    I2C_CR1_TCIE
                        |    I2C_CR1_ERRIE;
// enable analog noise filtering or digital
//    myI2C->CR1 |= I2C_CR1_ANFOFF;// currently analog
// clock stretch enabled

// set own address
    myI2C->OAR1 = I2C_OAR1_OA1EN | ((get_slave_address() & 0x7F) << 1);
// enable
    myI2C->CR1 |= I2C_CR1_PE;
}


Код
void gpio_pin_conf(
    GPIO_TypeDef *gp,
    uint8_t    num,
    uint8_t    value,
    const struct gpio_configuration *conf)
{
    volatile uint32_t *altreg;
    uint32_t msk2 = 1 << (num*2);
    uint32_t msk4 = 1 << ((num & 0x07)*4);
    num &= 0x0f;
    gp->MODER &= ~(3*msk2);
    if(conf->output) gp->MODER |= msk2;
    if(conf->analog) gp->MODER |= 3*msk2;
    if(conf->alter) gp->MODER |= 2*msk2;

    if(conf->open_drain) gp->OTYPER |= 1 << num;
    else gp->OTYPER &= ~(1 << num);

    gp->OSPEEDR &= ~(3*msk2);
    gp->OSPEEDR |= conf->speed * msk2;

    gp->PUPDR &= ~(3*msk2);
    if(conf->pullup) gp->PUPDR |= msk2;
    if(conf->pulldn) gp->PUPDR |= 2*msk2;

    //set value
    gp->BSRR |= 1 << (num + value?0:16);
    //set af
    altreg = &gp->AFR[(num >= 8)];
    *altreg &= ~(0x0F * msk4);
    *altreg |= conf->altfunc * msk4;
}
Go to the top of the page
 
+Quote Post
gerber
сообщение Oct 6 2016, 11:59
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Как по мне, сбрасывать периферию, не включив её клок, бессмысленно, она "мертва".
Последовательность инициализации несколько напрягает - сначала нужно включать клок, потом инитить и включать периферию, только потом конфигурировать "ноги", и уже в самом конце разрешать от неё прерывания. При нарушении такой последовательности возможны всяки-разны казусы, типа невовремя стрельнувшего прерывания и т. п.
Хотя это всё мелочи и придирки, в общем-то. laughing.gif
Ах, да, ещё I2C Slave не нуждается в делителях клока, это всё нужно только мастеру. Slave работает на том клоке SCL, который приходит от мастера.

Сообщение отредактировал gerber - Oct 6 2016, 12:01


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 12:05
Сообщение #7


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



ну а так в целом- все регистры проинициализированы корректно? Или чего-то забыто?

Цитата(gerber @ Oct 6 2016, 14:59) *
Как по мне, сбрасывать периферию, не включив её клок, бессмысленно, она "мертва".
Последовательность инициализации несколько напрягает - сначала нужно включать клок, потом инитить и включать периферию, только потом конфигурировать "ноги", и уже в самом конце разрешать от неё прерывания. При нарушении такой последовательности возможны всяки-разны казусы, типа невовремя стрельнувшего прерывания и т. п.
Хотя это всё мелочи и придирки, в общем-то. laughing.gif
Ах, да, ещё I2C Slave не нуждается в делителях клока, это всё нужно только мастеру. Slave работает на том клоке SCL, который приходит от мастера.

не понял по включению клока:
Код
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

вот включил клок, только потом дальше начинаю инициализировать регистры. Не так?
Go to the top of the page
 
+Quote Post
gerber
сообщение Oct 6 2016, 12:08
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Цитата(Метценгерштейн @ Oct 6 2016, 15:05) *
ну а так в целом- все регистры проинициализированы корректно? Или чего-то забыто?

В целом, вроде ОК.
Цитата(Метценгерштейн @ Oct 6 2016, 15:05) *
не понял по включению клока:
Код
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

вот включил клок, только потом дальше начинаю инициализировать регистры. Не так?

Это клок GPIOB, имелся в виду клок I2C-контроллера
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
да, его надо включать в самом начале инициализации, даже до сброса периферии, КМК.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 12:16
Сообщение #9


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Код
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
gpio_pin_conf(GPIOB, 6,1,&pinconf);
gpio_pin_conf(GPIOB, 7,1,&pinconf);
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
RCC->APB1RSTR ^= RCC_APB1RSTR_I2C1RST;


так пойдет?

Здесь мы ловим всех блох, которые глючат. Поэтому любое, что режет глаз- будем править.

Насчет делителя для мастера- можно его не трогать? Я понял, что это просто лишнее написано и не применяется, но не мешает слейву моему.
Go to the top of the page
 
+Quote Post
gerber
сообщение Oct 6 2016, 12:25
Сообщение #10


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Цитата(Метценгерштейн @ Oct 6 2016, 15:16) *
так пойдет?

Я бы снес инициализацию ног после инициализации I2C, хотя это и непринципиально, возможно. Дело вкуса, но подключать неинициализированный I2C к реальной шине, а потом его инициализировать, ИМХО, не очень правильно.
Цитата(Метценгерштейн @ Oct 6 2016, 15:16) *
Насчет делителя для мастера- можно его не трогать? Я понял, что это просто лишнее написано и не применяется, но не мешает слейву моему.

Да, это не мешает слейву, просто лишняя операция.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 12:30
Сообщение #11


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Цитата(gerber @ Oct 6 2016, 15:25) *
Я бы снес инициализацию ног после инициализации I2C, хотя это и непринципиально, возможно. Дело вкуса, но подключать неинициализированный I2C к реальной шине, а потом его инициализировать, ИМХО, не очень правильно.


Не очень понял- как предлагаете сделать?
Go to the top of the page
 
+Quote Post
gerber
сообщение Oct 6 2016, 12:38
Сообщение #12


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Цитата(Метценгерштейн @ Oct 6 2016, 15:30) *
Не очень понял- как предлагаете сделать?

myI2C->CR1 |= I2C_CR1_PE;
потом
gpio_pin_conf(GPIOB, 6,1,&pinconf);
gpio_pin_conf(GPIOB, 7,1,&pinconf);
и лишь потом
NVIC_EnableIRQ(I2C1_IRQn);
Но, повторюсь, это всё дело вкуса, и вряд ли решит вопрос стабильности работы I2C.
ИМХО, аппаратный I2C Slave в STM32 пригоден для работы лишь с идеальным I2C-мастером, соблюдающим "километровые" тайминги, и не переключающим SDA вблизи фронтов SCL.
Вблизи - это на расстоянии менее 2-3 мкс.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 12:42
Сообщение #13


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



Можно как-то попросить поделиться драйвером вашим?
Пока что стоит на прогоне плата у меня- ничего не вылетает. Может просто помыл грязь перед этим.
Go to the top of the page
 
+Quote Post
k155la3
сообщение Oct 6 2016, 13:56
Сообщение #14


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

Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848



Цитата(Метценгерштейн @ Oct 6 2016, 11:51) *
STM32 подключен слейвом к другому процу АРМ на Линуксе.
Все работает, но поведение странное. Периодически отваливается шина I2C и мой STM не получает никакие команды из вне. Написана на регистрах инициализация. Подтяжки шины к +3,3 по 7,5 К.
Куда можно смотреть? Может что не проинициализировал в МК?


Подтяжки шины к +3,3 по 7,5 К. - нормальные, но все равно посмотрите осцилграфом форму фронтов (SDA-SCL). Мало ли что могло затянуть.
Захват данных идет по фронту. Если поплыло - на осцилографе будет видно.
На скорости 300 kHz у меня работает нормально на 10к.

В чем проявляется "отваливание" ?

Я свой колхоз с I2C HAL (MSP430) отлаживал с активным использованием лог. анализатора.
Сильно рекомендую.

Ваш проект "slave" - а он, на мой взгляд существенно сложнее master.
Особенно обратите внимание на ACK - NACK квитирование. Если не соотв-ет протоколу I2C и slave отработал не корректно
(по логике протокола) то можно войти в ступор. Например вход в режим "ожидания готовности slave".
А слейв это сделал "не в том смысле", или наоборот, не сделал.

Как альтернативный вариант. Может ошибка в мастере ?






Go to the top of the page
 
+Quote Post
Метценгерштейн
сообщение Oct 6 2016, 14:54
Сообщение #15


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

Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079



на ночь оставлю на прогоне девайс- посмотрим к утру. Правки внес, что gerber предложил. Еще убрал внутреннюю подтяжку программную
Код
.pullup=0, // было 1

0 выставил.

Мастер- это Линукс. Должно быть все отлажено. Проц на линуксе, в смысле.

Посмотрим утром. Отпишусь.
Go to the top of the page
 
+Quote Post

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

 


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


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