PIC18F27Q43 外付けEEPROM(I2C)ドライバー

# トマト栽培の育苗で、丸1日分の時刻データ、３か所の地温データ、温度データをEEPROMに記録していました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/Kup7GOSGyww?si=DW1YRVhCxtRTaN7u" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

Q43に新しく追加された機能、Timerを使ったタイムアウト処理で、通信失敗の場合、バスを解放します。
今回はTimer4を割り振っています。

```C:EEPROM24LCxxx.h
/* 
 * File:   24LCxxx.h
 * Created on 2023/01/04, 18:05
 */

#ifndef EEPROM24LCxxx_H
#define	EEPROM24LCxxx_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
    
#define EEPROMdeviceAdd 0xAC
#define EEPROM24LC256 0xAC
    
#define EEPROM_PAGE_SIZE 32 
extern uint8_t eepromPageBuffer[EEPROM_PAGE_SIZE];
extern uint8_t eeprom_b1Write(uint8_t _deviceAdd, uint16_t _address, uint8_t _data);
extern uint8_t eeprom_b1Read(uint8_t _deviceAdd,uint16_t _address);
extern uint8_t eeprom_bnWrite(uint8_t _deviceAdd,uint16_t _address, uint8_t *_dataArray);
extern uint8_t eeprom_bnRead(uint8_t _deviceAdd, uint16_t _address, uint8_t *_dataArray);
#ifdef	__cplusplus
}
#endif

#endif	/* 24LCXXX_H */
```

```C:EEPROM24LCxxx.c
#include "EEPROM_24LCxxx.h"
#include "Q_I2C1.h"

uint8_t eeprom_b1Write(uint8_t _deviceAdd, uint16_t _address, uint8_t _data)
{
    uint8_t _addH, _addL;
    _addH=(uint8_t)(_address>>8);
    _addL=(uint8_t)(_address);
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=3;
    I2C1TXB=_addH;
    I2C1CON0bits.S=1;
    
    while(!I2C1STAT0bits.BFRE)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
     if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1TXB=_addL;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1TXB=_data;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1PIRbits.PC1IF==0)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    I2C1CON0bits.S=0;
    while(I2C1STAT0bits.MMA)
    {
         if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    __delay_ms(10);
    return true;
}

uint8_t eeprom_b1Read(uint8_t _deviceAdd,uint16_t _address)
{
    uint8_t ret;
    uint8_t _addH, _addL;
    _addH=(uint8_t)(_address>>8);
    _addL=(uint8_t)(_address);
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;

    I2C1ADB1 = _deviceAdd;
    I2C1CNT=2;
    I2C1TXB=_addH;
    I2C1CON0bits.S=1;
    while(!I2C1STAT0bits.BFRE)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE0;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE1;
        }
    };
    I2C1TXB=_addL;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE2;
        }
    };
    I2C1PIRbits.PC1IF=0;
    //リスタート
    I2C1CON0bits.RSEN=1;
    while(!I2C1CON0bits.MDR)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE3;
        }
    };
    I2C1CON0bits.S=1;
    I2C1ADB1 = _deviceAdd|0x01;
    I2C1CNT=1;
    while(!I2C1STAT1bits.RXBF)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE4;
        }
    };
    ret=I2C1RXB;
    I2C1CON0bits.RSEN=0;
    I2C1CON0bits.S=0;
    I2C1PIR=0x00;
    while(I2C1STAT0bits.MMA)
    {
        if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return 0xE5;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return ret;
}

uint8_t eepromPageBuffer[EEPROM_PAGE_SIZE];
uint8_t eeprom_bnWrite(uint8_t _deviceAdd, uint16_t _address, uint8_t *_dataArray)
{
    uint8_t cnt;
    uint8_t _addH, _addL;
    _addH=(uint8_t)(_address>>8);
    _addL=(uint8_t)(_address);
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=2+EEPROM_PAGE_SIZE;
    I2C1TXB=_addH;
    I2C1CON0bits.S=1;
    
    while(!I2C1STAT0bits.BFRE)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
     if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1TXB=_addL;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    do{
        I2C1TXB=_dataArray[cnt++];
        while(I2C1STAT1bits.TXBE!=1)
        {
             if(I2C1ERRbits.BTOIF)
            {
                I2C_TimeOUT_OP();
                return false;
            }
        };
    }while(I2C1CNT!=0);
        
    while(I2C1PIRbits.PC1IF==0)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    I2C1CON0bits.S=0;
    while(I2C1STAT0bits.MMA)
    {
         if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return true;
}

 
uint8_t eeprom_bnRead(uint8_t _deviceAdd, uint16_t _address, uint8_t *_dataArray)
{
    uint8_t cnt,ret;
    uint8_t _addH, _addL;
    _addH=(uint8_t)(_address>>8);
    _addL=(uint8_t)(_address);
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;

    I2C1ADB1 = _deviceAdd;
    I2C1CNT=2;
    I2C1TXB=_addH;
    I2C1CON0bits.S=1;
    while(!I2C1STAT0bits.BFRE)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE0;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE1;
        }
    };
    I2C1TXB=_addL;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE2;
        }
    };
    I2C1PIRbits.PC1IF=0;
    //リスタート
    I2C1CON0bits.RSEN=1;
    while(!I2C1CON0bits.MDR)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return 0xE3;
        }
    };
    I2C1CON0bits.S=1;
    I2C1ADB1 = _deviceAdd|0x01;
    I2C1CNT=EEPROM_PAGE_SIZE;//32bytes
    cnt=0;
    do{
        while(!I2C1STAT1bits.RXBF)
        {
            if(I2C1ERRbits.BTOIF)
            {
                I2C_TimeOUT_OP();
                return 0xE4;
            }
        };
        _dataArray[cnt++]=I2C1RXB;
    }while(I2C1CNT!=0);
    I2C1CON0bits.RSEN=0;
    I2C1CON0bits.S=0;
    I2C1PIR=0x00;
    while(I2C1STAT0bits.MMA)
    {
        if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return 0xE5;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return 1;
}

```

```C: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);
extern uint8_t I2C1_b2Read(uint8_t _deviceAdd,uint8_t _address ,uint8_t* buf);
extern void I2C_TimeOUT_OP(void);
#ifdef	__cplusplus
extern "C" {
#endif




#ifdef	__cplusplus
}
#endif

#endif	/* Q_I2C1_H */

```

```C:QI2C1.c
#include <pic18f27q43.h>

#include "Q_I2C1.h"

uint8_t i2c1Cnt;
//*************************************************//
//** I2C1初期化
//*************************************************//
void I2C1_Init(void)
{
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;  
    I2C1CON0bits.MODE=0b100;//master mod, 7bits address
    I2C1CON1bits.ACKCNT=1;
    I2C1CON2bits.ABD=0;//I2C1ADB0/1use
    I2C1CON2bits.BFRET=0b11;//64clocks
    I2C1CLK=0b0011;//MFINTOSC500kHz
    I2C1PIR=0x00;
    //Bus Time out
    I2C1BTO=0b0010;//Timer4
    I2C1ERRbits.BTOIE=1;
    I2C1ERRbits.BTOIF=0;
   
    I2C1CON0bits.EN=1;
}
//*************************************************//
//** I2C1 1バイト送信
//*************************************************//
bool I2C1_b1Write(uint8_t _deviceAdd, uint8_t _data1)
{
    PIR11bits.TMR4IF=0;
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=1;
    I2C1TXB=_data1;
    I2C1CON0bits.S=1;
   
    while(!I2C1STAT0bits.BFRE)
    {
       if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(!I2C1STAT1bits.TXBE)
    {
       if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1PIRbits.PC1IF==0)
    {
       if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    I2C1CON0bits.S=0;
    while(I2C1STAT0bits.MMA)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    TMR4=0;
    return true;
}

//*************************************************//
//** I2C1 2バイト送信
//*************************************************//
uint8_t I2C1_b2Write(uint8_t _deviceAdd, uint8_t _data1, uint8_t _data2)
{
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1CON0bits.EN=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=2;
    I2C1TXB=_data1;
    I2C1CON0bits.S=1;
    
    while(!I2C1STAT0bits.BFRE)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
     if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    //while(!I2C1CON1bits.ACKSTAT);
    I2C1TXB=_data2;
    while(I2C1STAT1bits.TXBE!=1)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1PIRbits.PC1IF==0)
    {
         if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    I2C1CON0bits.S=0;
    while(I2C1STAT0bits.MMA)
    {
         if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return true;
}

//*************************************************//
//** I2C1 1バイト受信
//*************************************************//
uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address)
{
    uint8_t ret;
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=1;
    I2C1TXB=_address;
    I2C1CON0bits.S=1;
    while(!I2C1STAT0bits.BFRE)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    //リスタート
    I2C1CON0bits.RSEN=1;
    while(!I2C1CON0bits.MDR)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1CON0bits.S=1;
    I2C1ADB1 = _deviceAdd|0x01;
    I2C1CNT=1;
    while(!I2C1STAT1bits.RXBF)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    ret=I2C1RXB;
    I2C1CON0bits.RSEN=0;
    I2C1CON0bits.S=0;
    I2C1PIR=0x00;
    while(I2C1STAT0bits.MMA)
    {
        if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return ret;
}

//*************************************************//
//** I2C1 2バイト受信
//*************************************************//
uint8_t I2C1_b2Read(uint8_t _deviceAdd,uint8_t _address ,uint8_t* buf)
{
    uint8_t ret;
    PIE11bits.TMR4IE=1;
    T4CONbits.TMR4ON=1;
    I2C1ADB1 = _deviceAdd;
    I2C1CNT=1;
    I2C1TXB=_address;
    I2C1CON0bits.S=1;
    while(!I2C1STAT0bits.BFRE)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    while(I2C1STAT1bits.TXBE!=1)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1PIRbits.PC1IF=0;
    //リスタート
    I2C1CON0bits.RSEN=1;
    while(!I2C1CON0bits.MDR)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1CON0bits.S=1;
    I2C1ADB1 = _deviceAdd|0x01;
    I2C1CNT=2;
    while(!I2C1STAT1bits.RXBF)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    I2C1CON1bits.ACKDT=0;
    buf[0]=I2C1RXB;
    
    while(!I2C1STAT1bits.RXBF)
    {
        if(I2C1ERRbits.BTOIF)
        {
            I2C_TimeOUT_OP();
            return false;
        }
    };
    //I2C1CON1bits.ACKDT=0;
    //I2C1CON1bits.ACKCNT=0;
    buf[1]=I2C1RXB;
    //I2C1CON1bits.ACKDT=0;
    I2C1CON0bits.RSEN=0;
    I2C1CON0bits.S=0;
    I2C1PIR=0x00;
    while(I2C1STAT0bits.MMA)
    {
        if(I2C1ERRbits.BTOIF)
        {
           I2C_TimeOUT_OP();
            return false;
        }
    };
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    return ret;
}
void I2C_TimeOUT_OP(void)
{
    I2C1ERRbits.BTOIF=0;
    PIE11bits.TMR4IE=0;
    T4CONbits.TMR4ON=0;
    TMR4=0x00;
    I2C1CON0bits.S=0;
    I2C1STAT1bits.CLRBF = 1;
    I2C1CON0bits.EN=0;
}

```