PIC32MX370F512F 64pin (２) オシレータ設定、割り込み、シリアル通信

記事内容は、後日も随時更新していきます。

:::note
**24/10/22　シリアル通信の受信コードのバグ改良。URXDAビットのチェックを追加。**
**24/11/08  オシレータ設定は、コンフィグで80Mhzに設定されている内容に改変**
:::

![IMG_5016.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/82e30e52-8176-d46c-3bb3-15c0be61b6d0.jpeg)


# オシレータ設定
内蔵オシレータ８Mhzを使用して、システムクロックを80MHzに設定します。
![データシートオシレータ１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/bb1f0e3d-6846-95ca-6b9d-47e7aabe0820.png)


まず、コンフィグレーションビットで、電源オン時に、SYSCLK＝８０Mhz で起動させています。
ソフトウェアでも、SYSCLKを変更できるので、PLLODIV＝２を、PLLODIV＝１にして、SYSCLK＝８０Mhzに設定することもできます。
同時に、ペリフェラルに供給されるクロックPBCLKも８０Mhzにしたいので、PBDIVビットを１にしています。
オシレータレジスタは、ロックが掛かっているので、SYSKEYレジスタを使って、ロックを解除しています。
![コンフィグレーション設定画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/ed00577e-0695-2b7d-3835-84c819ee3dda.png)

```C:コンフィグレーションビットSYSCLK＝４０Mhz
// 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 ２)

// 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)
....<略>
```


```C:オシレータ設定SYSCLK=40Mhz→80Mhz
//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
```




# 割込み許可 CP0 Statusレジスタ　IEビット
セクション 2. M4K® コア搭載デバイス用 CPU DS61113E_JP - p.2-26
![CP0_Statusレジスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/c72cfd3a-1266-43c9-efab-18cce0c0fda1.png)

MIPS内コプロセッサCP0　Statusレジスタのビット０：IE　をセットすると割込み許可になります。
```C:CP0Statusレジスタで割込み許可
tmp_CP0_Status=_CP0_GET_STATUS();
    tmp_CP0_Status|=0x00000001;//CP0.STATUS.IE=1で割り込み許可
    _CP0_SET_STATUS(tmp_CP0_Status);
```

# USART設定
PPSで、
RC13:U1TX
RC14:U1RX
に設定しています。
```C:USART PPS
//PPS
    SYSKEY = 0x0; // ensure OSCCON is locked
    SYSKEY = 0xAA996655; // Write Key1 to SYSKEY
    SYSKEY = 0x556699AA; // Write Key2 to SYSKEY

    RPC13Rbits.RPC13R=0b0011; //RPC13:U1TX
    U1RXR=0b0111;             //RPC14:U1RX
    
    SYSKEY = 0x0; // ensure OSCCON is locked
```
# USART 標準入出力関数
![_mon_putc関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/0d5b7e71-a04f-2de4-929e-911b0d03c624.png)

printf文が使えるように、_mon_putcを実装しました。
```C:_mon_putc関数
/**
 * 32-Bit Language Tools Libraries P.38
 * Description: Writes a character to stdout.
 * printf文で使用。
 * @param c 出力１文字
 */
void _mon_putc (char c)
{
    while (U1STAbits.UTXBF); //Wait till transmission is complete
    U1TXREG = c;
}
```
:::note warn
# 受信時の動作
URXDAフラグがクリアの時にも、割り込みが発生している。ここで躓いた。

```C:受信割り込み処理
void __ISR(_UART_1_VECTOR,IPL1AUTO) ISR_UART1(void)
{
    if( IFS1bits.U1RXIF==1)
    {
        IFS1bits.U1RXIF=0;
        if(U1STAbits.URXDA)//←これがないと、正しく受信しない。
        {
            do{
                rxU1.ch=U1RXREG;
                rxU1.buf[rxU1.length]=rxU1.ch;
                rxU1.length++;
                if(rxU1.length>=RXUSART_BUFFER_SIZE)
                {
                    rxU1.length=0;
                }
            }while(U1STAbits.URXDA);  
            if(rxU1.ch==0x0a && rxU1.length>=3)//0x0a:'\n'
            {
                //rxUsart.buf[rxUsart.length-2]='\0';//\a\n終端文字FromPC
                rxU1.buf[rxU1.length-2]=0x00;//\a\n終端文字FromPC
                rxU1.completed=true;  
                IEC1bits.U1RXIE=0;
            } 
        }
    }
}
```

:::




# コード＜オシレータ設定、Timer１割り込み、シリアル通信送受信、受信割り込み＞
```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"


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) 
{
    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();
    usartInit();
    __delay_ms(10);//これを入れないとazが出力されない。
    putchar('a');putchar('z');
    //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("len:");
            printf("%d %s\r",rxU1.length, rxU1.buf);            
            rxU1.length=0;
            IFS1bits.U1RXIF=0;
            IEC1bits.U1RXIE=1;
        }
    }
    
    
    return;
}



```

```C:Peripheral.h


#ifndef PERIPHERAL_H
#define	PERIPHERAL_H

#ifdef	__cplusplus
extern "C" {
#endif
#include <xc.h>
#include <cp0defs.h> 
#include <sys/attribs.h>
#include <stdio.h>
#include <stdbool.h>
    
#define SYSCLK      80000000L		// System clock 40Mhz
#define CTCLK		(SYSCLK / 2)    // CoreTimerCLK SystemClock/2
#define CTus 		(CTCLK / 1000000)	// us delay unit Term
#define CTms     	(CTCLK / 1000)	// ms delay unit Term

#define High 1
#define Low  0
    

//USART-----------------------------------    
#define BAUDRATE 115200
#define SET_SPBRG_DATA  (((unsigned int)((SYSCLK/4)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((SYSCLK/16)/BAUDRATE))-1)    

#define RXUSART_BUFFER_SIZE 50
typedef struct
{
    uint8_t buf[RXUSART_BUFFER_SIZE];
    uint8_t length;
    uint8_t completed;
    uint8_t ch;
}_rxUsart;
extern volatile _rxUsart rxU1;

extern void usartInit(void);
extern uint8_t getch(void);
extern void myUsartPrint(uint8_t *txBuf, uint8_t _length);    
    
//Timer-----------------------------------------------
    typedef struct{
        uint32_t cnt;
        bool fg;
    }_tm;
    extern _tm tm1;
    extern void timer1Init(void);


//Delay------------------------------------------------    
extern void __delay_ms(long _ms);
extern void __delay_us(long _us);
    
    
    
    
#ifdef	__cplusplus
}
#endif

#endif	/* PERIPHERAL_H */


```

```C:Peripheral.c
#include "peripheral.h"


//USART---------------------------------------------------
//USART受信用構造体
volatile _rxUsart rxU1;

/**
 * usart初期化関数
 */
void usartInit(void)
{
    //1.ボーレート設定115200
    U1BRG=SET_SPBRG_DATA1;
    //2.Serial mode setting
    U1RXREG=0x0000;
    U1TXREG=0x0000;
    U1MODEbits.PDSEL=0b00;//8bits no parity
    U1MODEbits.STSEL=1;//1stopbits
    //PPS
    SYSKEY = 0x0; // ensure OSCCON is locked
    SYSKEY = 0xAA996655; // Write Key1 to SYSKEY
    SYSKEY = 0x556699AA; // Write Key2 to SYSKEY

    RPC13Rbits.RPC13R=0b0011; //RPC13:U1TX
    U1RXR=0b0111;             //RPC14:U1RX
    
    SYSKEY = 0x0; // ensure OSCCON is locked
    
    //Rx interrupt
    IFS1bits.U1RXIF=0;
    IPC7bits.U1IP=1;
    IPC7bits.U1IS=1;
    IEC1bits.U1RXIE=1;
    U1STAbits.URXISEL=0b00;//not empty
   
    //IO direction change
    TRISC=0x0000;
    TRISCbits.TRISC14=1; //Input For U1RX.
    
    rxU1.length=0;
    //4.Serial port enabled
    U1STAbits.URXEN=1;
    U1STAbits.UTXEN=1;
    U1MODEbits.ON=1;
}

/**
 * 32-Bit Language Tools Libraries P.38
 * Description: Writes a character to stdout.
 * printf文で使用。
 * @param c 出力１文字
 */
void _mon_putc (char c)
{
    while (U1STAbits.UTXBF); //Wait till transmission is complete
    U1TXREG = c;
}

/**
 * usart 文字入力受信関数
 * @return 受信文字
 */
uint8_t getch(void)
{
    while(!U1STAbits.URXDA)
            return U1RXREG;
}

//タイマー------------------------------------------
_tm tm1;

/**
 *Timer1初期化 
 */
void timer1Init(void)
{
    T1CON=0x00;
    TMR1=0x0000;
    //PR1=0x1388;//PBCLK=40Mhz
    PR1=0x2710;//PBCLK=80Mhz
    T1CONbits.TCKPS=0b01; //1:8
    T1CONbits.ON=1;
    IFS0bits.T1IF=0;
    IPC1bits.T1IP=1;
    IPC1bits.T1IS=0;
    IEC0bits.T1IE=1;
}

//ディレイ--------------------------------------------
/**
 * __delay_ms
 * @param _ms
 */
void __delay_ms(long _ms)
{
    long count;
    count=_ms*CTms;
    _CP0_SET_COUNT(0);
    while(_CP0_GET_COUNT()<=count);
}

/**
 * __delay_us
 * @param _us
 */
void __delay_us(long _us)
{
    long count;
    count=_us*CTus;
    _CP0_SET_COUNT(0);
    while(_CP0_GET_COUNT()<=count);
}

```

```C:Interrupt.h

#ifndef INTERRUPT_H
#define	INTERRUPT_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <cp0defs.h> 
#include <sys/attribs.h>
#include <sys/attribs.h>
#include "peripheral.h"
     
extern   void __ISR(_TIMER_1_VECTOR) ISR_Timer1(void);
extern   void __ISR(_UART_1_VECTOR) ISR_UART1(void);
#ifdef	__cplusplus
}
#endif

#endif	/* INTERRUPT_H */


```

```C:Interrupt.c
#include "interrupt.h"


void __ISR(_TIMER_1_VECTOR,IPL1AUTO) ISR_Timer1(void)
{
    IFS0bits.T1IF=0;
    tm1.cnt++;
    if(tm1.cnt==500)
    {
        tm1.cnt=0;
        LATBbits.LATB0=~LATBbits.LATB0;
    } 
}

void __ISR(_UART_1_VECTOR,IPL1AUTO) ISR_UART1(void)
{
    if( IFS1bits.U1RXIF==1)
    {
        IFS1bits.U1RXIF=0;
        if(U1STAbits.URXDA)
        {
            do{
                rxU1.ch=U1RXREG;
                rxU1.buf[rxU1.length]=rxU1.ch;
                rxU1.length++;
                if(rxU1.length>=RXUSART_BUFFER_SIZE)
                {
                    rxU1.length=0;
                }
            }while(U1STAbits.URXDA);  
            if(rxU1.ch==0x0a && rxU1.length>=3)//0x0a:'\n'
            {
                //rxUsart.buf[rxUsart.length-2]='\0';//\a\n終端文字FromPC
                rxU1.buf[rxU1.length-2]=0x00;//\a\n終端文字FromPC
                rxU1.completed=true;  
                IEC1bits.U1RXIE=0;
            } 
        }
    }
}



```