記事内容は、後日も随時更新していきます。
24/10/22 シリアル通信の受信コードのバグ改良。URXDAビットのチェックを追加。
24/11/08 オシレータ設定は、コンフィグで80Mhzに設定されている内容に改変
オシレータ設定
内蔵オシレータ8Mhzを使用して、システムクロックを80MHzに設定します。
まず、コンフィグレーションビットで、電源オン時に、SYSCLK=80Mhz で起動させています。
ソフトウェアでも、SYSCLKを変更できるので、PLLODIV=2を、PLLODIV=1にして、SYSCLK=80Mhzに設定することもできます。
同時に、ペリフェラルに供給されるクロックPBCLKも80Mhzにしたいので、PBDIVビットを1にしています。
オシレータレジスタは、ロックが掛かっているので、SYSKEYレジスタを使って、ロックを解除しています。
コンフィグレーションビットSYSCLK=40Mhz
// 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 2)
// 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)
....<略>
オシレータ設定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
MIPS内コプロセッサCP0 Statusレジスタのビット0:IE をセットすると割込み許可になります。
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
に設定しています。
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 標準入出力関数
printf文が使えるように、_mon_putcを実装しました。
_mon_putc関数
/**
* 32-Bit Language Tools Libraries P.38
* Description: Writes a character to stdout.
* printf文で使用。
* @param c 出力1文字
*/
void _mon_putc (char c)
{
while (U1STAbits.UTXBF); //Wait till transmission is complete
U1TXREG = c;
}
受信時の動作
URXDAフラグがクリアの時にも、割り込みが発生している。ここで躓いた。
受信割り込み処理
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;
}
}
}
}
コード<オシレータ設定、Timer1割り込み、シリアル通信送受信、受信割り込み>
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;
}
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 */
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 出力1文字
*/
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);
}
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 */
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;
}
}
}
}