spi驱动之can总线mcp2515驱动测试

问1:linux内核.config Makefile Kbuild的关系?
答1:在word里可以找到答案





问2:因为mcp2515是spi转can芯片,所以首先移植spi驱动,分析spi驱动过程
答2:

----------------------------spi驱动整体框架---------------------------------------------		

	spi驱动分三个层次:spi核心层,spi控制器驱动层,spi设备驱动层
	spi核心层		:	与平台无关,向上提供统一接口,位置SPI核心层的代码位于driver/spi/spi.c
	spi控制器驱动层 :	平台移植相关层,每条spi总线提供相应的读写方法,物理上连接若干个从设备,
						 一个控制器驱动可以用数据结构struct spi_master来描述
	spi设备驱动层   :  用户接口层,通过struct spi_driver和struct spi_device描述。	
	
	




//-------------------------------------------------------
spi设备驱动层
*********************************************************
1.		spi_driver和spi_device结构

struct spi_driver {
	const struct spi_device_id *id_table;
	int			(*probe)(struct spi_device *spi);
	int			(*remove)(struct spi_device *spi);
	void			(*shutdown)(struct spi_device *spi);
	int			(*suspend)(struct spi_device *spi, pm_message_t mesg);
	int			(*resume)(struct spi_device *spi);
	struct device_driver	driver;
};


struct spi_device {
	struct device		dev;
	struct spi_master	*master;
	u32			max_speed_hz;
	u8			chip_select;
	u8			mode;
	u8			bits_per_word;
	int			irq;
	void			*controller_state;
	void			*controller_data;
	char			modalias[SPI_NAME_SIZE];

}


 		.modalias   = "m25p10",
 
        .mode   =SPI_MODE_0,   //CPOL=0, CPHA=0 此处选择具体数据传输模式
 
        .max_speed_hz    = 10000000, //最大的spi时钟频率
 
        /* Connected to SPI-0 as 1st Slave */
 
        .bus_num    = 0,   //设备连接在spi控制器0上
 
        .chip_select    = 0, //片选线号,在S5PC100的控制器驱动中没有使用它作为片选的依据,而是选择了下文controller_data里的方法。
 
        .controller_data = &smdk_spi0_csi[0],  
 
通常来说spi_device对应着SPI总线上某个特定的slave。并且spi_device封装了一个spi_master结构体。
spi_device结构体包含了私有的特定的slave设备特性,包括它最大的频率,片选那个,输入输出模式等等


总结:	Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定,
		probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道,SPI的通信是通过消息队列机制,
		而不是像I2C那样通过与从设备进行对话的方式。


***********************************************
2.		spi_device在board中如何注册,通过spi_board_info结构体

spi_device以下一系列的操作是在platform板文件中完成!
 
spi_device的板信息用spi_board_info结构体来描述:
 

struct spi_board_info {
 
charmodalias[SPI_NAME_SIZE];
 
const void*platform_data;
 
void*controller_data;
 
intirq;
 
u32max_speed_hz;
 
u16bus_num;
 
u16chip_select;
 
u8mode;
 
};
 
 
 
这个结构体记录了SPI外设使用的主机控制器序号、片选信号、数据比特率、SPI传输方式等
 
构建的操作是以下的两个步骤:
 
1.
static struct spi_board_info s3c_spi_devs[] __initdata = {
 
{
 
.modalias = "m25p10a",
 
.mode = SPI_MODE_0,
 
.max_speed_hz = 1000000,
 
.bus_num = 0,
 
.chip_select = 0,
 
.controller_data = &smdk_spi0_csi[SMDK_MMCSPI_CS],
 
},
 
};
 
2.
 
 
 
而这个info在init函数调用的时候会初始化:
 
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));
 
 
 
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));//注册spi_board_info。
这个代码会把spi_board_info注册到链表board_list上。spi_device封装了一个spi_master结构体,
事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,
找到挂接在它上面的spi设备,然后创建并注册spi_device。
 
至此spi_device就构建并注册完成了!!!!!!!!!!!!!

*******************************************************************
3. spi_driver的构建与注册
 
 
driver有几个重要的结构体:spi_driver、spi_transfer、spi_message
 
driver有几个重要的函数    :spi_message_init、spi_message_add_tail、spi_sync
 
 
 
   //spi_driver的构建
 
static struct spi_driver   m25p80_driver = { 
 
.driver = {
 
        .name   ="m25p80",
 
        .bus    =&spi_bus_type,
 
        .owner  = THIS_MODULE,
 
    },
 
    .probe  = m25p_probe,
 
    .remove =__devexit_p(m25p_remove),
 
};
 
//spidriver的注册
 
 
 
spi_register_driver(&m25p80_driver);
 
在有匹配的spi_device时,会调用m25p_probe
 
 
 
probe里完成了spi_transfer、spi_message的构建;
 
spi_message_init、spi_message_add_tail、spi_sync、spi_write_then_read函数的调用




	
----------------------------spi驱动分析流程---------------------------------------------
在spi核心层 driver/spi/spi.c	 				

static int __init spi_init(void)
				注册spi总线
				bus_register(&spi_bus_type)	
		
		  		在sys/class下产生spi_master这个节点,用于自动产生设备节点,下面挂接的是控制器的节点		
				class_register(&spi_master_class);	 	
				
其中注册bus结构体
struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_attrs	= spi_dev_attrs,
	.match		= spi_match_device,		//匹配函数
	.uevent		= spi_uevent,
	.suspend	= spi_suspend,
	.resume		= spi_resume,
};							
	 			
类结构体	 				
static struct class spi_master_class = {
	.name		= "spi_master",
	.owner		= THIS_MODULE,
	.dev_release	= spi_master_release,
};	 				
	 				
	 				
顺便分析下匹配函数
static int spi_match_device(struct device *dev, struct device_driver *drv)
				const struct spi_device	*spi = to_spi_device(dev);	
				
				利用id表格匹配
				spi_match_id(sdrv->id_table, spi);
				
				利用名字匹配
				strcmp(spi->modalias, drv->name)	 				





再来看看spi注册函数
int spi_register_driver(struct spi_driver *sdrv)
		注册标准的driver,匹配bus设备链表上的device,如果找到执行相应的函数		
		driver_register(&sdrv->driver);
		
		
最后看看device相关的板级信息函数
int __init spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
	struct boardinfo	*bi;

	bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
	if (!bi)
		return -ENOMEM;
	bi->n_board_info = n;
	memcpy(bi->board_info, info, n * sizeof *info);

	mutex_lock(&board_lock);
	list_add_tail(&bi->list, &board_list);
	mutex_unlock(&board_lock);
	return 0;
}		
函数很简单,利用定义的spi_board_info信息,填充了boardinfo结构,并挂到board_list链表









spi的控制层中重要函数,master的注册函数
int spi_register_master(struct spi_master *master)
			
			扫描并实例化spi设备
			scan_boardinfo(master);	
				寻找注册好的board_list链表中的device
				list_for_each_entry(bi, &board_list, list)
				
				
				因为可能存在多个spi总线,因此spi信息结构也会有
 				多个,找到bus号匹配的就对了
				for (n = bi->n_board_info; n > 0; n--, chip++) {
					if (chip->bus_num != master->bus_num)
				
				//找到了就要实例化它上面的设备了	
				spi_new_device(master, chip)	
			







driver/spi/spidev.c
spi设备文件的自动产生代码分析
 
      这部分代码相当于注册了一个spi实际driver,既是核心平台无关代码,又是个具体实例,
      我们来看下一下具体做了什么,也好学习一spi_driver的各部分具体都需要做些什么,
      代码位于driver/spi/spidev.c下

static int __init spidev_init(void)
			    
			    注册主设备号为153的spi字符设备,spidev_fops结构下面会介绍 
			    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);

				在sys/class下产生spidev这个节点,udev会利用其在dev下产生spidev 
				spidev_class = class_create(THIS_MODULE, "spidev"); 
				
				//注册spi驱动
				status = spi_register_driver(&spidev_spi_driver);


注册的spi_driver 结构体spidev_spi_driver
static struct spi_driver spidev_spi = {
	.driver = {
		.name =		"spidev",
		.owner =	THIS_MODULE,
	},
	.probe =	spidev_probe,					//匹配成功
	.remove =	__devexit_p(spidev_remove),

};

匹配函数
static int spidev_probe(struct spi_device *spi)
			下面两句用于在sys/class/spidev下产生类似于,spidev%d.%d形式的节点,这样,udev等工具就可以
			自动在dev下创建相应设备号的设备节点
			dev = device_create(spidev_class, &spi->dev, spidev->devt,
			spidev, "spidev%d.%d",
		    spi->master->bus_num, spi->chip_select);
		    
		    
至此,spi驱动分析完毕。	






问3:利用linux2.6.32内核自带的spi测试程序,测试的时候
     经过测试,mosi发送数据正确,但是mosi没有直连miso脚,也能收到数据
     用示波器测量miso脚,也没有接收到数据波形,默认高电平,怎么回事?
答3:     
     	
     	
     	
     	
     	
问4:逆向跟踪分析miso脚寄存器相关调用函数?     	
答4:spi_read_reg(drv_data, RA_UART_EMI_REC)  打印寄存器的值是正确的,现在是怎么把寄存器的数据放到驱动中间层?  

struct spi_driver_data 
{
	/* Driver model hookup */
	struct platform_device *pdev;

	/* SPI framework hookup */
	struct spi_master *master;

	/* Driver message queue */
	struct workqueue_struct	*workqueue;
	spinlock_t lock;
	struct list_head queue;
	int busy;
	int run;

	/* Message Transfer pump */
	struct work_struct pump_messages;
	struct tasklet_struct pump_transfers;
	struct spi_message* cur_msg;
	struct spi_transfer* next_transfer;

	u32		transfer_count;

	struct dc_spi_transfer		tx;
	struct dc_spi_transfer		rx;

	...

}  




struct dc_spi_transfer
{
	unsigned int idx;
	unsigned int pos;
	struct spi_transfer* cur;
	struct spi_transfer* transfers[MAX_SPI_TRANSFER_PER_MESSAGE];
}

struct spi_transfer {
	/* it's ok if tx_buf == rx_buf (right?)
	 * for MicroWire, one buffer must be null
	 * buffers must work with dma_*map_single() calls, unless
	 *   spi_message.is_dma_mapped reports a pre-existing mapping
	 */
	const void	*tx_buf;
	void		*rx_buf;
	unsigned	len;

	dma_addr_t	tx_dma;
	dma_addr_t	rx_dma;

	unsigned	cs_change:1;
	u8		bits_per_word;
	u16		delay_usecs;
	u32		speed_hz;

	struct list_head transfer_list;
}





问5:分析spidev的ioctl接口函数?
答5:
在spidev.c中

static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		 	spidev_message(spidev, ioc, n_ioc)
		 		spidev_sync(spidev, &msg)
		 			spi_async(spidev->spi, message)
		 				master->transfer(spi, message)
		 				
		 				
//--------------
函数spi->master->transfer()在函数spi_bitbang_start()中被初始化为函数spi_bitbang_transfer()如下 

if (!bitbang->master->transfer)
     bitbang->master->transfer = spi_bitbang_transfer; 

函数spi_bitbang_transfer()又在函数s3c24xx_spi_probe()中被调用。 

函数spi_bitbang_transfer()在文件spi_bitbang.c中实现。 









//-------------------------------------------------------
调试打印记录
parse_spi_message: TX transfer for 3 bytes, buffer VA cc170000(ccf5aa55)


parse_spi_message: 
1 xfers, 
wr 3, 
rd 0 
(pri=3, 
qw=0, 
bytes=0, 
rout=3, 
rxs=3)

SPI_DEBUG_PRINT_INFO("%s: %d xfers, wr %d, rd %d (pri=%d, qw=%d, bytes=%d, rout=%d, rxs=%d)\n", 
		__func__, 
		drv_data->transfer_count, 
		drv_data->total_write, 
		drv_data->total_read,
		drv_data->priming, 
		drv_data->qwords, 
		drv_data->bytes, 
		drv_data->readout, 
		drv_data->rx_start_idx)		 				



	int total_write;					// total number of bytes to write
	int total_read;						// total number of bytes to read
	int total_write_or_read;			// total number of bytes to read or write
									
	int bytes;							// number of bytes read-writes
	int qwords;							// number of qword read-writes
	int readout;						// number of byte reads at the end of transfer
	int priming;						// number of bytes to prime
	int rx_start_idx;					// position where to start saving rx into input buffer






问6:spi的probe函数执行过程,如何调用底层驱动函数?
答6:
int __init dc_usart_spi_probe(struct platform_device *pdev)
				init_queues(drv_data)
					tasklet_init(&drv_data->pump_transfers,	pump_transfers,	(unsigned long)drv_data)
					INIT_WORK(&drv_data->pump_messages, pump_messages)
					
						RELEASE_STATIC void pump_messages(struct work_struct *data)
												drv_data->cur_msg->state = parse_spi_message(drv_data)
												tasklet_schedule(&drv_data->pump_transfers)		
												
													RELEASE_STATIC void pump_transfers(unsigned long data)
																		dc_usart_nondma_transfer(drv_data)
																			rxc = spi_receive_byte(drv_data)
																			
																			
通过queue_work(drv_data->workqueue, &drv_data->pump_messages)调用工作任务函数pump_messages,
认为调用parse_spi_message函数中
else if (transfer->rx_buf)一直为假,所以drv_data->total_read=0,所以spi_receive_byte接收的寄存器数据没有填充spi_transfer
所以,应用接口层没有收到底层发来的数据

当spi有接收数据的时候,通过什么机制调用parse_spi_message

了解两个函数
tasklet_init	
INIT_WORK																		


  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
全志R40平台的tinav2.1系统下打开SPI2接口 1、(可选修改) Q:\r40_tinav2.1\spi20_r40_tinav2.1\lichee\brandy\build.sh build_uboot() { if [ "x${PLATFORM}" = "xsun50iw1p1" ] || \ [ "x${PLATFORM}" = "xsun50iw2p1" ] || \ [ "x${PLATFORM}" = "xsun50iw6p1" ] || \ [ "x${PLATFORM}" = "xsun50iw3p1" ] || \ [ "x${PLATFORM}" = "xsun8iw12p1" ] || \ [ "x${PLATFORM}" = "xsun8iw10p1" ] || \ [ "x${PLATFORM}" = "xsun8iw11p1" ]; then cd u-boot-2014.07/ else cd u-boot-2011.09/ fi make distclean if [ "x$MODE" = "xota_test" ] ; then export "SUNXI_MODE=ota_test" fi make ${PLATFORM}_config make -j16 #make spl #make fes if [ ${PLATFORM} = "sun8iw11p1" ]; then make distclean make ${PLATFORM}_nor_config make -j16 #make spl #make fes fi cd - 1>/dev/null } 2、 Q:\r40_tinav2.1\spi20_r40_tinav2.1\lichee\linux-3.10\drivers\spi\spidev.c static struct spi_driver spidev_spi_driver = { .driver = { .name = "spidev", .owner = THIS_MODULE, .of_match_table = of_match_ptr(spidev_dt_ids), }, .probe = spidev_probe, .remove = spidev_remove, /* NOTE: suspend/resume methods are not necessary here. * We don't do anything except pass the requests to/from * the underlying controller. The refrigerator handles * most issues; the controller driver handles the rest. */ }; 3、验证APP程序: Q:\r40_tinav2.1\spi20_r40_tinav2.1\package\allwinner\spidev20_test\Makefile ############################################## # OpenWrt Makefile for helloworld program # # # Most of the variables used here are defined in # the include directives below. We just need to # specify a basic description of the package, # where to build our program, where to find # the source files, and where to install the # compiled program on the router. # # Be very careful of spacing in this file. # Indents should be tabs, not spaces, and # there should be no trailing whitespace in # lines that are not commented. # ############################################## include $(TOPDIR)/rules.mk # Name and release number of this package PKG_NAME:=spidev20_test PKG_VERSION:=0.0.1 PKG_RELEASE:=1 # This specifies the directory where we're going to build the program. # The root build directory, $(BUILD_DIR), is by default the build_mipsel # directory in your OpenWrt SDK directory PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME) include $(BUILD_DIR)/package.mk # Specify package information for this program. # The variables defined here should be self explanatory. # If you are running Kamikaze, delete the DESCRIPTION # variable below and uncomment the Kamikaze define # directive for the description below define Package/spidev20_test SECTION:=utils CATEGORY:=Allwinner TITLE:=spidev20_test just test the SPI2 interface DEPENDS:=+libpthread endef # Uncomment portion below for Kamikaze and delete DESCRIPTION variable above define Package/spidev20_test/description If you can't figure out what this program does, you're probably brain-dead and need immediate medical attention. endef # Specify what needs to be done to prepare for building the package. # In our case, we need to copy the source files to the build directory. # This is NOT the default. The default uses the PKG_SOURCE_URL and the # PKG_SOURCE which is not defined here to download the source from the web. # In order to just build a simple program that we have just written, it is # much easier to do it this way. define Build/Prepare mkdir -p $(PKG_BUILD_DIR) $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Configure endef define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ CC="$(TARGET_CC)" \ CFLAGS="$(TARGET_CFLAGS)" -Wall \ LDFLAGS="$(TARGET_LDFLAGS)" \ LIBS="-lpthread" \ all endef # We do not need to define Build/Configure or Build/Compile directives # The defaults are appropriate for compiling a simple program such as this one # Specify where and how to install the program. Since we only have one file, # the helloworld executable, install it by copying it to the /bin directory on # the router. The $(1) variable represents the root directory on the router running # OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install # directory if it does not already exist. Likewise $(INSTALL_BIN) contains the # command to copy the binary file from its current location (in our case the build # directory) to the install directory. define Package/spidev20_test/install $(INSTALL_DIR) $(1)/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/spidev20_test $(1)/bin/ endef # This line executes the necessary commands to compile our program. # The above define directives specify all the information needed, but this # line calls BuildPackage which in turn actually uses this information to # build a package. $(eval $(call BuildPackage,spidev20_test)) Q:\r40_tinav2.1\spi20_r40_tinav2.1\package\allwinner\spidev20_test\src\Makefile TARGET = spidev20_test INCLUDES += -I. -Icommon/ LIBS += -lpthread -lm -lrt SRCS = spidev20_test.c OBJS = $(SRCS:.c=.o) %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< $(TARGET): $(OBJS) $(CC) -o $@ $(OBJS) $(LIBS) $(LDFLAGS) all:$(TARGET) clean: rm -rf $(TARGET) *.o *.a *~ cd common && rm -f *.o *.a *.bak *~ .depend Q:\r40_tinav2.1\spi20_r40_tinav2.1\package\allwinner\spidev20_test\src\spidev20_test.c /* * 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 <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/spidev0.0"; //static const char *device = "/dev/spidev0.1"; static const char *device = "/dev/spidev2.0"; 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, //}; // CityBrand WelCome U! uint8_t tx[] = { 0x43, 0x69, 0x74, 0x79, 0x42, 0x72, 0x61, 0x6E, 0x64, 0x20, 0x57, 0x65, 0x6C, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x55, 0x21, 0x43, 0x69, 0x74, 0x79, 0x42, 0x72, 0x61, 0x6E, 0x64, 0x20, 0x57, 0x65, 0x6C, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x55, 0x21, 0x43, 0x69, 0x74, 0x79, 0x42, 0x72, 0x61, 0x6E, 0x64, 0x20, 0x57, 0x65, 0x6C, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x55, 0x21, }; uint8_t rx[ARRAY_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]); if (!(ret % 20)){ puts("\n"); } printf("%c", rx[ret]); } //puts(""); puts("\n"); } 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; } 4、修改配置文件: Q:\r40_tinav2.1\spi20_r40_tinav2.1\target\allwinner\azalea-m2ultra\configs\sys_config.fex [jtag_para] jtag_enable = 1 jtag_ms = port:PB14<3><default><default><default> jtag_ck = port:PB15<3><default><default><default> jtag_do = port:PB16<3><default><default><default> jtag_di = port:PB17<3><default><default><default> 修改为: [jtag_para] jtag_enable = 0 ;jtag_ms = port:PB14<3><default><default><default> ;jtag_ck = port:PB15<3><default><default><default> ;jtag_do = port:PB16<3><default><default><default> ;jtag_di = port:PB17<3><default><default><default> ;---------------------------------------------------------------------------------- ;SPI controller configuration ;---------------------------------------------------------------------------------- [spi0] spi0_used = 0 spi0_cs_number = 2 spi0_cs_bitmap = 3 spi0_cs0 = port:PC23<3><1><default><default> spi0_cs1 = port:PI14<2><1><default><default> spi0_sclk = port:PC2<3><default><default><default> spi0_mosi = port:PC0<3><default><default><default> spi0_miso = port:PC1<3><default><default><default> [spi1] spi1_used = 0 spi1_cs_number = 2 spi1_cs_bitmap = 3 spi1_cs0 = port:PA0<3><1><default><default> spi1_cs1 = port:PA4<3><1><default><default> spi1_sclk = port:PA1<3><default><default><default> spi1_mosi = port:PA2<3><default><default><default> spi1_miso = port:PA3<3><default><default><default> [spi2] spi2_used = 0 spi2_cs_number = 2 spi2_cs_bitmap = 3 spi2_cs0 = port:PB14<2><1><default><default> spi2_cs1 = port:PB13<2><1><default><default> spi2_sclk = port:PB15<2><default><default><default> spi2_mosi = port:PB16<2><default><default><default> spi2_miso = port:PB17<2><default><default><default> [spi3] spi3_used = 0 spi3_cs_number = 2 spi3_cs_bitmap = 3 spi3_cs0 = port:PA5<3><1><default><default> spi3_cs1 = port:PA9<3><1><default><default> spi3_sclk = port:PA6<3><default><default><default> spi3_mosi = port:PA7<3><default><default><default> spi3_miso = port:PA8<3><default><default><default> ;---------------------------------------------------------------------------------- ;SPI device configuration ;compatible --- device name ;spi-max-frequency --- work frequency ;reg --- chip select ;optional properties: spi-cpha, spi-cpol, spi-cs-high ;---------------------------------------------------------------------------------- ;[spi0/spi_board0] ;compatible = ;spi-max-frequency = ;reg = ;spi-cpha ;spi-cpol ;spi-cs-high 修改为: ;---------------------------------------------------------------------------------- ;SPI controller configuration ;---------------------------------------------------------------------------------- ;spi0有接SPI器件(和PC引脚和NAND冲突),但是空贴! [spi0] spi0_used = 0 spi0_cs_number = 2 spi0_cs_bitmap = 3 spi0_cs0 = port:PC23<3><1><default><default> spi0_cs1 = port:PI14<2><1><default><default> spi0_sclk = port:PC2<3><default><default><default> spi0_mosi = port:PC0<3><default><default><default> spi0_miso = port:PC1<3><default><default><default> ;和gmac0复用冲突了! [spi1] spi1_used = 0 spi1_cs_number = 2 spi1_cs_bitmap = 3 spi1_cs0 = port:PA0<3><1><default><default> spi1_cs1 = port:PA4<3><1><default><default> spi1_sclk = port:PA1<3><default><default><default> spi1_mosi = port:PA2<3><default><default><default> spi1_miso = port:PA3<3><default><default><default> ;大排针J9引出来了! [spi2] spi2_used = 1 spi2_cs_number = 2 spi2_cs_bitmap = 3 spi2_cs0 = port:PB14<2><1><default><default> spi2_cs1 = port:PB13<2><1><default><default> spi2_sclk = port:PB15<2><default><default><default> spi2_mosi = port:PB16<2><default><default><default> spi2_miso = port:PB17<2><default><default><default> ;和gmac0复用冲突了! [spi3] spi3_used = 0 spi3_cs_number = 2 spi3_cs_bitmap = 3 spi3_cs0 = port:PA5<3><1><default><default> spi3_cs1 = port:PA9<3><1><default><default> spi3_sclk = port:PA6<3><default><default><default> spi3_mosi = port:PA7<3><default><default><default> spi3_miso = port:PA8<3><default><default><default> ;---------------------------------------------------------------------------------- ;SPI device configuration ;compatible --- device name ;spi-max-frequency --- work frequency ;reg --- chip select ;optional properties: spi-cpha, spi-cpol, spi-cs-high ;---------------------------------------------------------------------------------- ;[spi0/spi_board0] ;compatible = ;spi-max-frequency = ;reg = ;spi-cpha ;spi-cpol ;spi-cs-high [spi2/spi_board2] compatible = "spidev" spi-max-frequency = 50000000 reg = 0 ;spi-cpha = 0 ;spi-cpol = 0 ;spi-cs-high = 0 5、刷机之后: root@TinaLinux:/# root@TinaLinux:/# find . -name spi* ./bin/spidev20_test ./dev/spidev2.0 ./proc/irq/44/spi2 ./rom/bin/spidev20_test ./rom/usr/lib/opkg/info/spidev20_test.control ./rom/usr/lib/opkg/info/spidev20_test.list ./sys/bus/spi ./sys/bus/spi/devices/spi2.0 ./sys/bus/spi/drivers/spidev ./sys/bus/spi/drivers/spidev/spi2.0 ./sys/bus/platform/devices/spi2 ./sys/bus/platform/drivers/spi ./sys/bus/platform/drivers/spi/spi2 ./sys/devices/soc/spi2 ./sys/devices/soc/spi2/spi_master ./sys/devices/soc/spi2/spi_master/spi2 ./sys/devices/soc/spi2/spi_master/spi2/spi2.0 ./sys/devices/soc/spi2/spi_master/spi2/spi2.0/spidev ./sys/devices/soc/spi2/spi_master/spi2/spi2.0/spidev/spidev2.0 ./sys/class/spi_master ./sys/class/spi_master/spi2 ./sys/class/spidev ./sys/class/spidev/spidev2.0 ./sys/kernel/debug/clk/hosc/pll_periph0/spi2 ./sys/kernel/debug/clk/hosc/spi0 ./sys/kernel/debug/clk/hosc/spi1 ./sys/kernel/debug/clk/hosc/spi3 ./sys/module/spidev ./usr/lib/opkg/info/spidev20_test.control ./usr/lib/opkg/info/spidev20_test.list root@TinaLinux:/# root@TinaLinux:/#

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值