発注していた基板が届き、組み立てた。
以前、超音波距離計のために作ったソフトを改造して書き込んでみた。いくつかのバグを修正して動いたが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;
(続く)

















