spi test
硬件协议
http://www.mct.net/faq/spi.html
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
http://baike.baidu.com/view/245026.htm
软件
①.添加spi平台设备
在arch/arm/plat-s3c24xx/devs.c已经定义了spi平台设备3c_device_spi0和3c_device_spi1,如下
只是没有加入到mach-mini2440.c,所以只需加入即可如下-----添加3c_device_spi0-------搜索for spi取得关键点
/opt/FriendlyArm/mini2440/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c
note: about nss from 2440 spec
When the SPI system is enabled, the direction of pins except nSS pin is controlled by MSTR bit of SPCONn
register. The direction of nSS pin is always input.
When the SPI is a master, nSS pin is used to check multi-master error, provided that the SPPIN's ENMUL bit is
active, and another GPIO should be used to select a slave.
If the SPI is configured as a slave, the nSS pin is used to select SPI as a slave by one master.
nss 引脚大多数情况下都作为输入(基本上都是)
当2440作为spi master时,nss不要使用(在SPPIN's ENMUL=1时,nss脚要用于排错)。2440的spi master需要使用其他gpio来选中spi slave。当然有几个slave,2440就要再花费几个gpio.
当2400作为spi slave时,2440的nss作为输入,其他spi master要用这个nss来选中这个spi slave.
看来nss的片选功能用于slave模式里面-被片选。
**********************************/
然后配置spi的平台驱动(亦实现spi主机控制器驱动) Samsung S3C24XX series SPI,
还需配置spi外设驱动 User mode SPI device driver support,以便生成设备节点。为便于操作,配置成模块,如下
重新编译内核烧写
编译模块得到两个ko,考到板子上执行
②测试/dev/spidev0.0 .在源码的Documentation/spi目录有写好的测试代码
在spidev_test.c ,我的/usr/include/linux/spi/spidev.h 不管用,所以就直接连接到2.6.32里面
考到板子上执行
source code for testing
refer to
http://www.arm9home.net/read.php?tid-4422.html
http://www.arm9home.net/read.php?tid-10788.html
http://www.arm9home.net/read.php?tid-11762.html
http://www.cnblogs.com/nkzc/archive/2010/07/21/1781959.html
*********************************************************************************************************************************************************
对于te6410 2012-6-10 21
spi平台设备platform_device s3c64xx_device_spi,arch/arm/mach-s3c64xx/dev-spi.c
2012-7-15 19:57:34
关于autorequest GPIO-24 的内核崩溃
后来跟踪到drivers/spi/spi.c里的一个函数里面spi_setup()调用的 status = spi->master->setup(spi);
有用的信息
http://e2e.ti.com/support/embedded/linux/f/354/p/119946/427889.aspx#427889
http://www.mct.net/faq/spi.html
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
http://baike.baidu.com/view/245026.htm
软件
①.添加spi平台设备
在arch/arm/plat-s3c24xx/devs.c已经定义了spi平台设备3c_device_spi0和3c_device_spi1,如下
/* SPI (0) */ static struct resource s3c_spi0_resource[] = { [0] = { .start = S3C24XX_PA_SPI, .end = S3C24XX_PA_SPI + 0x1f, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_SPI0, .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, } }; static u64 s3c_device_spi0_dmamask = 0xffffffffUL; struct platform_device s3c_device_spi0 = { .name = "s3c2410-spi", .id = 0, .num_resources = ARRAY_SIZE(s3c_spi0_resource), .resource = s3c_spi0_resource, .dev = { .dma_mask = &s3c_device_spi0_dmamask, .coherent_dma_mask = 0xffffffffUL } }; EXPORT_SYMBOL(s3c_device_spi0); /* SPI (1) */ static struct resource s3c_spi1_resource[] = { [0] = { .start = S3C24XX_PA_SPI + S3C2410_SPI1, .end = S3C24XX_PA_SPI + S3C2410_SPI1 + 0x1f, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_SPI1, .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, } }; static u64 s3c_device_spi1_dmamask = 0xffffffffUL; struct platform_device s3c_device_spi1 = { .name = "s3c2410-spi", .id = 1, .num_resources = ARRAY_SIZE(s3c_spi1_resource), .resource = s3c_spi1_resource, .dev = { .dma_mask = &s3c_device_spi1_dmamask, .coherent_dma_mask = 0xffffffffUL } }; EXPORT_SYMBOL(s3c_device_spi1);
只是没有加入到mach-mini2440.c,所以只需加入即可如下-----添加3c_device_spi0-------搜索for spi取得关键点
/opt/FriendlyArm/mini2440/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c
//for spi #include <linux/spi/spi.h> #include <mach/spi.h>
//for spi static struct spi_board_info s3c2410_spi0_board[] = { [0] = { .modalias = "spidev", .bus_num = 0, //此spi外设挂接在了哪个spi总线上.2440有两个spi总线(spi主控制器,就像有3个串口一样)。根据外设接线填写。 .chip_select = 0,//片选引脚序号。从0开始。在bus_num(=0)对应的3c2410_spi_info结构体中描述起始片选引脚和数目。 .max_speed_hz = 500*1000, }, }; static struct s3c2410_spi_info s3c2410_spi0_platdata = { .pin_cs = S3C2410_GPF(2),//第一个片选引脚 .num_cs = 1,//片选引脚数目即外接几个spi slave .bus_num = 0,//spi总线编号。因为2440有两个,所以可选值0 1 };
/* devices we initialise */ static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c24xx_uda134x, &s3c_device_nand, &s3c_device_sdi, &s3c_device_usbgadget, &s3c_device_spi0,//for spi };
static void __init mini2440_machine_init(void) { #if defined (LCD_WIDTH) s3c24xx_fb_set_platdata(&mini2440_fb_info); #endif s3c_i2c0_set_platdata(NULL); s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND); s3c_device_nand.dev.platform_data = &friendly_arm_nand_info; s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg; platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); s3c_pm_init(); s3c_device_spi0.dev.platform_data= &s3c2410_spi0_platdata;//for spi spi_register_board_info(s3c2410_spi0_board, ARRAY_SIZE(s3c2410_spi0_board));//for spi }/**********************************
note: about nss from 2440 spec
When the SPI system is enabled, the direction of pins except nSS pin is controlled by MSTR bit of SPCONn
register. The direction of nSS pin is always input.
When the SPI is a master, nSS pin is used to check multi-master error, provided that the SPPIN's ENMUL bit is
active, and another GPIO should be used to select a slave.
If the SPI is configured as a slave, the nSS pin is used to select SPI as a slave by one master.
nss 引脚大多数情况下都作为输入(基本上都是)
当2440作为spi master时,nss不要使用(在SPPIN's ENMUL=1时,nss脚要用于排错)。2440的spi master需要使用其他gpio来选中spi slave。当然有几个slave,2440就要再花费几个gpio.
当2400作为spi slave时,2440的nss作为输入,其他spi master要用这个nss来选中这个spi slave.
看来nss的片选功能用于slave模式里面-被片选。
**********************************/
然后配置spi的平台驱动(亦实现spi主机控制器驱动) Samsung S3C24XX series SPI,
还需配置spi外设驱动 User mode SPI device driver support,以便生成设备节点。为便于操作,配置成模块,如下
Device Drivers ---> [*] SPI support ---> <M> Samsung S3C24XX series SPI <M> User mode SPI device driver support
重新编译内核烧写
编译模块得到两个ko,考到板子上执行
[root@FriendlyARM plg]# insmod spi_s3c24xx.ko [root@FriendlyARM plg]# insmod spidev.ko先insmod spidev.ko也行,如下
[root@FriendlyARM plg]# insmod spidev.ko [root@FriendlyARM plg]# insmod spi_s3c24xx.koinsmod spidev.ko后会出现设备/dev/spidev0.0
②测试/dev/spidev0.0 .在源码的Documentation/spi目录有写好的测试代码
[root@localhost spi]# pwd /opt/FriendlyArm/mini2440/linux-2.6.32.2/Documentation/spi [root@localhost spi]# ls butterfly Makefile~ spidev spidev_fdx.c spidev_test.c spi-lm70llp Makefile pxa2xx spidev_fdx spidev_test spidev_test.c~ spi-summary编译spidev_test.c
在spidev_test.c ,我的/usr/include/linux/spi/spidev.h 不管用,所以就直接连接到2.6.32里面
//#include <linux/spi/spidev.h> #include </opt/FriendlyArm/mini2440/linux-2.6.32.2/include/linux/spi/spidev.h>
[root@localhost spi]# arm-linux-gcc spidev_test.c -o spidev_test
考到板子上执行
[root@FriendlyARM plg]# ./spidev_test -D /dev/spidev0.0 spi mode: 0 bits per word: 8 max speed: 500000 Hz (500 KHz) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
source code for testing
/* * SPI testing utility (using spidev driver) * * Copyright (c) 2007 MontaVista Software, Inc. * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * Cross-compile with cross-gcc -I/path/to/cross-kernel/include */ #include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/types.h> #include </opt/FriendlyArm/mini2440/linux-2.6.32.2/include/linux/spi/spidev.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static void pabort(const char *s) { perror(s); abort(); } static const char *device = "/dev/spidev1.1"; static uint8_t mode; static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; static void transfer(int fd) { int ret; uint8_t tx[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D, }; uint8_t rx[ARRAY_SIZEARRAY_SIZE(tx)] = {0, }; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = ARRAY_SIZE(tx), .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret == 1) pabort("can't send spi message"); for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { if (!(ret % 6)) puts(""); printf("%.2X ", rx[ret]); } puts(""); } static void print_usage(const char *prog) { printf("Usage: %s [-DsbdlHOLC3]\n", prog); puts(" -D --device device to use (default /dev/spidev1.1)\n" " -s --speed max speed (Hz)\n" " -d --delay delay (usec)\n" " -b --bpw bits per word \n" " -l --loop loopback\n" " -H --cpha clock phase\n" " -O --cpol clock polarity\n" " -L --lsb least significant bit first\n" " -C --cs-high chip select active high\n" " -3 --3wire SI/SO signals shared\n"); exit(1); } static void parse_opts(int argc, char *argv[]) { while (1) { static const struct option lopts[] = { { "device", 1, 0, 'D' }, { "speed", 1, 0, 's' }, { "delay", 1, 0, 'd' }, { "bpw", 1, 0, 'b' }, { "loop", 0, 0, 'l' }, { "cpha", 0, 0, 'H' }, { "cpol", 0, 0, 'O' }, { "lsb", 0, 0, 'L' }, { "cs-high", 0, 0, 'C' }, { "3wire", 0, 0, '3' }, { "no-cs", 0, 0, 'N' }, { "ready", 0, 0, 'R' }, { NULL, 0, 0, 0 }, }; int c; c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); if (c == -1) break; switch (c) { case 'D': device = optarg; break; case 's': speed = atoi(optarg); break; case 'd': delay = atoi(optarg); break; case 'b': bits = atoi(optarg); break; case 'l': mode |= SPI_LOOP; break; case 'H': mode |= SPI_CPHA; break; case 'O': mode |= SPI_CPOL; break; case 'L': mode |= SPI_LSB_FIRST; break; case 'C': mode |= SPI_CS_HIGH; break; case '3': mode |= SPI_3WIRE; break; case 'N': mode |= SPI_NO_CS; break; case 'R': mode |= SPI_READY; break; default: print_usage(argv[0]); break; } } } int main(int argc, char *argv[]) { int ret = 0; int fd; parse_opts(argc, argv); fd = open(device, O_RDWR); if (fd < 0) pabort("can't open device"); /* * spi mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) pabort("can't set spi mode"); ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) pabort("can't get spi mode"); /* * bits per word */ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't set bits per word"); ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't get bits per word"); /* * max speed hz */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't set max speed hz"); ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't get max speed hz"); printf("spi mode: %d\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); transfer(fd); close(fd); return ret; }
refer to
http://www.arm9home.net/read.php?tid-4422.html
http://www.arm9home.net/read.php?tid-10788.html
http://www.arm9home.net/read.php?tid-11762.html
http://www.cnblogs.com/nkzc/archive/2010/07/21/1781959.html
*********************************************************************************************************************************************************
对于te6410 2012-6-10 21
spi平台设备platform_device s3c64xx_device_spi,arch/arm/mach-s3c64xx/dev-spi.c
static struct resource s3c64xx_spi1_resource[] = { [0] = { .start = S3C64XX_PA_SPI1, .end = S3C64XX_PA_SPI1 + 0x100 - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = DMACH_SPI1_TX, .end = DMACH_SPI1_TX, .flags = IORESOURCE_DMA, }, [2] = { .start = DMACH_SPI1_RX, .end = DMACH_SPI1_RX, .flags = IORESOURCE_DMA, }, [3] = { .start = IRQ_SPI1, .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, }, }; static struct s3c64xx_spi_info s3c64xx_spi1_pdata = { .cfg_gpio = s3c64xx_spi_cfg_gpio, .fifo_lvl_mask = 0x7f, .rx_lvl_offset = 13, }; struct platform_device s3c64xx_device_spi1 = { .name = "s3c64xx-spi", .id = 1, .num_resources = ARRAY_SIZE(s3c64xx_spi1_resource), .resource = s3c64xx_spi1_resource, .dev = { .dma_mask = &spi_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &s3c64xx_spi1_pdata, }, }; EXPORT_SYMBOL(s3c64xx_device_spi1); void __init s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs) { struct s3c64xx_spi_info *pd; /* Reject invalid configuration */ if (!num_cs || src_clk_nr < 0 || src_clk_nr > S3C64XX_SPI_SRCCLK_48M) { printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__); return; } switch (cntrlr) { case 0: pd = &s3c64xx_spi0_pdata; break; case 1: pd = &s3c64xx_spi1_pdata; break; default: printk(KERN_ERR "%s: Invalid SPI controller(%d)\n", __func__, cntrlr); return; } pd->num_cs = num_cs; pd->src_clk_nr = src_clk_nr; pd->src_clk_name = spi_src_clks[src_clk_nr]; }添加信息到板子文件中,arch/arm/mach-s3c64xx/mach-s3c6410.c
/*add by fatfish for mcp251x*/ static void cs_set_level(unsigned line_id, int lvl) { gpio_direction_output(line_id, lvl); }; static struct s3c64xx_spi_csinfo s3c64xx_spi1_csinfo = { .fb_delay=0x3, .line=S3C64XX_GPC(7), .set_level=cs_set_level, }; static int mcp251x_ioSetup(struct spi_device *spi) { // printk(KERN_INFO "mcp251x: setup gpio pins CS and External Int\n"); printk("mcp251x_ioSetup\n"); s3c_gpio_setpull(S3C64XX_GPL(8), S3C_GPIO_PULL_UP); // External interrupt from CAN controller s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_SFN(3)); // External interrupt from CAN controller (hopefully external interrupt) // s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_INPUT); // External interrupt from CAN controller s3c_gpio_setpull(S3C64XX_GPC(7), S3C_GPIO_PULL_NONE); // Manual chip select pin as used in 6410_set_cs s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_OUTPUT); // Manual chip select pin as used in 6410_set_cs return 0; } static struct mcp251x_platform_data mcp251x_info = { .oscillator_frequency = 16000000, .board_specific_setup = mcp251x_ioSetup, .transceiver_enable = NULL, .power_enable = NULL, }; //spi_device的板信息使用spi_board_info结构体描述,记录了该spi外设的名字,使用的主机控制器序号,片选序号,波特率,spi传输模式(CPHA,CPOL)等 static struct spi_board_info __initdata forlinx6410_mc251x_info[] = { { .modalias = "mcp2515", .platform_data = &mcp251x_info, .irq = IRQ_EINT(16), .max_speed_hz = 10*1000*1000, .bus_num = 1, .chip_select = 0, .mode = SPI_MODE_0, .controller_data=&s3c64xx_spi1_csinfo, }, };
static struct platform_device *smdk6410_devices[] __initdata = { ... &s3c64xx_device_spi0, &s3c64xx_device_spi1,//添加dev-spi.c中的s3c64xx_device_spi1 ... }; static void __init smdk6410_machine_init(void) { s3c64xx_spi_set_info(0,0,1); s3c64xx_spi_set_info(1,0,1);//添加dev-spi.c中的s3c64xx_spi1_pdata spi_register_board_info(forlinx6410_mc251x_info,ARRAY_SIZE(forlinx6410_mc251x_info));//注册spi_board_info ... platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices)); }
2012-7-15 19:57:34
关于autorequest GPIO-24 的内核崩溃
后来跟踪到drivers/spi/spi.c里的一个函数里面spi_setup()调用的 status = spi->master->setup(spi);
有用的信息
http://e2e.ti.com/support/embedded/linux/f/354/p/119946/427889.aspx#427889
HI , i solved the above issue.... by adding the below function call
gpio_request(gpio, NULL); before we set the direction of gpio i.e gpio_direction_output(gpio,0);
Thanks & Regards
Siva Prasad T