【瑞萨RA6E2评估板】CAN FD功能和通讯兼容性测试
[复制链接]
CANFD通讯功能是比较高级的功能,RA6E2具有CAN FD通讯功能,而且瑞萨公司还提供了CAN FD的培训教材,本次测试除了使用开发板RA6E2以外还,还使用了米尔STM32MP135开发板,通过两块板的硬件进行连接,这里CAN FD的引脚不能直接连接,需要PHY TJA1043芯片,这个芯片将TTL信号转换为差分信号。
参考实验教程,首先建立项目CANFD_FSP_Project,
项目模板使用FPB_RA6E2,项目类型为Keil项目
增加按钮的IRQ模块,使用按钮来发送数据。
我在项目中使用uart作为调试输出,所以再增加uart模块。引脚为P410和P411。
增加uart之后就需要增加CAN FD设置了。初步的设置如下:
首先不要急着设置CAN FD lite模块,应该设置PIN引脚,P402和P401引脚
两个引脚都需要设置。然后设置增加CAN FD Lite
增加完成后发现出现错误。说明还有其它的设置。然后设置系统时钟。
按照上面的图来设置。
按照上图设置,这时can fd模块的错误消失了。
项目代码如下:
#include "hal_data.h"
#include <stdio.h>
/* Macro definition */
#define CARRIAGE_ASCII (13u) /* Carriage return */
#define ZERO_ASCII (48u) /* ASCII value of zero */
#define NINE_ASCII (57u) /* ASCII value for nine */
#define DATA_LENGTH (8u) /* Expected Input Data length */
#define UART_ERROR_EVENTS (UART_EVENT_BREAK_DETECT | UART_EVENT_ERR_OVERFLOW | UART_EVENT_ERR_FRAMING | \
UART_EVENT_ERR_PARITY) /* UART Error event bits mapped in registers */
#define RESET_VALUE (0x00)
/* Flag for user callback */
static volatile uint8_t g_uart_event = RESET_VALUE;
static uint8_t g_temp_buffer[DATA_LENGTH] = {RESET_VALUE};
/* Counter to update g_temp_buffer index */
static volatile uint8_t g_counter_var = RESET_VALUE;
/* Flag to check whether data is received or not */
static volatile uint8_t g_data_received_flag = false;
void R_BSP_WarmStart(bsp_warm_start_event_t event);
extern bsp_leds_t g_bsp_leds;
static volatile bool g_sw_press;
can_info_t can_rx_info =
{
.error_code = 0,
.error_count_receive = 0,
.error_count_transmit = 0,
.rx_fifo_status = 0,
.rx_mb_status = 0,
.status = 0,
};
const canfd_afl_entry_t p_canfd0_afl[] =
{
{
.id =
{
.id = 0x40,
.frame_type = CAN_FRAME_TYPE_DATA,
.id_mode = CAN_ID_MODE_STANDARD,
},
.mask =
{
.mask_id = 0x7FE,
.mask_frame_type = 0,
.mask_id_mode = 1,
},
.destination =
{
.minimum_dlc = CANFD_MINIMUM_DLC_0,
.rx_buffer = CANFD_RX_MB_0,
},
}
};
/* Flags to be set in Callback function */
bool b_canfd_tx_complete = false;
bool b_canfd_rx_complete = false;
bool b_canfd_err_status = false;
/* CANDFD RX and TX variables */
can_frame_t g_can_tx_frame;
can_frame_t g_can_rx_frame;
can_frame_t g_can_rx_frame_fifo;
uint8_t tx_data[64];
/*******************************************************************************************************************//**
* [url=home.php?mod=space&uid=159083]@brief[/url] Blinky example application
*
* Blinks all leds at a rate of 1 second using the software delay function provided by the BSP.
*
**********************************************************************************************************************/
void hal_entry (void)
{
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
fsp_err_t err = FSP_SUCCESS;
size_t buff_len;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
unsigned char send_buff[32]="RA Keil Exit\r";
/* Define the units to be used with the software delay function */
const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;
/* Set the blink frequency (must be <= bsp_delay_units */
const uint32_t freq_in_hz = 2;
/* Calculate the delay in terms of bsp_delay_units */
const uint32_t delay = bsp_delay_units / freq_in_hz;
/* LED type structure */
bsp_leds_t leds = g_bsp_leds;
/* If this board has no LEDs then trap here */
if (0 == leds.led_count)
{
while (1)
{
; // There are no LEDs on this board
}
}
/* Holds level to set for pins */
bsp_io_level_t pin_level = BSP_IO_LEVEL_LOW;
err = R_ICU_ExternalIrqOpen(&g_external_irq_ctrl,&g_external_irq_cfg);
if(FSP_SUCCESS != err) __BKPT();
err = R_ICU_ExternalIrqEnable(&g_external_irq_ctrl);
if(FSP_SUCCESS != err) __BKPT();
err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
if(FSP_SUCCESS != err) __BKPT();
buff_len = strlen((char *)send_buff);
err = R_SCI_UART_Write(&g_uart0_ctrl, send_buff, buff_len);
if(FSP_SUCCESS != err) __BKPT();
while (1)
{
/* Enable access to the PFS registers. If using r_ioport module then register protection is automatically
* handled. This code uses BSP IO functions to show how it is used.
*/
R_BSP_PinAccessEnable();
/* Update all board LEDs */
for (uint32_t i = 0; i < leds.led_count; i++)
{
/* Get pin to toggle */
uint32_t pin = leds.p_leds[i];
/* Write to this pin */
R_BSP_PinWrite((bsp_io_port_pin_t) pin, pin_level);
}
err = R_CANFD_InfoGet(&g_canfd0_ctrl,&can_rx_info);
if(FSP_SUCCESS != err) __BKPT();
if((can_rx_info.rx_mb_status & (1 << 0) ) ==(1 << 0))
{
err = R_CANFD_Read(&g_canfd0_ctrl,0,&g_can_rx_frame);
if(err != FSP_SUCCESS) __BKPT();
}
if(g_sw_press)
{
err = R_SCI_UART_Write(&g_uart0_ctrl, send_buff, buff_len);
if(FSP_SUCCESS != err) __BKPT();
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
break;
}
}
err = FSP_SUCCESS;
for(uint16_t i = 0; i< DATA_LENGTH;i++)
{
tx_data[i] = (uint8_t) (i + 1);
}
memcpy((uint8_t *)&g_can_tx_frame.data[0],(uint8_t *)&tx_data[0],DATA_LENGTH);
g_can_tx_frame.id = 0x40;
g_can_tx_frame.id_mode = CAN_ID_MODE_STANDARD;
g_can_tx_frame.type = CAN_FRAME_TYPE_DATA;
g_can_tx_frame.data_length_code = 8;
g_can_tx_frame.options = 0;
/* Write some data to the transmit frame */
err = R_CANFD_Write(&g_canfd0_ctrl,0,&g_can_tx_frame);
/* Handle error*/
if(FSP_SUCCESS != err) __BKPT();
g_sw_press = false;
}
/* Protect PFS registers */
R_BSP_PinAccessDisable();
/* Toggle level for next write */
if (BSP_IO_LEVEL_LOW == pin_level)
{
pin_level = BSP_IO_LEVEL_HIGH;
}
else
{
pin_level = BSP_IO_LEVEL_LOW;
}
/* Delay */
R_BSP_SoftwareDelay(delay, bsp_delay_units);
}
}
/*******************************************************************************************************************//**
* This function is called at various points during the startup process. This implementation uses the event that is
* called right before main() to set up the pins.
*
* @param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
/* Enable reading from data flash. */
R_FACI_LP->DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
* C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event)
{
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
IOPORT_CFG_OPEN(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);
}
}
void user_irq_callback(external_irq_callback_args_t * p_args)
{
if(p_args->channel == 9)
{
g_sw_press = true;
}
}
void user_uart_callback(uart_callback_args_t * p_args)
{
/* Logged the event in global variable */
g_uart_event = (uint8_t)p_args->event;
/* Reset g_temp_buffer index if it exceeds than buffer size */
if(DATA_LENGTH == g_counter_var)
{
g_counter_var = RESET_VALUE;
}
if(UART_EVENT_RX_CHAR == p_args->event)
{
switch (p_args->data)
{
/* If Enter is pressed by user, set flag to process the data */
case CARRIAGE_ASCII:
{
g_counter_var = RESET_VALUE;
g_data_received_flag = true;
break;
}
/* Read all data provided by user until enter button is pressed */
default:
{
g_temp_buffer[g_counter_var++] = (uint8_t ) p_args->data;
break;
}
}
}
}
/* Callback function */
void canfd0_callback(can_callback_args_t *p_args)
{
/* TODO: add your own code here */
switch(p_args->event)
{
case CAN_EVENT_TX_COMPLETE:
{
b_canfd_tx_complete = true;
break;
}
case CAN_EVENT_RX_COMPLETE:
{
b_canfd_rx_complete = true;
break;
}
case CAN_EVENT_ERR_WARNING:
case CAN_EVENT_ERR_PASSIVE:
case CAN_EVENT_ERR_BUS_OFF:
case CAN_EVENT_BUS_RECOVERY:
case CAN_EVENT_MAILBOX_MESSAGE_LOST:
case CAN_EVENT_ERR_BUS_LOCK:
case CAN_EVENT_ERR_CHANNEL:
case CAN_EVENT_TX_ABORTED:
case CAN_EVENT_ERR_GLOBAL:
case CAN_EVENT_FIFO_MESSAGE_LOST:
case CAN_EVENT_TX_FIFO_EMPTY:
{
b_canfd_err_status = true;
break;
}
}
}
这里需要重点关照的内容如下:
const canfd_afl_entry_t p_canfd0_afl[] =
{
{
.id =
{
.id = 0x40,
.frame_type = CAN_FRAME_TYPE_DATA,
.id_mode = CAN_ID_MODE_STANDARD,
},
.mask =
{
.mask_id = 0x7FE,
.mask_frame_type = 0,
.mask_id_mode = 1,
},
.destination =
{
.minimum_dlc = CANFD_MINIMUM_DLC_0,
.rx_buffer = CANFD_RX_MB_0,
},
}
};
canfd_afl_entry_t 结构中的ID设置为0x40,十进制为64。这个为CAN中的包过滤地址,最开始我就是没有理解该地址,使得通讯只能引起中断,结果数据无法接收。
这个结构是用来设置AFLT(地址过滤表)的,这里只是用了一个地址,(需要注意:芯片可以支持多个地址的。)发送数据代码如下,
if(g_sw_press)
{
err = R_SCI_UART_Write(&g_uart0_ctrl, send_buff, buff_len);
if(FSP_SUCCESS != err) __BKPT();
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
break;
}
}
err = FSP_SUCCESS;
for(uint16_t i = 0; i< DATA_LENGTH;i++)
{
tx_data[i] = (uint8_t) (i + 1);
}
memcpy((uint8_t *)&g_can_tx_frame.data[0],(uint8_t *)&tx_data[0],DATA_LENGTH);
g_can_tx_frame.id = 0x64;
g_can_tx_frame.id_mode = CAN_ID_MODE_STANDARD;
g_can_tx_frame.type = CAN_FRAME_TYPE_DATA;
g_can_tx_frame.data_length_code = 8;
g_can_tx_frame.options = 0;
/* Write some data to the transmit frame */
err = R_CANFD_Write(&g_canfd0_ctrl,0,&g_can_tx_frame);
/* Handle error*/
if(FSP_SUCCESS != err) __BKPT();
g_sw_press = false;
}
这里我没有按照实验教材中将代码放到IRQ按钮中断里,而是放到了主循环里。这一点需要注意,还有就是地址,我的为100,十六进制0x64,因为我的STM32MP135开发板为100地址。因为没有发现如何修改这个地址。所以只能为100了。
程序写完后开始运行。
启动linux开发板,使用如下代码初始化。
参考STM32MP135的测试连接 STM32MP135测试
cansend can0 64#11.22.33.44
发出命令后发现RA6E2开发板的中断有了反应
说数据接收成功。
|