09_NoOS(裸机程序)\16_I2C编程\002_example_i2c_ap3216c_printf_show

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


	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一口Linux

众筹植发

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值