Невозможно использовать printf () вне main, если printf () не используется хотя бы один раз в main - PullRequest
0 голосов
/ 15 марта 2019

Я отлаживаю неисправное последовательное соединение в TrueSTM Atollic IDE.

Окно просмотра, Expressions требует от меня выбрать переменную и отобразить ее в виде массива. Недостаток заключается в том, что мне нужно повторно выбирать, что при каждой перекомпиляции он становится очень медленным для значений +100, и мне это не очень понятно.

Итак, я создал функцию, которая просто распечатывает байты, хранящиеся в одном из буферов, которые затем отображаются мне на консоли SWV.

freertos.c

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#include "stdbool.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

uint8_t X [4] = {0xFF,0xFF,0xFF,0xFF};
uint8_t * xt = X;

 osThreadDef(CAN_Producer, FrameExtractorNEW, osPriorityNormal, 0, 128);
 defaultTaskHandle = osThreadCreate(osThread(CAN_Producer), NULL);

void FrameExtractorNEW(void const * argument){

            Print_Bytes(xt,4);  // fails
            printf("Cheese\n")  // fails
}

main.c

#include "main.h"
#include "cmsis_os.h"
#include "can.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{

  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_CAN2_Init();
  MX_CAN1_Init();
  MX_USART3_UART_Init();

  MX_FREERTOS_Init();
  osKernelStart();      
  while (1)
  {}
}


// accept pointer to first element, and number of consecutive byte values to display
void Print_Bytes(uint8_t * a1, int bytes_to_read){  
    for (int i = 0; i<bytes_to_read; i++){
        printf("0x%02X " , *(a1+i));        
    }   
}

Пока что все просто и понятно.

Моя проблема в том, что если я попытаюсь использовать функцию Print_Bytes() в freertos.c, она будет работать, но только при условии, что она была вызвана хотя бы один раз до main.c. Распечатка чего-либо, используя printf() в main.c хотя бы один раз, также заставит его работать в других файлах.

Без этого «включения» выполнение программы переходит к HardFault_Handler() со следующими ошибками.

enter image description here

У меня есть необходимые включения для printf() и Print_Bytes() для функций, которые их вызывают, но, кажется, этого недостаточно для того, чтобы заставить его работать, как я ожидаю, оно должно работать.

Ответы [ 2 ]

1 голос
/ 16 марта 2019

Могу поспорить, что printf при первом запуске инициализирует некоторые внутренние переменные. В основном он использует кучу основной программы и стек. Если вы впервые используете задачу, она делает это в куче и стеке задачи, и ни одно из стандартных выделений может не работать в этом контексте (printf использует функцию malloc).

Лично я написал собственные безопасные версии этого семейства функций с бесплатной ОСРВ. Это очень плохая практика - использовать многопоточные небезопасные функции.

0 голосов
/ 20 марта 2019

вероятно, ваш минимальный размер кучи недостаточно велик (опция ld file ide ...) lib по умолчанию (nano и т.д ..) будет вызывать sbrake "для разделения стека и увеличения кучи, но это не значит, что его следует использовать в контексте rtos, поэтому он не будет работать, если указатель стека не является основным стеком :(

Так что если вы сделаете первый print или malloc и т. Д. ... внутри main перед запуском oskernel, это поможет (sp is main stack), увеличив вашу кучу. Если вы сделаете это впервые в потоке, это не удастся, потому что sbrake использует sp для свободной памяти задач, а не для основного стека, поэтому printf не сможет выделить mem

.

Вы можете заметить, что printf rely или std lib malloc, который не является повторно входящим и не является многопоточным, безопаснее ... Более безопасная отформатированная печать может быть выполнена через форматирующую строку vsnprintf в буфер, принадлежащий задаче.

...