Hacemos ejemplos para STM32, recopilados en diferentes entornos de desarrollo

Como he mencionado varias veces en artículos anteriores, soy uno de los desarrolladores del servicio Todo el hardware, a través del cual cualquiera puede trabajar de forma remota con varias placas de depuración que los fabricantes de microcontroladores colocan allí. De forma predeterminada, se carga una aplicación de demostración de muestra en cada placa. El proyecto de autoensamblaje de esta aplicación se puede descargar para iniciar experimentos desde cero. Todo estaría bien, pero diferentes usuarios prefieren diferentes entornos de desarrollo. Por supuesto, es imposible cubrir toda la diversidad, pero al menos Eclipse, que significa GNU en general (en el caso de STM32, es más bien un ensamblaje especial del STM32 Cube IDE) y Keil con IAR vale la pena. En realidad, se me indicó que hiciera al menos alguna unificación de proyectos de demostración para placas STM32. En este artículo, primero te diré cómo ser un usuario simple,que fue al servicio y descargó el ejemplo. Qué se debe hacer para recolectarlo. Bueno, y solo entonces, habrá unas memorias que justifiquen la decisión elegida, además de simplemente describir las impresiones de la obra.







1. Qué tipo de aplicaciones



Primero echemos un vistazo a las aplicaciones que se ofrecen. Ingresamos al sitio https://all-hw.com/ .



Debe iniciar sesión allí (el registro es gratuito). Después de eso, se mostrará una lista de tableros disponibles. El primero de ellos no tiene pantalla, por lo que resulta inconveniente como ilustración del artículo. El segundo es banal, todo el mundo lo tiene, simplemente no es interesante hablar de ello. Elegiré el tercero: STM32F469I Discovery . Después de seguir algunos pasos, me encuentro en la siguiente página: En realidad, a la izquierda vemos el tablero que quita la cámara. Y esa misma aplicación funciona allí. El contador simplemente hace tictac. Y si ingresa una línea en el terminal de la derecha, se mostrará en la pantalla, ya que el terminal está conectado al puerto de depuración UART. Bueno, aquí entré a Just Test.



























Parece que una aplicación para que un controlador implemente esta funcionalidad no es complicada, pero ... Pero ... Pero repito, tomamos el número de tipos de placas ST y lo multiplicamos por al menos tres. Y nuevamente, una condición muy importante: el tiempo de desarrollo de esta aplicación no debería ser largo. Necesitamos desarrollarlo lo más rápido posible. Y debe ser compilado por al menos tres compiladores.



2. Posibles formas



Lo primero que me viene a la mente es desarrollar una aplicación típica en el STM32Cube MX. Allí, puede generar todo para tres entornos de desarrollo y agregar rápidamente dispositivos estándar. Así es, pero:



  1. Si observa los ejemplos de trabajo con aplicaciones creadas a través de CubeMX, puede ver que allí, después de la creación automática, todavía necesita modificar mucho con un archivo. Es decir, aunque se ahorra tiempo, todavía no es máximo.
  2. , .
  3. Cube MX STemWin, ( , , , ST STemWin TouchGFX, – ).


En realidad, esto es suficiente para posponer tal opción en reserva y ver si hay soluciones más simples ... Resulta que las hay, y también están relacionadas con el Cube MX. Cualquiera que haya trabajado con este entorno sabe que se compone de código central y paquetes que sirven a una familia específica de controladores. ¿Qué es el paquete? Este es un archivo ZIP. Vamos a descargarlo y descomprimirlo. Tome, digamos, un paquete para un STM32H747 nuevo. Tengo este archivo en.stm32cubeh7_v1-8-0.zip.



Y vemos tanta riqueza en ello:







estas son soluciones típicas para diferentes placas de prototipos con este tipo de controlador. Bueno. Entramos en nuestro catálogo STM32H747I-DISCO... Hay aplicaciones independientes listas para usar y por separado, ejemplos para trabajar con bloques de controlador. No hay nada interesante aquí para aquellos que solo quieran crear un ejemplo, pero los desarrolladores de una aplicación de demostración típica deben estudiar el contenido del directorio UART.







Y de las aplicaciones, bueno, por supuesto, STemWin. Y el mas simple. Hola Mundo. El directorio en el que se encuentra será de interés para todos los usuarios.







Haremos nuestro ejemplo basándonos en esta aplicación. ¿Por qué? Ingresamos al directorio STemWin_HelloWorld y vemos:







Los programadores de ST hicieron todo por nosotros. Crearon fuentes que se pueden compilar desde Keil, desde IAR y desde Eclipse (que es, de hecho, Cube-IDE). Por lo tanto, basta con corregir estas fuentes, ¡y la tarea se resolverá sin editar los archivos que dependen de los entornos de desarrollo! Bueno, y el proyecto Hello World, también muestra textos en la pantalla. Es suficiente agregarle soporte UART, y todo funcionará. Es por eso que señalé anteriormente que el ejemplo de UART también es útil para los desarrolladores.



Y en este caso particular, pisé la garganta de mi propia canción. Si alguien ha leído mis artículos anteriores, sabe que odio a HAL. HAL y optimización son dos cosas incompatibles. En proyectos reales, uso el trabajo directo con hardware o los controladores de Konstantin Chizhov (biblioteca mcucpp). Pero en este caso particular, este no es en absoluto el caso. Solo estamos haciendo un programa que muestra textos y funciona con un puerto COM. En un controlador con una frecuencia de reloj de cientos de megahercios. Para ser honesto, en el momento de Ona, un BK-shka ordinario hizo frente a esto, cuyo procesador funcionaba a una frecuencia de 3 MHz. Además, el BK-shki no tenía comandos RISC, ni siquiera había una tubería. Pero había un bus multiplexado (es decir, varios relojes por ciclo) y una DRAM asíncrona sin almacenamiento en caché. En breve,el rendimiento fue de sólo 300 mil operaciones registro-registro por segundo. Y esto fue suficiente para resolver el problema de generar textos y trabajar con UART (a través del bloque IRPS). Es decir, la optimización del código HAL para esta tarea en los STM32 modernos también es suficiente para las tareas en cuestión. Pero la velocidad de desarrollo al usar HAL será la más alta.



Aparecerá una nueva placa, definitivamente tendrá un HAL con llamadas unificadas adjuntas. Corregiremos la inicialización en el ejemplo típico, según el ejemplo de UART adjunto, y el trabajo, siempre será el mismo. La velocidad de revelado es de decenas de minutos. Ni siquiera un reloj. Es decir, para solucionar este problema definitivamente lo mejor es usar HAL, aunque no me gusta para casos de combate.



Todos. El mínimo de teoría, sin el cual es imposible pasar a la práctica, le dije. Te contaré cosas teóricas más detalladas después del trabajo de laboratorio. Así que pasemos a los experimentos.



3. Qué debe hacer el usuario final



3.1 Descarga el paquete



Entonces. No vas a crear algo por tu cuenta de inmediato, pero primero quieres jugar con un ejemplo listo para usar tomado del sitio web de All-Hardware. ¿Qué necesitas para construirlo y ejecutarlo? Primero, necesita descargar bibliotecas para una placa específica. Al trabajar con soluciones de código abierto, ya me he encontrado con el hecho de que no es suficiente descargar un proyecto. Todavía necesitamos instalar 100,500 herramientas y descargar 100,500 bibliotecas de terceros. Aquí solo necesita descargar y descomprimir un archivo. Es cierto que su tamaño es gigantesco. Pero el contenido es genial. Entonces. Necesitamos paquetes para STM32 CubeMX. Ahora, un enlace directo a su repositorio se ve así:



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



En la siguiente tabla se muestra el paquete que debe descargarse.

Pagar Paquete
STM32F429I Descubrimiento STM32CubeF4
STM32F469I Descubrimiento STM32CubeF4
STM32G474RE DPOW1 Discovery (sin pantalla) STM32CubeG4
Descubrimiento STM32F746G STM32CubeF7
STM32H747I Descubrimiento STM32CubeH7


3.2 Copiar el proyecto y empezar a trabajar



La estructura de los paquetes es la misma en el interior, entonces vamos al directorio con la siguiente jerarquía:

<Nombre del paquete> \ Proyectos \ <Nombre del tablero> \ Aplicaciones \ STemWin.



Copie el directorio con el ejemplo allí. Obtenemos algo como esto:





La ubicación del directorio es importante porque las rutas a las bibliotecas están escritas en formato relativo. Si el proyecto no se está construyendo debido a la gran cantidad de archivos que faltan, no está adivinando su ubicación en la jerarquía de directorios.
Entramos en el catálogo, seleccionamos una variante de proyecto para uno de los entornos de desarrollo, abrimos el proyecto, trabajamos con él ... ¡Fin de instrucciones!







3.3 Característica de la placa de descubrimiento STM32G474RE DPOW1



Esta placa no tiene pantalla, lo que significa que no hay un catálogo de STemWin en el paquete propietario para ella. Por lo tanto, el proyecto debe ubicarse en el siguiente nivel:



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



4. Cómo se crean los proyectos



Lo fácil que es armar un ejemplo está claro. Ahora veamos cómo se hacen estos ejemplos. Quizás esta información sea útil para aquellos que quieren hacer algo más que mostrar textos en la pantalla. Pues bien, cuando en unos meses sea necesario introducir la siguiente placa, y ya me he olvidado de todo, yo mismo abriré este artículo para refrescar las instrucciones en mi memoria.



4.1 Agregar e inicializar UART



El ejemplo típico de STemWin Hello World, como era de esperar, carece de UART. Debe agregarse. Parecería que tomamos el código de muestra y lo agregamos. Por desgracia, la vida es más complicada. En una función de trabajo, lo hacemos de esta manera. Pero hay algunos matices durante la inicialización. Para empezar, diferentes placas de creación de prototipos tienen diferentes puertos conectados al adaptador USB-UART integrado en el adaptador JTAG. Cuál está conectado, debe buscar en la descripción de la placa. Usualmente, por supuesto, USART1, pero es mejor verificarlo.



Además, la diversidad es introducida por el hecho de que a medida que se desarrollan los controladores, se agregan varias funciones útiles al equipo UART. También deben inicializarse en la HAL de las nuevas placas. En particular, trabajar con FIFO.



Por lo tanto, sugiero los siguientes pasos típicos:



  1. Agregue un identificador de puerto.
  2. Agregue la inicialización de hardware UART.
  3. Agregue la inicialización de los pines UART.
  4. Agregue el controlador de interrupciones UART.


Con el mango, todo es claro y universal. Se verá algo como esto:



UART_HandleTypeDef huart1;


Vea el resto en el ejemplo de su directorio \ <Nombre del paquete> \ Proyectos \ <Nombre del tablero> \ Ejemplos \ UART .



Por ejemplo, proyecto \ STM32Cube_FW_H7_V1.8.0 \ Projects \ STM32H747I-DISCO \ Examples \ UART \ UART_WakeUpFromStopUsingFIFO .



En la función main () hay una inicialización del propio UART (solo debes asegurarte de que la velocidad sea 9600, si no, introdúcela). La conexión con las piernas se configura en otro archivo, en la función

void HAL_UART_MspInit (UART_HandleTypeDef * huart) .



Prefiero ponerlo todo en una sola función. Como el tiempo es limitado, no busqué compilar dicha función a partir de estos materiales, colocarla en el archivo main.cy sin olvidar llamarla desde la función 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 , . .
Bueno, las interrupciones son simples. Buscamos un archivo con el sufijo _it.c en el ejemplo y transferimos las líneas UART al archivo con el sufijo _it de nuestro proyecto.



En este caso, del archivo

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



al archivo

\ STM32Cube_FW_H7_H7_V1.8_M. \ STemWin \ Demo_H747 \ CM7 \ Core \ Src \ stm32h7xx_it.c



transfiere el fragmento:



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


Todos.



4.2 Editar función de trabajo principal



Con la función de trabajo principal, en principio, todo es más simple. Aunque, no en principio, y en particular, no del todo, pero hablaremos de esto a continuación. Por ahora, veamos qué función se llama al final de la función principal. En este caso, estos son:



  MainTask();


Esto significa que el trabajo principal se realiza en él. Simplemente reemplazamos su cuerpo con un ejemplo típico tomado de nuestro sitio.



4.3 ¿Qué sigue?



Además, puede llevar ejemplos de otros equipos, como acabamos de hacer con el equipo UART. Es cierto que el control del funcionamiento de este equipo está fuera del alcance de este artículo. Como puede ver, el control típico en la página WEB es solo para la imagen y para una UART. El resto se reenvía un poco más difícil. Sin embargo, no puedo evitar decirles cómo una vez me ordenaron que hiciera un generador de código Morse basado en la placa STM32G474RE DPOW1 Discovery en una noche . Una noche para desarrollar desde cero en un tablero desconocido no lo dispone a leer cientos de páginas de documentación. Si el proyecto se hiciera durante siglos, simplemente comenzaría a demostrarle a la gerencia que no está bien y que todo debe ser estudiado cuidadosamente. Pero el proyecto también tenía un ciclo de vida corto. Así que decidí seguir el camino de sacar ejemplos.



Entonces, para el código Morse necesita un seno con una frecuencia de 1 KHz ... Con el movimiento habitual de su mano, descomprima el archivo en.stm32cubeg4_v1-3-0.zip y examine el directorio D: \ tmp \ STM32Cube_FW_G4_V1.3.0 \ Projects \ B-G474E-DPOW1 \ Examples ... Y nada bueno allí no encontrado ...







No hay nada útil en el directorio DAC.







¿Ese es el final? Realmente no. Veamos ejemplos de otras placas con el mismo cristal (aunque en paquetes diferentes) ... ¡Y esta es la belleza que encontramos para la placa Nucleo!







La belleza es que dentro del archivo main.c hay una tabla para generar el 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};


Comprobamos y nos aseguramos de que sí. Este ejemplo genera un seno o un triángulo en la salida del DAC. Y solo con una frecuencia de 1 KHz. ¡Eso es genial! Como el tiempo era limitado, ni siquiera me molesté en leer ninguna teoría. Solo me aseguré de que toda la formación tenga lugar a nivel de hardware echando un vistazo rápido al código. Después de eso, en el proyecto, reemplacé el controlador con el de la placa requerida, lo ensamblé, lo completé, lo encendí y, pasando la sonda del osciloscopio a lo largo de las patas, encontré el que tenía ese seno. Luego lo conecté a la entrada de los altavoces, reemplacé la generación de un seno o un triángulo por la generación de un seno o silencio (sí, hice otra tabla de solo ceros) ... Bueno, escribir una parte aplicada con código Morse fue tan fácil como pelar peras. Recordé mi juventud, el departamento militar, el coronel Pavlov ...



En general, la técnica "busque un ejemplo, insértelo en su código" es bastante eficaz. Y el enfoque de “construir un ejemplo típico - descargar una biblioteca enorme” contribuye a esto, porque todos estos ejemplos de marca son parte de ello.



5. Problemas en la unificación



A un colega le gusta citar la siguiente afirmación filosófica:



“En teoría, no hay diferencia entre teoría y práctica. En la práctica, lo es ".



Cuando trabajaba con un montón de STM32 diferentes, lo recordaba regularmente. Ya he dicho sobre UART inevitablemente diferentes, pero parece que el StemWin unificado no debería presentar ninguna sorpresa ... ¡Presentado!



5.1 STM32H747



Se dibuja el título Hello World. Pero cuando transfiero el código de trabajo, veo una pantalla azul. Es solo que primero dibujamos una pantalla roja por un segundo, luego una pantalla verde por un segundo, luego una pantalla azul por un segundo, luego comienza el trabajo. Si coloca un punto de interrupción justo después de la inicialización, incluso antes de cualquier dibujo, cuando se activa, las lecturas del temporizador desde el último inicio son visibles en la pantalla. Luego, se sobrescriben con la misma pantalla azul. ¿Qué?



Elimino la salida de tres colores por un segundo e inmediatamente agrego el trabajo. Funciona, pero se congela rápidamente para siempre. Poco a poco descubro qué se congela después de 37 milisegundos. ¿Qué tipo de momento mágico es este? Un milisegundo es claro. Marca del sistema. Pero 37. Sí, al menos algo redondo, cercano ...



Cuánto tiempo, corto, pero descubro que todo se muestra en el controlador de interrupcionesHAL_DSI_IRQHandler (DSI_HandleTypeDef * hdsi) . Se llama, se muestra todo, después de lo cual se terminan sus llamadas. Todo se forma en el búfer, pero no aparece en la pantalla. Más precisamente, todo aparece en la pantalla dos veces durante la vida del programa. En la inicialización (el mismo artefacto de una vida pasada) y después de 37 ms. Todo lo que estaba en el medio, nadie lo verá.



En la mente, necesita estudiar la documentación y averiguar qué es qué. Pero, de hecho, el tiempo para la tarea no es poco, sino muy poco. Está claro que hay que provocar la interrupción, pero ¿cómo? Honestamente, estoy tratando de llamar a GUI_Exec (), aunque GUI_Delay () se llama allí de todos modos ... No ayuda.



El ejemplo está muerto. Más bien, es gracioso allí. Hello World se emite como lo hace en los primeros 37 ms. Y luego, un ejemplo muerto. Ok, tomaré un ejemplo con animación del mismo catálogo. Él trabaja. Poco a poco, averiguo qué se debe sacar de él para que nuestro ejemplo funcione ... Así es como se ve nuestro código típico:



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


¡Bueno, es lógico! ¡Y funciona! ... En otras placas ... Pero después de tal edición, de alguna manera se movió en el H747:







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




Pero en general, funciona, y en particular: las pantallas roja y verde duran un segundo, la azul parpadea y la pantalla de trabajo aparece inmediatamente. Después de una pequeña cantidad de experimentos, resultó que todo comienza a funcionar completamente de esta 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 la unificación ... Se sospechaba que el escenario era el culpable:



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


Pero los experimentos con la edición no dieron un resultado ideal y el tiempo no permitió estudiar los detalles. Quizás alguien en los comentarios te diga cómo actuar correctamente, y esta sección muestra cómo puedes actuar en un tiempo limitado para el desarrollo. Mientras tanto, el código permanecía en un estado tan terrible. Afortunadamente, esto no es un tutorial, sino solo un ejemplo de código de trabajo.



5.2 STM32F429



Esta placa es vieja, ¿qué podría tener de malo? ¡Rudimentos! En el tablero antiguo, surgen las excrecencias que existen, pero que hace tiempo que dejaron de funcionar. Ejecute el ejemplo de Hello World y vea:







La imagen se gira 90 grados con respecto a la típica. ¿Qué podría ser más fácil? En 2016, mientras arrastraba el firmware de la impresora 3D MZ3D de Arduinka a STM32F429, personalmente cambié la imagen con configuraciones simples. Venga. ¿Cómo van las cosas aquí? ¡Y aquí están los ajustes!



#define LCD_SWAP_XY  1 
#define LCD_MIRROR_Y 1


Intentar cambiarlos no ayuda. Comprobando dónde se utilizan ... ¡Pero en ninguna parte! Se acaban de anunciar. Sospecho que ya no se procesaron cuando se implementó DMA2D, pero no responderé. Sin embargo, existe la misma función. Aquí tienes consejos de decenas de foros. Usé esta función en 2016:



GUI_SetOrientation(GUI_SWAP_XY)


Algunos todavía agregan una constante reflejada ... Pero no el punto. ¡Esta función no funciona en 2020! ¡No funciona y eso es todo! Y la biblioteca se entrega en forma de objeto, por qué no funciona, nadie lo dirá.



Bueno, todavía entiendo las pantallas. Voy al archivo \ STM32F429-DISC1 \ Drivers \ BSP \ Components \ ili9341 \ ili9341.c (sí, está protegido contra escritura, pero es fácil de quitar). El chip gráfico está configurado allí. Nosotros cambiamos.







El mismo texto.
  ili9341_WriteReg(LCD_MAC);
  ili9341_WriteData(0xC8);




en





El mismo texto.
  ili9341_WriteReg(LCD_MAC);
  ili9341_WriteData(0x48|0x20);




La imagen, por supuesto, gira ... Pero el búfer está claramente configurado de forma algo incorrecta:







Estas son las dimensiones:



#define XSIZE_PHYS 240
#define YSIZE_PHYS 320


Tampoco afectan el trabajo de ninguna manera. Lo mismo se aplica a este sitio:



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


Pero el sitio es más interesante:



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


Agregué negación por diversión:







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




Tengo esta belleza.







Obtuve una belleza similar, pero no exactamente la misma en otros experimentos, no recuerdo más ... En resumen, todos llegamos a la misma conclusión decepcionante. Tenemos que sentarnos y arreglarlo ... Pero no hay tiempo asignado para el juicio. ¿Qué hacer? Afortunadamente, logré obtener la respuesta a esta pregunta de Google. Como resultado, el código típico de la aplicación de demostración se ve así:



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


Y para F429 debe reducirse 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);	


Se utiliza la función de generar texto girado. Es cierto, para esto tienes que agregar la entidad "rectángulo". Bueno, que puedes hacer. Y el contador debe mostrarse no mediante la función de imprimir un número, sino primero formando una cadena, y solo luego mostrándolo en forma rotada. Pero por lo demás, todo resultó casi universal. Incluso es posible, por el contrario, mostrar textos en todas partes de esta manera, pero no indicar la bandera de rotación en todas partes. Pero me parece que esto ya será una perversión.



6. Conclusión



Examinamos la metodología para desarrollar programas típicos para varias placas STM32, tanto desde el punto de vista del desarrollador como desde el punto de vista del usuario que simplemente descargó la aplicación de demostración para su placa y solo quiere construirla sin pensar en la física. También miramos ejemplos que muestran que, lamentablemente, el grado de unificación del código es alto, pero no llega al cien por cien. Los conocimientos adquiridos se pueden comprobar trabajando alternativamente con diferentes placas a través del servicio All-Hardware, sin gastar dinero en su compra.



El artículo muestra cómo resolver las cosas de forma bastante superficial. Esto le permite dominar rápidamente un tablero específico. Pero, por supuesto, cuanto más tiempo trates con ella, más profundo conocimiento obtendrás. A la hora de resolver problemas reales, esto es sumamente importante, ya que los programas complejos, en los que el autor no comprende la física de los procesos, son un camino hacia errores en los algoritmos. Deseo que todos dominen todo lo suficientemente profundo. Sí, utilizando el hardware del servicio Todo el hardware.



All Articles