;*************************************************************** ; ; Title: Timpy - Remote - Eeprom ; Comment: Tiny MP3 Player [ Timpy ] Rev4.x リモコン用ファームウェア ; EEPROM ダウンローダ ; File Name: Timpy-R-Eeprom.asm ; Version: 4.x ; ( Oct. 29, 2005 イニシャルリリース) ; Last Update: Oct. 29, 2005 ; Copyright(C) Chiaki Nakajima ; ;*************************************************************** ; Include File(s) ; $pl (65535) $pw (132) $include (c8051f310.inc) ;プロセッサ固有定義 ; ;=============================================================== ; Port Assign ; pSwA bit P0.0 ;Aスイッチ pSwB bit P0.1 ;Bスイッチ pSwC bit P0.2 ;Cスイッチ pEncoderPwr bit P0.3 ;ロータリーエンコーダ電源 pIrTx bit P0.4 ;Uart0 TX pIrRx bit P0.5 ;Uart0 RX pEncoder1 bit P0.6 ;ロータリーエンコーダ入力1 pEncoder2 bit P0.7 ;ロータリーエンコーダ入力2 pBattery bit P1.0 ;バッテリ電圧検出 pIrRxPwr bit P1.1 ;赤外線受光モジュール電源 pReserved1 bit P1.2 ;予約 pSmbSda bit P1.3 ;SMBus SDA pSmbScl bit P1.4 ;SMBus SCL pEepromWp bit P1.5 ;EEPROM WP pIrTxMod bit P1.6 ;赤外線LED変調出力 pLcdBlShdn bit P1.7 ;LCDバックライト用コンバータシャットダウン pLcdD0 bit P2.0 ;LCDデータバスD0 pLcdD1 bit P2.1 ;LCDデータバスD1 pLcdD2 bit P2.2 ;LCDデータバスD2 pLcdD3 bit P2.3 ;LCDデータバスD3 pLcdD4 bit P2.4 ;LCDデータバスD4 pLcdD5 bit P2.5 ;LCDデータバスD5 pLcdD6 bit P2.6 ;LCDデータバスD6 pLcdD7 bit P2.7 ;LCDデータバスD7 pC2D bit P3.0 ;C2D pLcdA0 bit P3.1 ;LCDアドレスA0 pLcdRd bit P3.2 ;LCD /RD pLcdWr bit P3.3 ;LCD /WR pLcdRest bit P3.4 ;LCD /REST ; pLcdDB equ P2 ;LCDデータバス pLcdDBMDOUT equ P2MDOUT ;LCDデータバスのMDOUT ; ;=============================================================== ; Constant(s) ; bSwA equ 0 ;Aスイッチビット番号 bSwB equ 1 ;Bスイッチビット番号 bSwC equ 2 ;Cスイッチビット番号 cSwBitMask equ (1 SHL bSwA) OR (1 SHL bSwB) OR (1 SHL bSwC) ;スイッチビットマスク ; ;=============================================================== ; Data Area ; ;---------------------------------------;General Purpose Registers ; ; 使用ルーチンが重複しないように割り当てる dseg at 000h ;レジスタバンク0 rbMain equ $ ;Mainにて使用 fByteCtr equ R0 ;バイトカウンタ(割り込みで使用) fSlaveAddr equ R1 ;EEPROMスレーブアドレス fRomAddrH equ R2 ;EEPROMアドレス(H) fCheckSum equ R3 ;チェックサム ; dseg at 008h ;レジスタバンク1 ; dseg at 010h ;レジスタバンク2 ; dseg at 018h ;レジスタバンク3 ; ;未使用 ; ;---------------------------------------;Bit Addressable dseg at 020h fPlayMode: ds 1 ;プレイモード制御バイト bPmSwUpdate equ 6 ;ユーザインターフェースのための割り込みが実行されたらセット ; fStatus: ds 1 ;ステータスバイト bDataReady equ 0 ;受信完了フラグ bPagePlane equ 1 ;バッファプレーン ; fSwPortPrev: ds 1 ;pSwPortの前回値 fSwPortSave: ds 1 ;pSwPortの保存用 fSwStatus: ds 1 ;pSwPortの状態(チャッタキャンセル済み、1=ON) fSwStatus0to1: ds 1 ;fSwStatusでOFF→ONに変化したビット=1 fSwStatus1to0: ds 1 ;fSwStatusでON→OFFに変化したビット=1 ; ;---------------------------------------;Direct and Indirect Addressing dseg at 030h fUITimerCtr: ds 1 ;Timer3割り込みカウンタ ; DataSegmentEnd equ $ ;データセグメントの最後 ; iseg at 080h ;Stackセグメント開始アドレス Stack: ds 07fh ;128バイト ; if DataSegmentEnd >= Stack __ERROR__ "DataSegment too large." endif ; ;=============================================================== ; Macro(s) ; ;---------------------------------------;レジスタバンク選択マクロ SelectRegBank macro _rbSelect ; anl PSW, #11100111b ;RS0, RS1クリア orl PSW, #_rbSelect AND 00011000b ;RS0, RS1更新 ; endm ; ;---------------------------------------;16ビット加算マクロ(Aは破壊、引数の順番に注意) ; ; Y = A + B ; ; C : キャリ AddYAB16 macro _YH, _YL, _AH, _AL, _BH, _BL ; mov A, _AL ;A : _AL add A, _BL ;A : _AL + _BL mov _YL, A ;_YL更新 mov A, _AH ;A : _AH addc A, _BH ;A : _AH + _BH + C mov _YH, A ;_YH更新 ; endm ; ;---------------------------------------;FLASHメモリリードマクロ ; ; DPTR : リードアドレス ; ; A : リードデータ ReadFlash macro ; clr A ;A : 0 movc A, @A + DPTR ;A : リードデータ ; endm ; ;---------------------------------------;FLASHメモリライトマクロ ; ; DPTR : ライトアドレス ; ; A : ライトデータ WriteFlash macro ; mov FLKEY, #0a5h ;FLKEY : 0a5h mov FLKEY, #0f1h ;FLKEY : 0f1h movx @DPTR, A ;書き込み ; endm ; ;---------------------------------------;UART0 ボーレート設定マクロ Tx equ 1 Rx equ 2 ; SetUartBaud macro _TxRx ; if _TxRx = Tx ;送信用設定 : 1200baud orl CKCON, #00000010b ;SCA1セット : クロックソース = SYSCLK / 48 mov TH1, #02bh ;1200baud else if _TxRx = Rx ;受信用設定 : 9600baud anl CKCON, #11111101b ;SCA1クリア : クロックソース = SYSCLK / 12 mov TH1, #096h ;9600baud else __ERROR__ "Illegal operand in SetUartBaud." endif endif ; endm ; ;---------------------------------------;SMBus スタートコンディション生成マクロ ; ; 終了時、SIはセットされている TxSmbSta macro ; clr SI ;SIクリア setb STA ;スタートコンディション生成 jnb SI, $ ;SIセット待ち ; clr STA ;STAクリア ; endm ; ;---------------------------------------;SMBus データ送信マクロ ; ; 送信完了を待つ。終了時、SIはセット、受信したACK/NACKはSMB0CN.ACKビットに入っている TxSmbData macro _Data ; mov SMB0DAT, _Data ;データライト clr SI ;SIクリア jnb SI, $ ;SIセット待ち、SIはセットされたままになっている ; endm ; ;---------------------------------------;SMBus データ受信マクロ ; ; 事前にSMB0CN.ACKビットをセットしておく ; ; SIをクリアして受信完了を待つ。終了時、SIはセット、受信したデータはSMB0DATに入っている RxSmbData macro ; clr SI ;SIクリア jnb SI, $ ;SIセット待ち、SIはセットされたままになっている ; endm ; ;---------------------------------------;SMBus ストップコンディション生成マクロ ; ; 終了時、SIはクリアされている TxSmbSto macro ; setb STO ;ストップコンディション生成 clr SI ;SIクリア ; endm ; ;=============================================================== ; Vectors Section ; ;---------------------------------------;スタート cseg at 00000h VectorReset: ljmp Initialize ;リセット cseg at 00003h VectorInt0: ljmp VectorReset ;Int0 cseg at 0000bh VectorTmr0Ovfl: ljmp VectorReset ;Tmr0オーバフロー cseg at 00013h VectorInt1: ljmp VectorReset ;Int1 cseg at 0001bh VectorTmr1Ovfl: ljmp VectorReset ;Tmr1オーバフロー cseg at 00023h VectorUart0: ljmp IsrUart0 ;Uart0 cseg at 0002bh VectorTmr2Ovfl: ljmp VectorReset ;Tmr2オーバフロー cseg at 00033h VectorSpi0: ljmp VectorReset ;Spi0 cseg at 0003bh VectorSmb0: ljmp VectorReset ;Smb0 cseg at 00043h VectorReserve0: ljmp VectorReset ;Reserved cseg at 0004bh VectorAdc0Wind: ljmp VectorReset ;Adc0ウインドウ比較 cseg at 00053h VectorAdc0End: ljmp VectorReset ;Adc0変換終了 cseg at 0005bh VectorPca: ljmp VectorReset ;Pca cseg at 00063h VectorCmp0: ljmp VectorReset ;Cmp0 cseg at 0006bh VectorReserve1: ljmp VectorReset ;Reserved cseg at 00073h VectorTmr3Ovfl: ljmp IsrTimer3 ;Tmr3オーバフロー ; ;=============================================================== ; Initializing ; cseg at 00080h ; Initialize: ;---------------------------------------;内部状態初期化 mov SP, #Stack - 1 ;スタックポインタ初期化 ; ; ;HFオシレータ ; mov OSCICL, #0xxh ;HF発振周波数をできるだけ24.576MHzに近づける mov OSCICN, #083h ;HFオシレータイネーブル、分周なし ; ; ;Wdt mov PCA0MD, #000h ;WDTディスエーブル ; ; ;UART0 mov SCON0, #01000000b ;8ビットモード、受信動作とりあえず禁止 ; ; ;SMBus mov SMB0CF, #11000010b ;動作許可、その他機能禁止、クロックソース : Timer2 ; ; ;Voltage Reference mov REF0CN, #008h ;VREF=VDD ; ; ;Adc0 : バッテリ電圧検出 mov AMX0P, #000h ;P1.0:bBattery mov AMX0N, #011h ;シングルエンドモード mov ADC0CF, #01001100b ;CLKSAR=SYSCLK/10、データは左詰 mov ADC0CN, #01000000b ;ローパワートラックモード、ADC0停止 ; ; ;Timer0..3 : クロック設定 mov CKCON, #00110100b ;Timer0、Timer2はSYSCLK、Timer1、Timer3は分周クロックを使用 ; ; ;Timer0 :PCAクロックソース 24576000 / 3 = 8192000Hz ; ;Timer1 :UART0クロックソース mov TMOD, #00100010b ;Timer0 : Mode2、Timer1 : Mode2 mov TH0, #LOW (0 - 003d) ;0 - (24576000 / 8192000) mov TH1, #096h ;とりあえず9600baud mov TCON, #01010100b ;Timer0、Timer1動作許可、/INT1はエッジトリガ ; ; ;Timer2 :SMBusクロックソース 300kHz mov TMR2RLL, #LOW (0 - 082d) ;LOW (0 - (cSysclk / 300000)) mov TMR2RLH, #HIGH (0 - 082d) ;HIGH (0 - (cSysclk / 300000)) mov TMR2CN, #00000100b ;16bitリロードタイマ、動作許可 ; ; ;Timer3 : ユーザインターフェース処理のためのインターバルタイマ mov TMR3RLL, #LOW (0 - 20480d) ;LOW (0 - (cSysclk / 12d / 100d)) : インターバル = 10msec mov TMR3RLH, #HIGH (0 - 20480d) ;HIGH (0 - (cSysclk / 12d / 100d)) : インターバル = 10msec mov TMR3CN, #00000000b ;16bitリロードタイマ、クロック = SYSCLK / 12、動作停止 ; ; ;PCA mov PCA0MD, #00000100b ;基準クロック : タイマ0オーバフロー mov PCA0CPH0, #108d ;モジュール0 : 出力周波数 = 37.926kHz mov PCA0CPM0, #01000110b ;モジュール0 : 周波数出力モード mov PCA0CPL1, #LOW 032768d ;モジュール1 : デューティ = 50% mov PCA0CPH1, #HIGH 032768d ;モジュール1 : デューティ = 50% mov PCA0CPM1, #11000010b ;モジュール1 : 16ビットPWMモード mov PCA0CPM2, #01001000b ;モジュール2 : ソフトウェアタイマモード(WaitAusec, WaitAmsecで使用) setb CR ;PCA動作許可 ; ; ;I/Oポート : 定数宣言を使っていないので変更の際は要注意 mov P0, #11111111b ;全ピン"H" mov P0MDIN, #11111111b ;全ピンデジタルI/O mov P0MDOUT, #00011000b ;pIrTx、pEncoderPwrはプッシュプル、他はオープンドレイン(入力) mov P0SKIP, #11001111b ;UART0以外のピンをスキップ mov P1, #00111101b ;pLcdBlShdn、pIrTxMod、pIrRxPwrのみ"L" mov P1MDIN, #11111110b ;pBatteryのみアナログ入力 mov P1MDOUT, #11100010b ;pSmbScl、pSmbSda、pReserved1、pBatteryはオープンドレイン mov P1SKIP, #00100111b ;pLcdBlShdn、pIrTxMod、pSmbScl、pSmbSdaを除いたピンをスキップ mov P2, #11111111b ;全ピン"H" mov P2MDIN, #11111111b ;全ピンデジタルI/O mov P2MDOUT, #00000000b ;全ピンとりあえずオープンドレイン(入力) mov P2SKIP, #11111111b ;全ピンスキップ mov P3, #11101111b ;pLcdRestのみ"L" mov P3MDIN, #11111111b ;全ピンデジタルI/O mov P3MDOUT, #00011110b ;pC2Dのみオープンドレイン(入力) mov XBR0, #00000101b ;SMBus、UARTをピンにアサイン mov XBR1, #01000010b ;CEX0、CEX1をピンにアサイン、クロスバーイネーブル ; ; ;変数域初期化 mov R0, #Stack ;R0 : 初期化開始アドレス _Init1: mov @R0, #0 ;@R0 : 0クリア djnz R0, _Init1 ;R0 : R0 - 1、<> 0 ならループ ; ; ; ;割り込み制御 ; mov IT01CF, #01100000b ;/INT1はアクティブ"L"、pEncoder1 = P0.6から入力 ; ; ; ;LCD初期化 ; call InitLcd ;LCD初期化 ; ; ;動作開始 orl TMR3CN, #00000100b ;TR3セット、Timer3動作開始 orl EIE1, #10000000b ;ET3セット、Timer3割り込み許可 setb EA ;グローバル割り込み許可 ; ;=============================================================== ; Main ; Main: ;---------------------------------------;メイン処理ループ ; ; setb pIrRxPwr ;プルアップ有効のために赤外線受光モジュール電源ON SetUartBaud Tx ;1200baud mov A, 0100d ;A : 100 call WaitAmsec ;Amsec待ち ; mov fSlaveAddr, #10100000b ;EEPROMスレーブアドレス初期化 mov fRomAddrH, #0 ;EEPROMアドレス(H)初期化 clr pEepromWp ;EEPROMライトプロテクト解除 ; clr fStatus.bDataReady ;受信完了フラグクリア mov fByteCtr, #0 ;バイトカウンタ初期化 mov EMI0CN, #0 ;外部RAMアドレス上位バイト更新 clr TI0 ;TI0クリア clr RI0 ;RI0クリア setb ES0 ;UART0割り込み許可 setb REN0 ;UART0受信許可 ; _Main1: ; ;ページライトループ jnb fStatus.bDataReady, _Main1 ;1ページ受信完了待ち ; mov C, fStatus.bPagePlane ;C : バッファプレーン mov ACC.0, C ;ACC.0 : バッファプレーン anl A, #00000001b ;下位1ビット抽出 mov DPH, A ;DPH更新 mov DPL, #0 ;DPL初期化 mov fCheckSum, #0 ;チェックサム初期化 ; TxSmbSta ;スタートコンディション生成 TxSmbData fSlaveAddr ;スレーブアドレス、ライト TxSmbData fRomAddrH ;ワードアドレス(H) TxSmbData #0 ;ワードアドレス(L) ; _Main2: ; ;受信データをEEPROMへ転送 movx A, @DPTR ;A : 受信データ TxSmbData A ;受信データをEEPROMへ送る add A, fCheckSum ;チェックサム計算 mov fCheckSum, A ;fCheckSum更新 inc DPL ;DPL + 1 mov A, DPL ;A : DPL jnz _Main2 ;256バイト終了でなければループ ; ; ;1ページ転送終了、ページライト、チェックサム送信 TxSmbSto ;ストップコンディション生成 clr fStatus.bDataReady ;受信完了フラグクリア ; mov A, fCheckSum ;A : チェックサム swap A ;ニブル交換 anl A, #00fh ;下位4ビット抽出 cjne A, #010d, _Main3 ;A - 10 _Main3: jc _Main4 ;A < 10ならジャンプ ; add A, #07d ;A : 10..15を"A".."F"に変換 _Main4: add A, #030h ;A : ASCIIに変換 clr TI0 ;TI0クリア mov SBUF0, A ;上位ニブル文字送信 ; mov A, 005d ;A : 5 call WaitAmsec ;Amsec待ち ; mov A, fCheckSum ;A : チェックサム anl A, #00fh ;下位4ビット抽出 cjne A, #010d, _Main5 ;A - 10 _Main5: jc _Main6 ;A < 10ならジャンプ ; add A, #07d ;A : 10..15を"A".."F"に変換 _Main6: add A, #030h ;A : ASCIIに変換 clr TI0 ;TI0クリア mov SBUF0, A ;上位ニブル文字送信 ; inc fRomAddrH ;EEPROMアドレス(H) + 1 cjne fRomAddrH, #0, _Main1 ;EEPROMアドレス(H) <> 0ならループ ; ; ;256ページライト終了、A1、P0を更新 inc fSlaveAddr ; inc fSlaveAddr ;fSlaveAddr[A1:P0] + 1 jmp _Main1 ;次のページへ ; ;=============================================================== ; Subroutines ; WaitAusec: ;---------------------------------------;Acc(usec)待ち (A > 0) ; ; PCA Module2を使用 push ACC push B ; mov B, #08d ;B : 24576000 / 3 / 1000000 mul AB ;BA : A * 8 AddYAB16 PCA0CPH2, PCA0CPL2, B, ACC, PCA0H, PCA0L ;PCA0CP[HL]2 : PCA0[HL] + (A * 8) clr CCF2 ;CCF2クリア jnb CCF2, $ ;CCF2がセットされるまでループ ; pop B pop ACC ret ; WaitAmsec: ;---------------------------------------;Acc(msec)待ち (A > 0) ; ; PCA Module2を使用 push ACC ; _WaitAmsec1: ; ;1msec待ち push ACC ; AddYAB16 PCA0CPH2, PCA0CPL2, #HIGH 08192d, #LOW 08192d, PCA0H, PCA0L ;PCA0CP[HL]2 : PCA0[HL] + (24576000 / 3 / 1000) clr CCF2 ;CCF2クリア jnb CCF2, $ ;CCF2がセットされるまでループ ; pop ACC djnz ACC, _WaitAmsec1 ;A : A - 1、<> 0ならループ ; pop ACC ret ; WaitA100msec: ;---------------------------------------;Acc(100msec)待ち(低精度) ; ; WaitAmsecを使用 push ACC push B ; mov B, ACC ;B : ループカウンタ初期化 mov A, #0100d ;A : 100(msec) ; _WaitA100msec1: call WaitAmsec ;Amsec待ち djnz B, _WaitA100msec1 ;B : B - 1、<> 0ならループ ; pop B pop ACC ret ; ;=============================================================== ; Interrupt Service Routines ; IsrUart0: ;---------------------------------------;UART0割り込み処理 : EEPROMライトデータ受信 push ACC push PSW ; ; ;送信処理 jnb TI0, _IsrUart1 ;TI0がクリアならジャンプ ; clr TI0 ;TI0クリア ; _IsrUart1: ; ;受信処理 jnb RI0, _IsrUart0 ;RI0がクリアならジャンプ ; mov A, SBUF0 ;A : 受信データ clr RI0 ;RI0クリア ; movx @fByteCtr, A ;受信データをデータバッファへ転送 inc fByteCtr ;バイトカウンタ + 1 cjne fByteCtr, #0, _IsrUart0 ;バイトカウンタ <> 0なら終了へ ; ; ;1ページ分データ受信完了 mov A, EMI0CN ;A : 外部RAMアドレス上位バイト mov C, ACC.0 ;C : 外部RAMアドレス上位バイトのLSB mov fStatus.bPagePlane, C ;バッファプレーン更新 xrl EMI0CN, #00000001b ;外部RAMアドレス上位バイトのLSBを反転 setb fStatus.bDataReady ;受信完了フラグセット ; _IsrUart0: pop PSW pop ACC reti ; IsrTimer3: ;---------------------------------------;Timer3割り込み処理 : ユーザインターフェース処理 ; ; 処理中はfSwStatus*の整合性が失われることに注意 push ACC push PSW ; anl TMR3CN, #01111111b ;TF3Hクリア ; mov fSwStatus0to1, fSwStatus ;fSwStatus0to1にfSwStatusの前回値をコピーしておく mov fSwStatus1to0, fSwStatus ;fSwStatus1to0にfSwStatusの前回値をコピーしておく mov C, pSwA ;C : pSwAの今回値 mov ACC.bSwA, C ;ACC.bSwA更新 mov C, pSwB ;C : pSwBの今回値 mov ACC.bSwB, C ;ACC.bSwB更新 mov C, pSwC ;C : pSwCの今回値 mov ACC.bSwC, C ;ACC.bSwC更新 cpl A ;論理反転して正論理にする mov fSwPortSave, A ;fSwPortSaveに一時保存 xrl A, fSwPortPrev ;A : 前回値 xor 今回値 anl fSwStatus, A ;fSwStatusについて前回値 = 今回値のビットのみクリア cpl A ;A : 前回値 = 今回値のビットのみ1 anl A, fSwPortSave ;A : fSwPortSaveについて前回値 = 今回値のビットを抽出 orl A, fSwStatus ;A : fSwStatusについて前回値 = 今回値のビットを更新 anl A, #cSwBitMask ;A : スイッチ入力ビットのみ抽出 mov fSwStatus, A ;fSwStatus更新 xrl fSwStatus0to1, A ;fSwStatus0to1 : fSwStatusについて前回値 <> 今回値のビットのみ1 anl fSwStatus0to1, A ;fSwStatus0to1 : ((前回値 <> 今回値) and (今回値 = 1))のビットのみ1 xrl fSwStatus1to0, A ;fSwStatus1to0 : fSwStatusについて前回値 <> 今回値のビットのみ1 cpl A ;反転 anl fSwStatus1to0, A ;fSwStatus1to0 : ((前回値 <> 今回値) and (今回値 = 0))のビットのみ1 mov fSwPortPrev, fSwPortSave ;fSwPortPrev更新 setb fPlayMode.bPmSwUpdate ;PmSwUpdateフラグセット ; inc fUITimerCtr ;Timer3割り込みカウンタ更新 ; pop PSW pop ACC reti ; ;=============================================================== ; End of Source CodeSegmentEnd: ; ; if CodeSegmentEnd >= 03dffh __ERROR__ "Code segment is too large." endif ; end ;===============================================================