www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | README

commit 46e08a7fceb7b64373fe34e5fe25fab6deb653a1
parent 759a35c7c18993643862dda253235389b7878cc9
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Fri, 21 Apr 2023 14:56:18 +0900

update

Diffstat:
Mman/draft/rp2040_1.html | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mpub/draft/rp2040_1.html | 208++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mpub/rss.xml | 4++--
3 files changed, 420 insertions(+), 15 deletions(-)

diff --git a/man/draft/rp2040_1.html b/man/draft/rp2040_1.html @@ -42,17 +42,20 @@ RP2040は電源を入れるといくつかの段階(ここでは関係ないの 以上のことから、プログラムを実行するためにはCRC32を計算し、UF2という形式\ に変換することが必要である。 </p> +<pre>\ +source code ---------> object ------> elf ------> crc32 ----> uf2 + compile link crc32 uf2 +</pre> <h2>CRC32(巡回冗長検査)</h2> <h3>基本</h3> <p> 入力のデータをごにょごにょしてある値を出力する。\ -<figure> <blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> -データ転送等に伴う偶発的な誤りの検査によく使われている。 +<p> +データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 +</p> </blockquote> -<figcaption><cite>Wikipedia 巡回冗長検査<sup>[5]</sup></cite></figcaption> -</figure> らしい。 </p> <p> @@ -170,6 +173,7 @@ RP2040では<code>0xffffffff</code>を使う。\ 更にこの工程を32ビットの<code>int</code>だけで行うことを考える: </p> <pre><code>\ +計算間違いしてる気がする。 111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) 11111111111111111111111111111111 0xffffffff @@ -239,10 +243,216 @@ crc32(uint8_t *idata, size_t len) return c; } </code></pre> -<h2>UF2</h2> +<p> +<code>main()</code>関数では上の<code>crc32()</code>に、<code>idata</code>として入力\ +となるバイナリデータの先頭を、<code>len</code>として<code>252</code>を渡してCRC32\ +を計算させる。その後、出力先のファイルに入力元のデータをコピーしていき、253バイト\ +目から256バイト目だけ、計算したCRC32に置き換える。入力元のこの場所にデータが\ +書き込まれていないかどうかは確かめていない。\ +<h2>UF2(USB Flashing Format)</h2> +<p> +Microsoftが開発したフラッシュ書き込み用のファイル形式らしい: +<blockquote cite="https://github.com/microsoft/uf2"> +<p> +UF2 is a file format, developed by Microsoft for PXT (also known as +Microsoft MakeCode), that is particularly suitable for flashing microcontrollers +over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. +</p> +</blockquote> +<p> +このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に\ +表として纏められている: +<blockquote cite"https://github.com/microsoft/uf2"> +<table> +<thead><tr> +<th>Offset</th><th>Size</th><th>Value</th> +</tr></thead> +<tbody> +<tr> +<td>0</td> +<td>4</td> +<td>First magic number, <code>0x0A324655</code> (<code>"UF2\n"</code>)</td> +</tr> +<tr> +<td>4</td> +<td>4</td> +<td>Second magic number, <code>0x9E5D5157</code></td> +</tr> +<tr> +<td>8</td> +<td>4</td> +<td>Flags</td> +</tr> +<tr> +<td>12</td> +<td>4</td> +<td>Address in flash where the data should be written</td> +</tr> +<tr> +<td>16</td> +<td>4</td> +<td>Number of bytes used in data (often 256)</td> +</tr> +<tr> +<td>20</td> +<td>4</td> +<td>Sequential block number; starts at 0</td> +</tr> +<tr> +<td>24</td> +<td>4</td> +<td>Total number of blocks in file</td> +</tr> +<tr> +<td>28</td> +<td>4</td> +<td>File size or board family ID or zero</td> +</tr> +<tr> +<td>32</td> +<td>476</td> +<td>Data, padded with zeros</td> +</tr> +<tr> +<td>508</td> +<td>4</td> +<td>Final magic number, <code>0x0AB16F30</code></td> +</tr> +</tbody> +</table> +</blockquote> + +<p> +RP2040のデータシート<sup>[3]</sup>を見ると、8バイト目のFlagsは28バイト目に\ +ファミリーIDが書き込まれていることを示す<code>0x00002000</code>、\ +12バイト目は書き込みを行うフラッシュROMの先頭アドレスである\ +<code>0x10000000</code>、16バイト目の、各ブロックのデータサイズは256バイト、\ +28バイト目のファミリーIDは<code>0xe48bff56</code>である。\ +あとは表の通り3つのマジックナンバーをセットし、32バイト目以降にデータを書き込み、\ +20バイト目と24バイト目にブロックの通し番号と総数をそれぞれ書き込めばいい。\ +ブロックの通し番号はデータのついでに書き込めるが、総数はデータを全部\ +さばいた後でないと分からないので、最後全てのブロックにまとめて書き込むようにした。\ +できたのが以下のコード: +</p> +<pre><code>\ +#include &lt;stdio.h&gt; +#include &lt;stdint.h&gt; +#include &lt;stdlib.h&gt; +#include &lt;string.h&gt; + + +size_t +fwrite32l(uint32_t d, FILE *f) +{ + int i; + uint8_t b; + for (i = 0; i &lt; 32; i += 8) { + b = (uint8_t) (d &gt;&gt; i & 0xff); + fwrite(&b, 1, 1, f); + if (ferror(f)) { + fprintf(stderr, "Fwrite32l: write error.\n"); + return 0; + } + } + return 4; +} +int +main(int argc, char *argv[]) +{ + FILE *src = NULL, *dst = NULL; + size_t sdata = 476; + int retnum = 0; + + uint32_t mag1 = 0x0A324655; + uint32_t mag2 = 0x9E5D5157; + uint32_t flags = 0x00002000; // familyID present + uint32_t saddr = 0x10000000; + uint32_t nbyte = 256; + uint32_t blk = 0; + uint32_t nblk = 0; + uint32_t famid = 0xe48bff56; + uint8_t data[sdata]; + uint32_t mag3 = 0x0AB16F30; + + if (argc != 3) { + fprintf(stderr, "Usage: %s src dst\n", argv[0]); + exit(1); + } + + if ((src = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[1]); + retnum = 1; + goto defer; + } + if ((dst = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[2]); + retnum = 1; + goto defer; + } + + while (!feof(src)) { + fwrite32l(mag1, dst); + fwrite32l(mag2, dst); + fwrite32l(flags, dst); + fwrite32l(saddr, dst); + fwrite32l(nbyte, dst); + fwrite32l(blk, dst); + fwrite32l(nblk, dst); // dammy + fwrite32l(famid, dst); + + memset(data, 0, sdata); + fread(data, 1, nbyte, src); + if (ferror(src)) { + fprintf(stderr, "Read error: %s.\n", argv[1]); + retnum = 1; + goto defer; + } + fwrite(data, 1, sdata, dst); + if (ferror(src)) { + fprintf(stderr, "Write error: %s.\n", argv[2]); + retnum = 1; + goto defer; + } + fwrite32l(mag3, dst); + saddr += nbyte; + blk++; + nblk++; + } + + for (int i = 0; i &lt; nblk; i++) { + if (i == 0) + if (fseek(dst, 24, SEEK_SET) &lt; 0) { + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } + fwrite32l(nblk, dst); + if (i &lt; nblk - 1) + if(fseek(dst, 512 - 4, SEEK_CUR) &lt; 0){ + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } + } + +defer: + if (src) + fclose(src); + if (dst) + fclose(dst); + return retnum; +} +</code></pre> +<p>\ +<code>fwrite32l()</code>関数は指定されたファイルに32ビットの整数を\ +下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので\ +作っておいたけど必要なのかな?あと名前が気に入らない。\ +</p> + +<h2>参考</h2> <ul> <li> [1] Hennesy, J. L. and Patterson, D. A. 2017. Computer Organization And Design RISC-V Edition. @@ -259,4 +469,7 @@ crc32(uint8_t *idata, size_t len) <li> [5] <a href="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB">巡回冗長検査.Wikipedia</a> </li> +<li> +[6] <a href="https://github.com/microsoft/uf2">USB Flashing Format (UF2).GitHub</a> +</li> </ul> diff --git a/pub/draft/rp2040_1.html b/pub/draft/rp2040_1.html @@ -41,16 +41,18 @@ RP2040は電源を入れるといくつかの段階(ここでは関係ないの <p> 以上のことから、プログラムを実行するためにはCRC32を計算し、UF2という形式に変換することが必要である。 </p> +<pre>source code ---------> object ------> elf ------> crc32 ----> uf2 + compile link crc32 uf2 +</pre> <h2>CRC32(巡回冗長検査)</h2> <h3>基本</h3> <p> -入力のデータをごにょごにょしてある値を出力する。<figure> -<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> -データ転送等に伴う偶発的な誤りの検査によく使われている。 +入力のデータをごにょごにょしてある値を出力する。<blockquote cite="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB"> +<p> +データ転送等に伴う偶発的な誤りの検査によく使われている<sup>[5]</sup>。 +</p> </blockquote> -<figcaption><cite>Wikipedia 巡回冗長検査<sup>[5]</sup></cite></figcaption> -</figure> らしい。 </p> <p> @@ -145,8 +147,9 @@ RP2040は電源を入れるといくつかの段階(ここでは関係ないの <p> これを<code>for</code>ループで回す都合上、最初のバイトもXORを取る。上の例では最初は<code>0x0</code>とXORを取っているが、この値を<code>0x0</code>以外にすることもできる。そうした方がいろいろいいこともあるらしい。RP2040では<code>0xffffffff</code>を使う。更にこの工程を32ビットの<code>int</code>だけで行うことを考える: </p> -<pre><code>111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) -|......| +<pre><code>計算間違いしてる気がする。 +111000111000000110000110111000111000001010010011111000111000000110010011 入力(適当) + 11111111111111111111111111111111 0xffffffff 11100011000000000000000000000000 先頭1バイトを24ビットシフト -------------------------------- XOR @@ -212,10 +215,196 @@ crc32(uint8_t *idata, size_t len) return c; } </code></pre> -<h2>UF2</h2> +<p> +<code>main()</code>関数では上の<code>crc32()</code>に、<code>idata</code>として入力となるバイナリデータの先頭を、<code>len</code>として<code>252</code>を渡してCRC32を計算させる。その後、出力先のファイルに入力元のデータをコピーしていき、253バイト目から256バイト目だけ、計算したCRC32に置き換える。入力元のこの場所にデータが書き込まれていないかどうかは確かめていない。<h2>UF2(USB Flashing Format)</h2> +<p> +Microsoftが開発したフラッシュ書き込み用のファイル形式らしい: +<blockquote cite="https://github.com/microsoft/uf2"> +<p> +UF2 is a file format, developed by Microsoft for PXT (also known as +Microsoft MakeCode), that is particularly suitable for flashing microcontrollers +over MSC (Mass Storage Class; aka removable flash drive)<sup>[6]</sup>. +</p> +</blockquote> +<p> +このファイルに変換する上で必要な情報はGitHubのmicrosoft/uf2<sup>[6]</sup>に表として纏められている: +<blockquote cite"https://github.com/microsoft/uf2"> +<table> +<thead><tr> +<th>Offset</th><th>Size</th><th>Value</th> +</tr></thead> +<tbody> +<tr> +<td>0</td> +<td>4</td> +<td>First magic number, <code>0x0A324655</code> (<code>"UF2\n"</code>)</td> +</tr> +<tr> +<td>4</td> +<td>4</td> +<td>Second magic number, <code>0x9E5D5157</code></td> +</tr> +<tr> +<td>8</td> +<td>4</td> +<td>Flags</td> +</tr> +<tr> +<td>12</td> +<td>4</td> +<td>Address in flash where the data should be written</td> +</tr> +<tr> +<td>16</td> +<td>4</td> +<td>Number of bytes used in data (often 256)</td> +</tr> +<tr> +<td>20</td> +<td>4</td> +<td>Sequential block number; starts at 0</td> +</tr> +<tr> +<td>24</td> +<td>4</td> +<td>Total number of blocks in file</td> +</tr> +<tr> +<td>28</td> +<td>4</td> +<td>File size or board family ID or zero</td> +</tr> +<tr> +<td>32</td> +<td>476</td> +<td>Data, padded with zeros</td> +</tr> +<tr> +<td>508</td> +<td>4</td> +<td>Final magic number, <code>0x0AB16F30</code></td> +</tr> +</tbody> +</table> +</blockquote> + +<p> +RP2040のデータシート<sup>[3]</sup>を見ると、8バイト目のFlagsは28バイト目にファミリーIDが書き込まれていることを示す<code>0x00002000</code>、12バイト目は書き込みを行うフラッシュROMの先頭アドレスである<code>0x10000000</code>、16バイト目の、各ブロックのデータサイズは256バイト、28バイト目のファミリーIDは<code>0xe48bff56</code>である。あとは表の通り3つのマジックナンバーをセットし、32バイト目以降にデータを書き込み、20バイト目と24バイト目にブロックの通し番号と総数をそれぞれ書き込めばいい。ブロックの通し番号はデータのついでに書き込めるが、総数はデータを全部さばいた後でないと分からないので、最後全てのブロックにまとめて書き込むようにした。できたのが以下のコード: +</p> +<pre><code>#include &lt;stdio.h&gt; +#include &lt;stdint.h&gt; +#include &lt;stdlib.h&gt; +#include &lt;string.h&gt; +size_t +fwrite32l(uint32_t d, FILE *f) +{ + int i; + uint8_t b; + for (i = 0; i &lt; 32; i += 8) { + b = (uint8_t) (d &gt;&gt; i & 0xff); + fwrite(&b, 1, 1, f); + if (ferror(f)) { + fprintf(stderr, "Fwrite32l: write error.\n"); + return 0; + } + } + return 4; +} +int +main(int argc, char *argv[]) +{ + FILE *src = NULL, *dst = NULL; + size_t sdata = 476; + int retnum = 0; + + uint32_t mag1 = 0x0A324655; + uint32_t mag2 = 0x9E5D5157; + uint32_t flags = 0x00002000; // familyID present + uint32_t saddr = 0x10000000; + uint32_t nbyte = 256; + uint32_t blk = 0; + uint32_t nblk = 0; + uint32_t famid = 0xe48bff56; + uint8_t data[sdata]; + uint32_t mag3 = 0x0AB16F30; + + if (argc != 3) { + fprintf(stderr, "Usage: %s src dst\n", argv[0]); + exit(1); + } + + if ((src = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[1]); + retnum = 1; + goto defer; + } + if ((dst = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Could not open %s.\n", argv[2]); + retnum = 1; + goto defer; + } + + while (!feof(src)) { + fwrite32l(mag1, dst); + fwrite32l(mag2, dst); + fwrite32l(flags, dst); + fwrite32l(saddr, dst); + fwrite32l(nbyte, dst); + fwrite32l(blk, dst); + fwrite32l(nblk, dst); // dammy + fwrite32l(famid, dst); + + memset(data, 0, sdata); + fread(data, 1, nbyte, src); + if (ferror(src)) { + fprintf(stderr, "Read error: %s.\n", argv[1]); + retnum = 1; + goto defer; + } + fwrite(data, 1, sdata, dst); + if (ferror(src)) { + fprintf(stderr, "Write error: %s.\n", argv[2]); + retnum = 1; + goto defer; + } + + fwrite32l(mag3, dst); + + saddr += nbyte; + blk++; + nblk++; + } + + for (int i = 0; i &lt; nblk; i++) { + if (i == 0) + if (fseek(dst, 24, SEEK_SET) &lt; 0) { + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } + fwrite32l(nblk, dst); + if (i &lt; nblk - 1) + if(fseek(dst, 512 - 4, SEEK_CUR) &lt; 0){ + fprintf(stderr, "Seek error: %s.\n argv[2]"); + retnum = 1; + goto defer; + } + } + +defer: + if (src) + fclose(src); + if (dst) + fclose(dst); + return retnum; +} +</code></pre> +<p><code>fwrite32l()</code>関数は指定されたファイルに32ビットの整数を下位バイトから順に書き込む関数である。バイトオーダーとかややこしそうなので作っておいたけど必要なのかな?あと名前が気に入らない。</p> + +<h2>参考</h2> <ul> <li> [1] Hennesy, J. L. and Patterson, D. A. 2017. Computer Organization And Design RISC-V Edition. @@ -232,6 +421,9 @@ crc32(uint8_t *idata, size_t len) <li> [5] <a href="https://ja.wikipedia.org/wiki/%E5%B7%A1%E5%9B%9E%E5%86%97%E9%95%B7%E6%A4%9C%E6%9F%BB">巡回冗長検査.Wikipedia</a> </li> +<li> +[6] <a href="https://github.com/microsoft/uf2">USB Flashing Format (UF2).GitHub</a> +</li> </ul> </article> diff --git a/pub/rss.xml b/pub/rss.xml @@ -5,8 +5,8 @@ <description>ウェブページの更新履歴</description> <language>ja-jp</language> <link>https://www.mtkn.jp</link> -<lastBuildDate>Thu, 20 Apr 2023 20:12:16 +0900</lastBuildDate> -<pubDate>Thu, 20 Apr 2023 20:12:16 +0900</pubDate> +<lastBuildDate>Fri, 21 Apr 2023 14:55:46 +0900</lastBuildDate> +<pubDate>Fri, 21 Apr 2023 14:55:46 +0900</pubDate> <docs>https://www.rssboard.org/rss-specification</docs> <item> <title>Xlibで遊んでみる6</title>