commit 46e08a7fceb7b64373fe34e5fe25fab6deb653a1
parent 759a35c7c18993643862dda253235389b7878cc9
Author: Matsuda Kenji <info@mtkn.jp>
Date: Fri, 21 Apr 2023 14:56:18 +0900
update
Diffstat:
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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+size_t
+fwrite32l(uint32_t d, FILE *f)
+{
+ int i;
+ uint8_t b;
+ for (i = 0; i < 32; i += 8) {
+ b = (uint8_t) (d >> 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 < nblk; i++) {
+ if (i == 0)
+ if (fseek(dst, 24, SEEK_SET) < 0) {
+ fprintf(stderr, "Seek error: %s.\n argv[2]");
+ retnum = 1;
+ goto defer;
+ }
+ fwrite32l(nblk, dst);
+ if (i < nblk - 1)
+ if(fseek(dst, 512 - 4, SEEK_CUR) < 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+size_t
+fwrite32l(uint32_t d, FILE *f)
+{
+ int i;
+ uint8_t b;
+ for (i = 0; i < 32; i += 8) {
+ b = (uint8_t) (d >> 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 < nblk; i++) {
+ if (i == 0)
+ if (fseek(dst, 24, SEEK_SET) < 0) {
+ fprintf(stderr, "Seek error: %s.\n argv[2]");
+ retnum = 1;
+ goto defer;
+ }
+ fwrite32l(nblk, dst);
+ if (i < nblk - 1)
+ if(fseek(dst, 512 - 4, SEEK_CUR) < 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>