PIC18F27Q43 SPI通信

# Q43のSPI通信

![IMG_4727.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/c5c5b489-ed9d-b84f-9413-a480e40ad073.jpeg)

::: note
**MSSPからの変更点**
・送信バッファと、受信バッファが用意された。
・送信ビット数、送信バイト数をカウントするレジスタ
・LSBとMSBを逆転できるようなった。
・SPIの４線それぞれに、極性を指定できる。
・ボーレートの計算が楽。
:::

# 1.SPIモジュールの初期化
SPI1モジュールはI2C1モジュールとデフォルトピンが競合しているので、
**SPI2モジュールを使用します。**
## 1.1 SPI2のピン割り付け
|ピン番号|ピン名|機能|SPI端子名|
|:---:|:---:|:---:|:---:|
|23|RB2|SPI2|SDI|
|24|RB3|SPI2|CLK|
|25|RB4|SPI2|SDO|
|26|RB5|SPI2|/CS|

:::note
※PPS機能を使えば、主にPORTB、PORTCに割り付けることができます。

※CSピンだけは、モジュールで駆動しないで、ユーザーがポート端子を操作するようにしました。SPIモジュールで自動制御もできまが、SPIモジュールが複数あった場合は、汎用のIOピン制御になります。

※CSピンをハードウェアで制御するばあいは、ポートA、ポートCに割り付けることができます。
:::

```C:PPSでSPI端子を割り付け。
//SPI2 pin setting-------------------
    TRISB|=0x04;    //RB2:SDI　input
    //PPS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;//Unlock.
    SPI2SDIPPS=0x0A;//RB2;
    RB3PPS=0x34;    //SPI2 CLK
    RB4PPS=0x35;    //SPI2 SDO
    //RB5PPS=0x36;  //SPI2 SS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;//lock.
```
```C:CS端子だけは、ユーザー制御
    #define SPI2_CS PORTBbits.RB5    
```

## 1.2　SPI２モジュールの初期化
まず、SPIクロックの極性と、サンプリング位置を設定します。![SMP_CKE_CKP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/e50764bc-281c-d3b0-73d4-9e6e98a19705.png)
![samplint_edge_diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f050410a-9752-e61b-b19e-82f7e86a0230.png)
Clientデバイスの規定にあわせて、SPIクロック波形をこの３ビットで決定します。今回は、MCP23S17に合わせて設定しました。
同じレジスタで、チップセレクトピンの極性を設定しておきます。SSPビットをセットします。これで、ハードウェアでCSピンを制御する場合、CSピンが自動で、Active low出力されます。
```C:クロック波形の指定と、CSピンの出力極性の設定
SPI2CON1=0x44;  //SMP:0,CKE:1,CKP:0,SSP:1 active low
```
## 1.3　SPIモジュール　ホストモード
HOSTモードは４種類。全二重、受信のみ、送信のみ、NoTransfers。
![mode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/fd077110-be09-4c56-e995-269a209e3c47.png)
送信、受信ともに同時に行いたいので、**Full Duplex mode**を選択します。TRXビット、RXTビットをセットします。
```C:SPI HOSTモード設定(FullDuplex) 
SPI2CON2=0x03;  //TXR=1 RXR=1; Full Duplex mode
```
## 1.3 SPIクロックソース
SPIのクロックソースを選びます。
![SPICLK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/42031e4f-578e-b27a-4bf8-7b57cd2ca45f.png)
MSSPモジュールよりも高速に設定できようになりました。
![SCKbaudrate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/e5f7523d-2f4b-4e21-19f0-8c2f07deab93.png)
システムクロックFoscは、32Mhzです。
クロックソースをFoscシステムクロック(32Mhz)に設定します。この入力クロックを上記式を用いて、減速して8Mhzに設定しました。
```C:SPIクロックソースの指定、速度設定
    SPI2CLK=0b00000;//Fosc=32Mhz
    SPI2BAUD=0x1;   //8Mhz n=1 32Mhz/(2*(1+1))
```
## 1.4　ビットカウントの仕方を設定
送信、受信カウンタを設定します。ビット単位または、バイト単位でカウントするかを決定します。
SPICON0レジスタのBMODEビットで選択します。
![BMODE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f6ff5827-e929-dd57-d74b-5cf750d8379e.png)
今回は、BMODE＝１とし、８ビット単位でカウントするように設定しました。8ビット長の指定は、後述のSPIxTWIDEで設定します。
```C:BMODE設定
 SPI2CON0=0x03;  //MST:1 BMODE:1
```
同じレジスタの、MSTビットもセットしておきます。SPIバスをHostとして使用するか、Clientとして使用するかを決定するビットです。Hostとしてバスを使用するので１をセットしています。
## 1.5　データの大きさをビットで指定。
**BMODE=1の場合、** SPI2TWIDTHレジスタに、１データのビット長をセットしておきます。送信データ長を３ビットで指定します。ということは、通常は８ビットで構成されているデータを3ビットや、5ビットにして送信することもできるはずです。![SPIxTWIDE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/eaee8393-dfda-7df6-bf78-5b0fa6f40a05.png)

今回は、データは通常どうりの、８ビットで構成されているので、８をセットします。
```C:1データのビット数(大きさ）
SPI2TWIDTH=8;   //１データビット数(8bitデータ)
```

SPI2CNTレジスタは、BMODE＝１の場合、送受信のデータ数をその都度、プログラムの中でセットします。![SPIxTCNT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/cb01164a-1be5-5282-fca7-62372066f7ba.png)


## 1.6　SPI2モジュールの有効化
最後にSPI2モジュールを有効にします。EN＝１の時は、設定が有効になりませんので、EN＝０で設定して、EN＝１で、モジュールの設定を確定させます。
```C:SPIモジュールの有効化
  SPI2CON0bits.EN=1;
```

# 2.Q43 SPIコード
:::note
・CSピンだけは、ソフトウェアで制御しています。

・通信の開始は、BusyフラグでモジュールがIdle状態か、確認したのちに、CSピンをLOWにして、通信を開始しています。通信の終了もCSピンで制御して、Highにして終了です。

・送信バッファに１バイトデータを書きこむと、ハードが８クロック出力し、受信バッファに８ビットデータが格納されます。

・読込だけ行うときは、ダミーデータ(0xFF)をクライアントに送信して、受信バッファから、データを読み出します。
:::

```C:Q_SPI.h
#ifndef Q_SPI2_H
#define	Q_SPI2_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 SPI2_CS PORTBbits.RB5    
    
typedef struct{
    uint8_t val;
    bool errorCode;
}SPI_RD;


extern void SPI2_Init(void);
extern void SPI2_START(void);
extern void SPI2_STOP(void);
extern SPI_RD SPI2_b3Write(uint8_t _val, int8_t _data1, int8_t _data2);
extern SPI_RD SPI2_bnWrite(uint8_t _num, uint8_t* _data);
extern SPI_RD SPI2_b1Read(uint8_t _val, uint8_t _data1);
extern SPI_RD SPI2_b1Write(uint8_t _val);
extern void  SPI2_SetTotalCount(uint16_t _val);
extern uint16_t SPI2_GetTotalCount(void);
extern SPI_RD SPI2_Write(uint8_t _val);
    
#ifdef	__cplusplus
}
#endif

#endif	/* Q_SPI2_H */
```
```C:Q_SPI.c
#include "Q_SPI2.h"


//****************************************//
//* SPI2_Init       　                    *//
//SPI2モジュール初期化
//****************************************//
void SPI2_Init(void)
{
    //SPI2 pin setting-------------------
    TRISB|=0x04;    //RB2:SDI　input
    //PPS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;//Unlock.
    SPI2SDIPPS=0x0A;    //RB2;
    RB3PPS=0x34;        //SPI2 CLK
    RB4PPS=0x35;        //SPI2 SDO
    //RB5PPS=0x36;      //SPI2 SS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;//lock.
    
    //SPI2 Configration----------------
    SPI2CON1=0x44;  //CKE:1, SSP:1 active low
    SPI2CON2=0x03;  //TXR=1 RXR=1; Full Duplex mode
    SPI2CLK=0b00000;//Fosc=32Mhz
    SPI2BAUD=0x1;   //8Mhz n=1 32Mhz/(2*(1+1))
    SPI2CON0=0x03;  //MST:1 BMODE:1
    SPI2TWIDTH=8;   //１データビット数
    SPI2CON0bits.EN=1;
    SPI2_CS=1;
}

//****************************************//
//* SPI2_START                           *//
//****************************************//
void SPI2_START(void)
{
    uint8_t timeUp=0;
    while(SPI2CON2bits.BUSY)
    {
        timeUp++;
        if(timeUp>200)
        {
            return;
        }
    };
    SPI2_CS=0;
}
//****************************************//
//* SPI2_STOP                            *//
//****************************************//
void SPI2_STOP(void)
{
    SPI2_CS=1;
}
//****************************************//
//* SPI2_SetTotalCount                   *//
//_val:ビット数またはバイト数(BMODEによる)
//****************************************//
#define BMODE 1
void SPI2_SetTotalCount(uint16_t _val)
{
#if BMODE
    SPI2TCNT=_val;//バイト数
#else
    SPI2TWIDTH = (uint8_t)(_val&0x0007);
    SPI2TCNT=_val>>3;
#endif    
}
//****************************************//
//* SPI2_SetTotalCount                   *//
//return: SPI2CNT値　または、SPI2CNT&SPI2WIDHT値
//****************************************//
uint16_t SPI2_GetTotalCount(void)
{
    uint16_t ret;
#if BMODE
    ret=SPI2TCNT;
    printf("byteNum=%d\n",ret);
#else    
    ret = SPI2TCNT;
    ret = ret<<3 | SPI2TWIDTH;
    printf("bitNum=%d\n",ret);
#endif    
    return ret;
}
//****************************************//
//* SPI2_Write                           *//
//_val:送信データ
//****************************************//
SPI_RD SPI2_Write(uint8_t _val)
{
    SPI_RD spiRD;
    uint8_t val,timeUp;
    
    spiRD.errorCode=false;
    SPI2TXB=_val;
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    spiRD.val=SPI2RXB;
    spiRD.errorCode=true;
    return spiRD;
}
//****************************************//
//* SPI2_bnWrite                           *//
//nバイト送信関数
//_num:送信数（バイト数）
//_data:送信バッファ先頭ｱﾄﾞﾚｽ
//****************************************//
SPI_RD SPI2_bnWrite(uint8_t _num, uint8_t* _data)
{
    uint8_t val,timeUp;
    SPI_RD spiRD;
    
    SPI2_START();
    SPI2_SetTotalCount(_num);//bit Counter set
    do{
        SPI2TXB=*_data++;
        timeUp=0;
        while(PIR5bits.SPI2RXIF == 0)
        {
            timeUp++;
            if(timeUp>200)
            {
                return spiRD;
            }
        };
        val=SPI2RXB;
    }while(--_num);
    
    SPI2_STOP();
    spiRD.val=val;
    spiRD.errorCode=true;
    return spiRD;
}
//****************************************//
//* SPI2_b1Write                          *//
//1バイト送信関数
//_val:送信データ
//return:自作Spiデータ構造体
//****************************************//
SPI_RD SPI2_b1Write(uint8_t _val)
{
    SPI_RD spiRD;
    uint8_t val,timeUp;
    
    spiRD.errorCode=false;
    
    SPI2_SetTotalCount(1);//送信バイト数セット
    SPI2_START();       //CS High=>Low
    SPI2TXB=_val;       //送信データセット
    
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)//送信完了待ちを受信フラグで確認
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    val=SPI2RXB;    //バイト読み出し
    SPI2_STOP();    //CS Low=>High
    spiRD.val=SPI2RXB;//結果を構造体に格納。
    spiRD.errorCode=true;
    return spiRD;
}

//****************************************//
//* SPI2_b3Write                           *//
//３バイト送信関数
//_val:送信データ
//_data1:送信データ
//_data2:送信データ
//****************************************//
SPI_RD SPI2_b3Write(uint8_t _val, int8_t _data1, int8_t _data2)
{
    SPI_RD spiRD;
    uint8_t val,timeUp;
    uint8_t bitNum;
    
    spiRD.errorCode=false;
    
    SPI2_SetTotalCount(3);
    SPI2_START();
    SPI2_GetTotalCount();
    SPI2TXB=_val;
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    SPI2_GetTotalCount();
    val=SPI2RXB;
    SPI2TXB=_data1;
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0){
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    SPI2_GetTotalCount();
    val=SPI2RXB;
    SPI2TXB=_data2;
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0){
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    val=SPI2RXB;
    SPI2_STOP();
    spiRD.val=SPI2RXB;
    spiRD.errorCode=true;
    SPI2_GetTotalCount();
    return spiRD;
}



//****************************************//
//* SPI2_b1Read                          *//
//１バイト受信関数（２バイト送信後）
//_val:送信データ
//_data:送信データ
//return:SPI_RD構造体(受信データ)
//****************************************//
SPI_RD SPI2_b1Read(uint8_t _val, uint8_t _data1)
{
    SPI_RD spiRD;
    uint8_t val,timeUp;
    
    SPI2_SetTotalCount(3);
    SPI2_START();
    //1.SPIｱﾄﾞﾚｽ送信
    SPI2TXB=_val;
    timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    val=SPI2RXB;
    //2.レジスタｱﾄﾞﾚｽ送信
    SPI2TXB=_data1;
     timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    val=SPI2RXB;
    //3.レジスタ値受信
    SPI2TXB=0xFF;//dummy tx data
     timeUp=0;
    while(PIR5bits.SPI2RXIF == 0)
    {
        timeUp++;
        if(timeUp>200)
        {
            return spiRD;
        }
    };
    val=SPI2RXB;
    SPI2_STOP();
    spiRD.val=val;
    spiRD.errorCode=true;
    return spiRD;
}



```
```MCP23Sxx.h
#ifndef MCP23S17_H
#define	MCP23S17_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"
#include "Q_SPI2.h"

#define MCP23S17_deviceAdd1 0x4E
#define MCP23S17_deviceAdd2 0x46

/*-----------------------------------*/
//MCP23S08 I/O expander
/*-----------------------------------*/
#define MCP23S08_Device1Add 0x40
#define MCP23S08_Device2Add 0x42    
#define MCP23S_R 1
#define MCP23S_W 0

typedef enum 
{
    IODIR=0x00,
    IPOL,
    GPINTEN,
    DEFVAL,
    INTCN,
    IOCON,
    GPPU,
    mINTF,
    INTCAP,
    GPIO,
    OLAT=0x0A
}_reg;

extern unsigned char  reg_value[10];
extern uint8_t MCP23S_buf[30];
extern SPI_RD MCP23S08_Init(uint8_t _device_add);

/*-----------------------------------*/
//MCP23S17 I/O expander
/*-----------------------------------*/
#define MCP23S17_Device1Add 0x4E
extern SPI_RD MCP23S17_Init(uint8_t _device_add);


#ifdef	__cplusplus
}
#endif

#endif	/* MCP23S17_H */
```
```MCP23Sxx.c
#include "MCP23Sxx.h"

/*-----------------------------------*/
//MCP23S08 I/O expander
//_device_add:デバイスｱﾄﾞﾚｽ
//return:SPI_RD構造体
/*-----------------------------------*/
SPI_RD MCP23S08_Init(uint8_t _device_add)
{
    SPI_RD spiRD;
    uint8_t i;
    for(i=0x00; i<0x0A; i++)
    {
        SPI2_b3Write(MCP23S08_Device1Add,i,0x00);
    }
    
    SPI2_b3Write(MCP23S08_Device1Add,IODIR,0x00);
    SPI2_b3Write(MCP23S08_Device1Add,IOCON,0x38);
    SPI2_b3Write(MCP23S08_Device2Add,IODIR,0x00);
    SPI2_b3Write(MCP23S08_Device2Add,IOCON,0x38);
    spiRD.errorCode=true;
    
    for(i=0x00; i<=0x0A; i++)
    {
        spiRD=SPI2_b1Read(MCP23S08_Device1Add|0x01,i);
        printf("[%02x]=%02x\n",i,spiRD.val);
    }
    putch('\n');
     for(i=0x00; i<=0x0A; i++)
    {
        spiRD=SPI2_b1Read(MCP23S08_Device2Add|0x01,i);
        printf("[%02x]=%02x\n",i,spiRD.val);
    }
    
    return spiRD;
}

/*-----------------------------------*/
//MCP23S17 I/O expander
/*-----------------------------------*/
SPI_RD MCP23S17_Init(uint8_t _device_add)
{
    SPI_RD spiRD;
    uint8_t i;
    
    //Bank切り替え
    SPI2_b3Write(MCP23S17_Device1Add,0x0A,0xA8);
    __delay_ms(10);
    //Bank=1
    SPI2_b3Write(MCP23S17_Device1Add,0x00,0x00);    //PORTA IO direction
    SPI2_b3Write(MCP23S17_Device1Add,0x10,0x00);    //PORTB IO direction
    SPI2_b3Write(MCP23S17_Device1Add,0x09,0x00);    //GPIOA 
    SPI2_b3Write(MCP23S17_Device1Add,0x19,0x00);    //GPIOB
    spiRD.errorCode=true;
    //設定確認のレジスタ読み出し
    printf("MCP23S17 init\n");
    for(i=0x00; i<=0x0A; i++)
    {
        spiRD=SPI2_b1Read(MCP23S17_Device1Add|0x01,i);
        printf("[%02x]=%02x\n",i,spiRD.val);
    }
    for(i=0x10; i<=0x1A; i++)
    {
        spiRD=SPI2_b1Read(MCP23S17_Device1Add|0x01,i);
        printf("[%02x]=%02x\n",i,spiRD.val);
    }
    putch('\n');
    
    return spiRD;
}

```
```C: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"
#include "Q_SPI2.h"
#include "MCP23Sxx.h"

void portInit(void);
void oscillatorInit(void);
void vicInit(void);

void main(void)
{
    uint8_t counter=0;
    uint16_t ledVal;
    //CPUハード初期化-----------------------
    portInit();
    oscillatorInit();
    vicInit();
    
    //周辺機能初期化--------------------------------
    timer0Init();
    iocInit();
    usartInit();
    adcInit();
    SPI2_Init();
    MCP23S17_Init(0x4E);
    printf("START\n");    
    
    
    INTCON0bits.GIE=1;//Enable all masked interrupts
    
    while(1)
    {
        //Timer0 interrupt process-------
        if(tm0.fg)
        {
            tm0.fg=false;
            //Interrupt ADCC process----------
            if(adcInfo.completed)
            {
                adcInfo.completed=false;
                printf("ANA2:%02X %4d\n",adcInfo.val[0],adcInfo.val[0]);
                //LED点灯
                ledVal = adcInfo.val[0];
                SPI2_b3Write(MCP23S17_Device1Add,0x0A,(uint8_t)ledVal);
                ledVal >>=8; 
                SPI2_b3Write(MCP23S17_Device1Add,0x1A,(uint8_t)ledVal);
                //ADCC復帰処理
                PIE1bits.ADIE=1;
                PIE3bits.TMR2IE=1;
                T2CONbits.TMR2ON=1;
            }
            T0CON0bits.EN=1;
            PIE3bits.TMR0IE=1;
        } 
        
        //Usart interrupt process--------
        if(rxUsart.completed)
        {
            rxUsart.completed=false;
            printf("echo:%s\n",rxUsart.buf);
            rxUsart.length=0;
            PIE4bits.U1RXIE=1;
        }
        
        //Interrupt On Change process--------
        if(ioc.fg)
        {
            ioc.fg=false;
            printf("Switch ON:%d\n",counter);
            PORTBbits.RB1=~PORTBbits.RB1;
            counter++;
            PIE0bits.IOCIE=1;
        }
        
        
        
    }
    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;
}
```