Spacemacs に Specman mode を導入する
概要
有名なパッケージではないため自動でインストールできない major-modeである specman-mode を手動で使えるように設定する。
手順
以下の通りに進みます。
- specman-mode.el のダウンロード
- load-path とモードの追加
specman-mode.el のダウンロード
24 以降に対応した specman-mode を Cadence forum から入手する。
適当な場所(.spacemacs.d/lisps など)に置く。
load-path とモードの追加
emacs を立ち上げて
space f e d
で .spacemacs または .spacemacs.d/init.el を開く。 そして dotspacemacs/user-config に以下を追加する
(add-to-list 'load-path "~/.spacemacs.d/lisps") ;;specman-mode (autoload 'specman-mode "specman-mode" "Specman code editing mode" t) (setq auto-mode-alist (remove-duplicates (append (list (cons "\\.e\\'" 'specman-mode) (cons "\\.ecom\\'" 'specman-mode) (cons "\\.erld\\'" 'specman-mode)) auto-mode-alist)))
これで使えるようになります。 もろもろ不慣れで幼稚なミスで autoload できずにはまった。 ※ load-path に設定するパスをミスしていた。
Spacemacs
目的
emacs + vim という最新の環境に開発環境をアップデートする。 ちなみに私はそこまでカスタマイズしていないemacsを15年くらいは使っている。 vi はほぼ使ったことが無い。
きっかけ
最新のemacs環境を調べていたら、世の中は vim が主流になっていることが判明した。 確かに周りでも vim を使う人が多いとは感じていた。 そろそろ vim に切り替えるかと思っていたら
こんな記事に出会って、今の私に一番違和感なく環境をアップデートできそうだと感じた。 これをきっかけに vim でも編集ができるようになれればと思う。
概要
emacs にもろもろの拡張をセットにしてインストールして、 カスタマイズしまくったものを spacemacs と呼んでいる。 そのインストールは spacemacs という拡張lisp で一括インストールできる。
spacemacs は Githubにあり、
からダウンロードできる。 基本的には素の emacs に対して ~/emacs.d を上記のもので置き換えるだけ。 15年前には考えられないような状態なので、特にカスタマイズしていないで使ってきた私にはちょっと衝撃だった。
インストールの詳細はREADME.mdを参照してもらえれば問題ない。
機能のこと
素のemacsを拡張しているが、それ自体は spacemacs の外で開発されている。 主な拡張は
Evil
- vi キーバインドにする拡張で初期設定で選択することで有効になる。
- 参考:Evil: EmacsをVimのごとく使う - 導入編 - 貳佰伍拾陸夜日記
neotree
which-key
- コマンドのヒント情報がbuffer下部に表示される
- 参考:GitHub - justbur/emacs-which-key: Emacs package that displays available keybindings in popup
helm
日本語入力
Windows から Linux に入って Xwindowを飛ばしているので、mozcをインライン表示したい。 また、fcitx + mozc と emacs25 を使うように Linux 環境は構築してある。
インストール
emacs-mozc-bin パッケージを linux に導入する。emacs-mozcは導入しない。 また、.spacemacs または spacemacs.d/init.el の user-config 内に
(defun dotspacemacs/user-config () ;; 省略 ;;mozc (when (require 'mozc nil t) (setq default-input-method "japanese-mozc") (global-set-key [zenkaku-hankaku] 'toggle-input-method) ;; 全角半角で切り替えられる (defvar mozc-candidate-style) ;; avoid compile error (if (require 'mozc-popup nil t) (setq mozc-candidate-style 'popup) (setq mozc-candidate-style 'echo-area))) ;;省略 )
のように記述する
おまけ
入力モードの切り替えが暴走する事がある。それを防ぐため .bashrc に
xset -r 49
を追加した。
Spacemacs 操作方法備忘録
個人的な備忘録
neotree の表示
Space f t
Raspberry pi で AP のレジスタをC言語で直接変更してモーターを PWM で操作する
目的
PWM でDCモータを操作します。 また、フルブリッジのモータードライバICを使います。
注意点
Linux のシステムコールを含む(mmap関数)ので、root 権限が必要なため sudo コマンドを利用する必要があります。 プログラム名を sample.c とするならば、
$ gcc sample.c $ sudo ./a.out
のように実行してください。
モータドライバIC
TA7291P を使いました。
モータードライバー TA7291P (2個入): 半導体 秋月電子通商 電子部品 ネット通販
端子記号 | 端子番号 | 端子説明 |
---|---|---|
GND | 1 | GND |
OUT1 | 2 | 出力端子 |
NC | 3 | |
Vref | 4 | 制御電源端子 |
IN1 | 5 | 入力端子 |
IN2 | 6 | 入力端子 |
VCC | 7 | ロジック側電源端子 |
VS | 8 | 出力側電源端子 |
NC | 9 | |
OUT2 | 10 | 出力端子 |
回路の概要
本当は RaspberryPi 3 を使っています。
main() プログラム
正転と逆転をGPIO20/21 を使って切り替えています。
void main() { volatile unsigned *addr; int count; //-------------------------- // GPIO gpio = io_mapping(GPIO_BASE); // set GPIO18 mode to ALT5(PWM0) *(gpio + 0x4/4) = (*(gpio + 0x4/4) & ~(0x7 << 24 )) | (0b010 << 24); // set GPIO20/21 mode to Output *(gpio + 0x8/4) = (*(gpio + 0x8/4) & ~(0x7 << 0 )) | (0b001 << 0); *(gpio + 0x8/4) = (*(gpio + 0x8/4) & ~(0x7 << 3 )) | (0b001 << 3); //-------------------------- // Clock clk = io_mapping(CLK_BASE); // add the offset address of pwm clk manager clk += 0xA0/4; // disable *clk = CLK_PASSWD + (0x1<<5); // divided by 192 *(clk+0x4/4) = CLK_PASSWD + (192 << 12); // choose oscillator(19.2MHz) as source *clk = CLK_PASSWD + 0x1 + (0x1 << 4); //-------------------------- // PWM pwm = io_mapping(PWM_BASE); *pwm = 0; // Disable usleep(10); *(pwm + 0x10/4) = 8; // set RNG *(pwm + 0x14/4) = 6; // set DAT *pwm = 0x1; // Enable //-------------------------- // drive motor for( count = 0; count < 2; count++ ){ // set if( count % 2 ){ *(gpio + 0x1C/4) = 0x1 << 20; } else { *(gpio + 0x1C/4) = 0x1 << 21; } sleep(3); // clear *(gpio + 0x28/4) = 0x1 << 21; *(gpio + 0x28/4) = 0x1 << 20; sleep(3); } *pwm = 0; // Disable usleep(10); }
電圧、電流波形
ChannelA が電圧(PWM)で、ChannelB は電流波形です。 また、電流波形は1Ωの抵抗両端で測定しました。
Raspberry pi で AP のレジスタをC言語で直接変更して PWM を操作する
やること
Raspberry Pi 用の特別なライブラリとドライバを利用せずにPWMをC言語で操作する。
注意点
Linux のシステムコールを含む(mmap関数)ので、root 権限が必要なため sudo コマンドを利用する必要があります。 プログラム名を sample.c とするならば、
$ gcc sample.c $ sudo ./a.out
のように実行してください。
main()
IC 18pin (RaspberryPi の端子だと 12pin) をALT5モードにして、PWMを発生させる。 PWM のサブモードは
- ある期間(M, RNG)内で、バランスよく N(N, DAT) 回 Highとなる
- サイトによっては balanced mode と記載あり
- 仕様書にはPWM algorithm
- ある期間(M, RNG)内で、最初に N(N, DAT) 回 Highとなる
- サイトによっては legacy mode と記載あり
- 仕様書には M/S transmission
の2つあります。 正式な名称は不明で、完全な仕様書を読むと記載があるのかもしれません。
実際の波形
上記のモードだけを切り替えた波形を参考に添付します。 他の設定値は同じです。
balanced mode
legacy mode
サンプルコードではクロックのソースを Oscillator(19.2MHz)にして これをもとに 192 分周して100kHzにしています。 また、PWM algorithm( balanced mode ) です。
void main() { //------------------------------------ // set GPIO18 mode to ALT5(PWM0) //------------------------------------ gpio = io_mapping(GPIO_BASE); *(gpio + 0x4/4) = (*(gpio + 0x4/4) & ~(0x7 << 24 )) | (0b010 << 24); //------------------------------------ // set source clock //------------------------------------ clk = io_mapping(CLK_BASE); clk += 0xA0/4; // Oscillator 19.2MHz *clk = CLK_PASSWD + (0x1<<5); *(clk+0x4/4) = CLK_PASSWD + (192 << 12); *clk = CLK_PASSWD + 0x1 + (0x1 << 4); //------------------------------------ // set pwm //------------------------------------ pwm = io_mapping(PWM_BASE); *pwm = 0; // Disable usleep(10); // wait for stable *(pwm + 0x10/4) = 4; // set RNG *(pwm + 0x14/4) = 2; // set DAT *pwm = 0x1; // Enable }
物理アドレスのアクセス用マッピング
過去記事を参照してください。
使っているレジスタ
Clock 関連
ADDRESS | Name | Description | Size | Read/Write |
---|---|---|---|---|
0x3F10_1000 | CM_PWMCTL | PWM Clock Control | 32 | R/W |
0x3F10_1004 | CM_PWMDIV | PWM Clock Divisors | 32 | R/W |
CM_PWMCTL
名前は類推で、記載を見つけられず WiringPi ソースコードから該当アドレスを確認しました。 ただし、CM_GPnCTL レジスタの記述があり、レジスタの操作は仕様書が参考になります。
Clock 系のレジスタへの書き込みはbit[31:24]に0x5a を同時に書き込む必要があります。
使っている bit field は
SRC bit[3:0]
- 0 : GND
- 1 : oscillator
- 4 : PLL
- 他にも色々ある
ENAB bit[4]
- 1 : Start
- 0 : Stop
KILL bit[5]
- 1 : stop and reset
- 0 : no action
です。
CM_PWMDIV
名前は類推で、記載を見つけられず WiringPi ソースコードから該当アドレスを確認しました。 ただし、CM_GPnDIV レジスタの記述があり、レジスタの操作は仕様書が参考になります。
クロックの分周を決めるレジスタです。
使っている bit field は
- DIVI bit[23:12]
- Integer part of divisor
PWM 設定関連
ADDRESS | Name | Description | Size | Read/Write |
---|---|---|---|---|
0x3F20_C000 | CTL | PWM Channel1 Range | 32 | R/W |
0x3F20_C010 | RNG1 | PWM Channel1 Range | 32 | R/W |
0x3F20_C014 | DAT1 | PWM Channel1 Data | 32 | R/W |
CTL
仕様書からの抜粋です。 初期値はどれも 0x0 で、 bit0(Enable) と bit7(PWMのモード切り替え) を使えばほぼ大丈夫なはず。
bit# | Name | Description | Read/Write |
---|---|---|---|
7 | MSEN1 |
Channel 1 M/S Enable 0: PWM algorithm is used 1: M/S transmission is used. |
RW |
4 | POLA1 |
Channel 1 Polarity 0 : 0=low 1=high 1: 1=low 0=high |
RW |
1 | MODE1 |
Channel 1 Mode 0: PWM mode 1: Serialiser mode |
RW |
0 | PWEN1 |
Channel 1 Enable 0: Channel is disabled 1: Channel is enabled RW 0x0 |
RW |
RNGn
PWM の期間をこのレジスタ値で分割します。 32 未満の値で設定してください。
DATn
RNGn で設定した期間のうちHiとする回数を設定できます。
全容
Raspberry pi で AP のレジスタをC言語で直接変更して GPIO を操作する
やること
Raspberry Pi 用の特別なライブラリとドライバを利用せずにGPIOをC言語で操作する。
その他の普通の手段
wiringPi を利用する
Device Tree Overlay でドライバを利用する
gpio コマンドを利用する
- 本質的には wiringPi と同じ
注意点
Linux のシステムコールを含む(mmap関数)ので、root 権限が必要なため sudo コマンドを利用する必要があります。 プログラム名を sample.c とするならば、
$ gcc sample.c $ sudo ./a.out
のように実行してください。
main()
IC 20pin (RaspberryPi の端子だと 38pin) を操作して、High/Low をずっと繰り返す。
アドレスをいちいち addr/4 していますが、仕様書に記載されている byte アドレスを 32bit(4byte)アドレスに変換しているためです。 C言語の int は今回 32bitなので、アドレスを保持しているポインタに 1 を加算すると 32bit 分ポインタがずれます。
void main() { int count; volatile unsigned *addr; gpio = io_mapping(GPIO_BASE); // set GPIO20 to output mode ( bit[2:0] ). offset is 0x8( byte address ) . *( gpio + 0x8/4 ) = (*( gpio + 0x8/4 ) & ~(0x7)) | (0x1 << 0); for( count = 0 ; ; count++){ usleep(1000); addr = ( count % 2 ) ? gpio + 0x1C/4 : gpio + 0x28/4 ; *addr = 0x1 << 20; } }
物理アドレスのアクセス用マッピング
過去記事を参照してください。
使っているレジスタ
ADDRESS | Name | Description | Size | Read/Write |
---|---|---|---|---|
0x3F20_0008 | GPFSEL2 | GPIO Function Select 2 | 32 | R/W |
0x3F20_001C | GPSET0 | GPIO Pin Output Set 0 | 32 | W |
0x3F20_0028 | GPCLR0 | GPIO Pin Output Clear 0 | 32 | W |
GPFSELn
SoC の端子は色々な機能を切り替えられるようになっていて、 RaspberryPi も同じようになっている。 今回は output モードに切り替えていて、GPFSEL2 の bit[2:0] に 1 を書き込んでいます。
GPSETn
Write Only のレジスタで、1 の書き込みで対応するGPIOが High になる。
GPCLRn
Write Only のレジスタで、1 の書き込みで対応するGPIOが Low になる。
その他
レジスタの値をそのまま反映する GPLEVn もあるが、他のGPIOの値を含めてレジスタReadして対応するbitだけ変更する必要がり(Read modified write)、少し手数が増えて複雑となります。
全容
Raspberry pi で AP のレジスタを操作する前に
Linux からのレジスタ操作
仮想アドレス
OS上の通常のプログラムはハードウェアのアドレス(物理アドレス)からは隔離されていて、 仮想的なアドレス空間上で動作しています。 その仮想アドレスがOSとHW(MMU)で変換されて、一部が物理アドレスです。
そのため、AP の仕様書に記載されている物理アドレスへアクセスするにはひと工夫が必要です。
mmap()
Linux のシステムコールmmap()を使って、物理アドレスへアクセスすることができます。
今回は SRAM の開始アドレスが仕様書から 0x0000_0000 であることがわかるので、 これを基準にしてGPIOなどへアクセスします。
mmap() の概要
物理アドレスをプログラムの仮想アドレス上に割り当てることができます。 (これ以外の目的に使うこともあります。) ただし、ファイルシステムや、HW の制約により Block/Pase size に気をつける必要があります。 Block/Page size は予め決められたアドレスマップ上の区切りのことです。
サンプルコード
volatile unsigned * io_mapping(int base_addr) { char *gpio_mem, *gpio_map; if (!mem_fd) { mem_fd = open("/dev/mem", O_RDWR|O_SYNC); check((mem_fd < 0), "can't open /dev/mem \n"); } gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1)); check( ( gpio_mem == NULL), "allocation error \n"); // Make sure pointer is on 4K boundary if ((unsigned long) gpio_mem % PAGE_SIZE) gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE); // Now map it gpio_map = (char *)mmap((caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, base_addr ); check( ((long)gpio_map < 0), "mmap error \n"); return (volatile unsigned *)gpio_map; }
io_mapping() は、 SRAM のアドレスを基準にして、アクセスしたい領域のベースアドレスをオフセットにして 物理アドレスの割当用に確保した仮想アドレス空間gpio_memを戻り値とします。
Raspberry pi の AP に関して
Broadcom 2835
Raspberry pi のAP(CPU)公式ドキュメント
場所が少しわかりにくいのでリンクを記載します。 Top ベージからは、"Help" > "Documentation" > "Hardware" > "Raspberrypi" です。
ここから "BCM2835" > "Peripheral specification" にあります。
このドキュメントの課題
- 情報が不完全で必要としている情報も欠落している
- 誤記もある
- AVR のドキュメントと比較すると随分とわかりにくい
レジスタのアドレスなど参考になるサンプルコード
wiring Pi
このライブラリの作者はいろいろなFAQ/Forumで回答者としてアドバイスされています。 細かいことを Google 検索するとかなりの確率でお世話になる。
調べてわかったこと(備忘録)
Peripheral Base Address ( Physical )
上記公式ドキュメントと
https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
で確認できます。
BCM2835(Raspberry Pi Model A, B, B+, the Compute Module, and the Raspberry Pi Zero) 0x7E00_0000
BCM2836(Raspberry Pi 2 Model B)/BCM2837(Raspberry Pi 3) 0x3F00_0000 (訂正:0x3E00_0000は間違い)
PWM pin
BCM2835 で GPIO18 を使って、モードは ALT5 にする。
PWM モード
2つのモードがある。
PWM algorithm
単位期間内のHigh/Low Cycle をバランスよく配置する。 DCモータの駆動のように平均電圧をなんとかするだけなら、こちらで使用した方が良いかもしれない。
MS algorithm
単位期間内のHigh/Low cycle が各々固まっている。 単位期間内のHigh期間が終わってから、Low 期間となる。 サーボモータの回転角を PWM 波形で制御する場合はこちらが制御しやすいだろうと思う。
Clock source
PWM のカウンタクロックは主に下記の通りとなる。 ただし、PLL の周波数はOSで設定されている通りなので、 下記周波数は調査する必要がある。
- Oscillator = 19.2MHz
- PLLA = 500MHz?