外付けSSDにUbuntuをインストールしてデュアルブート環境を構築してみた

外付けSSDUbuntuをインストールしてみたのでメモ。

現在のところ、特に問題なく使用できている。

準備

ライブUSB用のUSBメモリ
Amazon | BUFFALO【国内メーカー】 USBメモリ 32GB USB3.2(Gen1)/3.1(Gen 1)/3.0/2.0 充実サポート RUF3-K32GA-BK/N【Amazon.co.jp限定】 | バッファロー | USBメモリ・フラッシュドライブ 通販

外付けSSD
Amazon | BUFFALO USB3.1Gen1 ポータブルSSD 480GB 日本製 PS5/PS4(メーカー動作確認済) 耐衝撃・コネクター保護機構 SSD-PG480U3-B/NL | バッファロー | 外付SSD 通販

SSD用USBケーブル
付属のケーブルは50cmと短く、取り回しがしづらそうだったので別で購入。
Amazon.co.jp: エレコム USBケーブル 【microB】 USB3.0 (USB A オス to microB オス) スタンダード 2m ブラック USB3-AMB20BK: パソコン・周辺機器

USBハブ(セルフパワータイプ)
Amazon | BUFFALO USB3.0 セルフパワー 4ポートハブ ブラック 外付けHDDに最適 上挿しモデル マグネット付き BSH4A315U3BK 【Windows/Mac 対応】 | バッファロー | USBハブ 通販

ISOファイル
Ubuntu 20.04 LTS
今回は日本語Remixを使用した。
以下からISOイメージをダウンロードしておく。
Ubuntu 20.04 LTS 日本語 Remix リリース | Ubuntu Japanese Team

手順

基本的にはこちらの記事をほぼそのまま参考にさせてもらった。
Ubuntu 20.04 LTS インストール方法(外付けドライブ用) - Qiita

つまづきポイント

ライブUSBで起動時、画面が固まってしまい、インストールに進めなかった。
調べてみたところ、NVIDIAGPUドライバ周り?の不具合らしい。
以下を参考に、ブート時のメニューで「Ubuntu (safe graphics)」を選択することで、フリーズを回避できた。
Ubuntu 20.04 その25 - Ubuntu 20.04 LTSの既知の問題 - kledgeb

Ubuntu (safe graphics)」を選択して起動した場合、画面の解像度が低く、 インストールウィザードが画面からはみ出してしまい、次へ進むボタンなどが押せなくなってしまう。
Superキー(WindowsでいうWinキー)を押しながらドラッグすることでウィンドウを移動できる。
Ubuntu 18.04 その96 - Ubuntuやフレーバーインストール時、インストーラーの画面がディスプレイからはみ出す場合は - kledgeb

初心者が組み込みRustやってみる - その4

初心者が組み込みRustやってみる - その3 - 雨垂れ石を穿つ
のつづき。

8. LED、再び

tomoyuki-nakabayashi.github.io

これまでは初期設定済みのペリフェラルが提供されていたが、今度は自分で初期設定する。

ほとんどのペリフェラルは、電源が入っていない状態で起動する。そのため、RCC (Reset and Clock Control) を使ってペリフェラルの電源をオンにしないといけないらしい。

さらに、GPIOは電源を入れた後の初期状態だとデジタル入力として設定されている。デジタル出力として使うよ、の設定をしないといけない。

マニュアルやrustdocと格闘して、なんとか解答例を見ずに自力でLEDを点灯させることができた。
今は「マニュアルのここに書いてあるよ」が与えられているが、それも自分で探すのは相当大変そう。。。
でも苦労の末、思った通りに動くと楽しい。

9. クロックと時間

tomoyuki-nakabayashi.github.io

今まで与えられていたdelay関数を自分で実装する。

9.1. forループで遅延

  • forループによる遅延は、マイクロコントローラ内のプロセッサのクロック数に依存する。
  • 空のfor文はコンパイラによる最適化で削除されるため、releaseモードで実行すると遅延しなくなってしまう。

9.2. NOP

  • 最適化によってdelay関数が壊れないようにするには、 cortex_m クレートの cortex_m::asm::nop を呼び出す。

9.3. ワンショットタイマ

  • forループの代わりに、ハードウェアタイマを使って遅延を実装する。
  • ハードウェアタイマは、マイクロコントローラから利用できるペリフェラルの1つ。レジスタを使って制御できる。
    • TIM6 というのが使えるらしい。マニュアルを読むと、内部的にはDAC(Digital to Analog Converter)にも繋がっていて、DACをdriveする(駆動する?動かす?)のにも使われているらしい。

マニュアルを読みつつ、分からないところは手順に従いつつ、最終的なコードは以下。

#![no_main]
#![no_std]

use aux9::{entry, tim6};

#[inline(never)]
fn delay(tim6: &tim6::RegisterBlock, ms: u16) {
    // ms tick後にオフになるようにタイマを設定
    tim6.arr.write(|w| w.arr().bits(ms));
    // タイマを有効化
    tim6.cr1.write(|w| w.cen().set_bit());
    // 更新イベントが発生するまで待つ
    while !tim6.sr.read().uif().bit_is_set() {}
    // 更新イベントフラグをクリアする
    tim6.sr.modify(|_, w| w.uif().clear_bit());
}

#[entry]
fn main() -> ! {
    let (mut leds, rcc, tim6) = aux9::init();

    // TIM6の電源を入れる
    rcc.apb1enr.modify(|_, w| w.tim6en().set_bit());
    // OPM (One Pulse Mode) に設定する
    tim6.cr1.write(|w| w.opm().set_bit().cen().clear_bit());
    // カウンタが1KHzで動作するようにプリスケーラを設定する
    let psc = 7999;
    tim6.psc.write(|w| w.psc().bits(psc));

    let ms = 50;
    loop {
        for curr in 0..8 {
            let next = (curr + 1) % 8;

            leds[next].on();
            delay(tim6, ms);
            leds[curr].off();
            delay(tim6, ms);
        }
    }
}

まとめ

  • ペリフェラルを使うには、電源を入れるところから。
  • 電源の入れ方や使い方(どのレジスタにどんな値をセットするか)はマニュアルを頑張って読む。
    • とにかくマニュアルをよく読んで理解することが重要だと感じた。
  • ハードウェアタイマを利用することで、正確なタイミングで処理を実行できる。
  • 苦労して作ったものが動くと、楽しい。

初心者が組み込みRustやってみる - その3

初心者が組み込みRustやってみる - その2 - 雨垂れ石を穿つ
のつづき。

6. Hello, world!

  • iprintln!panic! マクロは、マイクロコントローラのITMにメッセージを出力する。
  • ITM は Instrumentation Trace Macrocell の略で、SWD(Serial Wire Debug)の上で通信するプロトコル
  • マイクロコントローラからデバッグしているホストPCにメッセージを送ることができる。
  • OpenOCD はマイコンとホストPCを接続するためのもので、その上でITMプロトコルで受信したデータを解釈するためのツールが itmdump ?

冒頭に

注意 ユーザーマニュアル(page 21)ではんだ付けしなければならないと書いてあるにも関わらず、 STM32F3DISCOVERY上のSB10「はんだブリッジ」(ボードの裏を見て下さい)がはんだ付けされていない、と複数の読者が報告しています。 これは、後ほど出てくるITMとiprint!マクロを使うために必要です。
TL;DR 2つの選択肢があります。SB10はんだブリッジをはんだ付けするか、下記写真の通りSW0とPB3の間をワイヤで接続するか、です。

のように注意書きがあり、これをしないと itmdump を実行しているターミナルに何も出力されなかった。
(はんだ付けされているように見えたが、よくわからず。)
指示の通りジャンパワイヤで接続することで、itmdumpを実行したコマンドプロンプト上ににログが出力された。

7. レジスタ

  • レジスタに値を書き込むことで、ペリフェラル(今回はGPIO)を制御することができる。
    • LEDと接続されているGPIOピンにhighを書き込むことで、LEDが点灯する。
  • レジスタの詳細を知るには、リファレンスマニュアルを読む。

7.1. RTRM(Read The Reference Manual)

  • マニュアルを読むことで、メモリのどのアドレスがどのレジスタに対応するかがわかる

7.2. (誤った)最適化

コンパイラによる最適化によって、意図しない動きをしてしまうことがある。
元のプログラム

        // A magic address!
        const GPIOE_BSRR: u32 = 0x48001018;

        // Turn on the "North" LED (red)
        *(GPIOE_BSRR as *mut u32) = 1 << 9;

        // Turn on the "East" LED (green)
        *(GPIOE_BSRR as *mut u32) = 1 << 11;

        // Turn off the "North" LED
        *(GPIOE_BSRR as *mut u32) = 1 << (9 + 16);

        // Turn off the "East" LED
        *(GPIOE_BSRR as *mut u32) = 1 << (11 + 16);

コンパイラによる最適化
同じアドレスへの書き込みは無駄なので、最後の書き込みだけが有効となる。

        // A magic address!
        const GPIOE_BSRR: u32 = 0x48001018;

        // Turn off the "East" LED
        *(GPIOE_BSRR as *mut u32) = 1 << (11 + 16);

誤った最適化を避けるには、通常の読み書きの代わりにvolatile操作 core::ptr::write_volatile を使う。

7.3. 0xBAAAAAAD番地

  • 不正な番地(そのアドレスにレジスタがない)にアクセスした場合、例外が発生する。
  • gdbのコマンドを使うことで、例外が発生した際のプログラムカウンタやレジスタの値を確認することができる。

7.5. 型安全な操作

16進数のアドレスを直接扱ってメモリにアクセスすることは間違いのもと。
安全な方法でレジスタにアクセスするためのAPIを使用する。

最初のプログラム

#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux7::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
    aux7::init();

    unsafe {
        // 魔法のアドレス!
        const GPIOE_BSRR: u32 = 0x48001018;

        // 「北」のLED(赤)を点灯します
        *(GPIOE_BSRR as *mut u32) = 1 << 9;

        // 「東」のLED(緑)を点灯します
        *(GPIOE_BSRR as *mut u32) = 1 << 11;

        // 「北」のLEDを消灯します
        *(GPIOE_BSRR as *mut u32) = 1 << (9 + 16);

        // 「東」のLEDを消灯します
        *(GPIOE_BSRR as *mut u32) = 1 << (11 + 16);
    }

    loop {}
}


安全な方法(API)を使用したプログラム

#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux7::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
    let gpioe = aux7::init().1;

    // 北のLEDを点灯
    gpioe.bsrr.write(|w| w.bs9().set_bit());

    // 東のLEDを点灯
    gpioe.bsrr.write(|w| w.bs11().set_bit());

    // 北のLEDのを消灯
    gpioe.bsrr.write(|w| w.br9().set_bit());

    // 東のLEDを消灯
    gpioe.bsrr.write(|w| w.br11().set_bit());

    loop {}
}

このAPIは、 https://crates.io/crates/svd2rust のツールを使用して、System View Description (SVD) ファイルから自動生成されている。
SVDファイルはマイクロコントローラのベンダが提供するXMLファイルで、レジスタブロックのレイアウトやベースアドレス、レジスタのRead/Writeのパーミッションなどの情報が含まれる。

初心者が組み込みRustやってみる - その2

初心者が組み込みRustやってみる - その1 - kanno's blog
のつづき。

5. LEDルーレット

github.com

こちらのリポジトリからテンプレートをクローンしてきて実行する。

5.1 ビルド

以下のコマンドがうまくいかず。

cargo readobj --target thumbv7em-none-eabihf --bin led-roulette -- -file-headers

github.com

のIssueを参考に cargo-binutils のバージョンを0.3.0に上げてみたところ、うまくいった。

5.5 課題

8つのLEDを順番に点灯、消灯させる課題が与えられる。

以下のような実装で実現できた。

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::{entry, prelude::*, Delay, Leds};

#[entry]
fn main() -> ! {
    let (mut delay, mut leds): (Delay, Leds) = aux5::init();

    let half_period = 50_u16;

    let mut prev = 0;
    let mut curr = 1;
    loop {
        leds[curr].on();
        delay.delay_ms(half_period);

        leds[prev].off();
        delay.delay_ms(half_period);

        prev = curr;
        curr = (curr + 1) % 8;
    }
}

初心者が組み込みRustやってみる - その1

組み込みに興味があるので、やってみる。

前提

  • 普段はAndroidエンジニア。
  • Web(フロントエンド・バックエンド)も大体わかる。
  • 組み込みはまったくの未経験。
    • 数年前にラズパイを少しだけ触ってみたことがある。
    • がラズパイとマイコンの違いもよく分かっていない。どうやら違うらしい、ということに最近気がついたレベル。
  • Rustは業務では使っていないが競技プログラミングで使用していて、小さなプログラムを書いた経験はある。

教材

docs.rust-embedded.org

で紹介されている

docs.rust-embedded.org

の日本語訳の

tomoyuki-nakabayashi.github.io

をやってみる。
日本語訳ありがたや・・・。

ハードウェアの準備

こちらに従ってハードウェアを準備した。

tomoyuki-nakabayashi.github.io

購入先は以下。

メモ
F3のマイクロコントローラは、「Cortex-M4Fプロセッサ」というのを搭載しているらしい。

開発環境の構築

手順に従って各種ツールをインストール。 今回はWindowsでやってみる。 特に詰まることもなく、手順通りインストールできた。

今回は環境を作るところまで。 後日続きをやっていく。

【書籍】アウトプット大全

BEFORE

技術書を中心に書籍を読んでいるが、身についた・役立った実感があまり持てていなかった。
他の人のブログでこの本が紹介されているのを見て、効率的に学習して役立てる方法を知りたいと思い購入。

AFTER

気づき

  • アウトプットしなければ、記憶に残らない。自己成長ではなく、自己満足
  • 実際に本書を読みながら、アウトプットしてみた感想
    • 気づきを得た箇所にマークをつけて、後からアウトプットのために見返すので、インプットの質も上がったように感じる

TODO

  • 今後読む本は、ブログに読書感想を書く

メモ

以下は自分が「いいな」「なるほど」と思った箇所のメモ

1章 アウトプットの基本法

  • 記憶はアウトプットにより定着する
    • インプット:アウトプットの黄金比は3:7

2章 科学に裏付けられた、伝わる話し方

  • 「クッション話法」で柔らかく伝える
    • ダメな話法
      • No But 話法
        • 例: 最近、遅刻が多いようだな。せっかく売上業績が上がっているのに台無しじゃないか
    • クッション話法
      • Yes 〜 But話法
        • 例: 最近、売上業績も上がっているし、がんばっているね。ただ、遅刻が多いのは問題だな。時間厳守で頼むよ
        • ポジティブな話を先に伝える。
  • 褒める
    • 「結果」ではなく、「強化したい行動」をできるだけ細かく伝える
      • 「結果」を褒めると、増長する
      • 「行動」を褒めると、気付きにつながる
  • 叱る
    • 感情をぶつけるのは「怒る」
    • 修正したい具体的な方法を指摘する
    • 失敗した原因・理由・対策を本人に考えさせる/一緒に考える

3章 能力を最大限に引き出す書き方

  • 書く
    • 書くことによって、脳は対象物に対して集中力を高め、積極的に情報を収集し始める
  • ひらめく
    • ひらめきに必要な4つの段階
      • 準備
        • 問題や課題と徹底的に格闘する
          • たくさん本や資料を読む
          • ノートやカードに何かを書き出してみる
          • チームで議論や討論をする
      • 孵化(インキュベーション)
        • 問題をしばらく放置する
      • ひらめく
        • 無意識のうちに情報の再編・関連づけが行われた結果、ひらめきが生まれる
      • 検証
        • ひらめきが本当に正しいのか、理論的・実践的に検証する
  • 目標を実現する
    • 毎日目標を見返す
      • 脳に目標が刻み込まれ、実現のために必要な情報を無意識に探すようになる
    • 目標を公言する
      • 適度なプレッシャー
    • 定期的にフィードバックする
      • 達成度を評価して、できていない場合対策を講じる

4章 圧倒的に結果を出す人の行動力

  • 行動する
    • 行動しなければ、「自己成長」ではなく、「自己満足」
  • 続ける
    • 「今日やる」ことだけを考える
    • 楽しみながら実行する
    • 目標を細分化する
    • 結果を記録する
    • 結果が出たらご褒美をあげる
  • 決断する
    • 5秒で決める
      • ファーストチェス理論
        • プロのチェスプレイヤーが5秒で決めた次の手と30分かけて考えた手は、86%一致する
        • 知識や経験が十分にある、熟練した専門家の直感的な最初の判断は、かなり正しい
    • ワクワクする方を選ぶ
      • ドーパミンが出ていて脳のパフォーマンスがアップするので、成功する確率が高い
    • 最初に思いついた方を優先する
      • 最初に思いついたアイデアは、直感であり本能に根ざした心の声
      • 後から出てくる考えは、たいてい打算的・常識的でこぢんまりとした正論
  • 眠る
    • 6時間睡眠を14日間続けると、2日間完全に徹夜したときと同程度の集中力低下が起こる
    • 7時間以上の睡眠が必須
    • 喫煙より睡眠不足の方が、はるかに健康に悪い

5章 アウトプット力を高める7つのトレーニング法

  • 読書感想を書く
    • 本を読んだら、必ずその感想を書く
    • アウトプットするからこそ記憶に残り、自己成長につながる
    • 読書感想のテンプレート
      • ビフォー
      • アフター
        • 気づき
        • TODO