Перейти к содержанию
    

Тээк.. Если прерывание разрешено в таймере (бит Update interrupt flag), плюс не запрещены прерывания в целом (PRIMASK = 0), следовательно дело может быть в запрете в NVIC? Или я еще что-то упускаю?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если прерывание разрешено в таймере (бит Update interrupt flag), плюс не запрещены прерывания в целом (PRIMASK = 0), следовательно дело может быть в запрете в NVIC?

 

 

Нужно вызвать функцию разрешения прерывания в NVIC:

 

NVIC_EnableIRQ(Номер прерывания таймера);

 

 

 

Или я еще что-то упускаю?

 

Тактирование таймера включено? Нужные флаги в статусе устанавливаются?

 

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нужно вызвать функцию разрешения прерывания в NVIC:

 

NVIC_EnableIRQ(Номер прерывания таймера);

 

Тактирование таймера включено? Нужные флаги в статусе устанавливаются?

 

Товарищи, таймер-то включен и NVIC именно так и проинициализирован, и прерывания происходят. КРОМЕ случая зависания в указанном месте CPAL. Более того, если при этом я разорву линию I2C - программа выйдет из этого цикла, т.к. __CPAL_I2C_HAL_GET_BUSY(pDevInitStruct->CPAL_Dev) возвращает 0 - и дальше программа будет продолжать работать хорошо, в смысле, прерывания таймеров возобновятся.

 

Так определите, кто (где, почему) запретил прерывание, если оно не вызывается.

 

Вот я и спрашиваю, если в регистрах таймера все в порядке и не запрещены прерывания - то дело может быть в запрете прерывания в NVIC, либо же еще в чем-нибудь?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

то дело может быть в запрете прерывания в NVIC, либо же еще в чем-нибудь?

Чудес не бывает. Когда снова "зависните" - проанализируйте отладчиком регистры, NVIC в том числе. Может, например, Вы в обработчике прерывания забываете сбрасывать pending бит события таймера или что-то в этом роде.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мастер определяет, сколько читать/писать. Если у ведомого запросить больше, чем он может дать, он выставит NACK.

Я извиняюсь за некропостинг, но это не так.

Если у ведомого запросить больше, он может вообще ничего не делать - посылает подтверждения (или неподтверждения) приёмник, т.е. мастер. В этом случае мы получим много-много FF-ов, если слейв-передатчик отпустит шину вообще. Его дело - правильно подтвердить посылку с собственным адресом, и всё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

OMG.. Извиняюсь, товарищи. Нашел таки косяк )

Датчик читался по таймеру А, а таймауты отслеживались по таймеру В. Хоть приоритет у В был и выше, чем А, они были в одной группе. Установил NVIC_PriorityGroup_2 - все, кажется, Ок. Не учел, что прерывания из одной группы не обрывают друг друга.

 

Спасибо всем за ответы! )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хочу поднять эту тему. Пытаюсь завести I2C через CPAL вместе с freeRTOSом. Подскажите как в cpal_conf.h замутить таймер через vApplicationTickHook(), который у меня отсчитывает миллисекунды.

Я так полагаю это делается В от здесь. Но как правильно это дело задефайнить не догоняю.

/*  -- Section 4 :         **** Configure Timeout method, TimeoutCallback ****

    Description: This section allows you to implement your own Timeout Procedure.
                 By default Timeout procedure is implemented with Systick timer and 
                 CPAL_I2C_TIMEOUT_Manager is defined as SysTick_Handler.
                 */


#define _CPAL_TIMEOUT_INIT()           SysTick_Config((SystemCoreClock / 1000));\
                                                          NVIC_SetPriority (SysTick_IRQn, 0) 
                                       /*<! Configure and enable the systick timer
                                       to generate an interrupt when counter value
                                       reaches 0. In the Systick interrupt handler 
                                       the Timeout Error function is called. Time base is 1 ms */

#define _CPAL_TIMEOUT_DEINIT()         SysTick->CTRL = 0        /*<! Disable the systick timer */ 


#define CPAL_I2C_TIMEOUT_Manager       SysTick_Handler         /*<! This callback is used to handle Timeout error.
                                                                     When a timeout occurs CPAL_TIMEOUT_UserCallback
                                                                     is called to handle this error */
#ifndef CPAL_I2C_TIMEOUT_Manager
   void CPAL_I2C_TIMEOUT_Manager(void);
#else   
   void SysTick_Handler(void);  
#endif /* CPAL_I2C_TIMEOUT_Manager */ 

/*#define CPAL_TIMEOUT_UserCallback        (void)*/                  /*<! Comment this line and implement the callback body in your 
                                                                      application in order to use the Timeout Callback. 
                                                                      It is strongly advised to implement this callback, since it
                                                                      is the only way to manage timeout errors. */

В общем основной вопрос как прикрутить к CPAL свой собственный таймер.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я убрал всю инициализацию таймеров в CPAL (закомментив тело вами показанных макросов)

#define _CPAL_TIMEOUT_INIT()           /*SysTick_Config((SystemCoreClock / 1000));\
                                       NVIC_SetPriority (SysTick_IRQn, 0) */
                                       /*<! Configure and enable the systick timer
                                       to generate an interrupt when counter value
                                       reaches 0. In the Systick interrupt handler 
                                       the Timeout Error function is called. Time base is 1 ms */

#define _CPAL_TIMEOUT_DEINIT()         /*SysTick->CTRL = 0*/        /*<! Disable the systick timer */ 


/*#define CPAL_I2C_TIMEOUT_Manager       SysTick_Handler*/          /*<! This callback is used to handle Timeout error. 
                                                                     When a timeout occurs CPAL_TIMEOUT_UserCallback 
                                                                     is called to handle this error */ 

/*#define CPAL_TIMEOUT_UserCallback        (void)      */            /*<! Comment this line and implement the callback body in your 
                                                                      application in order to use the Timeout Callback. 
                                                                      It is strongly advised to implement this callback, since it
                                                                      is the only way to manage timeout errors. */

и сделал так:

void SysTick_Handler(void)
{
    xPortSysTickHandler();
    CPAL_I2C_TIMEOUT_Manager();
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А ещё такой вопрос, не касающийся CPAL: может ли быть такое что используя стандартную библиотеку STM в режиме Мастер не отпускает линию что бы принять ACK от слэйва после отправки адреса устройства? Просто некоторое время slave нормально отвечал, затем я немного решил порефакторить код и всё сломалось. Вернул на место, всё равно ничего не работает. Смотрю по осцилограмме - слэйв не отправляет ACK. Хотя в его работе вообще ничего меняться не должно было. Выкладываю код:

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

//Инициализация GPIO
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);	

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;	

// SCL пин
GPIO_InitStruct.GPIO_Pin = I2C1_SCL_PIN; 
GPIO_Init(I2C1_SCL_PORT, &GPIO_InitStruct);	 
GPIO_PinAFConfig(I2C1_SCL_PORT, I2C1_SCL_PIN_SOURCE, GPIO_AF_I2C1);	 

// SDA пин	
GPIO_InitStruct.GPIO_Pin = I2C1_SDA_PIN; 
GPIO_Init(I2C1_SDA_PORT, &GPIO_InitStruct);	 
GPIO_PinAFConfig(I2C1_SDA_PORT, I2C1_SDA_PIN_SOURCE, GPIO_AF_I2C1); 

// Конфигурация I2C
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

I2C_Cmd(I2C1, DISABLE); 

I2C_DeInit(I2C1);
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_OwnAddress1 = I2C1_OWN_ADDRESS;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed = I2C_SPEED;
I2C_Init(I2C1, &I2C_InitStruct);	 

// Включение интерфейса
I2C_Cmd(I2C1, ENABLE);

 

чтение регистра

// Проверка готовности линии 
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); 

// Генерация первого старта
I2C_GenerateSTART(I2Cx, ENABLE);

// Проверка что линия свободна
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); 

// Отправка адреса подчинённого устройства (запись)
I2C_Send7bitAddress(I2Cx, slaveAddress, I2C_Direction_Transmitter);

// Проверка ACK от подчинённого устройства (есть ли такой адрес на шине)
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 

// Отправка адреса регистра чтения
I2C_SendData(I2Cx, regAddress);

// Проверка ACK от подчинённого устройства
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); 

// Генерация повторного старта
I2C_GenerateSTART(I2Cx, ENABLE);

// Проверка что линия свободна
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); 

// Отправка адреса подчинённого устройства (чтение)
I2C_Send7bitAddress(I2Cx, slaveAddress, I2C_Direction_Receiver);

// Проверка ACK от подчинённого устройства
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

// Завершаем приём
I2C_AcknowledgeConfig(I2Cx, DISABLE);   

// Проверка что байт принят (данные загружены в регистр DR) 
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)); 

// Генерируем стоп	
I2C_GenerateSTOP(I2C1, ENABLE);	

return I2C_ReceiveData(I2Cx);

 

И после первой отправки адреса устройства ACK я так и не дожидаюсь. Устройство STA381BWS.

 

Добавил к коду сдвиг адреса Slave'а на один бит влево. Ничего не изменилось.

Изменено пользователем Ruslan-maniak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Коллеги, поделитесь опытом

кто как восстанавливает работу I2C (STM32f407)?

После получения status HAL Timeout, иногда наблюдаю выставленный флаг BUSY причем стереть его не представляется возможным.

Передергивание (PE) не помогает.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 minutes ago, BALDA said:

Передергивание (PE) не помогает.

Сброс блока точно поможет. Как-то так:
 

RCC->APB1RSTR |= RCC_APB1RSTR_I2C1_RST;

// wait a few cycles

RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1_RST;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ещё заметил, что сильно уменьшает количество "подвисонов" вот такой сброс перед конфигурированием.

  I2C1->CR1 = I2C_CR1_SWRST;
  I2C1->CR1 = 0;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 hours ago, scifi said:

Сброс блока точно поможет

Как показывает практика, подвиcает не блок микроконтроллера, а один из slave'вов держит линию данных в нуле. Лечится ручным дерганьем клока, или генерацией старт-стопов пока SDA не придет в норму. Но и ресет I2C я тоже в этих случаях добавляю.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я делал так, как рекомендует сам разработчик интерфейса (NXP).

1. При обнаружении зависания линии отменяю транзакции по этой шине.

2. Выключаю модуль I2C, деактивирую и перенастраиваю GPIO на режим ручного управления без изменения типа выходных драйверов.

3. Даю больше 9 стробов по линии SCL.

4. Выключаю синхронизацию модуля I2C.

5. Сбрасываю модуль I2C в регистрах RCC.

6. Заново инициализирую модуль (включение синхронизации, настройка GPIO и т.д.).

Такую последовательность я провожу как при старте ПО, так и в процессе работы девайса при обнаружении заклинивания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...