MSSPモジュール I2C通信作成資料
以前作成した、MSSPモジュール I2Cマスターの基本動作を組み込んだ時の資料をまとめました。
データシートDS41391Bから、自分なりに読み込んだタイミングチャート。
PIC16F1827データシート DS41391B
このデータシートをそのままC言語に翻訳する作業を淡々と行いました。
各々の状態遷移を複数の関数を作成することで、実行します。
データシートP.268 29.6.6.4 Typical Transmit Sequence
1.スタートコンディションの発行 SSP1CON2レジスタのSENビット
をセット
2.SSP1IFビット
がセットされる。 スタートが完了したら、SSP1IFビット
がセットされる。
3.SSP1IFビット
をユーザーがクリアする。
4.MSSPモジュールは、他の制御が起きる前に、スタートに必要な経過時間待つ。
5.ユーザーは、SSP1BUF
にスレーブアドレスを書きこむ
6.SDAピンから、1ビットずつシフトしながら、スレーブアドレス8ビットがすべて出力される。
7.MSSPモジュールは、スレーブからのACKを受信し、その値を、SSP1CON2のACKSTATビット
に格納する。
8.9クロック目の終わりに、MSSPモジュールは割込みを発生させる。 このとき、SSP1IFビットはセットされる。
9.ユーザーは、データバイトをSSP1BUF
に格納する(次に出力するデータ)
10.8ビットすべてが送信されるまで、SDAピンからデータが1ビットずつ出力される。
11.MSSPモジュールは、スレーブからのACKを受信し、その値を、SSP1CON2のACKSTATビット
に格納する。
12.すべてのデータを転送するまで、8から11の動作をくりかえす。
13.ユーザーは、SSP1CON2のPENビットまたは、RSENビット
をセットすることで、ストップ、リスタートを生成することができます。ストップ、リスタートが生成されたら、割り込みが起こります。
MSSPモジュール I2Cマスター 送受信コード
#ifndef I2C_MSSP1_H
#define I2C_MSSP1_H
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#define _XTAL_FREQ 16000000
#ifdef __cplusplus
extern "C" {
#endif
//-----------------------------------------------
#define I2C1_Ack 0//SSP1CON2.ACKDT master:receive mode
#define I2C1_NoAck 1//SSP1CON2.ACKDT master:receive mode
extern void I2C1_Reg_Init(void);
extern bool I2C1_Start(void);
extern bool I2C1_ReStart(void);
extern bool I2C1_Stop(void);
extern bool I2C1_Tx_Buffer_Write(uint8_t _byte_data);
extern uint8_t I2C1_Rx_Buffer_Read(void);
extern bool I2C1_Wait_Ack(void);
extern bool I2C1_Send_Ack(uint8_t _Ack_Nack);
extern bool I2C1_CheckIdle(void);
extern bool I2C1_ClearSSPxIF(void);
//------------------------------------------------
//-----------------------------------------------
extern bool I2C1_b1Write(uint8_t _device_add, uint8_t _data);
extern uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2);
extern uint8_t I2C1_DataBuffer[10];
extern bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len);
extern uint8_t I2C1_b1Read(uint8_t _device, uint8_t _data1);
extern uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1);
extern bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len);
//-----------------------------------------------
#ifdef __cplusplus
}
#endif
#endif /* I2C_MSSP1_H */
#include "I2C_MSSP1.h"
uint8_t I2C1_DataBuffer[10];//読取りバッファ
//--------------------------------------------
//I2C1 MSSP1初期化
//--------------------------------------------
void I2C1_Reg_Init(void)
{
SSP1STAT=0xC0;
SSP1CON1=0x38;
SSP1CON3=0x00;
//SSP1ADD=0x50;//Fosc=16Mhz Fclock=50kHz
SSP1ADD=0x27;//Fosc=16MHz Fclock=100kHz
//SSP1ADD=0x09;//Fosc=16MHz Fclock=400kHz
PIE1bits.SSP1IE=0;
}
//--------------------------------------------
//I2C1 MSSP1スタートコンディション発令
//--------------------------------------------
bool I2C1_Start(void)
{
if(!I2C1_CheckIdle()) return false;
SSP1CON2bits.SEN=1;
if(!I2C1_ClearSSPxIF())return false;
NOP();
NOP();
NOP();
NOP();
NOP();
return true;
}
//--------------------------------------------
//I2C1 MSSP1リスタートコンディション発令
//--------------------------------------------
bool I2C1_ReStart(void)
{
//restart
if(!I2C1_CheckIdle()) return false;
SSP1CON2bits.RSEN=1;
NOP();
NOP();
NOP();
NOP();
NOP();
return true;
}
//--------------------------------------------
//I2C1 MSSP1ストップコンディション発令
//--------------------------------------------
bool I2C1_Stop(void)
{
if(!I2C1_CheckIdle()) return false;
SSP1CON2bits.PEN=1;
if(!I2C1_ClearSSPxIF())return false;
NOP();
NOP();
NOP();
NOP();
NOP();
return true;
}
//--------------------------------------------
//I2C1 MSSP1 送信バッファ書込み
//--------------------------------------------
bool I2C1_Tx_Buffer_Write(uint8_t _byte_data)
{
if(!I2C1_CheckIdle()) return false;
SSP1BUF=_byte_data;
if(!I2C1_ClearSSPxIF())return false;
NOP();
NOP();
NOP();
NOP();
NOP();
return true;
}
//--------------------------------------------
//I2C1 MSSP1 受信バッファ読み出し
//--------------------------------------------
uint8_t I2C1_Rx_Buffer_Read(void)
{
uint8_t ret, cnt;
ret=0xFF;
cnt=0;
if(!I2C1_CheckIdle()) return false;
SSP1CON2bits.RCEN=1;
while(!SSP1STATbits.BF){
__delay_us(3);
cnt++;
if(cnt==100)return false;
}
if(!I2C1_CheckIdle()) return false;
ret = SSP1BUF;
if(!I2C1_ClearSSPxIF())return false;
return ret;
}
//--------------------------------------------
//I2C1 MSSP1 ACK確認
//--------------------------------------------
bool I2C1_Wait_Ack(void)
{
//while(SSP1CON2bits.ACKSTAT);
if(SSP1CON2bits.ACKSTAT)
{
return false;//error
}else
{
return true;//success
}
}
//--------------------------------------------
//I2C1 MSSP1 ACK送信
//--------------------------------------------
bool I2C1_Send_Ack(uint8_t _Ack_Nack)
{
if(!I2C1_CheckIdle()) return false;
SSP1CON2bits.ACKDT=_Ack_Nack;
SSP1CON2bits.ACKEN=1;
if(!I2C1_ClearSSPxIF())return false;
return true;
}
//--------------------------------------------
//I2C1 MSSP1 アイドリングチェック
//--------------------------------------------
bool I2C1_CheckIdle(void)
{
uint8_t cnt=0;
while(SSP1STATbits.R_nW || SSP1CON2 & 0x1F)
{
/* __delay_us(2);
cnt++;
if(cnt==100)
return false;*/
};//MSSP1 is idle mode
return true;
}
//--------------------------------------------
//I2C1 MSSP1 SSP1IFフラグクリア
//--------------------------------------------
bool I2C1_ClearSSPxIF(void)
{
uint8_t cnt=0;
while(!PIR1bits.SSP1IF)
{
/* __delay_us(2);
cnt++;
if(cnt==100)
return false;*/
};
PIR1bits.SSP1IF=0;
return true;
}
//-----------------------------------------------------------------
//----------------------------------------------------
// I2C1 MSSP1 1バイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ
//----------------------------------------------------
bool I2C1_b1Write(uint8_t _device_add, uint8_t _data)
{
//start condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
return false;
//send data
I2C1_Tx_Buffer_Write(_data);
if(!I2C1_Wait_Ack())
return false;
//Stop condition
I2C1_Stop();
return true;
}
//----------------------------------------------------
// I2C1 MSSP1 2バイト送信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_data2:送信データ
//----------------------------------------------------
uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2)
{
//start condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
{
return 0xF1;
//return false;
}
//send data
I2C1_Tx_Buffer_Write(_data1);
if(!I2C1_Wait_Ack())
{
return 0xF2;
//return false;
}
//send data
I2C1_Tx_Buffer_Write(_data2);
if(!I2C1_Wait_Ack())
{
return 0xF3;
//return false;
}
//Stop condition
I2C1_Stop();
return true;
}
//----------------------------------------------------
// I2C1 MSSP1 nバイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ先頭アドレス
//_len:送信長
//----------------------------------------------------
bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len)
{
//start condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
return false;
//send data
do{
I2C1_Tx_Buffer_Write(*_data);
if(!I2C1_Wait_Ack())
return false;
_data++;
}while(--_len);
//Stop condition
I2C1_Stop();
return true;
}
//----------------------------------------------------
// I2C1 MSSP1 1バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値:受信バイトデータ
//----------------------------------------------------
uint8_t I2C1_b1Read(uint8_t _device_add, uint8_t _data1)
{
uint8_t ret;
//Start Condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
return false;
//send data
I2C1_Tx_Buffer_Write(_data1);
if(!I2C1_Wait_Ack())
return false;
//restart
I2C1_ReStart();
//send device address
I2C1_Tx_Buffer_Write(_device_add|0x01);
if(!I2C1_Wait_Ack())
return false;
//recieve data
ret=I2C1_Rx_Buffer_Read();
//send Nack
I2C1_Send_Ack(I2C1_NoAck);
//Stop Condition
I2C1_Stop();
return ret;
}
//----------------------------------------------------
// I2C1 MSSP1 2バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値:2バイトデータ
//----------------------------------------------------
uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1)
{
uint16_t ret;
//Start Condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
return false;
//send data
I2C1_Tx_Buffer_Write(_data1);
if(!I2C1_Wait_Ack())
return false;
//restart
I2C1_ReStart();
//send device address
I2C1_Tx_Buffer_Write(_device_add|0x01);
if(!I2C1_Wait_Ack())
return false;
//recieve data
ret=I2C1_Rx_Buffer_Read();
ret<<=8;
//send Ack
I2C1_Send_Ack(I2C1_Ack);
//recieve data
ret|=I2C1_Rx_Buffer_Read();
//send Nack
I2C1_Send_Ack(I2C1_NoAck);
//Stop Condition
I2C1_Stop();
return ret;
}
//----------------------------------------------------
// I2C1 MSSP1 nバイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_len:受信長
//戻り値:受信の成否
//----------------------------------------------------
bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len)
{
uint8_t index=0;
//Start Condition
I2C1_Start();
//send device address
I2C1_Tx_Buffer_Write(_device_add);
if(!I2C1_Wait_Ack())
return false;
//send data
I2C1_Tx_Buffer_Write(_data1);
if(!I2C1_Wait_Ack())
return false;
//restart
I2C1_ReStart();
//send device address
I2C1_Tx_Buffer_Write(_device_add|0x01);
if(!I2C1_Wait_Ack())
return false;
//recieve data
do{
I2C1_DataBuffer[index++]=I2C1_Rx_Buffer_Read();
if(_len!=1)
{
I2C1_Send_Ack(I2C1_Ack);
}
_len--;
}while(_len!=0);
//send Nack
I2C1_Send_Ack(I2C1_NoAck);
//Stop Condition
I2C1_Stop();
return true;
}