我为学生的汽车应用设计了一个
PCB。我试图用CAN总线在两个PCB之间进行
通信。
电路板的原理附在这个帖子上。使用家庭参考指令和本
论坛中的那些,我已经能够在回送模式下在同一个板上发送和接收CAN消息。现在我正在尝试通信。在正常模式下,两个不同板之间的电路板连接如下:DCPIC CANTX与MCP2562中的CANTX相连。DSPIC CANRX与MCP2562中的CANRX相连。第二板上的连接与第一个电路上的连接相同。在线路两端,我检查了CANRX输入在任何时候都稳定3.3V,CANTANX输出始终稳定在0V。CANH和CANL也稳定在2.5V。我正在使用的代码:接收传输PPS配置时钟配置。
以上来自于百度翻译
以下为原文
I've designed a PCB for a student automo
tive application. I'm trying to
communicate between two of these PCBs using a CAN bus. The schematic of the board is attached to this post. Using the family reference instructions and those present in this forum
I've been able to send and receive CAN messages in the same board in loopback mode. Now I'm trying to communicate between the two different boards in normal mode. The board connections are the following:
The dspic CANTX is connected to the CANTX in the mcp2562.
The dspic CANRX is connected to the CANRX in the mcp2562.
The connections on the second board are the same as the ones on the first.There are 120 ohm terminations at both ends of the line. I've checked that the CANRX input is 3.3V stable at all times and that the
CANTX output is stable 0V at all times.The CANH and CANL are also stable at 2.5V. The code I'm using:Receiving// FST Li***oa
// Project Template
// DSPIC33EP256MU806 Configuration Bit Settings
// 'C' source line config statements
// FGS
#pragma config GWRP = OFF // General Segment Write-Protect bit (General Segment may be written)
#pragma config GSS = OFF // General Segment Code-Protect bit (General Segment Code protect is disabled)
#pragma config GSSK = OFF // General Segment Key bits (General Segment Write Protection and Code Protection is Disabled)
// FOSCSEL
#pragma config FNOSC = FRC // Initial Oscillator Source Selection bits (Internal Fast RC (FRC))
#pragma config IESO = OFF // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)
// FOSC
#pragma config POSCMD = HS // Primary Oscillator Mode Select bits (XT Crystal Oscillator Mode)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF // Peripheral pin select configuration (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)
// FWDT
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128 // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON // PLL Lock Wait Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable bit (Watchdog timer always enabled)
// FPOR
#pragma config FPWRT = PWR128 // Power-on Reset Timer Value Select bits (128ms)
#pragma config BOREN = ON // Brown-out Reset (BOR) Detection Enable bit (BOR is enabled)
#pragma config ALTI2C1 = OFF // Alternate I2C pins for I2C1 (SDA1/SCK1 pins are selected as the I/O pins for I2C1)
// FICD
#pragma config ICS = NONE // ICD Communication Channel Select bits (Reserved, do not use)
#pragma config RSTPRI = PF // Reset Target Vector Select bit (Device will obtain reset instruction from Primary flash)
#pragma config JTAGEN = OFF // JTAG Enable bit (JTAG is disabled)
// FAS
#pragma config AWRP = OFF // Auxiliary Segment Write-protect bit (Aux Flash may be written)
#pragma config APL = OFF // Auxiliary Segment Code-protect bit (Aux Flash Code protect is disabled)
#pragma config APLK = OFF // Auxiliary Segment Key bits (Aux Flash Write Protection and Code Protection is Disabled)
#include
// NOTE: Always include timing.h
#include "lib_pic33e/timing.h"
#include
//#include
#include
#include
/* This code example demonstrates a method to configure the ECAN module to receive Standard ID
CAN messages. SID Messages with SID range 0x1D0-0x1D7 will be accepted. */
/* Include fuse configuration code here. Optionally the fuse configuration can be specified via
MPLAB IDE Menu operations. */
#define NUM_OF_ECAN_BUFFERS 16
/* This is the ECAN message buffer declaration. Note the buffer alignment. */
__eds__ unsigned int ecan1MsgBuf[NUM_OF_ECAN_BUFFERS][8] __attribute__((eds, space(dma), aligned(NUM_OF_ECAN_BUFFERS * 16)));
void
can1_config() {
/* Set up the CAN module for 1Mbps speed with 10 Tq per bit. */
C1CFG1bits.SJW = 0;
C1CFG1bits.BRP = 1; //TQ = 2*(BRP+1)/FCAN
C1CFG2bits.PRSEG = 6; // 2TQ
C1CFG2bits.SEG1PH = 5; // 3TQ
C1CFG2bits.SAM = 0; //Sample 1 times
C1CFG2bits.SEG2PHTS = 1;
C1CFG2bits.SEG2PH = 1; //2TQ
C1FCTRLbits.DMABS = 4; //16 buffers in device ram
C1FCTRLbits.FSA = 5; //TX/RX buffer TRB5
}
void
dma0_config() {
/* Assign 32x8word Message Buffers for ECAN1 in device RAM. This example uses DMA0 for TX.
Refer to 21.8.1 “DMA Operation for Transmitting Data” for details on DMA channel
configuration for ECAN transmit. */
DMA0CONbits.SIZE = 0x0;
DMA0CONbits.DIR = 0x1;
DMA0CONbits.AMODE = 0x2;
DMA0CONbits.MODE = 0x0;
DMA0REQ = 70;
DMA0CNT = 7;
DMA0PAD = (volatile unsigned int)&C1TXD;
DMA0STAL = (unsigned int) ecan1MsgBuf;
DMA0STAH = 0;
DMA0CONbits.CHEN = 0x1;
/* Configure Message Buffer 0 for Transmission and assign priority */
C1TR01CONbits.TXEN0 = 0x1;
C1TR01CONbits.TX0PRI = 0x3;
}
void
dma1_config() {
/* Assign 32x8word Message Buffers for ECAN1 in device RAM. This example uses DMA1 for RX.
Refer to 21.8.1 “DMA Operation for Transmitting Data” for details on DMA channel
configuration for ECAN transmit. */
DMA1CONbits.SIZE = 0x0;
DMA1CONbits.DIR = 0x0;
DMA1CONbits.AMODE = 0x2;
DMA1CONbits.MODE = 0x0;
DMA1REQ = 34;
DMA1CNT = 7;
DMA1PAD = (volatile unsigned int)&C1RXD;
DMA1STAL = (unsigned int) ecan1MsgBuf;
DMA1STAH = 0;
DMA1CONbits.CHEN = 0x1;
}
void
can_filter_config() {
C1CTRL1bits.WIN = 1;
/* Select Acceptance Filter Mask 0 for Acceptance Filter 0 */
C1FMSKSEL1bits.F0MSK=0x0;
/* Configure Acceptance Filter Mask 0 register to mask SID<2:0>
* Mask Bits (11-bits) : 0b111 1111 1000 */
C1RXM0SIDbits.SID = 0x000;
/* Configure Acceptance Filter 0 to match standard identifier
Filter Bits (11-bits): 0b011 1010 xxx with the mask setting, message with SID
range 0x1D0-0x1D7 will be accepted by the ECAN module. */
C1RXF0SIDbits.SID = 0x01D0;
/* Acceptance Filter 0 to check for Standard Identifier */
C1RXM0SIDbits.MIDE = 0x1;
C1RXF0SIDbits.EXIDE= 0x0;
/* Acceptance Filter 0 to use Message Buffer 10 to store message */
C1BUFPNT1bits.F0BP = 0xA;
/* Filter 0 enabled for Identifier match with incoming message */
C1FEN1bits.FLTEN0=0x1;
/* Clear Window Bit to Access ECAN
* Control Registers */
C1CTRL1bits.WIN=0x0;
}
void
can1_send(volatile unsigned int i) {
LATEbits.LATE5 = 1;
ecan1MsgBuf[0][0] = 0x740;
/* CiTRBnEID = 0bxxxx 0000 0000 0000
EID<17:6> = 0b0000 0000 0000 */
ecan1MsgBuf[0][1] = 0x0000;
/* CiTRBnDLC = 0b0000 0000 xxx0 1111
EID<17:6> = 0b000000
RTR = 0b0
RB1 = 0b0
RB0 = 0b0
DLC = 0b1111 */
ecan1MsgBuf[0][2] = 0x0008;
/* Write message data bytes */
ecan1MsgBuf[0][3] = i;
ecan1MsgBuf[0][4] = 0xDEAD;
ecan1MsgBuf[0][5] = 0xBEEF;
ecan1MsgBuf[0][6] = 0xABBA;
/* Request message buffer 0 transmission */
C1TR01CONbits.TXREQ0 = 0x1;
/* The following shows an example of how the TXREQ bit can be polled to check if transmission
is complete. */
while(C1TR01CONbits.TXREQ0 == 1) {
if (C1INTF) {
LATEbits.LATE7 = 1;
LATBbits.LATB12 = 1;
uprintf("%un", C1INTF);
USBTasks();
}
__delay_ms(100);
}
LATEbits.LATE5 = 0;
}
int
main(void) {
unsigned long address;
int i;
volatile unsigned int count = 0;
/* The dsPIC33E device features I/O remap. This I/O remap configuration for the ECAN module
can be performed here. */
TRISEbits.TRISE3 = 0;
TRISEbits.TRISE5 = 0;
TRISEbits.TRISE7 = 0;
TRISBbits.TRISB12 = 0;
USBInit();
config_pps_can();
/* Set up the ECAN1 module to operate at 250 kbps. The ECAN module should be first placed
in configuration mode. */
C1CTRL1bits.REQOP = 4;
while(C1CTRL1bits.OPMODE != 4);
can1_config();
dma0_config();
dma1_config();
can_filter_config();
IEC2bits.C1IE = 1;
C1INTEbits.RBIE = 1;
C1INTEbits.TBIE = 1;
C1INTEbits.WAKIE = 1;
/* Place the ECAN module in normal
* mode. */
C1CTRL1bits.REQOP = 0;
while(C1CTRL1bits.OPMODE != 0);
LATEbits.LATE3 = 1;
/* The following code shows one example of how the application can wait
for a message to be received in message buffer 10 */
while(1)
{
/* Message was received. */
while (C1RXFUL1 == 0) ;
C1RXFUL1bits.RXFUL10 = 0;
LATEbits.LATE3 ^= 1;
}
}
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv))_C1Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle CAN1 Transmit and
* recieve interrupt.
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _C1Interrupt( void )
{
if( C1INTFbits.TBIF ) {
C1INTFbits.TBIF = 0;
}
if( C1INTFbits.RBIF ) {
C1INTFbits.RBIF = 0;
}
if (C1INTFbits.WAKIF) {
LATBbits.LATB12 ^= 1;
C1INTFbits.WAKIF = 0;
}
LATEbits.LATE3 ^= 1;
IFS2bits.C1IF = 0; // clear interrupt flag
}
//------------------------------------------------------------------------------
// DMA interrupt handlers
//------------------------------------------------------------------------------
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle DMA0interrupt
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _DMA0Interrupt( void )
{
IFS0bits.DMA0IF = 0; // Clear the DMA0 Interrupt Flag;
}
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv)) _DMA1Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle DMA1interrupt
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _DMA1Interrupt( void )
{
IFS0bits.DMA1IF = 0; // Clear the DMA1 Interrupt Flag;
}
Transmitting// FST Li***oa
// Project Template
// DSPIC33EP256MU806 Configuration Bit Settings
// 'C' source line config statements
// FGS
#pragma config GWRP = OFF // General Segment Write-Protect bit (General Segment may be written)
#pragma config GSS = OFF // General Segment Code-Protect bit (General Segment Code protect is disabled)
#pragma config GSSK = OFF // General Segment Key bits (General Segment Write Protection and Code Protection is Disabled)
// FOSCSEL
#pragma config FNOSC = FRC // Initial Oscillator Source Selection bits (Internal Fast RC (FRC))
#pragma config IESO = OFF // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)
// FOSC
#pragma config POSCMD = HS // Primary Oscillator Mode Select bits (XT Crystal Oscillator Mode)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF // Peripheral pin select configuration (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)
// FWDT
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128 // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON // PLL Lock Wait Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF // Watchdog Timer Enable bit (Watchdog timer always enabled)
// FPOR
#pragma config FPWRT = PWR128 // Power-on Reset Timer Value Select bits (128ms)
#pragma config BOREN = ON // Brown-out Reset (BOR) Detection Enable bit (BOR is enabled)
#pragma config ALTI2C1 = OFF // Alternate I2C pins for I2C1 (SDA1/SCK1 pins are selected as the I/O pins for I2C1)
// FICD
#pragma config ICS = NONE // ICD Communication Channel Select bits (Reserved, do not use)
#pragma config RSTPRI = PF // Reset Target Vector Select bit (Device will obtain reset instruction from Primary flash)
#pragma config JTAGEN = OFF // JTAG Enable bit (JTAG is disabled)
// FAS
#pragma config AWRP = OFF // Auxiliary Segment Write-protect bit (Aux Flash may be written)
#pragma config APL = OFF // Auxiliary Segment Code-protect bit (Aux Flash Code protect is disabled)
#pragma config APLK = OFF // Auxiliary Segment Key bits (Aux Flash Write Protection and Code Protection is Disabled)
#include
// NOTE: Always include timing.h
#include "lib_pic33e/timing.h"
#include
//#include
#include
#include
/* This code example demonstrates a method to configure the ECAN module to receive Standard ID
CAN messages. SID Messages with SID range 0x1D0-0x1D7 will be accepted. */
/* Include fuse configuration code here. Optionally the fuse configuration can be specified via
MPLAB IDE Menu operations. */
#define NUM_OF_ECAN_BUFFERS 16
/* This is the ECAN message buffer declaration. Note the buffer alignment. */
__eds__ unsigned int ecan1MsgBuf[NUM_OF_ECAN_BUFFERS][8] __attribute__((eds, space(dma), aligned(NUM_OF_ECAN_BUFFERS * 16)));
void
can1_config() {
/* Set up the CAN module for 1Mbps speed with 10 Tq per bit. */
C1CFG1bits.SJW = 0;
C1CFG1bits.BRP = 1; //TQ = 2*(BRP+1)/FCAN
C1CFG2bits.PRSEG = 6; // 2TQ
C1CFG2bits.SEG1PH = 5; // 3TQ
C1CFG2bits.SAM = 0; //Sample 1 times
C1CFG2bits.SEG2PHTS = 1;
C1CFG2bits.SEG2PH = 1; //2TQ
C1FCTRLbits.DMABS = 4; //16 buffers in device ram
C1FCTRLbits.FSA = 5; //TX/RX buffer TRB5
}
void
dma0_config() {
/* Assign 32x8word Message Buffers for ECAN1 in device RAM. This example uses DMA0 for TX.
Refer to 21.8.1 “DMA Operation for Transmitting Data” for details on DMA channel
configuration for ECAN transmit. */
DMA0CONbits.SIZE = 0x0;
DMA0CONbits.DIR = 0x1;
DMA0CONbits.AMODE = 0x2;
DMA0CONbits.MODE = 0x0;
DMA0REQ = 70;
DMA0CNT = 7;
DMA0PAD = (volatile unsigned int)&C1TXD;
DMA0STAL = (unsigned int) ecan1MsgBuf;
DMA0STAH = 0;
DMA0CONbits.CHEN = 0x1;
/* Configure Message Buffer 0 for Transmission and assign priority */
C1TR01CONbits.TXEN0 = 0x1;
C1TR01CONbits.TX0PRI = 0x3;
}
void
dma1_config() {
/* Assign 32x8word Message Buffers for ECAN1 in device RAM. This example uses DMA1 for RX.
Refer to 21.8.1 “DMA Operation for Transmitting Data” for details on DMA channel
configuration for ECAN transmit. */
DMA1CONbits.SIZE = 0x0;
DMA1CONbits.DIR = 0x0;
DMA1CONbits.AMODE = 0x2;
DMA1CONbits.MODE = 0x0;
DMA1REQ = 34;
DMA1CNT = 7;
DMA1PAD = (volatile unsigned int)&C1RXD;
DMA1STAL = (unsigned int) ecan1MsgBuf;
DMA1STAH = 0;
DMA1CONbits.CHEN = 0x1;
}
void
can_filter_config() {
C1CTRL1bits.WIN = 1;
/* Select Acceptance Filter Mask 0 for Acceptance Filter 0 */
C1FMSKSEL1bits.F0MSK=0x0;
/* Configure Acceptance Filter Mask 0 register to mask SID<2:0>
* Mask Bits (11-bits) : 0b111 1111 1000 */
C1RXM0SIDbits.SID = 0x000;
/* Configure Acceptance Filter 0 to match standard identifier
Filter Bits (11-bits): 0b011 1010 xxx with the mask setting, message with SID
range 0x1D0-0x1D7 will be accepted by the ECAN module. */
C1RXF0SIDbits.SID = 0x01D0;
/* Acceptance Filter 0 to check for Standard Identifier */
C1RXM0SIDbits.MIDE = 0x1;
C1RXF0SIDbits.EXIDE= 0x0;
/* Acceptance Filter 0 to use Message Buffer 10 to store message */
C1BUFPNT1bits.F0BP = 0xA;
/* Filter 0 enabled for Identifier match with incoming message */
C1FEN1bits.FLTEN0=0x1;
/* Clear Window Bit to Access ECAN
* Control Registers */
C1CTRL1bits.WIN=0x0;
}
void
can1_send(volatile unsigned int i) {
LATEbits.LATE5 = 1;
ecan1MsgBuf[0][0] = 0x740;
/* CiTRBnEID = 0bxxxx 0000 0000 0000
EID<17:6> = 0b0000 0000 0000 */
ecan1MsgBuf[0][1] = 0x0000;
/* CiTRBnDLC = 0b0000 0000 xxx0 1111
EID<17:6> = 0b000000
RTR = 0b0
RB1 = 0b0
RB0 = 0b0
DLC = 0b1111 */
ecan1MsgBuf[0][2] = 0x0008;
/* Write message data bytes */
ecan1MsgBuf[0][3] = i;
ecan1MsgBuf[0][4] = 0xDEAD;
ecan1MsgBuf[0][5] = 0xBEEF;
ecan1MsgBuf[0][6] = 0xABBA;
/* Request message buffer 0 transmission */
C1TR01CONbits.TXREQ0 = 0x1;
/* The following shows an example of how the TXREQ bit can be polled to check if transmission
is complete. */
while(C1TR01CONbits.TXREQ0 == 1) {
if (C1INTF) {
LATEbits.LATE7 = 1;
LATBbits.LATB12 = 1;
uprintf("%un", C1INTF);
USBTasks();
}
__delay_ms(100);
}
LATEbits.LATE5 = 0;
}
int
main(void) {
unsigned long address;
int i;
volatile unsigned int count = 0;
/* The dsPIC33E device features I/O remap. This I/O remap configuration for the ECAN module
can be performed here. */
TRISEbits.TRISE3 = 0;
TRISEbits.TRISE5 = 0;
TRISEbits.TRISE7 = 0;
TRISBbits.TRISB12 = 0;
USBInit();
config_pps_can();
/* Set up the ECAN1 module to operate at 250 kbps. The ECAN module should be first placed
in configuration mode. */
C1CTRL1bits.REQOP = 4;
while(C1CTRL1bits.OPMODE != 4);
can1_config();
dma0_config();
dma1_config();
can_filter_config();
IEC2bits.C1IE = 1;
C1INTEbits.RBIE = 1;
C1INTEbits.TBIE = 1;
C1INTEbits.WAKIE = 1;
/* Place the ECAN module in normal
* mode. */
C1CTRL1bits.REQOP = 0;
while(C1CTRL1bits.OPMODE != 0);
LATEbits.LATE3 = 1;
/* The following code shows one example of how the application can wait
for a message to be received in message buffer 10 */
can1_send(count++);
while(1)
{
can1_send(count++);
LATEbits.LATE3 ^= 1;
__delay_ms(10);
}
}
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv))_C1Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle CAN1 Transmit and
* recieve interrupt.
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _C1Interrupt( void )
{
if( C1INTFbits.TBIF ) {
C1INTFbits.TBIF = 0;
}
if( C1INTFbits.RBIF ) {
C1INTFbits.RBIF = 0;
}
if (C1INTFbits.WAKIF) {
LATBbits.LATB12 ^= 1;
C1INTFbits.WAKIF = 0;
}
LATEbits.LATE3 ^= 1;
IFS2bits.C1IF = 0; // clear interrupt flag
}
//------------------------------------------------------------------------------
// DMA interrupt handlers
//------------------------------------------------------------------------------
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle DMA0interrupt
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _DMA0Interrupt( void )
{
IFS0bits.DMA0IF = 0; // Clear the DMA0 Interrupt Flag;
}
/******************************************************************************
* Function: void __attribute__((interrupt, no_auto_psv)) _DMA1Interrupt(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Interrupt service routine to handle DMA1interrupt
*****************************************************************************/
void __attribute__ ( (interrupt, auto_psv, shadow) ) _DMA1Interrupt( void )
{
IFS0bits.DMA1IF = 0; // Clear the DMA1 Interrupt Flag;
}
PPS config void config_pps_can(void)
{
TRISGbits.TRISG6 = 0;
TRISGbits.TRISG7 = 1;
TRISGbits.TRISG8 = 0;
TRISGbits.TRISG9 = 1;
PPSUnLock; // send unlock sequence to allow reprograming the pins
PPSOutput(OUT_FN_PPS_C1TX, OUT_PIN_PPS_RP118);
PPSInput(IN_FN_PPS_C1RX, IN_PIN_PPS_RPI119);
PPSOutput(OUT_FN_PPS_C2TX, OUT_PIN_PPS_RP120);
PPSInput(IN_FN_PPS_C2RX, IN_PIN_PPS_RPI121);
PPSLock; // relock the pin control regs
}
Clock configvoid __attribute__((user_init)) config_clock(void)
{
/*
* FIN is external primary oscillator.
* FPPLIN = FIN / N1, must be in [0.8, 8] MHz.
* FVCO = FPPLIN * M, must be in [120, 340] MHz.
* FOSC = FVCO / N2, must be in [15, 140] MHz (max. temperature 85C).
* Overall:
* FOSC = FIN * M/(N1*N2) =
* = FIN * (PLLFDB + 2)/((PPLPRE + 2) * 2(PLLPOST + 1))
*/
#if FCY64 // 64 MHz
#define FCY 64000000UL
#define FOSC FCY*2
CLKDIVbits.PLLPRE = 2; // N1 = 4
PLLFBD = 62; // M = 64
CLKDIVbits.PLLPOST = 0b00; // N2 = 2
// Overall PLL: X8 = 64/(4*2)
#elif FCY70 // 70 MHz
#define FCY 70000000UL
#define FOSC FCY*2
CLKDIVbits.PLLPRE = 2; // N1 = 4
PLLFBD = 68; // M = 70
CLKDIVbits.PLLPOST = 0b00; // N2 = 2
// Overall PLL: X8.75 = 70/(4*2)
#elif FAST // 106 MHz
// Gotta go fast
#define FCY 106000000UL
#define FOSC FCY*2
CLKDIVbits.PLLPRE = 2; // N1 = 4
PLLFBD = 104; // M = 106
CLKDIVbits.PLLPOST = 0b00; // N2 = 2
// Overall PLL: X13.25 = 106/(4*2)
#else // DEFAULT: 16 MHz
#define FCY 16000000UL
#define FOSC FCY*2
CLKDIVbits.PLLPRE = 2; // N1 = 4
PLLFBD = 30; // M = 32
CLKDIVbits.PLLPOST = 0b01; // N2 = 4
// Overall PLL: X2 = 32/(4*4)
#endif
// Initiate Clock Switch to Primary Oscillator with PLL (NOSC=0b011)
__builtin_write_OSCCONH(0b011);
__builtin_write_OSCCONL(OSCCONL | 0b1);
// Wait for Clock switch to occur
while (OSCCONbits.COSC != 0b011);
//USB Clock configuration assuming 16MHz crystal
/*Configure the auxilliary PLL to provide 48MHz needed for USB Operation.*/
// Configuring the auxiliary PLL, since the primary
// oscillator provides the source clock to the auxiliary
// PLL, the auxiliary oscillator is disabled. Note that
// the AUX PLL is enabled. The input 16MHz clock is divided
// by 2, multiplied by 24 and then divided by 4. Wait till
// the AUX PLL locks.
ACLKCON3 = 0x24C3;
ACLKDIV3 = 0x7;
ACLKCON3bits.ENAPLL = 1;
while(ACLKCON3bits.APLLCK != 1);
}
Attached Image(s)
0