本例通过连续高速传输数据来测试eCAN。验证接收到的数据。任何错误都会被标记。MBX0传输给MBX16, MBX1传输给MBX17,以此类推....
本例以CAN模块自检模式为例。即,传输/接收发生在模块内部(甚至所需的acknowledge也是在模块内部生成的)。因此,不需要一个CAN收发器来运行这个特定的测试用例,并且在CAN引脚/总线中看不到任何活动。因为一切都是内部的,不需要120欧姆的终端电阻。请注意,一个真实的CAN应用程序需要一个CAN收发器和终端电阻在总线的两端。
void main(void)
{
Uint16 j;
//eCAN控制寄存器需要使用32位的读/写访问。因此,我们将为这个示例创建一组影子寄存器。这些影子寄存器将用于确保访问是32位而不是16位。
struct ECAN_REGS ECanaShadow;
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2803x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Initialize GPIO:
// This example function is found in the DSP2803x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio(); // Skipped for this example
// For this example, configure CAN pins using GPIO regs here
// This function is found in DSP2803x_ECan.c
InitECanaGpio();
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2803x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
//用指向shell中断服务例程(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使在这个例子中没有使用中断。这对于调试非常有用。
// The shell ISR routines are found in DSP2803x_DefaultIsr.c.
// This function is found in DSP2803x_PieVect.c.
InitPieVectTable();
// Step 4. Initialize all the Device Peripherals:
// Not required for this example
// Step 5. User specific code, enable interrupts:
MessageReceivedCount = 0;
ErrorCount = 0;
PassCount = 0;
InitECana(); // Initialize eCAN-A module
// Mailboxes can be written to 16-bits or 32-bits at a time
// Write to the MSGID field of TRANSMIT mailboxes MBOX0 - 15
ECanaMboxes.MBOX0.MSGID.all = 0x9555AAA0;
ECanaMboxes.MBOX1.MSGID.all = 0x9555AAA1;
ECanaMboxes.MBOX2.MSGID.all = 0x9555AAA2;
ECanaMboxes.MBOX3.MSGID.all = 0x9555AAA3;
ECanaMboxes.MBOX4.MSGID.all = 0x9555AAA4;
ECanaMboxes.MBOX5.MSGID.all = 0x9555AAA5;
ECanaMboxes.MBOX6.MSGID.all = 0x9555AAA6;
ECanaMboxes.MBOX7.MSGID.all = 0x9555AAA7;
ECanaMboxes.MBOX8.MSGID.all = 0x9555AAA8;
ECanaMboxes.MBOX9.MSGID.all = 0x9555AAA9;
ECanaMboxes.MBOX10.MSGID.all = 0x9555AAAA;
ECanaMboxes.MBOX11.MSGID.all = 0x9555AAAB;
ECanaMboxes.MBOX12.MSGID.all = 0x9555AAAC;
ECanaMboxes.MBOX13.MSGID.all = 0x9555AAAD;
ECanaMboxes.MBOX14.MSGID.all = 0x9555AAAE;
ECanaMboxes.MBOX15.MSGID.all = 0x9555AAAF;
// Write to the MSGID field of RECEIVE mailboxes MBOX16 - 31
ECanaMboxes.MBOX16.MSGID.all = 0x9555AAA0;
ECanaMboxes.MBOX17.MSGID.all = 0x9555AAA1;
ECanaMboxes.MBOX18.MSGID.all = 0x9555AAA2;
ECanaMboxes.MBOX19.MSGID.all = 0x9555AAA3;
ECanaMboxes.MBOX20.MSGID.all = 0x9555AAA4;
ECanaMboxes.MBOX21.MSGID.all = 0x9555AAA5;
ECanaMboxes.MBOX22.MSGID.all = 0x9555AAA6;
ECanaMboxes.MBOX23.MSGID.all = 0x9555AAA7;
ECanaMboxes.MBOX24.MSGID.all = 0x9555AAA8;
ECanaMboxes.MBOX25.MSGID.all = 0x9555AAA9;
ECanaMboxes.MBOX26.MSGID.all = 0x9555AAAA;
ECanaMboxes.MBOX27.MSGID.all = 0x9555AAAB;
ECanaMboxes.MBOX28.MSGID.all = 0x9555AAAC;
ECanaMboxes.MBOX29.MSGID.all = 0x9555AAAD;
ECanaMboxes.MBOX30.MSGID.all = 0x9555AAAE;
ECanaMboxes.MBOX31.MSGID.all = 0x9555AAAF;
//将邮箱0-15配置为Tx, 16-31配置为Rx,因为这个写入是对整个寄存器(而不是位域),所以不需要影子寄存器。
// Enable all Mailboxes */
// Since this write is to the entire register (instead of a bit
// field) a shadow register is not required.
ECanaRegs.CANME.all = 0xFFFFFFFF;
// Specify that 8 bits will be sent/received
ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX2.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX3.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX4.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX5.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX6.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX7.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX8.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX9.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX10.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX11.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX12.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX13.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX14.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX15.MSGCTRL.bit.DLC = 8;
// Write to the mailbox RAM field of MBOX0 - 15
ECanaMboxes.MBOX0.MDL.all = 0x9555AAA0;
ECanaMboxes.MBOX0.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX1.MDL.all = 0x9555AAA1;
ECanaMboxes.MBOX1.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX2.MDL.all = 0x9555AAA2;
ECanaMboxes.MBOX2.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX3.MDL.all = 0x9555AAA3;
ECanaMboxes.MBOX3.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX4.MDL.all = 0x9555AAA4;
ECanaMboxes.MBOX4.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX5.MDL.all = 0x9555AAA5;
ECanaMboxes.MBOX5.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX6.MDL.all = 0x9555AAA6;
ECanaMboxes.MBOX6.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX7.MDL.all = 0x9555AAA7;
ECanaMboxes.MBOX7.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX8.MDL.all = 0x9555AAA8;
ECanaMboxes.MBOX8.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX9.MDL.all = 0x9555AAA9;
ECanaMboxes.MBOX9.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX10.MDL.all = 0x9555AAAA;
ECanaMboxes.MBOX10.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX11.MDL.all = 0x9555AAAB;
ECanaMboxes.MBOX11.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX12.MDL.all = 0x9555AAAC;
ECanaMboxes.MBOX12.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX13.MDL.all = 0x9555AAAD;
ECanaMboxes.MBOX13.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX14.MDL.all = 0x9555AAAE;
ECanaMboxes.MBOX14.MDH.all = 0x89ABCDEF;
ECanaMboxes.MBOX15.MDL.all = 0x9555AAAF;
ECanaMboxes.MBOX15.MDH.all = 0x89ABCDEF;
// Since this write is to the entire register (instead of a bit
// field) a shadow register is not required.
EALLOW;
ECanaRegs.CANMIM.all = 0xFFFFFFFF;
// Configure the eCAN for self test mode
// Enable the enhanced features of the eCAN.
EALLOW;
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.STM = 1; // Configure CAN for self-test mode
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
EDIS;
// Begin transmitting
for(;;)
{
ECanaRegs.CANTRS.all = 0x0000FFFF; // Set TRS for all transmit mailboxes
while(ECanaRegs.CANTA.all != 0x0000FFFF ) {} // Wait for all TAn bits to be set..
ECanaRegs.CANTA.all = 0x0000FFFF; // Clear all TAn
MessageReceivedCount++;
//Read from Receive mailboxes and begin checking for data */
for(j=16; j<32; j++) // Read & check 16 mailboxes
{
mailbox_read(j); // This func reads the indicated mailbox data
mailbox_check(TestMbox1,TestMbox2,TestMbox3); // Checks the received data
}
}
}
MSGID寄存器
标识符扩展。IDE位的特性会随着AMI位的值而变化。
当AMI = 1时:
1.
接收邮箱的IDE位是“不在乎”。
接收邮箱的IDE位被传输的消息的IDE位覆盖。
2.
必须满足过滤条件才能接收消息。
3.
被比较的比特数是被传输消息的IDE位值的函数。
当AMI = 0时:
1.
接收邮箱的IDE位决定要比较的位数。
2.
过滤不适用。
msgid必须匹配位对位才能接收消息。
当AMI = 1时:
IDE = 1: RECEIVED消息具有扩展标识符
IDE = 0: RECEIVED消息有一个标准标识符
当AMI = 0时:
IDE = 1:待接收消息必须具有扩展标识符
IDE = 0:待接收消息必须有一个标准标识符。
接收掩码启用位。AME仅用于接收邮箱。自动回复(AAM[n]=1, CANMD[n]=0)邮箱不能设置,否则邮箱行为未定义。
这个位不会被消息接收修改。
1使用对应的接收掩码。
0没有使用接收掩码,所有标识符位必须匹配才能接收消息
自动应答模式位。此位仅对配置为传输的邮件邮箱有效。对于接收邮箱,此位没有作用:邮箱始终配置为正常接收操作。
这个位不会被消息接收修改。
1自动接听模式。如果接收到匹配的远程请求,CAN模块通过发送邮箱的内容来响应远程请求。
0正常发送模式。邮箱不回复远程请求。接收远程请求帧对消息邮箱没有影响。
消息标识符1在标准标识符模式下,如果IDE位(MSGID.31) = 0,则消息标识符存储在ID.28:18位中。在这种情况下,位ID.17:0没有意义。
在扩展标识模式下,如果IDE位(MSGID.31) = 1,则消息标识存储在ID.28:0位中。
CANMDL寄存器和CANMDH寄存器
邮箱的8个字节用来存储CAN消息的数据字段。DBO (MC.10)的设置决定了存储数据的顺序。数据从CAN总线传输或接收,从0字节开始。
•当DBO (MC.10) = 1时,数据存储或读取从CANMDL寄存器的最低有效字节开始,到CANMDH寄存器的最高有效字节结束。
•当DBO (MC.10) = 0时,数据存储或读取从CANMDL寄存器的最高有效字节开始,到CANMDH寄存器的最低有效字节结束。
只有配置邮箱n进行传输(CANMD[n] (CANMD.31-0)=0)或关闭邮箱(CANME[n] (CANME.31-0)=0),寄存器CANMDL(n)和CANMDH(n)才能写入。如果TRS[n] (TRS.31-0)=1,则寄存器CANMDL(n)和CANMDH(n)不能写入,除非CDR (MC.8)=1,且MBNR (MC.4-0)设置为n。这些设置也适用于应答模式(AAM (MSGID.29)=1)配置的消息对象。
CANMIM寄存器
每个邮箱都有一个可用的中断标志。这可以是接收中断,也可以是传输中断,具体取决于邮箱的配置。该寄存器受EALLOW保护。
邮箱中断屏蔽。上电后,所有中断掩码位被清除,中断被禁用。这些位允许单独屏蔽任何邮箱中断。
1启用邮箱中断。如果消息已成功传输(对于发送邮箱),或者消息已接收而没有任何错误(对于接收邮箱),则会产生中断。
0邮箱中断被禁用。
CANMC寄存器
自我测试模式。该位受EALLOW保护。
1 模块处于自检模式。在这种模式下,CAN模块产生自己的确认(ACK)信号,从而可以在没有总线连接模块的情况下进行操作。消息不发送,而是回读并存储在适当的邮箱中。收到的帧的MSGID不存储在STM的MBR中。
注意:在STM中,如果没有配置MBX接收传输的帧,那么该帧将被存储在MBX0中,即使MBX0没有配置接收操作。如果将lam配置为某些邮箱可以接收和存储数据帧,则将丢失不满足任何接收邮箱的接收掩码过滤条件的数据帧。
0 模块处于正常模式。
CANTRS寄存器
当邮箱n准备传输时,CPU应该将TRS[n]位设置为1以启动传输。
这些位通常由CPU设置,并由CAN模块逻辑清除。CAN模块可以为远程帧请求设置这些位。当传输成功或中止时,这些位被重置。
如果将邮箱配置为接收邮箱,则CANTRS中对应的位将被忽略,除非接收邮箱配置为处理远程帧。如果设置了接收邮箱的TRS[n]位,则不会忽略接收邮箱的TRS[n]位。因此,设置了RTR的接收邮箱可以发送远端帧,只要设置了接收邮箱的TRS位。一旦远端帧被发送,TRS[n]位被CAN模块清除。因此,可以使用同一个邮箱从另一种模式请求数据帧。如果CPU尝试设置位,而eCAN模块尝试清除位,则该位被设置。
设置CANTRS[n]导致特定的消息n被发送。可以同时设置多个位。因此,所有设置了TRS位的消息依次传输,从拥有最高邮箱号(=最高优先级)的邮箱开始,除非TPL位另有规定。
CANTRS中的位是通过从CPU写入1来设置的。写一个0没有影响。上电后,所有位被清除。
1设置TRSn发送消息到该邮箱。可以同时设置几个比特位,并依次传送所有消息。
0没有操作
//这个函数读取邮箱号(MBXnbr)所指示的内容。
void mailbox_read(int16 MBXnbr)
{
volatile struct MBOX *Mailbox;
Mailbox = &ECanaMboxes.MBOX0 + MBXnbr;
TestMbox1 = Mailbox->MDL.all; // = 0x9555AAAn (n is the MBX number)
TestMbox2 = Mailbox->MDH.all; // = 0x89ABCDEF (a constant)
TestMbox3 = Mailbox->MSGID.all;// = 0x9555AAAn (n is the MBX number)
} // MSGID of a rcv MBX is transmitted as the MDL data.
void mailbox_check(int32 T1, int32 T2, int32 T3)
{
if((T1 != T3) || ( T2 != 0x89ABCDEF))
{
ErrorCount++;
}
else
{
PassCount++;
}
}
void InitECanaGpio(void)
{
EALLOW;
/* Enable internal pull-up for the selected CAN pins */
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.
GpioCtrlRegs.GPAPUD.bit.GPIO30 = 0; // Enable pull-up for GPIO30 (CANRXA)
GpioCtrlRegs.GPAPUD.bit.GPIO31 = 0; // Enable pull-up for GPIO31 (CANTXA)
/* Set qualification for selected CAN pins to asynch only */
// Inputs are synchronized to SYSCLKOUT by default.
// This will select asynch (no qualification) for the selected pins.
GpioCtrlRegs.GPAQSEL2.bit.GPIO30 = 3; // Asynch qual for GPIO30 (CANRXA)
/* Configure eCAN-A pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be eCAN functional pins.
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1; // Configure GPIO30 for CANRXA operation
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1; // Configure GPIO31 for CANTXA operation
EDIS;
}