PCAN FD

1 CAN FD
1.1 MCU with CAN FD
GD32C103: USART upgrade
STM32G0B1: RM0444, DS13560, AN5096, USART1 (PA9, PA10) and DFU (PA11, PA12)
STM32G431: RM0440, DS12589, AN5093, USART1 (PA9, PA10) and DFU (PA11, PA12)

Refer to AN2606 to get what STM32 devices support DFU bootloader.

NUCLEO-G431RB评估板上的唯一一个USB接口不是连接到STM32G431的,而是给ST-Link用的。
Discovery开发板一般有2个USB接口,一个是ST-Link,另外一个是USB通信口。

1.2 FD Format bit
STM32G0x1 R1.FDF: Receive Register 1, FD Format bit; if this bit is set, a CAN FD frame was received, otherwise, a CAN 2.0 frame was received.

1.3 gcc
github kylesrm / stm32g431-nucleo-makefile
cp lib/HAL/Inc/stm32g4xx_hal_conf_template.h src/stm32g4xx_hal_conf.h

1.4 schematics
github lijinlong21549 / STM32G474_board

1.5 CAN FD bus transceiver
TJA1042

2 PCAN FD
moonglow / pcan_pro_x

USB_EP_MSGOUT:
struct ucan_tx_msg {
  uint16_t  size;
  uint16_t  type;
  uint32_t  tag_low;
  uint32_t  tag_high;
  uint8_t  channel_dlc;
  uint8_t  client;
  uint16_t  flags;
  uint32_t  can_id;
  uint8_t  d[];
}__attribute__((packed));

USB_EP_MSGIN:
struct ucan_rx_msg {
  // size 整个结构体的长度
  uint16_t  size;
  uint16_t  type;
  // unit: us
  uint32_t  ts_low;
  // ts_high = 0
  uint32_t  ts_high;
  // tag_low = 0
  uint32_t  tag_low;
  // tag_high = 0
  uint32_t  tag_high;
  // high 4-bit is DLC,
  // low 4-bit is CAN instance ID, 0 or 1
  uint8_t  channel_dlc;
  uint8_t  client;
  uint16_t  flags;
  uint32_t  can_id;
  uint8_t  d[];
}__attribute__((packed));

struct ucan_command {
  // low 12-bit means opcode
  // high 4-bit means CAN instance ID

  uint16_t  opcode_channel;
  uint16_t  args[3];
}__attribute__((packed));

static const uint8_t pcan_fd_len2dlc[] =
{
  0, 1, 2, 3, 4, 5, 6, 7, 8,  /* 0 - 8 */
  9, 9, 9, 9,     /* 9 - 12 */
  10, 10, 10, 10,         /* 13 - 16 */
  11, 11, 11, 11,         /* 17 - 20 */
  12, 12, 12, 12,         /* 21 - 24 */
  13, 13, 13, 13, 13, 13, 13, 13,     /* 25 - 32 */
  14, 14, 14, 14, 14, 14, 14, 14,     /* 33 - 40 */
  14, 14, 14, 14, 14, 14, 14, 14,     /* 41 - 48 */
  15, 15, 15, 15, 15, 15, 15, 15,     /* 49 - 56 */
  15, 15, 15, 15, 15, 15, 15, 15      /* 57 - 64 */
};

static const uint8_t pcan_fd_dlc2len[] =
{
  0, 1, 2, 3, 4, 5, 6, 7,
  8, 12, 16, 20, 24, 32, 48, 64
};

3 STM32F072 Porting
3.1 Porting
moonglow / pcan_pro_x

Src/pcanpro_fd_protocol.c
Src/pcanpro_timestamp.c
Src/pcanfd_ucan.h
Src/pcanfd_usb_fw.h
Src/pcanpro_can.h
Src/pcan_usbpro_fw.h
Src/pcanpro_protocol.h
Src/pcanpro_timestamp.h

Add include "pcan_fd/pcanpro_fd_protocol.c" to Src/pcan_usb.c.

3.2 Debug
1) Windows PCAN-View
When PCAN-View starts, it will send the below commands.
01: UCAN_CMD_RESET_MODE
80: UCAN_USB_CMD_CLK_SET - PCAN-View Clock Frequency, 20 MHz
04: UCAN_CMD_TIMING_SLOW - PCAN-View Nominal Bit rate, 500 kBit/s, STM32G4 FDCAN_NBTP
05: UCAN_CMD_TIMING_FAST - PCAN-View Data Bit rate, 2 MBit/s, STM32G4 FDCAN_DBTP
02: UCAN_CMD_NORMAL_MODE - bus active
0c: UCAN_CMD_CLR_DIS_OPTION
0b: UCAN_CMD_SET_EN_OPTION
3ff: UCAN_CMD_END_OF_COLLECTION

每一个High-speed USB_EP_CMDOUT MPL(Max Packet Length)可以包含多个8字节命令(Aggregation mode),但是实际上只有第一个8字节是命令,跟在8个字节后面的是8个FF,表示命令集合结束。8个FF后面的数据是无效数据,是Windows PCAN FD驱动没有清零导致的传给PCAN FD下位机的误导数据。下一个High-speed MPL报文重复该模式。

2) Busload packet
PCAN FD sends 16-byte UCAN_MSG_BUSLOAD (10 00 04 00) to Windows PC periodically through USB_EP_MSGIN when PCAN-View starts. We can append debug messages to UCAN_MSG_BUSLOAD (10 00 ff ff 00 00 00 00 00 00 00 00 xx xx xx xx). Then use Bus Hound to catch the packets.

3) Full-speed USB
PCAN-USB: VID_0C72&PID_000C
PCAN-USB FD: VID_0C72&PID_0012
需要修改bRequest = USB_VENDOR_REQUEST_INFO的返回值,否则Windows会发送wValue = 0的SET_CONFIG,进而导致Windows PCAN-View不工作。修改点是pcan_device.device_nr = 0,pcan_device.can[0].channel_nr = 0。
USB_EP_CMDOUT buffer size: 128-byte, otherwise STM32 Full-speed USB cannot receive UCAN_CMD_NORMAL_MODE.
USB_EP_MSGOUT buffer size: 256-byte
USB_EP_MSGIN_CH1: UCAN_USB_MSG_CALIBRATION = 0x100

当USB是Full-speed时,此时Max Packet Length是64字节,Windows PCAN-View USB_EP_MSGIN的buffer size是4096字节,因为函数pcan_protocol_poll中每次都发送64字节,没有Zero Length Packet或者Short Packet,这个导致Windows的URB无法退出,一直等待设备发送了4096字节才退出URB。需要修改该处的代码,使每次发送字节数不要是Max Packet Length的整数倍。

4) Bit timing
STM32F072 CANbps = APB_clock / BRP / (tseg1 + tseg2 + 1)
需要调用函数_get_precalculated_bitrate将PCAN-View要设置的低速500 kBit/s换算成STM32F072的寄存器值,寄存器名字是CAN_BTR,地址是0x4000_641C,每个写进去的字段需要减去1。
从函数SystemClock_Config中找出APB1 bxCAN的时钟信息,APB1的时钟是48 MHz。

5) Timer
使用2个16-bit定时器实现us定时,TIM3.CNT存储us的低16-bit,TIM9.CNT存储us的高16-bit,设置TIM3的PSC到(48 - 1),即是对48 MHz APB1进行48分频,所以每一个bit即是1us,设置TIM9的PSC到(1 - 1),即是对TIM3.CNT的溢出计数不分频,故而TIM9.CNT存储的是us的高16-bit。

可以直接使用32-bit TIM2,将PSC设置为(48-1),并且时钟分频的值为0后,每个bit就代表1uS。

6) LED
PCAN FD双通道需要5个LED。