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] [ 前へ ] 連載記事一覧 [ 次へ ]

posted by skyriver at 18:13| Comment(0) | Z80 | このブログの読者になる | 更新情報をチェックする

2025年06月01日

AKI80でCP/M(その2)割込み動作試験


1.はじめに
 前回の記事で秋月さんが販売しているAKI-80を改造して CP/M が動作するようになったことを書きましたが、今回は割込み動作を確認しましたので記録しておきます。前回の記事に書いたように割込み対応の回路部分は今回開発したプリント基板のAki80Adapterを製造依頼した後に変更し、AKI-80の本体側に追加したものです。


2.タイマ割込み
 CPU(TMPZ84C015)に内蔵されているうカウンタ/タイマ(以降、CTCと記す)を使ったタイマ割込みで割込み動作試験を行いました。
 CTCには4つのチャンネルがあり、今回は2番目のch1を使ってみます。CTCのコントロールレジスタのビットアサインは下図のようになっています、

CTCのコントロールレジスタ(TOSHIBAのデータシートから抜粋)

 試験内容としては「5ms毎にタイマ割込みを発生させ、割込み処理内でワードデータをインクリメントする」という簡易なものです。
 下図は試験時の画面です。0x0100,0x0102 がそれぞれタイマ割込み設定と停止の処理で0x0104がカウンタです。想定通りカウンタがインクリメントされているので割込み処理は問題なく動作しているようです。
 尚、アセンブラルーチンのロードはGAME言語で作成した自作モニタ(Gamon)を使い、試験処理もGAME言語で記述しています。

タイマ割込み試験時の画面

 タイマ割込み設定処理のソースは下記の通りです。Z80での通常のmode2割込み処理です。

タイマ割込み設定処理(Z80アセンブラ)
;++++++++++++++++++++++++++++++++++++ ; AKI80 timer interrupt test ; Ver 0.01 2025/05/30 by skyriver ;++++++++++++++++++++++++++++++++++++ C INCLUDE Aki80Ada.inc C ;++++++++++++++++++++++++++++++++++++ C ; definitions for Aki80Adaptor C ; Ver 0.01 2025/05/22 by skyriver C ;++++++++++++++++++++++++++++++++++++ C C ifndef AKI80ADA C C AKI80ADA EQU 1 C C C DATPORT EQU 0ECH ; data port C CMDPORT EQU 0EDH ; command port C C C ; +++ status bit allign +++ C RXRDY_B EQU 01H C TXRDY_B EQU 80H C SDERR_B EQU 02H C C C ; +++ mode command +++ C SIO_CHAR EQU 1 ; char mode C SIO_STR EQU 2 ; put string C SD_SECT EQU 3 ; set sector C SD_RD EQU 4 ; read block C SD_WRBUF EQU 5 ; write data to buffer C SD_WR EQU 6 ; write block C SD_INI EQU 12H ; init SD C C C ; **** internal I/O **** C C CTCCH0 EQU 10H ; CTC C CTCCH1 EQU 11H ; CTC C CTCCH2 EQU 12H ; CTC C CTCCH3 EQU 13H ; CTC C C WDTER EQU 0F0H ; watch dog timer & standby mode C WDTCR EQU (WDTER + 1) ; make WDT disable/clear C INTPR EQU 0F4H ; int priority C C endif 0000' ASEG ORG 0100H 0100 18 04 START: JR SetInt ; set interrupt by CTC 0102 18 21 EXIT: JR StopInt ; stop interrupt 0104 0000 TIMCNT: DW 0 ; interrupt counter ; set CTC int 0106 F3 SetInt: DI 0107 ED 5E IM 2 0109 3E 01 LD A,high IntVec 010B ED 47 LD I,A 010D CD 0118 CALL IniCtc 0110 21 0000 LD HL,0 0113 22 0104 LD (TimCnt),HL 0116 FB EI 0117 C9 RET ; set CTC 0118 3E 38 IniCtc: LD A,low IntVec 011A D3 10 OUT (CTCCH0),A ; set vector addr 011C 3E A7 LD A,10100111B ; enable int,timer,pre:256, 011E D3 11 OUT (CTCCH1),A 0120 3E F0 LD A,240 ; 12.288*1000000/256/240=200[Hz] = 5ms 0122 D3 11 OUT (CTCCH1),A 0124 C9 RET ; stop CTC int 0125 StopInt: 0125 3E 03 LD A,00000011B ; reset channel 0127 D3 11 OUT (CTCCH1),A 0129 C9 RET ; timer interrupt 012A IntCtc: ;; PUSH AF 012A E5 PUSH HL 012B 2A 0104 LD HL,(TIMCNT) 012E 23 INC HL 012F 22 0104 LD (TIMCNT),HL 0132 E1 POP HL ;; POP AF 0133 FB IntNul: EI 0134 ED 4D RETI ORG ($+0007H) AND 0FFF8H 0138 IntVec: 0138 0133 DW IntNul 013A 012A DW IntCtc 013C 0133 DW IntNul 013E 0133 DW IntNul END


3.リアルタイムモニタ
 タイマ割込みが動くことが確認できたので「リアルタイムモニタ(ZealMon)の製作」の記事で書いたZ80用リアルタイムモニタのデモを動かしてみました。前述の記事ではタイマ割込みができる動作環境が無かったのでWeb上で動作するMSX環境のMSXPenを使用しましたが、今回のAKI-80により実機上での確認が可能になりました(今では他にも自作のHD64180Compact環境でも可能)。
 デモを実行した画面のキャプチャが下図になります。想定通りに動きました。

★追記 2025/06/03 {
 下図で複数のタスクが同時に表示する時に交互表示ではなく2文字連続表示になっています。理由は次の通りです。CP/M側の処理をコールすることで文字表示を行っており、CP/M側の処理はスレッドセーフ性が保証されないためCP/M側の処理をコール中はタスクスイッチを行わないようにしています。
}

リアルタイムモニタ(ZealMon)のデモ実行画面

 X(旧Twitter)に投稿したメッセージに添付したリアルタイムモニタのデモ動画を貼っておきます。



4.ケース
 今回はAKI-80を改造し、裏側にも追加配線がある状態なので保護する意味でもケースを作成しようと思っているのですが、Aki80Adapterを装着した状態だと直方体のケースに収まり辛いです。割込み試験を優先したので暫定的に底面だけを保護するボトムケースを作成してみました。
 下の写真はボトムケースに入れた状態でCP/Mを動かしている時の様子です。チップの文字が見えるようにライティングするとLEDの点灯状態が判らなくなる・・

ボトムケースに入ったCP/M動作中のAKI-80


[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

posted by skyriver at 09:59| Comment(0) | Z80 | このブログの読者になる | 更新情報をチェックする

2025年05月25日

AKI80でCP/M


1.はじめに
 秋月さんのスーパーAKI-80が秋葉原店で¥280(Z80にちなんで¥Z80と言うことらしい)で大量に販売されていてX(旧Twitter)のタイムラインで話題になっていてZ80色が一段と濃厚になっています。動かすために必要な部品は今では入手困難な物もあり、色々な対応情報がポストされています。
 個人的にはキットはあまり購入しないのですが、以前AKI-80ゴールドを購入したことを思い出し発掘しました(秋月さん製のROMライターも持っているのでこれにもAKI80が付いているはず)。
 発掘した基板は表面にピンヘッダを半田付けした状態で放置されていましたw
 そこで超小型Z80マイコン(Z80PicCompact)のようにUSB機能を有した20ピンのPIC(PIC18F14K50)を使って動かしてみようと思います。


2.基本設計
 基本的な構想は次の通りです。
  1. SRAM
     基板上には32KBのSRAMが実装されていますが、全RAMの状態で動かしたいので手持ちの128KBのSRAM(M68AF127B)に乗せ換えます。ICパッケージの縦幅が広くてAKI80のパターンに合わないのでピンを折り曲げてSOJパッケージのように加工します。この手法はたまに見かけますがCPU実験室の管理人さんは猫が足をお腹の下に折り曲げて座る香箱座りにちなんで香箱付けと命名しているようです(うまい命名ですね)。

  2. ROM
     ROMは実装せずにPIC(PIC18F14K50T-I/S)が代行します。とは言っても今回使用するPICは非力で内蔵のフラッシュメモリ(8KWord)では容量的に足りないのでリセット直後のブートコードだけPICに内蔵し、PICに接続されているSDカードからブートするようにします。
     CP/Mを移植するまではhexloaderが起動するようにして任意のプログラムを起動できるようにします。

  3. シリアル通信
     今回使用するPICにはUSB機能もあるのでPICとパソコンをUSBで接続します。Z80から見るとPICはI/O装置のように見え、8ビットパラレルでZ80と通信します。パソコン~Z80間は調歩同期シリアルに一度も変換されずに接続されるので高速な通信が可能です。また、電源もUSBから給電します。

  4. 外部記憶装置
     PICのSPIインターフェースにSDカードを接続します。Z80からはI/O空間上に8ビットバスで接続されているように見えます。

  5. 割込み対応
     Z80がI/O空間上のPIC(今回は0xec~0xefを割り当てた)にアクセスするとハード的にWAIT状態になるようにすることでPICがZ80からの要求を取りこぼさないようにしています。
     しかし割込み応答時にIORQ/もアクティブになる(同時にM1/もアクティブになる)ため(この時のアドレスバスはメモリ上のコードをフェッチする際の値になる)、アドレスバスがたまたまPICのI/Oアドレスの値になった場合、WAITしないようにPIC用のI/Oアドレスディコードロジック内にM1/がhighであるという条件も付け加えました。
     上記のことは今回基板を起こしたAki80Adapterを製造依頼した後に追加したのでI/OアドレスディコードロジックはAKI80側に実装しました。
     どこに?・・1ゲートしか使用されていなかった 74VHC00 を利用(使用されていた1ゲートも今回の改造で不要になるので4ゲート使用可能)し、更に 74HC32 も重ねて実装しました。
     このようにロジックICを重ねていけばいくらでもロジックを増やせそうにも思えますが、半田付けを例えば IC1-1Pin,IC2-1Pin,IC1-2Pin,IC2-2Pin・・の順にしないと半田付けが困難で直ぐにブリッジしてしまうので表面実装用のロジックICを重ねると作業性が悪くなります。


3.今回の改造内容
 今回の改造内容は下記の回路図の通りです。左側の四角内がAKI80で右側が新規に基板を作成したAki80Adapterです。両者はAKI80のROMソケットで接続され、Aki80Adapter側はソケット対応の連結用丸ピン端子だけでROMは実装しません。

今回実施した改造


3-1)AKI80側の改造
 AKI80側の改造内容をAKI80の回路図上に書いたものが下図になります。上述のように中央の74VHC00は未使用になったので取り外し、パターンカット後に74HC32と74HC00を重ねて実装し直しました。

AKI80側の改造の回路図

 同様に手書きではありますが、参考に(なるのか?)パターン図も載せておきます。

AKI80側の改造のパターン図

 上述した香箱処理したメモリの様子が下の写真です。

香箱処理したメモリチップ(上から) 香箱処理したメモリチップ(横から)

 改造後の状態が下の写真になります。SRAMとROMソケットの間の隙間は殆どないので見た目は良くないですが線材はSRAMの上を這わせました。基板のトップ面とボトム面の結線の線材を通すため、パターンカット兼用のホールをドリルで開けています。
 また、今回予定している確認を全て完了したわけではないので未洗浄で結線の固定やカプトンテープでの保護等もまだ行っていません。

改造後のAKI80(トップ面) 改造後のAKI80(ボトム面)


3-2)Aki80Adapterの制作
 今回制作したAki80Adapterのパターン図(グランドベタ化前)が下図になります。横やりが入ると面倒なのでグランドベタ化後の図は省略します(的確なコメントなら大歓迎)。

Aki80Adapterのパターン図

 3Dイメージが下図になります。

Aki80Adapterの3Dイメージ

 出来上がったプリント基板が下の写真です。

Aki80Adapterのプリント基板

 部品実装後(洗浄前)が下の写真になります。

Aki80Adapter(トップ面) Aki80Adapter(ボトム面)


4.動作確認
 下の写真は動作確認中の様子です。ピンヘッダ用の穴に釣り糸を通してロジアナからのプローブ線を固定しています。

動作確認の様子

 動作確認としてPICがデータバス上にINI命令を出力してZ80に実行させることでメモリ上の0100hにJP 0100hの3バイトのコードを書き込ませた後、0100hへジャンプした時のロジアナ波形が下図になります。黄色文字の部分がPICが生成しているコードで右側の緑文字部分がメモリ上に書き込んだコードをZ80が実行している部分になります。メモリ上での動作はウェイト無しで12MHz動作になっています。

ロジアナ波形例

 ここまでくれば一段落ですね(ホッ)。
 まずはPICからZ80にHexLoaderをロードさせた状態で、CP/MのBIOSのエミュレート+MSBASICのhexファイルを作成し、TeraTermからロードすることで無事MSBASICが動作しました。
 気が向いた時にCP/Mも移植して見ようと思います。

CP/MのBIOSエミュによるMSBASICの起動



 X(旧Twitter)に投稿したメッセージに添付した動画を貼っておきます。



★追記 2025/05/27
 PICからHexLoaderをロードした状態でBoot.hex(SDカードからIPLをロード後、IPLを起動する)を読み込んでCP/Mが立ち上がりました。PIC側の初期ロード対象プログラムをboot.hexに変更すれば、USB接続でCP/Mが自動起動するようにできますが、暫くはHexloaderが立ち上がる状態で遊んでみたいと思います。

CP/Mの起動画面


★追記 2025/05/28
 パソコンと接続し、CP/Mが動作中の写真も貼っておきます。

パソコンと接続中のAki80Adapter




[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

posted by skyriver at 11:19| Comment(0) | Z80 | このブログの読者になる | 更新情報をチェックする