tunozemichanの日記 / tunozemichan's diary

SORD社のコンピューターM68やM68MXの解析についての備忘録です。This blog is a memorandum about the analysis of SORD's computers M68 and M68MX.

Raspberry Pi PICOのPIO(Programmable I/O)のコードをArduino IDE経由でSDKの関数を使って書く(その1)

Raspberry Pi PICOのPIOをArduino IDEを使って書く方法のメモです。

 

PIOでLチカっぽいことをする方法

まず、PIOのアセンブラを書きます。この時、PIOに関するCのコードを併記しておくと、設定の修正があった時、1つのファイルにまとまって情報があって楽になります。

test_signal.pioと言う名前で以下のコードを書きました。


.program test_signal

// ここから、PIOアセンブラコード

loop: // ループの起点。解説書だと.wrapとも書いてある。
    wait 1, gpio 0 // GPIO0がHIGHになるまで待つ
    set pins, 0  [10] // set pinとして設定した名前pinsのピンを0にして、10遅延(その状態を維持する)
    set pins, 0  [10]
    set pins, 0  [10]
    set pins, 0  [6]
    set pins, 1  [10]
    set pins, 0  [7]
    set pins, 1  [3]
    set pins, 0  [5]
    set pins, 1  [11]
    wait 0, gpio 0

// ここまで

% c-sdk {

// 初期化関数

static inline void test_signal_program_init(PIO pio, uint sm, uint offset, uint pin) {
    pio_sm_config c = test_signal_program_get_default_config(offset);

 // Set pinをセット

    sm_config_set_set_pins(&c, pin, 1);

   // GPIOを初期化

    pio_gpio_init(pio, pin);

 // pinの方向を決める。set pinで設定したら出力に決まっているが、設定した方がよいみたい

    pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);

 

    //  state machineを初期化
    pio_sm_init(pio, sm, offset, &c);

    // state machine起動

   pio_sm_set_enabled(pio, sm, true);
}
%}

 

遅延と書いたのは、その状態をクロック数分維持するという意味です。PICOのシステムクロックの速度に依存します。PIOのstate machineをシステムクロックの何分の一で動かすのかは、

sm_config_set_clkdiv(&c, 6.25);

と、初期化関数の中で記載します。上記では6.25分の1で動かします。

 

このコードをpioasm Onlineのページの左の枠にコピペします。即座にアセンブルされ、右の枠に出力されます。また、% c-sdk { %}で囲った範囲はCのコードとして扱われて、やはり成形されて一緒に出力されます。

Cコード部分に以下の情報が付加されます。

 
static const struct pio_program test_signal_program = {
    .instructions = test_signal_program_instructions,
    .length = 9,
    .origin = -1,
};
PIOアセンブラコードの起点originと長さlengthの情報です。

static inline pio_sm_config test_signal_program_get_default_config(uint offset) {
    pio_sm_config c = pio_get_default_sm_config();
    sm_config_set_wrap(&c, offset + test_signal_wrap_target, offset + test_signal_wrap);
    return c;
}
PIOのループwrapの定義です。

 

右の枠に出たアセンブラコードとCのコードを例えば、test_signal.pio.hとしてinoファイルのあるフォルダに保存します。

 

ここまで来たら、Arduino IDEのコード、例えばtest_signal.inoを書きます。


// Our assembled program:
#include "test_signal.pio.h"

void setup() {
    PIO pio = pio0;
    uint offset = pio_add_program(pio, &test_signal_program);
// 使っていないstate machineの番号を得る。0番号が明白なら、sm = 0;とか書いてもよい。
    uint sm = pio_claim_unused_sm(pio, true);
// test_signal.pio.hに書かれている通り、最後の引数はset pinに割り当てるGPIOの番号
    test_signal_program_init(pio, sm, offset, 15);
    while (true) {
    }
}

void loop() {
}
setup()関数内で、test_signal_program_init()に具体的なピン番号を渡すだけです。
loop()で何か処理をするなら、setup()内のwhileを消し忘れないようにしましょう。
 
お勧め参考書
参考書として有名なのはインターフェース2021年8月号がありますが、その後に出版された「ラズベリーパイ Pico/Pico W攻略本」の方がサンプルコード(特にUART)が整理されていて、自分としては読みやすかったし、得るものが多かったです。
 
MicroPythonやCircuitPythonでもPIOのコードを書けますが、SDKのCの関数を知らないと混乱します。今回に限って言えば、敷居が低いのはSDK(またはArduino IDE))です。
 
Set pinとOut pin
上記書籍のUARTのサンプルコードにはっきり書いてありますが、Set pinとOut pinは同一ピンに割り当てられます。UARTでは、Set pinでスタートビットを出力して、その後、Out pinでデータを送るコードになっています。
Set pin、Out pinを定義するには、初期化関数の引数に加えるだけです。例えば、上記の例の初期化関数の定義のところで
 test_signal_program_init(PIO pio, uint sm, uint offset, uint set_pins, uint out_pins)などと修正して、 
    sm_config_set_set_pins(&c, set_pins, 1);
    sm_config_set_oput_pins(&c, out_pins, 1);
とするだけです。inoファイルのsetup()内でset_pinsとout_pinsに同じGPIO番号を割り当てれば、両方使えるピンになります。GPIO15番を割り当てるなら以下のようなこんな感じです。
 
 test_signal_program_init(pio, sm, offset, 15, 15);
 
 

Raspberry Pi PiCOのPIOをMicroPythonから使う

Raspberry Pi PicoのPIOをMicroPythonから使った時の備忘録です。

 

例えば、GPIO0の立ち上がりによって、インプットピンがHIGHになるのを待って、ある波形をGPIO15ピンから出力する場合は、MicroPython用のPIOアセンブラの記法では以下のようになる。

 


@rp2.asm_pio(set_init=rp2.PIO.OUT_HIGH)
def base_signal(): // 適当な名前
    wait(1, pin, 0) // in_pinの0番目が1=HIGHになるのを待つ
    set(pins, 0) [10] // set_pinを上げ下げする
    set(pins, 0) [10]
    set(pins, 0) [10]
    set(pins, 0) [6]
    set(pins, 1) [10]
    set(pins, 0) [7]
    set(pins, 1) [3]
    set(pins, 0) [5]
    set(pins, 1) [11]
    wait(0, pin, 0) // in_pin0番目が0=LOWになるのを待つ
 
既に記憶が曖昧ですが、本家SDKでは、wait 0 gpio 1とか、gpioを露わに書く記法が許されていますが、MicroPythonでできるかどうか忘れました。試したときはできなかったと思いますが、単純に文法を間違っただけの気がします。
 
実際に起動する命令は以下のようになります。
pin0 = Pin(0,Pin.IN,Pin.PULL_UP)
pin15 = Pin(15,Pin.OUT)

sm = rp2.StateMachine(0, base_signal, freq=20000000, set_base=Pin(15),out_base=Pin(15),in_base=Pin(0))
 
# Start the StateMachine.
sm.active(1)
 
セットピンとアウトピンを同じGPIO15に割り当てていますが、これは本家SDKでも許された書き方です。しかし、何故かCircuitPythonでは許されず、重複しているというエラーが出ます。
セットピンとアウトピンが別々にしか許されない場合、かなり出来ることに制限がかかるので早急に治ることを願います。
 
 
 
 

Analysis of SORD M68 Keyboard (Part 5)

With an approximate understanding of the circuit configuration and the exchange of signals, I directly observed the waveform using a logic analyzer.

The topmost signal is transmitted from the keyboard to the M68, and the one below it is the signal sent from the M68 to the keyboard. Below that is the CLK signal (1MHz) input into the 74166 and 74164.

The signals are observed intermittently. I will zoom in on one of the clusters.

The signal that appeared as one cluster consists of signals from two frequencies. I will zoom in on the waveform at the very beginning.

The input signal, from rising to falling edge, lasts for 4 microseconds (uSec), while the output signal is delayed by 2 uSec and has a waveform lasting from falling to rising edge for 2 uSec.

When no key on the keyboard is pressed at all, this waveform continues indefinitely.

Presumably, the 4 uSec duration of this input signal serves as a scan command for a certain column on the keyboard, and with a 2 uSec delay, the keyboard sends back the pressed information for that column.

Let's look at the signal when the "P" key is pressed.

As expected, changes are observed in the output waveform. The appearance in two places is thought to be because the M68 is scanning twice consecutively, a total of 2 times. This is inferred from the fact that the code for waiting for key input in the BOOT ROM also scans twice.

I will zoom in on this changed waveform.

The waveform above is the measured value. Below it, the data has been fitted into bits. Although it is supposed to be 8 bits, it turns out to be 10 bits, and with a CLK of 1MHz, I wonder if 200 nanoseconds (nSec) is below the resolution. But, setting that aside, it translates to 08h, which in the keyboard of the M23, if the scan line matches, indeed corresponds to the "P" key.

Even if the interpretation were incorrect, now that the waveform is understood, creating a circuit that can interpret a PS/2 keyboard and emulate this waveform would effectively turn it into an M68 keyboard.

 

SORD M68 Keyboardの解析(その5)

おおよその回路構成と信号のやりとりの想像がついたところで、ロジックアナライザで波形を直接観察しました。

信号の全景

最上段が、キーボードからM68に送信される信号で、その下が、M68からキーボードに送られてくる信号です。下は、74166と74164に入力されているCLK信号(1MHz)です。

信号がとびとびに観測されています。一つの塊を拡大してみます。

 

 

1つの塊に見えた信号は、二つの周波数から構成される信号でした。一番先頭の波形を拡大します。

 

 

入力信号は、立ち上がりから立下りまで4uSec、出力信号は、2uSec遅れて、立下りから立ち上がりまで2uSecの波形でした。

キーボードのキーを全く押さない時は、この波形がずっと続きます。

おそらく、この入力信号の4uSecがキーボードにおけるある列のスキャン命令で、2uSec遅れて、キーボードがその列の押下情報を送っていると思われます。

実際に"P"のキーを押した信号を見てみます。

”P"キーを押下した時の波形

推測通り、出力波形に変化が見られます。2か所に出現するのは、M68が連続で計2回スキャンしているからだと思われます。これはBOOT ROMのキー入力待ちのコードでも2回スキャンしているので、そこからの推測です。

この変化した波形を拡大します。

波形の詳細

上の波形が実測値。下がビットに当てはめたものです。8ビットのはずですが、10ビットになる上に、CLKが1MHzで200nSecは分解能以下なのでは?と思いますが、まあ、その辺は置いておくと、08hとなり、これはM23のキーボードでは、スキャンラインがあっているとすれば、まさに"P"のキーに当たります。

それが間違っていたとしても、もう波形がわかったので、PS/2キーボードを解釈し、この波形をエミュレートする回路を作れば、M68キーボードとなるでしょう。

 

 

Analysis of SORD M68 Keyboard (Part 4)

I have transcribed the wiring diagram of the SORD M68 keyboard into a more abstract circuit diagram.



 

74166 sends the keyboard press information as a serial 8-bit data. Assuming it sends the same data as the SORD M23, I believe it would be either 04h (0000 0100), 08h (0000 1000), 10h (0001 0000), 20h (0010 0000), or 40h (0100 0000). In any case, an 8-bit sequence with one bit set should be transmitted.

 

 

SORD M68 Keyboardの解析(その4)

SORD M68のキーボードの結線図から、抽象度を上げた回路図に書き起こしました。



 

74166がキーボードの押下情報をシリアル8ビットで送るわけですが、SORD M23と同じデータが流れるとすれば、それは、04h(0000 0100)、08h(0000 1000)、10h(0001 0000)、20h(0010 0000)、40h(0100 0000)かなと思います。いずれにせよ、どこか1つのビットが立った8ビット列が送出されるはずです。

 

Analysis of SORD M68 keyboard (part3)

I have started analyzing the circuitry of a SORD M68 keyboard that has been left untouched for many years. Although I haven't fully uncovered the entire circuit yet, I've been able to understand the basics of its operation. It seems that the M68 keyboard uses a key scanning method typical of 1980s PCs, converting the key matrix press information (parallel) into an 8-bit serial format and sending it to the M68. I will further investigate the specific signal details using a logic analyzer. Since it doesn't use a special transfer method, I believe it's possible to create an adapter to convert it to PS/2 or USB.