2020.02.21,第一个任务:基于bcm617xx调通mcp2515实现SPI转CAN(未结束)
纪念第一次调Linux内核驱动
上步骤!
1.在kernel_3.0.1_bcm\arch\mips\bcm617xx\cpuh下的platform.c文件中加入4个结构体,分别是spi_gpio_platform_data、mcp251x_platform_data、spi_board_info、platform_device。
1.1 spi_gpio_platform_data中填入硬件电路图中SPI连接的GPIO引脚号。
static struct spi_gpio_platform_data spigpio_platform_data = {
.sck = 9,
.mosi = 10,
.miso = 12,
.num_chipselect = 11,
};
1.2 mcp251x_platform_data中填入硬件电路图上mcp2515连接的晶振频率,以及采用下降沿触发的方式。
static struct mcp251x_platform_data mcp251x_info = {
.oscillator_frequency = 25 * 1000 * 1000,
.irq_flags = IRQF_TRIGGER_FALLING,
//.board_specific_setup = &mcp251x_setup,
//.power_enable = mcp251x_power_enable,
//.transceiver_enable = NULL,
};
1.3 spi_board_info中需要填入设备模块的名字、SPI最大速率、总线编号、片选、SPI模式以及平台数据(platform_data)还有中断号。模块名称"mcp2515",这将与mcp251x.c里面的devicename对应,否则无法注册;由于mcp2515是挂在spi下,所以platform_data应该填入1.2中的数据,中断采用的是外部中断。
static struct spi_board_info bcm617xx_spi_baord_info[] __initdata = {
{
.modalias = "mcp2515",
.max_speed_hz = 1*1000*1000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
.platform_data = &mcp251x_info,
//.irq = CELIVERO_CPUH_GPIO,
.irq = CELIVERO_CPUH_IRQ_EXT0,
},
};
1.4 platform_device中填入name、id、dev。由于使用GPIO模拟SPI,所以name填"spi_gpio",这个名字与spi_gpio.c中的drivername对应,否则无法注册。
static struct platform_device bcm617xx_spi_gpio = {
.name = "spi_gpio",
.id = 0,
.dev = {
.platform_data = &spigpio_platform_data,
},
};
2.内核注册spi_gpio,在\kernel_3.0.1_bcm\drivers\spi下spi_gpio.c中修改引脚号,并配置IO口的模式和方向。注:这里面的drivername为spi_gpio,与1.4中的name需相同。
2.1 修改引脚宏定义
#define GPIO_PIN_MISO (12)
#define GPIO_PIN_SCK (9)
#define GPIO_PIN_MOSI (10)
#define GPIO_PIN_CS (11)
2.2 根据手册,配置引脚
/* reg address */
#define PM_MUX_ADDR_BASE (0x1EC02400)
#define PM_MUX_ADDR_MAXSIZE (0x100)
#define GPIO_ADDR_BASE (0x1EC01400)
#define GPIO_ADDR_MAXSIZE (0x100)
#define GPIO_SWPORTB_DR (0x0C)
#define GPIO_SWPORTB_DDR (0x10)
#define GPIO_EXT_PORTB (0x54)
static void __iomem *pmmux_address_base = NULL;
static void __iomem *gpio_address_base = NULL;
pmmux_address_base = ioremap(PM_MUX_ADDR_BASE, PM_MUX_ADDR_MAXSIZE);
if (pmmux_address_base == NULL) {
PRINT_ERROR("ioremap failed!\n");
goto out_ioremap;
}
gpio_address_base = ioremap(GPIO_ADDR_BASE, GPIO_ADDR_MAXSIZE);
if (gpio_address_base == NULL) {
PRINT_ERROR("ioremap failed!\n");
goto out_ioremap;
}
/* PM_MUX_CTRL_REGS_PIN_MUX_CTRL_19 */
reg = ioread32(pmmux_address_base + 0x8C);
reg &= ~(0xF << 16); //GPIOH_12
reg &= ~(0xF << 12); //GPIOH_11
reg &= ~(0xF << 8); //GPIOH_10
reg &= ~(0xF << 4); //GPIOH_9
iowrite32(reg, pmmux_address_base + 0x8C);
/* PM_MUX_CTRL_REGS_PIN_MUX_PAD_CTRL_11 */
reg = ioread32(pmmux_address_base + 0xc4);
reg &= ~(0xC << 4);
reg |= (0x4 << 4); // GPIOH_11 set PULL_UP
iowrite32(reg, pmmux_address_base + 0xc4);
printk("%s, %d: GPIOH_11 set PULL_UP\n\n", __FILE__, __LINE__);
/* PM_MUX_CTRL_REGS_PIN_MUX_PAD_CTRL_21 */
reg = ioread32(pmmux_address_base + 0x94);
reg &= ~(0xf);
reg |= (0x0); // EXT_IRQH_0
iowrite32(reg, pmmux_address_base + 0x94);
/* set GPIO direction */
reg = ioread32(gpio_address_base + GPIO_SWPORTB_DDR);
reg &= ~(0x1 << GPIO_PIN_MISO); // input
reg |= (0x1 << GPIO_PIN_MOSI); // output
reg |= (0x1 << GPIO_PIN_SCK); // output
reg |= (0x1 << GPIO_PIN_CS); // output
iowrite32(reg, gpio_address_base + GPIO_SWPORTB_DDR);
reg = ioread32(gpio_address_base + GPIO_SWPORTB_DR);
reg |= (0x1 << GPIO_PIN_CS); // CS = 1
iowrite32(reg, gpio_address_base + GPIO_SWPORTB_DR);
3.内核提供mcp251x的驱动,所以在kernel_3.0.1_bcm\drivers\net\can底下注册mcp2515即可。
3.1 修改宏定义devicename,这里使用的是mcp2515。注:这里的drivername应与1.3中的modalias相同。
#define DEVICE_NAME "mcp2515"
4.修改完代码,现在需要在menuconfig中开启相关功能。
4.1 开启spi_gpio
Device Drivers --->
[*] SPI support --->
-*- Utilities for Bitbanging SPI masters
GPIO-based bitbanging SPI Master
User mode SPI device driver support
4.2 开启mcp2515
[*] Networking support --->
CAN bus subsystem support --->
Raw CAN Protocol (raw access with CAN-ID filtering)
Broadcast Manager CAN Protocol (with content filtering)
Platform CAN drivers with Netlink support
[*] CAN bit-timing calculation
Microchip MCP251x SPI CAN controllers
5.编译后将镜像文件烧入板子,应该可以看到spi_gpio和mcp2515注册成功。
6.使用SocketCAN测试是否可用
6.1 下载
6.1.1 canutils的最新源码http://www.pengutronix.de/software/socket-can/download/canutils,最新的为4.0.6。
6.1.2 canutils编译需要libsocketcan库,http://www.pengutronix.de/software/libsocketcan/download/,我下载的是0.0.11。
6.2 编译
6.2.1编译libsocketcan
./configure --host=mipsel-unknown-linux CC=mipsel-unknown-linux-gnu-gcc --prefix=/home/SocketCan/libsocketcan
make
make install
6.2.2 编译canutils
./configure CC=mipsel-unknown-linux-gnu-gcc --host=mipsel-unknown-linux --build=i386-linux libsocketcan_LIBS=-lsocketcan LDFLAGS=-L/home/SocketCan/libsocketcan/lib libsocketcan_CFLAGS=-I/home/SocketCan/libsocketcan/include CFLAGS=-I/home/SocketCan/libsocketcan/include --prefix=/home/SocketCan/canutils
make
make install
7.将lib、bin啥的拷入板子对应目录,该软链接的软链接。
8.回环测试
8.1 配置波特率、回环模式
ifconfig can0 down
canconfig can0 bitrate 500000
canconfig can0 ctrlmode loopback on triple-sampling off
ifconfig can0 up
8.2 开始测试!
candump can0 &
cansend can0 -e 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
成功收到
[8] 11 22 33 44 55 66 77 88
[8] 11 22 33 44 55 66 77 88
至于为啥收到了两帧,还不懂问题出在哪里。
9.两块板子对接测试
注:配置前需要先执行ifconfig can0 down!
两块块板子配置
ifconfig can0 down
canconfig can0 ctrlmode loopback off triple-sampling on
ifconfig can0 up
candump can0 &
cansend can0 -e 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
奇了怪了,就是收不到数据!!!硬件也检查了,软件也检查了,回环可以,但是实际使用却不行,真不知道为啥!仍然在查!