CAN初始化
CAN的模式
- CAN主要有三种:初始化模式、正常模式和睡眠模式
CAN的初始化步骤
CAN基本外设初始化
CAN外设初始化主要是CAN通信中的配置,比如波特率、采样点等
当硬件处于初始化模式时,可以进行软件初始化。为进入该模式,软件将 CAN_MCR 寄存器的 INRQ 位置 1,并等待硬件通过将 CAN_MCR 寄存器的 INAK 位置 1 来确认请求。在初始化模式下,所有从 CAN 总线传入和传出的消息都将停止,并且 CAN 总线输出 CANTX的状态为隐性(高)。为初始化 CAN 控制器,软件必须设置位定时 (CAN_BTR) 和 CAN 选项 (CAN_MCR) 寄存器
CAN筛选器初筛化
筛选器主要是通过CAN报文的ID获取自己需要的报文
软件必须将 FINIT 位 (CAN_FMR) 置 1,才可以初始化筛选器相关寄存器。筛选器的初始化也可以在初始化模式之外进行(即使 CAN 正在正常通信,也可以重新配置筛选器。筛选器必须处于激活状态,无法重新配置)。
注意:
FINIT=1 时, CAN 接收停用。筛选器值也可通过停用( CAN_FA1R 寄存器的)相关筛选器激活位来修改。如果某个筛选器组未使用,建议将其保持未激活状态(将相应 FACT 位保持清零)
CAN切换为正常模式
进入正常模式的请求可通过将 CAN_MCR 寄存器的 INRQ 位清零来发出。但是,CAN不是立即进入正常模式的,必须等待一个由 11 个连续隐性位(总线空闲状态)组成的序列,才可以进入正常模式。硬件通过将 CAN_MSR 寄存器的 INAK 位清零,来确认切换到正常模式。
示例代码
- 检查参数传入是否正确
使能CAN引脚、配置复用通道、使能CAN时钟
CAN_RX_GPIO_CLK_ENABLE(); /* CAN_RX脚时钟使能 */ CAN_TX_GPIO_CLK_ENABLE(); /* CAN_TX脚时钟使能 */ sys_gpio_set(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN, SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU); sys_gpio_set(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN, SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU); sys_gpio_af_set(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN, CAN_TX_GPIO_AF); sys_gpio_af_set(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN, CAN_RX_GPIO_AF); RCC->APB1ENR |= 1 << 25; /* 使能CAN时钟 CAN使用的是APB1的时钟(max: 42M) */退出休眠,进行CAN初始化配置
如果软件通过将 INRQ 位置 1 来请求进入初始化模式,则必须同时将 SLEEP 位清零。CAN1->MCR = 0x0000; /* 退出睡眠模式(同时设置所有位为0) */ CAN1->MCR |= 1 << 0; /* 请求CAN进入初始化模式 */ while ((CAN1->MSR & 1 << 0) == 0) /* 等待进入初始化模式成功 */ { i++; if (i > 100) /* 进入初始化模式失败 */ { return 2; } } CAN1->MCR |= 0 << 7; /* 非时间触发通信模式 */ CAN1->MCR |= 0 << 6; /* 软件自动离线管理 */ CAN1->MCR |= 0 << 5; /* 睡眠模式通过软件唤醒(清除CAN1->MCR的SLEEP位) */ CAN1->MCR |= 1 << 4; /* 禁止报文自动传送 */ CAN1->MCR |= 0 << 3; /* 报文不锁定,新的覆盖旧的 */ CAN1->MCR |= 0 << 2; /* 优先级由报文标识符决定 */ CAN1->BTR = 0; /* 清除原来的设置. */ CAN1->BTR |= mode << 30; /* LBKM = mode, 模式设置 0, 普通模式; 1, 回环模式; */ CAN1->BTR |= tsjw << 24; /* SJW[1:0] = tsjw, 重新同步跳跃宽度(Tsjw)为 tsjw + 1 个时间单位 */ CAN1->BTR |= tbs2 << 20; /* TS2[2:0] = tbs2, Tbs2 = tbs2 + 1 个时间单位 */ CAN1->BTR |= tbs1 << 16; /* TS1[2:0] = tbs1, Tbs1 = tbs1 + 1 个时间单位 */ CAN1->BTR |= brp << 0; /* BRP[9:0] = brp, Fdiv = brp + 1 */ /* 波特率: Fpclk1 / ((Tbs1 + Tbs2 + 1) * Fdiv) */ CAN1->MCR &= ~(1 << 0); /* 请求CAN退出初始化模式 */ while ((CAN1->MSR & 1 << 0) == 1) { i++; if (i > 0XFFF0) { return 3; /* 退出初始化模式失败 */ } }初始化筛选器
/* 过滤器初始化, 这里只用到了过滤器0, 且不过滤任何ID */ CAN1->FMR |= 1 << 0; /* 过滤器组工作在初始化模式 */ CAN1->FA1R &= ~(1 << 0); /* 过滤器0不激活 */ CAN1->FS1R |= 1 << 0; /* 过滤器位宽为32位. */ CAN1->FM1R |= 0 << 0; /* 过滤器0工作在标识符屏蔽位模式 */ CAN1->FFA1R |= 0 << 0; /* 过滤器0关联到FIFO0 */ CAN1->sFilterRegister[0].FR1 = 0X00000000; /* 32位ID */ CAN1->sFilterRegister[0].FR2 = 0X00000000; /* 32位MASK */ CAN1->FA1R |= 1 << 0; /* 激活过滤器0 */切换到正常模式
CAN1->FMR &= 0 << 0; /* 过滤器组进入正常模式 */