本篇开始讲解FlexCAN的使用方法,采用SDK自动生成驱动。
新建工程CAN_Test,具体步骤不再重复,新建完毕,打开Processor Expert界面,在Components Library中添加flexcan,添加时会自动增加辅助模块(若是没有禁用其它版本SDK,则会弹出提示,此处会有多个版本供选择,不同版本兼容性可能有问题)。
添加完,在Components中我们可以看到多了三个组件,其中2个为参考组件。
接下来,我们要进行配置。
1、配置FlexCAN的IO,选中pin_mux模块,然后在Components Inspector - pin_mux中,设置CAN0的收发引脚。
2、配置时钟,选中clockMain1,在Components Inspector - clockMain1中将外设桥时钟设为50MHz。
3、配置CAN,将PE clock source设置为Peripheral clock,为了确保波特率误差小,PE时钟最好不要太低。另外注意,此处不能设置波特率,默认都是500Kbps,若要调整,只能在代码中手动设置,设置方法较为复杂。
其它不做配置,直接生成代码。
我们不使用CAN中断,采用轮询方式,一般为确保实时性,最多使用一个定时器中断作为任务分配计时,不过多使用中断。
由于生成的CAN驱动仍然数据分散的底层驱动,我们将CAN的初始化,发送、接收数据封装成通用函数。
初始化中,数组中波特率默认的都是500Kbps的配置,若要修改波特率,我们调用FLEXCAN_DRV_SetBitrate函数即可,函数的参数要通过波特率计算出分频、同步段、传播段、相位缓冲段1、相位缓冲段2。
这里教大家一个快速设置波特率的方法,假设我们要将波特率设置为250Kbps。我们可以先将PE时钟设置高一倍,例如200MHz,生成代码,在Generated_Code的canCom1.c中找到canCom1_InitConfig0,里面有波特率参数,复制出来,然后将PE设置为100MH,生成代码,再调用FLEXCAN_DRV_SetBitrate函数,将刚刚复制的参数传入,波特率就设置为了250Kbps,其它波特率也类似于此。不过不能整除的可能还是要自行计算。
此处我们保持500Kbps波特率,发送ID为:0x00c18064,只接收ID:0x00a180c8
#define ReceiveCANID 0x00c18064
#define SendCANID 0x00a180c8
void FlexCAN_Initial(void)
{
uint32_t mailbox = 5;
//FLEXCAN_DRV_SetBitrate(INST_CANCOM1,&canCom1_InitConfig0);
FLEXCAN_DRV_Init(INST_CANCOM1,&canCom1_State,&canCom1_InitConfig0); //default is 500K
/*
* CANCLK is Protocol Engine(PE) clock
* CanBaud = CANCLK/(PRESDIV+1)/Tq
* Tq=(1+(PROPSEG+1)+(PSEG1+1)+(PSEG2+1))
* limit:
* 4<=PROPSEG+1+PSEG1+1<=16
* 2<=PSEG2+1<=8
* if CANCLK=100MHz,
* CanBaud=500Kbps, when PRESDIV=9,PROPSEG=7,PSEG1=7,PSEG2=2, RJW=1
* CanBaud=250Kbps, when PRESDIV=24,PROPSEG=7,PSEG1=4,PSEG2=1, RJW=1
* */
//const flexcan_time_segment_t baudrate = {.propSeg=7,.phaseSeg1=4,.phaseSeg2=1,.preDivider=24,.rJumpwidth=1};
//FLEXCAN_DRV_SetBitrate(INST_CANCOM1,&baudrate);
//EDMA_DRV_Init(&dmaController1_State,&dmaController1_InitConfig0,edmaChnStateArray,edmaChnConfigArray,EDMA_CONFIGURED_CHANNELS_COUNT);
flexcan_data_info_t dataInfo =
{
.data_length = 8U,
.msg_id_type = FLEXCAN_MSG_ID_EXT
};
/* Configure RX message buffer with index RX_MSG_ID and RX_MAILBOX */
FLEXCAN_DRV_ConfigRxMb(INST_CANCOM1, mailbox, &dataInfo, 0xc18064);
}
void FlexCAN_SendData(uint8_t * data, uint32_t len)
{
uint32_t mailbox = 0;
/* Set information about the data to be sent
* - 1 byte in length
* - Standard message ID
* - Bit rate switch enabled to use a different bitrate for the data segment
* - Flexible data rate enabled
* - Use zeros for FD padding
*/
flexcan_data_info_t dataInfo =
{
.data_length = len,
.msg_id_type = FLEXCAN_MSG_ID_EXT
};
/* Configure TX message buffer with index TX_MSG_ID and TX_MAILBOX*/
FLEXCAN_DRV_ConfigTxMb(INST_CANCOM1, mailbox, &dataInfo, SendCANID);
/* Execute send non-blocking */
FLEXCAN_DRV_Send(INST_CANCOM1, mailbox, &dataInfo, SendCANID, data);
}
uint8_t FlexCAN_ReceiveData(uint8_t *data)
{
/* Define receive buffer */
flexcan_msgbuff_t recvBuff;
uint32_t mailbox = 5;
uint32_t status=0;
status = ((CAN_0->IFLAG1)>>mailbox)&0x01;
//MailBox is receive buffer
if (status != 1)
{
return;
}
/* Start receiving data in RX_MAILBOX. */
FLEXCAN_DRV_Receive(INST_CANCOM1, mailbox, &recvBuff);
/* Wait until the previous FlexCAN receive is completed */
if(FLEXCAN_DRV_GetTransferStatus(INST_CANCOM1, mailbox) == STATUS_SUCCESS)
{
/* Check the received message ID and payload */
if(recvBuff.msgId == ReceiveCANID)
{
/* Toggle output value LED1 */
//PINS_DRV_TogglePins(PTC, (1 << 12));
uint8_t i;
for(i=0;i
我们现在调用函数,进行CAN收发测试。
以下示例代码逻辑为:启动后先初始化时钟和引脚,约1s闪烁红色LED,循环判断接收到0x00c18064的数据,收到数据后将首字节数据+1回馈,并且翻转绿色LED。
void ReceiveCANData()
{
uint8_t data[8] = {0};
uint8_t dataLen = 0;
if((dataLen=FlexCAN_ReceiveData(data))!=0)
{
/* Toggle output value LED1 */
PINS_DRV_TogglePins(PTC, (1 << 12));
data[0] +=1;
FlexCAN_SendData(data,dataLen);
}
}
uint32_t countA=0,countB=0;
int main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of Processor Expert internal initialization. ***/
/* Write your code here */
/* For example: for(;;) { } */
CLOCK_DRV_Init(g_clockManConfigsArr[0]);
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS,g_pin_mux_InitConfigArr);
FlexCAN_Initial();
//uint8_t canData[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
for(;;)
{
ReceiveCANData();
countA++;
if(countA>1000000)
{
countA=0;
countB=countB>10000?0:countB+1;
PINS_DRV_TogglePins(PTC,1<<11);
//SendCANData(1,0xa180c8,canData,8);
}
}
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of RTOS startup code. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
收发示例: