MSCAN初始化代码(采用24MHz总线时钟当时不行,于是直接采用了外部晶振时钟16MHz)
void CAN_Init(uint_8 mode,uint_8 open_filter,uint_32 acc_id)
{
uint_8 i;
//对CAN_EN和CAN_STB置高,进入正常模式
gpio_init(CAN_EN, GPIO_OUTPUT, TURN_ON);
gpio_init(CAN_STB, GPIO_OUTPUT, TURN_ON);
gpio_init(CONTROL, GPIO_OUTPUT, TURN_OFF);
MSCAN_MemMapPtr p = (MSCAN_MemMapPtr) MSCAN_BASE_PTR;
//MSCAN模块时钟门控制;SIM_SCGC的MSCAN位=1:使能总线给MSCAN时钟;
//SIM_SCGC的MSCAN位=0:禁止总线给MSCAN时钟
SIM_SCGC |=(uint_32)(SIM_SCGC_MSCAN_MASK);
//MSCAN的引脚复用选择CAN_TX为PTC7,CAN_RX为PTC6
SIM_PINSEL1 &= (uint_32)~(uint_32)(SIM_PINSEL1_MSCANPS_MASK);
MSCAN->CANCTL0 |= MSCAN_CANCTL0_INITRQ_MASK; //MSCAN初始化请求
while(!(MSCAN->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK)){;} //等待初始化模式确认
MSCAN->CANCTL1 =0x80; //使能MSCAN 选择OSC时钟
if(open_filter) //开启接收过滤器,只接收标示符为acc_id的帧
{
// 使用2个32位接收过滤器
p->CANIDAC &= ~MSCAN_CANIDAC_IDAM_MASK;
// 第1个32位滤波器
// 设置接受寄存器的值
p->CANIDAR_BANK_1[0]=acc_id>>3;
p->CANIDAR_BANK_1[1]=acc_id<<5;
p->CANIDAR_BANK_1[2]=0xFF;
p->CANIDAR_BANK_1[3]=0xFF;
// 设置屏蔽寄存器的值
p->CANIDMR_BANK_1[0]=0x00;
p->CANIDMR_BANK_1[1]=0x1F;
p->CANIDMR_BANK_1[2]=0xFF;
p->CANIDMR_BANK_1[3]=0xFF;
// 第2个32位滤波器
// 设置接受寄存器的值
p->CANIDAR_BANK_2[0]=acc_id>>3;
p->CANIDAR_BANK_2[1]=acc_id<<5;
p->CANIDAR_BANK_2[2]=0xFF;
p->CANIDAR_BANK_2[3]=0xFF;
// 设置屏蔽寄存器的值
p->CANIDMR_BANK_2[0]=0x00;
p->CANIDMR_BANK_2[1]=0x1F;
p->CANIDMR_BANK_2[2]=0xFF;
p->CANIDMR_BANK_2[3]=0xFF;
}
else//关闭过滤器
{
for (i = 0; i < 16; i++)
{
if(i <=3) //i>=0 &&
p->CANIDAR_BANK_1[i] = 0xFF;
else if(i>=4 && i <=7)
p->CANIDMR_BANK_1[i-4] = 0xFF;
else if(i>=8 && i <=11)
p->CANIDAR_BANK_2[i-8] = 0xFF;
else
p->CANIDMR_BANK_2[i-12]= 0xFF;
}
}
//配置时钟
p->CANCTL1 &= ~MSCAN_CANCTL1_CLKSRC_MASK; // 采用晶振时钟(16MHz)作为模块时钟
p->CANBTR0 |= MSCAN_CANBTR0_SJW(2);
p->CANBTR1 &= ~MSCAN_CANBTR1_SAMP_MASK; // 位时间采样次数为1
// MSCAN传输波特率 = 模块时钟 / [(1 + TSEG1 + TSEG2) * 分频因子]
// = 16000K/[(1+4+11)*2]=500Kbps
//500K BRP=1 TSEG1=15 TSEG2=2
p->CANBTR0 |= MSCAN_CANBTR0_BRP(1); // 模块时钟2分频
p->CANBTR1 |= MSCAN_CANBTR1_TSEG2(3); // TSEG2:3+1=4 Tq
p->CANBTR1 |= MSCAN_CANBTR1_TSEG1(10); // TSEG1:10+1=11 Tq
//配置工作模式
if(mode == LOOP_MODE)
{
MSCAN->CANCTL1 |= MSCAN_CANCTL1_LOOPB_MASK;
}
else
{
MSCAN->CANCTL1 &= ~MSCAN_CANCTL1_LOOPB_MASK;
}
p->CANCTL1 &= ~MSCAN_CANCTL1_LISTEN_MASK; // 禁止侦听模式,即开启正常模式
//退出初始化模式
p->CANCTL0 &= ~MSCAN_CANCTL0_INITRQ_MASK; //退出初始化模式,进入正常模式
//等待应答初始化模式
while ((p->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK) == 1);
//等待总线通信时钟同步
while ((p->CANCTL0 & MSCAN_CANCTL0_SYNCH_MASK) == 0);
//设置中断方式
p->CANTIER = 0x00; //禁止发送中断
p->CANRIER = 0x01; //开启接收满中断
//设置嵌套向量中断控制寄存器值,使能CAN接收中断
NVIC_Init(MSCAN_RX_IRQn,2);
gpio_set(CONTROL,GPIO_HIGH);
}
任何正在进行的传输或接收都将中止,与CAN总线的同步将丢失。该模块通过设置INITAK = 1来指示进入初始化模式。
导致我们初始化时钟域请求失败的原因可能有:
1.CAN芯片是否存在且正常供电(同网上要有外联CANH-CANL节点)
2.CAN芯片是否损坏
3.保证电源电压至少为CAN芯片最低工作电压