mNEFOのメモ帳

ツイッターとかに書ききれなかったメモの集まり

GPSとRV-8803-C7で限界まで精度を高める

RP2350の内部タイマーの生の値はtimer_hw->timerawlで取得できます(マイクロ秒)。 ここで、GPSとRV-8803-C7の1pps時にタイマーの生の値を取得し比較します。 GPSと同期できていれば理論上では両者に差がないはずですがおおよそ数百マイクロ秒のずれがあるはずです。 これはI2Cのクロックや書き込み量にもよりますが、I2C書き込みの遅延によります。 SPI駆動で高速動作するDS3234では見られなかった現象です。ただし、SPI駆動は消費電力が大きいためRV-8803-C7は消費電力で有利なI2Cを選択したのだと思われます。 RV-8803-C7そういうときのためにRTC機能を一旦停止するRESETフラグが存在します。 私の環境(I2C 100kHz、7バイトとRESETの書き込み)ではおおよそ700μsの差があったので、GPSと同期時に

  • RESETフラグ書き込みし、RTCを一時停止
  • 年月日時刻(7バイト)を書き込み
  • add_alarm_in_us()を1000000+700マイクロ秒後に実行しRESETフラグをクリアしRTCを再始動

という手順を踏むことで数十μs以内のずれに抑え込むことができました。このとき1秒遅れるのであらかじめ書き込みを行う年月日時刻は1秒進める必要があります。 繰り上がりも考慮しなくてはいけないので同期は秒数1桁が8より小さいときに(GPSの1pps時に判明する時刻は1秒過去、I2Cの遅延解消で1秒遅れ)で行うとよいです。

つぎに、RV-8803-C7のオフセット調整です。 RP2350のタイマの生の値はそれほど正確ではありませんが、RV-8803-C7のオフセット調整を行うには十分です。 たとえば、GPSとの同期直後のずれが30μsだったとして、10秒後に33μsならばずれは3/10=0.3ppmのずれがあることになります。 RV-8803-C7は0.238ppmごとにオフセットが設定できますので0.3/0.238=1.2≒1をレジスタに(-32~+31の範囲)書き込んでやれば調整できます。

こんな感じでRP2350ニキシー管時計はRV-8803-C7の性能を限界まで引き出しています。

RP2350Bでニキシー管時計のPIO改

前回、 blog.m9841.info RP2350のPIOでニキシー管の制御の記事を編集したがあれこれあってアップデートした。 最初のPIO制御の問題は

  • IRQにCPUが介在するため、フラッシュ書き込み時などにちらつきが出てしまう
  • ブランク表示に対応していないため、ブランク表示にしたいときゴーストが出る

が有ったがこれを解消している。

  • IRQ4とCPUによる強制同期はそもそも不要だったので削除
  • ブランキングに対応するためデューティーはフラグ・デューティー・フラグ・デューティーのようになる配列へ変更
  • ループ処理を活用しプログラム行数を削除
.program nixie_anode_driver
.wrap_target
    ; irq 4        
    ; wait 0 irq 4 ; for check fps count debug
    set x, 1                ; set output bit (x is used for another purpose)
    mov isr, x              ; use isr for output bit
    set y, 7                ; set tube number loop
loop:
    pull block              ; get skip flag from DMA
    mov x, osr              ; move osr to x for skip flag
    irq 0                   ; sync with cathode driver
    jmp !x skip_output      ; if skip flag is zero(cathode is blank), skip pin output
    mov pins, ~isr          ; 0 is on, 1 is off
skip_output:
    pull block              ; get duty from DMA
    mov x, osr              ; move osr to x for duty loop
duty_loop:
    jmp x-- duty_loop       ; duty loop
    mov pins, ~null         ; 0 is on, 1 is off
    set x, 19               ; 19 + 1 times loop
delay_loop:
    jmp x-- delay_loop [31] ; 10x32 clock loop delay
    irq 1                   ; sync with cathode driver
    in null, 1              ; shift zero to isr from LSB(see init)
    jmp y-- loop            ; tube number loop
.wrap

.program nixie_cathode_driver
.wrap_target
    pull block              ; get cathode bits from DMA
    wait 1 irq 0            ; wait for anode driver
    nop [1]                 ; delay for anode jmp clock
    out pins, 12            ; output cathode bits to pins
    wait 1 irq 1            ; wait for anode driver and Leave it ON for a short time to discharge.
    mov pins, null          ; turn off cathode bits
.wrap

実際の命令数は22となった。一つのPIOには32命令まで入るのでまだ10個余裕がある。

盆休みの成果(Web Serial)

HTMLやjsはよくわからんのでAIに相談しながら作ったやつ。 AIには引き出し役になってもらう感じで進めた。RP2350時計のUIとしてHTMLが使えるのはいいけど、 HTML側からの命令群がどうしてもコピペになる(ソースや世界が別なのでどうしようもない)のがちょっと面倒。 共通の定義ファイルとか作れると楽だろうけど難しいな。 mnefo.github.io

RV-8803-C7の割込みの罠

RV-8803-C7の割込みには数種類あって、CONTROLレジスタにフラグを立てて好きなのを選ぶ感じです。 今回はPeriodic Countdown Timer Interrupt(周期カウントダウンタイマー割込み)を使いたいのでデータシートの4.5.2の手順の通りやればいいはずですがうまくいきませんでした。 データシートだとCONTROLレジスタはデフォルトオール0であとは使うフラグを立てればいいだけなのですが、プログラムを書いて調べたところUIEビットが初期状態で立っておりいったん消す必要があった感じです。

ニキシー管のダイナミック制御におけるクロスフェード

縦軸は仮にデューティーとしているが、正しくはカソードの出現割合で60FPSで60回出現させたら最大という意味です。 (本物のデューティーはアノード側で制御しているので) 数字の0を表示しているときに0の出現回数を徐々に落として疑似的に暗くすると同時に、次の1の数字の出現回数を徐々に増やし明るくする。 すると0→1へ変化するとき徐々に重なりながら変化するクロスフェードとなる。 現在前述の考え方でカソード側の変数を変化させるようプログラムをしていますがなぜか無慈悲にパキパキ入れ替わるだけとなりクロスフェードしてくれない状態です。 (以前に作ったPIOではない制御ではうまくいっていた手法が通じなくっている)

概念図

PIOでのニキシー管の制御におけるクロック分周

RPシリーズのPIOは特に何も設定をしなければCPUのクロックそのままで動作します。 RP2350では150MHzです。前述のニキシー管制御アノード側PIOの一周期(.wrap_targetに戻るまで)が例えば800ステップだとすると、 150*106/800=187500、1秒間に18万7千500回繰り返すことになります(18万7千500FPS)。 そんな数字は当然ニキシー管自体が付いてこれない領域なので、CPUクロックを分周させて速度を落とします。 2分周なら75MHz、、、といった具合です。8管制御の場合、90FPSあたりが限度(これ以上増やすとゴーストが消えなくなってくる)です。 その時の分周は単純に150*106/(90*800)=2083となります。2083分周させればちょうどいい感じに800ステップのpioを90FPSでこなせるのです。 150*106/2083=72011 800*90=72000 とほぼ一致します。デューティーを可変させると当然PIOのステップ数が変化してしまいますが、同時に分周も設定してやるようにするとどんなデューティーでもおなじFPSで制御できるのです。 尚、RPシリーズのPIOの分周を途中で変更したいときはsm_config_set_clkdivではなく、pio_sm_set_clkdivをつかう。 前者はSMの初期設定時にしか有効にならない。途中で変えるなら後者。