Redirecionar printf () do STM32 para o Qt Creator Console

kdpv.svg


Freqüentemente, ao depurar o software do microcontrolador, torna-se necessário enviar mensagens, registros, dados capturados e outras coisas para a tela do PC. Ao mesmo tempo, quero que a saída seja mais rápida e que as linhas não sejam exibidas em nenhum lugar, mas diretamente no IDE - sem sair do código, por assim dizer. Na verdade, isso é sobre o artigo - como eu tentei imprimir e exibir no meu ambiente favorito, mas não muito microcontrolador, do Qt Creator.


Em geral, você pode criar um grande número de maneiras de gerar informações de texto a partir do microcontrolador. No entanto, as técnicas mais usadas não são tantas:



A semi-hospedagem é bastante lenta, o RTT está vinculado às soluções de hardware e software Segger *, o USB não está presente em todos os microcontroladores. Portanto, geralmente, prefiro os dois últimos - o uso de UART e ITM. Sobre eles e será discutido abaixo.


* Upd. - de fato, como sugerido nos comentários, não é assim. Existem opções no lado do software e do hardware. Portanto, dos métodos acima, o RTT será talvez o mais universal.


E imediatamente algumas explicações sobre o software que será usado a seguir. Como sistema operacional, agora tenho o Fedora 28, e o pacote atual de software para trabalhar com microcontroladores é:



Redirecionar printf () no GCC


Portanto, para redirecionar a saída de printf () no GCC, você precisa adicionar chaves de vinculador


-specs=nosys.specs -specs=nano.specs 

Se você precisar exibir números de ponto flutuante, lembre-se da tecla


 -u_printf_float 

E implemente a função _write (). Por exemplo, algo como isto


 int _write(int fd, char* ptr, int len) { (void)fd; int i = 0; while (ptr[i] && (i < len)) { retarget_put_char((int)ptr[i]); if (ptr[i] == '\n') { retarget_put_char((int)'\r'); } i++; } return len; } 

onde retarget_put_char () é uma função que carrega o caractere diretamente na interface desejada.


printf () -> ITM -> Qt Creator


O Instrumentation Trace Macrocell (ITM) é um bloco dentro do núcleo Cortex-M3 / M4 / M7 usado para saída não invasiva (rastreamento) de vários tipos de informações de diagnóstico. Para implementar printf () sobre ITM, você precisa saber o seguinte:


  • Usa o relógio TRACECLKIN, cuja frequência geralmente é igual à frequência principal
  • Possui 32 peças das chamadas portas de estímulo para saída de dados
  • O CMSIS incorpora a função ITM_SendChar (), que carrega um símbolo na porta de estímulo 0
  • Os dados são enviados por um barramento síncrono (TRACEDATA, TRACECLK) ou por uma linha SWO assíncrona de fio único (TRACESWO)
  • A linha SWO geralmente é multiplexada com JTDO, o que significa que funciona apenas no modo de depuração pelo SWD
  • A retirada pelo SWO é realizada usando o código Manchester ou NRZ (UART 8N1)
  • Os dados são transmitidos em quadros de um determinado formato - você precisa de um analisador no lado de recebimento
  • O ITM geralmente é configurado a partir do IDE ou do utilitário correspondente (no entanto, ninguém proíbe a configuração no código do programa - a saída para o SWO funcionará sem uma sessão de depuração elevada)

A maneira mais conveniente de usar o ITM é enviar via SWO usando a codificação NRZ - portanto, você precisa de apenas uma linha e será possível receber dados não apenas usando um depurador com uma entrada especial, mas também um adaptador USB-UART comum, embora a uma velocidade mais baixa.


Eu segui o caminho usando um depurador e fui forçado a modificar meu STLink-V2 chinês para dar suporte ao SWO. Então tudo é simples - conectamos o microcontrolador JTDO / TRACESWO ao pino do depurador correspondente e vamos configurar o software.


O Openocd possui o comando "tpiu config" - com ele você pode configurar o método para exibir informações de rastreamento (em mais detalhes no Guia do Usuário do OpenOCD ). Então, por exemplo, usando argumentos


 tpiu config internal /home/esynr3z/itm.fifo uart off 168000000 

configure a saída para o arquivo /home/esynr3z/itm.fifo, use a codificação NRZ e calcule a velocidade máxima de transferência com base na frequência TRACECLKIN de 168 MHz - para o STLink é 2 MHz. E outra equipe


 itm port 0 1 

habilitará a porta zero para transferência de dados.


O código fonte do OpenOCD inclui o utilitário itmdump (contrib / itmdump.c) - com ele você pode analisar as strings dos dados recebidos.


Para compilar, entramos


 gcc itmdump.c -o itmdump 

Na inicialização, especifique o arquivo / pipe / ttyUSB * necessário e a opção -d1 para exibir os bytes de dados recebidos como cadeias


 ./itmdump -f /home/esynr3z/itm.fifo -d1 

E o último. Para enviar um personagem via SWO, complementamos _write (), descrito acima, com uma função


 int retarget_put_char(int ch) { ITM_SendChar((uint32_t)ch); return 0; } 

Portanto, o plano geral é o seguinte: dentro do Qt Creator, configuramos o openocd para salvar todas as informações recebidas no SWO em um pipe nomeado criado anteriormente, e podemos ler pipe, analisar linhas e exibir usando itmdump em execução como uma ferramenta externa. Obviamente, existe uma maneira mais elegante de resolver o problema - escrever o plugin apropriado para o Qt Creator. No entanto, espero que a abordagem descrita abaixo seja útil para alguém.


Vá para as configurações do plug-in Bare Metal (Ferramentas-> Opções-> Dispositivos-> Bare Metal).


config_baremetal.png


Selecione o servidor GDB usado e adicione os comandos de inicialização de linha ao final da lista


 monitor tpiu config internal /home/esynr3z/itm.fifo uart off 168000000 monitor itm port 0 1 

Agora, pouco antes do depurador colocar o cursor no início de main (), o ITM será configurado.


Adicione o itmdump como a ferramenta externa (Ferramentas-> Externa-> Configurar ...).


external_itmdump.png


Não se esqueça de definir a variável


 QT_LOGGING_TO_CONSOLE=1 

para exibir a saída do utilitário no console do Qt Creator (painel 7 Mensagens gerais).


Agora ative o itmdump, ative o modo de depuração, inicie a execução do código e ... nada acontece. No entanto, se você interromper a depuração, a execução do itmdump será encerrada e todas as linhas impressas através de printf () aparecerão na guia Mensagens Gerais.


Após uma breve pesquisa, descobriu-se que as linhas do itmdump deveriam ser armazenadas em buffer e exibidas no stderr - então elas aparecem no console interativamente, enquanto depuram o programa. Carreguei uma versão modificada do itmdump no GitHub .


Há mais uma ressalva. A depuração na inicialização será interrompida na execução do comando "monitor tpiu config ..." se o itmdump não for executado anteriormente. Isso acontece devido ao fato de que o pipe de abertura (/home/esynr3z/itm.fifo) dentro do openocd para gravação está bloqueando, e o depurador irá travar até que o pipe seja aberto para leitura da outra extremidade.


Isso é um pouco desagradável, especialmente se, em algum momento, o ITM não for necessário, mas você precisar executá-lo à toa, alternar constantemente o servidor GDB ou excluir / adicionar linhas em suas configurações. Portanto, eu tive que cavar um pouco de fontes openocd e encontrar o lugar onde você precisa substituir uma muleta pequena.


No arquivo src / target / armv7m_trace.c, há uma linha com o procedimento de abertura desejado


 armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); 

precisa ser substituído por


 int fd = open(CMD_ARGV[cmd_idx], O_CREAT | O_RDWR, 0664); armv7m->trace_config.trace_file = fdopen(fd, "ab"); 

Agora, nosso tubo será aberto imediatamente e não brilhará. Assim, você pode deixar as configurações do Bare Metal em paz e o itmdump somente será executado quando necessário.


Como resultado, a saída de mensagens durante a depuração se parece com isso


debug.png


printf () -> UART -> Qt Creator


Nesse caso, tudo é aproximadamente o mesmo:


  • Adicione uma função com inicialização UART ao código
  • Implementamos retarget_put_char (), onde o caractere será enviado ao buffer do transceptor
  • Conectamos o adaptador USB-UART
  • Adicione um utilitário às Ferramentas externas que lerá as linhas da porta COM virtual e as exibirá na tela.

Esbocei esse utilitário no C- uartdump . O uso é bastante simples - você só precisa especificar o nome da porta e a taxa de transmissão.


external_uartdump.png


No entanto, vale a pena notar um recurso. Este utilitário não depende da depuração e o Qt Creator não oferece nenhuma opção para fechar as Ferramentas Externas em execução. Portanto, para parar de ler a porta COM, adicionei outra ferramenta externa.


external_uartdump_close.png


Bem, apenas no caso, anexarei um link ao modelo do CMake para o projeto que apareceu nas capturas de tela - GitHub .

Source: https://habr.com/ru/post/pt440024/


All Articles