1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PIC18F27Q43 I2C通信 Host(Master) クロック400khzに速度をUP!

Last updated at Posted at 2024-05-03

IMG_4534.JPG

前回、I2C Host 通信について書きました。このときは内蔵オシレータMFINTOSC 500KHzをI2Cクロックソースに選択して、dividerの5で割った、100kHz がI2Cクロックになっていました。 100KHzでは遅いので、I2C標準の400KHzまで、速度を速めることにしました。

I2Cモジュールに入力するクロックソースを作る。

最終的にI2Cクロックスピードを、400kHzにするためには、その5倍の速度、2MHzのクロックソースを作り出す必要があります。

I2Cモジュールは入力されたクロックを4または5で割った周波数を使って運用されています。

18F27Q43には、自由にパルス周波数を調整してペリフェラルにわたせる、ちょうどいいモジュールがあります。

Reference Clock Output Module

datasheetCLKREF1.png

設定はシンプルで、入力クロックソースを指定し、divide値とduty比を決定して、作りたい周波数のパルスをペリフェラルに渡すことができます。

今回は、Fosc=32MHzから2MHzのクロックをI2Cモジュールに渡したいので、divider=16 duty=50% クロックソースをFOSC=32MHzにしました。最後にENビットをONしたら、I2Cモジュールのクロックソースに2MHzのクロックが入力されます。
これで、前回、100kHz どまりだったスピードを400Khzにアップできました。

あとのI2Cモジュールの設定は、前回と同じです。

コード

Q_peripheral.c
//******************************************************//
// * Clock Reference Output 初期化
// *****************************************************//
void CLKREF_Init(void)
{
    CLKRCONbits.DC = 0b10; //duty 50%
    //CLKRCONbits.DIV = 0b110; //divided by 64 I2CCLK:0.5Mhz/5=100kHz
    //CLKRCONbits.DIV = 0b101; //divided by 32 I2CCLK:1Mhz/5=200kHz
    CLKRCONbits.DIV = 0b100; //divided by 16 I2CCLK:2Mhz/5=400kHz
    //CLKRCONbits.DIV = 0b011; //divided by  8 I2CCLK:4Mhz/5=800kHz
    CLKRCLK = 0b00000; //Sorce is Fosc
    CLKRCONbits.EN=1;
    __delay_ms(10);
}
Q_I2C1.h
#ifndef Q_I2C1_H
#define	Q_I2C1_H
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"

extern void I2C1_Init(void);
extern bool I2C1_b1Write(uint8_t _deviceAdd, uint8_t _data1);
extern uint8_t I2C1_b2Write(uint8_t _deviceAdd, uint8_t _data1, uint8_t _data2);
extern uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address);
#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* Q_I2C1_H */
Q_I2C1.c
#include <pic18f27q43.h>

#include "Q_I2C1.h"

uint8_t i2c1Cnt;
//*************************************************//
//** I2C1初期化
//*************************************************//
void I2C1_Init(void)
{
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;//I2Cバッファ、RXBF、TXBEビットクリア
    I2C1CON0bits.MODE=0b100;//Host mode, 7bits address
    I2C1CON1bits.ACKCNT=1;  //最終ACK確認で返す値0:ACK 1:NACK
    I2C1CON2bits.ABD=0;     //I2C1ADB0をアドレスバッファとして使用
    I2C1CON2bits.BFRET=0b00;//8clocksスタートになる準備パルス数
    I2C1CON2bits.FME = 1;   //Fi2cclk/5
  //I2C1CLK=0b0011;         //MFINTOSC500kHz//I2C用クロックソース
    I2C1CLK = 0b00100;      //Clock Reference Output//I2C用クロックソース400KHz
    I2C1PIR=0x00;           //I2C1専用割り込みフラグのクリア
    I2C1CON0bits.EN=1;      //I2C1モジュール有効
}
//*************************************************//
//** I2C1 1バイト送信
//*************************************************//
bool I2C1_b1Write(uint8_t _deviceAdd, uint8_t _data1)
{
    I2C1ADB1 = _deviceAdd;       //アドレスバッファにClientアドレスをセット
    I2C1CNT=1;                   //送信データ数をセット
    I2C1TXB=_data1;              //送信データを1バイトだけ、前もってセット
    I2C1CON0bits.S=1;            //Startコンディション
    while(!I2C1STAT0bits.BFRE);  //I2Cバスが解放されているか?
    while(!I2C1STAT1bits.TXBE);  //送信バッファが空か?(セットしたデータの送信完了)
    while(I2C1PIRbits.PC1IF==0); //Stopコンディションになったか?
    I2C1PIRbits.PC1IF=0;         //Stopフラグクリア
    while(I2C1STAT0bits.MMA);    //Host mode active を見て終了確認 0:not active 1:active
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;     //I2Cバッファ、RXBF,TXBEのクリア
    return true;
}

//*************************************************//
//** I2C1 2バイト送信
//*************************************************//
uint8_t I2C1_b2Write(uint8_t _deviceAdd, uint8_t _data1, uint8_t _data2)
{
    I2C1ADB1 = _deviceAdd;  //Clientデバイスアドレスセット
    I2C1CNT=2;              //送信データ数
    I2C1TXB=_data1;         //送信バッファに最初のデータをセット
    I2C1CON0bits.S=1;       //スタートコンディションセット
    
    while(!I2C1STAT0bits.BFRE)      //I2Cバスが解放されているか?
    {};
    while(I2C1STAT1bits.TXBE!=1)
    {};                             //最初のデータ送信完了?
    //while(!I2C1CON1bits.ACKSTAT);
    I2C1TXB=_data2;                 //次の送信データをセット
    while(I2C1STAT1bits.TXBE!=1);   //送信完了?
    while(I2C1PIRbits.PC1IF==0);    //ストップコンディション確定?
    I2C1PIRbits.PC1IF=0;            //ストップフラグクリア
    while(I2C1STAT0bits.MMA);       //Host mode Active確認 0:not Active 1:active
    //Set Clear Buffer Flag         
    I2C1STAT1bits.CLRBF = 1;        //I2C1バッファ、TXBE,RXBFクリア
    return true;
}

//*************************************************//
//** I2C1 1バイト受信
//*************************************************//
uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address)
{
    uint8_t ret;
    I2C1ADB1 = _deviceAdd;          //Clientアドレスセット
    I2C1CNT=1;                      //送信バイト数(この場合は、引数の_address)
    I2C1TXB=_address;               //送信バイトセット
    I2C1CON0bits.S=1;               //Startコンディションセット
    while(!I2C1STAT0bits.BFRE);     //I2Cバス解放?確認
    while(I2C1STAT1bits.TXBE!=1);   //送信バッファ 0:full 1:empty 送信完了確認
    //リスタート
    I2C1CON0bits.RSEN=1;            //リスタート開始
     while(!I2C1CON0bits.MDR);      //RSENセットで1になる。
    I2C1CON0bits.S=1;               //Startコンディションセット
    I2C1ADB1 = _deviceAdd|0x01;     //Clientアドレス+R/Wビット
    I2C1CNT=1;                      //読み出し数
    while(!I2C1STAT1bits.RXBF);     //読み込み完了待ち?
    ret=I2C1RXB;                    //バッファから読み出し
    I2C1CON0bits.RSEN=0;            //リスタート解除
    I2C1PIR=0x00;                   //PIRクリア
    while(I2C1STAT0bits.MMA);       //HostmodeActime 0:not Active 1:active
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;        //I2C1バッファクリア
    return ret;
}
main.c

/*
 * File:   main.c
 * Author: yutak
 *
 * Created on 2022/12/29, 18:47
 */



// PIC18F27Q43 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // External Oscillator Selection (Oscillator not enabled)
#pragma config RSTOSC = HFINTOSC_64MHZ// Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)

// CONFIG2
#pragma config CLKOUTEN = OFF   // Clock out Enable bit (CLKOUT function is disabled)
#pragma config PR1WAY = OFF     // PRLOCKED One-Way Set Enable bit (PRLOCKED bit can be set and cleared repeatedly)
#pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)

// CONFIG3
#pragma config MCLRE = EXTMCLR  // MCLR Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
#pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
#pragma config MVECEN = ON      // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
#pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit (IVTLOCKED bit can be cleared and set only once)
#pragma config LPBOREN = OFF    // Low Power BOR Enable bit (Low-Power BOR disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)

// CONFIG4
#pragma config BORV = VBOR_1P9  // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 1.9V)
#pragma config ZCD = OFF        // ZCD Disable bit (ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PPS1WAY = OFF     // PPSLOCK bit One-Way Set Enable bit (PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)

// CONFIG5
#pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)

// CONFIG6
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG7
#pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
#pragma config BBEN = OFF       // Boot Block enable bit (Boot block disabled)
#pragma config SAFEN = OFF      // Storage Area Flash enable bit (SAF disabled)
#pragma config DEBUG = OFF      // Background Debugger (Background Debugger disabled)

// CONFIG8
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block not Write protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not Write protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not Write protected)
#pragma config WRTSAF = OFF     // SAF Write protection bit (SAF not Write Protected)
#pragma config WRTAPP = OFF     // Application Block write protection bit (Application Block not write protected)

// CONFIG10
#pragma config CP = OFF         // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
#include "Q_interrupt27Q43.h"
#include "Q_initialize.h"
#include "Q_I2C1.h"
#include "I2C_LCD.h"
#include "stringFormat.h"

void portInit(void);
void oscillatorInit(void);
void vicInit(void);
uint8_t ret[5];
void main(void)
{
    uint8_t val, i;
    //CPUハード初期化-------------------------------
    portInit();         //port初期化
    oscillatorInit();   //オシレータ初期化Fosc=32MHz
    vicInit();          //ベクターテーブル初期化
    
    //周辺機能初期化--------------------------------
    usartInit();
    printf("START I2C\n");
    CLKREF_Init();
    I2C1_Init();
    //MCP23017初期化-------------------------------
    I2C1_b2Write(0x4C,0x0A,0x80);
    I2C1_b2Write(0x4C,0x00,0x00);
    I2C1_b2Write(0x4C,0x09,0x00);
    I2C1_b2Write(0x4C,0x0A,0x00);
    I2C1_b2Write(0x4C,0x10,0x00);
    I2C1_b2Write(0x4C,0x19,0x00);
    I2C1_b2Write(0x4C,0x1A,0x00);
    //MCP23017初期化値シリアル出力------------------
    for(i=0; i<=0x0A; i++)
    {
        val=I2C1_b1Read(0x4C,i);
        printf("[%x]=%x\n",i,val);
    }
     for(i=0x10; i<=0x1A; i++)
    {
        val=I2C1_b1Read(0x4C,i);
        printf("[%x]=%x\n",i,val);
    }
    
    while(1)
    {
        __delay_ms(500);
        I2C1_b1Write(0x4A,0x55);        //PCF8574
        I2C1_b2Write(0x4C,0x0A,0xAA);   //MCP23017 portA
        I2C1_b2Write(0x4C,0x1A,0xAA);   //MCP23017 portB
        
        __delay_ms(500);
        I2C1_b1Write(0x4A,0xAA);        //PCF8574
        I2C1_b2Write(0x4C,0x0A,0x55);   //MCP23017 portA
        I2C1_b2Write(0x4C,0x1A,0x55);   //MCP23017 portB
        
    }
    return;
}

void oscillatorInit(void)
{
    //オシレータ設定----------------
    OSCCON3bits.CSWHOLD=1;//Hold
    OSCCON1bits.NDIV=1;//64Mhz/2=32Mhz;
    while(!OSCCON3bits.NOSCR);
    while(!PIR0bits.CSWIF);//ready state
    PIR0bits.CSWIF=0;
    OSCCON3bits.CSWHOLD=0;
    while(!OSCCON3bits.ORDY);
}

void portInit(void)
{
    //ポート設定----------------------    
    PORTA=0x00;
    LATA=0x00;
    ANSELA=0x00;
    TRISA=0x00;
    
    PORTB=0x00;
    LATB=0x00;
    ANSELB=0x00;
    TRISB=0x00;
    
    PORTC=0x00;
    LATC=0x00;
    ANSELC=0x00;
    TRISC=0x00;
    
     //PPS---------------------
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
    
    //I2C1-------------------------
    //RC4 for SDA
    RC4PPS=0x38;
    I2C1SDAPPS=0x14;
    //RC3 for SCL
    RC3PPS = 0x37;
    I2C1SCLPPS=0x13;
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;
    
    ODCONCbits.ODCC3=1;
    ODCONCbits.ODCC4=1;
    
    RC3I2Cbits.TH=1;
    RC4I2Cbits.TH=1;
    
}

void vicInit(void)
{
 //割り込みテーブルaddress設定----------------------------------
    INTCON0bits.GIE=0;//Enable all masked interrupts
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=0;
    IVTBASE = 0x000008;
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=1;
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?