試作品の立ち上げでマイコンのデバッグをしていると、
周辺回路の挙動が思ってたのとちょっと違うな……というのがけっこうある。
で、その場であれこれ修正しながらやっているわけだけど、
そんな中でやられたなと思ったのがDIPスイッチのビット順である。
マイコンのピン割当もなかなか苦労が多いものだと思っていたが、
DIPスイッチの1~8番をGPIOの0~7bit目に規則的に割り付けてくれてあり、
これだと下位8bitを切り取ればそのまま使えてありがたいなと。
そう思ってコーディングしていたのだが、実機で動かすとなんかおかしい。
いろいろ確認していると、MSBとLSBが逆であることに気づいた。
で、よくよくDIPスイッチを見てみたのである。
すると左から順番に1,2,3,4,5,6,7,8と書かれていて1番がMSB、8番がLSBだったのである。
このDIPスイッチ、今までも何度も何度も操作してきたけど、
左がMSB、右がLSBということしか意識していなかったので、
番号がMSB→LSBで振られているということに全く気づいていなかった。
で、基板設計した人はDIPスイッチの番号順につないでくれたわけで、
マイコンのレジスタのLSBがDIPスイッチのMSBになってしまったのである。
こりゃやられたなと思った。
もうこうなれば下位8ビットを切り取る処理は無意味なので、
GPIOレジスタの値をビットフィールドで扱えるようにして、
addr= (gpio1.ad_1<<7 | gpio1.ad_2<<6 | gpio1.ad_3<<5 | gpio1.ad_4<<4 |gpio1.ad_5<<3 | gpio1.ad_6<<2 | gpio1.ad_7<<1 | gpio1.ad_8<<0);
という書き方にしたのだった。
ビット順の入れ換えと考えればもっと効率的な書き方もありますけど……
DIPスイッチを1bitずつ順番に並べるという趣旨のわかりやすい書き方にした。
コンパイラの最適化がどんな風に働くかはわからないけど、
そんなに頻繁にやる処理でもないし、これでいいかなと。
きれいに並んでなければ元々こんなコーディングだったでしょうし。
ちなみにこのDIPスイッチの設定なのだが、
説明書には設定値ごとのDIPスイッチの設定が表として掲載されていて、
その対応表に従って設定するというのが本来のやり方である。
設定する数字にとある計算をして、それを2進数にして右をLSB、左をMSBで順番にセットしている、
というのは見る人が見ればすぐわかる話なのだが、公式には表の通りとなっている。
なので8番がLSBというところに疑問を持ってはいけないのである。
いろいろ調べるとDIPスイッチの番号は左から右に増えるのが一般的なようね。
ICの端子番号は左下から左回りに1,2,3,4……と数える慣例があり、
8極DIPスイッチの端子番号を考えると、左から1番-16番,2番-15番,3番-14番……の端子に対応する。
そういう総合的な事情を考えると左から1,2,3,4の方がありがたいと。
これにどのような意味を持たせるかは使う人次第である。
そもそも1番は機能AのON/OFF、2番はBのON/OFFのような使い方も多く、
それだとどっちがMSBかLSBかという話は全然問題にならない。
数値を表す目的で使う場合はどっちがLSBかMSBかというのは当然論点になるが、
左の1番をLSBとしているケースも多いようだ。
照明入門講座/ディップスイッチによるチャンネル設定 (サウンドハウス)
舞台照明のチャンネル番号は左の1番がLSBで、右の10番がMSBだと。
それはそういうものだと考えれば問題はないのかもしれない。
一方でうちの製品のように数字によらず、右をLSBとする考えもある。
どちらが正しいというものではないということである。
そもそも左側から大きな位を書いて行くというのが人間の発想で……
というのがバイトオーダーの話である。
コンピュータの大概の計算ではLSBから順番に計算する方が合理的である。
ゆえに2バイト以上の数値をメモリ上に格納するとき、
LSBを含むバイトから順番に格納していくリトルエンディアンが採用されることが近年は主流である。
0x12345678というデータをメモリ上に格納するとき、
アドレスの若い方から順に{78 56 34 12}と格納すると言われるとギョッとするが……
Intelはメモリ構造を図示するときに、右下を最下位アドレスとして、
右から左にバイトを並べて、上の行に進んでいくという書き方をしているらしい。
この方法でメモリダンプを表示するとあまり違和感なく読めますねとある。
と、コンピュータにとって前に格納するもの、小さな位を全部右に揃えれば人間の理解と一致するわけである。
でも、逆に前に格納するもの、小さな位を左に揃えるという考えもありそうですよねと。
おおよそ人間の理解には合わないので、2進数以外には適用困難でしょうけどね。
16極のDIPスイッチを左の1番をLSB、右側の16番をMSBに割りあてて、
このデータをリトルエンディアンでメモリ上に格納すると、
1~8番の数値が1バイト目、9~16番の数値が2バイト目に格納されることになる。
理屈には合うんですけどね。
果たしてどこまで考えてこういう仕様にしたのかはわかりませんけどね。
DIPスイッチをどう使うかはさておき、配線はLSBを揃えておく方がよかったのは明らかで、
早合点した僕もよくなかったけど、基板設計した人もどうなんだよと。
でも、僕も今日の今日まで気づいてなかったわけだし、表面的なものだけ見ていると気付かないのかも知れない。