-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprogrammateur-eeprom-diy-arduino.html
356 lines (243 loc) · 32 KB
/
programmateur-eeprom-diy-arduino.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Pour un projet, que vous verrez dans mon prochain article, j’avais besoin d’utiliser de la mémoire flash mais je n’avais pas de programmateur.Souhaitant prop...">
<link type="application/atom+xml" rel="alternate" href="https://elrindel.github.io/feed.xml" title="Elrindel/Flob Blog" />
<title>Programmer une mémoire Flash (EEPROM) 32 broches avec un Arduino | Elrindel/Flob Blog</title>
<meta property="og:title" content="Programmer une mémoire Flash (EEPROM) 32 broches avec un Arduino" />
<meta property="og:locale" content="fr_FR" />
<link rel="canonical" href="https://elrindel.github.io/programmateur-eeprom-diy-arduino" />
<meta property="og:url" content="https://elrindel.github.io/programmateur-eeprom-diy-arduino" />
<meta property="og:site_name" content="Elrindel/Flob Blog" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2020-07-18T10:03:32+02:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Programmer une mémoire Flash (EEPROM) 32 broches avec un Arduino" />
<link rel="shortcut icon" href="/favicon.ico" type="image/icon">
<link rel="icon" href="/favicon.ico" type="image/icon">
<link rel="stylesheet" type="text/css" href="/assets/css/style.css?v=1.0.4">
<link rel="stylesheet" type="text/css" href="/assets/css/simpleLightbox.min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/highlight-theme.css">
<link rel="stylesheet" type="text/css" href="/assets/css/rouge-code.css">
</head>
<body>
<header id="header">
<div class="container">
<h1 class="title">
<a href="/">Elrindel/Flob</a>
</h1>
<nav>
<ul>
<li><a href="/">Accueil</a></li>
<li><a href="https://github.com/Elrindel/" target="_blank">Github</a></li>
<li><a href="/liens">Liens</a></li>
<li><a href="/bin-dec-hex-converter">Bin Converter</a></li>
</ul>
</nav>
</div>
</header>
<section id="main">
<div class="container sidebar">
<article>
<header>
<h1>Programmer une mémoire Flash (EEPROM) 32 broches avec un Arduino</h1>
<p class="metas">Publié le : <b>18 Jul 2020</b> Catégories : <b>DIY</b></p>
</header>
<p>Pour un projet, que vous verrez dans mon prochain article, j’avais besoin d’utiliser de la mémoire flash mais je n’avais pas de programmateur.</p>
<p>Souhaitant proposer une solution facilement accessible (sans devoir acheter un programmateur à 50€ minimum), je me suis documenté pour programmer ma mémoire flash avec le matériel déjà en ma possession et qu’on retrouve chez beaucoup de bidouilleurs.</p>
<p>J’avais le choix entre un <code class="language-plaintext highlighter-rouge">Raspberry Pi</code> et un <code class="language-plaintext highlighter-rouge">Arduino Uno</code>.<br />
J’ai une grosse préférence pour l’<strong>Arduino</strong>. De plus, il s’avère que les mémoires que je dois programmer fonctionnent sous une tension de <strong>5V</strong>, ce qui est le cas de mon <code class="language-plaintext highlighter-rouge">Arduino Uno</code>.<br />
Le <strong>Raspberry Pi</strong> aurait compliqué les choses avec les <strong>3.3V</strong> des GPIO.<br />
D’ailleurs assurez vous de pas raccorder une mémoire <strong>3.3V</strong> sur du <strong>5V</strong> au risque de la griller.</p>
<p>C’est donc l’<code class="language-plaintext highlighter-rouge">Arduino Uno</code> qui me servira de programmateur d’<strong>EEPROM</strong> !</p>
<h2 id="solutions-existantes">Solutions existantes</h2>
<p>Il est important de préciser que je veux programmer des mémoires de <strong>512Ko</strong> via une interface <code class="language-plaintext highlighter-rouge">parallèle</code> ce qui implique d’avoir des <strong>mémoires flash</strong> avec au moins <strong>32 broches</strong> (voir ci-dessous pour les détails).</p>
<p>Evidemment je suis pas le premier à me dire qu’on peut programmer des <strong>EEPROM</strong> avec un <code class="language-plaintext highlighter-rouge">Arduino Uno</code> et j’ai effectivement trouvé deux ou trois projets à ce sujet sur internet.<br />
Ces derniers sont soit foireux, soit leur code me plait pas, soit ils sont incomplets … J’ai donc décidé de faire ma propre version que je vais vous partager ici !</p>
<h3 id="comment-lire-et-écrire-une-mémoire-flash-">Comment lire et écrire une mémoire flash ?</h3>
<p>Comme évoqué ci-dessus, je vais utiliser des mémoires avec une interface <code class="language-plaintext highlighter-rouge">parallèle</code> et <strong>32 broches</strong>.</p>
<p>Une puce mémoire avec interface <code class="language-plaintext highlighter-rouge">parallèle</code> possède un certain nombre d’entrées allant de <code class="language-plaintext highlighter-rouge">A0</code> à <code class="language-plaintext highlighter-rouge">AMS</code> <em>(Most signifiant address)</em>, <code class="language-plaintext highlighter-rouge">A0</code> étant donc le bit de poids faible et <code class="language-plaintext highlighter-rouge">AMS</code> le bit de poids fort.<br />
Ces entrées correspondent à l’adresse mémoire ciblée et leur nombre va donc dépendre de la taille de la mémoire.</p>
<p>Par exemple, pour <strong>512Ko</strong> on aura <strong>19 entrées</strong>, donc de <code class="language-plaintext highlighter-rouge">A0</code> à <code class="language-plaintext highlighter-rouge">A18</code>, car il faut <strong>19 bits</strong> pour atteindre toutes les adresses mémoire : <strong>512Ko</strong> = <strong>524288 octets</strong> (oui je devrais écrire Kio pour être exact … mais on se comprend ^^), vu qu’on commence à l’adresse 0, la dernière adresse sera <code class="language-plaintext highlighter-rouge">524287</code> ce qui nécessite exactement <strong>19 bits</strong>.</p>
<p>Ensuite on trouve les <strong>8</strong> broches <code class="language-plaintext highlighter-rouge">DQ0</code> à <code class="language-plaintext highlighter-rouge">DQ7</code> qui sont des sorties en mode <strong>lecture</strong> et des entrées en mode <strong>écriture</strong> !<br />
Lors de la <strong>lecture</strong>, elles vont prendre la valeur de la donnée contenue à l’adresse mémoire ciblée.<br />
Et inversement, lors de l’<strong>écriture</strong>, l’adresse mémoire ciblée va prendre la valeur qu’on enverra sur ces broches.</p>
<p>Le mode va dépendre de l’état des 3 entrées suivantes : <code class="language-plaintext highlighter-rouge">CE#</code> <em>(Chip Enable)</em>, <code class="language-plaintext highlighter-rouge">OE#</code> <em>(Output Enable)</em>, <code class="language-plaintext highlighter-rouge">WE#</code> <em>(Write Enable)</em><br />
<strong>Ces entrées sont activées à l’état bas (et donc désactivées à l’état haut), d’ailleurs on peut constater cela via la notation <code class="language-plaintext highlighter-rouge">#</code>.</strong></p>
<h4 id="la-lecture">La lecture</h4>
<p>Le mode <strong>lecture</strong> est le plus simple car il suffit de désactiver <code class="language-plaintext highlighter-rouge">WE#</code> puis d’activer <code class="language-plaintext highlighter-rouge">CE#</code> et <code class="language-plaintext highlighter-rouge">OE#</code> pour obtenir directement l’octet de l’adresse ciblée par les entrées <code class="language-plaintext highlighter-rouge">A0</code> à <code class="language-plaintext highlighter-rouge">AMS</code>.</p>
<p>Voici le diagramme représentant la lecture d’une mémoire flash <code class="language-plaintext highlighter-rouge">SST39SF040</code> (valable pour beaucoup d’autres mémoires) :</p>
<p><img src="/assets/images/39sf040-read-diagram.jpg" alt="39SF040 Read Diagram" title="39SF040 Read Diagram" class="center lightbox" /></p>
<p>Les seules limitations sont donc les temps d’attente entre l’assignation de l’adresse mémoire et l’accès aux données.<br />
Ces temps vont varier suivant les modèles, on parle de quelques dizaines de nanosecondes, mais il s’agit d’une durée minimale, on peut très bien attendre plus longtemps pour être certain d’accéder aux données.</p>
<h4 id="lécriture">L’écriture</h4>
<p>Pour l’<strong>écriture</strong> c’est plus délicat car il faut suivre une procédure pour réellement écrire dans la mémoire.<br />
En effet, il ne suffit pas d’activer <code class="language-plaintext highlighter-rouge">WE#</code> avec l’adresse et l’octet souhaités !</p>
<p>La procédure à suivre s’appelle une <strong>séquence</strong> qui correspond à l’<strong>envoi</strong> de certaines données à certaines adresses précises pour basculer dans le mode souhaité.<br />
Ces données de <strong>séquence</strong> ne sont pas écrites dans la mémoire (il n’y a donc pas de corruption de données en mémoire, heureusement).</p>
<p>Via différentes <strong>séquences</strong> on peut ainsi exécuter quelques commandes sur la mémoire, comme :</p>
<ul>
<li>Ecrire une donnée</li>
<li>Effacer une adresse mémoire</li>
<li>Effacer l’ensemble de la mémoire</li>
<li>Récupérer l’identifiant du fabricant et le modèle</li>
<li>Certaines mémoires proposent aussi un mode verrouillage (pour bloquer l’écriture)</li>
</ul>
<p>Ces <strong>séquences</strong> sont disponibles dans le <code class="language-plaintext highlighter-rouge">datasheet</code> de chaque mémoire !<br />
Le <code class="language-plaintext highlighter-rouge">datasheet</code> est un document indispensable en électronique, il regroupe toutes les informations techniques ainsi que des exemples d’utilisation (de temps en temps) pour chaque composant.<br />
Une simple recherche suffit à trouver un <code class="language-plaintext highlighter-rouge">datasheet</code> en utilisant tout simplement les mots clés <code class="language-plaintext highlighter-rouge">datasheet REFERENCE</code> <em>(<strong>REFERENCE</strong> étant évidemment la référence du composant que vous recherchez)</em>.</p>
<p>Concernant les mémoires qui m’intéressent pour mon projet, je retrouve quasiment toujours les mêmes <strong>séquences</strong>.<br />
Pour le moment j’ai trouvé seulement 2 variantes. Dans tous les cas il suffit de lire la documentation pour savoir quelle <strong>séquence</strong> utiliser pour votre mémoire et adapter le programme au besoin (voir plus bas).</p>
<p>Par exemple, voilà les séquences disponibles pour la mémoire <code class="language-plaintext highlighter-rouge">SST39SF040</code> :</p>
<p><img src="/assets/images/39sf040-sequences.jpg" alt="39SF040 Sequences" title="39SF040 Sequences" class="center lightbox" /></p>
<p>Et enfin le diagramme représentant l’écriture :</p>
<p><img src="/assets/images/39sf040-write-diagram.jpg" alt="39SF040 Write Diagram" title="39SF040 Write Diagram" class="center lightbox" /></p>
<p>Comme pour la lecture, il est nécessaire de respecter certains timing.</p>
<p>Ceci dit, l’<code class="language-plaintext highlighter-rouge">Arduino Uno</code> n’est pas très rapide et la majorité des opérations peuvent passer sans gérer les timing si le programme n’est pas très optimisé, mais il est préférable de les gérer pour pas avoir de surprise.</p>
<h2 id="les-composants-pour-fabriquer-votre-propre-programmateur-deeprom">Les composants pour fabriquer votre propre programmateur d’EEPROM</h2>
<p>Faisons les comptes des broches :</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">19</code> pour l’adresse</li>
<li><code class="language-plaintext highlighter-rouge">8</code> pour les données</li>
<li><code class="language-plaintext highlighter-rouge">3</code> pour les contrôles</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">30</code> broches qu’on va devoir manipuler (les 2 restantes correspondent à l’alimentation).</p>
<p>L’<code class="language-plaintext highlighter-rouge">Arduino Uno</code> possède <code class="language-plaintext highlighter-rouge">14</code> entrées/sorties numériques et <code class="language-plaintext highlighter-rouge">6</code> entrées analogiques.<br />
On peut déjà oublier <code class="language-plaintext highlighter-rouge">2</code> entrées/sortie numériques (pin 0 et pin 1) car elles sont utilisées pour la communication série (dont on aura besoin pour communiquer avec le PC).<br />
Heureusement on peut utiliser les <code class="language-plaintext highlighter-rouge">6</code> entrées analogique comme entrée/sortie numérique !</p>
<p>Ce qui fait un total de <code class="language-plaintext highlighter-rouge">18</code> entrées/sorties exploitables avec l’<code class="language-plaintext highlighter-rouge">Arduino Uno</code> !</p>
<p>Ce n’est donc pas suffisant mais il existe au moins deux solutions très simples à ce problème :</p>
<ol>
<li>2 x <code class="language-plaintext highlighter-rouge">74HC595</code> : Registre à décalage 8 bits (voir ci-dessous pour plus de détails)</li>
<li>2 x <code class="language-plaintext highlighter-rouge">74HC574</code> : Bascule 8 bits</li>
</ol>
<p>Personnellement j’ai choisi la première solution mais les deux sont tout à fait viables pour ajouter des sorties.<br />
Les <strong>registres à décalage</strong> ont cependant un très gros avantage car on peut en ajouter autant qu’on veut à la suite sans avoir besoin de sacrifier une sortie de l’Arduino à chaque nouvelle puce (contrairement aux bascules qui doivent être pilotées indépendamment les unes des autres).</p>
<p><em>D’ailleurs, petite info intéressante à ce sujet, on retrouve généralement des registres à décalage dans les bandeaux de led paramétrables. Si le bandeau permet de contrôler n’importe quelle led indépendamment des autres alors il y a de fortes chances pour que chaque led possède un registre à décalage.</em></p>
<p>C’est bien beau toutes ces entrées/sorties mais il faut les raccorder aux broches de la mémoire flash.<br />
Pour faire cela tout en pouvant insérer/retirer la puce mémoire facilement, il faut utiliser soit un <strong>socket</strong>, soit une <strong>breadboard</strong>.</p>
<p>L’utilisation d’un <strong>socket</strong> implique la conception d’un circuit imprimé (enfin il est toujours possible de faire ça en l’air évidemment, mais c’est pas très propre/fiable).<br />
Donc si vous avez une <strong>plaque de prototypage</strong> ou la possibilité de faire votre propre <strong>PCB</strong>, vous pouvez étudier cette solution, sinon ça sera une <strong>breadboard</strong> !<br />
<em>Il est également possible de faire fabriquer un circuit via des sites comme JLCPCB, PCBWay etc…</em></p>
<p>J’ai ce qu’il faut pour faire des <strong>circuits imprimés simple face</strong> du coup je pars sur la solution <strong>socket</strong> afin de faire quelque chose d’un peu plus propre qu’un simple prototype.<br />
D’ailleurs, en parlant de <strong>socket</strong>, il est temps d’aborder le sujet du <strong>package (boitier)</strong> de la puce ! Afin de pouvoir la manipuler facilement j’ai choisi du <code class="language-plaintext highlighter-rouge">DIP32</code>.<br />
Dans une seconde version je prévois l’utilisation du <code class="language-plaintext highlighter-rouge">PLCC32</code> qui peut également être manipulé facilement avec la pince qui va bien.</p>
<p>Donc, pour résumer, les composants nécessaires sont :</p>
<ul>
<li>1 x <code class="language-plaintext highlighter-rouge">Arduino Uno</code> (ou autre avec au moins autant de pins que le <code class="language-plaintext highlighter-rouge">Uno</code> et la bonne tension)</li>
<li>2 x <code class="language-plaintext highlighter-rouge">74HC595</code></li>
<li>1 x <code class="language-plaintext highlighter-rouge">Socket DIP32</code> ou <code class="language-plaintext highlighter-rouge">Breadboad</code> (si vous avez ou non la possibilité de faire un PCB)</li>
<li>Au moins une mémoire flash en boitier <code class="language-plaintext highlighter-rouge">DIP32</code>, dans mon cas ça sera une <code class="language-plaintext highlighter-rouge">39SF040</code> (pour le boitier <code class="language-plaintext highlighter-rouge">PLCC32</code> j’ai des <code class="language-plaintext highlighter-rouge">AM29F040</code>)</li>
</ul>
<p>Vous pouvez trouver l’ensemble de ces composants sur internet pour vraiment pas cher. Si vous n’êtes pas trop pressés vous trouverez votre bonheur sur des sites comme <strong>Aliexpress</strong> ou <strong>Ebay</strong>.</p>
<h3 id="explications-registre-à-décalage-74hc595">Explications registre à décalage 74HC595</h3>
<p>Ce registre à décalage possède <strong>16 broches</strong> dont <strong>9 sont des sorties</strong> (les broches de <code class="language-plaintext highlighter-rouge">QA</code> à <code class="language-plaintext highlighter-rouge">QH</code> ainsi que <code class="language-plaintext highlighter-rouge">QH'</code>).</p>
<p>Lors d’un cycle, chaque sortie va prendre la valeur de la sortie précédente, excepté <code class="language-plaintext highlighter-rouge">QA</code> qui prendra la valeur de l’entrée <code class="language-plaintext highlighter-rouge">SER</code>, et <code class="language-plaintext highlighter-rouge">QH'</code> qui est en quelque sorte une copie de <code class="language-plaintext highlighter-rouge">QH</code> (et prendra donc la valeur de <code class="language-plaintext highlighter-rouge">QG</code>).</p>
<p>Le mieux pour illustrer ces cycles, c’est encore de regarder le diagramme disponible dans le <strong>datasheet</strong> du composant :</p>
<p><img src="/assets/images/74hc595-timing-diagram.jpg" alt="74HC595 Timing Diagram" title="74HC595 Timing Diagram" class="center lightbox" /></p>
<p>Ce diagramme montre bien la progression d’un bit envoyé initialement via l’entrée <code class="language-plaintext highlighter-rouge">SER</code> puis propagé dans chaque sortie l’une après l’autre à chaque cycle.</p>
<p>Ceci dit, ce diagramme pourrait laisser penser qu’il faut absolument jongler avec les deux horloges <code class="language-plaintext highlighter-rouge">SRCLK</code> et <code class="language-plaintext highlighter-rouge">RCLK</code> afin d’attribuer tous les <strong>bits</strong> du registre, mais c’est faux !<br />
En effet, pour constater cela il faut regarder un autre diagramme, le <strong>diagramme logique</strong> :</p>
<p><img src="/assets/images/74hc595-logic-diagram.jpg" alt="74HC595 Logic Diagram" title="74HC595 Logic Diagram" class="center lightbox" /></p>
<p>On peut constater que pour <strong>1 bit</strong> il y a <strong>2 registres différents</strong>, le premier permet de gérer le décalage (colonne de gauche sur le diagramme), et le second stockera la valeur pour la sortie (colonne de droite).<br />
Le premier est géré par l’horloge <code class="language-plaintext highlighter-rouge">SRCLK</code> et le second par <code class="language-plaintext highlighter-rouge">RCLK</code>.</p>
<p>En clair, ça veut dire qu’on peut simplifier la gestion des horloges pour configurer l’ensemble des registres à décalage en utilisant uniquement l’horloge <code class="language-plaintext highlighter-rouge">SRCLK</code> pour définir tous les <strong>bits</strong>, puis une fois qu’ils sont tous configurés on a plus qu’à faire un coup d’horloge <code class="language-plaintext highlighter-rouge">RCLK</code> pour envoyer les valeurs sur la sortie.</p>
<p>Un autre point intéressant, la sortie <code class="language-plaintext highlighter-rouge">QH'</code> n’est pas liée à <code class="language-plaintext highlighter-rouge">RCLK</code> ni à <code class="language-plaintext highlighter-rouge">OE#</code>, on peut donc raccorder autant de puces qu’on le souhaite en série sans avoir besoin de faire un cycle <code class="language-plaintext highlighter-rouge">RCLK</code> entre chaque puce et sans dépendre de l’état de <code class="language-plaintext highlighter-rouge">OE#</code> !</p>
<p>Donc en reliant la sortie <code class="language-plaintext highlighter-rouge">QH'</code> d’une puce à l’entrée <code class="language-plaintext highlighter-rouge">SER</code> d’une autre puce, on permet aux données de passer d’une puce à l’autre.<br />
Il reste juste à relier toutes les broches communes à toutes les puces ensemble : <code class="language-plaintext highlighter-rouge">VCC</code>, <code class="language-plaintext highlighter-rouge">GND</code>, <code class="language-plaintext highlighter-rouge">RCLK</code>, <code class="language-plaintext highlighter-rouge">SRCLK</code></p>
<p>Les deux dernière broche, <code class="language-plaintext highlighter-rouge">OE#</code> et <code class="language-plaintext highlighter-rouge">SRCLR</code>, sont également communes à toutes les puces.<br />
<code class="language-plaintext highlighter-rouge">OE#</code> permet d’activer les sorties, dans le cas présent elles seront toujours actives, pour cela il faut mettre cette broche à l’état bas.<br />
<code class="language-plaintext highlighter-rouge">SRCLR</code> est un simple reset pour réinitialiser les registres à zéro. Ici c’est inutile, on va donc laisser cette broche à l’état haut (le reset est fait au passage à l’état bas).</p>
<h2 id="le-schéma-électronique">Le schéma électronique</h2>
<p>On a tout vu dans les chapitres précédents.<br />
Le schéma consiste donc tout simplement à raccorder les <strong>registres à décalage</strong> ensemble, relier leurs sorties sur les entrées <code class="language-plaintext highlighter-rouge">A0</code> à <code class="language-plaintext highlighter-rouge">AMS</code> de la mémoire, relier les alimentations puis apporter tout le reste sur des connecteurs pour y raccorder l’<code class="language-plaintext highlighter-rouge">Arduino</code>.</p>
<p>Sur le schéma j’ai directement inséré l’<code class="language-plaintext highlighter-rouge">Arduino Uno</code> comme pour réaliser un <strong>shield arduino</strong> (ça permet aussi de voir les raccordements à faire ^^).<br />
Mais lors de la fabrication du circuit, je n’ai pas fait de <strong>shield arduino</strong> car c’était trop délicat à faire avec un <strong>circuit simple face</strong> (et pour tout vous dire, j’ai foiré ma tentative de shield …).<br />
Je suis donc parti sur un simple PCB avec des connecteurs classiques en <strong>2.54mm</strong> (standard qu’on retrouve un peu partout, Arduino, breadboard etc…).</p>
<p><img src="/assets/images/arduino-flash-programmer-sch.jpg" alt="Arduino Flash Programmer Schéma" title="Arduino Flash Programmer Schéma" class="center lightbox" /></p>
<p>J’ai fait le choix d’utiliser seulement <strong>2 registres à décalage</strong>, ce qui fait <strong>16 sorties</strong>, je dois donc gérer les <strong>3 dernières</strong> (<code class="language-plaintext highlighter-rouge">A16</code>, <code class="language-plaintext highlighter-rouge">A17</code> et <code class="language-plaintext highlighter-rouge">A18</code>) directement avec les sorties de l’<code class="language-plaintext highlighter-rouge">Arduino</code> (donc sur un connecteur).</p>
<h2 id="aperçu-de-mon-prototype">Aperçu de mon prototype</h2>
<p>Comme précisé précédemment, je peux fabriquer uniquement des circuits imprimés à une face, ce qui n’est pas suffisant pour un tel projet si on veut faire ça proprement.</p>
<p>En effet, il faudra forcément croiser certaines liaisons pour un tel montage, ce qui nécessite d’avoir au moins deux couches de cuivre.</p>
<p>J’ai donc fait comme je pouvais avec une couche et j’ai fini les liaisons manquantes avec quelques morceaux de fil.</p>
<p>C’est donc un prototype loin d’être parfait (c’est un peu le rôle d’un prototype d’ailleurs) et je préfère ne pas partager les fichiers de cette conception car j’estime que ce n’est pas assez propre pour l’être.<br />
<em>(Il est cependant possible que je fasse évoluer ce projet en faisant un beau PCB 2 couches, mais ça sera pas avant 2021 je pense).</em></p>
<p>Mais voilà quand même un aperçu :</p>
<div class="gallery center">
<img src="/assets/images/arduino-flash-programmer-prototype-1.jpg" alt="Arduino Flash Programmer Prototype" title="Arduino Flash Programmer Prototype" class="lightbox" />
<img src="/assets/images/arduino-flash-programmer-prototype-2.jpg" alt="Arduino Flash Programmer Prototype" title="Arduino Flash Programmer Prototype" class="lightbox" />
<img src="/assets/images/arduino-flash-programmer-prototype-3.jpg" alt="Arduino Flash Programmer Prototype" title="Arduino Flash Programmer Prototype" class="lightbox" />
</div>
<h2 id="le-software-pour-gérer-la-programmation-de-la-mémoire">Le software pour gérer la programmation de la mémoire</h2>
<p>Il y a donc deux parties à coder, une pour l’<code class="language-plaintext highlighter-rouge">Arduino</code> (en <strong>C</strong>), l’autre pour le PC (en <strong>Python</strong>).</p>
<p>Afin de faciliter l’utilisation, j’ai fait en sorte de pouvoir accéder à toutes les commandes sur l’<code class="language-plaintext highlighter-rouge">Arduino</code> sans utiliser le client en <strong>python</strong> sur le PC.</p>
<p>Il est donc possible de manipuler la mémoire flash via un simple <code class="language-plaintext highlighter-rouge">moniteur série</code> comme celui proposé dans l’<code class="language-plaintext highlighter-rouge">IDE Arduino</code> ou tout autre client dans le genre comme <code class="language-plaintext highlighter-rouge">Putty</code>.</p>
<p>C’était surtout pratique pour les tests, mais désormais je n’utilise plus que mon client en <strong>python</strong> !</p>
<h3 id="arduino">Arduino</h3>
<p><strong>ATTENTION : Comme je l’ai déjà précisé dans l’introduction de cet article, j’ai des mémoires qui fonctionnent sous une tension de 5V et mon <code class="language-plaintext highlighter-rouge">Arduino Uno</code> est également en 5V.</strong><br />
<strong>Il est TRES IMPORTANT de vous assurer que votre mémoire et votre Arduino fonctionnement avec la même tension (pas seulement au niveau de l’alimentation mais aussi au niveau des sorties de l’Arduino) !</strong></p>
<p>J’ai fait deux version, une optimisée et compatible uniquement <code class="language-plaintext highlighter-rouge">Uno</code> et <code class="language-plaintext highlighter-rouge">Nano</code> (et normalement <code class="language-plaintext highlighter-rouge">Due</code> aussi), ainsi qu’une pour les autres cartes avec assez de pins comme <code class="language-plaintext highlighter-rouge">Mega</code>, <code class="language-plaintext highlighter-rouge">Yun</code> ou <code class="language-plaintext highlighter-rouge">Micro</code>.</p>
<p>La version pour les autres cartes fonctionne aussi sur <code class="language-plaintext highlighter-rouge">Uno</code> et <code class="language-plaintext highlighter-rouge">Nano</code> mais je trouve le code vraiment moche et clairement pas optimisé.<br />
La seule différence étant la manipulation des <strong>registres des ports</strong> de l’<code class="language-plaintext highlighter-rouge">Arduino</code> sur la version optimisée alors que l’autre version utilise les fonctions <code class="language-plaintext highlighter-rouge">Arduino</code> pour faire ces manipulations (fonctions vraiment lourdes en temps d’exécution, et il faut bien l’avouer, c’est moche).<br />
Le problème c’est que ces <strong>registres</strong> ne sont pas les mêmes sur toutes les cartes et ils sont même dans le désordre sur certaines …<br />
D’ailleurs, c’est surtout le fait que ce soit dans le désordre qui est problématique car dans le cas contraire j’aurais pu mapper les bons <strong>registres</strong> suivant la carte sélectionnée lors de la compilation …</p>
<p>Pour plus de détails sur l’utilisation des <strong>registres</strong> pour manipuler les pins de l’<code class="language-plaintext highlighter-rouge">Arduino</code> :</p>
<ul>
<li><a href="https://www.arduino.cc/en/Reference/PortManipulation" target="_blank">Arduino Port Registers</a></li>
<li><a href="https://arduino.pinout.guide/" target="_blank">Pinout Arduino</a> <em>(il faut voir la valeur <code class="language-plaintext highlighter-rouge">Port Pin</code> de chaque pin pour savoir sur quel registre ils sont)</em></li>
</ul>
<p>Je ne vais pas rentrer dans les détails du code ici.<br />
Toutes les instructions sont disponibles dans le <strong>readme</strong> du projet : <a href="https://github.com/Elrindel/Arduino-Flash-Programmer" target="_blank">Arduino Flash Programmer</a></p>
<h3 id="pc">PC</h3>
<p>Bien qu’il soit optionnel, c’est beaucoup plus simple d’utiliser un petit client en ligne de commande pour gérer la communication avec l’<code class="language-plaintext highlighter-rouge">Arduino</code> plutôt que d’ouvrir un moniteur série et envoyer toutes les commandes manuellement.<br />
Surtout si il faut envoyer un certain nombre de données (comme pour écrire un fichier entier dans la mémoire).</p>
<p>Il y a donc rien d’extraordinaire dans ce code, c’est juste une gestion des arguments avec quelques petites validations, puis une communication série avec l’<code class="language-plaintext highlighter-rouge">Arduino</code>.</p>
<p>La configuration du port série est celle de l’<code class="language-plaintext highlighter-rouge">Arduino</code> par défaut, à savoir <strong>8 data bits, no parity, 1 stop bit</strong> avec une vitesse de <strong>115200 baud</strong>.</p>
<p>Comme pour le code <code class="language-plaintext highlighter-rouge">Arduino</code>, toutes les infos sont dans le <strong>readme</strong> : <a href="https://github.com/Elrindel/Arduino-Flash-Programmer" target="_blank">Arduino Flash Programmer</a></p>
<h2 id="conclusion">Conclusion</h2>
<p>Je suis loin d’avoir traité tout le sujet de la programmation de mémoire flash mais ça reste une bonne initiation je pense :)</p>
<p>En tout cas ce projet peut clairement évoluer, il est donc possible qu’il y ait une évolution et donc un nouvel article (c’est même fort probable) !</p>
<p>D’ailleurs, mon prochain article sera indirectement lié puisqu’il s’agira d’une mise en pratique concrète afin de réaliser un autre projet.</p>
<h2 id="sources-et-inspirations">Sources et inspirations</h2>
<ul>
<li><a href="https://github.com/Elrindel/Arduino-Flash-Programmer" target="_blank">Code du projet</a></li>
<li><a href="https://www.alldatasheet.com/" target="_blank">AllDataSheet</a> <em>(Bah oui, sans datasheet on fait pas grand chose ^^)</em></li>
<li><a href="https://github.com/mkeller0815/MEEPROMMER" target="_blank">MEEPROMMER</a> <em>(Un projet similaire qui m’a inspiré)</em></li>
<li><a href="https://www.arduino.cc/en/Reference/PortManipulation" target="_blank">Arduino Port Registers</a></li>
<li><a href="https://arduino.pinout.guide/" target="_blank">Pinout Arduino</a></li>
</ul>
</article>
<nav>
<div id="summary"></div>
</nav>
</div>
</section>
<div class="container">
<div id="disqus_thread"></div>
<script>
let disqus = document.getElementById('disqus');
let observer = new IntersectionObserver((e) => {
if(e[0].isIntersecting){
observer.disconnect();
let disqus = document.createElement('script');
disqus.type = 'text/javascript';
disqus.async = true;
disqus.src = '//elrindel.disqus.com/embed.js';
document.getElementsByTagName('head')[0].appendChild(disqus);
}
});
observer.observe(document.getElementById('disqus_thread'));
</script>
</div>
<footer id="footer"></footer>
<script type="text/javascript" src="/assets/js/simpleLightbox.min.js"></script>
<script>
var imglightbox = new SimpleLightbox({elements:'img.lightbox',urlAttribute:'src'});
var alightbox = new SimpleLightbox({elements:'a.lightbox'});
</script>
<script async type="text/javascript" src="/assets/js/summary.js"></script>
</body>
</html>