本文记录用ti的TMS320F28379D LaunchPad调CAN通讯的过程,最后会给出代码。
用的是CCS11.1版本加上ti的C2000ware的库。
一开始用的是C2000ware库中的can_ex4_simple_transmit中的程序,把复用引脚改为开发板上的GPIO12和GPIO17引脚,上位机一直采集不到。排除了很久,发现CAN的比特率不对,跟程序设置的不一样。看这个帖子有感,想查一查系统的主频是多少。TI C2000WARE官方例程时钟配置的坑(针对TMS320F28379D LaunchPad XL) / DSP / WhyCan Forum(哇酷开发者社区)
系统的延迟函数DEVICE_DELAY_US()是以微妙为单位的,推测内层函数是汇编写的(时间测量比较准确),所以用它跟GPIO配合,测量系统的频率。
Device_initGPIO();
GPIO_setPadConfig(61, GPIO_PIN_TYPE_PULLUP); // Enable pullup on GPIO6 先启动输入上拉
GPIO_setPinConfig(GPIO_61_GPIO61); //配置复用
GPIO_setDirectionMode(61, GPIO_DIR_MODE_OUT); // GPIO6 = output 配置IO口的输入以及输出方向
while(1)
{
GPIO_writePin(61, 1); // Load output latch
DEVICE_DELAY_US(50000);
GPIO_writePin(61, 0); // Load output latch
DEVICE_DELAY_US(50000);
}
用示波器测量GPIO61口的波形,示波器测量图见下图。
从示波器中可以看到△x=100ms,即GPIO61口输出的高电平或者低电平的时间为100ms,而程序中的延迟函数设置的为50ms,由此可以看出系统主频慢了1/2.
从系统的初始化函数Device_init()(按住ctrl键点击这个函数之中)中找到SysCtl_setClock(DEVICE_SETCLOCK_CFG)语句,在按ctrl进入DEVICE_SETCLOCK_CFG,将参数改为下图所示。
上图依次为系统的外部主频大小、PLL的倍数。改变上述系统时钟参数之后,看GPIO口的输出波形,见下图。
看到GPIO口的输出波形高电平以及低电平持续时间变成了50ms,跟延时设定的时间一样。可以推断出系统原来的主频只为100Mhz,没有达到它可以运行的最高200Mhz。
回到can通信,当我把系统时钟按照上述步骤修改成主频为200Mhz的时候,C2000ware中的can_ex4_simple_transmit就可以在上位机采集到发送的数据。
下面是用开发板GPIO12和GPIO17做CANB发送引脚的通讯,250ms发送一次,接收中断,标志符为0x1,接收的数据可以在rxMsgData数组中看到。记得一定要按照上述步骤把系统时钟频率改掉!!!
#include "driverlib.h"
#include "device.h"
//
// Defines
//
#define MSG_DATARX_LENGTH 0 // "Don't care" for a Receive mailbox
#define MSG_DATATX_LENGTH 8
#define RX_MSG_OBJ_ID 10 // Use mailbox 1
#define TX_MSG_OBJ_ID 1
//
// Globals
//
uint16_t txMsgData[8];
uint16_t rxMsgData[8];
__interrupt void canbISR(void); // Receive interrupt for CAN-B.
// No Transmit interrupt for CAN-A
//
// Main
//
void main(void)
{
//
// Initialize device clock and peripherals
//
Device_init();
//
// Initialize GPIO
//
Device_initGPIO();
//
// Configure GPIO pins for CANTX/CANRX
//
GPIO_setPinConfig(GPIO_12_CANTXB);
GPIO_setPinConfig(GPIO_17_CANRXB);
//
// Configure GPIO pin which is toggled upon message reception
//
// GPIO_setPadConfig(34U, GPIO_PIN_TYPE_STD);
// GPIO_setDirectionMode(34U, GPIO_DIR_MODE_OUT);
//
// Initialize the CAN controller
//
CAN_initModule(CANB_BASE);
//
// Set up the CAN bus bit rate to 500kHz for each module
// Refer to the Driver Library User Guide for information on how to set
// tighter timing control. Additionally, consult the device data sheet
// for more information about the CAN module clocking.
//
CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
CAN_enableInterrupt(CANB_BASE, CAN_INT_IE0 | CAN_INT_ERROR |
CAN_INT_STATUS);
//
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
//
Interrupt_initModule();
//
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
//
Interrupt_initVectorTable();
//
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
//
//
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
// This registers the interrupt handler in PIE vector table.
//
Interrupt_register(INT_CANB0, &canbISR);
//
// Enable the CAN-B interrupt signal
//
Interrupt_enable(INT_CANB0);
//
// Set GLBINT0_EN bit in CAN_GLB_INT_EN register
//
CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
//
// Start CAN module A operations
//
//
// Initialize the receive message object used for receiving CAN messages.
// Message Object Parameters:
// CAN Module: A
// Message Object ID Number: 1
// Message Identifier: 0x1
// Message Frame: Standard
// Message Type: Receive
// Message ID Mask: 0x0
// Message Object Flags: None
// Message Data Length: "Don't care" for a Receive mailbox
//
CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, 0x1,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATARX_LENGTH);
CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID, 0x1,
CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 1,
CAN_MSG_OBJ_TYPE_TX, MSG_DATATX_LENGTH);
CAN_startModule(CANB_BASE);
txMsgData[0] = 0x01;
txMsgData[1] = 0x23;
txMsgData[2] = 0x45;
txMsgData[3] = 0x67;
txMsgData[4] = 0x89;
txMsgData[5] = 0xAB;
txMsgData[6] = 0xCD;
txMsgData[7] = 0xEF;
//
EINT;
ERTM;
// Start reception - Just wait for data from another node
//
while(1)
{
CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID, MSG_DATATX_LENGTH, txMsgData);
DEVICE_DELAY_US(2000000);
}
}
__interrupt void
canbISR(void)
{
uint32_t status;
//
// Read the CAN-B interrupt status (in the CAN_INT register) to find the
// cause of the interrupt
//
status = CAN_getInterruptCause(CANB_BASE);
//
// If the cause is a controller status interrupt, then get the status.
// During first iteration of every ISR execution, status = 0x8000,
// which simply means CAN_ES != 0x07.
//
if(status == CAN_INT_INT0ID_STATUS)
{
//
// Read the controller status. This will return a field of status
// error bits that can indicate various errors. Error processing
// is not done in this example for simplicity. Refer to the
// API documentation for details about the error status bits.
// The act of reading this status will clear the interrupt.
//
status = CAN_getStatus(CANB_BASE); // Return CAN_ES value.
//
// Now status = 0x00000010, indicating RxOK.
//
//
// Check to see if an error occurred.
//
if(((status & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_MSK) &&
((status & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_NONE))
{
//
// Set a flag to indicate some errors may have occurred.
//
}
}
//
// Check if the cause is the CAN-B receive message object 1. Will be skipped
// in the first iteration of every ISR execution
//
else if(status == RX_MSG_OBJ_ID)
{
//
// Get the received message
//
CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, rxMsgData);
//
// Getting to this point means that the RX interrupt occurred on
// message object 1, and the message RX is complete. Clear the
// message object interrupt.
//
CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
//
// Increment a counter to keep track of how many messages have been
// received. In a real application this could be used to set flags to
// indicate when a message is received.
//
}
//
// If something unexpected caused the interrupt, this would handle it.
//
else
{
//
// Spurious interrupt handling can go here.
//
}
//
// Clear the global interrupt flag for the CAN interrupt line
//
CAN_clearGlobalInterruptStatus(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
//
// Acknowledge this interrupt located in group 9
//
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}
最后附上上位机发送接收成功图片