SPI驱动之子系统架构及重要数据结构



http://blog.csdn.net/miansi_yang/article/details/16064989


1. SPI子系统架构详解

SPI总线上有两类设备:一类是主控端,通常作为SOC系统的一个子模块出现,比如很多嵌入式MPU中都常常包含SPI模块;一类是受控端,例如一些SPI接口的Flash、传感器等等。主控端是SPI总线的控制者,通过使用SPI协议主动发起SPI总线上的会话,而受控端则被动接受SPI主控端的指令,并作出相应的响应。

图还未画好,之后补上,补上后在一些写分析,哈哈。。。

2. 重要数据结构

(1)spi_master

struct spi_master用来描述一个SPI主控制器,我们一般不需要自己编写spi控制器驱动。

  1. /**  
  2.  * 结构体master代表一个SPI接口,或者叫一个SPI主机控制器, 
  3.  * 一个接口对应一条SPI总线,master->bus_num则记录了这个总线号。  
  4.  */  
  5. struct spi_master {  
  6.     struct device   dev;  
  7.   
  8.     struct list_head list;  
  9.   
  10.     /**  
  11.      * 总线编号,从零开始。 
  12.      * 系统会用这个值去和系统中board_list链表中加入的每一个boardinfo结构中的每一个spi_board_info中的bus_num进行匹配, 
  13.      * (每个boardinfo结构都是一个spi_board_info的集合,每一个spi_board_info都是对应一个SPI(从)设备的描述) 
  14.      * 如果匹配上就说明这个spi_board_info描述的SPI(从)设备是链接在此总线上的,因此就会调用spi_new_device去创建一个spi_device。 
  15.      */  
  16.     s16         bus_num;  
  17.   
  18.     /* 支持的片选的数量。从设备的片选号不能大于这个数.该值当然不能为0,否则会注册失败 */  
  19.     u16         num_chipselect;  
  20.   
  21.     /* some SPI controllers pose alignment requirements on DMAable 
  22.      * buffers; let protocol drivers know about these requirements. 
  23.      */  
  24.     u16         dma_alignment;  
  25.   
  26.     /* spi_device.mode flags understood by this controller driver */  
  27.     u16         mode_bits;  
  28.   
  29.     /* other constraints relevant to this driver */  
  30.     u16         flags;  
  31. #define SPI_MASTER_HALF_DUPLEX  BIT(0)      /* can't do full duplex */  
  32. #define SPI_MASTER_NO_RX    BIT(1)      /* can't do buffer read */  
  33. #define SPI_MASTER_NO_TX    BIT(2)      /* can't do buffer write */  
  34.   
  35.     /* lock and mutex for SPI bus locking */  
  36.     spinlock_t      bus_lock_spinlock;  
  37.     struct mutex        bus_lock_mutex;  
  38.   
  39.     /* flag indicating that the SPI bus is locked for exclusive use */  
  40.     bool            bus_lock_flag;  
  41.   
  42.     int         (*setup)(struct spi_device *spi); //根据spi设备更新硬件配置  
  43.   
  44.     /** 
  45.      * 添加消息到队列的方法。此函数不可睡眠,其作用只是安排需要的传送, 
  46.      * 并且在适当的时候(传送完成或者失败)调用spi_message中的complete方法,来将结果报告给用户。 
  47.      */  
  48.     int         (*transfer)(struct spi_device *spi, struct spi_message *mesg);  
  49.   
  50.     /*cleanup函数会在spidev_release函数中被调用,spidev_release被登记为spidev的release函数*/  
  51.     void            (*cleanup)(struct spi_device *spi);  
  52. };  
/** 
 * 结构体master代表一个SPI接口,或者叫一个SPI主机控制器,
 * 一个接口对应一条SPI总线,master->bus_num则记录了这个总线号。 
 */
struct spi_master {
	struct device	dev;

	struct list_head list;

	/** 
	 * 总线编号,从零开始。
	 * 系统会用这个值去和系统中board_list链表中加入的每一个boardinfo结构中的每一个spi_board_info中的bus_num进行匹配,
	 * (每个boardinfo结构都是一个spi_board_info的集合,每一个spi_board_info都是对应一个SPI(从)设备的描述)
	 * 如果匹配上就说明这个spi_board_info描述的SPI(从)设备是链接在此总线上的,因此就会调用spi_new_device去创建一个spi_device。
	 */
	s16			bus_num;

	/* 支持的片选的数量。从设备的片选号不能大于这个数.该值当然不能为0,否则会注册失败 */
	u16			num_chipselect;

	/* some SPI controllers pose alignment requirements on DMAable
	 * buffers; let protocol drivers know about these requirements.
	 */
	u16			dma_alignment;

	/* spi_device.mode flags understood by this controller driver */
	u16			mode_bits;

	/* other constraints relevant to this driver */
	u16			flags;
#define SPI_MASTER_HALF_DUPLEX	BIT(0)		/* can't do full duplex */
#define SPI_MASTER_NO_RX	BIT(1)		/* can't do buffer read */
#define SPI_MASTER_NO_TX	BIT(2)		/* can't do buffer write */

	/* lock and mutex for SPI bus locking */
	spinlock_t		bus_lock_spinlock;
	struct mutex		bus_lock_mutex;

	/* flag indicating that the SPI bus is locked for exclusive use */
	bool			bus_lock_flag;

	int			(*setup)(struct spi_device *spi); //根据spi设备更新硬件配置

	/**
	 * 添加消息到队列的方法。此函数不可睡眠,其作用只是安排需要的传送,
	 * 并且在适当的时候(传送完成或者失败)调用spi_message中的complete方法,来将结果报告给用户。
	 */
	int			(*transfer)(struct spi_device *spi, struct spi_message *mesg);

	/*cleanup函数会在spidev_release函数中被调用,spidev_release被登记为spidev的release函数*/
	void			(*cleanup)(struct spi_device *spi);
};

spi控制器的驱动在kernel3.0.15/arch/arm/mach-exynos/mach-smdk4x12.c中声明和注册一个平台设备,然后在kernel3.0.15/driver/spi下面建立一个平台驱动。spi_master注册过程中会扫描kernel3.0.15/arch/arm/mach-exynos/mach-smdk4x12.c中调用spi_register_board_info注册的信息,为每一个与本总线编号相同的信息建立一个spi_device。根据Linux内核的驱动模型,注册在同一总线下的驱动和设备会进行匹配。spi_bus_type总线匹配的依据是名字,这样当自己编写的spi_driver和spi_device同名的时候,spi_driver的probe方法就会被用,spi_driver就能看到与自己匹配的spi_device了。

(2)spi_device

struct spi_device用来描述一个SPI从设备。

  1. /** 
  2.  * 该结构体用于描述SPI设备,也就是从设备的相关信息。 
  3.  * 注意:SPI子系统只支持主模式,也就是说SOC上的SPI只能工作在master模式, 
  4.  * 外围设备只能为slave模式。 
  5.  */  
  6. struct spi_device {  
  7.     struct device       dev;  
  8.     struct spi_master   *master; //对应的控制器指针  
  9.     u32         max_speed_hz; //spi传输时钟  
  10.     u8          chip_select; //片选号,用来区分同一主控制器上的设备  
  11.     u8          mode; //各bit的定义如下,主要是时钟相位/时钟极性  
  12. #define SPI_CPHA    0x01            /* clock phase */  
  13. #define SPI_CPOL    0x02            /* clock polarity */  
  14. #define SPI_MODE_0  (0|0)           /* (original MicroWire) */  
  15. #define SPI_MODE_1  (0|SPI_CPHA)  
  16. #define SPI_MODE_2  (SPI_CPOL|0)  
  17. #define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)  
  18. #define SPI_CS_HIGH 0x04            /* chipselect active high? */ //片选电位为高  
  19. #define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */ //先输出低比特位  
  20. #define SPI_3WIRE   0x10            /* SI/SO signals shared */ //输入输出共享接口,此时只能做半双工  
  21. #define SPI_LOOP    0x20            /* loopback mode */  
  22. #define SPI_NO_CS   0x40            /* 1 dev/bus, no chipselect */  
  23. #define SPI_READY   0x80            /* slave pulls low to pause */  
  24.     u8          bits_per_word; //每个字长的比特数  
  25.     int         irq; //使用到的比特数  
  26.     void            *controller_state;  
  27.     void            *controller_data;  
  28.     char            modalias[SPI_NAME_SIZE]; //spi是设备的名字  
  29.   
  30.     /* 
  31.      * likely need more hooks for more protocol options affecting how 
  32.      * the controller talks to each chip, like: 
  33.      *  - memory packing (12 bit samples into low bits, others zeroed) 
  34.      *  - priority 
  35.      *  - drop chipselect after each word 
  36.      *  - chipselect delays 
  37.      *  - ... 
  38.      */  
  39. };  
/**
 * 该结构体用于描述SPI设备,也就是从设备的相关信息。
 * 注意:SPI子系统只支持主模式,也就是说SOC上的SPI只能工作在master模式,
 * 外围设备只能为slave模式。
 */
struct spi_device {
	struct device		dev;
	struct spi_master	*master; //对应的控制器指针
	u32			max_speed_hz; //spi传输时钟
	u8			chip_select; //片选号,用来区分同一主控制器上的设备
	u8			mode; //各bit的定义如下,主要是时钟相位/时钟极性
#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 */
	u8			bits_per_word; //每个字长的比特数
	int			irq; //使用到的比特数
	void			*controller_state;
	void			*controller_data;
	char			modalias[SPI_NAME_SIZE]; //spi是设备的名字

	/*
	 * likely need more hooks for more protocol options affecting how
	 * the controller talks to each chip, like:
	 *  - memory packing (12 bit samples into low bits, others zeroed)
	 *  - priority
	 *  - drop chipselect after each word
	 *  - chipselect delays
	 *  - ...
	 */
};

(3)spi_driver

struct spi_driver用于描述SPI从设备驱动。驱动核心将根据driver.name和spi_board_info的modalias进行匹配,如果modalias和name相等,则绑定驱动程序和kernel3.0.5/arch/arm/mach-exynos/mach-smdk4x12.c中调用spi_register_board_info注册的信息对应的spi_device设备。它们的形式和struct platform_driver是一致的。

  1. struct spi_driver {  
  2.     const struct spi_device_id *id_table; //可以驱动的设备表,也就是说该驱动可以驱动一类设备  
  3.     int         (*probe)(struct spi_device *spi); //和spi_device匹配成功之后会调用这个方法.因此这个方法需要对设备和私有数据进行初始化  
  4.     int         (*remove)(struct spi_device *spi); //解除spi_device和spi_driver的绑定,释放probe申请的资源  
  5.     void            (*shutdown)(struct spi_device *spi); //一般牵扯到电源管理会用到,关闭  
  6.     int         (*suspend)(struct spi_device *spi, pm_message_t mesg); //一般牵扯到电源管理会用到,挂起  
  7.     int         (*resume)(struct spi_device *spi); //一般牵扯到电源管理会用到,恢复  
  8.     struct device_driver     driver;  
  9. };  
struct spi_driver {
	const struct spi_device_id *id_table; //可以驱动的设备表,也就是说该驱动可以驱动一类设备
	int			(*probe)(struct spi_device *spi); //和spi_device匹配成功之后会调用这个方法.因此这个方法需要对设备和私有数据进行初始化
	int			(*remove)(struct spi_device *spi); //解除spi_device和spi_driver的绑定,释放probe申请的资源
	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;
};

(4)spi_transfer

struct spi_transfer是对一次完整的数据传输的描述。每个spi_transfer总是读取和写入同样的长度的比特数,但是可以很容易的使用空指针舍弃读或写,为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的。

  1. struct spi_transfer {  
  2.     /* it's ok if tx_buf == rx_buf (right?) 
  3.      * for MicroWire, one buffer must be null 
  4.      * buffers must work with dma_*map_single() calls, unless 
  5.      *   spi_message.is_dma_mapped reports a pre-existing mapping 
  6.      */  
  7.     const void  *tx_buf; //要写入设备的数据(必须是dma_safe),或者为NULL  
  8.     void        *rx_buf; //要读取的数据缓冲(必须是dma_safe),或者为NULL  
  9.     unsigned    len; //tx和tr的大小(字节数),这里不是指它的和,而是各自的长度,它们总是相等的  
  10.   
  11.     dma_addr_t  tx_dma; //如果spi_message.is_dma_mapped是真,这个是tx的dma地址  
  12.     dma_addr_t  rx_dma; //如果spi_message.is_dma_mapped是真,这个是rx的dma地址  
  13.   
  14.     unsigned    cs_change:1; //影响此次传输之后的片选,指示本次transfer结束之后是否要重新片选并调用setup改变设置  
  15.     u8      bits_per_word; //每个字长的比特数,如果是0,使用默认值  
  16.     u16     delay_usecs; //此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息  
  17.     u32     speed_hz; //通信时钟,如果是0,使用默认值  
  18.   
  19.     struct list_head transfer_list; //用来连接的双向链表节点  
  20. };  
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; //要写入设备的数据(必须是dma_safe),或者为NULL
	void		*rx_buf; //要读取的数据缓冲(必须是dma_safe),或者为NULL
	unsigned	len; //tx和tr的大小(字节数),这里不是指它的和,而是各自的长度,它们总是相等的

	dma_addr_t	tx_dma; //如果spi_message.is_dma_mapped是真,这个是tx的dma地址
	dma_addr_t	rx_dma; //如果spi_message.is_dma_mapped是真,这个是rx的dma地址

	unsigned	cs_change:1; //影响此次传输之后的片选,指示本次transfer结束之后是否要重新片选并调用setup改变设置
	u8		bits_per_word; //每个字长的比特数,如果是0,使用默认值
	u16		delay_usecs; //此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息
	u32		speed_hz; //通信时钟,如果是0,使用默认值

	struct list_head transfer_list; //用来连接的双向链表节点
};

(5)spi_message

struct spi_message就是对多个spi_transfer的封装。在消息需要传递的时候,会将spi_transfer通过自己的transfer_list字段挂到spi_message的transfers链表头上。spi_message用来原子的执行spi_transfer表示的一串数组传输请求。这个传输队列是原子的,这意味着在这个消息完成之前不会有其它消息占用总线。消息的执行总是按照FIFO的顺序,向底层提交spi_message的代码要负责管理它的内存空间。未显示初始化的内存需要使用0来初始化。为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的。

  1. struct spi_message {  
  2.     struct list_head    transfers; //此次消息的传输队列,一个消息可以包含多个传输段  
  3.   
  4.     struct spi_device   *spi; //传输的目的设备  
  5.   
  6.     unsigned        is_dma_mapped:1; //如果为真,此次调用提供dma和cpu虚拟地址  
  7.   
  8.     /* REVISIT:  we might want a flag affecting the behavior of the 
  9.      * last transfer ... allowing things like "read 16 bit length L" 
  10.      * immediately followed by "read L bytes".  Basically imposing 
  11.      * a specific message scheduling algorithm. 
  12.      * 
  13.      * Some controller drivers (message-at-a-time queue processing) 
  14.      * could provide that as their default scheduling algorithm.  But 
  15.      * others (with multi-message pipelines) could need a flag to 
  16.      * tell them about such special cases. 
  17.      */  
  18.   
  19.     /* completion is reported through a callback */  
  20.     void            (*complete)(void *context); //异步调用完成后的回调函数  
  21.     void            *context; //回调函数的参数  
  22.     unsigned        actual_length; //此次传输的实际长度  
  23.     int         status; //执行的结果,成功被置0,否则是一个负的错误码  
  24.   
  25.     /* for optional use by whatever driver currently owns the 
  26.      * spi_message ...  between calls to spi_async and then later 
  27.      * complete(), that's the spi_master controller driver. 
  28.      */  
  29.     struct list_head    queue;  
  30.     void            *state;  
  31. };  
struct spi_message {
	struct list_head	transfers; //此次消息的传输队列,一个消息可以包含多个传输段

	struct spi_device	*spi; //传输的目的设备

	unsigned		is_dma_mapped:1; //如果为真,此次调用提供dma和cpu虚拟地址

	/* REVISIT:  we might want a flag affecting the behavior of the
	 * last transfer ... allowing things like "read 16 bit length L"
	 * immediately followed by "read L bytes".  Basically imposing
	 * a specific message scheduling algorithm.
	 *
	 * Some controller drivers (message-at-a-time queue processing)
	 * could provide that as their default scheduling algorithm.  But
	 * others (with multi-message pipelines) could need a flag to
	 * tell them about such special cases.
	 */

	/* completion is reported through a callback */
	void			(*complete)(void *context); //异步调用完成后的回调函数
	void			*context; //回调函数的参数
	unsigned		actual_length; //此次传输的实际长度
	int			status; //执行的结果,成功被置0,否则是一个负的错误码

	/* for optional use by whatever driver currently owns the
	 * spi_message ...  between calls to spi_async and then later
	 * complete(), that's the spi_master controller driver.
	 */
	struct list_head	queue;
	void			*state;
};

(6)两个重要的板级结构

两个板级结构,其中spi_board_info用来初始化spi_device,s3c64xx_spi_info用来初始化spi_master。这两个板级的结构需要在移植的时候在kernel3.0.15/arch/arm/mach-exynos/mach-smdk4x12.c中初始化。

spi_board_info(kernel3.0.15/linux/include/spi/spi.h)

  1. /* 该结构也是对SPI从设备(spi_device)的描述,只不过它是板级信息,最终该结构的所有字段都将用于初始化SPI设备结构体spi_device */  
  2. struct spi_board_info {  
  3.     /* the device name and module name are coupled, like platform_bus; 
  4.      * "modalias" is normally the driver name. 
  5.      * 
  6.      * platform_data goes to spi_device.dev.platform_data, 
  7.      * controller_data goes to spi_device.controller_data, 
  8.      * irq is copied too 
  9.      */  
  10.     char        modalias[SPI_NAME_SIZE]; //spi设备名,会拷贝到spi_device的相应字段中.这是设备spi_device在SPI总线spi_bus_type上匹配驱动的唯一标识  
  11.     const void  *platform_data; //平台数据  
  12.     void        *controller_data;  
  13.     int     irq; //中断号  
  14.   
  15.     /* slower signaling on noisy or low voltage boards */  
  16.     u32     max_speed_hz; //SPI设备工作时的波特率  
  17.   
  18.   
  19.     /* bus_num is board specific and matches the bus_num of some 
  20.      * spi_master that will probably be registered later. 
  21.      * 
  22.      * chip_select reflects how this chip is wired to that master; 
  23.      * it's less than num_chipselect. 
  24.      */  
  25.     u16     bus_num; //该SPI(从)设备所在总线的总线号,就记录了所属的spi_master之中的bus_num编号.一个spi_master就对应一条总线  
  26.     u16     chip_select; //片选号.该SPI(从)设备在该条SPI总线上的设备号的唯一标识  
  27.   
  28.     /* mode becomes spi_device.mode, and is essential for chips 
  29.      * where the default of SPI_CS_HIGH = 0 is wrong. 
  30.      */  
  31.     u8      mode; //参考spi_device中的成员  
  32.   
  33.     /* ... may need additional spi_device chip config data here. 
  34.      * avoid stuff protocol drivers can set; but include stuff 
  35.      * needed to behave without being bound to a driver: 
  36.      *  - quirks like clock rate mattering when not selected 
  37.      */  
  38. };  
/* 该结构也是对SPI从设备(spi_device)的描述,只不过它是板级信息,最终该结构的所有字段都将用于初始化SPI设备结构体spi_device */
struct spi_board_info {
	/* the device name and module name are coupled, like platform_bus;
	 * "modalias" is normally the driver name.
	 *
	 * platform_data goes to spi_device.dev.platform_data,
	 * controller_data goes to spi_device.controller_data,
	 * irq is copied too
	 */
	char		modalias[SPI_NAME_SIZE]; //spi设备名,会拷贝到spi_device的相应字段中.这是设备spi_device在SPI总线spi_bus_type上匹配驱动的唯一标识
	const void	*platform_data; //平台数据
	void		*controller_data;
	int		irq; //中断号

	/* slower signaling on noisy or low voltage boards */
	u32		max_speed_hz; //SPI设备工作时的波特率


	/* bus_num is board specific and matches the bus_num of some
	 * spi_master that will probably be registered later.
	 *
	 * chip_select reflects how this chip is wired to that master;
	 * it's less than num_chipselect.
	 */
	u16		bus_num; //该SPI(从)设备所在总线的总线号,就记录了所属的spi_master之中的bus_num编号.一个spi_master就对应一条总线
	u16		chip_select; //片选号.该SPI(从)设备在该条SPI总线上的设备号的唯一标识

	/* mode becomes spi_device.mode, and is essential for chips
	 * where the default of SPI_CS_HIGH = 0 is wrong.
	 */
	u8		mode; //参考spi_device中的成员

	/* ... may need additional spi_device chip config data here.
	 * avoid stuff protocol drivers can set; but include stuff
	 * needed to behave without being bound to a driver:
	 *  - quirks like clock rate mattering when not selected
	 */
};

s3c64xx_spi_info(kernel3.0.15/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h)

  1. struct s3c64xx_spi_info {  
  2.     int src_clk_nr;  
  3.     char *src_clk_name;  
  4.     bool clk_from_cmu;  
  5.   
  6.     int num_cs; //总线上的设备数  
  7.   
  8.     int (*cfg_gpio)(struct platform_device *pdev);  
  9.   
  10.     /* Following two fields are for future compatibility */  
  11.     int fifo_lvl_mask;  
  12.     int rx_lvl_offset;  
  13.     int high_speed;  
  14.     int tx_st_done;  
  15. };  
struct s3c64xx_spi_info {
	int src_clk_nr;
	char *src_clk_name;
	bool clk_from_cmu;

	int num_cs; //总线上的设备数

	int (*cfg_gpio)(struct platform_device *pdev);

	/* Following two fields are for future compatibility */
	int fifo_lvl_mask;
	int rx_lvl_offset;
	int high_speed;
	int tx_st_done;
};

boardinfo是用来管理spi_board_info的结构,spi_board_info在板级文件中通过spi_register_board_info(struct spi_board_info const *info, unsigned n)交由boardinfo来管理,并挂到board_list链表上。

boardinfo(kernel3.0.15/drivers/spi/spi.c)

  1. struct boardinfo {  
  2.     struct list_head    list; //用于挂到链表board_list上  
  3.     struct spi_board_info   board_info; //存放结构体spi_board_info  
  4. };  
struct boardinfo {
	struct list_head	list; //用于挂到链表board_list上
	struct spi_board_info	board_info; //存放结构体spi_board_info
};

spi_register_board_info(kernel3.0.15/drivers/spi/spi.c)

  1. int __init  
  2. spi_register_board_info(struct spi_board_info const *info, unsigned n)  
  3. {  
  4.     struct boardinfo *bi;  
  5.     int i;  
  6.   
  7.     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);  
  8.     if (!bi)  
  9.         return -ENOMEM;  
  10.   
  11.     for (i = 0; i < n; i++, bi++, info++) {  
  12.         struct spi_master *master;  
  13.   
  14.         memcpy(&bi->board_info, info, sizeof(*info));  
  15.         mutex_lock(&board_lock);  
  16.         list_add_tail(&bi->list, &board_list);  
  17.         list_for_each_entry(master, &spi_master_list, list)  
  18.             spi_match_master_to_boardinfo(master, &bi->board_info);  
  19.         mutex_unlock(&board_lock);  
  20.     }  
  21.   
  22.     return 0;  
  23. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SDB传感器驱动板,可以将采集回来的所有传感器数据,通过RS23串口发送给主控PC或者嵌入式系统。同时SDB传感器驱动板带两路直流电机驱动,具备两路旋转编码器接口,内带PID电机控制算法。主控可通过串口精确控制两路电机速度。SDB板的IO0到IO7可设置为舵机控制口,这在机器人系统内带例如舵机云台,机械手夹持的情况下是非常有用的。 SDB传感器驱动板引脚图: SDB直接支持的传感器有: 1.I2C总线通讯协议的传感器:Devantech公司的SRF04 / SRF05 / SRF08 / SRF10 超声波传感器,SP03 TTS,CMP03电子罗盘等。 2.RS485总线传感器,例如URM04超声波,ADIO扩展板等。 3.SPI接口。 4.CAN工业总线接口。 5.模拟量输出传感器:GP2D12等红外距离传感器,IDG300陀螺仪传感器,加速度传感器,光敏传感器等。 6.开关量输出的传感器,例如红外开关,碰撞模块,跌落传感器等。 SDB传感器驱动板技术规格: 工作电源:内带稳压电路,宽工作电压6V-12V(极限电压15V) 工作电流:150mA(供电电压12V) 工作温度范围 :-10~+70℃ 使用Cortex-M3内核 ARM 32BIT处理器,运算速度90MIPS,总线间通信均采用DMA(存储器直接访问)方式,通信和处理速度更快 与主控通信接口方式:RS232串口或者TTL电平串口。波特率可设置为9600、19200、38400和115200BPS 具备8路12BIT高精度模数转换 11路数字输入/输出接口,其中8路(IO0-IO7)可设置为舵机控制口 8路舵机控制口可控制舵机的度数及其旋转速度 1路I2C总线 1路RS485总线 1路CAN总线(2.2版本未使用) 1路SPI总线(2.2版本未使用) 两路直流电机控制,每通道4A电流,具有AB两相旋转编码器接口,内部集成参数可调整的PID算法,可精确控制电机转速。可读取回电机旋转圈数用于里程计数。电机电流可读取,可用于电流保护 尺寸:长96mm,宽90mm,高20mm。安装孔兼容PC104结构。 重量:约87g SDB传感器驱动板应用教程及资料截图:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值