Ejemplo n.º 1
0
//============================================================================
//函数名称:CANInit
//函数返回:0:成功;1:失败
//参数说明:
//         CANChannel:模块号
//		   baudrateKHz: 波特率
//         selfLoop: 模式选择(1=回环模式;0=正常模式)
//         idMask: ID过滤(1=ID过滤;0=ID不过滤)
//功能概要:CAN初始化
//============================================================================
uint8 CANInit(uint8 CANChannel,uint32 baudrateKHz,uint8 selfLoop,uint8 idMask)
{
    int8 i;
    CAN_MemMapPtr CANBaseAdd;
  
    //使能FlexCAN外部时钟
    OSC_CR |= OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK;
    
    //通过模块号选择模块基地址
    if(CANChannel == 0)
        CANBaseAdd = CAN0_BASE_PTR;
    else if(CANChannel == 1)
        CANBaseAdd = CAN1_BASE_PTR;
    
    //使能CAN模块时钟
    if(CANBaseAdd == CAN0_BASE_PTR)
        SIM_SCGC6 |=  SIM_SCGC6_FLEXCAN0_MASK;//使能CAN0的时钟模块
    else
        SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1_MASK;//使能CAN1的时钟模块
    
    //使能CAN中断
    if(CANChannel == 0)//使能CAN0的中断                                              
    {  
        NVICICPR0 = (NVICICPR0 & ~(0x07<<29)) | (0x07<<29);//清除挂载在FlexCAN0的中断  
        NVICISER0 = (NVICISER0 & ~(0x07<<29)) | (0x07<<29);//使能FlexCAN0中断 
        
        NVICICPR1 = (NVICICPR1 & ~(0x1F<<0)) | (0x1F);//清除挂载在FlexCAN0的中断                 
        NVICISER1 = (NVICISER1 & ~(0x1F<<0)) | (0x1F);//使能FlexCAN0中断                      
    }  
    else  //使能CAN1的中断
    {
        NVICICPR1 = (NVICICPR1 & ~(0xFF<<5)) | (0xFF<<5);//清除挂载在FlexCAN1的中断  
        NVICISER1 = (NVICISER1 & ~(0xFF<<5)) | (0xFF<<5);//使能FlexCAN1中断                       
    }

    //配置CAN_RX/TX复用引脚功能
    if(CANChannel == 0)
    {
		PORTA_PCR12 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //上拉
		PORTA_PCR13 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //上拉
    }
    else
    {
    	PORTE_PCR24 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Tx上拉
    	PORTE_PCR25 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Rx上拉
    } 
    
    //选择时钟源,外设时钟48MHz,内部时钟:12MHz
    CAN_CTRL1_REG(CANBaseAdd) |= CAN_CTRL1_CLKSRC_MASK;//选择内部时钟    
    
    CAN_MCR_REG(CANBaseAdd) |= CAN_MCR_FRZ_MASK;  //使能冻结模式   
    CAN_MCR_REG(CANBaseAdd) &= ~CAN_MCR_MDIS_MASK;//使能CAN模块
    //确认已退出冻结模式
    while((CAN_MCR_LPMACK_MASK & CAN_MCR_REG(CANBaseAdd)));

    //软件复位
    CAN_MCR_REG(CANBaseAdd) ^= CAN_MCR_SOFTRST_MASK; 
    //等待复位完成
    while(CAN_MCR_SOFTRST_MASK & CAN_MCR_REG(CANBaseAdd));   
    //等待进入冻结模式 
    while(!(CAN_MCR_FRZACK_MASK & CAN_MCR_REG(CANBaseAdd)));
    
    //将16个邮箱缓冲区内容清0
    for(i=0;i<16;i++)
    {
          CANBaseAdd->MB[i].CS = 0x00000000;
          CANBaseAdd->MB[i].ID = 0x00000000;
          CANBaseAdd->MB[i].WORD0 = 0x00000000;
          CANBaseAdd->MB[i].WORD1 = 0x00000000;
    }
    
    //接收邮箱过滤IDE比较,RTR不比较
    CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_EACEN_MASK;
    //远程请求帧产生
    CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_RRS_MASK;
    //邮箱首先从接收FIFO队列匹配然后再在邮箱中匹配
    CAN_CTRL2_REG(CANBaseAdd) &= ~CAN_CTRL2_MRP_MASK;
 
    //使用一个32位过滤器
    CAN_MCR_REG(CANBaseAdd) |= (CAN_MCR_REG(CANBaseAdd) & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0);
    //设置波特率
    if(SetCANBand(CANChannel,baudrateKHz) == 1)//若设置错误
        return 1;
    
    //模式选择:回环模式或正常模式
    if(1==selfLoop)
        CAN_CTRL1_REG(CANBaseAdd) |= CAN_CTRL1_LPB_MASK;//使用回环模式

    //初始化掩码寄存器
    if(1==idMask)//屏蔽ID
    {
    	CAN_RXMGMASK_REG(CANBaseAdd) = 0x1FFFFFFF;
		CAN_RX14MASK_REG(CANBaseAdd) = 0x1FFFFFFF;
		CAN_RX15MASK_REG(CANBaseAdd) = 0x1FFFFFFF;
    }
    else//不屏蔽ID
    {
    	CAN_RXMGMASK_REG(CANBaseAdd) = 0x0;
		CAN_RX14MASK_REG(CANBaseAdd) = 0x0;
		CAN_RX15MASK_REG(CANBaseAdd) = 0x0;
    }

    //如果单独掩码功能使能,为每个队列初始化单独的掩码寄存器
    if(CAN_MCR_REG(CANBaseAdd) & CAN_MCR_IRMQ_MASK)
    {
        for(i = 0; i < NUMBER_OF_MB ; i++)
        {        
            CANBaseAdd->RXIMR[i] = 0x1FFFFFFFL;
        }
    }
    
    //只有在冻结模式下才能配置,配置完推出冻结模式
	CAN_MCR_REG(CANBaseAdd) &= ~(CAN_MCR_HALT_MASK);
	//等待直到退出冻结模式
	while( CAN_MCR_REG(CANBaseAdd) & CAN_MCR_FRZACK_MASK);    
	//等到不在冻结模式,休眠模式或者停止模式
	while((CAN_MCR_REG(CANBaseAdd) & CAN_MCR_NOTRDY_MASK));
    
    return 0;
}
/*
 * LPLD_CAN_Init
 * 该函数用于Flex_CAN模块初始化
 * 参数:
 *    canx--设置CAN模块号
 *      |__CAN0             --CAN0号模块
 *      |__CAN1             --CAN1号模块
 *    baud_khz--设置CAN总线波特率
 *      |__0
 *      |__....
 *    selfloop--设置CAN总线自循环模式
 *      |__CAN_NOSELFLOOP   --不循环
 *      |__CAN_SELFLOOP     --循环 
 * 输出:
 *    0:配置出现错误
 *    1:配置成功
 */
uint8 LPLD_CAN_Init(CANx canx, uint32 baud_khz, uint8 selfloop)
{
    int8 i;
    CAN_MemMapPtr canptr = CANx_Ptr[canx];
  
    //使能FlexCAN外部时钟
    OSC_CR |= OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK;
    
    //使能CAN模块时钟
    if(canx == CAN0)
        SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0_MASK;//使能CAN0的时钟模块 
    else
        SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1_MASK;//使能CAN1的时钟模块
    
    //配置CAN_RX/TX复用引脚功能
    if(canx == CAN0)
    {
	//CAN0_TX
        PORTA_PCR12 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Tx上拉
        //CAN0_RX
	PORTA_PCR13 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //RX上拉
    }
    else
    {
    	PORTE_PCR24 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Tx上拉
    	PORTE_PCR25 = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; //Rx上拉
    } 
    //注:CTRL1不能在FRZ(冻结)模式下设置
    //选择时钟源,外设时钟48MHz,内部时钟:12MHz
    //选择内部时钟
    CAN_CTRL1_REG(canptr)|= CAN_CTRL1_CLKSRC_MASK;    
     
    //使能CAN模块
    CAN_MCR_REG(canptr) &= ~CAN_MCR_MDIS_MASK;
    
    //在时钟初始化完毕和CAN总线使能完毕后,
    //单片机自动进入冻结模式
    //只有在冻结模式下才能配置大多数CAN总线寄存器
    //使能冻结模式
    CAN_MCR_REG(canptr) |= CAN_MCR_FRZ_MASK; 
    //确认不在低功耗模式,如果在低功耗模式下软件复位无法完成
    while((CAN_MCR_REG(canptr) & CAN_MCR_LPMACK_MASK ));
    
    //软件复位
    //受影响的registers: MCR (except the MDIS bit), TIMER, ECR, ESR1, ESR2,
    //                    IMASK1, IMASK2, IFLAG1, IFLAG2 and CRCR.
    //不受影响的registers:CTRL1, CTRL2, RXIMR0–RXIMR63, RXMGMASK, RX14MASK,
    //                     RX15MASK, RXFGMASK, RXFIR, all Message Buffers
    //复位后MCR中RFEN=0,因而Rx FIFO并没有使能  --------重要
    //因而“使能冻结模式位”被复位
    
    //CAN 总线软件复位,复位后该自动清零
    CAN_MCR_REG(canptr) |= CAN_MCR_SOFTRST_MASK; 
    //等待复位完成
    while(CAN_MCR_SOFTRST_MASK & CAN_MCR_REG(canptr)); 
    
    //退出正常模式,再次使能冻结模式 ,因为软件复位使冻结模式退出 
    CAN_MCR_REG(canptr) |= CAN_MCR_FRZ_MASK;  
    //等待进入冻结模式 
    while(!(CAN_MCR_REG(canptr) & CAN_MCR_FRZACK_MASK));
    
    //=================Initialize the Module Configuration Register=============
    //1 Enable the individual filtering per MB and reception queue features by setting the IRMQ bit
    //1设置全匹配蔽位,并配置与之相关的寄存器
    CAN_CTRL2_REG(canptr) &= ~CAN_CTRL2_EACEN_MASK;//接收邮箱过滤IDE匹配,RTR不匹配
    CAN_CTRL2_REG(canptr) &= ~CAN_CTRL2_RRS_MASK;  //不自动产生远程请求帧产生
    CAN_MCR_REG(canptr)   &= ~CAN_MCR_IRMQ_MASK;   //使能全局匹配寄存器      
    CAN_CTRL2_REG(canptr) |= CAN_CTRL2_MRP_MASK;   //ID首先从邮箱中匹配
    CAN_CTRL1_REG(canptr) |= CAN_CTRL1_LBUF_MASK;  //发送的时候从低优先级发送
    CAN_RXMGMASK_REG(canptr) = 0x1FFFFFFF;         //28位ID全部匹配
    CAN_RX14MASK_REG(canptr) = 0x00000000;
    CAN_RX15MASK_REG(canptr) = 0x00000000;
    //2 WRN_EN bit
    //2设置是否产生警告中断
    CAN_MCR_REG(canptr)  &= ~CAN_MCR_WRNEN_MASK;    //不产生警告中断
    //3 SRX_DIS bit
    //3设置是否自我接受
    //CAN_MCR_REG(canptr)  |= CAN_MCR_SRXDIS_MASK;  //禁止CAN自我接收
    //4 Enable the Rx FIFO by setting the RFEN bit
    //4 设置是否使能RX FIFO
    CAN_MCR_REG(canptr)  &= ~CAN_MCR_RFEN_MASK ;    //禁止接收FIFO
    //5 Enable the abort mechanism by setting the AEN bit
    CAN_MCR_REG(canptr)  &= ~CAN_MCR_AEN_MASK;   
    //6 Enable the local priority feature by setting the LPRIO_EN bit
    CAN_MCR_REG(canptr)  &= ~CAN_MCR_LPRIOEN_MASK;
    

    //模式选择:回环模式或正常模式
    if(selfloop)
      CAN_CTRL1_REG(canptr) |= CAN_CTRL1_LPB_MASK;   //使用回环模式
    else
      CAN_CTRL1_REG(canptr) &= ~CAN_CTRL1_LPB_MASK;  //使用正常模式
    //->Initialize the Control Register
    //Determine the bit timing parameters: PROPSEG, PSEG1, PSEG2, RJW
    //Determine the bit rate by programming the PRESDIV field
    //Determine the internal arbitration mode (LBUF bit)
    //设置波特率
    if(LPLD_CAN_SetBaud(canx,baud_khz))//若设置错误
    {
        return 0;
    }
    //“SYNC” message 使能同步功能
    CAN_MCR_REG(canptr)  |= CAN_CTRL1_TSYN_MASK;
    CAN_TIMER_REG(canptr) = 0x0000;
    //->Initialize the Message Buffers
    //The Control and Status word of all Message Buffers must be initialized
    //If Rx FIFO was enabled, the ID filter table must be initialized
    //Other entries in each Message Buffer should be initialized as required
    //将16个邮箱缓冲区内容清0
    for(i=0;i<16;i++)
    {
      canptr->MB[i].CS    = 0x00000000;
      canptr->MB[i].ID    = 0x00000000;
      canptr->MB[i].WORD0 = 0x00000000;
      canptr->MB[i].WORD1 = 0x00000000;
    }
    //初始化所需要的接受邮箱,设置邮箱的ID,即filter的ID值
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_1,FILTER_SLAVEA_ID);//1
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_2,FILTER_SLAVEB_ID);//2
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_3,FILTER_SLAVEC_ID);//3
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_4,FILTER_SLAVED_ID);//4
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_5,FILTER_SLAVEE_ID);//5
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_6,FILTER_SLAVEF_ID);//6
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_7,FILTER_SLAVEG_ID);//7
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_8,FILTER_SLAVEH_ID);//8
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_9,FILTER_SLAVEI_ID);//9
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_10,FILTER_SLAVEJ_ID);//10
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_11,FILTER_SLAVEK_ID);//11
    LPLD_CAN_Enable_RX_Buf(canx,MB_NUM_12,FILTER_SLAVEL_ID);//12
    //->Initialize the Rx Individual Mask Registers
    //设置每个邮箱的匹配寄存器,用到那个邮箱设置哪给
    canptr->RXIMR[0]  = 0x00000000;
    canptr->RXIMR[1]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[2]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[3]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[4]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[5]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[6]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[7]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[8]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[9]  = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[10] = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[11] = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[12] = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[13] = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[14] = 0x1FFFFFFF; //设置28位屏蔽位
    canptr->RXIMR[15] = 0x1FFFFFFF; //设置28位屏蔽位
    //Set required interrupt mask bits in the IMASK Registers (for all MB interrupts), in
    //CTRL Register (for Bus Off and Error interrupts) and in MCR Register for Wake-Up interrupt
    //清除所有邮箱的标志位
    LPLD_CAN_ClearAllFlag(canx);
    //使能接受邮箱中断
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_1);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_2);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_3);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_4);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_5);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_6);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_7);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_8);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_9);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_10);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_11);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_12);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_13);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_14);
    LPLD_CAN_Enable_Interrupt(canx,MB_NUM_15);
    //Negate the HALT bit in MCR
    
    //只有在冻结模式下才能配置,配置完推出冻结模式
    CAN_MCR_REG(canptr) &= ~(CAN_MCR_HALT_MASK);
    //等待直到退出冻结模式
    while( CAN_MCR_REG(canptr) & CAN_MCR_FRZACK_MASK);    
    //等到不在冻结模式,休眠模式或者停止模式
    while((CAN_MCR_REG(canptr) & CAN_MCR_NOTRDY_MASK));
    //Starting with the last event, FlexCAN attempts to synchronize to the CAN bus.
    return 1;
}