当局自体素人ですので、MSSPプログラムのバグや記載内容の間違い等があるかも知れません。
気付いたら修正していきます


最終更新

MSSPプログラム

 2019年11月20日

記載内容

 2019年11月20日
MSSPの基本制御プログラムの遍歴まとめ

当局内のMSSPルーチンも当初と比較して小変更を繰り返してきました。
それだけ使用頻度が多かったし、かつ紛らわしくなってきました。
そこで、このコーナーで遍歴等をまとめてみる事にしました。


参考文献
①電子工作のためのPIC16F活用ガイドブック 後閑哲也著 技術評論社
②PIC16F1764日本語マニュアル MicroChip



履歴一覧

 I2Cマスタモード Ver0.1 送信のみ
 I2Cマスタモード Ver0.2 受信追加
 I2Cマスターモード Ver0.2a Ver0.2の小修正
 I2Cスレーブモード Ver0.1 受信のみ
 I2Cマスターモード Ver0.2b Ver0.2aの小修正
 I2Cマスターモード Ver0.2bのXC8への移植
 I2Cスレーブモード Ver0.2 送受信可、クロックストレッチ対応

 共通基本事項

ANSELはデジタル
 すなわち、’0’に設定

TRISは入力
 すなわち、’1’に設定




PIC16F1705の場合

RC0-1出力源設定
マニュアルに記してある、
RxyPPSレジスタの設定です。
これを初期設定に挿入

RC0PPSレジスタ=10H

RC1PPSレジスタ=11H




PIC16F18326の場合

RC0-1をSSP1に関連する設定場合

PPSレジスタ関連
SSP1CLKPPSレジスタ=10H
SSP1DATPPSレジスタ=11H
RC0PPSレジスタ=18H
RC1PPSレジスタ=19H

SSP2モジュールのマスク
PMD4レジスタ=04H
PICF1シリーズ内の差異によるMSSP使用の注意点

PIC16F1823/1828/1829等16F18xxシリーズ(PPS機能無)
 MSSP起動で自動的にRC0-1がMSSP入出力となり、そのまま使えます

PIC16F1705等PPS機能有のPIC(注1)
 16F1823と同様にRC0=SCL、RC1=SDAとする場合、
 PPSレジスタによる入出力ピン選択機能が付いたため、PPSの設定値が問題となります。
 パワーオンデフォルト値でI/Oピンと内蔵モジュールの接続が合致してない場合使えません
 16F1705の場合、デフォルトではI/Oピン入力とMSSP入力と合致している様です。
 しかし、RC0-1出力源はLATCとなっている
 この、RC0-1出力源をMSSPに変更します。

PIC16F18326等PPSおよびMSSP2、PMDレジスタがある場合(注2)
 16F1823と同様にRC0=SCL、RC1=SDAとする場合、
 16F1705の様にPPSレジスタの設定を行います。
 設定値は16F1705とは違いますの注意してください(注1)
 MSSP2のディセーブルをPMDxレジスタで行います。


注1)
PPSのパワーオンデフォルト値はPICによって違う様で注意が必要です。
PPS関連詳細は使用するPICマニュアル、PPSモジュールの章を参照してください

注2)
16F18326はMSSP2があるようです
詳細は不明ですが、どっちも機能している(デフォルト)とうまくない様です。
現在公開中のMSSPv1はMSSP1を使用します。
よって、PMDxレジスタを使用してMSSP2をディセーブルします。
PMDx関連詳細は使用するPICマニュアル、PMDxモジュールの章を参照してください
アッセンブラ版 
基本制御ルーチン群 Ver0.2b

 MSSP_I2C_02b.asm

注意
PIC16F1シリーズ以降での使用を想定しています
ASMでのMSSP関連PPSレジスタアドレスは下記の通り


PIC1705/1709 PPSレジスタ

BANK28
 E0FH PPSLOCK
 E20H SSPCLKPPS
 E21H SSPDATPPS
 E22H SSPSSPPS
以上のレジスタはMSSP関連レジスタの入力ピンを下記値で指定します。
xxxPPS=17H 入力はRC7
xxxPPS=16H 入力はRC6
xxxPPS=15H 入力はRC5
xxxPPS=14H 入力はRC4
xxxPPS=13H 入力はRC3
xxxPPS=12H 入力はRC2
xxxPPS=11H 入力はRC1
xxxPPS=10H 入力はRC0
xxxPPS=0FH 入力はRB7
xxxPPS=0EH 入力はRB6
xxxPPS=0DH 入力はRB5
xxxPPS=0CH 入力はRB4
xxxPPS=05H 入力はRA5
xxxPPS=04H 入力はRA4
xxxPPS=03H 入力はRA3
xxxPPS=02H 入力はRA2
xxxPPS=01H 入力はRA1
xxxPPS=00H 入力はRA0

例えば、
SSPCLKPPS=10H
 RC0はSCL(I2Cクロック入力)
SSPDATPPS=11H
 RC1はSDA(I2Cデータ入力)


BANK29
 E90H RA0PPS
 E91H RA1PPS
 E92H RA2PPS
 E94H RA4PPS
 E95H RA5PPS
 E9CH RB4PPS
 E9DH RB5PPS
 E9EH RB6PPS
 E9FH RB7PPS
 EA0H RC0PPS
 EA1H RC1PPS
 EA2H RC2PPS
 EA3H RC3PPS
 EA4H RC4PPS
 EA5H RC5PPS
 EA6H RC6PPS
 EA7H RC7PPS
以上のレジスタは各種モジュールの出力ピンを指定します。
例えば、
RC0PPS=10H
 RC0はSCL出力(I2Cクロック)
RC1PPS=11H
 RC1はSDA出力(I2Cデータ)

※I2C入出力ポートは同一である必要があります。

アッセンブラ版 I2Cマスターモード Ver0.2bの詳細


(2)主要サブルーチン


 1) MSSP_MAS
    MSSPモジュール初期設定および起動
    引数:無
    戻値:無

 2) MSSP_IDLE
    MSSPモジュールのアイドル状態待ち
    引数:無
    戻値:無

 3) STARTCON
    I2Cバスにスタートコンディション送出
    引数:無
    戻値:無

 4) RESTART
    スレーブにリスタート送出
    引数:無
    戻値:無

 5) STOPCON
    I2Cバスにストップコンディション送出
    引数:無
    戻値:無

 6) SEND_BYTE
    I2Cバスに1バイトのデータを送出
    引数:Wregの8bitデータ
    戻値:無

 7) RCV_BYTE
    I2Cバスより1バイトのデータを受信
    スレーブにACKを返信する(連続受信用)
    引数:無
    戻値:Wregに受信した1バイトデータ
    使用ワーク:wrk1

 8) LAST_RCV
    I2Cバスより1バイトのデータを受信
    スレーブにNACKを返信する(最終受信用)
    引数:無
    戻値:Wregに受信した1バイトデータ
    使用ワーク:wrk1


XC8版制御関数群 Ver0.2b

 MSSP02b.h

 MSSP02b.c


PPSレジスタの設定はアッセンブラ版の記載を参照して下さい。
XC8ではPPSレジスタアドレスを意識しなくても大丈夫なので楽です (^^♪

XC8版 I2Cマスターモード Ver0.2bの詳細

当局版MSSPモジュールのアッセンブラソースから移植
MSSP(I2Cマスタ)制御ソースファイル Ver0.2b

1) MsspMaster(void)
   MSSPモジュール初期設定および起動
   引数:無
   戻値:無

2) MsspIdle(void)
   MSSPモジュールのアイドル状態待ち
   引数:無
   戻値:無

3) I2C_START(void)
   I2Cバスにスタートコンディション送出
   引数:無
   戻値:無

4) I2C_RESTART(void)
   スレーブにリスタート送出
   引数:無
   戻値:無

5) I2C_STOP(void)
   I2Cバスにストップコンディション送出
   引数:無
   戻値:無

6) SendByte(unsigned char)
   I2Cバスに1バイトのデータを送出
   引数:8bitデータ
   戻値:無

7) unsigned char RcvByte(unsigned char)
   I2Cバスより1バイトのデータを受信
   引数:1byteデータ
       0=スレーブにACKを返信する(連続受信)
       1=スレーブにNACKを返信する(最終受信)
   戻値:受信した1バイトデータ


PIC内蔵MSSP制御方法詳細

<お断わり>
これは書きかけです、当局版MSSP制御プログラムを作成するに当たって、PICマニュアルからの当局自己解釈です。
この解釈を基にした上記MSSPプログラムは一応動作はしているようですが、素人解釈に付き間違っている場合もあります


1.I2Cマスターモードの概要

(1)I2Cバスラインの概要
  電源ラインに中抵抗(10Kオーム程度)によるプルアップされた、2本線で構成されている
  それぞれはSCL(シリアルクロックライン)とSDA(シリアルデータライン)と呼ばれる。
  この2本線をバスラインとし、送信開始と終了を司る「マスタ」デバイスとマスタの指示に呼応する「スレーブ」デバイスがある。
  マスタは基本的に単独(注1)、スレーブは複数存在でき、「スレーブアドレス」で識別される。
  プルアップ抵抗が概ね3Kオーム以下の低抵抗となると、I2Cバスがうまく動作しない事がある
  よって、プルアップ抵抗付きのデバイスを複数I2Cバスに接続する場合、注意が必要
  データは双方向シリアル転送で、基本は1バイト単位で送受され、送信はmsbから始まり、lsbで終了
  データを送受信している最中は、1つのマスタと1つのスレーブでバスを使用し、他のスレーブは静観しています。
  バスはVDD電位の時H1(H)、GND電位の時L(0)と見なされる正論理

(2)データ通信の基本的な概要

  1)SDAラインとSCLライン
   SCL=1の時、SDA電位を偏位させると、スタート・ストップ他等の特殊なI2Cバス命令と見なされる
   SCL=0の時、SDA電位を偏位させても、基本的に問題無い

  2)データビットの基本
   送受信されるデータビットは9bitが1つの基本の様です。(スタート・ストップコンディションを除く)
   最初の8bitはデータそのもので、9bit目はACKビットあるいはNACKビットとして機能します。
   ACKビットは肯定応答で、「了解した」とか「受信した」とかの意味になるようです。
   NACKビットは否定応答で、「受信できない」「送信データは無い」とかの意味になるようです。
   この9ビットのかたまりで基本の1バイトの送受信を行います。

  3)送受信される基本の1バイト(注2)
   1バイトのデータは、「I2Cアドレス」と「I2Cデータ」に大別されます。
   どちらも送受信に於いて、SSP1BUFレジスタに格納され(し)ます。
   a)I2Cアドレス
    bit7-bit1の7ビットはスレーブ側の識別アドレスとして使用し、マスタ側にアドレスは存在しません。
    bit0はR/Wビットとして意味を持ち、
    マスタがスレーブに送信する場合は、R/W=0
    マスタが受信し、スレーブに送信させる場合は、R/W=1としてアドレスコールの時に一緒にマスタが送ります。
    例えば、当局のMSSP関数を使用してマスタ側を構築した場合、
    スレーブに対してマスタがアドレス7CHを送信すると、このアドレスは3EH+R/W=0と言う事になり、
    3EHのI2Cアドレスのスレーブは次に送信されるI2Cデータを受信します。
    スレーブに対してマスタがアドレス7DHを送信すると、このアドレスは3EH+R/W=1と言う事になり、
    3EHのI2CアドレスのスレーブはマスタへI2Cデータを送信します。
   b)I2Cデータ
    受信成功の場合、SSP1BUFレジスタに格納されています。
    これを読みだせば良いだけです


  4)1バイト送信の基本バス操作
   ①バス・レディ 何もしていない時の基本状態、この状態からスタートし、通信終了後これにもどる
    SDA=1
    SCL=1
   ②スタート条件発令 マスタが行う
    SDA=1 → SDA=0
    SCL=1のまま
   ③データビット設定準備 マスタはSCL=0としてから、SDAのデータビットを設定する
    SDA=X 1or0 自由に変更可
    SCL=0
   ④データビットの確定 マスタはSCL=1とし、スレーブはSDAビットを自身のシフトレジスタに取り込む
    SDA=X(データバイトのbit7)
    SCL=1

    ③~④を繰り返す(データの6bit~7bit)

   ③データビット設定準備 マスタはSCL=0としてから、SDAのデータビットを設定する
    SDA=X 1or0 自由に変更可
    SCL=0
   ④データビットの確定 マスタはSCL=1とし、スレーブはSDAビットを自身のシフトレジスタに取り込む
    SDA=X(データバイトのbit0)
    SCL=1

   ⑤/ACK受信 マスタはSCL=0としてから、SDA=1とする
           スレーブは1バイト分のビットデータを受信したなら、SDA=0とする(/ACK送信)
           マスタは自身がSDA=1としたにも関わらず、SDA=0となった事を確認(/ACK受信)
    SDA=0
    SCL=0
   ⑥/ACK解除 マスタはSCL=1としてから、SCL=0とする
           スレーブはSCLの1クロックを確認すると、/ACKを解除する
    SDA=0
    SCL=1 → SCL=0
   ⑦送信終了準備 マスタはSCL=0としてから、SDAビットを0とし、その後SCL=1とする
           /ACK処理にて、すでにSCL=0になっている
    SDA=0
    SCL=0 → SCL=1
   ⑧ストップ条件発令 マスタはSCL=1としてから、SDAビットを1とする
    SDA=0 → SDA=1
    SCL=1
   ⑨バス・レディ
    SDA=1
    SCL=1


注1)マスタの複数存在
  実際、マスタは複数存在できる様です。
  それにより、複数のマスタがバス上の複数のスレーブを多重支配可能なようです。
  バスの調停等、話が面倒になるので、ここでは複数マスタは扱いません
  ここで記載のMSSPルーチンも複数マスタに対応していません。

注2)I2Cアドレス
  アドレス指定は7bitアドレスと10bitアドレスが存在する様ですが、ここでは7bitアドレスのみを扱います




2.I2Cスレーブモードの概要

(1)I2Cバスラインを常時見ているMSSPスレーブハードウエア
  MSSPはバスラインを監視し、何かが起こるとSSP1IFビットをセットし、割り込みを発生させます。
  そして、各種フラグを通してスレーブソフトウエアにI2Cバスに何が起きたのかを知らせます。
  MSSPハードウエアはスレーブソフトウエアにとって優秀なI2C執事と言う事になります。 (^^ゞ
  スレーブソフトはその執事の言葉(各種フラグ)を把握し、それに対する適切な指示を出す事が重要です。
  当局版スレーブソフト(ASM版)はそれらを実行するために、やってはいけないジャンプ命令を多用しています。
  ただ、多少は見易くするために、I2C進行に合わせた階層構造の形態を何とか保っていますが・・・ (-_-;)
  その階層間の移動発令はISR(割り込みルーチン)が指示する事になっています。

(2)データ通信の基本的な概要

  1)I2Cデータの進行(流れ)

   a)I2Cデータ
    I2Cデータは1バイトのデータで、I2Cクロックの9ビットで構成されています。
    I2CデータはSSP1BUFに格納したり、されたりして使用します
    送信する場合はその1バイトデータをSSP1BUFに格納してやります
    受信した場合はその1バイトデータはSSP1BUFに格納されています。

   b)I2Cデータのスレーブから見た受信
    ①マスタがスタートコンディション生成
    ②全てのスレーブはスタートを認知
    ③マスタがI2Cデータとしてスレーブアドレス1バイトを送信
    ④スレーブはそのデータを一応受信、自分のI2CアドレスならばACK応答、違うならば無視
    ⑤マスタはスレーブの応答を確認すると、I2Cデータを送信
    ⑥スレーブはデータを受信し応答
    ⑦マスタはスレーブの応答を確認すると、次のデータ送信かストップコンディション生成
    ⑧スレーブは次のI2Cデータ受信するか、ストップコンディション検知でアイドルに移行し通信終了

   b)I2Cデータのスレーブから見た送信
    ①マスタがスタートコンディション生成
    ②全てのスレーブはスタートを認知
    ③マスタがI2Cデータとしてスレーブアドレス1バイトを送信
    ④スレーブはそのデータを一応受信、自分のI2CアドレスならばACK応答、違うならば無視
    ⑤マスタはスレーブの応答を確認すると、I2Cデータ受信待ち
    ⑥スレーブはデータを送信、マスタは受信
    ⑦マスタは受信完了のACK応答、終了ならばNACK送信後ストップコンディション生成
    ⑧スレーブはACK応答を感知すると次のI2Cデータ送信する、NACKの場合ストップ待ち
     ストップコンディション検知でアイドルに移行し通信終了

   c)リスタートについて
    ①NACK受信の時、マスタからストップが来ないまま、リスタートがくる場合がある
     その場合、通常のスタート同様アドレス受信可能状態を取っておく
     事実上スレーブにとって、NACKもSTOPも同じ対応を取る事となる
     リスタートの場合、アドレスは変わらないが、R/Wが変わっている事が多い(当局比)


  2)MSSPの動作と各種フラグ(注3)

   a)受信待ち(アイドル運転中)
    一見何もしていないように見えますが、アイドル中のMSSPはI2Cバスを常時監視しています。
    この時点で各種フラグはOFFになっていなければなりません。
    自動でONとなるフラグも、手動でOFFにしなければならない事も多いので注意が必要です

   b)スタートおよびストップコンディション検出割り込み
    I2C通信の「始まり」と「終わり」の検出で、SSP1STATレジスタにあります
    当局版スレーブソフト(V0.2)は、いちいち対応が面倒なので、スタートビットをチェックしていません
    もちろんストップビットのチェックは必須です。
    S:スタートビット 1=検出された、0=検出されない
    P:ストップビット 1=検出された、0=検出されない
    共にMSSPをリセットしないとクリアされないので注意が必要です
    これはSSP1CON1SSPENビットをセットしてやる、1動作だけでS・P共にクリアされるようです。

   c)スレーブアドレスあるいはI2Cデータの受信
    MSSPは自身のアドレスを受信すると、そのアドレスはSSP1BUFレジスタに格納、
    R/WビットはSSP1R/Wビットへ格納し、(これでスレーブ側はその後データ受信かデータ送信かが決まる)
    マスタに/ACKを返信し、クロック閉鎖を行い、SSP1IFをセットし、割り込み発生させる
    スレーブ(ソフト)はSSP1IFをクリアし、送受信の準備をする
    ①受信の場合
     スレーブがクロック開放するとマスタはI2Cデータを送信、
     MSSPは受信データをSSP1BUFに格納し、
     /ACKを返信、クロック閉鎖、SSP1IFをセットし割り込み発生させる
     スレーブはSSP1BUFからデータ読み出し、SSP1IFをクリアする
     スレーブがクロック開放すると、マスタは次のデータ送信かストップコンディションを送信
     スレーブはそれらの検出待ちをする
    ②送信の場合
     スレーブは送信するデータを準備し、準備が出来たらSSP1BUFに格納
     スレーブがクロック開放すると、マスタはSSP1BUFに格納されたデータ1バイトを読み込む
     マスタからの/ACKを受信した場合、MSSPはクロック閉鎖しSSP1IFセットし割り込み発生させる
     その場合、スレーブは次のデータ送信の準備をし・・・と、繰り返しとなる
     マスタからのNACKを受信した場合、MSSPはクロック閉鎖を掛けない
     スレーブはNACKを検出したら、MSSPをリセットしアイドル状態にし、リスタートやストップに備える
     マスタはその後すぐにストップコンディション或いはリスタートコンディションを送信してくる

  3)重要なフラグ(スレーブモード目線
    文字ばかりでは無く、マニュアルのタイミング表を見る方が一目で解ります。

   a)PIR1:SSP1IF 割り込み発生フラグ
    SDA/SCLビットは9ビットで1単位となっています
    そのため、MSSPが9ビット目を処理されると同時にSSP1IFはセットされ割り込み発生させます。
    それと同時にMSSPはCKPビットをクリアし、クロックストレッチをONし、I2Cバス進行を一時停止させます。
    この時にスレーブソフトは各種処理を行い、CKPビットをセットし、クロック開放しI2Cバス進行再開させます
    これがスレーブモードプログラミングの基本的流れになります。
    割り込み無くしてスレーブモードプログラムは成立しません。
    その他にスタートコンディション、ストップコンディション発生でセットさせる事が出来ます。
    そのため、スレーブソフトの一部はISRに常駐する事が必須となります。
    この割り込みフラグはMSSPハードウエアがONし、スレーブソフトがOFFにします。

   b)SSP1CON1:CKP SCL(I2Cクロック)開放制御ビット
    CKPビットは’0’でI2Cのクロックを停止させ、I2Cバス進行を停止させます。
    IFビット同様にACK送受信後にMSSPがCKP=0としクロックストレッチをONします。
    CKP=1としクロックストレッチをOFFにするのはスレーブソフトが行います。

   c)SSP1STAT:R/W 読み書きビット情報
    マスタが最初に送ってくるI2Cアドレスの1バイト中、0ビット目がこの情報元となっています
    R/W=0ならばマスタ送信なので、スレーブは続いてマスタから送信されてくるデータを受信します。
    このビットはその後のスレーブの行動が決定される最初の分岐点となります。

   d)SSP1STAT:D/A データ/アドレスビット
    マスタから受信したI2Cデータ1バイトが、アドレスならば D/A=0
    マスタから受信したI2Cデータ1バイトが、通常データならば D/A=1
    マスタからのスタート/リスタート後の最初の1バイトがアドレスでその後のバイトが通常データです。
    スレーブがいちいち調べなくとも、MSSPが示してくれます。

   e)SSP1CON2:ACKSTAT 肯定応答(ACK)ステータスビット
    スレーブが1バイト送信後、マスタからACK返信を受信していた場合は、ACKSTAT=0
    スレーブが1バイト送信後、マスタからNACK返信を受信していた場合は、ACKSTAT=1となります。
    スレーブが1バイト送信後の次の行動に影響します。
    ACK受信の場合、マスタはさらにデータを要求しているので、スレーブは続けて送信します
    NACK受信の場合は、一応送信は終了となり、通常はその後マスタがSTOPを送信します。

   f)SSP1STAT:P ストップビット
    マスタがストップコンディションを生成(STOPを送信)すると、P=1となる。
    これを検出したら通信終了なので、MSSPをアイドル状態に移行させる。
    PビットはMSSPをリセットする事でクリアされる。

   g)SSP1STAT:S スタートビット
    マスタがスタートコンディションを生成(START送信)すると、S=1となる
    これを検出しても、スレーブはそれ程やる事は無いので、当局版スレーブでは無視している
    SビットはMSSPをリセットする事で、クリアされる
    ストップビット検出でもクリアされる(多分)

   h)SSP1STAT:BF バッファフル ステータスビット
    SSP1BUFレジスタの状態を示す
    大事なフラグではあるが、スレーブモードではそれ程注目しなくても、通常は大丈夫なフラグ
    当局版スレーブではチェックしていないが、マスタ版では送信確認のためポーリングしています。
    スレーブではマスタからのACK返信でスレーブからの送信が確認できる
    本来ならば、BFフラグで送信可能かチェックすべきだが・・・ してない (^_^;)

  4)スレーブ用設定ビット

   a)SSP1CON1:SSPM モード選択ビット 4bitあります
    ①0110 I2Cスレーブモード、7bitアドレス 通常これを選択
    ②0111 I2Cスレーブモード、7bitアドレス、STARTとSTOPの割り込み有効にする
    ③0111 I2Cスレーブモード、10bitアドレス 
    ③1111 I2Cスレーブモード、10bitアドレス、STARTとSTOPの割り込み有効にする

   b)SSP1CON2:GCEN ジェネラルコールイネーブルビット
    I2Cジェネラルコールアドレス「00H」を受信した時に割り込み有効にするかどうか選択

   c)SSP1CON1:ACKDT 肯定応答(ACK)データビット
    受信の最後に送信(返信)する9ビット目のビット内容
    1=NACK、0=ACK 

   d)SSP1CON1:SEN クロックストレッチイネーブルビット
    これは必ず有効にします
    1=スレーブ送受信の両方にクロックストレッチを有効にする
    0=クロックストレッチを無効にする

   e)SSP1ADD 8bitでスレーブアドレスを設定する
     最後のビット(bit0)は無視されます
     つまり、bit7-bit1での7bitアドレスを指定します

   f)PIE1:SSP1IE MSSP割り込み設定ビット
     当然、SSP1IE=1にして、割り込み有効にしておきます


注3)スレーブ側I2Cアドレスとクロックストレッチ
   ここでは7bitアドレスのみを扱います。
   さらにクロックストレッチ(クロック閉鎖)を行う事を前提とします
戻る  実験・製作の記録TOPへ戻る