【1】复习
1. platform平台总线
device注册注销
struct platform_device
{
char *name; >>> platform_driver >>>
>>> (id_table > device_driver->name)
}
driver注册注销
struct platform_driver
【2】作业
【一】、IIC
IIC总线(同步半双工串行总线):
(1).通过GPIO模拟时序
(2).使用IIC控制器
SCL:时钟线
SDA:数据线
全双工 半双工 单工
同步 异步
串行 并行
时序:
起始信号:
结束信号:
读数据:
修改数据:
协议:
a). signal read:
| start signal | Device address[6:0],W[7] | slave ACK | register address[7:0] | slave ACK | --->>>
SR | Device address[6:0],R[7] | slave ACK | Data[7:0] | MACK | SP |
b). signal write:
| start signal | Device address[6:0],W[7] | slave ACK | register address[7:0] | slave ACK | --->>>
Data[7:0] | slave ACK | SP |
W: write = 0
R: read = 1
SR:repeated start condition
SP:stop condition
【二】、IIC子系统
platform IIC SPI
总线 bus_type bus_type bus_type
驱动 platform_driver i2c_driver spi_driver
设备 platform_device (i2c_client) spi_device
i2c_board_info spi_board_info
分层:
设备驱动层:
需要驱动工程师完成的,向应用层提供操作的接口(fops)
向下操作硬件
核心层: i2c-core.c
内核提供好的,提供设备驱动和总线驱动注册和注销的方法
还提供设备驱动和总线驱动的匹配方式
总线驱动层:i2c-s3c2410.c
内核提供好的,按照用户传递的数据和操作时序操作硬件
驱动端:
struct i2c_client {
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
};
struct i2c_driver {
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
struct device_driver driver;
const struct i2c_device_id *id_table;
};
struct i2c_device_id {
char name[I2C_NAME_SIZE];
kernel_ulong_t driver_data;
};
/****************************************************
*功能:
*参数:
* @driver i2c_driver 结构体指针
*返回值:
***************************************************/
#define i2c_add_driver(struct i2c_driver *driver) \
i2c_register_driver(THIS_MODULE, driver)
void i2c_del_driver(struct i2c_driver *driver)
过程:
i2c_register_driver(THIS_MODULE, driver)
--->>> driver_register(&driver->driver);
--->>> bus_add_driver(drv);
--->>> driver_attach(drv);
--->>> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
--->>> __driver_attach
--->>> driver_match_device(drv, dev)
--->>> drv->bus->match ? drv->bus->match(dev, drv) : 1;
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
设备树 > id_table表
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
0 /* write data */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
/********************************************************************
*功能:i2c数据传输函数
*参数:
* @adap i2c_adapter结构体指针
* @msgs 信息包
* @num 消息包个数
*返回值:失败返回负数错误码,成功返回大于0的整数
*******************************************************************/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
板级信息:
struct i2c_board_info {
char type[I2C_NAME_SIZE]; //名字 --->>> 匹配
unsigned short addr; //从机地址
void *platform_data;
struct device_node *of_node;
int irq;
};
/***********************************************************
*功能:注册板级信息
*参数:
* @busnum 总线编号
* @info i2c_board_info结构体指针
* @n 个数
*返回值:失败返回负数错误码,成功返回0
**********************************************************/
int i2c_register_board_info(int busnum, \
struct i2c_board_info const *info,unsigned n)
1. MMA8451三轴加速度传感器,16脚,QFN封装
<2> BYP Bypass capacitor (0.1 μF), 旁路电容
<4> SCL I2C Serial Clock i2c时钟输入
<6> SDA I2C Serial Data i2c数据线
<7> SA0 I2C Least Significant Bit of the Device I2C Address
Table 9. I2C Address Selection Table
Slave Address (SA0 = 0) 0011100 (0x1C)
Slave Address (SA0 = 1) 0011101 (0x1D)
<9> INT2 Inertial Interrupt 2 Output
<11> INT1 Inertial Interrupt 1 Output
2. MMA8451相关配置寄存器和数据寄存器
1). XYZ_DATA_CFG register(address : 0x0E): 用于配置高通滤波输出数据量程设定
bit 4:置1--->>>使能高通滤波输出 置0:关闭高通滤波输出
bit 1:FS1
bit 0:FS0
FS1 FS0 range
0 0 2
0 1 4
1 0 8
1 1 reserved
2). CTRL_REG1 register(address : 0x2A): 设置睡眠模式下的采样频率、数据速率、
以及功能模式:standy/active
3). CTRL_REG2 register(address : 0x2B): 睡眠使能、系统模式、复位、自检
4). 数据寄存器
OUT_X_MSB :x高8位数据
OUT_X_LSB :x低8位数据
OUT_Y_MSB
OUT_Y_LSB
OUT_Z_MSB
OUT_Z_LSB
【二】、SPI
SPI总线:
MOSI :发送
MISO :接收
SCL :时钟
CS :片选
同步全双工串行总线
时钟极性:决定了时钟空闲状态为低电平还是高电平
0:低电平
1:高电平
时钟相位:决定在时钟线的第一次跳变沿采样数据还是在第二个跳变沿采样数据
0:串行同步时钟的第1个跳变沿采样数据,数据发送在第2个边沿
1:串行同步时钟的第2个跳变沿采样数据,数据发送在第1个边沿
spi缺点:
由于spi没有消息应答机制,所以spi发送数据没有i2c可靠。
【三】、SPI子系统
app应用层 open read writ close
---------------------------------------------------
spi设备驱动层(cdev->fops)
drv_open drv_read drv_write drv_close
---------------------------------------------------
spi的核心层 spi.c
提供两层的注销和注销的函数
提供设备和总线驱动匹配过程
---------------------------------------------------
spi总线驱动层 (厂商提供好的) spi-slsi.c
--------------|-------------------------|------------
mcp2515 mpu6050
驱动端:
struct spi_driver {
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
struct device_driver driver;
const struct spi_device_id *id_table;
};
struct spi_device_id {
char name[SPI_NAME_SIZE];
kernel_ulong_t driver_data;
};
int spi_register_driver(struct spi_driver *sdrv);
void spi_unregister_driver(struct spi_driver *sdrv)
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);
return strcmp(spi->modalias, drv->name) == 0;
}
设备端:
struct spi_device {
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
#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)
int irq;
};
struct spi_board_info {
char modalias[SPI_NAME_SIZE];
int irq;
u32 max_speed_hz;
u16 bus_num;
u16 chip_select;
u8 mode;
};
int spi_register_board_info(struct spi_board_info const *info, unsigned n);
/***************************************************************************
*功能: spi总线写数据
*参数:
* @spi
* @buf 写缓存区地址
* @len 写如数据的大小
*返回值:成功返回0,失败返回负数错误码
**************************************************************************/
int spi_write(struct spi_device *spi, const void *buf, size_t len)
/***************************************************************************
*功能: spi总线读数据
*参数:
* @spi
* @buf 读缓存区地址
* @len 读如数据的大小
*返回值:成功返回0,失败返回负数错误码
**************************************************************************/
int spi_read(struct spi_device *spi, void *buf, size_t len)
int spi_write_then_read(struct spi_device *spi,
const void *txbuf, unsigned n_tx,
void *rxbuf, unsigned n_rx);