在线时间0 小时
UID238553
注册时间2010-11-1
NXP金币0
该用户从未签到
注册会员

- 积分
- 77
- 最后登录
- 1970-1-1
|
1. 最近在做K61的CAN驱动,但是不能正常工作。我的做法是,在外挂节点测试发送的时候,在can的CAN_Init函数就会进入到严重硬件错误中。代码如下:
void LPLD_CAN_Init(CAN_InitTypeDef can_init_structure)
{
uint8 i;
CAN_MemMapPtr canx = can_init_structure.CAN_Canx;
uint32 baud = can_init_structure.CAN_BaudRate;
uint8 mask_mode = can_init_structure.CAN_RxMaskMode;
PortPinsEnum_Type tx_pin = can_init_structure.CAN_TxPin;
PortPinsEnum_Type rx_pin = can_init_structure.CAN_RxPin;
OSC_CR |= OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK;
if(canx == CAN0_BASE_PTR)
SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0_MASK;
else
SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1_MASK;
if(canx == CAN0_BASE_PTR)
{
if(tx_pin == PTF0)//CAN0_TX
{
PORTF_PCR0 = PORT_PCR_MUX(2);
}
else if(tx_pin == PTB18)
{
PORTB_PCR18 = PORT_PCR_MUX(2);
}
else
{
PORTA_PCR12 = PORT_PCR_MUX(2);
}
if (rx_pin == PTF1)//CAN0_RX
{
PORTF_PCR1 = PORT_PCR_MUX(2);
}
else if(rx_pin == PTB19)//CAN0_RX
{
PORTB_PCR19 = PORT_PCR_MUX(2);
}
else
{
PORTA_PCR13 = PORT_PCR_MUX(2);
}
}
else
{
if(tx_pin == PTF25)//CAN1_TX
{
PORTF_PCR25 = PORT_PCR_MUX(2);
}
else if(tx_pin == PTC17)
{
PORTC_PCR17 = PORT_PCR_MUX(2);
}
else
{
PORTE_PCR24 = PORT_PCR_MUX(2);
}
if(rx_pin == PTF24)//CAN1_RX
{
PORTF_PCR24 = PORT_PCR_MUX(2);
}
else if(rx_pin == PTC16)
{
PORTC_PCR16 = PORT_PCR_MUX(2);
}
else
{
PORTE_PCR25 = PORT_PCR_MUX(2);
}
}
//禁止CAN外设
//canx->MCR |= CAN_MCR_MDIS_MASK;
//只有在LPM_ACK = 1情况下才可以选择钟源
canx->CTRL1 |= CAN_CTRL1_CLKSRC_MASK; //选择peripheral clock作为CAN外设的时钟源
//设置此位必须在CAN停止模式下
//在时钟初始化完毕和CAN总线使能完毕后,
//单片机自动进入冻结模式
//只有在冻结模式下才能配置大多数CAN总线寄存器
//使能冻结模式
canx->MCR |= CAN_MCR_HALT_MASK;
canx->MCR |= CAN_MCR_FRZ_MASK;
canx->MCR &= ~CAN_MCR_MDIS_MASK;
while(!(canx->MCR & CAN_MCR_LPMACK_MASK));
//进行软件复位
canx->MCR ^= CAN_MCR_SOFTRST_MASK;
while(canx->MCR & CAN_MCR_SOFTRST_MASK);
//等待进入冻结模式
while(!(canx->MCR & CAN_MCR_FRZACK_MASK));
if(mask_mode == CAN_MSGOBJ_GLOBAL_MASKING)
{
canx->MCR &= ~CAN_MCR_IRMQ_MASK; //使能全局匹配寄存器禁止单独匹配
}
else
{
canx->MCR |= CAN_MCR_IRMQ_MASK; //使能Msg单独匹配
}
canx->MCR |= CAN_MCR_SUPV_MASK ; //设置成管理模式
canx->MCR |= CAN_MCR_SRXDIS_MASK ; //禁止自我接收
canx->MCR &= ~CAN_MCR_WRNEN_MASK; //不产生警告中断
canx->MCR &= ~CAN_MCR_RFEN_MASK ; //禁止接收FIFO
canx->MCR &= ~CAN_MCR_AEN_MASK; //禁止Abort
canx->MCR &= ~CAN_MCR_LPRIOEN_MASK;//禁止本地优先
//配置相关的寄存器
canx->CTRL2 |= CAN_CTRL2_EACEN_MASK; //接收邮箱过滤IDE匹配,RTR不匹配
canx->CTRL2 &= ~CAN_CTRL2_RRS_MASK; //不自动产生远程请求帧产生
canx->CTRL2 |= CAN_CTRL2_MRP_MASK; //ID首先从邮箱中匹配
//canx->CTRL1 |= CAN_CTRL1_LBUF_MASK; //发送的时候从低Msg开始
canx->CTRL1 &= ~CAN_CTRL1_LBUF_MASK; //发送的时候从低优先级发送
//canx->CTRL1 |= CAN_CTRL1_LPB_MASK; //loop 模式,用于测试
canx->CTRL1 &= ~CAN_CTRL1_LPB_MASK; //使用正常模式
//设置CAN总线通信的波特率
LPLD_CAN_SetBaudRate(canx,baud);
//清空CAN自由计数器
canx->TIMER = 0x0000;
//将MB_MAX个邮箱缓冲区内容清0
for(i = 0;i < MSG_MAX_NO; i++)
{
canx->MB.CS = 0x00000000;
canx->MB.ID = 0x00000000;
canx->MB.WORD0 = 0x00000000;
canx->MB.WORD1 = 0x00000000;
}
//清除64个邮箱的标志位
//canx->IFLAG1 = 0xFFFFFFFF;
//canx->IFLAG2 = 0xFFFFFFFF;
//禁止邮箱中断
//canx->IMASK1 = 0x00000000;
//canx->IMASK2 = 0x00000000;
/*
如果MCR的IRMQ为1,表示每个邮箱都可以单独进行ID匹配
注意:如果是low cost MCUs(低配置的MCU),没有单独匹配这项功能。
1\ID匹配会选择free to receive状态的邮箱作为胜者,
获胜的邮箱可以从接收缓冲区内将接收的帧 Move in 到MB中;
2\如果出现ID号相同的邮箱,会首先从序号低的邮箱进行匹配,如果
低序号邮箱是non free to receive状态,那么匹配过程将会查找
下一个邮箱直到找到free to receive状态且ID相同的邮箱;
3\如果ID号相同的邮箱都处于non free to receive状态,那么匹配过程
将停止在最后一个有相同ID的邮箱位置,将帧Move in 到MB中并且将该邮
箱的状态设置成OVERRUN。
RXIMR存储在单片机的RAM中,只有在CAN冻结模式下可写。
此时CANx_RXMGMASK、CANx_RX14MASK、CANx_RX15MASK不起作用
*/
for(i = 0;i < MSG_MAX_NO; i++)
{
canx->RXIMR = 0x1FFFFFFF;//设置邮箱29位全部屏蔽
}
/*
如果MCR的IRMQ为0,表示使用全局匹配寄存器进行匹配,
此时CANx_RXMGMASK、CANx_RX14MASK、CANx_RX15MASK起作用;
CANx_RXMGMASK管理除CANx_RX14MASK、CANx_RX15MASK以外的所有Msg;
ID匹配过程会停止在找到的第一个ID相同的邮箱位置,不管该邮箱是否处于
free to receive状态。
*/
canx->RXMGMASK = 0x1FFFFFFF; //29位ID全部匹配
canx->RX14MASK = 0x1FFFFFFF;
canx->RX15MASK = 0x1FFFFFFF;
canx->MCR &= ~CAN_MCR_FRZ_MASK; //退出冻结模式
//等待直到退出冻结模式
while( canx->MCR & CAN_MCR_FRZACK_MASK);
//只有在冻结模式下才能配置,配置完推出冻结模式
canx->MCR &= ~(CAN_MCR_HALT_MASK);
//等到不在冻结模式,休眠模式或者停止模式
while( canx->MCR & CAN_MCR_NOTRDY_MASK);
//使能CAN外设
canx->MCR &= ~CAN_MCR_MDIS_MASK;
}
以上是拉普兰德公司的驱动,因为我使用的是k61所以做了部分修改,就是在管脚设置那里。中间的
//清除64个邮箱的标志位
//canx->IFLAG1 = 0xFFFFFFFF;
//canx->IFLAG2 = 0xFFFFFFFF;
//禁止邮箱中断
//canx->IMASK1 = 0x00000000;
//canx->IMASK2 = 0x00000000;
这几句如果不去掉会进入严重错误中断。但我不明白为什么。
2.我有点不明白CAN0_IMASK1,CAN0_IMASK2的作用。CAN0模块一共只有16个message buffer,那么为何要用CAN0_IMASK1和CAN0_IMASK2两个寄存器呢。
3.我调用发送函数进行发送,发现之后CS的状态一直是0b1100,无法变为为0b1000。我觉得就是未执行发送。但是这时候自由运行定时器(CAN0_TIMER)一直在跑,应该模块是工作了。我的发送函数如下:
uint8 LPLD_CAN_TransmitMessage(CAN_MSGOBJ_InitTypeDef can_msg_init_structure, CAN_MessageFormat_TypeDef *can_tx_msg )
{
uint8 request;
uint8 msg_num_temp = can_msg_init_structure.CAN_MsgNum;
CAN_MemMapPtr canx_ptr = can_msg_init_structure.CAN_Canx;
uint32 message_id = can_tx_msg->CAN_MsgID;
uint8 *in_data_buffer = can_tx_msg->CAN_MsgDataBuffer;
uint8 in_data_length = can_tx_msg->CAN_MsgDataLength;
//如果发送Msg缓冲区中的CODE不等于CAN_MSGOBJ_TX_UNCONDITIONAL
if( LPLD_CAN_GetMsgCode(canx_ptr,msg_num_temp) != CAN_MSGOBJ_TX_UNCONDITIONAL)
{
//向发送Msg缓冲区中的CODE中写INACTIVE命令
canx_ptr->MB[msg_num_temp].CS |= CAN_MB_CS_CODE(CAN_MSGOBJ_TX_INACTIVE);
//设置Msg的ID
LPLD_CAN_SetMsgID(canx_ptr,msg_num_temp,message_id);
//向Msg中写入要发送的数据
LPLD_CAN_WriteData(canx_ptr,msg_num_temp,in_data_length,in_data_buffer);
//设置Msg的长度
LPLD_CAN_SetMsgLength(canx_ptr,msg_num_temp,in_data_length);
//向发送Msg缓冲区中的CODE中写TX_UNCONDITIONAL命令,等待发送完成
canx_ptr->MB[msg_num_temp].CS |= CAN_MB_CS_CODE(CAN_MSGOBJ_TX_UNCONDITIONAL);
//如果开启发送中断,发送完毕后会触发中断
request = 1;
}
else
{
request = 0;
}
return (request);
}
|
|