summaryrefslogtreecommitdiff
path: root/cpu-docs/espressif-software/esptool_serial-protocol_esp32p4_v5.3.1.html
blob: b5a01086c06004b3b565c66f1dfd7c2b41c833cd (plain) (blame)
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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
<!DOCTYPE html>
<html class="writer-html5" lang="en">
<head>
  <meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />

  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Serial Protocol - ESP32-P4 -  &mdash; esptool latest documentation</title>
      <link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=03e43079" />
      <link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=a60756f2" />
      <link rel="stylesheet" type="text/css" href="../_static/theme_overrides.css?v=851bd809" />

  
  <!--[if lt IE 9]>
    <script src="../_static/js/html5shiv.min.js"></script>
  <![endif]-->
  
        <script src="../_static/jquery.js?v=5d32c60e"></script>
        <script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
        <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js?v=becddca3"></script>
        <script src="../_static/doctools.js?v=888ff710"></script>
        <script src="../_static/sphinx_highlight.js?v=4825356b"></script>
    <script src="../_static/js/theme.js"></script>

    
        

    <script type="text/javascript">
        DOCUMENTATION_OPTIONS.PAGENAME = 'advanced-topics/serial-protocol';
        DOCUMENTATION_OPTIONS.PROJECT_SLUG = 'esptool';
        DOCUMENTATION_OPTIONS.LATEST_BRANCH_NAME = 'master';
        DOCUMENTATION_OPTIONS.VERSIONS_URL = '.././_static/esptool_versions.js';
        DOCUMENTATION_OPTIONS.LANGUAGES = ["en"];
        DOCUMENTATION_OPTIONS.IDF_TARGET = 'esp32p4';
        DOCUMENTATION_OPTIONS.HAS_IDF_TARGETS = ["esp8266", "esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32c6", "esp32h2", "esp32h4", "esp32p4", "esp32c5", "esp32c61", "esp32h21", "esp32s31"]
        DOCUMENTATION_OPTIONS.RELEASE = 'latest';
        DOCUMENTATION_OPTIONS.LANGUAGE_URL = 'en';

    </script>

    <script type="text/javascript" src=".././_static/esptool_versions.js"></script>
    <link rel="author" title="About these documents" href="../about.html" />
    <link rel="index" title="Index" href="../genindex.html" />
    <link rel="search" title="Search" href="../search.html" />
    <link rel="next" title="SPI Flash Modes" href="spi-flash-modes.html" />
    <link rel="prev" title="Firmware Image Format" href="firmware-image-format.html" /> 
</head>

<body class="wy-body-for-nav"> 
  <div class="wy-grid-for-nav">
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >

          
          
          <a href="../index.html" class="icon icon-home">
            esptool
              <img src="../_static/espressif-logo.svg" class="logo" alt="Logo"/>
          </a>

          
            <div class="selectors">
              <select id="target-select" style="width: 150px;" hidden>
                <option value="" disabled selected>Choose target...</option>
              </select>
            </div>
          

          <div class="selectors">
            <select id="version-select" style="width: 150px;" hidden>
              <option value="" disabled selected>Choose version...</option>
            </select>
          </div>

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>
        </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
              <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../installation.html">Installation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../esptool/index.html">Esptool</a></li>
<li class="toctree-l1"><a class="reference internal" href="../espefuse/index.html">Espefuse</a></li>
<li class="toctree-l1"><a class="reference internal" href="../espsecure/index.html">Espsecure</a></li>
<li class="toctree-l1"><a class="reference internal" href="../remote-serial-ports.html">Remote Serial Ports</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Advanced Topics</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="firmware-image-format.html">Firmware Image Format</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">Serial Protocol</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#packet-description">Packet Description</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#low-level-protocol">Low Level Protocol</a></li>
<li class="toctree-l4"><a class="reference internal" href="#command-packet">Command Packet</a></li>
<li class="toctree-l4"><a class="reference internal" href="#response-packet">Response Packet</a></li>
<li class="toctree-l4"><a class="reference internal" href="#commands">Commands</a></li>
<li class="toctree-l4"><a class="reference internal" href="#checksum">Checksum</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#functional-description">Functional Description</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#initialization">Initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="#initialization-chip-type-detection">Initialization - Chip Type Detection</a></li>
<li class="toctree-l4"><a class="reference internal" href="#writing-data">Writing Data</a></li>
<li class="toctree-l4"><a class="reference internal" href="#spi-configuration-commands">SPI Configuration Commands</a></li>
<li class="toctree-l4"><a class="reference internal" href="#bit-read-write">32-Bit Read/Write</a></li>
<li class="toctree-l4"><a class="reference internal" href="#reading-flash">Reading Flash</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="#tracing-esptool-serial-communications">Tracing Esptool Serial Communications</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="spi-flash-modes.html">SPI Flash Modes</a></li>
<li class="toctree-l2"><a class="reference internal" href="boot-mode-selection.html">Boot Mode Selection</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../troubleshooting.html">Troubleshooting</a></li>
<li class="toctree-l1"><a class="reference internal" href="../contributing.html">Contribute</a></li>
<li class="toctree-l1"><a class="reference internal" href="../versions.html">Versions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../migration-guide.html">Migration Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../resources.html">Resources</a></li>
<li class="toctree-l1"><a class="reference internal" href="../about.html">About</a></li>
</ul>

        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../index.html">esptool</a>
      </nav>

      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
          <li class="breadcrumb-item"><a href="index.html">Advanced Topics</a></li>
      <li class="breadcrumb-item active">Serial Protocol</li>
      <li class="wy-breadcrumbs-aside">
              <a href="https://github.com/espressif/esptool/blob/90e9560f/docs/en/advanced-topics/serial-protocol.rst" class="fa fa-github"> Edit on GitHub</a>
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
             
  <section id="serial-protocol">
<span id="id1"></span><h1>Serial Protocol<a class="headerlink" href="#serial-protocol" title="Permalink to this heading"></a></h1>
<p>This is technical documentation for the serial protocol used by the UART bootloader in the ESP32-P4 ROM and the esptool <a class="reference internal" href="../esptool/flasher-stub.html#stub"><span class="std std-ref">stub loader</span></a> program.</p>
<p>The UART bootloader runs on chip reset if certain strapping pins are set. See <a class="reference internal" href="../esptool/entering-bootloader.html#entering-the-bootloader"><span class="std std-ref">Entering the Bootloader</span></a> for details of this process.</p>
<p>By default, esptool uploads a stub “software loader” to the IRAM of the chip. The stub loader then replaces the ROM loader for all future interactions. This standardizes much of the behavior. Pass <code class="docutils literal notranslate"><span class="pre">--no-stub</span></code> to esptool in order to disable the stub loader. See <a class="reference internal" href="../esptool/flasher-stub.html#stub"><span class="std std-ref">Flasher Stub</span></a> for more information.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>There are differences in the serial protocol between ESP chips! To switch to documentation for a different chip, choose the desired target from the dropdown menu in the upper left corner.</p>
</div>
<section id="packet-description">
<h2>Packet Description<a class="headerlink" href="#packet-description" title="Permalink to this heading"></a></h2>
<p>The host computer sends a SLIP encoded command request to the ESP chip. The ESP chip responds to the request with a SLIP encoded response packet, including status information and any data as a payload.</p>
<section id="low-level-protocol">
<span id="id2"></span><h3>Low Level Protocol<a class="headerlink" href="#low-level-protocol" title="Permalink to this heading"></a></h3>
<p>The bootloader protocol uses <a class="reference external" href="https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol">SLIP</a> packet framing for data transmissions in both directions.</p>
<p>Each SLIP packet begins and ends with <code class="docutils literal notranslate"><span class="pre">0xC0</span></code>. Within the packet, all occurrences of <code class="docutils literal notranslate"><span class="pre">0xC0</span></code> and <code class="docutils literal notranslate"><span class="pre">0xDB</span></code> are replaced with <code class="docutils literal notranslate"><span class="pre">0xDB</span> <span class="pre">0xDC</span></code> and <code class="docutils literal notranslate"><span class="pre">0xDB</span> <span class="pre">0xDD</span></code>, respectively. The replacing is to be done <strong>after</strong> the checksum and lengths are calculated, so the packet length may be longer than the <code class="docutils literal notranslate"><span class="pre">size</span></code> field below.</p>
</section>
<section id="command-packet">
<h3>Command Packet<a class="headerlink" href="#command-packet" title="Permalink to this heading"></a></h3>
<p>Each command is a SLIP packet initiated by the host and results in a response packet. Inside the packet, the packet consists of a header and a variable-length body. All multi-byte fields are little-endian.</p>
<figure class="align-center" id="id3">
<div><img height="220" src="../_images/packetdiag-2b26411142ad479e9f6469f32c1e2f5f2ce1f1f0.png" width="928" /></div><figcaption>
<p><span class="caption-text">Command packet format</span><a class="headerlink" href="#id3" title="Permalink to this image"></a></p>
</figcaption>
</figure>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Comment</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>0</p></td>
<td><p>Direction</p></td>
<td><p>Always <code class="docutils literal notranslate"><span class="pre">0x00</span></code> for requests</p></td>
</tr>
<tr class="row-odd"><td><p>1</p></td>
<td><p>Command</p></td>
<td><p>Command identifier (see <a class="reference internal" href="#commands">Commands</a>).</p></td>
</tr>
<tr class="row-even"><td><p>2-3</p></td>
<td><p>Size</p></td>
<td><p>Length of Data field, in bytes.</p></td>
</tr>
<tr class="row-odd"><td><p>4-7</p></td>
<td><p>Checksum</p></td>
<td><p>Simple checksum of part of the data field (only used for some commands, see <a class="reference internal" href="#checksum">Checksum</a>).</p></td>
</tr>
<tr class="row-even"><td><p>8..n</p></td>
<td><p>Data</p></td>
<td><p>Variable length data payload (0-65535 bytes, as indicated by Size parameter). Usage depends on specific command.</p></td>
</tr>
</tbody>
</table>
</section>
<section id="response-packet">
<h3>Response Packet<a class="headerlink" href="#response-packet" title="Permalink to this heading"></a></h3>
<p>Each received command will result in a response SLIP packet sent from the ESP chip to the host. Contents of the response packet is:</p>
<figure class="align-center" id="id4">
<div><img height="220" src="../_images/packetdiag-1457843f5c1dc3f306a1c8e876eb44074a071e0a.png" width="928" /></div><figcaption>
<p><span class="caption-text">Command packet format</span><a class="headerlink" href="#id4" title="Permalink to this image"></a></p>
</figcaption>
</figure>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Comment</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>0</p></td>
<td><p>Direction</p></td>
<td><p>Always <code class="docutils literal notranslate"><span class="pre">0x01</span></code> for responses</p></td>
</tr>
<tr class="row-odd"><td><p>1</p></td>
<td><p>Command</p></td>
<td><p>Same value as Command identifier in the request packet that triggered the response</p></td>
</tr>
<tr class="row-even"><td><p>2-3</p></td>
<td><p>Size</p></td>
<td><p>Size of data field. At least the length of the <a class="reference internal" href="#status-bytes">Status Bytes</a> (2 or 4 bytes, see below).</p></td>
</tr>
<tr class="row-odd"><td><p>4-7</p></td>
<td><p>Value</p></td>
<td><p>Response value used by READ_REG command (see below). Zero otherwise.</p></td>
</tr>
<tr class="row-even"><td><p>8..n</p></td>
<td><p>Data</p></td>
<td><p>Variable length data payload. Length indicated by “Size” field.</p></td>
</tr>
</tbody>
</table>
<section id="status-bytes">
<h4>Status Bytes<a class="headerlink" href="#status-bytes" title="Permalink to this heading"></a></h4>
<p>The final bytes of the Data payload indicate command status:</p>
<p>For stub loader the final two bytes indicate status (most commands return at least a two byte Data payload):</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Comment</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>Size-2</p></td>
<td><p>Status</p></td>
<td><p>Status flag, success (<code class="docutils literal notranslate"><span class="pre">0</span></code>) or failure (<code class="docutils literal notranslate"><span class="pre">1</span></code>)</p></td>
</tr>
<tr class="row-odd"><td><p>Size-1</p></td>
<td><p>Error</p></td>
<td><p>If Status is 1, this indicates the type of error.</p></td>
</tr>
</tbody>
</table>
<p>For ESP32-P4 ROM (only, not the stub loader) the final four bytes are used, but only the first two bytes contain status information:</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Comment</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>Size-4</p></td>
<td><p>Status</p></td>
<td><p>Status flag, success (<code class="docutils literal notranslate"><span class="pre">0</span></code>) or failure (<code class="docutils literal notranslate"><span class="pre">1</span></code>)</p></td>
</tr>
<tr class="row-odd"><td><p>Size-3</p></td>
<td><p>Error</p></td>
<td><p>If Status 1, this indicates the type of error.</p></td>
</tr>
<tr class="row-even"><td><p>Size-2</p></td>
<td><p>Reserved</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p>Size-1</p></td>
<td><p>Reserved</p></td>
<td></td>
</tr>
</tbody>
</table>
</section>
<section id="rom-loader-errors">
<h4>ROM Loader Errors<a class="headerlink" href="#rom-loader-errors" title="Permalink to this heading"></a></h4>
<p>The ROM loader sends the following error values</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Value</p></th>
<th class="head"><p>Meaning</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x00</span></code></p></td>
<td><p>“Undefined errors”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x01</span></code></p></td>
<td><p>“The input parameter is invalid”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x02</span></code></p></td>
<td><p>“Failed to malloc memory from system”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x03</span></code></p></td>
<td><p>“Failed to send out message”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x04</span></code></p></td>
<td><p>“Failed to receive message”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x05</span></code></p></td>
<td><p>“The format of the received message is invalid”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x06</span></code></p></td>
<td><p>“Message is ok, but the running result is wrong”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x07</span></code></p></td>
<td><p>“Checksum error”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x08</span></code></p></td>
<td><p>“Flash write error” - after writing a block of data to flash,
the ROM loader reads the value back and the 8-bit CRC is compared
to the data read from flash. If they don’t match, this error is returned.</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x09</span></code></p></td>
<td><p>“Flash read error” - SPI read failed</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x0a</span></code></p></td>
<td><p>“Flash read length error” - SPI read request length is wrong</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x0b</span></code></p></td>
<td><p>“Deflate failed error” (compressed uploads only)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x0c</span></code></p></td>
<td><p>“Deflate Adler32 error”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x0d</span></code></p></td>
<td><p>“Deflate parameter error”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x0e</span></code></p></td>
<td><p>“Invalid RAM binary size”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x0f</span></code></p></td>
<td><p>“Invalid RAM binary address”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x64</span></code></p></td>
<td><p>“Invalid parameter”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x65</span></code></p></td>
<td><p>“Invalid format”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x66</span></code></p></td>
<td><p>“Description too long”</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x67</span></code></p></td>
<td><p>“Bad encoding description”</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x69</span></code></p></td>
<td><p>“Insufficient storage”</p></td>
</tr>
</tbody>
</table>
</section>
<section id="stub-loader-status-error">
<h4>Stub Loader Status &amp; Error<a class="headerlink" href="#stub-loader-status-error" title="Permalink to this heading"></a></h4>
<p>If the stub loader is used:</p>
<ul class="simple">
<li><p>The status response is always 2 bytes regardless of chip type.</p></li>
<li><p>Stub loader error codes are entirely different to the ROM loader codes. They all take the form <code class="docutils literal notranslate"><span class="pre">0xC*</span></code>, or <code class="docutils literal notranslate"><span class="pre">0xFF</span></code> for “unimplemented command”. (<a class="reference external" href="https://github.com/espressif/esptool/blob/master/flasher_stub/include/stub_flasher.h#L95">Full list here</a>).</p></li>
</ul>
<p>After sending a command, the host should continue to read response packets until one is received where the Command field matches the request’s Command field, or a timeout is exceeded.</p>
</section>
</section>
<section id="commands">
<h3>Commands<a class="headerlink" href="#commands" title="Permalink to this heading"></a></h3>
<section id="supported-by-stub-loader-and-rom-loader">
<h4>Supported by Stub Loader and ROM Loader<a class="headerlink" href="#supported-by-stub-loader-and-rom-loader" title="Permalink to this heading"></a></h4>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Description</p></th>
<th class="head"><p>Input Data</p></th>
<th class="head"><p>Output Data</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x02</span></code></p></td>
<td><p>FLASH_BEGIN</p></td>
<td><p><a class="reference external" href="#writing-data">Begin Flash Download</a></p></td>
<td><p>Four 32-bit words: size to erase, number of data packets, data size in one packet, flash offset. A fifth 32-bit word passed to ROM loader only: <code class="docutils literal notranslate"><span class="pre">1</span></code> to begin encrypted flash, <code class="docutils literal notranslate"><span class="pre">0</span></code> to not.</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x03</span></code></p></td>
<td><p>FLASH_DATA</p></td>
<td><p><a class="reference external" href="#writing-data">Flash Download Data</a></p></td>
<td><p>Four 32-bit words: data size, sequence number, <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">0</span></code>, then data. Uses <a class="reference internal" href="#checksum">Checksum</a>.</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x04</span></code></p></td>
<td><p>FLASH_END</p></td>
<td><p><a class="reference external" href="#writing-data">Finish Flash Download</a></p></td>
<td><p>One 32-bit word: <code class="docutils literal notranslate"><span class="pre">0</span></code> to reboot, <code class="docutils literal notranslate"><span class="pre">1</span></code> to run user code. Not necessary to send this command if you wish to stay in the loader</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x05</span></code></p></td>
<td><p>MEM_BEGIN</p></td>
<td><p><a class="reference external" href="#writing-data">Begin RAM Download Start</a></p></td>
<td><p>Total size, number of data packets, data size in one packet, memory offset</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x06</span></code></p></td>
<td><p>MEM_END</p></td>
<td><p><a class="reference external" href="#writing-data">Finish RAM Download</a></p></td>
<td><p>Two 32-bit words: execute flag, entry point address</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x07</span></code></p></td>
<td><p>MEM_DATA</p></td>
<td><p><a class="reference external" href="#writing-data">RAM Download Data</a></p></td>
<td><p>Four 32-bit words: data size, sequence number, <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">0</span></code>, then data. Uses <a class="reference internal" href="#checksum">Checksum</a>.</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x08</span></code></p></td>
<td><p>SYNC</p></td>
<td><p><a class="reference external" href="#initial-synchronisation">Sync Frame</a></p></td>
<td><p>36 bytes: <code class="docutils literal notranslate"><span class="pre">0x07</span> <span class="pre">0x07</span> <span class="pre">0x12</span> <span class="pre">0x20</span></code>, followed by 32 x <code class="docutils literal notranslate"><span class="pre">0x55</span></code></p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x09</span></code></p></td>
<td><p>WRITE_REG</p></td>
<td><p><a class="reference external" href="#32-bit-readwrite">Write 32-bit memory address</a></p></td>
<td><p>Four 32-bit words: address, value, mask and delay (in microseconds)</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x0a</span></code></p></td>
<td><p>READ_REG</p></td>
<td><p><a class="reference external" href="#32-bit-readwrite">Read 32-bit memory address</a></p></td>
<td><p>Address as 32-bit word</p></td>
<td><p>Read data as 32-bit word in <code class="docutils literal notranslate"><span class="pre">value</span></code> field.</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x0b</span></code></p></td>
<td><p>SPI_SET_PARAMS</p></td>
<td><p><a class="reference external" href="#spi-set-parameters">Configure SPI flash</a></p></td>
<td><p>Six 32-bit words: id, total size in bytes, block size, sector size, page size, status mask.</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x0d</span></code></p></td>
<td><p>SPI_ATTACH</p></td>
<td><p><a class="reference external" href="#spi-attach-command">Attach SPI flash</a></p></td>
<td><p>32-bit word: Zero for normal SPI flash. A second 32-bit word (should be <code class="docutils literal notranslate"><span class="pre">0</span></code>) is passed to ROM loader only.</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x0f</span></code></p></td>
<td><p>CHANGE_BAUDRATE</p></td>
<td><p><a class="reference external" href="#initial-synchronisation">Change Baud rate</a></p></td>
<td><p>Two 32-bit words: new baud rate, <code class="docutils literal notranslate"><span class="pre">0</span></code> if we are talking to the ROM loader or the current/old baud rate if we are talking to the stub loader.</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x10</span></code></p></td>
<td><p>FLASH_DEFL_BEGIN</p></td>
<td><p><a class="reference external" href="#writing-data">Begin compressed flash download</a></p></td>
<td><p>Four 32-bit words: uncompressed size, number of data packets, data packet size, flash offset. With stub loader the uncompressed size is exact byte count to be written, whereas on ROM bootloader it is rounded up to flash erase block size.
A fifth 32-bit word passed to ROM loader only: <code class="docutils literal notranslate"><span class="pre">1</span></code> to begin encrypted flash, <code class="docutils literal notranslate"><span class="pre">0</span></code> to not.</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x11</span></code></p></td>
<td><p>FLASH_DEFL_DATA</p></td>
<td><p><a class="reference external" href="#writing-data">Compressed flash download data</a></p></td>
<td><p>Four 32-bit words: data size, sequence number, <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">0</span></code>, then data. Uses <a class="reference internal" href="#checksum">Checksum</a>.</p></td>
<td><p>Error code <code class="docutils literal notranslate"><span class="pre">0xC1</span></code> on checksum error.</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x12</span></code></p></td>
<td><p>FLASH_DEFL_END</p></td>
<td><p><a class="reference external" href="#writing-data">End compressed flash download</a></p></td>
<td><p>One 32-bit word: <code class="docutils literal notranslate"><span class="pre">0</span></code> to reboot, <code class="docutils literal notranslate"><span class="pre">1</span></code> to run user code. Not necessary to send this command if you wish to stay in the loader.</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0x13</span></code></p></td>
<td><p>SPI_FLASH_MD5</p></td>
<td><p><a class="reference external" href="#verifying-uploaded-data">Calculate MD5 of flash region</a></p></td>
<td><p>Four 32-bit words: address, size, <code class="docutils literal notranslate"><span class="pre">0</span></code>, <code class="docutils literal notranslate"><span class="pre">0</span></code></p></td>
<td><p>Body contains 16 raw bytes of MD5 followed by 2 status bytes (stub loader) or 32 hex-coded ASCII (ROM loader) of calculated MD5</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0x14</span></code></p></td>
<td><p>GET_SECURITY_INFO</p></td>
<td><p>Read chip security info</p></td>
<td></td>
<td><p>32 bits <code class="docutils literal notranslate"><span class="pre">flags</span></code>, 1 byte <code class="docutils literal notranslate"><span class="pre">flash_crypt_cnt</span></code>, 7x1 byte <code class="docutils literal notranslate"><span class="pre">key_purposes</span></code>, 32-bit word <code class="docutils literal notranslate"><span class="pre">chip_id</span></code>, 32-bit word <code class="docutils literal notranslate"><span class="pre">eco_version</span></code></p></td>
</tr>
</tbody>
</table>
</section>
<section id="supported-by-stub-loader-only">
<h4>Supported by Stub Loader Only<a class="headerlink" href="#supported-by-stub-loader-only" title="Permalink to this heading"></a></h4>
<p>ROM loaders will not recognize these commands.</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Byte</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Description</p></th>
<th class="head"><p>Input</p></th>
<th class="head"><p>Output</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0xd0</span></code></p></td>
<td><p>ERASE_FLASH</p></td>
<td><p>Erase entire flash chip</p></td>
<td></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0xd1</span></code></p></td>
<td><p>ERASE_REGION</p></td>
<td><p>Erase flash region</p></td>
<td><p>Two 32-bit words: flash offset to erase, erase size in bytes. Both must be multiples of flash sector size.</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">0xd2</span></code></p></td>
<td><p>READ_FLASH</p></td>
<td><p><a class="reference external" href="#reading-flash">Read flash</a></p></td>
<td><p>Four 32-bit words: flash offset, read length, flash sector size, read packet size, maximum number of un-acked packets</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">0xd3</span></code></p></td>
<td><p>RUN_USER_CODE</p></td>
<td><p>Exits loader and runs user code</p></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</section>
<section id="supported-in-secure-download-mode">
<span id="supported-in-sdm"></span><h4>Supported in Secure Download Mode<a class="headerlink" href="#supported-in-secure-download-mode" title="Permalink to this heading"></a></h4>
<p>Secure Download Mode is a restricted version of the ROM Loader available on Espressif chips. It only allows a limited set of commands:</p>
<ul class="simple">
<li><p>synchronisation (<code class="docutils literal notranslate"><span class="pre">SYNC</span></code>)</p></li>
<li><p>attaching SPI flash (<code class="docutils literal notranslate"><span class="pre">SPI_ATTACH</span></code>)</p></li>
<li><p>updating SPI config (<code class="docutils literal notranslate"><span class="pre">SPI_SET_PARAMS</span></code>)</p></li>
<li><p>changing baud rate (<code class="docutils literal notranslate"><span class="pre">CHANGE_BAUDRATE</span></code>)</p></li>
<li><p>basic flash write (<code class="docutils literal notranslate"><span class="pre">FLASH_BEGIN</span></code>, <code class="docutils literal notranslate"><span class="pre">FLASH_DATA</span></code>, <code class="docutils literal notranslate"><span class="pre">FLASH_END</span></code>)</p></li>
<li><p>reading a summary of currently enabled security features (<code class="docutils literal notranslate"><span class="pre">GET_SECURITY_INFO</span></code>)</p></li>
</ul>
<p>Any other command (e.g., reading or writing memory, arbitrary code execution through loading to RAM, …) will result in an error.</p>
<p>You can read more about Secure Download Mode in the <a class="reference external" href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/security/security.html#uart-download-mode">ESP-IDF Security Overview</a> or read about its <a class="reference internal" href="../troubleshooting.html#sdm-limitations"><span class="std std-ref">limitations here</span></a>.</p>
</section>
</section>
<section id="checksum">
<h3>Checksum<a class="headerlink" href="#checksum" title="Permalink to this heading"></a></h3>
<p>The checksum field is ignored (can be zero) for all commands except for MEM_DATA, FLASH_DATA, and FLASH_DEFL_DATA.</p>
<p>Each of the <code class="docutils literal notranslate"><span class="pre">_DATA</span></code> command packets (like <code class="docutils literal notranslate"><span class="pre">FLASH_DEFL_DATA</span></code>, <code class="docutils literal notranslate"><span class="pre">MEM_DATA</span></code>) has the same “data payload” format:</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Bytes</p></th>
<th class="head"><p>Name</p></th>
<th class="head"><p>Format</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>0-3</p></td>
<td><p>“Data to write” length</p></td>
<td><p>Little endian 32-bit word.</p></td>
</tr>
<tr class="row-odd"><td><p>4-7</p></td>
<td><p>Sequence number</p></td>
<td><p>Little endian 32-bit word. The sequence numbers are 0 based.</p></td>
</tr>
<tr class="row-even"><td><p>8-15</p></td>
<td><p>0</p></td>
<td><p>Two words of all zeroes, unused.</p></td>
</tr>
<tr class="row-odd"><td><p>16-</p></td>
<td><p>“Data to write”</p></td>
<td><p>Length given at beginning of payload.</p></td>
</tr>
</tbody>
</table>
<p>The checksum is only applied to this final “data to write” section, not the first 16 bytes of data.</p>
<p>To calculate checksum, start with seed value 0xEF and XOR each individual byte in the “data to write”. The 8-bit result is stored in the checksum field of the packet header (as a little endian 32-bit value).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Because this checksum is not adequate to ensure valid data, the SPI_FLASH_MD5 command was added to validate flash contents after flashing. It is recommended that this command is always used. See <a class="reference internal" href="#verifying-uploaded-data">Verifying Uploaded Data</a>, below.</p>
</div>
</section>
</section>
<section id="functional-description">
<h2>Functional Description<a class="headerlink" href="#functional-description" title="Permalink to this heading"></a></h2>
<figure class="align-center" id="id5">
<div class="align-default"><img height="725" src="../_images/blockdiag-b0756ac4bad506cab0944d38fd3c41ad966afaed.png" width="420" /></div>
<figcaption>
<p><span class="caption-text">Download procedure flow chart</span><a class="headerlink" href="#id5" title="Permalink to this image"></a></p>
</figcaption>
</figure>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>This flow chart is used to illustrate the download procedure (writing to flash), other commands have different flows.</p>
</div>
<section id="initialization">
<h3>Initialization<a class="headerlink" href="#initialization" title="Permalink to this heading"></a></h3>
<p><ul class="simple">
<li><p>The ESP chip is reset into UART bootloader mode. The host starts by sending SYNC commands. These commands have a large data payload which is also used by the ESP chip to detect the configured baud rate. ESP32-P4 always initialises at 115200bps. However the sync packets can be sent at any baud rate, and the UART peripheral will detect this.</p></li>
<li><p>The host should wait until it sees a valid response to a SYNC command, indicating the ESP chip is correctly communicating.</p></li>
<li><p>Chip type detection then uses various methods to identify chip type, subtype, revision, etc. See below.</p></li>
<li><p>Esptool then (by default) uses the “RAM Download” sequence to upload <a class="reference internal" href="../esptool/flasher-stub.html#stub"><span class="std std-ref">stub loader</span></a> code to IRAM of the chip. The MEM_END command contains the entry-point address to run the stub loader.
The stub loader then sends a custom SLIP packet of the sequence OHAI (<code class="docutils literal notranslate"><span class="pre">0xC0</span> <span class="pre">0x4F</span> <span class="pre">0x48</span> <span class="pre">0x41</span> <span class="pre">0x49</span> <span class="pre">0xC0</span></code>), indicating that it is now running. This is the only unsolicited packet ever sent by the ESP.
If the <code class="docutils literal notranslate"><span class="pre">--no-stub</span></code> argument is supplied to esptool, this entire step is skipped.</p></li>
<li><p>For commands which need to use the flash, the ESP32-P4 ROM an stub loader requires the SPI_ATTACH and SPI_SET_PARAMS commands. See <a class="reference internal" href="#spi-configuration-commands">SPI Configuration Commands</a>.</p></li>
<li><p>For stub loader and/or ESP32-P4 ROM loader, the host can send a CHANGE_BAUD command to set the baud rate to an explicit value. Compared to auto-detecting during the SYNC pulse, this can be more reliable for setting very high baud rate. Esptool tries to sync at (maximum) 115200bps and then sends this command to go to a higher baud rate, if requested.</p></li>
</ul>
</p>
</section>
<section id="initialization-chip-type-detection">
<h3>Initialization - Chip Type Detection<a class="headerlink" href="#initialization-chip-type-detection" title="Permalink to this heading"></a></h3>
<section id="esp32-p4-chip-detection">
<h4>ESP32-P4 Chip Detection<a class="headerlink" href="#esp32-p4-chip-detection" title="Permalink to this heading"></a></h4>
<p>ESP32-P4 is detected by using <strong>GET_SECURITY_INFO (0x14)</strong> command and its <strong>chip-id</strong> value.</p>
</section>
<section id="overview-of-detection-for-all-chips">
<h4>Overview of Detection for All Chips<a class="headerlink" href="#overview-of-detection-for-all-chips" title="Permalink to this heading"></a></h4>
<figure class="align-center" id="id6">
<div class="align-default"><img height="640" src="../_images/blockdiag-4db88f1b40431100ebbd1950bbf9db2615cf555a.png" width="610" /></div>
<figcaption>
<p><span class="caption-text">All chips detection flow chart</span><a class="headerlink" href="#id6" title="Permalink to this image"></a></p>
</figcaption>
</figure>
<p>On older devices that do not support the <strong>GET_SECURITY_INFO (0x14)</strong> command (which provides the <strong>chip-id</strong>), esptool falls back to reading a <strong>magic register</strong> to determine the chip type.</p>
<p>The main exception is the <strong>ESP32-S2</strong>: although it supports the <strong>GET_SECURITY_INFO (0x14)</strong> command, the output lacks the <strong>chip-id</strong>. Therefore, esptool uses the <strong>magic register</strong> as a fallback for this chip as well.
If reading the register also fails, it indicates the chip is in <strong>secure download</strong> mode.</p>
<p>For details see: <a class="reference external" href="https://github.com/espressif/esptool/blob/v5.0.2/esptool/cmds.py#L101">esptool chip detection code</a></p>
</section>
</section>
<section id="writing-data">
<h3>Writing Data<a class="headerlink" href="#writing-data" title="Permalink to this heading"></a></h3>
<p>(Includes RAM Download, Flash Download, Compressed Flash Download.)</p>
<p><ul class="simple">
<li><p>RAM Download (MEM_BEGIN, MEM_DATA, MEM_END) loads data into the ESP chip memory space and (optionally) executes it.</p></li>
<li><p>Flash Download (FLASH_BEGIN, FLASH_DATA) flashes data into the ESP SPI flash.</p></li>
<li><p>Compressed Flash Download is the same, only the data is compressed using the gzip Deflate algorithm to reduce serial overhead.</p></li>
</ul>
</p>
<p>All three of these sequences follow a similar pattern:</p>
<ul class="simple">
<li><p>A _BEGIN command (FLASH_BEGIN, etc) is sent which contains basic parameters for the flash erase size, start address to write to, etc. The uploader also needs to specify how many “blocks” of data (ie individual data packets) will be sent, and how big each packet is.</p></li>
<li><p>One or more _DATA commands (FLASH_DATA, etc) is sent where the data payload contains the actual data to write to flash/RAM. In the case of Compressed Flash Downloads, the data is compressed using the gzip deflate algorithm. The number of _DATA commands is specified in the _BEGIN command, as is the size of each _DATA payload.
The last data block should be padded to the block size with 0xFF bytes.</p></li>
<li><p>An _END command (FLASH_END, etc) is sent to exit the bootloader and optionally reset the chip (or jump to an address in RAM, in the case of MEM_END). Not necessary to send after flashing if you wish to continue sending other or different commands.</p></li>
</ul>
<p>It’s not necessary to send flash erase commands before sending commands to write to flash, etc. The ROM loaders erase the to-be-written region in response to the FLASH_BEGIN command.
The stub loader does just-in-time erasing as it writes data, to maximize overall flashing performance (each block of data is read into RAM via serial while the previous block is simultaneously being written to flash, and 4KB and 64KB erases are done as needed before writing to flash).</p>
<p>The block size chosen should be small enough to fit into RAM of the device. Esptool uses 16KB which gives good performance when used with the stub loader.</p>
<section id="verifying-uploaded-data">
<h4>Verifying Uploaded Data<a class="headerlink" href="#verifying-uploaded-data" title="Permalink to this heading"></a></h4>
<p>The 8-bit checksum used in the upload protocol is not sufficient to ensure valid flash contents after upload. The uploader should send the SPI_FLASH_MD5 command or use another method to verify flash contents.</p>
<p>The SPI_FLASH_MD5 command passes the start address in flash and the size of data to calculate. The MD5 value is returned in the response payload, before the status bytes.</p>
<p>Note that the ESP32-P4 ROM loader returns the md5sum as 32 hex encoded ASCII bytes, whereas the stub loader returns the md5sum as 16 raw data bytes of MD5 followed by 2 status bytes.</p>
</section>
</section>
<section id="spi-configuration-commands">
<h3>SPI Configuration Commands<a class="headerlink" href="#spi-configuration-commands" title="Permalink to this heading"></a></h3>
<section id="spi-attach-command">
<h4>SPI Attach Command<a class="headerlink" href="#spi-attach-command" title="Permalink to this heading"></a></h4>
<p>The SPI_ATTACH command enables the SPI flash interface. It takes a 32-bit data payload which is used to determine which SPI peripheral and pins should be used to connect to SPI flash.</p>
<p>On the ESP32-P4 stub loader sending this command before interacting with SPI flash is optional. On ESP32-P4 ROM loader, it is required to send this command before interacting with SPI flash.</p>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Value</p></th>
<th class="head"><p>Meaning</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>0</p></td>
<td><p>Default SPI flash interface</p></td>
</tr>
<tr class="row-odd"><td><p>1</p></td>
<td><p>HSPI interface</p></td>
</tr>
<tr class="row-even"><td><p>(other values)</p></td>
<td><p>Pin numbers as 6-bit values, packed into a 30-bit value. Order (from MSB): HD pin, Q pin, D pin, CS pin, CLK pin.</p></td>
</tr>
</tbody>
</table>
<p>The “Default SPI flash interface” uses pins configured via the <code class="docutils literal notranslate"><span class="pre">SPI_PAD_CONFIG_xxx</span></code> eFuses (if unset, these eFuses are all zero and the default SPI flash pins given in the datasheet are used.)</p>
<p>When writing the values of each pin as 6-bit numbers packed into the data word, each 6-bit value uses the following representation:</p>
<p>On ESP32-P4 ROM loader only, there is an additional 4 bytes in the data payload of this command. These bytes should all be set to zero.</p>
</section>
<section id="spi-set-parameters">
<h4>SPI Set Parameters<a class="headerlink" href="#spi-set-parameters" title="Permalink to this heading"></a></h4>
<p>The SPI_SET_PARAMS command sets some parameters of the attached SPI flash chip (sizes, etc).</p>
<p>All the values which are passed except total size are hardcoded, and most are not used when writing to flash. See <a class="reference external" href="https://github.com/espressif/esptool/blob/da31d9d7a1bb496995f8e30a6be259689948e43e/esptool.py#L655">flash_set_parameters function</a> in esptool for the values which it sends.</p>
</section>
</section>
<section id="bit-read-write">
<h3>32-Bit Read/Write<a class="headerlink" href="#bit-read-write" title="Permalink to this heading"></a></h3>
<p>The 32-bit read/write commands (READ_REG, WRITE_REG) allow word-oriented reading and writing of memory and register data.</p>
<p>These commands can be used to manipulate peripherals in arbitrary ways. For example, the esptool “flash id” functionality is implemented by manipulating the SPI peripheral registers to send a JEDEC flash ID command to the flash chip and read the response.</p>
</section>
<section id="reading-flash">
<h3>Reading Flash<a class="headerlink" href="#reading-flash" title="Permalink to this heading"></a></h3>
<p>The stub loader implements a READ_FLASH command. This command behaves differently to other commands, including the ROM loader’s READ_FLASH command:</p>
<ul class="simple">
<li><p>The host sends the READ_FLASH command and the data payload contains the offset, read size, size of each individual packet of data, and the maximum number of “un-acknowledged” data packets which can be in flight at one time.</p></li>
<li><p>The stub loader will send a standard response packet, with no additional data payload.</p></li>
<li><p>Now the stub loader will start sending SLIP packets with raw data (of the size requested in the command). There is no metadata included with these SLIP packets.</p></li>
<li><p>After each SLIP packet is received, the host should send back a 4 byte raw SLIP acknowledgement packet with the total number of bytes which have been received. There is no header or other metadata included with these SLIP packets.</p></li>
<li><p>The stub loader may send up to a maximum number (specified by the host in the READ_FLASH commands) of data packets before waiting for the first acknowledgement packet. No more than this “max in flight” limit can be un-acknowledged at any one time.</p></li>
<li><p>After all data packets are acknowledged received, the stub loader sends a 16 byte MD5 digest of all the data which was read from flash. This is also sent as a raw SLIP packet, with no metadata.</p></li>
</ul>
<p>After the read flash process is complete, the stub loader goes back to normal command/response operation.</p>
<p>The ROM loader read flash command is more normal but also much slower to read data.</p>
</section>
</section>
<section id="tracing-esptool-serial-communications">
<span id="tracing-communications"></span><h2>Tracing Esptool Serial Communications<a class="headerlink" href="#tracing-esptool-serial-communications" title="Permalink to this heading"></a></h2>
<p>esptool has a <code class="docutils literal notranslate"><span class="pre">--trace</span></code> option which can be supplied in the first group of arguments (before the command). This will dump all traffic sent and received via the serial port to the console.</p>
<p>Here is a sample extract, showing a READ_REG command and response:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TRACE</span> <span class="o">+</span><span class="mf">0.000</span>   <span class="o">---</span> <span class="n">Cmd</span> <span class="n">READ_REG</span> <span class="p">(</span><span class="mh">0x0a</span><span class="p">)</span> <span class="o">|</span> <span class="n">data_len</span> <span class="mi">4</span> <span class="o">|</span> <span class="n">wait_response</span> <span class="mi">1</span> <span class="o">|</span> <span class="n">timeout</span> <span class="mf">3.000</span> <span class="o">|</span> <span class="n">data</span> <span class="mi">00100040</span> <span class="o">---</span>
<span class="n">TRACE</span> <span class="o">+</span><span class="mf">0.000</span>   <span class="n">Write</span> <span class="mi">14</span> <span class="nb">bytes</span><span class="p">:</span>       <span class="n">c0000a04000000000000100040c0</span>
<span class="n">TRACE</span> <span class="o">+</span><span class="mf">0.046</span>   <span class="n">Read</span> <span class="mi">1</span> <span class="nb">bytes</span><span class="p">:</span>         <span class="n">c0</span>
<span class="n">TRACE</span> <span class="o">+</span><span class="mf">0.000</span>   <span class="n">Read</span> <span class="mi">11</span> <span class="nb">bytes</span><span class="p">:</span>        <span class="mi">010</span><span class="n">a0200090000000000c0</span>
<span class="n">TRACE</span> <span class="o">+</span><span class="mf">0.000</span>   <span class="n">Received</span> <span class="n">full</span> <span class="n">packet</span><span class="p">:</span> <span class="mi">010</span><span class="n">a0200090000000000</span>
</pre></div>
</div>
<p>The +X.XXX value is the time delta (in seconds) since the last trace line.</p>
<p>Values are printed in hexadecimal. If more than 16 bytes is printed at one time, a split display is used with hexadecimal bytes on the left and ASCII on the right. Non-printable characters are represented as <code class="docutils literal notranslate"><span class="pre">.</span></code> in ASCII:</p>
<p>Note that multiple protocol layers are represented in the logs. The “Write X bytes” lines show exactly which bytes are being sent “over the wire”, including SLIP framing. Similarly the “Read X bytes” lines show what bytes are being read over the wire, including any SLIP framing.
Once a full SLIP packet is read, the same bytes - as a SLIP payload with any escaping removed - appear in the “Received full packet” log lines.</p>
<p>Here is a second example showing part of the initial synchronization sequence (lots of 0x55 bytes which are <code class="docutils literal notranslate"><span class="pre">U</span></code> in ASCII):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>TRACE +0.000   Write 46 bytes:
  c000082400000000 0007071220555555 | ...$........ UUU
  5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU
  5555555555555555 5555555555c0     | UUUUUUUUUUUUU.
TRACE +0.012   Read 1 bytes:         c0
TRACE +0.000   Read 63 bytes:
  0108040007071220 00000000c0c00108 | ....... ........
  0400070712200000 0000c0c001080400 | ..... ..........
  0707122000000000 c0c0010804000707 | ... ............
  122000000000c0c0 01080400070712   | . .............
TRACE +0.000   Received full packet: 010804000707122000000000
TRACE +0.000   Received full packet: 010804000707122000000000
</pre></div>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>If you don’t plan to use the esptool stub loader, pass <code class="docutils literal notranslate"><span class="pre">--no-stub</span> <span class="pre">--trace</span></code> to see interactions with the chip’s built-in ROM loader only. Otherwise, the trace will show the full binary upload of the loader.</p>
</div>
<p>In addition to this trace feature, most operating systems have “system call trace” or “port trace” features which can be used to dump serial interactions.</p>
</section>
</section>


           </div>
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="firmware-image-format.html" class="btn btn-neutral float-left" title="Firmware Image Format" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
        <a href="spi-flash-modes.html" class="btn btn-neutral float-right" title="SPI Flash Modes" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; Copyright 2016 - 2026, Espressif Systems (Shanghai) Co., Ltd.</p>
  </div>

  <ul class="footer">
        <li>
	    
            
            Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/espressif/sphinx_idf_theme">theme</a>  based on <a href="https://github.com/readthedocs/sphinx_rtd_theme">Read the Docs Sphinx Theme</a>.
         </li>

  </ul> 

</footer>
        </div>
      </div>
    </section>
  </div>

  <script>
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script> 

</body>
</html>