I met a problem when I was trying to send messages using MSCAN module in 9S12XET256. I read it in the datesheet that CAN0TFLG would be set by hardware ,but when I put the data in the buffer, I cleared the flag,but the flag did not be set ,so the process was stopped in finding an empty buffer after i sent data 3 times.I donnot know why?
code:
########################################################
CAN.h
#########################################################
#ifndef _CAN_H_
#define _CAN_H_
#include "MC9S12XET256.h"
#define BOOL byte
//宏定义busclk == 16M
#define busclk 16
//宏定义busclk == 8M
//#define busclk 8
//定义结构体
typedef struct{
dword Tx_ID;
byte Tx_Prio;
byte Tx_Length;
byte Tx_Data[8];
} MSCAN_T_Msg;
typedef struct{
dword Rx_ID;
byte Rx_Length;
byte Rx_Data[8];
} MSCAN_R_Msg;
//函数声明
//extern void createMsg(MSCAN_T_Msg *Msg,dword id,byte d[8],byte length,byte prio) ;
extern void setBaudRate(word baud_rate);
extern BOOL CAN_Send(MSCAN_T_Msg Msg);
//extern BOOL CAN1_Send(MSCAN_T_Msg Msg);
extern BOOL CAN_Receive(MSCAN_R_Msg *msg);
extern void CAN_Init(byte loop);
//extern void CAN1_Init(byte loop);
#endif
###########################################################################
CAN.c
###########################################################################
//********************************************************
// 需先在CAN.h中设置总线时钟,默认设置16M
//********************************************************
#include "CAN.h"
//MSCAN_R_Msg RxMsg;
//MSCAN_T_Msg TxMsg;
//**********************************************************
//MSCAN 初始化函数
//**********************************************************
void CAN_Init(byte loop)
{
MODRR_MODRR0 = 0;
MODRR_MODRR1 = 1; //选择PM0 PM1作为CAN0的引脚
if (loop) { //如果 loop = 1;使能环回自测
CAN0CTL1 = CAN0CTL1_LOOPB_MASK;
}
CAN0CTL0 = CAN0CTL0_INITRQ_MASK;//进入初始化模式
while(!CAN0CTL1_INITAK); //等待初始化响应
CAN0CTL1 = CAN0CTL1_CANE_MASK;//使能模块,选择晶振(4M)时钟作为时钟源
//setBaudRate(250);
CAN0BTR0 = 0X00;
CAN0BTR1 = 0X1C; //250k
//CANBTR0 = _canbtr0;
//CANBTR0 = CANBTR0_BRP0_MASK+CANBTR0_SJW_MASK;
//波特率2分频,同步跳转宽度4
//CANBTR1 = _canbtr1;
//CANBTR1_TSEG = 3;
//CANBTR1_TSEG = 10; //相位缓冲段SEG1、SEG2长度设置 4,11个Tq
CAN0IDAC_IDAM = 1; //Four 16-bit acceptance filters
CAN0IDAR0 = 0x00;CAN0IDMR0 = 0xFF;
CAN0IDAR1 = 0x00;CAN0IDMR1 = 0xFF;
CAN0IDAR2 = 0x00;CAN0IDMR2 = 0xFF;
CAN0IDAR3 = 0x00;CAN0IDMR3 = 0xFF;
CAN0IDAR4 = 0x00;CAN0IDMR4 = 0xFF;
CAN0IDAR5 = 0x00;CAN0IDMR5 = 0xFF;
CAN0IDAR6 = 0x00;CAN0IDMR6 = 0xFF;
CAN0IDAR7 = 0x00;CAN0IDMR7 = 0xFF; //接受所有的地址的消息
CAN0CTL0_INITRQ = 0; //关闭CAN初始化
while(CAN0CTL1_INITAK) //等待关闭初始化响应
;
// while(!CANCTL0_SYNCH) //等待CAN同步(连到总线是需要判断同步)
// ;
CAN0RFLG_RXF = 1; //清空消息接受缓冲器
CAN0RIER_RXFIE = 1; //使能接收消息中断
}
//**********************************************************
//MSCAN 接收数据函数
//**********************************************************
BOOL CAN_Receive(MSCAN_R_Msg *msg) { //接收8个数据
byte i;
if (CAN0RFLG_RXF){ //如果接收缓冲器满,返回0
return 0;
}
/* if (CANRXIDR1_IDE==0) { //如果是标准格式帧结构
msg->Rx_ID = (word)((CANRXIDR1<<8)+CANRXIDR0);
}
else if(CANRXIDR1_IDE==1){ //如果是扩展格式帧结构
msg->Rx_ID = (CANRXIDR3<<24)+(CANRXIDR2<<16)+(CANRXIDR1<<8)+CANRXIDR0;//MSCAN Receive Identifier Register 0
}*/
msg->Rx_ID = (CAN0RXIDR3<<24)+(CAN0RXIDR2<<16)+(CAN0RXIDR1<<8)+CAN0RXIDR0;//MSCAN Receive Identifier Register 0
msg->Rx_Length= CAN0RXDLR;
for(i=0;i<msg->Rx_Length;i++) {
msg->Rx_Data[i] = *(&(CAN0RXDSR0)+i);
}
CAN0RFLG = CAN0RFLG_RXF_MASK;
return (1);
}
//**********************************************************
//MSCAN 发送数据函数
//**********************************************************
BOOL CAN_Send(MSCAN_T_Msg Msg) {
byte i,Txbuf_empty_flag=0;
if(Msg.Tx_Length>8) //如果Msg的长度大于8,返回0
return (0);
//if(CANCTL0_SYNCH!= 0 ) //如果没有同步,返回0
// return (0);
while (!(CAN0TFLG & (0x01<<Txbuf_empty_flag))) {
Txbuf_empty_flag++;
if(Txbuf_empty_flag >= 3)
Txbuf_empty_flag = 0;
} //从三个传输缓冲器中找一个空的
CAN0TBSEL = (0x01<<Txbuf_empty_flag);
//选择可用的buffer
CAN0TXIDR0 = (byte)(Msg.Tx_ID);
CAN0TXIDR1 = (byte)(Msg.Tx_ID>>8);
CAN0TXIDR2 = (byte)(Msg.Tx_ID>>16);
CAN0TXIDR3 = (byte)(Msg.Tx_ID>>24);
CAN0TXDLR = Msg.Tx_Length;
CAN0TXTBPR = Msg.Tx_Prio;
for(i=0;i<Msg.Tx_Length;i++) {
*(&CAN0TXDSR0 + i) = Msg.Tx_Data[i];
}
CAN0TFLG =(0x01<<Txbuf_empty_flag); //清除标志位
while((CAN0TFLG&(0x01<<Txbuf_empty_flag))== 1);
return (1);
}
#########################################################################
main.c
##########################################################################
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include "CAN.h"
void delay() {
int i,j;
for(i=0;i<500;i++)
for(j=0;j<500;j++);
}
MSCAN_R_Msg r_msg;
MSCAN_T_Msg t_msg;
unsigned char i;
byte *t;
void main(void) {
PORTA = 0XFF;
DDRA = 0XFF;/* put your own code here */
//PLL_SetBusClk_16M();
//setBusClk16M_4OSC();
//Timer_OC_Init();
CAN_Init(1);
CAN1RIER_RXFIE = 1;
EnableInterrupts;
for(;;) {
(void)CAN_Send(t_msg);
delay();
PORTA_PA0 = ~PORTA_PA0;
_FEED_COP(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}
/*
#pragma CODE_SEG NON_BANKED
interrupt VectorNumber_Vcan0rx void CAN_Receice_ISR(void) {
DisableInterrupts;
CAN0RFLG_RXF = 1;
(void)CAN_Receive(&r_msg);
t_msg.Tx_ID = r_msg.Rx_ID;
t_msg.Tx_Length = r_msg.Rx_Length;
if(r_msg.Rx_Data[7] == 0x01) {
PORTA =~PORTA;
for( i=0;i<8;i++) {
t = t_msg.Tx_Data+i;
*t= r_msg.Rx_Data[i];
}
(void)CAN_Send(t_msg);
}
EnableInterrupts;
}
#pragma CODE_SEG DEFAULT
*/
Hi Zhanqiang,
In general, TX flag is set again, when CAN module detect acknowledge.
So, if there isn’t node on bus who acknowledge data from MSCAN module, TX buffer will be not freed.
Note: Be careful, MODRR registers could be written just once in normal mode. So, all you configuration for one MODRR register must be written by single command.
I cannot recommend to using CAN send function inside CAN RX interrupt due to potential problem with selecting TX buffer. This way, we could call CAN_Send() inside CAN_Send() function. So at least one of CAN_Send() will failure in that case.
I hope it helps you.
Best Regards
Radek