注:配置IO时不能配置为开漏模式
/*bsp_i2c.c*/
#include "bsp_i2c.h"
#define EEPROM_TEST_NUM 256 //写入数据个数
#define EEPROM_TEST_START_ADDR 0 //起始地址
uint8_t EEPROM_Buffer_Write[EEPROM_TEST_NUM];
uint8_t EEPROM_Buffer_Read[EEPROM_TEST_NUM];
static void LPI2C1_IOMUXC_Config(void);
static void LPI2C1_IOMUXC_PAD_Config(void);
static void EEPROM_LPI2C1_ModeInit(void);
static uint32_t I2C_Timeout_Callback(uint8_t errorcode);
static void LPI2C1_IOMUXC_Config(void)
{
IOMUXC_SetPinMux(EEPROM_LPI2C1SCL_IOMUXC,1);
IOMUXC_SetPinMux(EEPROM_LPI2C1SDA_IOMUXC,1);
}
static void LPI2C1_IOMUXC_PAD_Config(void)
{
IOMUXC_SetPinConfig(EEPROM_LPI2C1SCL_IOMUXC,LPI2C1_PAD_CONFIG_DATA);
IOMUXC_SetPinConfig(EEPROM_LPI2C1SDA_IOMUXC,LPI2C1_PAD_CONFIG_DATA);
}
static void EEPROM_LPI2C1_ModeInit(void)
{
lpi2c_master_config_t masterConfig;
CLOCK_SetMux(kCLOCK_Lpi2cMux,LPI2C1_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_Lpi2cDiv,LPI2C1_CLOCK_SOURCE_DIVIDER);
LPI2C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Hz = EEPROM_LPI2C1_BAUDRATE;
LPI2C_MasterInit(EEPROM_LPI2C1_MASTER, &masterConfig, LPI2C1_CLOCK_FREQUENCY);
}
void EEPROM_LPI2C1_MasterInit(void)
{
LPI2C1_IOMUXC_Config();
LPI2C1_IOMUXC_PAD_Config();
EEPROM_LPI2C1_ModeInit();
}
uint32_t EEPROM_LPI2C1_PageWrite(uint8_t ClientAddr,uint8_t WriteAddr,uint8_t *pBuffer,uint8_t NumByteToWrite)
{
lpi2c_master_transfer_t masterXfer = {0};
// struct _lpi2c_master_transfer
// {
// uint32_t
// flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for available
// options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */
// uint16_t slaveAddress; /*!< The 7-bit slave address. */
// lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. kLPI2C_Write kLPI2C_Read */
// uint32_t subaddress; /*!< Sub address. Transferred MSB first. */
// size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */
// void *data; /*!< Pointer to data to transfer. */
// size_t dataSize; /*!< Number of bytes to transfer. */
// };
status_t reVal = kStatus_Fail;//reVal = 1
if(NumByteToWrite>EEPROM_PAGE_SIZE){
PRINTF("NumByteToWrite>EEPROM_PageSize\r\n");
return 1;
}
masterXfer.slaveAddress = (ClientAddr>>1);
masterXfer.direction = kLPI2C_Write;
masterXfer.subaddress = WriteAddr;
masterXfer.subaddressSize = EEPROM_INER_ADDRESS_SIZE;
masterXfer.data = pBuffer;
masterXfer.dataSize = NumByteToWrite;
masterXfer.flags = kLPI2C_TransferDefaultFlag;
reVal = LPI2C_MasterTransferBlocking(EEPROM_LPI2C1_MASTER, &masterXfer);
if(reVal!=kStatus_Success){
PRINTF("LPI2C Write Error %s\r\n",__FUNCTION__);
return 1;
}
return 0;
}
//等待内部写入数据
uint8_t EEPROM_LPI2C1_WaitStandbyState(uint8_t ClientAddr)
{
status_t lpi2c_status;
uint32_t delay_count = EEPROM_LPI2C1_FLAG_TIMEOUT;
do{
LPI2C_MasterClearStatusFlags(EEPROM_LPI2C1_MASTER,kLPI2C_MasterNackDetectFlag);
lpi2c_status = LPI2C_MasterStart(EEPROM_LPI2C1_MASTER,(ClientAddr>>1), kLPI2C_Write);
Delay_n10us(4);
}while(EEPROM_LPI2C1_MASTER->MSR & kLPI2C_MasterNackDetectFlag && delay_count--);
LPI2C_MasterClearStatusFlags(EEPROM_LPI2C1_MASTER,kLPI2C_MasterNackDetectFlag);
lpi2c_status = LPI2C_MasterStop(EEPROM_LPI2C1_MASTER);
Delay_n10us(1);
if(delay_count==0 || lpi2c_status!=kStatus_Success){
I2C_Timeout_Callback(3);
return 1;
}
return 0;
}
static uint32_t I2C_Timeout_Callback(uint8_t errorcode)
{
PRINTF("I2C Wait Timeout\r\n");
return 0xFF;
}
//不限字节数写入数据
void I2C_EEPROM_Buffer_Write(uint8_t ClientAddr,uint8_t WriteAddr,uint8_t *pBuffer,uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0,NumOfSingle = 0,Addr = 0,count = 0;
uint8_t NumByteToWriteRest = NumByteToWrite;
Addr = WriteAddr % EEPROM_PAGE_SIZE;//写入的首地址是否和一页对齐 0
count = EEPROM_PAGE_SIZE-Addr;//该页还剩余可写入字节数 8
NumByteToWriteRest = (NumByteToWrite>count) ? (NumByteToWrite-count):(NumByteToWrite);//248
//要完整写入的页数不包括前count字节数
NumOfPage = NumByteToWriteRest / EEPROM_PAGE_SIZE;//31
//最后一页要写入的字节数
NumOfSingle = NumByteToWriteRest % EEPROM_PAGE_SIZE;//0
/*
* NumByteToWrite>count时,需要先往第一页写入count个字节
*/
if(count!=0 && NumByteToWrite>count){
EEPROM_LPI2C1_PageWrite(ClientAddr,WriteAddr,pBuffer,count);
EEPROM_LPI2C1_WaitStandbyState(ClientAddr);
WriteAddr += count;
pBuffer += count;
}
if(NumOfPage==0){//如果后续数据不足一页
EEPROM_LPI2C1_PageWrite(ClientAddr,WriteAddr,pBuffer,NumOfSingle);
EEPROM_LPI2C1_WaitStandbyState(ClientAddr);
}else{//如果后续数据大于一页
while(NumOfPage--){
EEPROM_LPI2C1_PageWrite(ClientAddr,WriteAddr,pBuffer,NumOfSingle);
EEPROM_LPI2C1_WaitStandbyState(ClientAddr);
WriteAddr += EEPROM_PAGE_SIZE;
pBuffer += EEPROM_PAGE_SIZE;
}
if(NumOfSingle){
EEPROM_LPI2C1_PageWrite(ClientAddr,WriteAddr,pBuffer,NumOfSingle);
EEPROM_LPI2C1_WaitStandbyState(ClientAddr);
}
}
}
uint32_t EEPROM_LPI2C1_BufferRead(uint8_t ClientAddr,uint8_t ReadAddr,uint8_t *pBuffer,uint16_t NumByteToRead)
{
lpi2c_master_transfer_t masterXfer = {0};
status_t reVal = kStatus_Fail;//reVal = 1
/* subAddress = ReadAddr, data = pBuffer 自从机处接收
起始信号 start + 设备地址 slaveaddress(w 写方向) + 子地址 subAddress +
重复起始信号 repeated start + 设备地址 slaveaddress(r 读方向) +
接收缓冲数据 rx data buffer + 停止信号 stop */
// struct _lpi2c_master_transfer
// {
// uint32_t
// flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for available
// options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */
// uint16_t slaveAddress; /*!< The 7-bit slave address. */
// lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. kLPI2C_Write kLPI2C_Read */
// uint32_t subaddress; /*!< Sub address. Transferred MSB first. */
// size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */
// void *data; /*!< Pointer to data to transfer. */
// size_t dataSize; /*!< Number of bytes to transfer. */
// };
masterXfer.slaveAddress = (ClientAddr>>1);
masterXfer.direction = kLPI2C_Read;
masterXfer.subaddress = (uint32_t)ReadAddr;
masterXfer.subaddressSize = EEPROM_INER_ADDRESS_SIZE;
masterXfer.data = pBuffer;
masterXfer.dataSize = NumByteToRead;
masterXfer.flags = kLPI2C_TransferDefaultFlag;
reVal = LPI2C_MasterTransferBlocking(EEPROM_LPI2C1_MASTER, &masterXfer);
if(reVal!=kStatus_Success){
PRINTF("Read failed %s\r\n",__FUNCTION__);
return 1;
}
return 0;
}
void EEPROM_LPI2C_Test(void)
{
uint16_t i;
PRINTF("Write Data\r\n");
for(i=0;i<EEPROM_TEST_NUM;i++)
{
EEPROM_Buffer_Write[i] = i;
PRINTF("0x%hX ", EEPROM_Buffer_Write[i]);
if((i+1)%10==0 || i==(EEPROM_TEST_NUM-1))
PRINTF("\r\n");
}
EEPROM_Buffer_Write[0] = 0xff;
EEPROM_Buffer_Write[1] = 0x65;
EEPROM_Buffer_Write[2] = 0x75;
I2C_EEPROM_Buffer_Write(EEPROM_WRITE_ADDRESS_8BIT,EEPROM_TEST_START_ADDR,EEPROM_Buffer_Write,EEPROM_TEST_NUM);
PRINTF("Write Success\r\n");
PRINTF("Read Data\r\n");
EEPROM_LPI2C1_BufferRead(EEPROM_READ_ADDRESS_8BIT,EEPROM_TEST_START_ADDR,EEPROM_Buffer_Read,EEPROM_TEST_NUM);
for(i=0;i<EEPROM_TEST_NUM;i++)
{
PRINTF("0x%hX ", EEPROM_Buffer_Read[i]);
if((i+1)%10==0 || i==(EEPROM_TEST_NUM-1))
PRINTF("\r\n");
}
}
/*bsp_i2c.h*/
#ifndef __BSP_I2C_H__
#define __BSP_I2C_H__
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#include "pad_config.h"
#include "fsl_lpi2c.h"
#include "fsl_debug_console.h"
#include "bsp_systick.h"
#define EEPROM_LPI2C1_MASTER_BASE (LPI2C1_BASE)
#define EEPROM_LPI2C1_MASTER ((LPI2C_Type *)EEPROM_LPI2C1_MASTER_BASE)
#define EEPROM_LPI2C1_BAUDRATE 400000U
#define EEPROM_LPI2C1SCL_GPIO GPIO1
#define EEPROM_LPI2C1SDA_GPIO GPIO1
#define EEPROM_LPI2C1SCL_GPIO_PIN 0U
#define EEPROM_LPI2C1SDA_GPIO_PIN 1U
#define EEPROM_LPI2C1SCL_IOMUXC IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL
#define EEPROM_LPI2C1SDA_IOMUXC IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA
#define LPI2C1_PAD_CONFIG_DATA (SRE_0_SLOW_SLEW_RATE | \
DSE_6_R0_6 | \
SPEED_1_MEDIUM_100MHz | \
ODE_0_OPEN_DRAIN_DISABLED | \
PKE_1_PULL_KEEPER_ENABLED | \
PUE_0_KEEPER_SELECTED | \
PUS_3_22K_OHM_PULL_UP | \
HYS_0_HYSTERESIS_DISABLED)
/*
选择 LPI2C 的时钟源
0 derive clock from pll3_60m
1 derive clock from osc_clk
*/
// 480/8=60MHz
#define LPI2C1_CLOCK_SOURCE_SELECT (0U)
// 60MHz/(5+1) = 10MHz
#define LPI2C1_CLOCK_SOURCE_DIVIDER (5U)
#define LPI2C1_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk)/8)/(LPI2C1_CLOCK_SOURCE_DIVIDER+1))
#define EEPROM_SIZE 256 //EEPROM总大小
#define EEPROM_PAGE_SIZE 8 //每页有8个字节
#define EEPROM_ADDRESS_7BIT (0xA0>>1)
#define EEPROM_WRITE_ADDRESS_8BIT (0xA0)
#define EEPROM_READ_ADDRESS_8BIT (0xA1)
#define EEPROM_INER_ADDRESS_SIZE 0x01
#define EEPROM_LPI2C1_FLAG_TIMEOUT ((uint32_t)0x100)
#define EEPROM_LPI2C1_LONG_TIMEOUT ((uint32_t)(10 * EEPROM_LPI2C1_FLAG_TIMEOUT))
void EEPROM_LPI2C1_MasterInit(void);
uint32_t EEPROM_LPI2C1_PageWrite(uint8_t ClientAddr,uint8_t WriteAddr,uint8_t *pBuffer,uint8_t NumByteToWrite);
uint8_t EEPROM_LPI2C1_WaitStandbyState(uint8_t ClientAddr);
void I2C_EEPROM_Buffer_Write(uint8_t ClientAddr,uint8_t WriteAddr,uint8_t *pBuffer,uint16_t NumByteToWrite);
uint32_t EEPROM_LPI2C1_BufferRead(uint8_t ClientAddr,uint8_t ReadAddr,uint8_t *pBuffer,uint16_t NumByteToRead);
void EEPROM_LPI2C_Test(void);
bool I2C_WriteByte(uint8_t SalveAddr,uint8_t RegAddr,uint8_t *DateByte);
#endif
/*pad_config.h*/
#ifndef __PAD_CONFIG_H__
#define __PAD_CONFIG_H__
#include "fsl_common.h"
/* SRE 压摆率选择 */
#define SRE_0_SLOW_SLEW_RATE IOMUXC_SW_PAD_CTL_PAD_SRE(0)
#define SRE_1_FAST_SLEW_RATE IOMUXC_SW_PAD_CTL_PAD_SRE(1)
/* 驱动能力配置,配置阻值的大小 */
#define DSE_0_OUTPUT_DRIVER_DISABLED IOMUXC_SW_PAD_CTL_PAD_DSE(0)
/* R0 260 Ohm @ 3.3V, 150Ohm@1.8V, 240 Ohm for DDR */
#define DSE_1_R0_1 IOMUXC_SW_PAD_CTL_PAD_DSE(1)
/* R0/2 */
#define DSE_2_R0_2 IOMUXC_SW_PAD_CTL_PAD_DSE(2)
/* R0/3 */
#define DSE_3_R0_3 IOMUXC_SW_PAD_CTL_PAD_DSE(3)
/* R0/4 */
#define DSE_4_R0_4 IOMUXC_SW_PAD_CTL_PAD_DSE(4)
/* R0/5 */
#define DSE_5_R0_5 IOMUXC_SW_PAD_CTL_PAD_DSE(5)
/* R0/6 */
#define DSE_6_R0_6 IOMUXC_SW_PAD_CTL_PAD_DSE(6)
/* R0/7 */
#define DSE_7_R0_7 IOMUXC_SW_PAD_CTL_PAD_DSE(7)
/* SPEED 带宽配置 */
#define SPEED_0_LOW_50MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(0)
#define SPEED_1_MEDIUM_100MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(1)
#define SPEED_2_MEDIUM_100MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(2)
#define SPEED_3_MAX_200MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(3)
/* ODE 是否使用开漏模式 */
#define ODE_0_OPEN_DRAIN_DISABLED IOMUXC_SW_PAD_CTL_PAD_ODE(0)
#define ODE_1_OPEN_DRAIN_ENABLED IOMUXC_SW_PAD_CTL_PAD_ODE(1)
/* PKE 是否使能保持器或上下拉功能 */
#define PKE_0_PULL_KEEPER_DISABLED IOMUXC_SW_PAD_CTL_PAD_PKE(0)
#define PKE_1_PULL_KEEPER_ENABLED IOMUXC_SW_PAD_CTL_PAD_PKE(1)
/* PUE 选择使用保持器还是上下拉 */
#define PUE_0_KEEPER_SELECTED IOMUXC_SW_PAD_CTL_PAD_PUE(0)
#define PUE_1_PULL_SELECTED IOMUXC_SW_PAD_CTL_PAD_PUE(1)
/* PUS 上下拉配置 */
#define PUS_0_100K_OHM_PULL_DOWN IOMUXC_SW_PAD_CTL_PAD_PUS(0)
#define PUS_1_47K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(1)
#define PUS_2_100K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(2)
#define PUS_3_22K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(3)
/* HYS 滞后功能 */
#define HYS_0_HYSTERESIS_DISABLED IOMUXC_SW_PAD_CTL_PAD_HYS(0)
#define HYS_1_HYSTERESIS_ENABLED IOMUXC_SW_PAD_CTL_PAD_HYS(1)
#endif