Fazemos exemplos para STM32, coletados em diferentes ambientes de desenvolvimento

Como mencionei várias vezes em artigos anteriores, sou um dos desenvolvedores do serviço All Hardware, por meio do qual qualquer pessoa pode trabalhar remotamente com várias placas de depuração publicadas por fabricantes de microcontroladores. Por padrão, um aplicativo de demonstração de amostra é carregado em cada placa. O projeto de automontagem deste aplicativo pode ser baixado para iniciar os experimentos do zero. Tudo ficaria bem, mas usuários diferentes preferem ambientes de desenvolvimento diferentes. Claro, é impossível cobrir toda a diversidade, mas pelo menos Eclipse, que significa GNU em geral (no caso do STM32, é antes uma montagem especial do IDE Cube STM32) e Keil com IAR, vale a pena. Na verdade, fui instruído a fazer pelo menos alguma unificação de projetos de demonstração para placas STM32. Neste artigo, vou primeiro dizer como ser um usuário simples,quem foi ao serviço e baixou o exemplo. O que precisa ser feito para coletá-lo. Pois bem, e só então, haverá algumas memórias justificando a decisão escolhida, bem como simplesmente descrevendo as impressões da obra.







1. Que tipo de aplicativos



Vamos primeiro dar uma olhada em quais aplicativos são oferecidos. Entramos no site https://all-hw.com/ .



Você precisa fazer o login (o registro é gratuito). Depois disso, uma lista de placas disponíveis será exibida. O primeiro deles não tem tela, por isso é inconveniente como ilustração para o artigo. A segunda é banal, todo mundo tem, só não é interessante falar disso. Vou escolher o terceiro - STM32F469I Discovery . Depois de passar por alguns passos, me vejo na página seguinte: Na verdade, à esquerda vemos a placa que a câmera remove. E esse mesmo aplicativo funciona lá. O contador só funciona. E se você inserir uma linha no terminal da direita, ela será exibida na tela, já que o terminal está conectado à porta de depuração do UART. Bem, aqui eu entrei no Just Test.



























Parece que uma aplicação para um controlador para implementar esta funcionalidade não é complicada, mas ... Mas ... Mas repito, pegamos o número de tipos de placas ST e multiplicamos por pelo menos três. E novamente, uma condição muito importante: o tempo de desenvolvimento deste aplicativo não deve ser longo. Precisamos desenvolvê-lo o mais rápido possível. E deve ser compilado por pelo menos três compiladores.



2. Formas possíveis



A primeira coisa que vem à mente é desenvolver uma aplicação típica no STM32Cube MX. Lá, você pode gerar tudo para três ambientes de desenvolvimento e adicionar rapidamente dispositivos padrão. É assim mesmo, mas:



  1. Se você olhar os exemplos de trabalho com aplicativos criados por meio do CubeMX, verá que lá, após a criação automática, ainda é necessário refinar muito com um arquivo. Ou seja, embora se economize tempo, ainda não é o máximo.
  2. , .
  3. Cube MX STemWin, ( , , , ST STemWin TouchGFX, – ).


Na verdade, isso é o suficiente para adiar tal opção na reserva e ver se existem soluções mais simples ... Acontece que existem, e elas também estão relacionadas ao Cube MX. Qualquer pessoa que já trabalhou com esse ambiente sabe que ele consiste em um código central e pacotes que atendem a uma família específica de controladores. Qual é o pacote? Este é um arquivo ZIP. Vamos fazer o download e descompactar. Pegue, digamos, um pacote de um STM32H747 totalmente novo. Eu tenho esse arquivo en.stm32cubeh7_v1-8-0.zip.



E vemos muita riqueza nisso:







são soluções típicas para diferentes placas de prototipagem com este tipo de controlador. OK. Entramos em nosso catálogo STM32H747I-DISCO... Existem aplicativos prontos separados e separadamente - exemplos para trabalhar com blocos de controlador. Não há nada de interessante aqui para quem deseja apenas construir um exemplo, mas os desenvolvedores de um aplicativo de demonstração típico devem estudar o conteúdo do diretório UART.







E de aplicativos, bem, é claro, STemWin. E o mais simples. Olá Mundo. O diretório em que está localizado será do interesse de todos os usuários.







Faremos nosso exemplo com base neste aplicativo. Por quê? Entramos no diretório STemWin_HelloWorld e vemos:







Os programadores de ST fizeram tudo por nós. Eles criaram fontes que podem ser compiladas do Keil, do IAR e do Eclipse (que é, na verdade, Cube-IDE). Assim, basta corrigir essas fontes, e a tarefa se resolverá sem editar os arquivos que dependem dos ambientes de desenvolvimento! Bem, e o projeto Hello World, ele também exibe textos na tela. Basta adicionar suporte UART a ele, e tudo funcionará. É por isso que observei acima que o exemplo UART também é útil para desenvolvedores.



E, neste caso particular, ponho-me na garganta da minha própria canção. Se alguém leu meus artigos anteriores, sabe que odeio HAL. HAL e otimização são duas coisas incompatíveis. Em projetos reais, eu uso o trabalho direto com hardware ou os drivers de Konstantin Chizhov (biblioteca mcucpp). Mas, neste caso específico, não é o caso. Estamos apenas fazendo um programa que exibe textos e funciona com uma porta COM. Em um controlador com uma frequência de clock de centenas de megahertz. Para ser honesto, na época de Ona, o BK-shka usual lidava com isso, o processador que funcionava a uma frequência de 3 MHz. Além disso, o BK-shki não tinha comandos RISC, não tinha nem pipeline. Mas havia um barramento multiplexado (ou seja, vários relógios por ciclo) e uma DRAM assíncrona sem armazenamento em cache. Em resumo,o desempenho foi de apenas 300 mil operações registro-registro por segundo. E isso foi o suficiente para resolver o problema de saída de texto e trabalhar com UART (através do bloco IRPS). Ou seja, a otimização do código HAL para essa tarefa nos STM32s modernos também é suficiente para as tarefas em questão. Mas a velocidade de desenvolvimento ao usar HAL será a mais alta.



Uma nova placa aparecerá, definitivamente terá um HAL com chamadas unificadas anexadas a ela. Corrigiremos a inicialização no exemplo típico, de acordo com o exemplo UART anexado, e o trabalho, será sempre o mesmo. Velocidade de desenvolvimento - dezenas de minutos. Nem mesmo um relógio. Ou seja, para resolver este problema, é definitivamente melhor usar o HAL, embora eu não goste dele para casos de combate.



Tudo. O mínimo de teoria, sem o qual é impossível passar à prática, eu disse. Contarei coisas teóricas mais detalhadas após o trabalho de laboratório. Então, vamos passar para os experimentos.



3. O que o usuário final deve fazer



3.1 Baixe o pacote



Então. Você não vai criar imediatamente algo próprio, mas primeiro quer brincar com um exemplo pronto tirado do site All-Hardware. O que você precisa para construir e executar? Primeiro, você precisa baixar bibliotecas para uma placa específica. Trabalhando com soluções Open Source, já percebi que não basta baixar um projeto. Ainda precisamos instalar 100.500 ferramentas e baixar 100.500 bibliotecas de terceiros. Aqui você só precisa baixar e descompactar um arquivo. É verdade que seu tamanho é gigantesco. Mas o conteúdo é ótimo. Então. Precisamos de pacotes para STM32 CubeMX. Agora, um link direto para seu repositório se parece com este:



www.st.com/en/development-tools/stm32cubemx.html#tools-software



Qual pacote deve ser baixado é mostrado na tabela abaixo.

Pagamento Pacote
STM32F429I Discovery STM32CubeF4
STM32F469I Discovery STM32CubeF4
STM32G474RE DPOW1 Discovery (sem tela) STM32CubeG4
STM32F746G Discovery STM32CubeF7
STM32H747I Discovery STM32CubeH7


3.2 Copiar o projeto e começar a trabalhar



A estrutura dos pacotes é a mesma internamente, então vamos para o diretório com a seguinte hierarquia:

<Nome do pacote> \ Projetos \ <Nome da placa> \ Aplicativos \ STemWin.



Copie o diretório com o exemplo lá. Temos algo assim:





A localização do diretório é importante porque os caminhos para as bibliotecas são escritos em formato relativo. Se o projeto não está sendo compilado devido ao grande número de arquivos ausentes, você não está adivinhando sua localização na hierarquia de diretórios.
Entramos no catálogo, selecionamos uma variante de projeto para um dos ambientes de desenvolvimento, abrimos o projeto, trabalhamos com ele ... Fim das instruções!







3.3 Recurso da placa de descoberta STM32G474RE DPOW1



Esta placa não possui tela, o que significa que não há catálogo STemWin no pacote proprietário dela. Portanto, o projeto deve ser colocado no próximo nível:



\ STM32Cube_FW_G4_V1.3.0 \ Projects \ B-G474E-DPOW1 \ Examples \ UART



4. Como os projetos são criados



O quão fácil é montar um exemplo é claro. Agora, vamos ver como esses exemplos são feitos. Talvez esta informação seja útil para quem deseja fazer algo diferente de apenas exibir textos na tela. Pois bem, quando dentro de alguns meses for necessário implementar a próxima placa, e já me esqueci de tudo, vou abrir este artigo eu mesmo para refrescar as instruções na minha memória.



4.1 Adicionando e inicializando UART



O exemplo típico do STemWin Hello World previsivelmente carece de um UART. Deve ser adicionado. Parece que pegamos o código de amostra e o adicionamos. Infelizmente, a vida é mais complicada. Em uma função de trabalho, fazemos assim. Mas existem algumas nuances durante a inicialização. Para começar, diferentes placas de prototipagem têm diferentes portas conectadas ao adaptador USB-UART embutido no adaptador JTAG. Qual deles está conectado, você precisa olhar na descrição no quadro. Normalmente, é claro, USART1, mas é melhor verificar novamente.



Além disso, a diversidade é introduzida pelo fato de que, conforme os controladores se desenvolvem, várias funções úteis são adicionadas ao equipamento UART. Eles também precisam ser inicializados no HAL das novas placas. Em particular, trabalhando com FIFO.



Portanto, sugiro as seguintes etapas típicas:



  1. Adicione uma alça de porta.
  2. Adicione inicialização de hardware UART.
  3. Adicione a inicialização de pinos UART.
  4. Adicione o manipulador de interrupção UART.


Com a alça, tudo é claro e universal. Vai parecer algo assim:



UART_HandleTypeDef huart1;


Veja o resto no exemplo de seu diretório \ <Package Name> \ Projects \ <Board Name> \ Examples \ UART .



Por exemplo, project \ STM32Cube_FW_H7_V1.8.0 \ Projects \ STM32H747I-DISCO \ Examples \ UART \ UART_WakeUpFromStopUsingFIFO .



Na função main () há uma inicialização do próprio UART (você só precisa ter certeza de que a velocidade é 9600, caso contrário, digite-a). A conexão com as pernas é configurada em outro arquivo, na função

void HAL_UART_MspInit (UART_HandleTypeDef * huart) .



Prefiro colocar tudo em uma função. Como o tempo é limitado, não procurei compilar essa função a partir desses materiais, colocando-a no arquivo main.c e não esquecendo de chamá-la da função main ().



static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */
	  GPIO_InitTypeDef  GPIO_InitStruct;


  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

//	__HAL_RCC_LPUART1_CLK_ENABLE();
	__HAL_RCC_USART1_CLK_ENABLE();

  /* USER CODE END USART1_Init 1 */
  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;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_EnableFifoMode(&huart1) != HAL_OK)
  {
    Error_Handler();
  }

  /* Enable the UART RX FIFO threshold interrupt */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXFT);

  /* Enable the UART wakeup from stop mode interrupt */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_WUF);

  /* USER CODE BEGIN USART3_Init 2 */
	__HAL_RCC_GPIOA_CLK_ENABLE();

  /*##-2- Configure peripheral GPIO ##########################################*/
  /* UART TX GPIO pin configuration  */
  GPIO_InitStruct.Pin       = GPIO_PIN_9;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLUP;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* UART RX GPIO pin configuration  */
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART1;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  /* NVIC for USART */
  HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
  HAL_NVIC_EnableIRQ(USART1_IRQn);
	

  /* USER CODE END USART1_Init 2 */

}




, , JTAG. . — , JTAG , . .
Bem, as interrupções são simples. Estamos procurando um arquivo com o sufixo _it.c no exemplo e transferimos as linhas UART para o arquivo com o sufixo _it do nosso projeto.



Neste caso, do arquivo

\ STM32Cube_FW_H7_V1.8.0 \ Projects \ STM32H747I-DISCO \ Examples \ UART \ UART_WakeUpFromStopUsingFIFO \ CM7 \ Src \ stm32h7xx_it.c



para o arquivo

\ STM32Cube_FW_H7_V1.07.8FW_H7_V1.07.8FW_H7_V1.07.8FW_H7_V1.07.0FW_H7_V1.07.0FW_H7_V1.07.8FW_H7_V1.07.08. \ STemWin \ Demo_H747 \ CM7 \ Core \ Src \ stm32h7xx_it.c



transfira o fragmento:



extern UART_HandleTypeDef huart1;
void USART1_IRQHandler(void)
{
 HAL_UART_IRQHandler(&huart1);
}


Tudo.



4.2 Editar função de trabalho principal



Com a função principal de trabalho, em princípio, tudo é mais simples. Embora, não em princípio, e em particular - não inteiramente, mas falaremos sobre isso abaixo. Por enquanto, vamos apenas ver qual função é chamada no final da função principal. Nesse caso, são:



  MainTask();


Isso significa que o trabalho principal é feito nele. Acabamos de substituir seu corpo por um exemplo típico tirado de nosso site.



4.3 O que vem a seguir?



Além disso - você pode arrastar exemplos de outros equipamentos, como acabamos de fazer com o equipamento UART. É verdade que o controle da operação deste equipamento está além do escopo deste artigo. Como você pode ver, o controle típico na página WEB é apenas para a imagem e para um UART. O resto é encaminhado um pouco mais difícil. No entanto, não posso deixar de contar como certa vez fui instruído a fazer um gerador de código Morse baseado na placa STM32G474RE DPOW1 Discovery em uma noite . Uma noite para desenvolver do zero em um quadro desconhecido não dispõe de centenas de páginas de documentação para ler. Se o projeto fosse feito há séculos, eu simplesmente começaria a provar para a gerência que não está certo e que tudo deve ser estudado com cuidado. Mas o projeto também teve um ciclo de vida curto. Então decidi seguir o caminho de puxar exemplos.



Então, para o código Morse, você precisa de um seno com frequência de 1 KHz ... Com o movimento usual da mão, descompacte o arquivo en.stm32cubeg4_v1-3-0.zip e examine o diretório D: \ tmp \ STM32Cube_FW_G4_V1.3.0 \ Projects \ B-G474E-DPOW1 \ Examples ... E nada de bom aí não encontrado ...







Não há nada útil no diretório DAC.







É o fim? Na verdade não. Vejamos exemplos de outras placas com o mesmo cristal (embora em embalagens diferentes) ... E esta é a beleza que encontramos para a placa Nucleo!







A beleza é que dentro do arquivo main.c existe uma tabela para geração do seno:



/* Sine wave values for a complete symbol */
uint16_t sinewave[60] = {
0x07ff,0x08cb,0x0994,0x0a5a,0x0b18,0x0bce,0x0c79,0x0d18,0x0da8,0x0e29,0x0e98,0x0ef4,0x0f3e,0x0f72,0x0f92,0x0f9d,
0x0f92,0x0f72,0x0f3e,0x0ef4,0x0e98,0x0e29,0x0da8,0x0d18,0x0c79,0x0bce,0x0b18,0x0a5a,0x0994,0x08cb,0x07ff,0x0733,
0x066a,0x05a4,0x04e6,0x0430,0x0385,0x02e6,0x0256,0x01d5,0x0166,0x010a,0x00c0,0x008c,0x006c,0x0061,0x006c,0x008c,
0x00c0,0x010a,0x0166,0x01d5,0x0256,0x02e6,0x0385,0x0430,0x04e6,0x05a4,0x066a,0x0733};


Nós verificamos e garantimos que sim. Este exemplo gera um seno ou triângulo na saída DAC. E apenas com frequência de 1 KHz. Isso é ótimo! Como o tempo era limitado, nem me preocupei em ler nenhuma teoria. Eu apenas me certifiquei de que toda a formação ocorresse no nível do hardware, dando uma rápida olhada no código. Depois disso, no projeto, troquei o controlador pelo da placa necessária, montei, preencha, iniciei e, após passar a ponta de prova do osciloscópio nas pernas, encontrei aquele em que aquele seno está presente. Em seguida, conectei-o à entrada dos alto-falantes, substituí a geração de um seno ou triângulo pela geração de um seno ou silêncio (sim, fiz outra tabela apenas com zeros) ... Bem, escrever uma parte aplicada com código Morse foi tão fácil quanto descascar peras. Lembrei-me de minha juventude, o departamento militar, o coronel Pavlov ...



Em geral, a técnica "encontre um exemplo, insira-o em seu código" é bastante eficaz. E a abordagem “para construir um exemplo típico - baixar uma biblioteca enorme” contribui para isso, porque todos esses exemplos de marca fazem parte dela.



5. Problemas na unificação



Um colega meu gosta de citar a seguinte declaração filosófica:



“Em teoria, não há diferença entre teoria e prática. Na prática, é. "



Ao trabalhar com vários STM32s diferentes, eu costumava me lembrar disso. Já disse sobre UARTs inevitavelmente diferentes, mas parece que um StemWin unificado não deve apresentar nenhuma surpresa ... Apresentado!



5.1 STM32H747



A legenda Hello World é desenhada. Mas quando transfiro o código de trabalho, vejo uma tela azul. Acontece que primeiro desenhamos uma tela vermelha por um segundo, depois uma tela verde por um segundo, depois uma tela azul por um segundo e o trabalho começa. Se você colocar um ponto de interrupção imediatamente após a inicialização, antes mesmo de qualquer desenho, quando ele for acionado, as leituras do cronômetro da última inicialização ficam visíveis na tela. Em seguida, eles são substituídos pela mesma tela azul. O que?



Eu removo a saída de três cores por um segundo e imediatamente adiciono o trabalho. Funciona, mas congela rapidamente para sempre. Gradualmente, descubro o que congela depois de 37 milissegundos. Que tipo de momento mágico é esse? Um milissegundo está claro. Tiquetaque do sistema. Mas 37. Sim, pelo menos algo redondo, perto ...



Quanto tempo, curto, mas descobri que tudo é exibido no manipulador de interrupçãoHAL_DSI_IRQHandler (DSI_HandleTypeDef * hdsi) . É chamado, tudo é mostrado, após o que suas chamadas são encerradas. Tudo é formado no buffer, mas não aparece na tela. Mais precisamente, tudo bate na tela duas vezes na vida do programa. Na inicialização (o mesmo artefato de uma vida passada) e após 37 ms. Tudo o que estava entre, ninguém vai ver.



Na mente - você precisa estudar a documentação e descobrir o que é. Mas, na verdade - o tempo para a tarefa não é um pouco, mas muito pouco. É claro que a interrupção deve ser provocada, mas como? Honestamente, estou tentando chamar GUI_Exec (), embora GUI_Delay () seja chamado lá de qualquer maneira ... Não ajuda.



O exemplo está morto. Em vez disso, é engraçado lá. Hello World é gerado como nos primeiros 37ms. E então - um exemplo morto. Ok, vou dar um exemplo com animação do mesmo catálogo. Ele trabalha. Gradualmente, descubro o que precisa ser arrastado para fora dele para fazer nosso exemplo funcionar ... É assim que nosso código típico se parece:



  	GUI_SetBkColor(GUI_RED);
        GUI_Clear();
  	GUI_Delay(1000);
  	GUI_SetBkColor(GUI_GREEN);
  	GUI_Clear();
  	GUI_Delay(1000);
  	GUI_SetBkColor(GUI_BLUE);
  	GUI_Clear();
  	GUI_Delay(1000);


Bem, é lógico! E funciona! .. Em outras placas ... Mas depois dessa edição, de alguma forma mudou para o H747:







O mesmo texto.
	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_RED);
        GUI_Clear();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);
	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_GREEN);
  	GUI_Clear();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);
	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_BLUE);
  	GUI_Clear();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);




Mas, em geral, funciona, e em particular - as telas vermelha e verde duram um segundo, e a azul pisca e a tela de trabalho aparece imediatamente. Após um pequeno número de experimentos, descobriu-se que tudo começou a funcionar totalmente desta forma:



	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_RED);
        GUI_Clear();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);
	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_GREEN);
  	GUI_Clear();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);
	GUI_MULTIBUF_Begin();
  	GUI_SetBkColor(GUI_BLUE);
  	GUI_Clear();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
	GUI_MULTIBUF_Begin();
	GUI_MULTIBUF_End();
  	GUI_Delay(1000);


Tanto para unificação ... Havia uma suspeita de que o cenário era o culpado:



/* Define the number of buffers to use (minimum 1) */
#define NUM_BUFFERS  3


Mas experimentos para corrigi-lo não deram um resultado ideal, e o tempo não permitiu estudar os detalhes. Talvez alguém nos comentários lhe diga como agir corretamente, e esta seção mostra como você pode agir em um tempo limitado de desenvolvimento. Nesse ínterim, o código permaneceu em um estado terrível. Felizmente, este não é um tutorial, mas apenas um exemplo de código funcional.



5,2 STM32F429



Esta placa é velha, o que pode haver de errado com ela? Rudimentos! No quadro antigo, surgem os frutos que existem, mas há muito deixaram de funcionar. Execute o exemplo Hello World e veja:







A imagem é girada 90 graus em relação à imagem normal. O que poderia ser mais fácil? Em 2016, enquanto arrastava o firmware da impressora 3D MZ3D de Arduinka para STM32F429, eu pessoalmente virei a imagem com configurações simples. Vamos. Como vão as coisas aqui? E aqui estão as configurações!



#define LCD_SWAP_XY  1 
#define LCD_MIRROR_Y 1


Tentar mudá-los não adianta. Verificando onde eles são usados ​​... Mas em lugar nenhum! Eles acabam de ser anunciados. Suspeito que pararam de processar quando o DMA2D foi implementado, mas não garantirei. No entanto, existe a mesma função. Aqui estão alguns conselhos de dezenas de fóruns. Usei esta função em 2016:



GUI_SetOrientation(GUI_SWAP_XY)


Alguns ainda adicionam uma constante de espelhamento ... Mas não é o ponto. Esta função não funciona em 2020! Não funciona e é isso! E a biblioteca é entregue em forma de objeto, por que não funciona - ninguém vai dizer.



Bem, ainda entendo as telas. Vou para o arquivo \ STM32F429-DISC1 \ Drivers \ BSP \ Components \ ili9341 \ ili9341.c (sim, está protegido contra gravação, mas pode ser facilmente removido). O chip gráfico é configurado lá. Nós mudamos.







O mesmo texto.
  ili9341_WriteReg(LCD_MAC);
  ili9341_WriteData(0xC8);




em





O mesmo texto.
  ili9341_WriteReg(LCD_MAC);
  ili9341_WriteData(0x48|0x20);




A imagem, é claro, gira ... Mas o buffer está claramente configurado de forma incorreta:







Estas são as dimensões:



#define XSIZE_PHYS 240
#define YSIZE_PHYS 320


também não afetam o trabalho de forma alguma. O mesmo se aplica a este site:



#define  ILI9341_LCD_PIXEL_WIDTH    ((uint16_t)240)
#define  ILI9341_LCD_PIXEL_HEIGHT   ((uint16_t)320)


Mas o site é mais interessante:



  if (LCD_GetSwapXYEx(0)) {
    LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
    LCD_SetVSizeEx(0, YSIZE_PHYS * NUM_VSCREENS, XSIZE_PHYS);
  } else {
    LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
    LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS * NUM_VSCREENS);
  }


Eu adicionei negação por diversão:







O mesmo texto.
  if (!LCD_GetSwapXYEx(0)) {
    LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
    LCD_SetVSizeEx(0, YSIZE_PHYS * NUM_VSCREENS, XSIZE_PHYS);
  } else {
    LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
    LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS * NUM_VSCREENS);
  }




Eu tenho essa beleza.







Obtive uma beleza semelhante, mas não exatamente a mesma em outros experimentos, não me lembro mais ... Resumindo, todos chegamos à mesma conclusão decepcionante. Temos que sentar e resolver isso ... Mas não há tempo alocado para o julgamento. O que fazer? Felizmente, consegui obter a resposta a esta pergunta do Google. Como resultado, o código típico no aplicativo de demonstração se parece com este:



  GUI_DispStringHCenterAt("www.all-hw.com",   xSize / 2, 20);


E para F429 deve ser reduzido a esta forma:

  GUI_RECT Rect = {20-10, 0, 20+10, xSize};		
  GUI_DispStringInRectEx("www.all-hw.com", &Rect, 
      GUI_TA_HCENTER | GUI_TA_VCENTER,
      20, GUI_ROTATE_CCW);	


A função de saída de texto girado é usada. Porém, para isso, você deve adicionar a entidade "retângulo". Bem, o que você pode fazer. E o contador deve ser exibido não pela função de impressão de um número, mas primeiro pela formação de um barbante e só então exibindo-o em uma forma giratória. Mas fora isso, tudo acabou quase universalmente. É até possível, ao contrário, exibir textos em todos os lugares dessa forma, mas não indicar a bandeira de rotação em todos os lugares. Mas me parece que isso já será uma perversão.



6. Conclusão



Examinamos a metodologia de desenvolvimento de programas típicos para várias placas STM32, tanto do ponto de vista do desenvolvedor quanto do ponto de vista do usuário que simplesmente baixou um aplicativo de demonstração para sua placa e só quer construí-lo sem pensar em física. Também vimos exemplos que mostram que, infelizmente, o grau de unificação do código é alto, mas não chega a cem por cento. O conhecimento adquirido pode ser verificado trabalhando alternadamente com diferentes placas através do serviço All-Hardware, sem gastar dinheiro na sua compra.



O artigo mostra como resolver as coisas de maneira bastante superficial. Isso permite que você domine rapidamente uma placa específica. Mas, é claro, quanto mais você lidar com ela, mais conhecimento profundo você obterá. Na solução de problemas reais, isso é extremamente importante, uma vez que programas complexos, nos quais o autor não entende a física dos processos, são um caminho para erros em algoritmos. Desejo que todos dominem tudo profundamente o suficiente. Sim, usando o hardware do serviço Todo o Hardware.



All Articles