Add CAN module in ch32v208rbt6

Now input test_can to connect CAN bus.
1. Set the IPC CAN speed to 250kbps. The method how to calculate the CAN speed could be seen in init_can of can_test.c.
2. Connect the board to the USBCAN and open the IPC.
3. input test_can command to send the message to the CAN bus so that the USBCAN receives the message.
4. The USBCAN will print the message.
This commit is contained in:
huoyujia081 2024-06-11 09:49:18 +08:00
parent d75e3ad7f9
commit 090b863637
9 changed files with 534 additions and 0 deletions

View File

@ -28,6 +28,7 @@
* @date 2024-4-29 * @date 2024-4-29
*/ */
#include "ch32v20x.h" #include "ch32v20x.h"
#include "connect_can.h"
#include "connect_uart.h" #include "connect_uart.h"
#include "core_riscv.h" #include "core_riscv.h"
#include "xsconfig.h" #include "xsconfig.h"
@ -86,6 +87,9 @@ void InitBoardHardware()
#ifdef BSP_USING_BLE #ifdef BSP_USING_BLE
WCHBLE_Init(); WCHBLE_Init();
HAL_Init(); HAL_Init();
#endif
#ifdef BSP_USING_CAN
InitHwCan();
#endif #endif
KPrintf("consle init completed.\n"); KPrintf("consle init completed.\n");
KPrintf("board initialization......\n"); KPrintf("board initialization......\n");

View File

@ -17,4 +17,12 @@ menuconfig BSP_USING_ADC
menuconfig BSP_USING_BLE menuconfig BSP_USING_BLE
bool "Using BLE" bool "Using BLE"
default y default y
menuconfig BSP_USING_CAN
bool "Using CAN device"
default y
select RESOURCES_CAN
if BSP_USING_CAN
source "$BSP_DIR/third_party_driver/can/Kconfig"
endif

View File

@ -13,4 +13,7 @@ endif
ifeq ($(CONFIG_BSP_USING_BLE),y) ifeq ($(CONFIG_BSP_USING_BLE),y)
SRC_DIR += ble SRC_DIR += ble
endif endif
ifeq ($(CONFIG_BSP_USING_CAN),y)
SRC_DIR += can
endif
include $(KERNEL_ROOT)/compiler.mk include $(KERNEL_ROOT)/compiler.mk

View File

@ -62,6 +62,8 @@ void Main_Circulation(void)
int test_ble(int argc, char *argv[]) int test_ble(int argc, char *argv[])
{ {
KPrintf("%s\n", VER_LIB); KPrintf("%s\n", VER_LIB);
WCHBLE_Init();
HAL_Init();
GAPRole_PeripheralInit(); GAPRole_PeripheralInit();
Peripheral_Init(); Peripheral_Init();
KPrintf("BLE Peripheral Slave Init Success.\n"); KPrintf("BLE Peripheral Slave Init Success.\n");

View File

@ -0,0 +1,4 @@
SRC_FILES := connect_can.c
SRC_DIR := test
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,248 @@
#include <connect_can.h>
#include <ch32v20x_gpio.h>
#include <ch32v20x_rcc.h>
#include <ch32v20x_misc.h>
static struct CanSendConfigure can_send_deconfig =
{
.stdid = 0x12,
.exdid = 0x12,
.ide = 0 ,
.rtr = 0,
.data_lenth = 8
};
static void CanGPIOInit(void)
{
CAN_FilterInitTypeDef can1_filter = {0};
GPIO_InitTypeDef gpio_initstructure = {0};
CAN_InitTypeDef can_initstruction = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOA, ENABLE); // 如果CAN引脚映射到PA需要设置A时钟源否则设置成B时钟源
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
/* 这里需要和原理图的引脚对应 */
gpio_initstructure.GPIO_Pin = GPIO_Pin_12; // CAN1_TX
gpio_initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_initstructure); // 初始化引脚
gpio_initstructure.GPIO_Pin = GPIO_Pin_11; // CAN1_RX
gpio_initstructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &gpio_initstructure); // 初始化引脚
}
static void Can1NvicConfig(void)
{
NVIC_InitTypeDef can_nvic_config;
can_nvic_config.NVIC_IRQChannel = CAN1_RX1_IRQn;
can_nvic_config.NVIC_IRQChannelPreemptionPriority = 2;
can_nvic_config.NVIC_IRQChannelSubPriority = 2;
can_nvic_config.NVIC_IRQChannelCmd = ENABLE;
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
NVIC_Init(&can_nvic_config);
}
static uint32 CanModeInit(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
CAN_FilterInitTypeDef can1_filter;
CAN_InitTypeDef can_initstruction;
struct CanDriverConfigure *config = ( struct CanDriverConfigure *)configure_info->private_data;
can_initstruction.CAN_TTCM = DISABLE;
can_initstruction.CAN_ABOM = DISABLE;
can_initstruction.CAN_AWUM = DISABLE;
can_initstruction.CAN_NART = ENABLE;
can_initstruction.CAN_TXFP = DISABLE;
can_initstruction.CAN_Mode = config->mode;
can_initstruction.CAN_RFLM = DISABLE;
can_initstruction.CAN_SJW = config->tsjw;
can_initstruction.CAN_BS1 = config->tbs1;
can_initstruction.CAN_BS2 = config->tbs2;
can_initstruction.CAN_Prescaler = config->brp;
CAN_Init(CAN1, &can_initstruction);
can1_filter.CAN_FilterNumber=0;
can1_filter.CAN_FilterMode=CAN_FilterMode_IdMask;
can1_filter.CAN_FilterScale=CAN_FilterScale_32bit;
can1_filter.CAN_FilterIdHigh=0x0000;
can1_filter.CAN_FilterIdLow=0x0000;
can1_filter.CAN_FilterMaskIdHigh=0x0000;
can1_filter.CAN_FilterMaskIdLow=0x0006;
can1_filter.CAN_FilterFIFOAssignment=CAN_Filter_FIFO1;
can1_filter.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&can1_filter);
#ifdef CAN_USING_INTERRUPT
Can1NvicConfig();
#endif
return 0;
}
static uint32 CanSendMsg(void * dev , struct BusBlockWriteParam *write_param )
{
NULL_PARAM_CHECK(write_param);
uint8 *data = (uint8 * ) write_param->buffer;
u8 messege_box;
u16 i = 0;
u16 timer_count = 1000;
CanTxMsg tx_data;
tx_data.StdId = 0x55;
tx_data.ExtId = 0x00;
tx_data.IDE = 0;
tx_data.RTR = 0;
tx_data.DLC = write_param->size;
for(i = 0;i < tx_data.DLC;i ++) {
tx_data.Data[i] = data[i];
}
messege_box = CAN_Transmit(CAN1,&tx_data);
while (CAN_TransmitStatus(CAN1,messege_box)== CAN_TxStatus_Failed &&timer_count) {
timer_count--;
}
if (timer_count<=0) {
return ERROR;
}
return EOK;
}
static uint32 CanRecvMsg(void *dev , struct BusBlockReadParam *databuf)
{
NULL_PARAM_CHECK(dev);
int i;
uint8 * buf = (uint8 *)databuf->buffer;
CanRxMsg msg;
if (CAN_MessagePending(CAN1, CAN_FIFO0) == 0)
return 0;
CAN_Receive(CAN1, CAN_FIFO0, &msg);
for(i = 0 ;i < msg.DLC;i ++)
buf[i] = msg.Data[i];
databuf->size = msg.DLC ;
return msg.DLC;
}
static struct CanDevDone dev_done =
{
.open = NONE,
.close = NONE,
.write = CanSendMsg,
.read = CanRecvMsg
};
static struct CanHardwareDevice dev;
#ifdef CAN_USING_INTERRUPT
void CAN1_RX0_IRQHandler(void)
{
CanRxMsg rxmsg;
int i = 0;
CAN_Receive(CAN1, 0, &rxmsg);
for (i = 0;i < 8;i ++)
KPrintf("rxbuf [%d] = :%d",i,rxmsg.Data[i]);
}
DECLARE_HW_IRQ(CAN1_RX0_IRQn, CAN1_RX0_IRQHandler, NONE);
#endif
static int BoardCanBusInit(struct CanDev *CanDev_bus, struct CanDriver *can_driver)
{
x_err_t ret = EOK;
/*Init the can bus */
ret = CanBusInit(&CanDev_bus->can_bus, CanDev_bus->bus_name);
if (EOK != ret) {
KPrintf("Board_can_init canBusInit error %d\n", ret);
return ERROR;
}
/*Init the can driver*/
ret = CanDriverInit(can_driver, CAN_DRIVER_NAME);
if (EOK != ret) {
KPrintf("Board_can_init canDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the can driver to the can bus*/
ret = CanDriverAttachToBus(CAN_DRIVER_NAME, CanDev_bus->bus_name);
if (EOK != ret) {
KPrintf("Board_can_init CanDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
static x_err_t HwCanDeviceAttach(const char *bus_name, const char *device_name)
{
NULL_PARAM_CHECK(bus_name);
NULL_PARAM_CHECK(device_name);
x_err_t result;
struct CanHardwareDevice *can_device;
/* attach the device to can bus*/
can_device = (struct CanHardwareDevice *)x_malloc(sizeof(struct CanHardwareDevice));
CHECK(can_device);
memset(can_device, 0, sizeof(struct CanHardwareDevice));
can_device->dev_done = &dev_done;
result = CanDeviceRegister(can_device, NONE, device_name);
if (EOK != result) {
KPrintf("board_can_init canDeviceInit device %s error %d\n", "can1", result);
return ERROR;
}
result = CanDeviceAttachToBus(device_name, bus_name);
if (result != EOK) {
SYS_ERR("%s attach to %s faild, %d\n", device_name, bus_name, result);
}
CHECK(result == EOK);
KPrintf("%s attach to %s done\n", device_name, bus_name);
return result;
}
struct CanDev can1;
int InitHwCan(void)
{
x_err_t ret = EOK;
struct CanDev *can_bus;
static struct CanDriver can_driver;
memset(&can_driver, 0, sizeof(struct CanDriver));
can_driver.configure = CanModeInit;
CanGPIOInit();
can_bus = &can1;
can_bus->instance = CAN1;
can_bus->bus_name = CAN_BUS_NAME_1;
can_bus->can_bus.private_data = &can1;
ret = BoardCanBusInit(can_bus, &can_driver);
if (EOK != ret) {
KPrintf(" can_bus_init %s error ret %u\n", can_bus->bus_name, ret);
return ERROR;
}
ret = HwCanDeviceAttach(CAN_BUS_NAME_1,CAN_1_DEVICE_NAME_1);
if (EOK != ret) {
KPrintf(" HwCanDeviceAttach %s error ret %u\n", can_bus->bus_name, ret);
return ERROR;
}
return EOK;
}

View File

@ -0,0 +1,4 @@
SRC_FILES := can_test.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan
* PSL v2. You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
* Mulan PSL v2 for more details.
*/
/**
* @file can_test.c
* @brief test ch32v307 can
* @version 1.0
* @author AIIT XUOS Lab
* @date 2024-03-14
*/
#include <ch32v20x_gpio.h>
#include <ch32v20x_misc.h>
#include <ch32v20x_rcc.h>
#include "ch32v20x.h"
#include "connect_can.h"
#include "debug.h"
#include "shell.h"
/* CAN Mode Definition */
#define TX_MODE 0
#define RX_MODE 1
/* Frame Format Definition */
#define Standard_Frame 0
#define Extended_Frame 1
/* CAN Communication Mode Selection */
#define CAN_MODE TX_MODE
// #define CAN_MODE RX_MODE
/* Frame Formate Selection */
#define Frame_Format Standard_Frame
// #define Frame_Format Extended_Frame
/*********************************************************************
* @fn CAN_Mode_Init
*
* @brief Initializes CAN communication test mode.
* Bps =Fpclk1/((tpb1+1+tbs2+1+1)*brp)
* https://www.cnblogs.com/wchmcu/p/17546797.html
*
* @param tsjw - CAN synchronisation jump width.
* tbs2 - CAN time quantum in bit segment 1.
* tbs1 - CAN time quantum in bit segment 2.
* brp - Specifies the length of a time quantum.
* mode - Test mode.
* CAN_Mode_Normal.
* CAN_Mode_LoopBack.
* CAN_Mode_Silent.
* CAN_Mode_Silent_LoopBack.
*
* @return none
*/
static int init_can(u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode) {
CAN_InitTypeDef CAN_InitSturcture = {0};
CAN_FilterInitTypeDef CAN_FilterInitSturcture = {0};
CAN_InitSturcture.CAN_TTCM = DISABLE;
CAN_InitSturcture.CAN_ABOM = DISABLE;
CAN_InitSturcture.CAN_AWUM = DISABLE;
CAN_InitSturcture.CAN_NART = ENABLE;
CAN_InitSturcture.CAN_RFLM = DISABLE;
CAN_InitSturcture.CAN_TXFP = DISABLE;
CAN_InitSturcture.CAN_Mode = mode;
CAN_InitSturcture.CAN_SJW = tsjw;
CAN_InitSturcture.CAN_BS1 = tbs1;
CAN_InitSturcture.CAN_BS2 = tbs2;
CAN_InitSturcture.CAN_Prescaler = brp;
CAN_Init(CAN1, &CAN_InitSturcture);
CAN_FilterInitSturcture.CAN_FilterNumber = 0;
#if (Frame_Format == Standard_Frame)
/* identifier/mask mode, One 32-bit filter, StdId: 0x317 */
CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;
CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFE0;
CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x0006;
/* identifier/mask mode, Two 16-bit filters, StdId: 0x317锟斤拷0x316 */
// CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;
// CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_16bit;
// CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;
// CAN_FilterInitSturcture.CAN_FilterIdLow = 0xFFF8;
// CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62C0;
// CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0xFFF8;
/* identifier list mode, One 32-bit filter, StdId: 0x317锟斤拷0x316 */
// CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdList;
// CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
// CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;
// CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
// CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62C0;
// CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0;
/* identifier list mode, Two 16-bit filters, StdId: 0x317,0x316,0x315,0x314
*/
// CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdList;
// CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_16bit;
// CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;
// CAN_FilterInitSturcture.CAN_FilterIdLow = 0x62C0;
// CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0x62A0;
// CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x6280;
#elif (Frame_Format == Extended_Frame)
/* identifier/mask mode, One 32-bit filter, ExtId: 0x12124567 */
CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x9092;
CAN_FilterInitSturcture.CAN_FilterIdLow = 0x2B3C;
CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0xFFFE;
#endif
CAN_FilterInitSturcture.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
CAN_FilterInitSturcture.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitSturcture);
return 0;
}
static u8 CAN_Send_Msg(u8 *msg, u8 len) {
u8 mbox;
u16 i = 0;
CanTxMsg CanTxStructure;
CanTxStructure.StdId = 0x317;
CanTxStructure.IDE = CAN_Id_Standard;
CanTxStructure.RTR = CAN_RTR_Data;
CanTxStructure.DLC = len;
for (i = 0; i < len; i++) {
CanTxStructure.Data[i] = msg[i];
}
mbox = CAN_Transmit(CAN1, &CanTxStructure);
i = 0;
while ((CAN_TransmitStatus(CAN1, mbox) != CAN_TxStatus_Ok) && (i < 0xFFF)) {
i++;
}
if (i == 0xFFF) {
return 1;
} else {
return 0;
}
}
static u8 CAN_Receive_Msg(u8 *buf) {
u8 i;
CanRxMsg CanRxStructure;
if (CAN_MessagePending(CAN1, CAN_FIFO1) == 0) {
return 0;
}
CAN_Receive(CAN1, CAN_FIFO1, &CanRxStructure);
for (i = 0; i < 8; i++) {
buf[i] = CanRxStructure.Data[i];
}
return CanRxStructure.DLC;
}
int test_can(int argc, char *argv[]) {
u8 i;
u8 cnt = 0;
u8 tx, rx;
u8 txbuf[8];
u8 rxbuf[8];
init_can(
CAN_SJW_1tq, CAN_BS2_5tq, CAN_BS1_6tq, 20,
CAN_Mode_Normal); // 在这种参数下设置时钟源为外部时钟120M对应的波特率是250kbps
#if (CAN_MODE == TX_MODE)
for (cnt = 0; cnt < 8; cnt++) {
for (i = 0; i < 8; i++) {
txbuf[i] = cnt + i;
}
tx = CAN_Send_Msg(txbuf, 8);
if (tx) {
KPrintf("CAN1 Send Failed\r\n");
} else {
KPrintf("CAN1 Send Success\r\n");
KPrintf("CAN1 Send Data:\r\n");
for (i = 0; i < 8; i++) {
KPrintf("%02x\r\n", txbuf[i]);
}
}
Delay_Ms(1000);
}
#elif (CAN_MODE == RX_MODE)
rx = CAN_Receive_Msg(rxbuf);
if (rx) {
KPrintf("CAN1 Receive Data:\r\n");
for (i = 0; i < 8; i++) {
KPrintf("%02x\r\n", txbuf[i]);
}
} else {
KPrintf("CAN1 No Receive Data\r\n");
}
#endif
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
test_can, test_can, test CAN);

View File

@ -0,0 +1,33 @@
#ifndef CONNECT_CAN_H
#define CONNECT_CAN_H
#include <bus_can.h>
#include <dev_can.h>
#include <ch32v20x.h>
#include <ch32v20x_can.h>
struct CanDev
{
CAN_TypeDef *instance;
char *bus_name;
// CAN_InitTypeDef init;
uint8 can_flag;
struct CanBus can_bus;
};
int InitHwCan(void);
#endif