2025年06月09日

AKI80でCP/M(その3)PIO試験


1.はじめに
 秋月さんの秋葉原店で¥280 で特売されているスーパーAKI80がX(旧Twitter)で話題になっています。以前購入した AKI80ゴールドを発掘し、20ピンのPICを使ってCP/Mが動くように改造し、タイマ割込みを使った割込みが問題なく動いたことを前回の記事で書きました。
 今回はPIO(CPUに内蔵されているパラレルインターフェース)の動作確認について書いてみたいと思います。


2.PIO機能
 CPU(TMPZ84C015)に内蔵されたPIOは同シリーズの別チップだったPIOをほぼそのまま1チップ化したもので2チャンネルのパラレルインターフェース機能があります。
 下図はPIO機能のブロック図です(タイポってますね⇒最下行のDiagaram)。

PIOのブロック図(TOSHIBAのデータシートから抜粋)

 PIOには次の4つのモードがあります。
  1. モード0:ハンドシェイク方式のバイト出力
  2. モード1:ハンドシェイク方式のバイト入力
  3. モード2:ハンドシェイク方式のバイト入出力(ポートAのみ可)
  4. モード3:ビットモード
 今回の動作試験ではモード3を使用します。このモードはビット単位で割込み指定可能で複数ビットでのand/or条件も指定できるので外部からの信号に対する割込みコントローラ的に使用することも可能です(今回の試験ではPIOの割込みは使用しません)。


3.試験内容
 先日、AliExpressさんで格安のマイクロサーボ(SG90)を見つけ購入しましたので、今回の試験ではZ80でマイクロサーボを動かしてみたいと思います。Z80でサーボを動かす日が来るとは思ってもいませんでした。Lチカならぬサボグル(サーボをグルグル回す)ですねw

マイクロサーボ(SG90)

 サーボモータは下図のように20ms程の周期のPWM信号で制御可能です。

サーボモータの制御(SG90のデータシートから抜粋)



4.サーボ制御
 PWM機能の無いZ80で制御できるのでしょうか?
⇒タイマ割込みを使えば割合簡単に制御できます。制御信号の生成方法に関しては「PIC24FJで4足ロボットの製作」の記事を参照してください。

 今回は3つのタイマ割込みとPIOの全出力を使い、16個のマイクロサーボの制御信号の生成にチャレンジしてみました。サーボの制御信号はタイマ割込み処理によってバックグラウンドで生成されるので、アプリケーション側ではサーボ制御用の変数を変更するだけでサーボを自由に動かすことができます。

 下図は今回作成したサーボ制御信号の出力例です。図中のそれぞれのタイミングマーカーは
  • P0:PWMの周期
  • P1:最短パルス幅
  • P2:最長パルス幅
  • P3:パルス幅の中央値
  • P4:隣接するチャンネル間の時間差
です。

サーボモータの制御信号例

 サーボ制御信号発生処理部のソースも貼っておきます。

サーボ制御信号生成処理(Z80アセンブラ)
;++++++++++++++++++++++++++++++++++++ ; AKI80 serbo control test ; Ver 0.01 2025/06/06 by skyriver ;++++++++++++++++++++++++++++++++++++ .LIST 0023 SETTIM EQU 00100011B ; CTC mode enable int,timer,pre:256 0080 INTBIT EQU 10000000B ; enabke interrupt 0004 TIMBIT EQU 00000100B ; set timer value next 0000' ASEG ORG 0100H 0100 18 25 START: JR Init ; initialize CTC & PIO 0102 18 5D EXIT: JR StopInt ; stop interrupt 0104 80 00 Serbo0: DB 80H,00H ; PIOA0 serbo pulse width and adjust 0106 80 00 Serbo1: DB 80H,00H ; PIOB0 0108 80 00 Serbo2: DB 80H,00H ; PIOA1 010A 80 00 Serbo3: DB 80H,00H ; PIOB1 010C 80 00 Serbo4: DB 80H,00H ; PIOA2 010E 80 00 Serbo5: DB 80H,00H ; PIOB2 0110 80 00 Serbo6: DB 80H,00H ; PIOA3 0112 80 00 Serbo7: DB 80H,00H ; PIOB3 0114 80 00 Serbo8: DB 80H,00H ; PIOA4 0116 80 00 Serbo9: DB 80H,00H ; PIOB4 0118 80 00 SerboA: DB 80H,00H ; PIOA5 011A 80 00 SerboB: DB 80H,00H ; PIOB5 011C 80 00 SerboC: DB 80H,00H ; PIOA6 011E 80 00 SerboD: DB 80H,00H ; PIOB6 0120 80 00 SerboE: DB 80H,00H ; PIOA7 0122 80 00 SerboF: DB 80H,00H ; PIOB7 0124 0104 SerbPt: DW Serbo0 0126 01 PerBit: DB 1 ; period bit value ; initialize CTC, PIO and work area 0127 F3 Init: DI 0128 ED 5E IM 2 012A 3E 01 LD A,high IntVec 012C ED 47 LD I,A 012E CD 0141 CALL IniCtc 0131 CD 014E CALL IniPio 0134 21 0104 LD HL,Serbo0 0137 22 0124 LD (SerbPt),HL 013A 3E 01 LD A,1 013C 32 0126 LD (PerBit),A 013F FB EI 0140 C9 RET ; initialize CTC 0141 3E C8 IniCtc: LD A,low IntVec 0143 D3 10 OUT (CTCCH0),A ; set vector addr 0145 3E A7 LD A,SETTIM OR INTBIT OR TIMBIT 0147 D3 10 OUT (CTCCH0),A 0149 3E 78 LD A,120 ; 12.288*1000000/256/120=400[Hz] = 2.5ms 014B D3 10 OUT (CTCCH0),A 014D C9 RET ; initialize PIO 014E 21 015E IniPio: LD HL,PINIDAT 0151 E5 PUSH HL 0152 01 031D LD BC,PINILEN * 256 + PIOACMD 0155 ED B3 OTIR 0157 E1 POP HL 0158 01 031F LD BC,PINILEN * 256 + PIOBCMD 015B ED B3 OTIR 015D C9 RET 015E PINIDAT: 015E CF DB 11001111B ; mode3(bit mode) 015F 00 DB 00000000B ; all bits are output 0160 07 DB 00000111B ; no interrupt 0003 PINILEN EQU $ - PINIDAT ; stop CTC int 0161 StopInt: 0161 3E 03 LD A,00000011B ; reset channel 0163 D3 10 OUT (CTCCH0),A 0165 F3 DI 0166 C9 RET ; timer interrupt ; pulse width 1.5 +/ 0.8[ms] ; 2.5ms : 120 96 ; (255*(1/2-1/8)+24)/120*2.5 = 2.49[ms] ; 1.5ms : 72 48 ; 0.5ms : 24 0 0018 LOWOFST EQU 24 ; lowest value offset 0167 IntCtc0: 0167 F5 PUSH AF 0168 C5 PUSH BC 0169 E5 PUSH HL 016A 3E A7 LD A,SETTIM OR INTBIT OR TIMBIT 016C D3 11 OUT (CTCCH1),A 016E D3 12 OUT (CTCCH2),A 0170 2A 0124 LD HL,(SerbPt) 0173 7E LD A,(HL) 0174 CB 3F SRL A 0176 47 LD B,A 0177 E6 FC AND 0FCH 0179 0F RRCA 017A 0F RRCA 017B 90 SUB B 017C ED 44 NEG 017E C6 18 ADD A,LOWOFST ; add serbo senter value 0180 23 INC HL 0181 86 ADD A,(HL) ; add adjust 0182 23 INC HL 0183 D3 11 OUT (CTCCH1),A 0185 7E LD A,(HL) 0186 CB 3F SRL A 0188 47 LD B,A 0189 E6 FC AND 0FCH 018B 0F RRCA 018C 0F RRCA 018D 90 SUB B 018E ED 44 NEG 0190 C6 18 ADD A,LOWOFST ; add serbo senter value 0192 23 INC HL 0193 86 ADD A,(HL) ; add adjust 0194 23 INC HL 0195 D3 12 OUT (CTCCH2),A 0197 3A 0126 LD A,(PerBit) ; get bit pattern 019A D3 1C OUT (PIOADAT),A 019C D3 1E OUT (PIOBDAT),A 019E 07 RLCA 019F 30 03 JR NC,IntC010 01A1 21 0104 LD HL,Serbo0 01A4 IntC010: 01A4 22 0124 LD (SerbPt),HL 01A7 32 0126 LD (PerBit),A 01AA E1 POP HL 01AB C1 POP BC 01AC F1 POP AF 01AD FB IntNul: EI 01AE ED 4D RETI ; CTC ch1 interrupt ; (serbo pulse off 01B0 IntCtc1: 01B0 F5 PUSH AF 01B1 3E 23 LD A,SETTIM ; disable int, not set timer value 01B3 D3 11 OUT (CTCCH1),A 01B5 AF XOR A 01B6 D3 1C OUT (PIOADAT),A ; set serbo pulse off 01B8 F1 POP AF 01B9 FB EI 01BA ED 4D RETI 01BC IntCtc2: 01BC F5 PUSH AF 01BD 3E 23 LD A,SETTIM ; disable int, not set timer value 01BF D3 12 OUT (CTCCH2),A 01C1 AF XOR A 01C2 D3 1E OUT (PIOBDAT),A ; set serbo pulse off 01C4 F1 POP AF 01C5 FB EI 01C6 ED 4D RETI ORG ($+0007H) AND 0FFF8H 01C8 IntVec: 01C8 0167 DW IntCtc0 01CA 01B0 DW IntCtc1 01CC 01BC DW IntCtc2 01CE 01AD DW IntNul END

 また、AKI80 のピンヘッダに出ているPIO出力をマイクロサーボへ接続するために、下図のようなサーボ用ハブを作成しました。

サーボ用ハブ

 下図は今回作成したサーボ用ハブを使ってAKI80にマイクロサーボを接続した状態の写真です。上記のサーボ制御信号発生処理を使ってGAME言語でサーボの試験処理を記述し、動かしました。

マイクロサーボとAKI80


 X(旧Twitter)に投稿したメッセージに添付した動画を貼っておきます。最初の4個は手持ちであったもので動作音が大きいようです。5番目以降のサーボは最近購入(昨日着荷)したものでケース内のギアにグリスがたっぷりと塗布されていて最後のサーボだけ動作音が大きめです。最初と最後のサーボは動きも渋いようですね。ソフトウェア的にはオフセット調整機能もあるのですが、大きくずれている個体は無かったのでオフセット調整は行っていません。

★追記 2025/06/10 {
 動画をよく見るとサーボの動きが激しくなるとサーボ用ハブの緑LEDの光が弱くなっています。これは安定化電源の電流制限により供給電圧が低下している状況だと思われます。電流制限の値を2.5Aから3.0Aに変更したところ、全てのサーボが正常に動くようになりました。
}




[TOP] [ 前へ ] AKI80でCP/M [ 次へ ]

posted by skyriver at 18:13| Comment(0) | Z80 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください