Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 OTG USB проблема с отладкой
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
Chameleon
Проц STM32F411RE.

Сгенерил в кубе и собрал в кейле пример виртуального ком-порта (CDC класс). Все работает.
Когда пытаюсь добавить в код вывод отладки через UART, все разваливается.

Просто добавляю в начало обработчика OTG_USB_IRQHandler строку

UARTPrint("\r\n---USB_IRQHandler")

и после этого в терминале вижу бесконечно только эту стоку и само устройство перестает определяться.
Скорость UART 115200.

До этого всегда делал отладку по этому принципу и для silabs и для SAM7, никогда она не мешала.
В STM32 USB имеет какие-то критичные тайм-ауты?

---------- Продолжение ---------------------

Через отладчик выяснил, что USB контроллер завален прерываниями. Например код обработки

CODE
/* Handle Connection event Interrupt */
    if(__HAL_PCD_GET_FLAG(hpcd, USB_OTG_GINTSTS_SRQINT))
    {
      HAL_PCD_ConnectCallback(hpcd);
      __HAL_PCD_CLEAR_FLAG(hpcd, USB_OTG_GINTSTS_SRQINT);
    }


Это прерывание сыплется непрерывно.

Дефайн __HAL_PCD_CLEAR_FLAG определен как

CODE
#define __HAL_PCD_CLEAR_FLAG(__HANDLE__, __INTERRUPT__)    (((__HANDLE__)->Instance->GINTSTS) &= (__INTERRUPT__))


Если упростить, получится

CODE
GINTSTS &= 0x40000000;


Но ведь для сброса флага прерывания в него надо записывать "1" ????
Т.е. делать так:
CODE
GINTSTS |= 0x40000000;


И так "сбрасываются" все биты прерываний в регистре GINTSTS.

Как вообще эти примеры оказываются работоспособными???
Forger
Цитата(Chameleon @ Feb 21 2017, 10:35) *
UARTPrint("\r\n---USB_IRQHandler")


Нельзя внутри обработчиков прерываний выполнять такие толстые и медленные функции.
В данном случае эта функция будет выполняться как минимум 2мс, чем затормозит на это время все остальные прерывания, этого достаточно, чтобы USB отвалился.
Из прерывания можно тока по-быстрому просемафорить о чем-то флагами или сервисом rtos, и уже в основном коде (задаче) это выполнять.
Конечно, можно поиграться приоритетами прерываний и разрешить вытесняющие прерывания, но это в данном случае тупик.


Chameleon
QUOTE (Forger @ Feb 21 2017, 15:18) *
Нельзя внутри обработчиков прерываний выполнять такие толстые и медленные функции.
В данном случае эта функция будет выполняться как минимум 2мс, чем затормозит на это время все остальные прерывания, этого достаточно, чтобы USB отвалился.
Из прерывания можно тока по-быстрому просемафорить о чем-то флагами или сервисом rtos, и уже в основном коде (задаче) это выполнять.
Конечно, можно поиграться приоритетами прерываний и разрешить вытесняющие прерывания, но это в данном случае тупик.


А вы ожидали чего-то иного c USB? wink.gif


Всю жизнь отлаживал так инициализацию USB. Даже на скорости 9600. Вроде в стандарт уже заложен допуск таких задержек для отладки.

Прерывание "Подключение" должно сыпаться непрерывно? Или все таки произойти один раз?
Forger
Цитата(Chameleon @ Feb 21 2017, 15:28) *
Прерывание "Подключение" должно сыпаться непрерывно? Или все таки произойти один раз?

Если нарушить логику подключения тормозами в других прерываниях, то иного ожидать не приходится ))

А как выглядит внутри этот самый UARTPrint?
Chameleon
QUOTE (Forger @ Feb 21 2017, 15:30) *
Если нарушить логику подключения тормозами в других прерываниях, то иного ожидать не приходится ))

А как выглядит внутри этот самый UARTPrint?


Прерывания включены только для USB.

CODE
void UARTPrint(char *s)
{
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}
Forger
Цитата(Chameleon @ Feb 21 2017, 15:37) *
Прерывания включены только для USB.

Это не меняет дела:

Цитата
Код
while((USART1->SR & USART_SR_TXE) == 0);
USART1->DR = *s++;
if (*s == 0) break;

Все ясно, на скорости 9600 эта функция будет выполняться еще дольше ... (в 12 раз дольше, чем на 115200)
Тупо висим в прерывании, пока не отправится вся строка - как у вас с такой "отладкой" вообще что-то работает?!

Если проект без вашей "отладки" нормально работает, то переделывайте отладку на нормальную или откажитесь вовсе от такого метода отладки.
aaarrr
Цитата(Forger @ Feb 21 2017, 15:45) *
Все ясно, на скорости 9600 эта функция будет выполняться еще дольше ... (в 12 раз дольше, чем на 115200)
Тупо висим в прерывании, пока не отправится вся строка - как у вас с такой "отладкой" вообще что-то работает?!

Должно работать. Причина не в "тормозах" отладочной печати.

Надо разбираться, почему прерывание от USB постоянно активно.
Chameleon
QUOTE (Forger @ Feb 21 2017, 15:45) *
Это не меняет дела:


Все ясно, на скорости 9600 эта функция будет выполняться еще дольше ... (в 12 раз дольше, чем на 115200)
Тупо висим в прерывании, пока не отправится вся строка - как у вас с такой "отладкой" вообще что-то работает?!

Если проект без вашей "отладки" нормально работает, то переделывайте отладку на нормальную или откажитесь вовсе от такого метода отладки.


Отладка на 115200. 9600 я для примера написал. Время на обработку пакета по стандарту допускается до 50мс без передачи данных и до 500 мс с передачей данных. 50 мс это 500 символов на скорости 115200. Страница текста.

Я всегда использовал такую отладку для юсб. Для Silabs, SAM7, NXP. Не было никаких проблем. Один STM32 долбанутый какой-то.
Forger
Цитата(Chameleon @ Feb 21 2017, 15:55) *
Я всегда использовал такую отладку для юсб. Для Silabs, SAM7, NXP. Не было никаких проблем. Один STM32 долбанутый какой-то.

А без вашей "отладки" этот же пример работает нормально?
jcxz
Цитата(Forger @ Feb 21 2017, 18:18) *
Нельзя внутри обработчиков прерываний выполнять такие толстые и медленные функции.
В данном случае эта функция будет выполняться как минимум 2мс,

А как Вы определили что находится у ТС внутри этого самого UARTPrint()?
Да ещё и удалённо определили время её выполнения даже не зная что внутри! Поделитесь секретами мастерства!!! Думаю всем тут будет любопытно biggrin.gif
И вообще - странно как это она может выполняться целых 2мс на Cortex с тактовой в десятки МГц если внутри неё например просто копируется указанная строка в буфер символов???
Или даже просто не строка, а сам указатель.

PS: Я подобные отладочные функции вставлял в ISR работающие на частотах в десятки кГц - и всё прекрасно работало. Да - конечно правда без куба wink.gif
Chameleon
QUOTE (Forger @ Feb 21 2017, 16:06) *
А без вашей "отладки" этот же пример работает нормально?


Без отладки - да, нормально.

Добавляю в начало обработчика прерывания код, просто задержка от балды.

CODE
{
   volatile uint32_t x;
   for (x = 0; x < 2000000; x++);
}


Устройство определяется через 5 секунд после подключения, но ОПРЕДЕЛЯЕТСЯ.

Заменяю эту задержку на

CODE
    UARTPrint("\r\n-IRQ");

Все, ничего не работает.
Такое впечатление, что UART и USB какие-то ресурсы поделить не могут.
jcxz
Цитата(Chameleon @ Feb 21 2017, 19:15) *
UARTPrint("\r\n-IRQ");

Вы телепатов ищете? Приведите код этой самой UARTPrint().
А то тут только один телепат пока нашёлся....
Chameleon
QUOTE (jcxz @ Feb 21 2017, 16:18) *
Вы телепатов ищете? Приведите код этой самой UARTPrint().
А то тут только один телепат пока нашёлся....


См. Post #5 выше.
Forger
Цитата(jcxz @ Feb 21 2017, 16:12) *
А как Вы определили что находится у ТС внутри этого самого UARTPrint()?
Да ещё и удалённо определили время её выполнения даже не зная что внутри! Поделитесь секретами мастерства!!!

Богатый жизненный опыт и умение пользоваться калькулятором wink.gif



Цитата(Chameleon @ Feb 21 2017, 16:15) *
Такое впечатление, что UART и USB какие-то ресурсы поделить не могут.

Если подряд поставить два-три вызова этой функции, они все вызываются?
Chameleon
QUOTE (Forger @ Feb 21 2017, 16:32) *
Богатый жизненный опыт и умение пользоваться калькулятором wink.gif




Если подряд поставить два-три вызова этой функции, они все вызываются?


Вроде как нет... Такое впечатление, что обработчик вызывает сам себя.
У кортекса есть вложенные прерывания? Надо их запрещать? Может вызваться новое прерывание, пока не завершилость предыдущее?


Forger
Цитата(Chameleon @ Feb 21 2017, 16:40) *
У кортекса есть вложенные прерывания? Надо их запрещать? Может вызваться новое прерывание, пока не завершилость предыдущее?

Если разрешено соотв. прерывание от USART, то в данном случае может произойти все что угодно.
Покажите вашу инициализацию USART.

И все же не помешает по-курить базовую матчасть по кортексам и его NVIC sm.gif
Chameleon
QUOTE (Forger @ Feb 21 2017, 16:43) *
Если разрешено соотв. прерывание от USART, то в данном случае может произойти все что угодно.
Покажите вашу инициализацию USART.

И все же не помешает по-курить базовую матчасть по кортексам и его NVIC sm.gif


USART кубом настроен, прерывания выключены, я там ничего не трогал.
Forger
Цитата(Chameleon @ Feb 21 2017, 16:52) *
USART кубом настроен, прерывания выключены, я там ничего не трогал.

Нужно, точно локализовать источник косяка. Пока что все упирается в вашу функцию. Копайте в этом направлении.
Например, подряд в основном коде вызвать ее несколько раз или более радикально - гонять в бесконечном цикле, но не в прерываниях.
A.Lex
Цитата(Chameleon @ Feb 21 2017, 15:52) *
USART кубом настроен, прерывания выключены, я там ничего не трогал.

А включить USART не забыли?
Chameleon
QUOTE (Forger @ Feb 21 2017, 16:43) *
Если разрешено соотв. прерывание от USART, то в данном случае может произойти все что угодно.
Покажите вашу инициализацию USART.

И все же не помешает по-курить базовую матчасть по кортексам и его NVIC sm.gif


На sam4s код юсб от sam7 завелся с пол-оборота. Тот же кортекс. И такая же отладка была.

Весь код инициализации прерываний

CODE
NVIC_ClearPendingIRQ((IRQn_Type) ID_UDP);
NVIC_SetPriority((IRQn_Type) ID_UDP, 0);
NVIC_EnableIRQ((IRQn_Type) ID_UDP);


Что тут курить-то?
Forger
Цитата(Chameleon @ Feb 21 2017, 17:18) *
На sam4s код юсб от sam7 завелся с пол-оборота. Тот же кортекс. И такая же отладка была.

А тогда чего вы полезли на STM32, коли на sam4s все "заводится с пол-оборота"? wink.gif

Цитата
Весь код инициализации прерываний
Код
NVIC_ClearPendingIRQ((IRQn_Type) ID_UDP);
NVIC_SetPriority((IRQn_Type) ID_UDP, 0);
NVIC_EnableIRQ((IRQn_Type) ID_UDP);

А что такое ID_UDP?

И покажите наконец-то код инициализации USART.

Цитата
Что тут курить-то?


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


Chameleon
А тогда чего вы полезли на STM32, коли на sam4s все "заводится с пол-оборота"? wink.gif

Потому что sam4s не толерантный к 5 вольтам. И труднопокупаемый. А STM32 как грязи на любом развале.

А что такое ID_UDP?


UDP = USB Device port

И покажите наконец-то код инициализации USART.

CODE
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}

/**
* @brief Initializes the UART mode according to the specified parameters in
* the UART_InitTypeDef and create the associated handle.
* @param huart: pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if(huart == NULL)
{
return HAL_ERROR;
}

/* Check the parameters */
if(huart->Init.HwFlowCtl != UART_HWCONTROL_NONE)
{
/* The hardware flow control is available only for USART1, USART2, USART3 and USART6 */
assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance));
assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));
}
else
{
assert_param(IS_UART_INSTANCE(huart->Instance));
}
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));

if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_UART_MspInit(huart);
}

huart->gState = HAL_UART_STATE_BUSY;

/* Disable the peripheral */
__HAL_UART_DISABLE(huart);

/* Set the UART Communication parameters */
UART_SetConfig(huart);

/* In asynchronous mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));

/* Enable the peripheral */
__HAL_UART_ENABLE(huart);

/* Initialize the UART state */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState= HAL_UART_STATE_READY;
huart->RxState= HAL_UART_STATE_READY;

return HAL_OK;
}

/**
* @brief Initializes the half-duplex mode according to the specified
* parameters in the UART_InitTypeDef and create the associated handle.
* @param huart: pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if(huart == NULL)
{
return HAL_ERROR;
}

/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));

if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_UART_MspInit(huart);
}

huart->gState = HAL_UART_STATE_BUSY;

/* Disable the peripheral */
__HAL_UART_DISABLE(huart);

/* Set the UART Communication parameters */
UART_SetConfig(huart);

/* In half-duplex mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_IREN | USART_CR3_SCEN));

/* Enable the Half-Duplex mode by setting the HDSEL bit in the CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_HDSEL);

/* Enable the peripheral */
__HAL_UART_ENABLE(huart);

/* Initialize the UART state*/
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState= HAL_UART_STATE_READY;
huart->RxState= HAL_UART_STATE_READY;

return HAL_OK;
}


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


Я не собираюсь их там оставлять. После отладки кода все они удаляются.
Forger
Цитата(Chameleon @ Feb 21 2017, 17:49) *
А STM32 как грязи на любом развале.

В таком случае все же придется изучать матчасть и иногда копаться в даташитах )))


Цитата
Посмотрите наконец-то post #5 на первой странице.

Там нет кода инициализации USART. Вы вообще понимаете смысл слова "инициализация"?
Короче, покажите код, где USART настраивается на роботу, где настраиваются его регистры и т.п.


Цитата
Я не собираюсь их там оставлять. После отладки кода все они удаляются.

Отладочный код (DEBUG) должен работать практически одинаково с финальным (RELEASE). В крайнем случае он как минимум должен хотя бы работать, в обоих случаях wink.gif
Я лишь предостерег от граблей, на которые сам наступал в свое время.
Кстати, нет никакой нужды удалять отладочный код, для этого есть встроенный в любой компилятор препроцессор (#ifdef #endif и т. п.)
Chameleon

В таком случае все же придется изучать матчасть и иногда копаться в даташитах )))



Там нет кода инициализации USART. Вы вообще понимаете смысл слова "инициализация"?
Короче, покажите код, где USART настраивается на роботу, где настраиваются его регистры и т.п.


Исправил.

Отладочный код (DEBUG) должен работать практически одинаково с финальным (RELEASE). В крайнем случае он как минимум должен хотя бы работать, в обоих случаях wink.gif
Я лишь предостерег от граблей, на которые сам наступал в свое время.
Кстати, нет никакой нужды удалять отладочный код, для этого есть встроенный в любой компилятор препроцессор (#ifdef #endif и т. п.)



Препроцессор - зло. Он не нужен.
Forger
Цитата(Chameleon @ Feb 21 2017, 17:49) *
Код
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }


Коли вы используете HAL в инициализации USART, то советую и в других функциях по работе с USART использовать HAL.
Рекомендую посмотреть в сторону HAL_UART_Transmit

Кстати, вызов этой вашей толстой функции происходит только в одном месте или раскидан по всему проекту?
Если это так, то срочно переписывайте вашу функцию-самодеятельность под HAL полностью (подробности см. в реализации HAL_UART_Transmit).



Цитата(Chameleon @ Feb 21 2017, 18:08) *
Препроцессор - зло. Он не нужен.


Это кто ж такой умный сказал вам такую абсолютную глупость? cranky.gif
#define - это тоже препроцессор, неужели ваша религия не позволяет им тоже пользоваться? sm.gif
Chameleon
QUOTE (Forger @ Feb 21 2017, 18:13) *
Коли вы используете HAL в инициализации USART, то советую и в других функциях по работе с USART использовать HAL.
Рекомендую посмотреть в сторону HAL_UART_Transmit

Кстати, вызов этой вашей толстой функции происходит только в одном месте или раскидан по всему проекту?
Если это так, то срочно переписывайте вашу функцию-самодеятельность под HAL полностью (подробности см. в реализации HAL_UART_Transmit).

Это кто ж такой умный сказал вам такую абсолютную глупость? cranky.gif


Я в первую очередь пробовал через HAL_UART_Transmit, нет разницы. Вызовы только в обработчике USB_OTG_Handler. Но я пробовал оставлять только единственный вызов в начале обработчика. Тоже не работает.

Препроцессор зло, это аксиома. Не требует доказательств.
Forger
Цитата(Chameleon @ Feb 21 2017, 18:21) *
Я в первую очередь пробовал через HAL_UART_Transmit, нет разницы.

В основном коде ВНЕ прерываний эта функция работает? В бесконечном цикле.

В любом случае подобные функции не должны работать таким образом, как у вас.
Правильно так: кидать байты строки в некую программную очередь и разрешать передачу, заранее настроив прерывания от USART.
Можно даже извратиться на DMA, но это уже детали, не относящиеся к делу...

Цитата
Препроцессор зло, это аксиома. Не требует доказательств.
Весьма сочувствую вашему "вероисповеданию" ... crying.gif
Тонны "магических цифр" по коду - это самый страшный кошмар любого программиста.
Поэтому мне всегда грустно видеть, как некоторые "программисты" этот кошмар сознательно воплощают в своей реальности, отказываясь даже от безобидных #define ....

Короче, сначала в пустом проекте отладьте нормально работу этой вашей "отладочной" функции и уже потом суйте ее куда планировали.
В противном случае все это - бесконечный пинг-понг ...
jcxz
Цитата(Chameleon @ Feb 21 2017, 19:21) *
См. Post #5 выше.

Ну естественно так делать нельзя. Вызов не должен быть блокирующим.
Chameleon
В основном коде ВНЕ прерываний эта функция работает? В бесконечном цикле.

Да.

В любом случае подобные функции не должны работать таким образом, как у вас.
Правильно так: кидать байты строки в некую программную очередь и разрешать передачу, заранее настроив прерывания от USART.

Так и делаю сейчас.

Можно даже извратиться на DMA, но это уже детали, не относящиеся к делу...

Весьма сочувствую вашему "вероисповеданию" ... crying.gif
Тонны "магических цифр" по коду - это самый страшный кошмар любого программиста.
Поэтому мне всегда грустно видеть, как некоторые "программисты" этот кошмар сознательно воплощают в своей реальности, отказываясь даже от безобидных #define ....

#define - > #define -> #define .. еще раз десять вложенных #define и в конце a = 5;
Это конечно лучше.
Про малоуловимые глюки в макросах и смысла нет говорить.
А уж условная компиляция так помогает понять логику работы...



jcxz
Цитата(Forger @ Feb 21 2017, 21:13) *
Кстати, вызов этой вашей толстой функции происходит только в одном месте или раскидан по всему проекту?
Если это так, то срочно переписывайте вашу функцию-самодеятельность под HAL полностью (подробности см. в реализации HAL_UART_Transmit).

Если человек вызывает такие функции (как в 5-м посте) из ISR ничтоже сумняшеся, то и в остальном коде он мог наделать очевидных глупостей.
Например вызывать этот UARTPrint() из ISR и из фоновой задачи без блокировок.
Переписывание этого под гал или чего-то другое ничего не даст. Если нет понимания как всё в сумме оно работает.....

ЗЫ: теме место - в "помощи начинающему".
Chameleon
QUOTE (jcxz @ Feb 21 2017, 18:49) *
Если человек вызывает такие функции (как в 5-м посте) из ISR ничтоже сумняшеся, то и в остальном коде он мог наделать очевидных глупостей.
Например вызывать этот UARTPrint() из ISR и из фоновой задачи без блокировок.
Переписывание этого под гал или чего-то другое ничего не даст. Если нет понимания как всё в сумме оно работает.....

ЗЫ: теме место - в "помощи начинающему".


Forger
Цитата(Chameleon @ Feb 21 2017, 18:46) *
Про малоуловимые глюки в макросах и смысла нет говорить.
А уж условная компиляция так помогает понять логику работы...

Ну, судя по тому, как вы спотыкаетесь на примитивной функции и можно сказать на ровном месте, то действительно вам не стоит пользоваться ни препроцессором ни чем-то еще более функциональным smile3046.gif
Пожалуй, очень правильно, что вам кто-то строго настрого запретил пользоваться препроцессором, внушив, что, якобы, это злейшее зло.... Пусть уж лучше так biggrin.gif

Цитата(jcxz @ Feb 21 2017, 18:49) *
Переписывание этого под гал или чего-то другое ничего не даст. Если нет понимания как всё в сумме оно работает.....
ЗЫ: теме место - в "помощи начинающему".

Трудно не согласиться sm.gif
Chameleon
Чем дальше в лес, тем толще партизаны.

Сделал отладочный вывод в массив в озу и затем из него в UART.
Устройство подключается и определяестя.
Но когда начинается вывод через UART, устройство отваливается.
Через отладчик выяснил, что процессор падает в HardFault.

Падает на этой функции:

CODE
void up(void)
{
    volatile char *s = mem;
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}

mem - это массив с данными.

Если в отладчике зайти в эту фунцию и вручную шагать, то все работает. Если же сделать Step Over - HardFault.

Проект сгенерирован кубом. Он же правильно все тайминги выставляет? Задержка доступа к FLASH, частоты шин APB, AHB?
Forger
Цитата(Forger @ Feb 21 2017, 18:31) *
Правильно так: кидать байты строки в некую программную очередь и разрешать передачу, заранее настроив прерывания от USART.


Цитата( @ Feb 22 2017, 07:53) *
Так и делаю сейчас.

Покажите код, где вы это делаете.
Chameleon
QUOTE (Forger @ Feb 22 2017, 08:50) *
Покажите код, где вы это делаете.


CODE
static char mem[16384];
static volatile uint32_t p;


void up(void)
{
    HAL_UART_Transmit(&huart1,(uint8_t *)mem,strlen(mem),100);
}

void dbgInit(void)
{
    memset(mem,0,16384);
    p = 0;
}

void UARTPrint(char *s)
{
    volatile uint32_t x;
    if(p > 16000) return;
  for(;;)
  {
        mem[p++] = *s++;
        if(*s == 0) break;
  }
}


в main:

dbgInit();
MX_USB_DEVICE_Init();

... задержка

up();

внутри перывания USB в самом начале

UARTPrint("\r\m-----IRQ");
Forger
Я имел ввиду другое, гораздо более грамотное решение, связанное с обработчиком прерываний от USART, ну, да бог с ним, суть не в этом.
Короче, этот код работает или виснет в некой up()?
Chameleon
QUOTE (Forger @ Feb 22 2017, 09:49) *
Я имел ввиду другое, гораздо более грамотное решение, связанное с обработчиком прерываний от USART, ну, да бог с ним, суть не в этом.
Короче, этот код работает или виснет в некой up()?


Падает на этой функции:

CODE
void up(void)
{
    volatile char *s = mem;
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}

mem - это массив с данными.

Если в отладчике зайти в эту фунцию и вручную шагать, то все работает. Если же сделать Step Over - HardFault.
Forger
Цитата(Chameleon @ Feb 22 2017, 11:18) *
Падает на этой функции:
Код
void up(void)
{
    volatile char *s = mem;
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}

Мля, я не про эту несчастную кривую функцию, которая не предназначенная для использования в прерываниях в принципе!
Я про тот набор текста, который приведен в посте #35. Оно работает как вам нужно или тоже типит?
Chameleon
QUOTE (Forger @ Feb 22 2017, 11:27) *
Мля, я не про эту несчастную кривую функцию, которая не предназначенная для использования в прерываниях в принципе!
Я про тот набор текста, который приведен в посте #35. Оно работает как вам нужно или тоже типит?


Падает на up().
esaulenka
Цитата(Chameleon @ Feb 21 2017, 10:35) *
Дефайн __HAL_PCD_CLEAR_FLAG определен как
Код
GINTSTS &= 0x40000000;

Но ведь для сброса флага прерывания в него надо записывать "1" ????
Т.е. делать так:
Код
GINTSTS |= 0x40000000;


Вообще говоря, этот код работает.
В это место вы попадаете с установленным 30-м битом; он ещё раз умножается на 30-й бит и записывается обратно.
Вариант
Код
GINTSTS |= 0x40000000;

неправильный, он лишние флажки поскидывает.
Простой и понятный вариант
Код
GINTSTS = 0x40000000;

но для индусов это слишком просто.

По делу не помогу. Я это нагромождение дефайнов и абстракций не осилил. Заметно лучше, чем SPL, но для прикручивания своего протокола понадобилось бы переписать половину этой "библиотеки". Плюнул, взял libopencm3 - там тоже переписывать надо, но хотя бы структура прозрачная.

Цитата(Forger @ Feb 22 2017, 11:27) *
Мля, я не про эту несчастную кривую функцию, которая не предназначенная для использования в прерываниях в принципе!


У меня вопрос. Где граница, при превышении которой этот самый-лучший-в-мире стек упадёт нафиг? Убираем несчастную кривую функцию, добавляем два высокоприоритетных прерывания. Будет работать? Увеличиваем частоту прерываний на порядок. Будет работать?

Стандартом заложено, что интерфейс может "подтормаживать". А библиотекописатели это не проверяли, у них в случае торможений всё вообще раком встаёт. Это проблема библиотеки, разве не так?
uriy
Вероятно надо использовать HAL_UART_Transmit_IT или HAL_UART_Transmit_DMA для передачи по прерываниям или по DMA.
HAL_UART_Transmit передает по поллингу, эта функция блокирующая на все время передачи.
Forger
Цитата(esaulenka @ Feb 22 2017, 11:43) *
Код
GINTSTS = 0x40000000;

но для индусов это слишком просто.
Так было сделано в одной из старых версий HAL, а щас стоит "&=". Видать, есть на то причины ...
Полагаю, что дело в разных особенностях работы разных битов в одном и том же регистре. В нюансы не вникал, но других причин не вижу.


Цитата
По делу не помогу. Я это нагромождение дефайнов и абстракций не осилил.

Не надо читать и вникать в эту кучу кода, достаточно лишь один раз скомпилировать в одну либу и подключить к проекту вместе с H-файлами.
Не забыть про ключик компиляции, при котором каждая функция кладется в свою ELF-секцию, так в финальную прошивку попадут только те функции, которые используются, а не целиком соотв. С-файл.

Цитата
У меня вопрос. Где граница, при превышении которой этот самый-лучший-в-мире стек упадёт нафиг? Убираем несчастную кривую функцию, добавляем два высокоприоритетных прерывания. Будет работать? Увеличиваем частоту прерываний на порядок. Будет работать?

Речь тут не про HAL/CUBE и т. п, а про совсем другое - про банальное нарушение базового правила кода под МК: заходить в прерывания можно только для того, чтобы "отметиться" и что-то просемафорить наружу в основной код.
А число-дробилки и циклы ожидания выносятся наружу в основной код. Иначе жди беды!




Цитата(uriy @ Feb 22 2017, 11:59) *
Вероятно надо использовать HAL_UART_Transmit_IT или HAL_UART_Transmit_DMA для передачи по прерываниям или по DMA.
HAL_UART_Transmit передает по поллингу, эта функция блокирующая на все время передачи.

Дык, с самого начала этой темы тока об этом и говорю, но что-то очень туго это доходит 1111493779.gif


Цитата(Chameleon @ Feb 22 2017, 11:33) *
Падает на up().

Вижу простое решение: отладить это чудо-код на ПУСТОМ проекте, добиться от него стабильной работы в разных ситуациях (банально тесты), и уже только после этого куда-то сувать.

Но я лично воспользовался бы уже готовым решением, которое не требует наличия UART и т.п.
Для этого достаточно уже существующего SWD или JTAG: https://electronix.ru/forum/index.php?s=&am...t&p=1482569
Таких тормозов нет и в помине. Работает как раз с полпинка, но обладает в сотни раз бОльшим функционалом. Бесплатно, исходники открыты.

Но коли нравиться изобретать велосипед, то конечно же продолжайте в том же духе:
Код
void UARTPrint(char *s)
{
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}


rolleyes.gif
Chameleon
QUOTE (Forger @ Feb 22 2017, 12:11) *
Вижу простое решение: отладить это чудо-код на ПУСТОМ проекте, добиться от него стабильной работы в разных ситуациях (банально тесты), и уже только после этого куда-то сувать.


Спасибо, КЭП.

Вы что, не понимаете, что это и есть ПУСТОЙ ПРОЕКТ. Только USB и UART. Что я и пытаюсь добиться стабильной работы в разных ситуациях? Да, да, передача строки по поллингу и есть СИТУАЦИЯ. И они должны работать вместе в любых комбинациях?

QUOTE (Forger @ Feb 22 2017, 12:11) *
Но я лично воспользовался бы уже готовым решением, которое не требует наличия UART и т.п.
Для этого достаточно уже существующего SWD или JTAG: https://electronix.ru/forum/index.php?s=&am...t&p=1482569
Таких тормозов нет и в помине. Работает как раз с полпинка, но обладает в сотни раз бОльшим функционалом. Бесплатно, исходники открыты.

Но коли нравиться изобретать велосипед, то продолжайте в том же духе:
CODE
void UARTPrint(char *s)
{
    for(;;)
    {
        while((USART1->SR & USART_SR_TXE) == 0);
        USART1->DR = *s++;
        if (*s == 0) break;
    }
}


rolleyes.gif


Отличный совет - не получается? Как нибудь придумай обход. Прилепи костыль. Авось по другому прокатит.

Forger
Цитата(Chameleon @ Feb 22 2017, 12:20) *
Спасибо, КЭП.

Вы что, не понимаете, что это и есть ПУСТОЙ ПРОЕКТ. Только USB и UART.

А что делает тут USB?
Короче, ПУСТОЙ НОВЫЙ проект только для того, чтобы отладить ваши несчастные костыльные функции.
Добейтесь тут от них нормальной работы в ПУСТОМ проекте. Поиграйтесь с размером стека (например).
В конце концов, сделайте нормальный функционал БЕЗ поллинга!

Цитата
Что я и пытаюсь добиться стабильной работы в разных ситуациях? Да, да, передача строки по поллингу и есть СИТУАЦИЯ. И они должны работать вместе в любых комбинациях?

Я не пойму, чего вы хотите добиться? Чтобы проект был сделан сразу нормально и без костылей или, просто, хотите что-то доказать себе или кому-то?

Цитата
Отличный совет - не получается? Как нибудь придумай обход. Прилепи костыль. Авось по другому прокатит.

Костыль - это как раз ваша самодеятельная чудо-функция, использующая поллинг в прерывании.
Я же говорю про готовое решение, которое отлажено за вас и отлично работает как раз с полпинка, благодаря наличию документации и тому, что это написано профессионалами, а не любителями-изобретателями.
Если не хотите или не можете освоить готовые решения, так пользуйтесь и далее своими чудо-функциями, которая как вы говорите, "с полпинка работает на sam4s" и т. п.

Короче, далее бейтесь о стену уже без моей помощи - все, чем я мог помочь, тут уже прозвучало и неоднократно и не только от меня. Удачи wink.gif
Chameleon
QUOTE (Forger @ Feb 22 2017, 12:38) *
А что делает тут USB?
Короче, ПУСТОЙ НОВЫЙ проект только для того, чтобы отладить ваши несчастные костыльные функции.
Добейтесь тут от них нормальной работы в ПУСТОМ проекте. Поиграйтесь с размером стека (например).
В конце концов, сделайте нормальный функционал БЕЗ поллинга!


Я не пойму, чего вы хотите добиться? Чтобы проект был сделан сразу нормально и без костылей или, просто, хотите что-то доказать себе или кому-то?


Костыль - это как раз ваша самодеятельная чудо-функция, использующая поллинг в прерывании.
Я же говорю про готовое решение, которое отлажено за вас и отлично работает как раз с полпинка, благодаря наличию документации и тому, что это написано профессионалами, а не любителями-изобретателями.
Если не хотите или не можете освоить готовые решения, так пользуйтесь и далее своими чудо-функциями, которая как вы говорите, "с полпинка работает на sam4s" и т. п.

Короче, далее бейтесь о стену уже без моей помощи - все, чем я мог помочь, тут уже прозвучало и неоднократно и не только от меня. Удачи wink.gif


Вы вообще читаете, что я пишу? Какая от вас может быть помощь, если вы помните только то что было написано на первой странице поста?
Forger
Цитата(Chameleon @ Feb 22 2017, 12:52) *
Вы вообще читаете, что я пишу?

Мне лишь одного этого хватило:
Цитата(Chameleon @ Feb 21 2017, 18:08) *
Препроцессор - зло. Он не нужен.

Это позволяет лишний раз убедиться, что:
Цитата(Chameleon @ Feb 22 2017, 07:53) *
Чем дальше в лес, тем толще партизаны.


.
jcxz
Цитата(Chameleon @ Feb 22 2017, 10:53) *
Через отладчик выяснил, что процессор падает в HardFault.
Падает на этой функции:

HardFault - это ни о чём не говорит.
Возможно там у Вас UsageFault или MemFault или BusFault или ещё какой, а потом происходит эскалация до HardFault, так как у Вас и механизм исключений конечно не прописан и не инициализирован.
Изучайте документацию на ядро в части исключений. У Cortex-M есть куча регистров, по которым можно определить конкретный тип и причину fault-а. И тогда легко будет найти ошибку.
Forger
Цитата(jcxz @ Feb 22 2017, 13:53) *
И тогда легко будет найти ошибку.

lol.gif
esaulenka
Цитата(Forger @ Feb 22 2017, 12:11) *
Не надо читать и вникать в эту кучу кода, достаточно лишь один раз скомпилировать в одну либу и подключить к проекту вместе с H-файлами.
Не забыть про ключик компиляции, при котором каждая функция кладется в свою ELF-секцию, так в финальную прошивку попадут только те функции, которые используются, а не целиком соотв. С-файл.

Классно. Рад за вас, что у вас всё всегда работает.
Почему-то мой код надо отлаживать, а не просто написать и нажать кнопочку "build". И в процессе отладки очень хочется минимизировать количество "чёрных ящиков".


Цитата(Forger @ Feb 22 2017, 12:11) *
Речь тут не про HAL/CUBE и т. п, а про совсем другое - про банальное нарушение базового правила кода под МК: заходить в прерывания можно только для того, чтобы "отметиться" и что-то просемафорить наружу в основной код.
А число-дробилки и циклы ожидания выносятся наружу в основной код. Иначе жди беды!

То-то у кортексов настолько развесистый NVIC, что им с лёгкостью можно заменить простенькую операционку.

Ну я основную идею понял. "у меня всё работает, а шаг вправо, шаг влево - это сам дурак". Спасибо за мнение.
Forger
Цитата(esaulenka @ Feb 22 2017, 14:07) *
Почему-то мой код надо отлаживать, а не просто написать и нажать кнопочку "build".

Как раз в данном случае именно так и должен работать такой примитивный код.

Цитата
И в процессе отладки очень хочется минимизировать количество "чёрных ящиков".

БИНГО! Начинает доходить! Вот почему я уже трижды написал "создать ПУСТОЙ ПРОЕКТ" !!!

Цитата
То-то у кортексов настолько развесистый NVIC, что им с лёгкостью можно заменить простенькую операционку.

Ну-ну, а спотыкаемся уже на детских грабельках smile3046.gif

Цитата
Ну я основную идею понял.

Основная идея как раз совсем в другом:
1) чуть назад отойти от стены, в которую уперся как ...,
2) глянуть на нее издали,
3) найти в ней дверь,
4) подойти, открыть
5) и наконец-то двигаться дальше.

Самые простые решения чаще всего лежат прямо перед носом.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.