Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 зависание при добавлении любой функции
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Neo_Matrix
Имеется плата на stm32f407 камне. Пытаюсь написать функцию парсинга ответов от модема, но при добавлении любой строки в функцию - получаю полное зависание проца. Как отлаживать не могу понять, так как присутствует FreeRTOS.
Собственно сама функция выглядит так:
Код
uint8_t modemresponse(char * data, uint16_t leng)
{
    if(iblanks(Uart3RXBuf, leng))
    {
        return 0;
    }
    else if(memchr(data, '+', leng) && memchr(data, ':', leng))
    {
        return 1;
    }
    else if(strstr(data,"ERROR") != NULL)
    {
        return 2;
    }
    else
    {
        return 3;
    }
}

Если сделать как ниже, то все работает. Тоесть достаточно закоментировать любой из else if или даже else. Если закоментировать один вариант выбора и вместо него в конец функции подставить хотя бы
Код
HAL_UART_Transmit(&huart6,(uint8_t *)"Zavislo\r",8,100);
или все что угодно - опять висяк.
Код
uint8_t modemresponse(char * data, uint16_t leng)
{
    if(iblanks(Uart3RXBuf, leng))
    {
        return 0;
    }
    else if(memchr(data, '+', leng) && memchr(data, ':', leng))
    {
        return 1;
    }
    //else if(strstr(data,"ERROR") != NULL)
    //{
    //    return 2;
    //}
    else
    {
        return 3;
    }
}

Когда то с таким сталкивался и проблема была в размере СТОК\ХЕАП. В данном случае пробовал менять их размер и в FreeRTOS и в Стартап файле, но как узнать какой размер куда прописывать?

Похоже разобрался. Поставил во FreeRTOS вместо heap4 тип heap1.
gazpar
Странно, что работает:

Код
const void * memchr ( const void * ptr, int value, size_t num );
      void * memchr (       void * ptr, int value, size_t num );

const char * strstr ( const char * str1, const char * str2 );
      char * strstr (       char * str1, const char * str2 );


Т.к. функиции возвращают указатели.
А сравнение уже нужно производить другими функциями. Типа:

Код
int strncmp ( const char * str1, const char * str2, size_t num );
Сергей Борщ
Цитата(gazpar @ Feb 18 2016, 03:08) *
Странно, что работает:
Т.к. функиции возвращают указатели.
И нулевой указатель в отдельных случаях. Так что код вполне рабочий.
esaulenka
Цитата(Neo_Matrix @ Feb 18 2016, 00:33) *
Когда то с таким сталкивался и проблема была в размере СТОК\ХЕАП. В данном случае пробовал менять их размер и в FreeRTOS и в Стартап файле, но как узнать какой размер куда прописывать?

Для этого надо вдумчиво прочитать документацию и провести эксперименты.



Цитата(Neo_Matrix @ Feb 18 2016, 00:33) *
Похоже разобрался. Поставил во FreeRTOS вместо heap4 тип heap1.

Маловероятно. Скорее всего, проблема где-то глубже.
Кроме того, heap1 очень ущербный - там в принципе нет free(). С ним можно работать, если у Вас задачи-массивы-проч создаются один раз, статически. Если же пользоваться malloc()/free() при работе, операционка довольно быстро повиснет.
Neo_Matrix
gazpar
Странно, что работает:


void *memchr(const void *buffer, int ch, size_t count);
Эта функция возвращает указатель на первый из символов ch, входящих в массив buffer, или нулевой указатель, если символ ch не найден.


Сама реализация вполне рабочая. И совершенно не важно, что там идет после if (if else), можно хоть сравнение добавить uint8_t a=1; if(a==1); все равно функция виснет.

esaulenka
Глубже копать уже просто некуда(ну или я не вижу).
В конечном счете выяснил, что при всех вариантах heap,кроме heap_4 все работает. Даже на heap_5 работает, а он почти тот же heap_4.
Остановился на heap_2. Маалоков нет. Динамические только очереди и пару задач временами убиваются/создаются.
gazpar
Ок.

Neo_Matrix,
Вы используете прерывания?
Если да, то при настройке оных, какой устанавливаете NVIC_PriorityGroup: 0, 1, 2, 3 или 4?


esaulenka
Цитата(Neo_Matrix @ Feb 18 2016, 11:30) *
Глубже копать уже просто некуда(ну или я не вижу).

Ну, если Вы можете чётко сказать "в задаче А столько-то свободного стека, в задаче Б - столько-то, хипа используется столько-то", в эту сторону копать не стоит.
А пока "я не знаю, переполняется что-то или нет", копать есть куда. И много...


Цитата(Neo_Matrix @ Feb 18 2016, 11:30) *
Остановился на heap_2. Маалоков нет. Динамические только очереди и пару задач временами убиваются/создаются.

Ну так создание/удаление очередей-задач - это чистейший маллок/фрии.
А heap_2 - это плохо. Оно нормально работает только при выделении/удалении элементов одинакового размера.



Ну и было б неплохо вместо "проц виснет" описать "вываливается в hardfault, link-register указывает на функцию ааа(), там у меня происходит ...".
Начинать читать здесь: http://www.freertos.org/Debugging-Hard-Fau...ontrollers.html
Neo_Matrix
gazpar
Настройка прерываний следущая
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
esaulenka
Я увеличивал стек и кучу в 2 раза, это нечего не меняло.
Цитата
Ну так создание/удаление очередей-задач - это чистейший маллок/фрии.

Тут полностью согласен, но у меня размер очередей одинаков, так что должно работать.
Цитата
Ну и было б неплохо вместо "проц виснет" описать "вываливается в hardfault, link-register указывает на функцию ааа()....

Я не могу понять где оно валится в хардфолт, отладка как то странно работает под РТОС, попробую еще с отладкой разобраться(РТОС первый раз использую).
gazpar
В этой РТОС есть специальные службы для определения, что где ломается

Hooks

В обработчики hook'ов можно добавить отладочные сообщения(зажечь какой-то led(или выдать какую-либо последовательность мигания), отправить сообщение в usart и т.п.)

Используется примерно так:
Код
void vApplicationStackOverflowHook( xTaskHandle pxTask,char *pcTaskName )
{
    ( void ) pcTaskName;
    ( void ) pxTask;
    printf("\r\n\r\nStack overflowed by \"%10s\" task\r\n\r\n",pcTaskName);
    
}
Neo_Matrix
Немного добавлю по отладке. Есть задача, которая в цикле запускает вышеуказанную функцию. Собственно вот:
Код
void vTemp(void const * argument)
{
  for(;;)
  {
    uint16_t leng; //Длина строки до знака \n
    uint8_t resp; //Собственно сам ответ 0,1,2,3.....
    if(uart3_not_empty) //Обработчик прерывания устанавливает флаг 1\0
    {
        leng = uart3_readline(); //вычисляем длину строки вместе с \r\n
        sprintf(debug_buff, "leng: %d, line: %s", len, Uart3RXBuf); //формировка данных в соседний порт для отладки(длина строки и сама строка)
        USART_STR(USART6, debug_buff);  //просто отправка данных в соседний порт для отладки
        resp = process_response(uart3_fifo_line,len); // тут вызов глючной функции
        sprintf(debug_buff, "resp: %d \r\n", resp); //формовка
        TM_USART_Puts(USART6, debug_buff); //отправка для отладки
        }
}
}

Как видно в начале происходит проверка на новые данные if(uart3_not_empty), и даже если условие if не выполнено, все равно все висло.
uart3_not_empty инициализируется 0-лем, в прерывании флаг ставится в 1. Зависон просходил даже при условии отсутствия данных на ком порте, но только при условии, что в функции process_response вариантов if(if else) более трех.

Цитата(gazpar @ Feb 18 2016, 12:56) *
В этой РТОС есть специальные службы для определения, что где ломается

О, теперь понятно!!! Спасибо!

Еще добавлю, на сайте РТОС есть такое:
Known Issues with the Current Version
Heap_4.c cannot be used on 8-bit devices (FreeRTOS V8.2.1)
A typo in the calculation of xHeapStructSize means heap_4.c cannot be used to provide the heap when FreeRTOS is being built for an 8-bit microcontroller.
Software timers and FreeRTOS-MPU
The software timer API is not yet included in the official distribution of FreeRTOS/source/include/mpu_wrappers.h.
Может как то связано.....
esaulenka
Цитата(Neo_Matrix @ Feb 18 2016, 14:41) *
Немного добавлю по отладке. Есть задача, которая в цикле запускает вышеуказанную функцию. Собственно вот:

1) Хорошим тоном является наличие не обычного флажка, а семафора. Или очереди.
В этом случае задача не будет крутиться впустую.

2) Также хорошим тоном (а в случае "где-то у меня память течёт" - необходимым средством) является использование snprintf() вместо sprintf(). sprintf() легко и непринуждённо портит память, лежащую сразу после выходного буфера (сколько раз сам на это наступал...).


Цитата(Neo_Matrix @ Feb 18 2016, 14:41) *
Как видно в начале происходит проверка на новые данные if(uart3_not_empty), и даже если условие if не выполнено, все равно все висло.

Ну отлично просто. Но пока мы не увидим, где и что конкретно повисло, результаты разглядывания кофейной гущи будут точнее, чем разглядывание кода.


Цитата(Neo_Matrix @ Feb 18 2016, 14:41) *
О, теперь понятно!!! Спасибо!

Т.е. ссылка в 4-м сообщении - непонятная, а ссылка в 9-м - понятная? Удивительное дело, ведь ведут они в конечном итоге в одно и то же место.
Neo_Matrix
Цитата(esaulenka @ Feb 18 2016, 15:09) *
1) Хорошим тоном является наличие не обычного флажка, а семафора. Или очереди.
В этом случае задача не будет крутиться впустую.
2) Также хорошим тоном (а в случае "где-то у меня память течёт" - необходимым средством) является использование snprintf() вместо sprintf(). sprintf() легко и непринуждённо портит память, лежащую сразу после выходного буфера (сколько раз сам на это наступал...).

Как можно заметить задача именуется vTemp. Это временное решение, созданное для вывода отладки в ЮАРТ. Этой задачи вовсе не должно было быть. Потому с семафорами я не заморачивался.

Цитата(esaulenka @ Feb 18 2016, 15:09) *
Ну отлично просто. Но пока мы не увидим, где и что конкретно повисло, результаты разглядывания кофейной гущи будут точнее, чем разглядывание кода.

Если бы я видел, где повисло уже и сам бы решал проблему. Вечером буду пробовать по добавлять отладки в код РТОСа.

Цитата(esaulenka @ Feb 18 2016, 15:09) *
Т.е. ссылка в 4-м сообщении - непонятная, а ссылка в 9-м - понятная? Удивительное дело, ведь ведут они в конечном итоге в одно и то же место.

Дело вовсе не в ссылке, а в примере который там показан.

esaulenka не нужно так агрессивно относится к заданным вопросам, не все так хорошо знакомы с РТОСом, как Вы. После всего прочитанного, мне стало ясно как отлаживать РТОСом, возможно скоро я и найду причину беды, если нет - перепишу с нуля обработчик прерывания и ф-кцию.
esaulenka
Цитата(Neo_Matrix @ Feb 18 2016, 17:45) *
esaulenka не нужно так агрессивно

Ок. Извините.

У Вас проблема в том, что полностью отсутствуют средства диагностики.
Настоятельно рекомендую разобраться, что такое hardfault, в какие регистры надо при этом смотреть (для начала - скопировать обработчик с сайта freertos, погуглить "hardfault cortex site:electronix.ru -redirect").
Также при работе с RTOS необходимо знание, сколько куда памяти уходит. Во фриртос это почти что встроенная штука (почему-то в heap'е нет диагностики, но это легко поправить).

Без диагностики можно долго "исправлять" методом тыка, и оно опять развалится в самый неподходящий момент...
Neo_Matrix
esaulenka,gazpar
Спасибо за помощь. Уже немного разобрался в отладке.....
Зло было найдено, это была соседняя функция которая в этот момент слала данные в тот же USART TX.
Было так:
Код
HAL_UART_Transmit (&huart3,(uint8_t *)"AT\r",3,100);

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

А так все нормально:
Код
HAL_UART_Transmit_IT(&huart3,(uint8_t *)"AT\r",3);


В цикле отправка без прерывания, а прием по прерываниям работает, под РТОС почему то нет. Или это HAL виноват...
esaulenka
Слово "HAL" я пропустил. Вас ждёт масса удивительных открытий.

Например, отсутствие нормальных семафоров:
Код
#if (USE_RTOS == 1)
  #error " USE_RTOS should be 0 in the current HAL release "
#else
  #define __HAL_LOCK(__HANDLE__)                                           \
                                do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)  \
                                    {                                      \
                                       return HAL_BUSY;                    \
                                    }                                      \
                                    else                                   \
                                    {                                      \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                      \
                                  }while (0)

  #define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                      (__HANDLE__)->Lock = HAL_UNLOCKED;   \
                                    }while (0)
#endif /* USE_RTOS */

В особо неудачном случае оно действительно может повиснуть.

Правда, это старая версия, возможно, за год что-то поменялось...
Код
  * @file    stm32f1xx_hal_def.h
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    15-December-2014


PS повторюсь. Не зная, как и что ломалось, гарантировать "вот теперь-то точно всё будет хорошо" нельзя.
Neo_Matrix
К сожалению не изменилось нечего sad.gif
Кроме:
Код
* @file    stm32f4xx_hal_def.h
  * @author  MCD Application Team
  * @version V1.4.4
  * @date    22-January-2016
  * @brief   This file contains HAL common defines, enumeration, macros and
  *          structures definitions.

Часть кода соответствует Вашей sm.gif

Толком с отладкой я еще не разобрался, но зависало именно в тот момент, когда отправку данных перебивал прием по прерыванию.
ХАЛ конечно зло, но учить ЦМСИС желания нет, да и код какой то сложно читаемый после него. В СПЛ уже достало делать инициализацию, когда то с таймером промучился почти 2 дня. Надеюсь они ХАЛ допилят.
turnon
Цитата(esaulenka @ Feb 18 2016, 17:09) *
2) Также хорошим тоном (а в случае "где-то у меня память течёт" - необходимым средством) является использование snprintf() вместо sprintf(). sprintf() легко и непринуждённо портит память, лежащую сразу после выходного буфера (сколько раз сам на это наступал...).

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