只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效
The SPI in the microcontroller must be configured in mode (0,0) or (1,1) in 8-bit operating mode
Spi-imx.c
spi_imx 30830000.ecspi: mode_bits = 71(0x47),0100 0111, mode 3 , SPI_CS_HIGH, SPI_NO_CS
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
#define SPI_LOOP 0x20 /* loopback mode */
#define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */
#define SPI_READY 0x80 /* slave pulls low to pause */
#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */
修改时钟频率
Dts:
clocks = <&mcp251x_clock>;
dtsi:
clocks {
#address-cells = <1>;
#size-cells = <0>;
mcp251x_clock: mcp251x_clock {
compatible = "fixed-clock";
reg = <1>;
#clock-cells = <0>;
clock-frequency = <20000000>;
clock-output-names = "mcp251x_clock";
};
…….
……
}
传输规则
spi_tx_buf[0] = 4bit(cmd)+ 4bit(reg地址的高4位)
spi_tx_buf[1] = 8bit(reg地址的低8为)
要使能片选脚
cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
DRV_CANFDSPI_RamInit
给mcp2518的ram初始化,长度2048
1字=2字节(1 word = 2 byte)
1字节=8位(1 byte = 8bit)
一次可以读写4个字节的整数倍,每个字节后地址会自动加一,地址从0x400到0xbff
随机存取存储器(英语:Random Access Memory,缩写:RAM),也叫主存,是与CPU直接交换数据的内部存储器。
#define SPI_DEFAULT_BUFFER_LENGTH
改为8,kernel起不来
改为64 ,96
[ 1.391649] imx-sdma 30bd0000.dma-controller: sdma firmware not ready!
[ 1.398187] spi_bitbang_transfer_one : 290 status = -22
[ 1.403510] mcp251x spi1.0: SPI transfer failed: -22
[ 1.408495] spi_master spi1: failed to transfer one message from queue
[ 1.415034] mcp251x spi1.0: spi transfer failed: ret = -22
[ 1.420530] mcp251x spi1.0: 0: DRV_CANFDSPI_RamInit error
内核报错
spi-bitbang.c: master->transfer_one = spi_bitbang_transfer_one;
关掉DRV_CANFDSPI_RamInit就没有imx-sdma 30bd0000.dma-controller: sdma firmware not ready!
这个意思没有加载sdma的固件
可是有log
[ 5.685641] imx-sdma 30bd0000.dma-controller: loaded firmware 4.4
而且在
./lib/firmware/imx/sdma/sdma-imx7d.bin
./lib/firmware/imx/sdma/sdma-imx6q.bin
都是有固件存在的
说明是加载了,但加载时间比较后面,我们在使用驱动的时候并没有加载到这个固件
只要让mcp251x.c改为用以模块的形式加载就没有问题了,这样加载时间会比较后面。
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mcp2518_irq>;
interrupt-parent = <&gpio5>;
interrupts = <8 2>;
gpio5_8 代表io口号,2代表中断类型
dt-bindings/interrupt-controller/irq.h下定义
中断类型如下
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1
#define IRQ_TYPE_EDGE_FALLING 2
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH 4
#define IRQ_TYPE_LEVEL_LOW 8
中断脚的定义必须放在从设备的设备树当中?待确认
interrupt-parent
interrupts
设备树中加入这两个参数,驱动会自动生成中断号,应该在某处申请的,带研究
利用中断函数,去检测中断类型,去操作相应寄存器
P25 3-14
#define cREGADDR_CiINT 0x01C
#define cREGADDR_CiINTFLAG cREGADDR_CiINT
中断寄存器
con_reqop = FIELD_PREP(MCP25XXFD_CAN_CON_REQOP_MASK, mode_req);
err = regmap_update_bits(priv->map, MCP25XXFD_CAN_CON,
MCP25XXFD_CAN_CON_REQOP_MASK, con_reqop);
Mode_req来至mcp25xxfd_get_normal_mode
rx-offload.c rx-offload.h:
can_rx_offload_add_manual
Bitfield.h:
#define FIELD_PREP(_mask, _val)
ip link set can0 down
ip link set can0 type can bitrate 250000 loopback on/off
ip link set can0 up
candump can0 &
cansend can0 -s 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
0x19FA044A 0x22 0x00 0xF0 0xFF 0xFF 0xFF 0xFF 0xFF
~/can-utils/canutils/4.0.6-r0/
编译candump
aarch64-poky-linux-gcc --sysroot=/opt/fsl-imx-wayland/4.14-sumo/sysroots/aarch64-poky-linux -DHAVE_CONFIG_H -I. -I../include -I../include -I../include -DPF_CAN=29 -DAF_CAN=PF_CAN -O2 -pipe -g -feliminate-unused-debug-types -Wall -g -O2 -MT candump.o -MD -MP -MF .deps/candump.Tpo -c -o candump.o candump.c
aarch64-linux-gnu-gcc -I./ -o candump candump.c
snprintf返回传输大小
server从CAN总线上接收数据,client将数据发到CAN总线上,当CAN总线上有数据时,server才能接收数据,当CAN总线空闲时,client才能将数据发送出去
net/can/raw.c
raw_recvmsg()是应用层read的接口函数,调用了没有数据会停着
net/can/af_can.c:
当有数据时才会调用canfd_rcv()
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
regmap_write(priv->map, MCP25XXFD_IOCON, val);
regmap_read(priv->map, MCP25XXFD_IOCON, ret);
if (new_state == CAN_STATE_BUS_OFF) {
mcp25xxfd_chip_stop(priv, CAN_STATE_BUS_OFF);
can_bus_off(priv->ndev);
}
err = regmap_read(priv->map, MCP25XXFD_CAN_TREC, &trec);
REGISTER 3-20: CiTREC – TRANSMIT/RECEIVE ERROR COUNT REGISTER
Yocto 编译
drivers/net/can/spi/mcp25xxfd/mcp25xxfd-core.o: In function `mcp25xxfd_probe':
| mcp25xxfd-core.c:(.text+0x1dbc): undefined reference to `can_rx_offload_add_manual'
| mcp25xxfd-core.c:(.text+0x1dbc): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `can_rx_offload_add_manual'
解决:rm work/imx8mmevk-poky-linux/linux-imx/4.14.98-r0/build/drivers/net/can/rx-offload.o
Dtb没有编译出来
Bitbake –C compile linux-imx
参数-C 中C大写才会编译设备树
在bus-off后,can会在500ms后restart,这时候can的模式会从MCP25XXFD_CAN_CON_MODE_CONFIG(4)切到MCP25XXFD_CAN_CON_MODE_CAN2_0(6)
代码:
con_reqop = FIELD_PREP(MCP25XXFD_CAN_CON_REQOP_MASK, mode_req);
err = regmap_update_bits(priv->map, MCP25XXFD_CAN_CON,
MCP25XXFD_CAN_CON_REQOP_MASK, con_reqop);
这个过程中可能出现数据发送,网络数据发送调用ndo_start_xmit这个接口函数
static const struct net_device_ops mcp25xxfd_netdev_ops = {
.ndo_open = mcp25xxfd_open,
.ndo_stop = mcp25xxfd_stop,
.ndo_start_xmit = mcp25xxfd_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
这个时候
这个地方就会导致内核挂掉
解决在can开始restart时会有rx,tx的缓存初始化操作
在这个初始化时,调用netif_stop_queue把tx队列置为off状态,使得暂时不能发送数据
在restart结束后,调用netif_start_queue把tx队列off位清除