{"id":408,"date":"2024-02-15T13:12:22","date_gmt":"2024-02-15T12:12:22","guid":{"rendered":"https:\/\/redero.fr\/?p=408"},"modified":"2025-09-19T21:55:13","modified_gmt":"2025-09-19T19:55:13","slug":"du-schema-a-lapplication-bring-up-express","status":"publish","type":"post","link":"https:\/\/redero.fr\/?p=408","title":{"rendered":"Du sch\u00e9ma \u00e0 l\u2019application: bring-up logiciel express"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Je continue sur ma lanc\u00e9e d\u2019exp\u00e9rimenter diff\u00e9rents sc\u00e9narios d\u2019utilisation de Zephyr RTOS pour combiner entre eux l\u2019\u00e9lectronique et le logiciel applicatif.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dans cette optique, j\u2019ai sorti de mon tiroir une carte d\u2019\u00e9valuation obsol\u00e8te de chez ST, un <a href=\"https:\/\/www.st.com\/en\/evaluation-tools\/st25dv-discovery.html\">ST25DV-DISCOVERY<\/a> datant de 2016, que j\u2019avais r\u00e9cup\u00e9r\u00e9e d\u2019une op\u00e9ration rangement d\u2019un labo \u00e9lectronique. Cette carte comprend un \u00e9cran et un bouton \u00e0 4 directions fa\u00e7on joystick, j\u2019avais l\u2019id\u00e9e d\u2019en faire un mini-jeu fa\u00e7on arcade, sans \u00e9crire de code, esp\u00e9rant trouver un Pong ou un Tetris \u00e0 r\u00e9utiliser quelque part.<\/p>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a13dabd16cd7&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a13dabd16cd7\" class=\"wp-block-image aligncenter size-medium wp-duotone-unset-1 wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"171\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/st25dv_mb1283_disco-300x171.png\" alt=\"\" class=\"wp-image-624\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/st25dv_mb1283_disco-300x171.png 300w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/st25dv_mb1283_disco-1024x584.png 1024w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/st25dv_mb1283_disco-768x438.png 768w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/st25dv_mb1283_disco.png 1094w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Par chance, ma carte a le bon go\u00fbt d\u2019avoir un STM32 et tous ses p\u00e9riph\u00e9riques sont d\u00e9j\u00e0 support\u00e9s par Zephyr, ce qui me permet de me concentrer sur la partie couture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quelques liens utiles avant de commencer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Le <a href=\"https:\/\/www.st.com\/resource\/en\/user_manual\/um2096-getting-started-with-st25dvdiscovery-stmicroelectronics.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">sch\u00e9ma du kit, page 11 (MB1283)<\/a> <\/li>\n\n\n\n<li>Le <a href=\"https:\/\/github.com\/everedero\/zephyr_lvgl_2048_st25dv\" target=\"_blank\" rel=\"noreferrer noopener\">repo du projet<\/a><\/li>\n\n\n\n<li>La <a href=\"https:\/\/cdn-shop.adafruit.com\/datasheets\/ILI9341.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">datasheet de l\u2019\u00e9cran<\/a><\/li>\n\n\n\n<li>La <a href=\"https:\/\/media.digikey.com\/pdf\/data%20sheets\/st%20microelectronics%20pdfs\/stmpe811.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">datasheet du contr\u00f4leur de pav\u00e9 tactile<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">C\u2019est parti !<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">\u00c9cran LCD<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Erreur 404 : datasheet inexistante<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Faire fonctionner cet \u00e9cran est le plus gros morceau du projet, d\u2019autant que je ne m\u2019y connais pas beaucoup en \u00e9crans LCD. Je trouve beaucoup de pi\u00e8ces qui ne sont pas vendues sur \u00e9tag\u00e8re, et les datasheets sont difficiles \u00e0 se procurer sans passer par le distributeur ou le fabricant.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Les \u00e9crans sont g\u00e9n\u00e9ralement vendus sous forme de modules, avec un contr\u00f4leur int\u00e9gr\u00e9 permettant de leur parler par des bus s\u00e9rie comme I2C ou SPI, ou parall\u00e8les comme le MIPI DSI. La plupart des r\u00e9f\u00e9rences poss\u00e8dent des drivers compatibles, peut-\u00eatre parce-qu\u2019elles utilisent les m\u00eames r\u00e9f\u00e9rences de contr\u00f4leurs, mais comment savoir quel driver compatible utiliser sans d\u00e9monter le module d\u2019\u00e9cran ? Pour ce projet, j\u2019ai le code source original du kit, je peux simplement aller farfouiller dans le code, et je finis par trouver le nom d\u2019un \u00e9quivalent bien connu, le Ilitek ILI9341.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cet \u00e9quivalent est propos\u00e9 dans les catalogues Adafruit \/Sparkfun et il est bien connu et document\u00e9.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Autre d\u00e9couverte du monde des \u00e9crans, le pilote Zephyr d\u2019\u00e9cran LCD SPI a \u00e9t\u00e9 r\u00e9cemment renomm\u00e9 \u00ab\u00a0MIPI DBI\u00a0\u00bb. Un standard inconnu au bataillon en ce qui me concerne, mais de ce que j\u2019en comprends, c\u2019est un standard de commande d\u2019\u00e9cran LCD bas\u00e9 sur un bus SPI, plus deux pins suppl\u00e9mentaires : un reset et une pin de s\u00e9lection entre commande et data. Il a l\u2019air d\u2019\u00eatre standard de facto, mais n\u2019est mentionn\u00e9 nulle part, il y a sans doute une histoire technologique fascinante entrem\u00e9l\u00e9e de strat\u00e9gie g\u00e9opolitique, mais je d\u00e9cide d\u2019arr\u00eater de me poser des questions car j\u2019ai un Pong \u00e0 r\u00e9aliser.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">DC, WR, DCX, TE, SDA, WTF<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Comment remplir notre device tree ? Notre driver prend comme param\u00e8tres un bus SPI, ainsi que deux GPIOs, une \u00ab\u00a0reset\u00a0\u00bb et une \u00ab\u00a0dc\u00a0\u00bb, dc comme \u00ab\u00a0data \/ commande\u00a0\u00bb.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-2\"><img loading=\"lazy\" decoding=\"async\" width=\"417\" height=\"228\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_module.png\" alt=\"\" class=\"wp-image-421\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_module.png 417w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_module-300x164.png 300w\" sizes=\"auto, (max-width: 417px) 100vw, 417px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 \u00e9cran<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-3\"><img loading=\"lazy\" decoding=\"async\" width=\"762\" height=\"203\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel.png\" alt=\"\" class=\"wp-image-422\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel.png 762w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel-300x80.png 300w\" sizes=\"auto, (max-width: 762px) 100vw, 762px\" \/><figcaption class=\"wp-element-caption\"><em>Top level du sch\u00e9ma<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-4\"><img loading=\"lazy\" decoding=\"async\" width=\"472\" height=\"311\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_soc.png\" alt=\"\" class=\"wp-image-423\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_soc.png 472w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_soc-300x198.png 300w\" sizes=\"auto, (max-width: 472px) 100vw, 472px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 STM32<\/em><\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>        mipi_dbi {\n                compatible = \"zephyr,mipi-dbi-spi\";\n                reset-gpios = &lt;&amp;gpioc 1 GPIO_ACTIVE_HIGH&gt;;\n                dc-gpios = &lt;&amp;gpioc 0 GPIO_ACTIVE_HIGH&gt;;\n                spi-dev = &lt;&amp;spi2&gt;;\n                &#091;...]\n        };<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\"><em>boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il s\u2019agit donc du bus SPI 2, mais le MISO n\u2019est pas connect\u00e9. MOSI est c\u00e2bl\u00e9, mais il est renomm\u00e9 en \u00ab\u00a0SDA\u00a0\u00bb au top level&#8230; et en fait ce changement n\u2019est pas juste un hasard de copier-coller, il indique que notre c\u00e2ble peut \u00eatre utilis\u00e9 de mani\u00e8re bidirectionnelle, et oui, il existe un <a href=\"https:\/\/en.wikipedia.org\/wiki\/Serial_Peripheral_Interface#Three-wire\">SPI bidirectionnel<\/a>, half-duplex, o\u00f9 le c\u00e2ble data est cens\u00e9 s\u2019appeller SISO ou MOMI.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-medium wp-duotone-unset-5\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Serial_Peripheral_Interface#Three-wire\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"199\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/spi_fun-300x199.png\" alt=\"\" class=\"wp-image-424\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/spi_fun-300x199.png 300w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/spi_fun-1024x681.png 1024w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/spi_fun-768x511.png 768w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/spi_fun.png 1176w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Mauvaise nouvelle, mes GPIOs s\u2019appellent WR et TE, je ne sais pas qui est qui. Apr\u00e8s lecture de la <a href=\"https:\/\/cdn-shop.adafruit.com\/datasheets\/ILI9341.pdf\">datasheet de l\u2019\u00e9quivalence ILI9341<\/a>, WR ressemble \u00e0 WRX, Write-Read, mais \u00e7a correspond \u00e0 un autre mode d\u2019utilisation de l\u2019\u00e9cran. C\u2019est une pin \u00e9galement utilis\u00e9e comme D\/CX, donc je retrouve le DC que je cherchais, et c\u2019est la GPIO PC0.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">WRX (DCX)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8211; 8080-I \/8080-II system (WRX): Serves as a write signal and writes data at the rising edge.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8211; 4-line system (D\/CX): Serves as command or parameter select.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">TE signifie Tearing Effect, et sert \u00e0 synchroniser l\u2019\u00e9criture de l\u2019\u00e9cran avec son rafra\u00eechissement. Ce n\u2019est pas le reset, mais j\u2019ai envie de contr\u00f4ler cette pin avec le driver, donc pourquoi pas la c\u00e2bler au reset pour qu\u2019elle reste \u00e0 son niveau bas tout du long, d\u2019o\u00f9 la GPIO PC1.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Param\u00e9trage du driver<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois notre bus MIPI DBI virtuel cr\u00e9\u00e9, nous ajoutons le driver de notre \u00e9cran, avec ses param\u00e8tres.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;zephyr\/dt-bindings\/display\/ili9xxx.h&gt;\n&#091;...]\n        mipi_dbi {\n                &#091;...]\n                write-only;\n\n                ili9341: ili9341@0 {\n                        compatible = \"ilitek,ili9341\";\n                        mipi-max-frequency = &lt;20000000&gt;;\n                        reg = &lt;0&gt;;\n                        pixel-format = &lt;ILI9XXX_PIXEL_FORMAT_RGB888&gt;; \/\/ 1\n                        rotation = &lt;0&gt;;\n                        width = &lt;240&gt;;\n                        height = &lt;320&gt;;\n                        duplex = &lt;0x800&gt;;\n            };\n        };<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\"><em>boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00ab\u00a0duplex = &lt;0x800&gt;\u00a0\u00bb permet de param\u00e9trer le bus en half-duplex, ce qui est n\u00e9cessaire dans notre cas puisque MISO n\u2019est pas l\u00e0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00ab\u00a0write-only\u00a0\u00bb permet d\u2019\u00e9viter les lectures au maximum, ce qui est pertinent dans notre cas pour \u00e9viter les embouteillages sur le bus.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">pixel-format, width, et height, ont fait l\u2019objet d\u2019essais et erreurs. Au d\u00e9part, mon format de pixel \u00e9tait \u00e0 0, et j\u2019avais des couleurs toutes bizarres, probl\u00e8me rapidement r\u00e9solu apr\u00e8s avoir chang\u00e9 cette valeur.<\/p>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a13dabd183ca&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a13dabd183ca\" class=\"wp-block-image size-large wp-duotone-unset-6 wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/bad_pixel_format-1024x768.jpeg\" alt=\"\" class=\"wp-image-516\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/bad_pixel_format-1024x768.jpeg 1024w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/bad_pixel_format-300x225.jpeg 300w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/bad_pixel_format-768x576.jpeg 768w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/bad_pixel_format.jpeg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\"><em>Couleurs psych\u00e9d\u00e9liques, contours sales : v\u00e9rifier le pixel-format<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">mipi-max-frequency permet de s\u00e9lectionner la fr\u00e9quence du bus SPI. Ici la valeur est maximale, il est int\u00e9ressant de la diminuer pour jouer avec son analyseur logique pr\u00e9f\u00e9r\u00e9.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois le tout param\u00e9tr\u00e9, il faut signifier \u00e0 Zephyr qui est l\u2019\u00e9cran.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>zephyr,display = &amp;ili9341;<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\"><em>boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sans oublier de demander \u00e0 cmake de compiler les fichiers sources des drivers, dans le prj.conf :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_DISPLAY=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\"><em>game\/prj.conf<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Un coup d\u2019oeil au protocole<\/strong><\/h3>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a13dabd18be6&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a13dabd18be6\" class=\"wp-block-image size-large wp-duotone-unset-7 wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"228\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture-1024x228.png\" alt=\"\" class=\"wp-image-409\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture-1024x228.png 1024w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture-300x67.png 300w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture-768x171.png 768w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture-1536x342.png 1536w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/logic_capture.png 1874w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Voici un exemple de transmission d\u2019image en SPI. Ici on envoie un bitmap dans un rectangle aux coordonn\u00e9es (X1, Y1, X2, Y1) :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CD passe \u00e0 0, pour envoyer une commande<\/li>\n\n\n\n<li>La commande 0x2A (Column Address Set, CASET) est envoy\u00e9e sur le bus SPI<\/li>\n\n\n\n<li>CD passe \u00e0 1 pour envoyer une donn\u00e9e<\/li>\n\n\n\n<li>Les coordonn\u00e9es X1 et X2 sont envoy\u00e9es sur le bus SPI<\/li>\n\n\n\n<li>De la m\u00eame mani\u00e8re, 0x2B (Page Address Set, PASET) est envoy\u00e9, suivi des coordonn\u00e9es Y1 et Y2<\/li>\n\n\n\n<li>La commande 0x2C est ensuite transmise, suivie de tous les octets du bitmap<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Le protocole complet est d\u00e9crit dans la <a href=\"https:\/\/cdn-shop.adafruit.com\/datasheets\/ILI9341.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">datasheet ILI9341<\/a>. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">L\u2019exemple \u00ab\u00a0display\u00a0\u00bb<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois l\u2019\u00e9cran correctement configur\u00e9, il est possible de le tester \u00e0 l\u2019aide d\u2019un petit exemple tout \u00e0 fait utile pr\u00e9sent dans les dossiers d\u2019exemples Zephyr, j\u2019ai nomm\u00e9 : samples\/drivers\/display.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-8\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/display_sample_without_issue-1024x768.jpg\" alt=\"\" class=\"wp-image-410\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/display_sample_without_issue-1024x768.jpg 1024w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/display_sample_without_issue-300x225.jpg 300w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/display_sample_without_issue-768x576.jpg 768w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/display_sample_without_issue.jpg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Pav\u00e9<\/strong> tactile r\u00e9sistif<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019\u00e9cran n\u2019est pas seulement un \u00e9cran, il dispose \u00e9galement d\u2019un pav\u00e9 tactile, mais un pav\u00e9 tactile r\u00e9sistif. Les smartphones nous ont habitu\u00e9s \u00e0 la technologie capacitive, celle \u00e0 base d\u2019indium (ITO), et j\u2019avais oubli\u00e9 cette technologie plus ancienne et moins agr\u00e9able \u00e0 utiliser, mais qui a le bon go\u00fbt de ne pas contenir de m\u00e9taux ultra-rares. M\u00eame si la pr\u00e9sence de boutons physiques m\u2019enthousiasme bien plus, je rajoute mon pav\u00e9 tactile au device tree.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-9\"><img loading=\"lazy\" decoding=\"async\" width=\"587\" height=\"127\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_module.png\" alt=\"\" class=\"wp-image-464\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_module.png 587w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_module-300x65.png 300w\" sizes=\"auto, (max-width: 587px) 100vw, 587px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 composant<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-10\"><img loading=\"lazy\" decoding=\"async\" width=\"485\" height=\"61\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_soc.png\" alt=\"\" class=\"wp-image-466\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_soc.png 485w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_soc-300x38.png 300w\" sizes=\"auto, (max-width: 485px) 100vw, 485px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 STM32<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-11\"><img loading=\"lazy\" decoding=\"async\" width=\"762\" height=\"203\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel-1.png\" alt=\"\" class=\"wp-image-467\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel-1.png 762w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_screen_toplevel-1-300x80.png 300w\" sizes=\"auto, (max-width: 762px) 100vw, 762px\" \/><figcaption class=\"wp-element-caption\"><em>Top level du sch\u00e9ma<\/em><\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>&amp;i2c1 {\n        pinctrl-0 = &lt;&amp;i2c1_scl_pb6 &amp;i2c1_sda_pb7&gt;;\n        pinctrl-names = \"default\";\n        status = \"okay\";\n        clock-frequency = &lt;I2C_BITRATE_FAST&gt;;\n\n        stmpe811: stmpe811@41 {\n                compatible = \"st,stmpe811\";\n                status = \"okay\";\n                reg = &lt;0x41&gt;;\n                int-gpios = &lt;&amp;gpiob 5 GPIO_ACTIVE_LOW&gt;;\n                &#091;...]\n        };\n};<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\"><em>boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le lecteur aura rep\u00e9r\u00e9 les correspondances entre notre SCL et la pin I2C1_SCL PB6, notre SDA et la pin I2C1_SCL PB7, et notre interruption sur PB5.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Adresse I2C<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Mais comment trouver cette valeur de 0x41 ? Encore une fois elle m\u2019a \u00e9t\u00e9 donn\u00e9e par le copier-coller, mais voici o\u00f9 aller la chercher dans la<a href=\"https:\/\/media.digikey.com\/pdf\/data%20sheets\/st%20microelectronics%20pdfs\/stmpe811.pdf\" target=\"_blank\" rel=\"noreferrer noopener\"> datasheet du STMPE811<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-default-filter\"><img loading=\"lazy\" decoding=\"async\" width=\"630\" height=\"232\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_stmpe811_i2c.png\" alt=\"\" class=\"wp-image-411\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_stmpe811_i2c.png 630w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_stmpe811_i2c-300x110.png 300w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>ADDR0 <\/td><td>Address<\/td><\/tr><tr><td>0<\/td><td>0x82<\/td><\/tr><tr><td>1<\/td><td>0x84<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Nous avons donc une pin ADDR0 qui est connect\u00e9e soit \u00e0 GND (valeur 0), soit \u00e0 VCC (valeur 1). Il faut donc aller voir comment est configur\u00e9e ADDR0 sur notre sch\u00e9ma. ADDR0 n\u2019existe pas, mais j\u2019ai une pin A0\/DATA_OUT. De retour dans la datasheet, A0\/DATA_OUT est d\u00e9crite comme ceci:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Pin<\/td><td>Name<\/td><td>Function<\/td><\/tr><tr><td>3<\/td><td>A0\/Data Out<\/td><td>I2C address in Reset, Data out in SPI mode (VCC domain)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A0 est d\u00e9crit comme \u00ab\u00a0I2C address\u00a0\u00bb, donc A0 et ADDR0 sont deux noms d\u00e9signant la m\u00eame pin.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-12\"><img loading=\"lazy\" decoding=\"async\" width=\"403\" height=\"418\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_touchscreen_i2caddr.png\" alt=\"\" class=\"wp-image-412\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_touchscreen_i2caddr.png 403w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_touchscreen_i2caddr-289x300.png 289w\" sizes=\"auto, (max-width: 403px) 100vw, 403px\" \/><figcaption class=\"wp-element-caption\"><em>0 ou 1 ?<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">R83, qui m\u00e8ne \u00e0 VCC, est not\u00e9 \u00ab\u00a0NC\u00a0\u00bb, \u00ab\u00a0Not Connected\u00a0\u00bb, donc \u00e0 priori, il n\u2019y a aucun composant coll\u00e9 ici. Je peux v\u00e9rifier que mon sch\u00e9ma dit vrai directement sur la carte:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-13\"><img loading=\"lazy\" decoding=\"async\" width=\"248\" height=\"175\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/no_r83.png\" alt=\"\" class=\"wp-image-413\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">R86, qui m\u00e8ne \u00e0 GND, est quant \u00e0 elle une r\u00e9sistance 0 \u03a9, \u00e9quivalent \u00e0 un fil, donc notre ADDR0 est \u00e9gal \u00e0 0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Et notre adresse dans le DTS est 0x41, et pas 0x82. Pourquoi ? Car Zephyr RTOS, \u00e0 l\u2019instar de Linux, utilise les adresses 7 bits pour l\u2019I2C, quand notre datasheet utilise manifestement la <a href=\"https:\/\/www.totalphase.com\/support\/articles\/200349176-7-bit-8-bit-and-10-bit-i2c-slave-addressing\/\" target=\"_blank\" rel=\"noreferrer noopener\">version 8 bits<\/a>. Le LSB de la version 8 bits est toujours un Read\/Write. Le driver va en fait utiliser 0x82 pour l\u2019\u00e9criture et 0x83 pour la lecture, mais ces valeurs sont s\u00e9lectionn\u00e9es automatiquement \u00e0 partir de la \u00ab\u00a0racine\u00a0\u00bb 7-bit qui est 0x41, 0x82 d\u00e9plac\u00e9 d\u2019un bit vers la droite. <\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-14\"><a href=\"https:\/\/www.totalphase.com\/support\/articles\/200349176-7-bit-8-bit-and-10-bit-i2c-slave-addressing\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"249\" height=\"85\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/i2c_addr.png\" alt=\"\" class=\"wp-image-414\"\/><\/a><\/figure>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Bonus: shell I2C<\/summary>\n<p class=\"wp-block-paragraph\">Si vous voulez v\u00e9rifier des adresses I2C rapidement, il est possible de scanner le bus avec une commande shell.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Activez le shell et ses options :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_SHELL=y\nCONFIG_I2C=y\nCONFIG_I2C_SHELL=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois connect\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uart:~$ device list\ndevices:\n&#091;...]\n- i2c@40005400 (READY)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>uart:~$ i2c scan i2c@40005400\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:             -- -- -- -- -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n40: -- 41 -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n70: -- -- -- -- -- -- -- --                         \n1 devices found on i2c@40005400<\/code><\/pre>\n<\/details>\n\n\n\n<h3 class=\"wp-block-heading\">Niveau de l\u2019interruption<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Notez bien, ici c\u2019est \u00ab\u00a0@41\u00a0\u00bb au sens de \u00ab\u00a0@0x41\u00a0\u00bb et pas de 41 en d\u00e9cimal, m\u00eame syntaxe que les device trees en Linux.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Autre d\u00e9tail, notre interruption sur PB5, est-elle active niveau haut ou bas ? La datasheet nous dit qu\u2019elle est drain ouvert, sans mention de polarit\u00e9.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Pin<\/td><td>Name<\/td><td>Function<\/td><\/tr><tr><td>2<\/td><td>INT<\/td><td>Interrupt output (VCC domain), open drain<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-15\"><img loading=\"lazy\" decoding=\"async\" width=\"541\" height=\"242\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_int.png\" alt=\"\" class=\"wp-image-415\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_int.png 541w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_capscreen_int-300x134.png 300w\" sizes=\"auto, (max-width: 541px) 100vw, 541px\" \/><figcaption class=\"wp-element-caption\"><em>Extrait de sch\u00e9ma du SMTPE811<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">L\u2019\u00e9lectronicien n\u2019a pas oubli\u00e9 d\u2019ajouter une pull-up, par d\u00e9faut cette pin sera \u00e0 1, donc il faudra que logiciellement elle soit active \u00e0 l\u2019\u00e9tat bas. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Si elle \u00e9tait active \u00e0 l\u2019\u00e9tat haut, c\u00f4t\u00e9 stmpe811, vous forceriez \u00e0 1 une sortie qui \u00e9tait d\u00e9j\u00e0 \u00e0 1, et comme nous sommes \u00e0 drain ouvert, le 0 logique correspondrait \u00e0 la laisser vivre sa vie&#8230; donc elle serait \u00e0 1 aussi.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Niveau logique<\/td><td>0<\/td><td>1<\/td><\/tr><tr><td>Niveau \u00e9lectrique<\/td><td>1<\/td><td>1<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\"><em>Une table de v\u00e9rit\u00e9 trop nulle<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Un peu plus loin, la datasheet nous indique que la polarit\u00e9 est un param\u00e8tre \u00e0 s\u00e9lectionner dans le registre INT_CTRL (0x09) :<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">[2] INT_POLARITY: This bit sets the INT pin polarity<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1: Active high\/rising edge<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">0: Active low\/falling edge<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">La valeur par d\u00e9faut de ce registre est 0x00, donc le 3\u00e8me bit du registre est 0, donc il me reste \u00e0 v\u00e9rifier que le driver ne s\u2019amuse pas \u00e0 changer cette valeur pour que tout se passe bien.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dans le driver du STMPE811 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define STMPE811_INT_CTRL_REG         0x09U\n&#091;...]\n#define STMPE811_INT_CTRL_BIT_GLOBAL_INT BIT(0)\n&#091;...]\n    \/* Enable global interrupts *\/\n    err = i2c_reg_write_byte_dt(&amp;config-&gt;bus, \n                  STMPE811_INT_CTRL_REG,\n                  STMPE811_INT_CTRL_BIT_GLOBAL_INT);\n&#091;...]<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">zephyrproject\/zephyr\/drivers\/input\/input_stmpe811.c<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On \u00e9crit \u00ab\u00a0BIT(0)\u00a0\u00bb, c\u2019est-\u00e0-dire 1, dans le registre, et le reste des bits reste \u00e0 0, dont notre fameux 3\u00e8me bit. Le driver est d\u2019accord pour \u00eatre actif \u00e0 l\u2019\u00e9tat bas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pour demander \u00e0 ce que l\u2019on compile les drivers d\u2019entr\u00e9e :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_INPUT=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>B<\/strong>outon 4 directions + 1 clic<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Il ne s\u2019agit pas d\u2019un joystick puisqu\u2019il n\u2019est pas analogique, mais d\u2019un astucieux petit bouton poussoir avec 4 directions et un clic vertical.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-16\"><img loading=\"lazy\" decoding=\"async\" width=\"737\" height=\"499\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_comp.png\" alt=\"\" class=\"wp-image-416\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_comp.png 737w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_comp-300x203.png 300w\" sizes=\"auto, (max-width: 737px) 100vw, 737px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 composant<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-17\"><img loading=\"lazy\" decoding=\"async\" width=\"401\" height=\"109\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_soc.png\" alt=\"\" class=\"wp-image-417\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_soc.png 401w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_soc-300x82.png 300w\" sizes=\"auto, (max-width: 401px) 100vw, 401px\" \/><figcaption class=\"wp-element-caption\"><em>Sch\u00e9ma c\u00f4t\u00e9 STM32<\/em> &#8211;<em> pas de top-level, c\u2019est la m\u00eame page<\/em><\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>        buttons: gpio_keys {\n                compatible = \"gpio-keys\";\n                sel_button: button_2 {\n                        label = \"Sel\";\n                        gpios = &lt;&amp;gpioe 8 GPIO_ACTIVE_LOW&gt;;\n                };\n                left_button: button_3 {\n                        label = \"Left\";\n                        gpios = &lt;&amp;gpioe 9 GPIO_ACTIVE_LOW&gt;;\n                };\n                right_button: button_4 {\n                        label = \"Right\";\n                        gpios = &lt;&amp;gpioe 11 GPIO_ACTIVE_LOW&gt;;\n                };\n                up_button: button_5 {\n                        label = \"Up\";\n                        gpios = &lt;&amp;gpioe 10 GPIO_ACTIVE_LOW&gt;;\n                };\n                down_button: button_6 {\n                        label = \"Down\";\n                        gpios = &lt;&amp;gpioe 12 GPIO_ACTIVE_LOW&gt;;\n                };\n        };<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">boards\/st25dv_lvgl.overlay<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Attendez, PE11 est JOY_UP sur le sch\u00e9ma et \u00ab\u00a0right\u00a0\u00bb dans le DTS, tandis que PE10 est JOY_RIGHT sur le sch\u00e9ma et \u00ab\u00a0up\u00a0\u00bb dans le DTS ? Non je n\u2019ai pas fait d\u2019erreur, l\u2019erreur est dans la saisie de composant, dont <a href=\"http:\/\/www.hy1688.com.tw\/SWITCH\/TACT%20SWITCH\/TACT_File\/MT-008A.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">voici la datasheet<\/a>. Si on d\u00e9cide que la pin A est \u00ab\u00a0LEFT\u00a0\u00bb, puisque nous sommes libres de placer ce composant comme nous voulons, alors l\u2019ordre des pins dans le sens horaire est LEFT, UP, RIGHT, DOWN, ce qui correspond \u00e0 A(1), B(4), D(6) et C(3).<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-19 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large wp-duotone-default-filter\"><img loading=\"lazy\" decoding=\"async\" width=\"232\" height=\"128\" data-id=\"419\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_button2.png\" alt=\"\" class=\"wp-image-419\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-18\"><img loading=\"lazy\" decoding=\"async\" width=\"347\" height=\"205\" data-id=\"418\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_button.png\" alt=\"\" class=\"wp-image-418\" srcset=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_button.png 347w, https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/datasheet_button-300x177.png 300w\" sizes=\"auto, (max-width: 347px) 100vw, 347px\" \/><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\"><em>Datasheet<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full wp-duotone-unset-20\"><img loading=\"lazy\" decoding=\"async\" width=\"123\" height=\"139\" src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/sch_joy_zoom_pin.png\" alt=\"\" class=\"wp-image-475\"\/><figcaption class=\"wp-element-caption\"><em>Composant<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Il est possible d\u2019indiquer \u00e0 Zephyr quels codes sont associ\u00e9s \u00e0 quelles touches, avec zephyr,code.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;zephyr\/dt-bindings\/input\/input-event-codes.h&gt;\n&#091;...]\n                left_button: button_3 {\n                        label = \"Left\";\n                        gpios = &lt;&amp;gpioe 9 GPIO_ACTIVE_LOW&gt;;\n                        zephyr,code = &lt;INPUT_KEY_LEFT&gt;;\n                };<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ces codes sont peu ou prou les m\u00eames que sous Linux, si vous faites un \u00ab\u00a0evtest\u00a0\u00bb, vous aurez code 103 (KEY_UP) et code 108 (KEY_DOWN), en d\u00e9cimal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Dans input-event-codes.h :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define INPUT_KEY_LEFT 105 \/**&lt; Left Key *\/\n#define INPUT_KEY_DOWN 108 \/**&lt; Down Key *\/<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">zephyrproject\/zephyr\/include\/zephyr\/dt-bindings\/input\/input-event-codes.h<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pour que les drivers ad\u00e9quats soient compil\u00e9s, on n\u2019oublie pas le prj.conf :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_GPIO=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Bonus: shell GPIO<\/summary>\n<p class=\"wp-block-paragraph\">Le shell est d\u2019une grande aide pour d\u00e9bogguer les GPIOs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Activez le shell et ses options :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_SHELL=y\nCONFIG_GPIO=y\nCONFIG_GPIO_SHELL=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois connect\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uart:~$ gpio info \nLine         Reserved Device           Pin\n                         gpio@40020000     0\n                         gpio@40020000     1\n                         gpio@40020000     2\n                         gpio@40020000     3\n&#091;...]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je ne connais pas les adresses de registre par coeur, mais l\u2019information est rapide \u00e0 retrouver dans la datasheet ou dans le fichier DTS pr\u00e9-build\u00e9, zephyr.dts.pre:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>   gpioc: gpio@40020800 {\n    compatible = \"st,stm32-gpio\";\n    gpio-controller;\n    #gpio-cells = &lt;2&gt;;\n    reg = &lt;0x40020800 0x400&gt;;\n    clocks = &lt;&amp;rcc 0x030 0x00000004&gt;;\n   };  <\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">build\/zephyr\/zephyr.dts.pre<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je veux v\u00e9rifier que j\u2019ai la bonne GPIO et le bon niveau  pour mon bouton bleu, \u00e0 savoir :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>gpios = &lt;&amp;gpioc 14 GPIO_ACTIVE_LOW&gt;;<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">boards\/arm\/st25dv_mb1283_disco\/st25dv_mb1283_disco.dts<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quand le bouton est rel\u00e2ch\u00e9 :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uart:~$ gpio get gpio@40020800 14\n1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vous connaissez la gymnastique pour appuyer sur le bouton et invoquer la commande shell en m\u00eame temps :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uart:~$ gpio get gpio@40020800 14\n0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Mon bouton est donc correctement param\u00e9tr\u00e9 !<\/p>\n<\/details>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Le middleware : LVGL<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Plomberie et pseudo-drivers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois tout mon hardware c\u00e2bl\u00e9 et fonctionnel, j\u2019ai envie de tester LVGL, le module graphique dont tout le monde parle.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">LVGL va trouver l\u2019\u00e9cran tout seul puisque nous avons indiqu\u00e9 un zephyr,display, mais il reste quelques pseudo-drivers \u00e0 d\u00e9finir pour connecter le syst\u00e8me Zephyr au module LVGL.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;zephyr\/dt-bindings\/input\/input-event-codes.h&gt;\n#include &lt;zephyr\/dt-bindings\/lvgl\/lvgl.h&gt;\n\n\/ {\n        pointer {\n                compatible = \"zephyr,lvgl-pointer-input\";\n                input = &lt;&amp;stmpe811&gt;;\n                invert-y;\n        };\n\n        keypad {\n                compatible = \"zephyr,lvgl-keypad-input\";\n                input = &lt;&amp;buttons&gt;;\n                input-codes = &lt;INPUT_KEY_RIGHT INPUT_KEY_LEFT INPUT_KEY_UP INPUT_KEY_DOWN INPUT_KEY_ENTER&gt;;\n                lvgl-codes =  &lt;LV_KEY_DOWN LV_KEY_UP LV_KEY_RIGHT LV_KEY_LEFT LV_KEY_ENTER&gt;;\n        };\n};<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">boards\/st25dv_lvgl.overlay<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remarquez les petites adaptations r\u00e9alis\u00e9es : invert-y permet de remettre le pav\u00e9 tactile dans le m\u00eame sens que l\u2019\u00e9cran. Une rotation de 90\u00b0 dans l\u2019affectation des boutons est \u00e9galement r\u00e9alis\u00e9e en rempla\u00e7ant leurs noms.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En plus du tr\u00e8s attendu:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_LVGL=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il y a tout un tas de param\u00e8tres \u00e0 ajouter au prj.conf pour le bon fonctionnement du logiciel, \u00e0 aller chercher dans la documentation et dans les exemples.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Drivers d\u2019entr\u00e9es dans LVGL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Par d\u00e9faut, LVGL s\u00e9lectionne comme p\u00e9riph\u00e9rique d\u2019entr\u00e9e les touchpads et \u00e9crans tactiles, contr\u00f4l\u00e9s par le pseudo-driver \u00ab\u00a0zephyr,lvgl-pointer-input\u00a0\u00bb. Les autres p\u00e9riph\u00e9riques d\u2019entr\u00e9es doivent \u00eatre s\u00e9lectionn\u00e9s en plus, dans mon cas, mon bouton pseudo-joystick est g\u00e9r\u00e9 par le driver de claviers, \u00e0 activer avec :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_LV_Z_KEYPAD_INPUT=y<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/prj.conf<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pour tester le tout, un petit exemple capable d\u2019afficher des chiffres et de se d\u00e9placer avec le bouton directionnel : zephyrproject\/zephyr\/samples\/subsys\/display\/lvgl<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"1280\" style=\"aspect-ratio: 720 \/ 1280;\" width=\"720\" controls src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/hw_button_sample2.mp4\"><\/video><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Et maintenant, une application<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Je suis dor\u00e9navant libre d\u2019aller chercher ce que je veux dans toutes les applications LVGL, je rep\u00e8re un <a href=\"https:\/\/github.com\/100askTeam\/lv_lib_100ask.git\" target=\"_blank\" rel=\"noreferrer noopener\">projet Github LVGL avec un 2048 dedans<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quelques copier-collers et adaptations mineures plus tard, le 2048 s\u2019affiche sur mon \u00e9cran, mais je n\u2019ai qu\u2019un contr\u00f4le tactile, et le swipe sur un \u00e9cran tactile r\u00e9sistif&#8230; c\u2019est l\u2019inverse du fun.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Les interruptions des boutons \u00e9taient bien lues dans mon syst\u00e8me, mais impossible de jumper dans \u00ab\u00a0lv_100ask_2048_event\u00a0\u00bb, la gestion des \u00e9v\u00e8nements de mon application LVGL. Pourtant la fonction est pr\u00eate \u00e0 g\u00e9rer l\u2019apparition d\u2019un \u00e9v\u00e8nement de type appui bouton :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  else if(code == LV_EVENT_KEY)\n    {\n        game_2048-&gt;game_over = game_over(game_2048-&gt;matrix);\n        if (!game_2048-&gt;game_over)\n        {\n            switch(*((uint8_t *)lv_event_get_param(e)))\n            {\n                case LV_KEY_UP:\n                    success = move_left(&amp;(game_2048-&gt;score),           game_2048-&gt;matrix);\n                    break;<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/src\/lv_100ask_2048.c<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Il se trouve qu\u2019il manquait \u00e0 mon code quelques lignes :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    lv_group_t *btn_matrix_group;\n    btn_matrix_group = lv_group_create();\n    lv_group_add_obj(btn_matrix_group, game_2048-&gt;btnm);\n    lv_indev_set_group(lvgl_input_get_indev(lvgl_keypad), btn_matrix_group);<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-right has-small-font-size wp-block-paragraph\" style=\"margin-top:0;margin-bottom:0\">game\/src\/lv_100ask_2048.c<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ces lignes cr\u00e9ent un groupe de widgets, y ajoutent le widget principal du 2048 (game_2048-&gt;btnm), et lient le groupe ainsi cr\u00e9\u00e9 avec mon p\u00e9riph\u00e9rique d\u2019entr\u00e9e, lvgl_keypad. Et l\u00e0 \u00e7a marche bien mieux, puisque l\u2019\u00e9v\u00e8nement de clic bouton est transmis par le groupe au gestionnaire d\u2019\u00e9v\u00e8nements.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">J\u2019aurais pr\u00e9f\u00e9r\u00e9 un Tetris&#8230;. mais j\u2019ai appris de nouvelles technologies, j\u2019ai un 2048 portatif, j\u2019ai eu l\u2019occasion d\u2019aller harceler la communaut\u00e9 Zephyr avec mes probl\u00e8mes improbables (merci \u00e0 eux !), j\u2019ai gagn\u00e9 mon badge de contributeur\u2022ice, et j\u2019ai une justification pour garder des \u00e9lectroniques obsol\u00e8tes dans mon tiroir : c\u2019\u00e9tait un beau projet.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"720\" style=\"aspect-ratio: 1280 \/ 720;\" width=\"1280\" controls src=\"https:\/\/redero.fr\/wp-content\/uploads\/2024\/02\/stm_2048.mp4\"><\/video><figcaption class=\"wp-element-caption\">\u00c0 retrouver sur <a href=\"https:\/\/github.com\/everedero\/zephyr_lvgl_2048_st25dv\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/everedero\/zephyr_lvgl_2048_st25dv<\/a><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Mise \u00e0 jour : la carte a \u00e9t\u00e9 merg\u00e9e dans le repo principal, vous pouvez dor\u00e9navant utiliser \u00ab\u00a0st25dv_mb1283_disco\u00a0\u00bb !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je refais tout le software embarqu\u00e9 d\u2019un kit d\u2019\u00e9valuation avec mon nouvel RTOS pr\u00e9f\u00e9r\u00e9, en repartant du sch\u00e9ma, jusqu\u2019\u00e0 avoir un petit jeu fonctionnel.<\/p>\n","protected":false},"author":1,"featured_media":434,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"[]"},"categories":[37],"tags":[56,54,29,25],"class_list":["post-408","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-lvgl","tag-stm32","tag-video","tag-zephyr"],"_links":{"self":[{"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/posts\/408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/redero.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=408"}],"version-history":[{"count":90,"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/posts\/408\/revisions"}],"predecessor-version":[{"id":1304,"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/posts\/408\/revisions\/1304"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/redero.fr\/index.php?rest_route=\/wp\/v2\/media\/434"}],"wp:attachment":[{"href":"https:\/\/redero.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redero.fr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redero.fr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}