I.MX6U:I2C协议下的AP3216C驱动编写与搭建
记录贴:记录在I.MX6U开发板上通过I2C与AP3216C通信,获取三合一环境传感器传回的数据,并将数据显示在LCD屏幕上。
一、I2C协议概念
(1)基本介绍
I2C(Inter-Integrated Circuit),中文称为内部集成电路总线,是一种由飞利浦(Philips)公司在1980年代开发的串行通信总线,常用于芯片间的短距离通信。
I2C使用两条线在主控制器与从机间进行通信:SCL(时钟线)与SDA(数据线);I2C 是支持多从机的,也就是一个 I2C 控制器下可以挂多个 I2C 从设备,这些不同的 I2C从设备有不同的器件地址,这样 I2C 主控制器就可以通过 I2C 设备的器件地址访问指定的 I2C设备了。
但是SDA 和 SCL 这两根线必须要接一个上拉电阻,一般是 4.7K。其余的 I2C 从器件都挂接到 SDA 和 SCL 这两根线上,这样就可以通过 SDA 和 SCL 这两根线来访问多个 I2C设备。
(2)通信流程
[起始位] → [从机地址+读写位] → [ACK应答位] → [数据传输] → [ACK/NACK] → [停止位]
当 I2C 主机发送完 8 位数据以后会将 SDA 设置为输入状态,等待 I2C 从机应答,也就是等到 I2C 从机告诉主机它接收到数据了。应答信号是由从机发出的,主机需要提供应答信号所需的时钟,主机发送完 8 位数据以后紧跟着的一个时钟信号就是给应答信号使用的。从机通过将 SDA 拉低来表示发出应答信号,表示通信成功,否则表示通信失败
I2C 总线在数据传输的时候要保证在 SCL 高电平期间, SDA 上的数据稳定,因此 SDA 上的数据变化只能在 SCL 低电平期间发生
起始位(Start):SDA在SCL为高时从高跳变到低
地址+读写位:发送从设备地址+R/W位(读=1,写=0)
ACK(应答):从设备拉低SDA表示响应
数据传输:每字节8位,每字节后都有ACK
停止位(Stop):SDA在SCL为高时从低跳变到高
(3)写时序
写时序图
具体步骤为: 1.开始信号
2.发送 I2C 设备地址,每个 I2C 器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个 I2C 器件。这是一个 8 位的数据,其中高 7 位是设备地址,最后 1 位是读写位,为1 的话表示这是一个读操作,为 0 的话表示这是一个写操作。
3.I2C 器件地址后面跟着一个读写位,为 0 表示写操作,为 1 表示读操作。
4.从机发送的 ACK 应答信号。
5.重新发送开始信号。
6.发送要写入数据的寄存器地址。
7.从机发送的 ACK 应答信号。
8.发送要写入寄存器的数据。
9.从机发送的ACK应答信号。
10.停止信号。
(4)读时序
与写时序相比,I2C 单字节读的时序稍显复杂,可分为四个主要步骤:首先,主机发送目标设备的地址;接着,发送想要读取的寄存器地址;然后,主机重新发起起始信号并再次发送设备地址(此时为读操作);最后,从设备将对应寄存器的数值传输给主机。
具体为:
1、主机发送起始信号。
2、主机发送要读取的 I2C 从设备地址。
3、读写控制位,因为是向 I2C 从设备发送数据,因此是写信号。
4、从机发送的 ACK 应答信号。
5、重新发送 START 信号。
6、主机发送要读取的寄存器地址。
7、从机发送的 ACK 应答信号。
8、重新发送 START 信号。
9、重新发送要读取的 I2C 从设备地址。
10、读写控制位,这里是读信号,表示接下来是从 I2C 从设备里面读取数据。
11、从机发送的 ACK 应答信号。
12、从 I2C 器件里面读取到的数据。
13、主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了。
14、主机发出 STOP 信号,停止 I2C 通信。
二、驱动I2C需要用到的寄存器
(1)I2Cx_IADR寄存器(地址寄存器)
I2Cx_IADR结构
这个寄存器只使用ADR(bit7:1)位,,主要是用来保存I2C从设备地址数据。当要访问某个 I2C 从设备的时候就需要将其设备地址写入到 ADR 里面。
(2)I2Cx_IFDR寄存器(分频寄存器)
I2Cx_IFDR结构
这个寄存器也只使用IC(bit5:0)这个位,用来设置 I2C 的波特率, I2C 的时钟源可以选择 IPG_CLK_ROOT=66MHz,通过设置 IC 位既可以得到想要的 I2C 波特率。
不能够随意设置,只能根据表设置想要的分频值。
(3)I2Cx_I2CR寄存器(控制寄存器)
I2Cx_I2CR结构
IEN(bit7): I2C 使能位,为 1 的时候使能 I2C,为 0 的时候关闭 I2C。
IIEN(bit6): I2C 中断使能位,为 1 的时候使能 I2C 中断,为 0 的时候关闭 I2C 中断。
MSTA(bit5):主从模式选择位,设置 IIC 工作在主模式还是从模式,为 1 的时候工作在主模式,为 0 的时候工作在从模式。
MTX(bit4):传输方向选择位,用来设置是进行发送还是接收,为 0 的时候是接收,为 1 的时候是发送。
TXAK(bit3):传输应答位使能,为 0 的话发送 ACK 信号,为 1 的话发送 NO ACK 信号。
RSTA(bit2):重复开始信号,为 1 的话产生一个重新开始信号。
(4)I2Cx_I2SR寄存器(状态寄存器)
I2Cx_I2SR结构
ICF(bit7):数据传输状态位,为 0 的时候表示数据正在传输,为 1 的时候表示数据传输完成。
IAAS(bit6):当为 1 的时候表示 I2C 地址,也就是 I2Cx_IADR 寄存器中的地址是从设备地址。
IBB(bit5): I2C 总线忙标志位,当为 0 的时候表示 I2C 总线空闲,为 1 的时候表示 I2C 总线忙。
IAL(bit4):仲裁丢失位,为 1 的时候表示发生仲裁丢失。
SRW(bit2):从机读写状态位,当 I2C 作为从机的时候使用,此位用来表明主机发送给从机的是读还是写命令。为 0 的时候表示主机要向从机写数据,为 1 的时候表示主机要从从机读取数据。
IIF(bit1): I2C 中断挂起标志位,当为 1 的时候表示有中断挂起,此位需要软件清零。
RXAK(bit0): 应答信号标志位,为 0 的时候表示接收到 ACK 应答信号,为 1 的话表示检测到 NO ACK 信号。
(5)I2Cx_I2DR寄存器(数据寄存器)
此寄存器只有低 8 位有效,当要发送数据的时候将要发送的数据写入到此寄存器,如果要接收数据的话直接读取此寄存器即可得到接收到的数据。
三、三合一环境传感器AP3216C
AP3216C支持环境光强度(ALS)、接近距离(PS)和红外线强度(IR)这三个环境参数检测。
寄存器地址 | 位 | 寄存器功能 | 描述 |
0X00 | 2:0 | 系统模式选择 | 000:掉电模式(默认) 001:使能ALS 010:使能PS+IR 011:使能ALS+PS+IR 100:软复位 101:ALS单次模式 110:PS+IR单次模式 111:ALS+PS+IR单次模式 |
0X0A | 7 | IR低位数据 | 0:IR&PS数据有效,1:无效 |
1:0 | IR最低两位数据 | ||
0X0B | 7:0 | IR高位数据 | IR高8位数据 |
0X0C | 7:0 | ALS低位数据 | ALS低8位数据 |
0X0D | 7:0 | ALS高位数据 | ALS高8位数据 |
0X0E | 7 | PS低位数据 | 0:物体在远离;1:物体在接近 |
6 | 0:IR&PS数据有效;1:IR&PS数据无效 | ||
3:0 | PS最低4位数据 | ||
0X0F | 7 | PS高位数据 | 0:物体在远离;1:物体在接近 |
6 | 0:IR&PS数据有效;1:IR&PS数据无效 | ||
5:0 | PS最低6位数据 |
如表所示,想要使AP3216C正常工作,就是使能这些寄存器。0X00 这个寄存器是模式控制寄存器,用来设置 AP3216C 的工作模式,一般开始先将其设置为 0X04,也就是先软件复位一次 AP3216C。接下来根据实际使用情况选择合适的工作模式,比如设置为 0X03,也就是开启 ALS+PS+IR。从 0X0A~0X0F 这 6 个寄存器就是数据寄存器,保存着 ALS、 PS 和 IR 这三个传感器获取到的数据值。如果同时打开 ALS、PS 和 IR 则读取间隔最少要 112.5ms,因为 AP3216C 完成一次转换需要 112.5ms。
四、代码编写流程
实验目的:通过I.MX6U 的 I2C1 来读取 AP3216C 内部的 ALS、 PS 和 IR 这三个传感器的值,并且在 LCD 上显示。
任务流程:
(1)初始化相应的IO&初始化I2C1
初始化I2C1相应的IO,设置其复用功能。
初始化I2C1接口,设置波特率
这两步编写在 bsp_i2c.c中:
#include "bsp_i2c.h"
#include "bsp_delay.h"
#include "stdio.h"
/*
* @description : 初始化I2C,波特率100KHZ
* @param - base : 要初始化的IIC设置
* @return : 无
*/
void i2c_init(I2C_Type *base)
{
/* 1、配置I2C */
base->I2CR &= ~(1 IFDR = 0X15 I2CR |= (1I2SR & (1 I2CR) & (1 I2CR |= (1 I2DR = ((unsigned int)address I2SR & (1 I2CR |= (1 I2DR = ((unsigned int)address I2SR &= ~(1I2CR &= ~(1 I2CR |= (1 I2CR &= ~((1 I2SR & (1 I2SR & (1 I2SR &= ~(1 I2CR |= 1 I2DR = *buf++; /* 将buf中的数据写入到I2DR寄存器 */
while(!(base->I2SR & (1 I2SR &= ~(1 I2SR))
break;
}
base->I2SR &= ~(1 I2SR & (1 I2SR &= ~(1 I2CR &= ~((1 I2CR |= (1 I2DR; /* 假读 */
while(size--)
{
while(!(base->I2SR & (1 I2SR &= ~(1 I2CR |= (1 I2DR;
}
}
/*
* @description : I2C数据传输,包括读和写
* @param - base: 要使用的IIC
* @param - xfer: 传输结构体
* @return : 传输结果,0 成功,其他值 失败;
*/
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
{
unsigned char ret = 0;
enum i2c_direction direction = xfer->direction;
base->I2SR &= ~((1 I2SR >> 7) & 0X1)){};
/* 如果是读的话,要先发送寄存器地址,所以要先将方向改为写 */
if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
{
direction = kI2C_Write;
}
ret = i2c_master_start(base, xfer->slaveAddress, direction); /* 发送开始信号 */
if(ret)
{
return ret;
}
while(!(base->I2SR & (1 I2SR); /* 检查是否出现传输错误 */
if(ret)
{
i2c_master_stop(base); /* 发送出错,发送停止信号 */
return ret;
}
/* 发送寄存器地址 */
if(xfer->subaddressSize)
{
do
{
base->I2SR &= ~(1 subaddressSize--; /* 地址长度减一 */
base->I2DR = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器写入子地址
while(!(base->I2SR & (1 I2SR);
if(ret)
{
i2c_master_stop(base); /* 发送停止信号 */
return ret;
}
} while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));
if(xfer->direction == kI2C_Read) /* 读取数据 */
{
base->I2SR &= ~(1 slaveAddress, kI2C_Read); /* 发送重复开始信号和从机地址 */
while(!(base->I2SR & (1 I2SR);
if(ret)
{
ret = I2C_STATUS_ADDRNAK;
i2c_master_stop(base); /* 发送停止信号 */
return ret;
}
}
}
/* 发送数据 */
if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0))
{
i2c_master_write(base, xfer->data, xfer->dataSize);
}
/* 读取数据 */
if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0))
{
i2c_master_read(base, xfer->data, xfer->dataSize);
}
return 0;
}
在bsp_i2c.h中声明函数与一些变量类型声明
#ifndef _BSP_I2C_H
#define _BSP_I2C_H
#include "imx6ul.h"
/* 相关宏定义 */
#define I2C_STATUS_OK (0)
#define I2C_STATUS_BUSY (1)
#define I2C_STATUS_IDLE (2)
#define I2C_STATUS_NAK (3)
#define I2C_STATUS_ARBITRATIONLOST (4)
#define I2C_STATUS_TIMEOUT (5)
#define I2C_STATUS_ADDRNAK (6)
/*
* I2C方向枚举类型
*/
enum i2c_direction
{
kI2C_Write = 0x0, /* 主机向从机写数据 */
kI2C_Read = 0x1, /* 主机从从机读数据 */
} ;
/*
* 主机传输结构体
*/
struct i2c_transfer
{
unsigned char slaveAddress; /* 7位从机地址 */
enum i2c_direction direction; /* 传输方向 */
unsigned int subaddress; /* 寄存器地址 */
unsigned char subaddressSize; /* 寄存器地址长度 */
unsigned char *volatile data; /* 数据缓冲区 */
volatile unsigned int dataSize; /* 数据缓冲区长度 */
};
/*
*函数声明
*/
void i2c_init(I2C_Type *base);
unsigned char i2c_master_start(I2C_Type *base, unsigned char address, enum i2c_direction direction);
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address, enum i2c_direction direction);
unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status);
unsigned char i2c_master_stop(I2C_Type *base);
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size);
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size);
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer);
#endif
(2)初始化AP3216C
初始化AP3216C,读取AP3216C的数据。
#include "bsp_ap3216c.h"
#include "bsp_i2c.h"
#include "bsp_delay.h"
#include "cc.h"
#include "stdio.h"
/*
* @description : 初始化AP3216C
* @param : 无
* @return : 0 成功,其他值 错误代码
*/
unsigned char ap3216c_init(void)
{
unsigned char data = 0;
/* 1、IO初始化,配置I2C IO属性
* I2C1_SCL -> UART4_TXD
* I2C1_SDA -> UART4_RXD
*/
IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL, 1);
IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA, 1);
/*
*bit 16:0 HYS关闭
*bit [15:14]: 1 默认47K上拉
*bit [13]: 1 pull功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 驱动能力为R0/6
*bit [0]: 1 高转换率
*/
IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL, 0x70B0);
IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA, 0X70B0);
i2c_init(I2C1); /* 初始化I2C1 */
/* 2、初始化AP3216C */
ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X04); /* 复位AP3216C */
delayms(50); /* AP33216C复位至少10ms */
ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X03); /* 开启ALS、PS+IR */
data = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG); /* 读取刚刚写进去的0X03 */
if(data == 0X03)
return 0; /* AP3216C正常 */
else
return 1; /* AP3216C失败 */
}
/*
* @description : 向AP3216C写入数据
* @param - addr: 设备地址
* @param - reg : 要写入的寄存器
* @param - data: 要写入的数据
* @return : 操作结果
*/
unsigned char ap3216c_writeonebyte(unsigned char addr,unsigned char reg, unsigned char data)
{
unsigned char status=0;
unsigned char writedata=data;
struct i2c_transfer masterXfer;
/* 配置I2C xfer结构体 */
masterXfer.slaveAddress = addr; /* 设备地址 */
masterXfer.direction = kI2C_Write; /* 写入数据 */
masterXfer.subaddress = reg; /* 要写入的寄存器地址 */
masterXfer.subaddressSize = 1; /* 地址长度一个字节 */
masterXfer.data = &writedata; /* 要写入的数据 */
masterXfer.dataSize = 1; /* 写入数据长度1个字节 */
if(i2c_master_transfer(I2C1, &masterXfer))
status=1;
return status;
}
/*
* @description : 从AP3216C读取一个字节的数据
* @param - addr: 设备地址
* @param - reg : 要读取的寄存器
* @return : 读取到的数据。
*/
unsigned char ap3216c_readonebyte(unsigned char addr,unsigned char reg)
{
unsigned char val=0;
struct i2c_transfer masterXfer;
masterXfer.slaveAddress = addr; /* 设备地址 */
masterXfer.direction = kI2C_Read; /* 读取数据 */
masterXfer.subaddress = reg; /* 要读取的寄存器地址 */
masterXfer.subaddressSize = 1; /* 地址长度一个字节 */
masterXfer.data = &val; /* 接收数据缓冲区 */
masterXfer.dataSize = 1; /* 读取数据长度1个字节 */
i2c_master_transfer(I2C1, &masterXfer);
return val;
}
/*
* @description : 读取AP3216C的数据,读取原始数据,包括ALS,PS和IR, 注意!
* : 如果同时打开ALS,IR+PS的话两次数据读取的时间间隔要大于112.5ms
* @param - ir : ir数据
* @param - ps : ps数据
* @param - ps : als数据
* @return : 无。
*/
void ap3216c_readdata(unsigned short *ir, unsigned short *ps, unsigned short *als)
{
unsigned char buf[6];
unsigned char i;
/* 循环读取所有传感器数据 */
for(i = 0; i < 6; i++)
{
buf[i] = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_IRDATALOW + i);
}
if(buf[0] & 0X80) /* IR_OF位为1,则数据无效 */
*ir = 0;
else /* 读取IR传感器的数据 */
*ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03);
*als = ((unsigned short)buf[3] << 8) | buf[2]; /* 读取ALS传感器的数据 */
if(buf[4] & 0x40) /* IR_OF位为1,则数据无效 */
*ps = 0;
else /* 读取PS传感器的数据 */
*ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F);
}
添加函数声明与变量声明:
#ifndef _BSP_AP3216C_H
#define _BSP_AP3216C_H
#include "imx6ul.h"
#define AP3216C_ADDR 0X1E /* AP3216C器件地址 */
/* AP3316C寄存器 */
#define AP3216C_SYSTEMCONG 0x00 /* 配置寄存器 */
#define AP3216C_INTSTATUS 0X01 /* 中断状态寄存器 */
#define AP3216C_INTCLEAR 0X02 /* 中断清除寄存器 */
#define AP3216C_IRDATALOW 0x0A /* IR数据低字节 */
#define AP3216C_IRDATAHIGH 0x0B /* IR数据高字节 */
#define AP3216C_ALSDATALOW 0x0C /* ALS数据低字节 */
#define AP3216C_ALSDATAHIGH 0X0D /* ALS数据高字节 */
#define AP3216C_PSDATALOW 0X0E /* PS数据低字节 */
#define AP3216C_PSDATAHIGH 0X0F /* PS数据高字节 */
/* 函数声明 */
unsigned char ap3216c_init(void);
unsigned char ap3216c_readonebyte(unsigned char addr,unsigned char reg);
unsigned char ap3216c_writeonebyte(unsigned char addr,unsigned char reg, unsigned char data);
void ap3216c_readdata(unsigned short *ir, unsigned short *ps, unsigned short *als);
#endif
(3)主函数中调用
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "bsp_ap3216c.h"
#include "stdio.h"
/*
* @description : main函数
* @param : 无
* @return : 无
*/
int main(void)
{
unsigned short ir, als, ps;
unsigned char state = OFF;
int_init(); /* 初始化中断(一定要最先调用!) */
imx6u_clkinit(); /* 初始化系统时钟 */
delay_init(); /* 初始化延时 */
clk_enable(); /* 使能所有的时钟 */
led_init(); /* 初始化led */
beep_init(); /* 初始化beep */
uart_init(); /* 初始化串口,波特率115200 */
lcd_init(); /* 初始化LCD */
tftlcd_dev.forecolor = LCD_RED;
lcd_show_string(30, 50, 200, 16, 16, (char*)"ALPHA-IMX6U IIC TEST");
lcd_show_string(30, 70, 200, 16, 16, (char*)"AP3216C TEST");
lcd_show_string(30, 90, 200, 16, 16, (char*)"ATOM@ALIENTEK");
lcd_show_string(30, 110, 200, 16, 16, (char*)"2019/3/26");
while(ap3216c_init()) /* 检测不到AP3216C */
{
lcd_show_string(30, 130, 200, 16, 16, (char*)"AP3216C Check Failed!");
delayms(500);
lcd_show_string(30, 130, 200, 16, 16, (char*)"Please Check! ");
delayms(500);
}
lcd_show_string(30, 130, 200, 16, 16, (char*)"AP3216C Ready!");
lcd_show_string(30, 160, 200, 16, 16, (char*)" IR:");
lcd_show_string(30, 180, 200, 16, 16, (char*)" PS:");
lcd_show_string(30, 200, 200, 16, 16, (char*)"ALS:");
tftlcd_dev.forecolor = LCD_BLUE;
while(1)
{
ap3216c_readdata(&ir, &ps, &als); /* 读取数据 */
lcd_shownum(30 + 32, 160, ir, 5, 16); /* 显示IR数据 */
lcd_shownum(30 + 32, 180, ps, 5, 16); /* 显示PS数据 */
lcd_shownum(30 + 32, 200, als, 5, 16); /* 显示ALS数据 */
delayms(120);
state = !state;
led_switch(LED0,state);
}
return 0;
}
(4)编写Makefile和链接脚本
Makefile
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= ap3216c
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
LIBPATH := -lgcc -L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4
INCDIRS := imx6ul \
stdio/include \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep \
bsp/gpio \
bsp/key \
bsp/exit \
bsp/int \
bsp/epittimer \
bsp/keyfilter \
bsp/uart \
bsp/lcd \
bsp/rtc \
bsp/i2c \
bsp/ap3216c
SRCDIRS := project \
stdio/lib \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep \
bsp/gpio \
bsp/key \
bsp/exit \
bsp/int \
bsp/epittimer \
bsp/keyfilter \
bsp/uart \
bsp/lcd \
bsp/rtc \
bsp/i2c \
bsp/ap3216c
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
.PHONY: clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH)
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
链接脚本:
SECTIONS{
. = 0X87800000;
.text :
{
obj/start.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}
五、验证与现象
(1)使用make指令编译链接相关文件
(2)使用正点原子的imxdownload烧录工具将代码烧录至SD卡
(3)现象
屏幕上显示传感器所检测到的数据。