1. Quel type d'applications
Voyons d'abord quelles applications sont proposées. Nous entrons sur le site https://all-hw.com/ .
Vous devez vous y connecter (l'inscription est gratuite). Après cela, une liste des tableaux disponibles sera affichée. Le premier d'entre eux n'a pas d'écran, ce n'est donc pas pratique comme illustration de l'article. Le second est banal, tout le monde l'a, ce n'est tout simplement pas intéressant d'en parler. Je vais choisir le troisième - STM32F469I Discovery . Après avoir parcouru quelques étapes, je me retrouve sur la page suivante: En fait, sur la gauche on voit le tableau que la caméra supprime. Et cette application même fonctionne là-bas. Le compteur tourne juste. Et si vous entrez une ligne dans le terminal sur la droite, elle sera affichée à l'écran, puisque le terminal est connecté au port de débogage UART. Eh bien, ici, je suis entré Just Test.
Il semble qu'une application pour un contrôleur pour implémenter cette fonctionnalité n'est pas compliquée, mais ... Mais ... Mais je le répète, on prend le nombre de types de cartes ST et on le multiplie par au moins trois. Et là encore, une condition très importante: le temps de développement de cette application ne doit pas être long. Nous devons le développer le plus rapidement possible. Et il doit être compilé par au moins trois compilateurs.
2. Moyens possibles
La première chose qui me vient à l'esprit est de développer une application typique dans le STM32Cube MX. Là, vous pouvez tout générer pour trois environnements de développement et ajouter rapidement des périphériques standard. C'est comme ça, mais:
- Si vous regardez les exemples de travail avec des applications créées via CubeMX, vous pouvez voir que là, après la création automatique, vous devez encore affiner beaucoup avec un fichier. Autrement dit, bien que le temps soit gagné, il n'est toujours pas maximal.
- , .
- Cube MX STemWin, ( , , , ST STemWin TouchGFX, – ).
En fait, cela suffit pour reporter une telle option en réserve et voir s'il existe des solutions plus simples ... Il s'avère qu'il y en a, et elles sont également liées au Cube MX. Quiconque a travaillé avec cet environnement sait qu'il se compose de code de base et de packages qui servent une famille spécifique de contrôleurs. Quel est le package? Ceci est un fichier ZIP. Téléchargeons-le et décompressons-le. Prenons, par exemple, un package pour un tout nouveau STM32H747. J'ai ce fichier en.stm32cubeh7_v1-8-0.zip.
Et on y voit une telle richesse:
ce sont des solutions typiques pour différentes cartes de prototypage avec ce type de contrôleur. D'accord. Nous entrons dans notre catalogue STM32H747I-DISCO... Il existe des applications prêtes à l'emploi séparément et séparément - des exemples pour travailler avec des blocs de contrôleur. Il n'y a rien d'intéressant ici pour ceux qui veulent juste construire un exemple, mais les développeurs d'une application de démonstration typique devraient étudier le contenu du répertoire UART.
Et des applications, bien sûr, STemWin. Et le plus simple. Bonjour le monde. Le répertoire dans lequel il se trouve intéressera tous les utilisateurs.
Nous ferons notre exemple sur la base de cette application. Pourquoi? Nous entrons dans le répertoire STemWin_HelloWorld et voyons:
Les programmeurs ST ont tout fait pour nous. Ils ont créé des sources qui peuvent être compilées à partir de Keil, d'IAR et d'Eclipse (qui est, en fait, Cube-IDE). Ainsi, il suffit de corriger ces sources, et la tâche sera résolue sans éditer les fichiers qui dépendent des environnements de développement! Eh bien, et le projet Hello World, il affiche également des textes à l'écran. Il suffit d'y ajouter le support UART et tout fonctionnera. C'est pourquoi j'ai noté ci-dessus que l'exemple UART est également utile pour les développeurs.
Et dans ce cas particulier, je marche sur la gorge de ma propre chanson. Si quelqu'un a lu mes articles précédents, il sait que je déteste HAL. HAL et l'optimisation sont deux choses incompatibles. Dans de vrais projets, j'utilise soit le travail direct avec du matériel, soit les pilotes de Konstantin Chizhov (bibliothèque mcucpp). Mais dans ce cas particulier, ce n'est pas du tout le cas. Nous faisons juste un programme qui affiche des textes et fonctionne avec un port COM. Sur un contrôleur avec une fréquence d'horloge de centaines de mégahertz. Pour être honnête, à l'époque d'Ona, le BK-shka habituel a fait face à cela, dont le processeur fonctionnait à une fréquence de 3 MHz. De plus, le BK-shki n'avait pas de commandes RISC, il n'y avait même pas de pipeline. Mais il y avait un bus multiplexé (c'est-à-dire plusieurs horloges par cycle) et une DRAM asynchrone sans mise en cache. En bref,la performance n'était que de 300 000 opérations de registre par seconde. Et cela suffisait pour résoudre le problème de la sortie de texte et travailler avec UART (via le bloc IRPS). Autrement dit, l'optimalité du code HAL pour cette tâche sur les STM32 modernes est également tout à fait suffisante pour les tâches à accomplir. Mais la vitesse de développement lors de l'utilisation de HAL sera la plus élevée.
Un nouveau tableau apparaîtra, il aura certainement HAL avec des appels unifiés attachés. Nous corrigerons l'initialisation dans l'exemple typique, selon l'exemple UART ci-joint, et le travail, ce sera toujours le même. La vitesse de développement est de plusieurs dizaines de minutes. Pas même une montre. Autrement dit, pour résoudre ce problème, il est certainement préférable d'utiliser HAL, même si je ne l'aime pas pour les cas de combat.
Tout. Le minimum de théorie, sans lequel il est impossible de passer à la pratique, dis-je. Je vous dirai des choses théoriques plus détaillées après les travaux de laboratoire. Alors passons aux expériences.
3. Ce que l'utilisateur final doit faire
3.1 Téléchargez le package
Alors. Vous n'allez pas créer immédiatement quelque chose de votre choix, mais vous voulez d'abord jouer avec un exemple prêt à l'emploi tiré du site Web All-Hardware. De quoi avez-vous besoin pour le créer et l'exécuter? Tout d'abord, vous devez télécharger des bibliothèques pour une carte spécifique. En travaillant avec des solutions Open Source, je suis déjà tombé sur le fait qu'il ne suffit pas de télécharger un projet. Nous devons encore installer 100 500 outils et télécharger 100 500 bibliothèques tierces. Ici, il vous suffit de télécharger et de décompresser un fichier. Certes, sa taille est gigantesque. Mais le contenu est tout simplement génial. Alors. Nous avons besoin de packages pour STM32 CubeMX. Maintenant, un lien direct vers leur référentiel ressemble à ceci:
www.st.com/en/development-tools/stm32cubemx.html#tools-software Le
paquet à télécharger est indiqué dans le tableau ci-dessous.
Payer | Paquet |
---|---|
Découverte STM32F429I | STM32CubeF4 |
Découverte STM32F469I | STM32CubeF4 |
STM32G474RE DPOW1 Discovery (pas d'écran) | STM32CubeG4 |
Découverte STM32F746G | STM32CubeF7 |
Découverte STM32H747I | STM32CubeH7 |
3.2 Copier le projet et se mettre au travail
La structure des packages est la même à l'intérieur, nous allons donc dans le répertoire avec la hiérarchie suivante:
<nom du package> \ Projects \ <nom de la carte> \ Applications \ STemWin.
Copiez le répertoire avec l'exemple ici. Nous obtenons quelque chose comme ceci:
La position du répertoire est importante, car les chemins vers les bibliothèques sont écrits dans un format relatif. Si le projet ne se construit pas en raison du grand nombre de fichiers manquants, vous ne devinez pas son emplacement dans la hiérarchie des répertoires.Nous entrons dans le catalogue, sélectionnons une variante de projet pour l'un des environnements de développement, ouvrons le projet, travaillons avec ... Fin des instructions!
3.3 Caractéristique de la carte de découverte STM32G474RE DPOW1
Cette carte n'a pas d'écran, ce qui signifie qu'il n'y a pas de catalogue STemWin dans le package propriétaire correspondant. Par conséquent, le projet doit être placé au niveau suivant:
\ STM32Cube_FW_G4_V1.3.0 \ Projects \ B-G474E-DPOW1 \ Examples \ UART
4. Comment les projets sont créés
Il est clair à quel point il est facile d'assembler un exemple. Voyons maintenant comment ces exemples sont réalisés. Peut-être que ces informations sont utiles pour ceux qui veulent faire autre chose que simplement afficher des textes à l'écran. Eh bien, quand dans quelques mois il faudra implémenter le prochain tableau, et que j'ai déjà tout oublié, j'ouvrirai moi-même cet article pour rafraîchir les instructions dans ma mémoire.
4.1 Ajouter et initialiser UART
L'exemple typique de STemWin Hello World manque de manière prévisible d'un UART. Il faut l'ajouter. Il semblerait que nous prenions l'exemple de code et que nous l'ajoutions. Hélas, la vie est plus compliquée. Dans une fonction de travail, nous le faisons de cette façon. Mais il y a quelques nuances lors de l'initialisation. Pour commencer, différentes cartes de prototypage ont différents ports connectés à l'adaptateur USB-UART intégré à l'adaptateur JTAG. Lequel est connecté, vous devez regarder dans la description de la carte. Habituellement, bien sûr, USART1, mais il vaut mieux vérifier.
En outre, la diversité est introduite par le fait qu'au fur et à mesure que les contrôleurs se développent, diverses fonctions utiles sont ajoutées à l'équipement UART. Ils doivent également être initialisés dans la HAL des nouvelles cartes. En particulier, travailler avec FIFO.
Par conséquent, je suggère les étapes typiques suivantes:
- Ajoutez une poignée de port.
- Ajoutez l'initialisation du matériel UART.
- Ajoutez l'initialisation des broches UART.
- Ajoutez un gestionnaire d'interruption UART.
Avec le manche, tout est clair et universel. Cela ressemblera à quelque chose comme ceci:
UART_HandleTypeDef huart1;
Le reste est dans l'exemple de leur répertoire \ <Nom du package> \ Projets \ <Nom de la carte> \ Exemples \ UART .
Par exemple, project \ STM32Cube_FW_H7_V1.8.0 \ Projects \ STM32H747I-DISCO \ Examples \ UART \ UART_WakeUpFromStopUsingFIFO .
Dans la fonction main (), il y a une initialisation de l'UART lui-même (il vous suffit de vous assurer que la vitesse est de 9600, sinon, entrez-la). La connexion avec les jambes est configurée dans un autre fichier, dans la fonction
void HAL_UART_MspInit (UART_HandleTypeDef * huart) .
Je préfère tout mettre dans une seule fonction. Le temps étant limité, je n'ai pas cherché à compiler une telle fonction à partir de ces matériaux, en la plaçant dans le fichier main.c et en n'oubliant pas de l'appeler depuis la fonction 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 , . .Eh bien, les interruptions sont simples. Nous recherchons un fichier avec le suffixe _it.c dans l'exemple et transférons les lignes UART dans le fichier avec le suffixe _it de notre projet.
Dans ce cas, du fichier
\ STM32Cube_FW_H7_V1.8.0 \ Projects \ STM32H747I-DISCO \ Examples \ UART \ UART_WakeUpFromStopUsingFIFO \ CM7 \ Src \ stm32h7xx_it.c
vers le fichier
\ STM32Cube_FW_H7.0WF1.8.0F. \ STemWin \ Demo_H747 \ CM7 \ Core \ Src \ stm32h7xx_it.c
transférez le fragment:
extern UART_HandleTypeDef huart1;
…
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
Tout.
4.2 Modification de la fonction de travail principale
Avec la fonction de travail principale, en principe, tout est plus simple. Bien que, pas en principe, et en particulier - pas entièrement, mais nous en parlerons ci-dessous. Pour l'instant, voyons simplement quelle fonction est appelée à la fin de la fonction principale. Dans ce cas, ce sont:
MainTask();
Cela signifie que le travail principal y est effectué. Nous remplaçons simplement son corps par un exemple typique tiré de notre site.
4.3 Quelle est la prochaine étape?
De plus, vous pouvez transporter des exemples d'autres équipements, comme nous venons de le faire avec l'équipement UART. Certes, le contrôle du fonctionnement de cet équipement sort du cadre de cet article. Comme vous pouvez le voir, le contrôle typique sur la page WEB est uniquement pour l'image et pour un UART. Le reste est transmis un peu plus difficile. Néanmoins, je ne peux pas m'empêcher de vous dire comment j'ai été une fois chargé de créer un générateur de code Morse basé sur la carte STM32G474RE DPOW1 Discovery en une soirée . Une soirée à développer à partir de zéro sur un tableau inconnu ne vous dispense pas de lire des centaines de pages de documentation. Si le projet était fait pendant des siècles, je commencerais simplement à prouver à la direction que ce n'est pas juste et que tout doit être soigneusement étudié. Mais le projet avait également un cycle de vie court. J'ai donc décidé de suivre la voie de l'extraction d'exemples.
Donc, pour le code Morse, vous avez besoin d'un sinus avec une fréquence de 1 KHz ... Avec le mouvement habituel de la main, décompressez le fichier en.stm32cubeg4_v1-3-0.zip et examinez le répertoire D: \ tmp \ STM32Cube_FW_G4_V1.3.0 \ Projects \ B-G474E-DPOW1 \ Exemples ... Et rien de bon là-bas not found ...
Il n'y a rien d'utile dans le répertoire DAC.
Est-ce la fin? Pas vraiment. Regardons des exemples d'autres cartes avec le même cristal (bien que dans d'autres packages) ... Et c'est la beauté que nous trouvons pour la carte Nucleo!
La beauté est que dans le fichier main.c, il y a une table pour générer le sinus:
/* 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};
Nous vérifions et nous assurons que oui. Cet exemple génère un sinus ou un triangle à la sortie DAC. Et juste avec une fréquence de 1 KHz. Alors c'est super! Le temps étant limité, je n'ai même pas pris la peine de lire une théorie. Je me suis juste assuré que toute la formation se déroule au niveau matériel en jetant un coup d'œil rapide au code. Après cela, dans le projet, j'ai remplacé le contrôleur par celui de la carte requise, assemblé, rempli, démarré et, après avoir exécuté la sonde de l'oscilloscope le long des jambes, j'ai trouvé celui sur lequel ce sinus est présent. Ensuite, je l'ai connecté à l'entrée des haut-parleurs, remplacé la génération d'un sinus ou d'un triangle par la génération d'un sinus ou d'un silence (oui, j'ai fait un autre tableau à partir de zéros seulement) ... Eh bien, écrire une partie appliquée avec du code Morse était aussi simple que de décortiquer des poires. Je me suis souvenu de ma jeunesse, du département militaire, du colonel Pavlov ...
En général, la technique "trouvez un exemple, insérez-le dans votre code" est assez efficace. Et l'approche «pour construire un exemple typique - télécharger une énorme bibliothèque» y contribue, car tous ces exemples de marque en font partie.
5. Problèmes d'unification
Un de mes collègues aime citer la déclaration philosophique suivante:
«En théorie, il n'y a pas de différence entre la théorie et la pratique. En pratique, ça l'est. "
Lorsque je travaillais avec un tas de STM32 différents, je m'en souvenais régulièrement. J'ai déjà parlé des UART forcément différents, mais il semblerait que le StemWin unifié ne devrait présenter aucune surprise ... Présenté!
5.1 STM32H747
La légende Hello World est dessinée. Mais lorsque je transfère le code de travail, je vois un écran bleu. C'est juste que nous dessinons d'abord un écran rouge pendant une seconde, puis un écran vert pendant une seconde, puis un écran bleu pendant une seconde, puis le travail commence. Si vous placez un point d'arrêt immédiatement après l'initialisation, même avant tout dessin, lorsqu'il est déclenché, les lectures de la minuterie du dernier démarrage sont visibles à l'écran. Ensuite, ils sont écrasés par le même écran bleu. Quoi?
Je supprime la sortie de trois couleurs d'une seconde, et ajoute immédiatement le travail. Cela fonctionne, mais il se fige rapidement pour toujours. Petit à petit, je découvre ce qui se fige après 37 millisecondes. Quel genre de temps magique est-ce? Une milliseconde est claire. Tique du système. Mais 37. Oui, au moins quelque chose de rond, proche ...
Combien de temps ou court, mais je découvre que tout est affiché dans le gestionnaire d'interruptionHAL_DSI_IRQHandler (DSI_HandleTypeDef * hdsi) . Il est appelé, tout est affiché, après quoi ses appels sont terminés. Tout est formé dans le tampon, mais n'apparaît pas à l'écran. Plus précisément, tout apparaît à l'écran deux fois dans la vie du programme. A l'initialisation (le même artefact d'une vie passée) et après 37 ms. Tout ce qui était entre, personne ne le verra.
Dans l'esprit - vous devez étudier la documentation et déterminer ce qui est quoi. Mais en fait - le temps pour la tâche n'est pas peu, mais très peu. Il est clair que l'interruption doit être provoquée, mais comment? J'essaye honnêtement d'appeler GUI_Exec (), bien que GUI_Delay () y soit de toute façon appelé ... Cela n'aide pas.
L'exemple est mort. C'est plutôt drôle là-bas. Hello World est imprimé comme il le fait dans les 37 premières ms. Et puis - un exemple mort. Ok, je vais prendre un exemple avec une animation du même catalogue. Il travaille. Peu à peu, je comprends ce qui doit en être retiré pour que notre exemple fonctionne ... Voici à quoi ressemble notre code typique:
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);
Eh bien, c'est logique! Et ça marche! .. Sur d'autres planches ... Mais après un tel montage, ça bougeait en quelque sorte sur le H747:
Le même texte.
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);
Mais en général, cela fonctionne, et en particulier - les écrans rouge et vert durent une seconde, et le bleu clignote et l'écran de travail apparaît immédiatement. Après un petit nombre d'expériences, il s'est avéré que tout commence à fonctionner pleinement sous cette forme:
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);
Voilà pour l'unification ... Il y avait un soupçon que le cadre était à blâmer:
/* Define the number of buffers to use (minimum 1) */
#define NUM_BUFFERS 3
Mais les expériences de correction n'ont pas donné un résultat idéal et le temps n'a pas permis d'en étudier les détails. Peut-être que quelqu'un dans les commentaires vous dira comment agir correctement, et cette section montre comment vous pouvez agir dans des conditions de temps de développement limité. Entre-temps, le code est resté dans un état si terrible. Heureusement, ce n'est pas un tutoriel, mais juste un exemple de code fonctionnel.
5.2 STM32F429
Ce tableau est vieux, qu'est-ce qui pourrait ne pas aller avec? Rudiments! À l'ancienne planche, des excroissances qui existent, mais qui ont depuis longtemps cessé de fonctionner, sortent. Exécutez l'exemple Hello World et voyez:
L'image pivote de 90 degrés par rapport à l'image typique. Qu'est-ce qui pourrait être plus facile? En 2016, en faisant glisser le firmware de l'imprimante 3D MZ3D d'Arduinka vers STM32F429, j'ai personnellement tourné l'image avec des paramètres simples. Allons. Comment ça va ici? Et voici les paramètres!
#define LCD_SWAP_XY 1
#define LCD_MIRROR_Y 1
Essayer de les changer, ça n'aide pas. Vérifier où ils sont utilisés ... Mais nulle part! Ils sont juste annoncés. Je soupçonne qu'ils n'étaient plus traités lorsque DMA2D a été mis en œuvre, mais je ne me porterai pas garant. Cependant, il y a la même fonction. Voici les conseils de dizaines de forums. J'ai utilisé cette fonction en 2016:
GUI_SetOrientation(GUI_SWAP_XY)
Certains ajoutent encore une constante de mise en miroir ... Mais pas le point. Cette fonction ne fonctionne pas en 2020! Ça ne marche pas et c'est tout! Et la bibliothèque est livrée sous forme d'objet, pourquoi cela ne fonctionne pas - personne ne le dira.
Eh bien, je comprends toujours les écrans. Je vais dans le fichier \ STM32F429-DISC1 \ Drivers \ BSP \ Components \ ili9341 \ ili9341.c (oui, il est protégé en écriture, mais il est facile à supprimer). La puce graphique y est configurée. Nous changeons.
Le même texte.
ili9341_WriteReg(LCD_MAC);
ili9341_WriteData(0xC8);
sur
Le même texte.
ili9341_WriteReg(LCD_MAC);
ili9341_WriteData(0x48|0x20);
L'image, bien sûr, tourne ... Mais le tampon est clairement configuré un peu incorrectement:
ce sont les dimensions:
#define XSIZE_PHYS 240
#define YSIZE_PHYS 320
n'affectent en aucun cas le travail. Il en va de même pour ce site:
#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240)
#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320)
Mais le site est plus intéressant:
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);
}
J'ai ajouté la négation pour le plaisir:
Le même texte.
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);
}
J'ai cette beauté.
J'ai eu une beauté similaire, mais pas exactement la même dans d'autres expériences, je ne me souviens plus ... Bref, nous arrivons tous à la même conclusion décevante. Nous devons nous asseoir et régler le problème ... Mais il n'y a pas de temps alloué pour la procédure. Que faire? Heureusement, j'ai réussi à obtenir la réponse à cette question de Google. En conséquence, le code typique de l'application de démonstration ressemble à ceci:
GUI_DispStringHCenterAt("www.all-hw.com", xSize / 2, 20);
Et pour F429 il faut le réduire à cette forme:
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);
La fonction de sortie du texte pivoté est utilisée. Cependant, pour cela, vous devez ajouter l'entité "rectangle". Eh bien, que pouvez-vous faire. Et le compteur doit être affiché non pas par la fonction d'impression d'un nombre, mais d'abord en formant une chaîne, et seulement ensuite en l'affichant sous une forme tournée. Mais sinon, tout s'est avéré presque universellement. Il est même possible, au contraire, d'afficher des textes partout de cette manière, mais pas d'indiquer le drapeau de rotation partout. Mais il me semble que ce sera déjà une perversion.
6. Conclusion
Nous avons examiné la méthodologie de développement de programmes typiques pour diverses cartes STM32, à la fois du point de vue du développeur et du point de vue de l'utilisateur qui a simplement téléchargé une application de démonstration pour sa carte et veut juste la construire sans penser à la physique. Nous avons également examiné des exemples montrant que, malheureusement, le degré d'unification du code est élevé, mais n'atteint pas cent pour cent. Les connaissances acquises peuvent être vérifiées en travaillant en alternance avec différentes cartes via le service All-Hardware, sans dépenser d'argent pour leur achat.
L'article montre comment trier les choses plutôt superficiellement. Cela vous permet de maîtriser rapidement une carte spécifique. Mais, bien sûr, plus vous traitez avec elle, plus vous en saurez plus. Lors de la résolution de problèmes réels, cela est extrêmement important, car les programmes complexes, dans lesquels l'auteur ne comprend pas la physique des processus, sont un chemin vers des erreurs dans les algorithmes. Je souhaite à tout le monde de tout maîtriser assez profondément. Oui, en utilisant le matériel du service Tout le matériel.