imx6ull.lds
SECTIONS {
. = 0x80100000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
ap3216c.c
#include "ap3216c.h"
#include "i2c.h"
#include "type.h"
static void delay(volatile unsigned int d)
{
while(d--);
}
static void ap3216c_init_io()
{
/*I2C1 复用UART4 SCL-TXD SDA-RXD*/
IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL, 1);
IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA, 1);
IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL, 0x70B0);
IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA, 0X70B0);
}
static uint8_t ap3216c_read_system_status()
{
unsigned char data = 0;
data = i2c_read_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONFIG, I2C1);
if(data != 0 || data != 0xff)
{
return 0; /* AP3216C正常 */
}
else
{
return 1; /* AP3216C失败 */
}
}
uint8_t ap3216c_init(void)
{
int ret = 0;
/*初始化IO*/
ap3216c_init_io();
i2c_init(I2C1);
/*初始化/复位AP3216C */
i2c_write_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONFIG, AP3216C_INIT, I2C1);
/*手册上写至少等待10ms*/
delay(10000);
/*开始转换*/
i2c_write_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONFIG, AP3216C_START_ALL, I2C1);
return ap3216c_read_system_status();
}
void ap3216c_read_ir(uint16_t *ir)
{
uint8_t ucIrLow;
uint8_t ucIrHigh;
uint8_t i;
ucIrLow = i2c_read_one_byte(AP3216C_ADDR, AP3216C_IRDATALOW, I2C1);
ucIrHigh = i2c_read_one_byte(AP3216C_ADDR, AP3216C_IRDATAHIGH, I2C1);
if(ucIrLow & 0x80)
{
*ir = 0;
return ;
}
else
{
*ir = ((uint16_t)ucIrHigh << 2) | (ucIrLow & 0X03);
}
return;
}
void ap3216c_read_als(uint16_t *als)
{
uint8_t ucAlsLow;
uint8_t ucAlsHigh;
uint8_t i;
ucAlsLow = i2c_read_one_byte(AP3216C_ADDR, AP3216C_ALSDATALOW, I2C1);
ucAlsHigh = i2c_read_one_byte(AP3216C_ADDR, AP3216C_ALSDATAHIGH, I2C1);
*als = ((uint16_t)ucAlsHigh << 8) | ucAlsLow;
return;
}
void ap3216c_read_ps(uint16_t *ps)
{
uint8_t ucPsLow;
uint8_t ucPsHigh;
uint8_t i;
ucPsLow = i2c_read_one_byte(AP3216C_ADDR, AP3216C_PSDATALOW, I2C1);
ucPsHigh = i2c_read_one_byte(AP3216C_ADDR, AP3216C_PSDATAHIGH, I2C1);
if(ucPsLow & 0x40)
{
*ps = 0;
return ;
}
else
{
*ps = ((uint16_t)(ucPsHigh & 0X3F) << 4) | (ucPsLow & 0x0F);
}
return;
}
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als)
{
ap3216c_read_ir(ir);
ap3216c_read_als(als);
ap3216c_read_ps(ps);
return;
}
ap3216c.h
#ifndef __AP3216C_H
#define __AP3216C_H
#include "type.h"
#define AP3216C_ADDR 0X1E /* AP3216C器件地址 */
/*
* AP3216C操作码定义
*/
typedef enum enAP3216C_OPCODE
{
AP3216C_SYSTEMCONFIG = 0, /* 配置寄存器 */
AP3216C_INTSTATUS = 1, /* 中断状态寄存器 */
AP3216C_INTCLEAR = 2, /* 中断清除寄存器 */
AP3216C_START_ALL = 3, /* 开启全模式ALS/PS/IR */
AP3216C_INIT = 4, /* 复位/初始化 */
AP3216C_IRDATALOW = 10, /* IR数据低字节 */
AP3216C_IRDATAHIGH = 11, /* IR数据高字节 */
AP3216C_ALSDATALOW = 12, /* ALS数据低字节 */
AP3216C_ALSDATAHIGH = 13, /* ALS数据高字节 */
AP3216C_PSDATALOW = 14, /* PS数据低字节 */
AP3216C_PSDATAHIGH = 15, /* PS数据高字节 */
AP3216C_DONOTHING_BULL
} AP3216C_OPCODE;
/**********************************************************************
* 函数名称: ap3216c_init
* 功能描述: 初始化
* 输入参数: 1.设备地址 2.要读的寄存器
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
unsigned char ap3216c_init(void);
/**********************************************************************
* 函数名称: ap3216c_read_ir
* 功能描述: 向IC从设备读IR数据
* 输入参数: 1.设备地址 2.要读的寄存器
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void ap3216c_read_ir(uint16_t *ir);
/**********************************************************************
* 函数名称: ap3216c_read_als
* 功能描述: 向IC从设备读ALS据
* 输入参数: 1.设备地址 2.要读的寄存器
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void ap3216c_read_als(uint16_t *als);
/**********************************************************************
* 函数名称: ap3216c_read_ps
* 功能描述: 向IC从设备读PS数据
* 输入参数: 1.设备地址 2.要读的寄存器
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void ap3216c_read_ps(uint16_t *ps);
/**********************************************************************
* 函数名称: ap3216c_read_data
* 功能描述: 向IC从设备读ir+ps+als数据
* 输入参数: 1.Ir 2.Ps 3.Als
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als);
#endif
i2c.c
#include "i2c.h"
void i2c_init(I2C_REGISTERS *I2C_BASE)
{
/*I2C_I2CR是控制寄存器,
* 可以: 使能I2C,使能中断, 选择主从模式.
*/
/* 配置I2C控制器步骤: 关闭I2C,配置,打开I2C */
/* 设置SCL时钟为100K
* I2C的时钟源来源于IPG_CLK_ROOT=49.5Mhz
* PLL2 = 528 MHz
* PLL2_PFD2 = 528 *18 /24 = 396 MHz
* IPG_CLK_ROOT = (PLL2_PFD2 / ahb_podf )/ ipg_podf = (396 MHz/4)/2 = 49.5Mhz
*
* PER_CLK_ROOT = IPG_CLK_ROOT/perclk_podf = 49.5 MHz/1 = 49.5 MHz
* 设置I2C的波特率为100K, 因此当分频值=49500000/100000=495
* 参考Table 31-3. I2C_IFDR Register Field Values 表中0x37对应的512最接近
* 即寄存器IFDR的IC位设置为0X37
*/
I2C_BASE->I2CR &= ~(1 << 7);
I2C_BASE->IFDR = 0x37;
I2C_BASE->I2CR |= (1<<7);
}
uint8_t i2c_check(I2C_REGISTERS *I2C_BASE, uint32_t status)
{
/* 检查是否发生仲裁丢失错误(arbitration lost) */
if(status & (1<<4))
{
I2C_BASE->I2SR &= ~(1<<4); /* 清除仲裁丢失错误位 */
I2C_BASE->I2CR &= ~(1 << 7); /* 复位I2C: 先关闭I2C */
I2C_BASE->I2CR |= (1 << 7); /* 再打开I2C */
return I2C_ARBITRATIONLOST;
}
else if(status & (1 << 0)) /* 检查NAK */
{
return I2C_NAK; /* 返回NAK(无应答) */
}
return I2C_OK;
}
uint8_t i2c_start(I2C_REGISTERS *I2C_BASE, uint8_t ucSlaveAddr, uint32_t ulOpcode)
{
if(I2C_BASE->I2SR & (1 << 5)) /* I2C忙 */
return 1;
/*
* 设置控制寄存器I2CR
* bit[5]: 1 主模式(master)
* bit[4]: 1 发送(transmit)
*/
I2C_BASE->I2CR |= (1 << 5) | (1 << 4);
/*
* 设置数据寄存器I2DR
* bit[7:0] : 要发送的数据,
* START信号后第一个数据是从设备地址
*/
I2C_BASE->I2DR = ((uint32_t)ucSlaveAddr << 1) | ((I2C_READ == ulOpcode)? 1 : 0);
return 0;
}
uint8_t i2c_stop(I2C_REGISTERS *I2C_BASE)
{
uint16_t usTimeout = 0xffff;
/*
* 清除控制寄存器I2CR[5:3]
* 发出STOP信号
*/
I2C_BASE->I2CR &= ~((1 << 5) | (1 << 4) | (1 << 3));
/* 等待STOP信号确实发出去了 */
while((I2C_BASE->I2SR & (1 << 5)))
{
usTimeout--;
if(usTimeout == 0) /* 超时跳出 */
return I2C_TIMEOUT;
}
return I2C_OK;
}
uint8_t i2c_restart(I2C_REGISTERS *I2C_BASE, uint8_t ucSlaveAddr, uint32_t ulOpcode)
{
/* I2C忙并且工作在从模式,跳出 */
if(I2C_BASE->I2SR & (1 << 5) && (((I2C_BASE->I2CR) & (1 << 5)) == 0))
return 6;
/*
* 设置控制寄存器I2CR
* bit[4]: 1 发送(transmit)
* bit[2]: 1 产生重新开始信号(Repeat start)
*/
I2C_BASE->I2CR |= (1 << 4) | (1 << 2);
/*
* 设置数据寄存器I2DR
* bit[7:0] : 要发送的数据,
* START信号后第一个数据是从设备地址
*/
I2C_BASE->I2DR = ((uint32_t)ucSlaveAddr << 1) | ((I2C_READ == ulOpcode)? 1 : 0);
return 0;
}
void i2c_write(I2C_REGISTERS *I2C_BASE, const uint8_t *pbuf, uint32_t len)
{
/* 等待数据寄存器就绪,可以再次发送数据 */
while(!(I2C_BASE->I2SR & (1 << 7)));
I2C_BASE->I2SR &= ~(1 << 1); /* 清除IICIF */
I2C_BASE->I2CR |= 1 << 4; /* 发送数据(transmit) */
while(len--)
{
I2C_BASE->I2DR = *pbuf++; /* 将buf中的数据写入到数据寄存器I2DR */
while(!(I2C_BASE->I2SR & (1 << 1))); /* 等待传输完成,完成或失败,中断状态位被置1 */
I2C_BASE->I2SR &= ~(1 << 1); /* 清除中断状态位 */
/* 检查有无错误 */
if(i2c_check(I2C_BASE, I2C_BASE->I2SR))
break;
}
I2C_BASE->I2SR &= ~(1 << 1); /* 清除中断状态位 */
i2c_stop(I2C_BASE); /* 发送停止信号 */
}
void i2c_read(I2C_REGISTERS *I2C_BASE, uint8_t *pbuf, uint32_t len)
{
volatile uint8_t dummy = 0;
dummy++; /* 防止编译警告 */
/* 等待数据寄存器就绪 */
while(!(I2C_BASE->I2SR & (1 << 7)));
I2C_BASE->I2SR &= ~(1 << 1); /* 清除IICIF */
I2C_BASE->I2CR &= ~((1 << 4) | (1 << 3)); /* 接收数据: Receive,TXAK */
/* 如果只接收一个字节数据的话发送NACK信号 */
if(len == 1)
I2C_BASE->I2CR |= (1 << 3);
dummy = I2C_BASE->I2DR; /* 假读 */
while(len--)
{
while(!(I2C_BASE->I2SR & (1 << 1))); /* 等待传输完成 */
I2C_BASE->I2SR &= ~(1 << 1); /* 清除标志位 */
if(len == 0)
{
i2c_stop(I2C_BASE); /* 发送停止信号 */
}
if(len == 1)
{
I2C_BASE->I2CR |= (1 << 3);
}
*pbuf++ = I2C_BASE->I2DR;
}
}
uint8_t i2c_transfer(I2C_REGISTERS *I2C_BASE, I2C_TRANSFER *transfer)
{
uint32_t ulRet = 0;
uint32_t ulOpcode = transfer->ulOpcode;
/*开始前准备工作,清除标志位
*bit-4 IAL 仲裁位,bit-1 IIF 中断标志位
*/
I2C_BASE->I2SR &= ~((1 << 1) | (1 << 4));
/* 等待传输完成 */
while(!((I2C_BASE->I2SR >> 7) & 0X1)){};
/* 如果要读某个寄存区,寄存器地址要先"写"给从设备
* 所以方向要"先写","后读"
*/
if ((transfer->ulSubAddressLen > 0) && (transfer->ulOpcode == I2C_READ))
{
ulOpcode = I2C_WRITE;
}
ulRet = i2c_start(I2C_BASE, transfer->ucSlaveAddress, ulOpcode);
if (ulRet)
{
return ulRet;
}
/* 等待传输完成: 中断状态为会被置1 */
while(!(I2C_BASE->I2SR & (1 << 1))){};
/* 检查是否出错 */
ulRet = i2c_check(I2C_BASE, I2C_BASE->I2SR);
if (ulRet)
{
i2c_stop(I2C_BASE); /* 发送停止信号 */
return ulRet;
}
/*如果ulSubAddressLen不为0,表示要发送寄存器地址*/
if (transfer->ulSubAddressLen)
{
do
{
/* 清除中断状态位 */
I2C_BASE->I2SR &= ~(1 << 1);
/* 调整长度, 也许寄存器地址有多个字节, 本程序最多支持4字节 */
transfer->ulSubAddressLen--;
I2C_BASE->I2DR = ((transfer->ulSubAddress) >> (8 * transfer->ulSubAddressLen));
while(!(I2C_BASE->I2SR & (1 << 1))); /* 等待传输完成: 中断状态位被置1 */
/* 检查是否出错 */
ulRet = i2c_check(I2C_BASE, I2C_BASE->I2SR);
if(ulRet)
{
i2c_stop(I2C_BASE); /* 出错:发送停止信号 */
return ulRet;
}
}
while ((transfer->ulSubAddressLen > 0) && (ulRet == I2C_OK));
if (I2C_READ == transfer->ulOpcode)
{
I2C_BASE->I2SR &= ~(1 << 1); /* 清除中断状态位 */
i2c_restart(I2C_BASE, transfer->ucSlaveAddress, I2C_READ); /* 发送重复开始信号和从机地址 */
while(!(I2C_BASE->I2SR & (1 << 1))){}; /* 等待传输完成: 中断状态位被置1 */
/* 检查是否出错 */
ulRet = i2c_check(I2C_BASE, I2C_BASE->I2SR);
if(ulRet)
{
ulRet = I2C_ADDRNAK;
i2c_stop(I2C_BASE); /* 出错:发送停止信号 */
return ulRet;
}
}
}
/* 发送数据 */
if ((I2C_WRITE == transfer->ulOpcode) && (transfer->ulLenth > 0))
{
i2c_write(I2C_BASE, transfer->pbuf, transfer->ulLenth);
}
/* 读取数据 */
if ((I2C_READ == transfer->ulOpcode) && (transfer->ulLenth > 0))
{
i2c_read(I2C_BASE, transfer->pbuf, transfer->ulLenth);
}
return 0;
}
uint8_t i2c_write_one_byte(uint8_t addr,uint8_t reg, uint8_t data,I2C_REGISTERS *I2C_BASE)
{
uint8_t status = 0;
uint8_t writedata=data;
I2C_TRANSFER transfer;
/* 配置I2C xfer结构体 */
transfer.ucSlaveAddress = addr; /* 备地址 */
transfer.ulOpcode = I2C_WRITE; /* 数据方向:写 */
transfer.ulSubAddress = reg; /* 发出设备地址后马上发寄存器地址 */
transfer.ulSubAddressLen = 1; /* 地址长度一个字节 */
transfer.pbuf = &writedata; /* 要发出的数据 */
transfer.ulLenth = 1; /* 数据长度1个字节 */
status = i2c_transfer(I2C_BASE, &transfer);
return status;
}
uint8_t i2c_read_one_byte(uint8_t addr, uint8_t reg,I2C_REGISTERS *I2C_BASE)
{
uint8_t val=0;
uint8_t status = 0;
I2C_TRANSFER transfer;
transfer.ucSlaveAddress = addr; /* 设备地址 */
transfer.ulOpcode = I2C_READ; /* 数据方向:读 */
transfer.ulSubAddress = reg; /* 发出设备地址后马上发寄存器地址,
* 这是一个写操作
* 之后会再次发出设备地址,读数据
*/
transfer.ulSubAddressLen = 1; /* 地址长度一个字节 */
transfer.pbuf = &val; /* 接收数据缓冲区 */
transfer.ulLenth = 1; /* 要读取的数据长度:1 */
status = i2c_transfer(I2C_BASE, &transfer);
return val;
}
i2c.h
#ifndef _I2C_H
#define _I2C_H
#include "type.h"
/*
*IC2状态码,方便通过返回值对程序返回处进行定位
*/
#define I2C_OK (0)
#define I2C_ERROR (1)
#define I2C_BUSY (2)
#define I2C_IDLE (3)
#define I2C_NAK (4)
#define I2C_ARBITRATIONLOST (5)
#define I2C_TIMEOUT (6)
#define I2C_ADDRNAK (7)
/*
*The I2C contains five 16-bit registers.
*/
/* 绝对地址 寄存器名 位宽(bit) 权限 复位值 章节/页
* 21A_0000 I2C Address Register (I2C1_IADR) 16 R/W 0000h 31.7.1/1463
* 21A_0004 I2C Frequency Divider Register (I2C1_IFDR) 16 R/W 0000h 31.7.2/1463
* 21A_0008 I2C Control Register (I2C1_I2CR) 16 R/W 0000h 31.7.3/1465
* 21A_000C I2C Status Register (I2C1_I2SR) 16 R/W 0081h 31.7.4/1466
* 21A_0010 I2C Data I/O Register (I2C1_I2DR) 16 R/W 0000h 31.7.5/1468
*/
/*目前仅用I2C1即可,后面使用2-4可以参考如下定义,通过对I2C1-4有序号的宏的命名来区分I2C寄存器组,完成通用接口的编写后,后面使用其他组寄存器仅需要把带序号的宏补齐,函数可以通用*/
#define I2C1_BASE_ADDR (0x21A0000u)
/* I2C1 Base address */
#define I2C1 ((I2C_REGISTERS *)I2C1_BASE_ADDR)
#define I2C2_BASE_ADDR (0x21A4000u)
/* I2C1 Base address */
#define I2C2 ((I2C_REGISTERS *)I2C2_BASE_ADDR)
/* 寄存器地址的宏结构体定义,此种方式仅定义入口地址即可 */
/* all registers address is Base address + xh offset*/
typedef struct tagRegisters{
volatile uint16_t IADR; /*I2C Address Register, offset: 0x0 */
uint8_t ReservedIADR[2];
volatile uint16_t IFDR; /*I2C Frequency Divider Register, offset: 0x4 */
uint8_t ReservedIFDR[2];
volatile uint16_t I2CR; /*I2C Control Register, offset: 0x8 */
uint8_t ReservedI2CR[2];
volatile uint16_t I2SR; /*I2C Status Register, offset: 0xC */
uint8_t ReservedI2SR[2];
volatile uint16_t I2DR; /*I2C Data I/O Register, offset: 0x10 */
} I2C_REGISTERS;
/*
* IC2操作码定义
*/
typedef enum enI2C_OPCODE
{
I2C_WRITE = 0, /* 主机向从机写数据 */
I2C_READ = 1, /* 主机从从机读数据 */
I2C_DONOTHING_BULL
} I2C_OPCODE;
/*
* 主机传输结构体
*/
typedef struct tagI2cTransfer
{
uint8_t ucSlaveAddress; /* 7位从机地址 */
uint32_t ulOpcode ; /* 操作码*/
uint32_t ulSubAddress; /* 目标寄存器地址 */
uint8_t ulSubAddressLen; /* 寄存器地址长度 */
volatile uint32_t ulLenth; /* 数据长度 */
uint8_t *volatile pbuf; /* 数据*/
} I2C_TRANSFER;
/**********************************************************************
* 函数名称: i2c_init
* 功能描述: 初始化i2c
* 输入参数: 1.I2C的基地址
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void i2c_init(I2C_REGISTERS *I2C_BASE);
/**********************************************************************
* 函数名称: i2c_check
* 功能描述: 检查并清除错误
* 输入参数: 1.I2C的基地址 2.传输结构体
* 输出参数: 无
* 返 回 值: 状态结果
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_check(I2C_REGISTERS *I2C_BASE, uint32_t status);
/**********************************************************************
* 函数名称: i2c_start
* 功能描述: 发送开始信号
* 输入参数: 1.I2C的基地址2.设备地址3.操作码
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_start(I2C_REGISTERS *I2C_BASE, uint8_t ucSlaveAddr, uint32_t ulOpcode);
/**********************************************************************
* 函数名称: i2c_stop
* 功能描述: 停止信号
* 输入参数: 1.I2C的基地址
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_stop(I2C_REGISTERS *I2C_BASE);
/**********************************************************************
* 函数名称: i2c_restart
* 功能描述: 发送重新开始信号
* 输入参数: 1.I2C的基地址 2.传输结构体
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_restart(I2C_REGISTERS *I2C_BASE, uint8_t ucSlaveAddr, uint32_t ulOpcode);
/**********************************************************************
* 函数名称: i2c_write
* 功能描述: i2c master 写操作
* 输入参数: 1.I2C的基地址 2.数据 3.数据长度
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void i2c_write(I2C_REGISTERS *I2C_BASE, const uint8_t *pbuf, uint32_t len);
/**********************************************************************
* 函数名称: i2c_read
* 功能描述: i2c_master 读操作
* 输入参数: 1.I2C的基地址 2.数据 3.数据长度
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
void i2c_read(I2C_REGISTERS *I2C_BASE, uint8_t *pbuf, uint32_t len);
/**********************************************************************
* 函数名称: i2c_transfer
* 功能描述: i2c传输,包括读写功能
* 输入参数: 1.I2C的基地址 2.传输结构体
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_transfer(I2C_REGISTERS *I2C_BASE, I2C_TRANSFER *transfer);
/**********************************************************************
* 函数名称: I2C_WriteOneByte
* 功能描述: 向IC从设备写入数据
* 输入参数: 1.设备地址 2.要写入寄存器 3.要写入数据
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_write_one_byte(uint8_t addr,uint8_t reg, uint8_t data, I2C_REGISTERS *I2C_BASE);
/**********************************************************************
* 函数名称: I2C_ReadOneByte
* 功能描述: 向IC从设备读数据
* 输入参数: 1.设备地址 2.要读的寄存器
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/22 V1.0 小火山 创建
***********************************************************************/
uint8_t i2c_read_one_byte(uint8_t addr, uint8_t reg, I2C_REGISTERS *I2C_BASE);
#endif
main.c
/***************************************************************
版本 : V1.0
描述 : I2C testapp
其他 :
***************************************************************/
#include "i2c.h"
#include "type.h"
#include "ap3216c.h"
#include "uart.h"
#include "my_printf.h"
void delay(volatile unsigned int d)
{
while(d--);
}
int main()
{
int ret = 0;
uint16_t ir;
uint16_t ps;
uint16_t als;
Uart_Init() ;
ret = ap3216c_init();
if (ret)
{
printf("ap3216c_init fail!\n\r");
}
else
{
printf("ap3216c_init ok!\n\r");
}
while(1)
{
delay(100000);
/*环境光强度(ALS)、接近距离(PS)和红外线强度(IR)*/
ap3216c_read_data(&ir,&ps,&als);
printf("ir=%d ps=%d als=%d\n\r",ir,ps,als);
}
return 0;
}
my_printf.c
#include "my_printf.h"
#include "uart.h"
//==================================================================================================
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg(ap,t) ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
//==================================================================================================
unsigned char hex_tab[]={'0','1','2','3','4','5','6','7',\
'8','9','a','b','c','d','e','f'};
static int outc(int c)
{
PutChar(c);
return 0;
}
static int outs (const char *s)
{
while (*s != '\0')
PutChar(*s++);
return 0;
}
static int out_num(long n, int base,char lead,int maxwidth)
{
unsigned long m=0;
char buf[MAX_NUMBER_BYTES], *s = buf + sizeof(buf);
int count=0,i=0;
*--s = '\0';
if (n < 0){
m = -n;
}
else{
m = n;
}
do{
*--s = hex_tab[m%base];
count++;
}while ((m /= base) != 0);
if( maxwidth && count < maxwidth){
for (i=maxwidth - count; i; i--)
*--s = lead;
}
if (n < 0)
*--s = '-';
return outs(s);
}
/*reference : int vprintf(const char *format, va_list ap); */
static int my_vprintf(const char *fmt, va_list ap)
{
char lead=' ';
int maxwidth=0;
for(; *fmt != '\0'; fmt++)
{
if (*fmt != '%') {
outc(*fmt);
continue;
}
lead=' ';
maxwidth=0;
//format : %08d, %8d,%d,%u,%x,%f,%c,%s
fmt++;
if(*fmt == '0'){
lead = '0';
fmt++;
}
while(*fmt >= '0' && *fmt <= '9'){
maxwidth *=10;
maxwidth += (*fmt - '0');
fmt++;
}
switch (*fmt) {
case 'd': out_num(va_arg(ap, int), 10,lead,maxwidth); break;
case 'o': out_num(va_arg(ap, unsigned int), 8,lead,maxwidth); break;
case 'u': out_num(va_arg(ap, unsigned int), 10,lead,maxwidth); break;
case 'x': out_num(va_arg(ap, unsigned int), 16,lead,maxwidth); break;
case 'c': outc(va_arg(ap, int )); break;
case 's': outs(va_arg(ap, char *)); break;
default:
outc(*fmt);
break;
}
}
return 0;
}
/**********************************************************************
* 函数名称: printf
* 功能描述: 自定义串口格式化函数,实现printf打印功能
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 返回0,表示函数正常返回
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
//reference : int printf(const char *format, ...);
int printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
my_vprintf(fmt, ap);
va_end(ap);
return 0;
}
/**********************************************************************
* 函数名称: my_printf_test
* 功能描述: printf测试函数,测试自定义printf函数打印是否正常
* 输入参数: 无
* 输出参数:无
* 返 回 值: 返回0,表示函数正常返回
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
int my_printf_test(void)
{
printf("This is www.100ask.org my_printf test\n\r") ;
printf("test char =%c,%c\n\r", 'A','a') ;
printf("test decimal number =%d\n\r", 123456) ;
printf("test decimal number =%d\n\r", -123456) ;
printf("test hex number =0x%x\n\r", 0x55aa55aa) ;
printf("test string =%s\n\r", "www.100ask.org") ;
printf("num=%08d\n\r", 12345);
printf("num=%8d\n\r", 12345);
printf("num=0x%08x\n\r", 0x12345);
printf("num=0x%8x\n\r", 0x12345);
printf("num=0x%02x\n\r", 0x1);
printf("num=0x%2x\n\r", 0x1);
printf("num=%05d\n\r", 0x1);
printf("num=%5d\n\r", 0x1);
return 0;
}
my_printf.h
#ifndef _MY_PRINTF_H
#define _MY_PRINTF_H
#define MAX_NUMBER_BYTES 64
/**********************************************************************
* 函数名称: my_printf_test
* 功能描述: printf测试函数,测试自定义printf函数打印是否正常
* 输入参数: 无
* 输出参数:无
* 返 回 值: 返回0,表示函数正常返回
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
extern int my_printf_test(void);
/**********************************************************************
* 函数名称: printf
* 功能描述: 自定义串口格式化函数,实现printf打印功能
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 返回0,表示函数正常返回
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
int printf(const char *fmt, ...);
#endif /* _MY_PRINTF_H */
start.S
.text
.global _start
_start:
//设置栈
ldr sp,=0x80200000
bl clean_bss
bl main
halt:
b halt
clean_bss:
/* 清除BSS段 */
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
clean:
str r3, [r1]
add r1, r1, #4
cmp r1, r2
bne clean
mov pc, lr
string_utils.c
#include "string_utils.h"
#define NULL ((void *)0)
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
#define _D 0x04 /* digit */
#define _C 0x08 /* cntrl */
#define _P 0x10 /* punct */
#define _S 0x20 /* white space (space/lf/tab) */
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
//==============================
unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
/*
* Rather than doubling the size of the _ctype lookup table to hold a 'blank'
* flag, just check for space or tab.
*/
#define isblank(c) (c == ' ' || c == '\t')
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)
static inline unsigned char __tolower(unsigned char c)
{
if (isupper(c))
c -= 'A'-'a';
return c;
}
static inline unsigned char __toupper(unsigned char c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
#define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)
/**********************************************************************
* 函数名称: simple_strtoul
* 功能描述: 字符串转换为无符号长整型数(long)
* 输入参数:
* cp -- 转换的字符串
* endptr -- 第一个不能转换的字符的指针
* base -- 字符串 str 所采用的进制,范围2 至36,或0
* 输出参数: 无
* 返 回 值: 回转换后的无符号长整数,如果没有执行有效的转换,则返回一个零值
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
{
unsigned long result = 0,value;
if (*cp == '0') {
cp++;
if ((*cp == 'x' || *cp == 'X') && isxdigit(cp[1])) {
base = 16;
cp++;
}
if (!base) {
base = 8;
}
}
if (!base) {
base = 10;
}
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
? toupper(*cp) : *cp)-'A'+10) < base) {
result = result*base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
/**********************************************************************
* 函数名称: simple_strtol
* 功能描述: 字符串转换为长整型数(long)
* 输入参数:
* cp -- 转换的字符串
* endptr -- 第一个不能转换的字符的指针
* base -- 字符串 str 所采用的进制,范围2 至36,或0
* 输出参数: 无
* 返 回 值: 回转换后的长整数,如果没有执行有效的转换,则返回一个零值
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
long simple_strtol(const char *cp,char **endp,unsigned int base)
{
if(*cp=='-')
return -simple_strtoul(cp+1,endp,base);
return simple_strtoul(cp,endp,base);
}
/**********************************************************************
* 函数名称: gets
* 功能描述: 将串口输入的字符转换为字符串
* 输入参数:
* s[] -- 字符数组指针,字符缓冲区
* 输出参数: 无
* 返 回 值: 字符串指针
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
char *gets(char s[])
{
int i = 0;
char c;
while(1)
{
c = GetChar();
/* 回显 */
PutChar(c);
if (c == '\n')
PutChar('\r');
else if (c == '\r')
PutChar('\n');
if((c == '\n') || (c == '\r'))
{
s[i] = '\0';
break;
}
else
{
s[i++] = c;
}
}
return s;
}
/**********************************************************************
* 函数名称: get_int
* 功能描述: 将从串口输入的字符转换为长整型数(long)
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 转换后的长整型数
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
int get_int(void)
{
char str[100];
gets(str);
return simple_strtol(str, NULL, 0);
}
/**********************************************************************
* 函数名称: get_uint
* 功能描述: 将从串口输入的字符转换为无符号长整型数(unsigned long)
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 转换后的无符号长整型数
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned int get_uint(void)
{
char str[100];
gets(str);
return simple_strtoul(str, NULL, 0);
}
string_utils.h
#ifndef _STRING_UTILS_H
#define _STRING_UTILS_H
#include "uart.h"
/**********************************************************************
* 函数名称: simple_strtoul
* 功能描述: 字符串转换为无符号长整型数(long)
* 输入参数:
* cp -- 转换的字符串
* endptr -- 第一个不能转换的字符的指针
* base -- 字符串 str 所采用的进制,范围2 至36,或0
* 输出参数: 无
* 返 回 值: 回转换后的无符号长整数,如果没有执行有效的转换,则返回一个零值
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
/**********************************************************************
* 函数名称: simple_strtol
* 功能描述: 字符串转换为长整型数(long)
* 输入参数:
* cp -- 转换的字符串
* endptr -- 第一个不能转换的字符的指针
* base -- 字符串 str 所采用的进制,范围2 至36,或0
* 输出参数: 无
* 返 回 值: 回转换后的长整数,如果没有执行有效的转换,则返回一个零值
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
long simple_strtol(const char *cp,char **endp,unsigned int base);
/**********************************************************************
* 函数名称: gets
* 功能描述: 将串口输入的字符转换为字符串
* 输入参数:
* s[] -- 字符数组指针,字符缓冲区
* 输出参数: 无
* 返 回 值: 字符串指针
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
char *gets(char s[]);
/**********************************************************************
* 函数名称: get_int
* 功能描述: 将从串口输入的字符转换为长整型数(long)
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 转换后的长整型数
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
int get_int(void);
/**********************************************************************
* 函数名称: get_uint
* 功能描述: 将从串口输入的字符转换为无符号长整型数(unsigned long)
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 转换后的无符号长整型数
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned int get_uint(void);
#endif /* _STRING_UTILS_H */
type.h
#ifndef _TYPE_H__
#define _TYPE_H__
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char s8;
typedef signed short int s16;
typedef signed int s32;
typedef signed long long int s64;
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
typedef unsigned long long int u64;
#define IOMUXC_UART4_TX_DATA_I2C1_SCL 0x020E00B4U, 0x2U, 0x020E05A4U, 0x1U, 0x020E0340U
#define IOMUXC_UART4_RX_DATA_I2C1_SDA 0x020E00B8U, 0x2U, 0x020E05A8U, 0x2U, 0x020E0344U
/*! @name SW_MUX_CTL_PAD - SW_MUX_CTL_PAD_JTAG_MOD SW MUX Control Register..SW_MUX_CTL_PAD_CSI_DATA07 SW MUX Control Register */
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK (0xFU) /* Merged from fields with different position or width, of widths (3, 4), largest definition used */
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT (0U)
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(x) (((uint32_t)(((uint32_t)(x)) << IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT)) & IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK) /* Merged from fields with different position or width, of widths (3, 4), largest definition used */
#define IOMUXC_SW_MUX_CTL_PAD_SION_MASK (0x10U)
#define IOMUXC_SW_MUX_CTL_PAD_SION_SHIFT (4U)
#define IOMUXC_SW_MUX_CTL_PAD_SION(x) (((uint32_t)(((uint32_t)(x)) << IOMUXC_SW_MUX_CTL_PAD_SION_SHIFT)) & IOMUXC_SW_MUX_CTL_PAD_SION_MASK)
/*! @name SELECT_INPUT - USB_OTG1_ID_SELECT_INPUT DAISY Register..USDHC2_WP_SELECT_INPUT DAISY Register */
#define IOMUXC_SELECT_INPUT_DAISY_MASK (0x7U) /* Merged from fields with different position or width, of widths (1, 2, 3), largest definition used */
#define IOMUXC_SELECT_INPUT_DAISY_SHIFT (0U)
#define IOMUXC_SELECT_INPUT_DAISY(x) (((uint32_t)(((uint32_t)(x)) << IOMUXC_SELECT_INPUT_DAISY_SHIFT)) & IOMUXC_SELECT_INPUT_DAISY_MASK) /* Merged from fields with different position or width, of widths (1, 2, 3), largest definition used */
static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
uint32_t muxMode,
uint32_t inputRegister,
uint32_t inputDaisy,
uint32_t configRegister,
uint32_t inputOnfield)
{
*((volatile uint32_t *)muxRegister) =
IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) | IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);
if (inputRegister)
{
*((volatile uint32_t *)inputRegister) = IOMUXC_SELECT_INPUT_DAISY(inputDaisy);
}
}
static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
uint32_t muxMode,
uint32_t inputRegister,
uint32_t inputDaisy,
uint32_t configRegister,
uint32_t configValue)
{
if (configRegister)
{
*((volatile uint32_t *)configRegister) = configValue;
}
}
#endif
uart.c
#include "uart.h"
static volatile unsigned int *IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA ;
static volatile unsigned int *IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA ;
/**********************************************************************
* 函数名称: Uart_Init
* 功能描述: 初始化UART,就是规定传输格式,设置波特率为115200,配置UART占用的GPIO管脚
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void Uart_Init(void)
{
IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA = (volatile unsigned int *)(0x20E0084);
IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA = (volatile unsigned int *)(0x20E0088);
*IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA = 0;
*IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA = 0;
UART1->UCR1 |= (1 << 0) ; /*关闭当前串口*/
/*
* 设置UART传输格式:
* UART1中的UCR2寄存器关键bit如下
* [14]: 1:忽略RTS引脚
* [8] : 0: 关闭奇偶校验 默认为0,无需设置
* [6] : 0: 停止位1位 默认为0,无需设置
* [5] : 1: 数据长度8位
* [2] : 1: 发送数据使能
* [1] : 1: 接收数据使能
*/
UART1->UCR2 |= (1<<14) |(1<<5) |(1<<2)|(1<<1);
/*
* UART1中的UCR3寄存器关键bit如下
* [2]: 1:根据官方文档表示,IM6ULL的UART用了这个MUXED模型,提示要设置
*/
UART1->UCR3 |= (1<<2);
/*
* 设置波特率
* 根据芯片手册得知波特率计算公式:
* Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1))
* 当我们需要设置 115200的波特率
* UART1_UFCR [9:7]=101,表示不分频,得到当前UART参考频率Ref Freq :80M ,
* 带入公式:115200 = 80000000 /(16*(UBMR + 1)/(UBIR+1))
*
* 选取一组满足上式的参数:UBMR、UBIR即可
*
* UART1_UBIR = 71
* UART1_UBMR = 3124
*/
UART1->UFCR = 5 << 7; /* Uart的时钟clk:80MHz */
UART1->UBIR = 71;
UART1->UBMR = 3124;
UART1->UCR1 |= (1 << 0); /*使能当前串口*/
}
/**********************************************************************
* 函数名称: PutChar
* 功能描述: 从串口输出单个字符到上位机
* 输入参数:单个字符
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void PutChar(int c)
{
while (!((UART1->USR2) & (1<<3))); /*等待上个字节发送完毕*/
UART1->UTXD = (unsigned char)c;
}
/**********************************************************************
* 函数名称: GetChar
* 功能描述: 通过串口,从上位机获取单个字符
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 返回接收到的字符
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned char GetChar(void)
{
while (!(UART1->USR2 & (1<<0))); /*等待接收数据*/
return (unsigned char)UART1->URXD;
}
/**********************************************************************
* 函数名称: PutStr
* 功能描述: 输出字符串,就是连续发送单个字符
* 输入参数: 字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void PutStr(const char *s)
{
while (*s)
{
PutChar(*s);
s++;
}
}
int raise(int signum)/* raise函数,防止编译报错 */
{
return 0;
}
uart.h
#ifndef _UART_H_
#define _UART_H_
/*UART1的寄存器的基地址*/
#define UART1_BASE (0x2020000u)
#define UART1 ((UART_Type *)UART1_BASE)
/*根据IMX6ULL芯片手册,定义UART的结构体*/
typedef struct {
volatile unsigned int URXD; /**< UART Receiver Register, offset: 0x0 */
unsigned char RESERVED_0[60];
volatile unsigned int UTXD; /**< UART Transmitter Register, offset: 0x40 */
unsigned char RESERVED_1[60];
volatile unsigned int UCR1; /**< UART Control Register 1, offset: 0x80 */
volatile unsigned int UCR2; /**< UART Control Register 2, offset: 0x84 */
volatile unsigned int UCR3; /**< UART Control Register 3, offset: 0x88 */
volatile unsigned int UCR4; /**< UART Control Register 4, offset: 0x8C */
volatile unsigned int UFCR; /**< UART FIFO Control Register, offset: 0x90 */
volatile unsigned int USR1; /**< UART Status Register 1, offset: 0x94 */
volatile unsigned int USR2; /**< UART Status Register 2, offset: 0x98 */
volatile unsigned int UESC; /**< UART Escape Character Register, offset: 0x9C */
volatile unsigned int UTIM; /**< UART Escape Timer Register, offset: 0xA0 */
volatile unsigned int UBIR; /**< UART BRM Incremental Register, offset: 0xA4 */
volatile unsigned int UBMR; /**< UART BRM Modulator Register, offset: 0xA8 */
volatile unsigned int UBRC; /**< UART Baud Rate Count Register, offset: 0xAC */
volatile unsigned int ONEMS; /**< UART One Millisecond Register, offset: 0xB0 */
volatile unsigned int UTS; /**< UART Test Register, offset: 0xB4 */
volatile unsigned int UMCR; /**< UART RS-485 Mode Control Register, offset: 0xB8 */
} UART_Type;
/**********************************************************************
* 函数名称: Uart_Init
* 功能描述: 初始化UART,就是规定传输格式,设置波特率为115200,配置UART占用的GPIO管脚
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void Uart_Init(void);
/**********************************************************************
* 函数名称: PutChar
* 功能描述: 从串口输出单个字符到上位机
* 输入参数:单个字符
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void PutChar(int c);
/**********************************************************************
* 函数名称: GetChar
* 功能描述: 通过串口,从上位机获取单个字符
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 返回接收到的字符
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
unsigned char GetChar(void);
/**********************************************************************
* 函数名称: PutStr
* 功能描述: 输出字符串,就是连续发送单个字符
* 输入参数: 字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/02/16 V1.0 zh(angenao) 创建
***********************************************************************/
void PutStr(const char *s);
#endif
Makefile
PREFIX=arm-linux-gnueabihf-
CC=$(PREFIX)gcc
LD=$(PREFIX)ld
AR=$(PREFIX)ar
OBJCOPY=$(PREFIX)objcopy
OBJDUMP=$(PREFIX)objdump
GCCDIR=$(shell which arm-linux-gnueabihf-gcc)
LIBDIR=$(subst arm-linux-gnueabihf-gcc,../,$(GCCDIR))
i2c.img : start.S uart.c i2c.c ap3216c.c main.c my_printf.c string_utils.c
$(CC) -nostdlib -g -c -o start.o start.S
$(CC) -nostdlib -g -c -o uart.o uart.c
$(CC) -nostdlib -g -c -o i2c.o i2c.c
$(CC) -nostdlib -g -c -o ap3216c.o ap3216c.c
$(CC) -nostdlib -g -c -o main.o main.c
$(CC) -nostdlib -g -c -o my_printf.o my_printf.c
$(CC) -nostdlib -g -c -o string_utils.o string_utils.c
$(LD) -T imx6ull.lds -g start.o i2c.o uart.o ap3216c.o main.o my_printf.o string_utils.o -o i2c.elf -lgcc -L$(LIBDIR)lib/gcc/arm-linux-gnueabihf/6.2.1
$(OBJCOPY) -O binary -S i2c.elf i2c.bin
$(OBJDUMP) -D -m arm i2c.elf > i2c.dis
./tools/mkimage -n ./tools/imximage.cfg.cfgtmp -T imximage -e 0x80100000 -d i2c.bin i2c.imx
dd if=/dev/zero of=1k.bin bs=1024 count=1
cat 1k.bin i2c.imx > i2c.img
clean:
rm -f i2c.dis i2c.bin i2c.elf i2c.imx i2c.img *.o