Jump to content

    
Sign in to follow this  
Neo_Matrix

STM32 зависание при добавлении любой функции

Recommended Posts

Имеется плата на 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.

Edited by Neo_Matrix

Share this post


Link to post
Share on other sites

Странно, что работает:

 

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 );

Share this post


Link to post
Share on other sites
Странно, что работает:

Т.к. функиции возвращают указатели.

И нулевой указатель в отдельных случаях. Так что код вполне рабочий.

 

Share this post


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

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

 

 

 

Похоже разобрался. Поставил во FreeRTOS вместо heap4 тип heap1.

Маловероятно. Скорее всего, проблема где-то глубже.

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

Share this post


Link to post
Share on other sites

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. Маалоков нет. Динамические только очереди и пару задач временами убиваются/создаются.

 

Edited by Neo_Matrix

Share this post


Link to post
Share on other sites
Глубже копать уже просто некуда(ну или я не вижу).

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

А пока "я не знаю, переполняется что-то или нет", копать есть куда. И много...

 

 

Остановился на heap_2. Маалоков нет. Динамические только очереди и пару задач временами убиваются/создаются.

Ну так создание/удаление очередей-задач - это чистейший маллок/фрии.

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

 

 

 

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

Начинать читать здесь: http://www.freertos.org/Debugging-Hard-Fau...ontrollers.html

Share this post


Link to post
Share on other sites

gazpar

Настройка прерываний следущая

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);

esaulenka

Я увеличивал стек и кучу в 2 раза, это нечего не меняло.

Ну так создание/удаление очередей-задач - это чистейший маллок/фрии.

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

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

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

Share this post


Link to post
Share on other sites

В этой РТОС есть специальные службы для определения, что где ломается

 

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);
     
}

Edited by gazpar

Share this post


Link to post
Share on other sites

Немного добавлю по отладке. Есть задача, которая в цикле запускает вышеуказанную функцию. Собственно вот:

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) более трех.

 

В этой РТОС есть специальные службы для определения, что где ломается

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

 

Еще добавлю, на сайте РТОС есть такое:

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.

Может как то связано.....

Share this post


Link to post
Share on other sites
Немного добавлю по отладке. Есть задача, которая в цикле запускает вышеуказанную функцию. Собственно вот:

1) Хорошим тоном является наличие не обычного флажка, а семафора. Или очереди.

В этом случае задача не будет крутиться впустую.

 

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

 

 

Как видно в начале происходит проверка на новые данные if(uart3_not_empty), и даже если условие if не выполнено, все равно все висло.

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

 

 

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

Т.е. ссылка в 4-м сообщении - непонятная, а ссылка в 9-м - понятная? Удивительное дело, ведь ведут они в конечном итоге в одно и то же место.

 

Share this post


Link to post
Share on other sites
1) Хорошим тоном является наличие не обычного флажка, а семафора. Или очереди.

В этом случае задача не будет крутиться впустую.

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

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

 

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

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

 

Т.е. ссылка в 4-м сообщении - непонятная, а ссылка в 9-м - понятная? Удивительное дело, ведь ведут они в конечном итоге в одно и то же место.

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

 

esaulenka не нужно так агрессивно относится к заданным вопросам, не все так хорошо знакомы с РТОСом, как Вы. После всего прочитанного, мне стало ясно как отлаживать РТОСом, возможно скоро я и найду причину беды, если нет - перепишу с нуля обработчик прерывания и ф-кцию.

Share this post


Link to post
Share on other sites
esaulenka не нужно так агрессивно

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

 

У Вас проблема в том, что полностью отсутствуют средства диагностики.

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

Также при работе с RTOS необходимо знание, сколько куда памяти уходит. Во фриртос это почти что встроенная штука (почему-то в heap'е нет диагностики, но это легко поправить).

 

Без диагностики можно долго "исправлять" методом тыка, и оно опять развалится в самый неподходящий момент...

Share this post


Link to post
Share on other sites

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 виноват...

Share this post


Link to post
Share on other sites

Слово "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 повторюсь. Не зная, как и что ломалось, гарантировать "вот теперь-то точно всё будет хорошо" нельзя.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this