2026年11月5日木曜日

シリアル制御フルカラーテープLEDを使う(その3)

発注していた基板が届き、組み立てた。

以前、超音波距離計のために作ったソフトを改造して書き込んでみた。いくつかのバグを修正して動いたがLEDが端から8~10個くらいしか光らない。オシロでLEDの制御波形を見ると単純なデータを出力させても1-LED内でのバイトデータ間の間隔が25μsもありLED間の間隔は更に大きく、SPIへの書き込み処理が間に合っていなくて、途中でリセット信号と判断されてしまうようだ。手っ取り早くCPUクロックを3MHzに落としたのが問題のようなので32MHzまで上げたい。しかし3MHz以外では波形を作るためのペリフェラルの構成を見付けつことが出来るだろうか?

とりあえずクロックを単純に32MHzまで上げてみたところ1-テープ(30-LED)全体を光らせる事は出来たが、(規格通りの波形ではないため当然だが)色のコントロールが全くできない。そこで回路をあれやこれや検討してみて、次の様に行う事とした。

最終的に生成するLEDの制御信号は1μs/bitとする。とするとSPIに与えるのクロックは1Mhzであるが、SPIのクロック選択にTME2-match/2が選べるのでTMR2で2Mhzを生成すればよい。TMR2の入力クロックはFosc/4固定、即ち8MHzだからTMR2で4分周すればよい。うまい事に8MHzを4分周するときにPWM5を組み合わせてで250nsのパルスを作る事が可能で、上手く収まる。そして出来上がったのが次の波形である。上のトレースがSPI1の出力即ちデータ(code)を表し、下のトレースがそれをLEDに与える制御信号である。データが1の時デューティサイクルが50%、データが0の時デューティサイクルが25%になっている事が分かる。

 そしてデータを与えれば思い通りに光らせる事が出来るようになった。


 この制御信号の生成には次のような論理演算を使った。

1-code = SDO1 & SCK1

0-code = /SDO1 & SCK1 & (T2-match + PWM5)    

PWMパルス = 0-code + 1-code 

 ここでSDO1はSPI1のデータ出力、SCK1はSPI1のクロック出力である。T2-matchはTMR2の出力で125nsの幅があり、PWM5はPWM5の出力で同じく125nsの幅がありこれら2つを合成して250nsとしている。最後のPWMパルスの合成(0-code + 1-code)にはDSMを使った。このための各ペリフェラルの初期化は次の様に行った。

// TMR2 - Fosc/4(8MHz)÷4 -> 2 MHz
// T2-match issued when PR2==TMR2; Pw is 125ns 
    PIE1bits.TMR2IE     = OFF;
    T2CONbits.T2CKPS    = 0x0;      // prescaler div by 1
    PR2                 = 3;        // devide by 4
    TMR2                = 0;
    T2CONbits.TMR2ON    = 1;
    //
// PWM5 - delayed T2-match(Pw 125ns)
    PWMTMRSbits.P5TSEL  = 01;       // TMR2
    PWM5DCH             = 1;        //
    PWM5DCLbits.PWM5DCL = 0;        //
    PWM5CONbits.PWM5POL = 0;        // 
    PWM5CONbits.PWM5EN  = 1;
    //
// SPI1
    SSP1CON1bits.CKP    = 0;        // IDLE Clock is Low
    SSP1CON1bits.SSPM   = 0x03;     // Master; CLK=T2-match / 2 = 1MHz
    SSP1STATbits.CKE    = 0;        // transition occurs when clk idl->actv 
    PIR1bits.SSP1IF     = 0;        //        
    SSP1CON1bits.SSPEN  = 1;
    //
// CLC1 for CARH = SCK1
    CLC1CONbits.LC1MODE = 2;        // 4-AND
    CLC1SEL0            = 0x12;     // SCK1
    CLC1GLS0            = 0x02;     // SEL0
    CLC1GLS1            = 0;        // T
    CLC1GLS2            = 0;        // T
    CLC1GLS3            = 0;        // T
    CLC1POL             = 0x0e;
    CLC1CONbits.EN      = 1;
    //
// CLC2- for CARL is SCK1 & (TMR2match | PWM6)
    CLC2CONbits.LC2MODE = 0x02;     // 4-AND
    CLC2SEL0            = 0x12;     // SCK1
    CLC2SEL2            = 0x1a;     // T2-match
    CLC2SEL3            = 0x10;     // PWM5
    CLC2GLS0            = 0x01;     // SEL0
    CLC2GLS1            = 0;        // T
    CLC2GLS2            = 0xA0;     // SEL2 + SEL3
    CLC2GLS3            = 0;        // T
    CLC2POL             = 0x0B;     // 
    CLC2CONbits.EN      = 1;       
    //
// DSM
    MDSRCbits.MDMS      = 0x08;     // MOD source is SDO1
    MDCARHbits.MDCH     = 0x0C;     // CarH src is CLC1
    MDCARHbits.MDCHPOL  = 0;
    MDCARHbits.MDCHSYNC = 0;
    MDCARLbits.MDCL     = 0x0D;     // CarL src is CLC2
    MDCARLbits.MDCLPOL  = 0;
    MDCARLbits.MDCLSYNC = 0;
    MDCONbits.MDOPOL    = 0;        // output is idle low (not invertd))
    MDCONbits.MDEN      = 1;

今後は光の動きを作り込んでいく。

(続く)