PIC32MX370F512F 64pin (４) SPI通信

# PIC32MX370F512T SPI通信

![IMG_5023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/02cc32d6-2ccd-153f-5277-488a217049b7.jpeg)

## **MCP23S17　SPI16bits IOエキスパンダーとSPI通信させます。**

:::note 
# PIC32MXのSPI2モジュールで駆動。
SPI2 SCK: 4番ピン　RG6(固定)
SPI2 SDI:51番ピン  RD3(PPS割り付け）
SPI2 SDO:45番ピン　RD11(PPS割り付け)
SPI2　CS:11番ピン  RB5(define定義）

![pin割り付け表.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f65e25f0-8b95-86c3-d8d8-5215d2559609.png)
:::

:::note
# SPIのボーレート設定レジスタの値
![SPI速度計算.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/61c15327-7fcb-4666-70da-2dd04cdc914d.png)

Section 23. Serial Peripheral Interface (SPI) DS61106G-page 23-29
![PIC32MX_SPIデータシートBRG計算.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/754dc890-db0c-66d5-1e16-571e0424ac11.png)

![BRG値表計算.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/1dbe5bc7-17e3-d9d2-3810-d79cfd5d162b.png)



BRGレジスタの値を１にしました。よって速度は、Fpb=80Mhzなので、Fsck=20Mhzで通信します。
```C:BRG設定
SPI2BRG=1;//Fsck=20Mhz Fpb=80Mhz
```
:::

# SPI2 コード
```C:PIC32_SPI2.h

#ifndef DSSSP2_H
#define	DSSSP2_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <cp0defs.h> 
#include <sys/attribs.h>
#include <stdio.h>
#include <stdbool.h>
#include "peripheral.h"    
    
#define Low 0
#define High 1    
    
#define SPI2_CS LATBbits.LATB5
    
typedef struct{
    uint8_t val;
    bool error;
}_SPI_RD;   

extern _SPI_RD SPI_RD;    
extern void Spi2Init(void);
extern void SPI2_Start(void);
extern uint8_t SPI2_Write(unsigned char _data);
extern bool SPI2_Write3byte(unsigned char _data0,unsigned char _data1,unsigned char _data2);

extern _SPI_RD SPI2_Read(void);
extern void SPI2_Stop(void);


/*-----------------------------------*/
//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 bool MCP23S_Init(uint8_t _device_add);
extern bool MCP23S_SendOPcode(uint8_t _device_add, uint8_t _reg_add, uint8_t RW);
extern bool MCP23S_WriteReg(uint8_t _device_add,uint8_t _reg_add, uint8_t _data);
extern bool MCP23S_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2);
extern uint8_t MCP23S_b1ReadReg(uint8_t _device_add, uint8_t _reg_add);
#ifdef	__cplusplus
}
#endif

#endif	/* SSP1_H */


```

```C:PIC32_SPI2.c
#include "PIC32_SPI2.h"


_SPI_RD SPI_RD;
//3pin mode
void Spi2Init(void)
{
    //1.using Interrupt
    IFS1bits.SPI2EIF=0;
    IEC1bits.SPI2EIE=0;
    //2.Master Mode
    SPI2CONbits.DISSDI=0;
    SPI2CONbits.DISSDO=0;
    SPI2CONbits.MODE16=0;
    SPI2CONbits.SMP=1;
    SPI2CONbits.CKE=1;
    SPI2CONbits.CKP=0;
    SPI2CONbits.MSTEN=1;//master mode
    //3.SPI baudrate 
    //SPI2BRG=255;
    SPI2BRG=1;//20Mhz Fpb=80Mhz
    SPI2STATbits.SPIROV=0;
    SPI2CON2=0x0000;
    SPI2CONbits.ENHBUF=0;//FIFObusser no use:0    
    //5.Port pin 
    
    //SDO2 RD11
    RPD11Rbits.RPD11R = 0b0110;
    //SDI2 RD3
    SDI2R = 0b0000;//RPD3
    
    TRISD|=0x0008; //RD3
    //4.SPI enable
    SPI2CONbits.ON=1;//1:Enable SPI
}

void SPI2_Start(void)
{
    SPI2_CS=Low;
}

uint8_t SPI2_Write(unsigned char _data)
{
   int  i;
    unsigned char buf;
    i=0;
    buf=SPI2BUF;
    for(i=0x7FFF; i; i--)
    {
        if(!SPI2STATbits.SPITBF)
        {
            break;
        }
    }
    SPI2BUF=_data;
    for(i=0x7FFF; i; i--)
    {
        if(!SPI2STATbits.SPITBF)
        {
            break;
        }
    }
    for(i=0x7FFF; i; i--)
    {
        if(!SPI2STATbits.SPIBUSY)
        {
            return true;
        }
    }
    return false;
}

bool SPI2_Write3byte(unsigned char _data0,unsigned char _data1,unsigned char _data2)
{
   int  i,j;
    unsigned char buf;
    for(j=0; j<3; j++)
    {
        buf=SPI2BUF;
        for(i=0x7FFF; i; i--)
        {
            if(!SPI2STATbits.SPITBF)
            {
                break;
            }
        }
        if(j==0)
            SPI2BUF=_data0;
        if(j==1)
            SPI2BUF=_data1;
        if(j==2)
            SPI2BUF=_data2;
        for(i=0x7FFF; i; i--)
        {
            if(!SPI2STATbits.SPITBF)
            {
                break;
            }
        }
        for(i=0x7FFF; i; i--)
        {
            if(IFS1bits.SPI1EIF)
            {
                IFS1bits.SPI1EIF=0;
                break;
            }
        }
    }
    return true;
}



_SPI_RD SPI2_Read(void)
{
    signed int i;
    
    SPI_RD.error=true;
    SPI_RD.val=0xFC;
    for(i=0x7FFF; i; i--)
    {
        if(SPI2STATbits.SPIRBF)
        {
            SPI_RD.val=SPI2BUF;
            SPI_RD.error=false;
            break;
        }
    }    
    return SPI_RD;
}

void SPI2_Stop(void)
{
    unsigned char buf;
    buf=SPI2BUF;
    SPI2_CS=High;
    __delay_us(10);
}


/*-----------------------------------*/
//MCP23S08 I/O expander
/*-----------------------------------*/
_reg MCP23S08reg;
unsigned char  reg_value[10]={0x00,0x00,0x00,0x00,0x18,
0xFF,0x00,0x00,0x00,0x00};
_SPI_RD SPI_RD;

bool MCP23S_Init(uint8_t _device_add)
{
    bool ret;
    ret=MCP23S_WriteReg(_device_add,IODIR,0x00);
    if(!ret) return 0xB1;
    __delay_ms(1);
    ret=MCP23S_WriteReg(_device_add,IOCON,0x38);
    if(!ret) return 0xB2;
    return true;
}


bool MCP23S_SendOPcode(uint8_t _device_add, uint8_t _reg_add, uint8_t RW)
{
    bool ret=false;
   
    ret=SPI2_Write(_device_add|RW);
    if(!ret)
    {
        return false;
    }
    ret=SPI2_Write(_reg_add);
    if(!ret)
    {
        return false;
    }
    return ret;
}

bool MCP23S_WriteReg(uint8_t _device_add,uint8_t _reg_add, uint8_t _data)
{
    bool ret=false;
    SPI2_Start();
    ret=MCP23S_SendOPcode(_device_add, _reg_add, MCP23S_W);
    if(ret!=true)
        return 0xF1;
    ret=SPI2_Write(_data);
    if(ret!=true)
        return 0xF2;
    SPI2_Stop();
    return ret;
}        

bool MCP23S_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2)
{
    bool ret=false;
    SPI2_Start();
    ret=SPI2_Write(_device_add|MCP23S_W);
    if(ret!=true)
        return 0xF1;
    ret=SPI2_Write(_data1);
    if(ret!=true)
        return 0xF2;
    ret=SPI2_Write(_data2);
    if(ret!=true)
        return 0xF3;
    SPI2_Stop();
    return ret;
}

uint8_t MCP23S_b1ReadReg(uint8_t _device_add, uint8_t _reg_add)
{
    bool ret;
    _SPI_RD rdRet;
    SPI2_Start();
    
    ret=SPI2_Write(_device_add|MCP23S_R);
    if(!ret)
    {
        return false;
    }
    ret=SPI2_Write(_reg_add);
    if(!ret)
    {
        return false;
    }
    SPI2_Write(0xFF);
    rdRet=SPI2_Read();
    
    SPI2_Stop();
    
     
    if(rdRet.error)
    {
        return rdRet.val=0xFE;
    }
    return rdRet.val;
}
```

```C:ds_MCP23S17.h
#ifndef DS_MCP23S17_H
#define	DS_MCP23S17_H

#include <xc.h> 
#include "PIC32_SPI2.h"

#define MCP23S17_deviceAdd1 0x4E
#define MCP23S17_deviceAdd2 0x46

extern void MCP23S17Init(uint8_t _deviceAdd);
extern void MCP23Sdebug(uint8_t _deviceAdd);

#ifdef	__cplusplus
extern "C" {
#endif /* __cplusplus */

#ifdef	__cplusplus
}
#endif /* __cplusplus */

#endif	/* DS_MCP23S17_H */

```

```C:ds_MCP23S17.c


#include "PIC32_SPI2.h"

void MCP23S17Init(uint8_t _deviceAdd)
{
    uint8_t ret,regVal[6];
    ret=MCP23S_WriteReg(_deviceAdd, 0x0A, 0xA8);
    regVal[0]=MCP23S_b1ReadReg(_deviceAdd,0x05);
    //printf("0x05=%02x ",regVal);
    regVal[1]=MCP23S_b1ReadReg(_deviceAdd,0x15);
   // printf("0x0A=%02x ",regVal);
    __delay_ms(1);
    ret=MCP23S_b2Write(_deviceAdd,0x00,0x00);//IOCON.bank=1 HAEN=1
    ret=MCP23S_b2Write(_deviceAdd,0x0A,0x00);
    ret=MCP23S_b2Write(_deviceAdd,0x10,0x00);
    ret=MCP23S_b2Write(_deviceAdd,0x1A,0x00);
    
    regVal[0]=MCP23S_b1ReadReg(_deviceAdd,0x00);
    regVal[1]=MCP23S_b1ReadReg(_deviceAdd,0x0A);
    regVal[2]=MCP23S_b1ReadReg(_deviceAdd,0x10);
    regVal[3]=MCP23S_b1ReadReg(_deviceAdd,0x1A);
    regVal[4]=MCP23S_b1ReadReg(_deviceAdd,0x05);
}

void MCP23Sdebug(uint8_t _deviceAdd)
{
    while(1)
    {
        MCP23S_b2Write(_deviceAdd,0x0A,0x55);
        MCP23S_b2Write(_deviceAdd,0x0A,0x55);
        MCP23S_b2Write(_deviceAdd,0x1A,0x55);
        MCP23S_b2Write(_deviceAdd,0x1A,0x55);
        __delay_ms(500);
        MCP23S_b2Write(_deviceAdd,0x0A,0xAA);
        MCP23S_b2Write(_deviceAdd,0x0A,0xAA);
        MCP23S_b2Write(_deviceAdd,0x1A,0xAA);
        MCP23S_b2Write(_deviceAdd,0x1A,0xAA);
        __delay_ms(500);
    }
}

 
```

main関数内の、Timer1割り込み処理(フラグ処理)で、IOエキスパンダーのLEDを点滅させています。
```C:main.c


// PIC32MX370F512H Configuration Bit Settings

// 'C' source line config statements

// DEVCFG3
#pragma config USERID = 0xFFFF          // Enter Hexadecimal value (Enter Hexadecimal value)
#pragma config FSRSSEL = PRIORITY_7     // Shadow Register Set Priority Select (SRS Priority 7)
#pragma config PMDL1WAY = OFF           // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
#pragma config IOL1WAY = OFF            // Peripheral Pin Select Configuration (Allow multiple reconfigurations)

// DEVCFG2
#pragma config FPLLIDIV = DIV_2         // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_20         // PLL Multiplier (20x Multiplier)
#pragma config FPLLODIV = DIV_2         // System PLL Output Clock Divider (PLL Divide by 1)

// DEVCFG1
#pragma config FNOSC = FRCPLL           // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF            // Secondary Oscillator Enable (Disabled)
#pragma config IESO = OFF               // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSECMD           // Clock Switching and Monitor Selection (Clock Switch Enable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
#pragma config FWDTWINSZ = WINSZ_25     // Watchdog Timer Window Size (Window Size is 25%)

// DEVCFG0
#pragma config DEBUG = OFF              // Background Debugger Enable (Debugger is Disabled)
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (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 <cp0defs.h> 
#include <sys/attribs.h>
#include "peripheral.h"
#include "PIC32_I2C1driver.h"
#include "I2C_LCD.h"
#include "PIC32_SPI2.h"
#include "ds_MCP23S17.h"

void portInit(void)
{
    TRISB=0x0000;
    TRISC=0x0000;
    TRISD=0x0000;
    TRISE=0x0000;
    TRISF=0x0000;
    TRISG=0x0000;
    
    ANSELB=0x0000;
    ANSELC=0x0000;
    ANSELD=0x0000;
    ANSELE=0x0000;
    ANSELF=0x0000;
    ANSELG=0x0000;
    
    PORTB=0x0000;
    PORTC=0x0000;
    PORTD=0x0000;
    PORTE=0x0000;
    PORTF=0x0000;
    PORTG=0x0000;
}

void main(void) 
{
    uint8_t val,length;
    uint8_t txt[10];
    unsigned int counter=0x0000;
    uint32_t address;
    unsigned int tmp_CP0_Status; // Temporary register for CP0 reg storing 
    
    //oscillator init---------------------------------
    SYSKEY = 0x0;           // ensure OSCCON is locked
    SYSKEY = 0xAA996655;    // Write Key1 to SYSKEY
    SYSKEY = 0x556699AA;    // Write Key2 to SYSKEY
    //PLL Output Divisor bits
    OSCCONbits.PLLODIV=0b000;   //000 = PLL output divided by 1
    //PeripheralBusClock diviser.
    OSCCONbits.PBDIV=0b00;  //SYSCLK divided by1
    SYSKEY = 0x0;           // ensure OSCCON is locked
    
    //port init---------------------------------------
    portInit();
    
    //peripheral initializing-------------------------
    timer1Init();
    I2C1_Init();
    LCD_Init(LcdDeviceAdd);
    I2C1BRG=0x003D;//600khz Fp=80Mhz
    LCD_Printf(LcdDeviceAdd,"PIC32MX",7,0x80);
    usartInit();
    __delay_ms(10);//これを入れないとazが出力されない。
    putchar('a');putchar('z');
    
    Spi2Init();
    MCP23S17Init(MCP23S17_deviceAdd1);
    //MCP23Sdebug(MCP23S17_deviceAdd1);
    //interrupt initializing-------------------------
    printf("\nPIC32MX370F512HT\n");
    
    //割り込み関連
    address=_CP0_GET_EBASE();//例外ベクタアドレス
    printf("EBASE=%lx\n",address);
    INTCONbits.MVEC=1;
    tmp_CP0_Status=_CP0_GET_STATUS();
    tmp_CP0_Status|=0x00000001;//CP0.STATUS.IE=1で割り込み許可
    _CP0_SET_STATUS(tmp_CP0_Status);
    // __builtin_enable_interrupts();
   
  
    while(1)
    {
        if(rxU1.completed)
        {
            rxU1.completed=false;
            printf("%s\r",rxU1.buf);            
            rxU1.length=0;
            IEC1bits.U1RXIE=1;
        }
        
        if(tm1.fg)
        {
            tm1.fg=false;
            
            LATBbits.LATB0=~LATBbits.LATB0;
            I2C1_b1Write(0x4A,val);
            
            MCP23S_b2Write(MCP23S17_deviceAdd1,0x0A,val);
            MCP23S_b2Write(MCP23S17_deviceAdd1,0x0A,val);
            MCP23S_b2Write(MCP23S17_deviceAdd1,0x1A,val);
            MCP23S_b2Write(MCP23S17_deviceAdd1,0x1A,val);
            
            if(val==0x55)
                val=0xAA;
            else
                val=0x55;
            length=sprintf(txt,"%8ld",counter++);
            LCD_Printf(LcdDeviceAdd,txt,length,0xC0);
            
            
            IEC0bits.T1IE=1;
        }
    }
    
    
    return;
}

```