PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)

PIC 16F1827をI2Cスレーブとして用い、かつ通常はスリープしている場合の動作メモです。
クロックは内部発振器16MHzで動作させています。

※注意 本記事に私的な解釈です。間違っている可能性は十分にありますので内容についての責任は持てません。

背景


Raspberry PiのGPIOで周辺ハードウェアーを制御するには、OSを介してのハード制御の為、信号のタイミング制御が難しいようです。
そちらはOSのないPICに任せ、Raspberry PiなどのOSの存在するハードは情報処理を行という機能分担が望ましいという結論になりました。

そこで、Raspberry PiとPIC間の通信をI2Cで行う場合の実機テストをする事にしました。

省電力の意味でPICのSLEEP(※1)を利用する場合のテスト結果のメモです。

※1 I2Cは機器内通信が前提の為、電源も同一系統でマスタ、スレーブ共に電源が立ち上がり、立ち下がりも同時になることが暗黙の了解であると思われます。
各電源が別系統の場合、例えば、Raspberry Piの電源がONでPICの電源がOFFの状態が長時間続く場合、I2Cの信号線を通じて、Raspberry Piの電源→プルフップ抵抗→PICの寄生ダイオードを通じてPICに電源が供給され、PICは起動してしまいます。もちろん、安定動作はしません。
その為、十分な電力が供給される事が前提のRaspberry Piシステムで、PICを節電目的でSLEEP動作させる必要性は大変少ないのではないかと思われますが、ここではあえてSLEEPさせた場合の動作をメモしています。

テスト環境


■PIC16F1827はI2Cスレーブとして動作
リード(R)を受信すると2byteのデータ(0xd0,0xd1)を順次送信する。
■I2CマスタはRaspberry Pi
1byteのデータ(0xAA)をスレーブ(16F1827)に送信し、その後2byteのデータを受信する。


結論


I2Cのスタートbitによる割り込みを受けた時から、ストップbit割り込みを受けるまでの間はSLEEPしてはならない。


テスト方法


■main()でSLEEPのルーブをする。SLEEPしない場合はNOPのループをする。
■割り込み処理時、各レジスタの値を記録する。
■RA0~4にパルスを出力し、ソース上の通過を外部に知らせる。

■ロジックアナライザ ZEROPLUS LAP-C(16064)により下記の信号を観測
(1)SCL I2Cクロック
(2)SDA I2Cデータ
(3)RA0 割り込み処理開始を知らせるパルス
(4)RA1 レジスタ値の記録完了を知らせるパルス
(5)RA2 I2C制御完了を知らせるパルス(この後、割り込み処理を抜ける)
(6)RA3 main()のループ内処理の開始を知らせるパルス(SLEEP前)
(7)RA4 main()のループ内処理の終了を知らせるパルス(SLEEP後)
(8)CLKOUT PICクロック

PIC ソースはこちらをクリック





テスト



割り込み終了の度にSLEEPした場合


この場合、クロックストレッチが発生しない箇所ができる。
その為、次の送信データをセットする時間的余裕がなく、本来送信すべきデータが送信されない。


■クロックストレッチが発生しない箇所がある
PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)



第一群はWモードでマスターのRaspberry Piが1byteのデータを送信してきます。
アドレス受信後、SCLがLOWになりクロックストレッチ(黄色矢印)が発生しています。

第二郡はRモードでPICは2BYTEのデータを送信します。
アドレスと1byte目の間のACKはクロックストレッチ(黄色矢印)が発生していますが、
1byte目と2byte目の間のACKではクロックストレッチ(赤色矢印)は発生していません。
下図は第二郡の部分を拡大したものです。


■クロックストレッチの生成は誰の責任
PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)

■PICハードがクロックストレッチの開始を行う例
例えば、上図の赤枠の部分はPICがアドレス+Rを受取り、A-ACKを返し、割り込みを生成し、割り込みルーチンに制御が移るシーンです。
ここでSCLをLOWにしクロックストレッチを行っているのはPICのハードです。

時間順に見ていくと、
(1)ACKのクロック(SCL)の立ち下がりで割り込みを生成し、PICのスリープを解除しています。
(2)それにより、PICのクロック(CLKOUT)(白い部分)が起動されています。
(3)PICハードでの割り込み遷移処理後、割り込みルーチに入った事を示す、RA0のパルス(5)が出力されています。

割り込み処理に入った時点で多くの時間が経っており、PICハードによるクロックストレッチがなければソフトにより直接クロックSCLをLOWにしてクロックストレッチするには間に合いません。
したがってクロックストレッチの開始はPICハードの責任です。ソフトでは直接SCLをLOWにしていません。
ソフトはSSP1CON1レジスタのCKPを1にする事により、停止されているクロックを有効化し再び転送動作を再開させる事(クロックストレッチの解除)のみです。上図の時間軸上では赤枠を過ぎた右側のRA2のパルスの位置です。

■クロックストレッチが開始されない例
上図の青枠の部分はPICがアドレス+Rを受取った後、1byte目のD-ACKを返す箇所です。
この例ではA-ACKの時のようなクロックストレッチは発生していません。

ACKのクロック(SCL)の立ち下がりで割り込みが生成された以後の動作はA-ACKの時と同じシーケンスを辿ります。
ソフトでCKP=1によるクロック有効化も行っていますが、既に意味はありません。

■各割り込み時点でのCKP(SSP1CON1-bit4)の状態
PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)
ssp1con1[0] unsigned char 0x3E
ssp1con1[1] unsigned char 0x2E
ssp1con1[2] unsigned char 0x2E
ssp1con1[3] unsigned char 0x3E
ssp1con1[4] unsigned char 0x3E
ssp1con1[5] unsigned char 0x2E
ssp1con1[6] unsigned char 0x2E
ssp1con1[7] unsigned char 0x3E
PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)ssp1con1配列の添字はRA0のパルス番号

クロックストレッチが発生するA-ACKの割り込み時点のssp1con[5]のbit4はOFFでクロックストレッチ中(Holds clock low (clock stretch))を示しています。
クロックストレッチが発生しない、1byte目のD-ACKの割り込み時点でもssp1con1[6]のbit4はOFFです。
にも、かかわらずクロックストレッチは発生しません。


I2Cスタートからストップ間はSLEEPを禁止した場合



レジスタの設定環境も正しいと思われ、ssp1con1[6]のbit4はOFFになっている事からハード上の環境としてSLEEPの影響を疑い、I2Cのスタートからストップの間、SLEEPをしない様にしました。

PIC 16F1827 I2C-SLAVEモードとSLEEPの動作確認(備忘録)

上図の様にクロックストレッチが発生しデータも目的通り0xD1が送信されました。

■最後のD-NACK
2byte目送信後のD-NACKではNACKの為、データの転送は終了であり、次の送信データセットの為の時間稼ぎは必要なく、クロックストレッチは発生しません。
マスター(Raspberry Pi)はこの時レシーバであり、必要量のデータを受信した事を送信者であるスレーブ(PIC)に伝える為にNACKを送っています。



感想


A-ACKの時とD-ACKの時の違いが何なのか遂に判りませんでした。
対処方法としてこれが正しいのかも判りません。
が、無理に割り込み終了都度、SLEEPさせる必要性もそれほど無いと思われるので、これでよしとします。

今までなら、記事にもせずに何処かにメモって置くだけなのですが、それだと整理もせずに結果だけで後で何だったか全く不明という状態でした。
当ブログのような僻地ブログでも公開するとなると少しは纏めようとするので、結果自分にとっても有益です。
万一、どなたかの役に立つなら望外の喜びです。

しかし、自分ならこんな長い記事は読む気がしません。

スポンサーサイト

PIC12F675 GPIO port change interrupt 処理のループと対策(備忘録)

PIC 12F675の割り込み処理がうまく動作しないので調べてみました。

GPIO port change interrupt 処理がループしている模様です。
割り込み処理を一旦抜けるものの再度割り込み処理に入る。これを永遠に繰り返します。

開発環境 : MPLAB X IDE v3.51、Microchip MPLAB XC8 C Compiler (Free Mode) V1.40、ICD3です。

■結果
GPIO port change interrupt の割り込み処理内でGPIOレジスタに何らかのアクセスを すると、割り込み処理ループの現象は無くなりました。

調査


■発生時のソース

※下記ソースは現象確認の為のもので、この現象に気づいた時のものではありません。

GP5がport change 監視の対象ピン(外部からパルス信号を与える)
GP1はオシロによるデバック目的の出力ピン(今回のレポートでは使用していません)
GP4はCLKOUTとして、クロックを監視(目的は割り込み処理内での現象把握の為)

/*
 * GPIO割り込みテスト
 * Created on 2017/02/11, 8:17
 */

// CONFIG
#pragma config FOSC = INTRCCLK  // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)


#include <xc.h>

char time_count;

void interrupt intservice() {
    INTCONbits.GIE = 0;
    if (INTCONbits.GPIE && INTCONbits.GPIF) {
        INTCONbits.GPIF = 0;

        if (time_count++ > 10) {
            INTCON = 0x00;
            SLEEP();
        }

        //asm("MOVF GPIO,W");
    }
    INTCONbits.GIE = 1;
}

void main(void) {
    GPIO = 0x00;
    ANSEL = 0x00;
    CMCON = 0X07; //Comparator Off (Lowest power) CM2:CM0 = 111
    TRISIO = 0b00100000; //GPIO5:input
    GPIO = 0x00; //GPIOクリア
    INTCON = 0x00; //割り込み不許可
    OPTION_REG = 0x00;
    IOC = 0x00;
    PIE1 = 0x00;
    ADCON0 = 0x00;

    GPIObits.GP1 = 0;
    GPIObits.GP2 = 0;
    INTCON = 0x88;  //Enables all unmasked interrupts;
                    //Enables the GPIO port change interrupt
    IOC = 0b00100000; //IOC5 : enable an interrupt-on-change

    time_count = 0;
    while (1) {
        asm("MOVF GPIO,W");
        //asm("MOVWF GPIO");
    }

    return;
}


■発生時のオシロ波形

※CH1(黄) GP5がport change 監視の対象ピン(外部からパルス信号を与える)
※CH2(青) GP1はオシロによるデバック目的の出力ピン(今回のレポートでは使用していません)
※CH3(紫) GP4はCLKOUTとして、クロックを監視(目的は割り込み処理内での現象把握の為)
PIC12F675 GPIO port change interrupt 処理のループと対策(備忘録)
(1)CH1(黄) GP5入力端子にパルスが入り、信号レベルが変化すると、
(2)interrupt intservice()に制御が移る。
(3)intservice()内で、time_count++により割り込み回数をカウントし、
(4)一定回数(10回)を超えると、SLEEPさせる。(注1)
(5)SLEEPより、内部クロックが停止しCH3(紫) GP4のCLKOUT波形は停止する。これによりSLEEPを通過したことを確認した。

※注1:GP1にパルスを出す方法では、GP1へのアクセスそのものがこの現象を妨げる要因になるので、SLEEPを使用し内部クロックを停止する事により、ポイント通過を確認しました。


■現象要約
一度の割り込みであるにもかかわらず、連続して10回以上の割り込みが発生する。
time_countを100回カウントしても同様。


発生要素


(1)mainのループ、この場合while(1)内でGPIOレジスタにアクセスし、かつ
(2)interrupt intservice()内で、GPIOレジスタにアクセスしていない場合
に発生する。

対策


interrupt intservice()内で、asm("MOVF GPIO,W"); によりGPIOに空アクセスする。
main()内でGPIOへのアクセス制限はかけられない為。


感想


■この対策に気づいた理由は、

PIC12F675 GPIO port change interrupt 処理のループと対策(備忘録)
出典:MICROCHIP社のPIC12F629/675 Data Sheet

↓上図の拡大
PIC12F675 GPIO port change interrupt 処理のループと対策(備忘録)

入力はすでに安定しているにもかかわらず、Interrupt-on-Changeが発生するということは、上図右下の2つのDフリップフロップよるchange検出回路が動作していない、すなわち、RD PORTが出ていない。
よって、GPIOを空読みしたらいいのでは。
これで解決しましたが、このRD PORTは単にポートを読む時だけではなさそうです。mainでのwhile(1)よる空ループではGPIOのリードをしなくても、changeを検出しています。

■さらに詳細は
その後、色々試みましたが良く判りませんでした。





お知らせ
■注意:Google Chrome以外のブラウザでは動作しない事もあります。
お好みに応じて
画像だけの表示でいいよ
やっぱり全部表示して
背景は黒がいいな
背景を元に戻して
サブジャンル
メモリアルマップ
My Favorite Photo
検索フォーム
プロフィール

otsu.usiwakamaru

Author:otsu.usiwakamaru
五条の橋でひらりひらりと欄干を飛び渡る牛若丸のように、興の向くまま電子回路にプログラミングに写真にと飛び回っています。

プロフィール詳細

カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
キーワード
クリックしたキーワードの記事のみ表示します。

電池 試み IXY デザイン  改造 3D ミッキー 

最新記事
月別アーカイブ
全記事表示リンク

全ての記事を表示する

おすすめプログ(新着記事)
リンク


にほんブログ村
カテゴリ
ART (1)
橋 (0)
PIC (2)
カウンタ
訪問者数(UU)

アクセス数

現在の閲覧者数

tael no013用