前面调通了SDRAM Flash GPIO之后,接下来调试EEPROM AT24C16功能,硬件设计如下所示
针对EEPROM的调试一般需要配置i2c总线的时钟源,总线的通讯速率,对i2c总脚的引脚进行初始化,发送i2c 地址命令判断i2c设备工作是否正常,接下来就是通过官方的接口对i2c设备进行操作。
void bsp_i2c5_eeprom_clock_init(){
/* Configure LPI2C5 using OSC_24M */
rootCfg.mux = kCLOCK_LPI2C5_ClockRoot_MuxOsc24MOut;
rootCfg.div = 1;
CLOCK_SetRootClock(kCLOCK_Root_Lpi2c5, &rootCfg);
}
/**
* @brief i2c5 pin mux init
*
* @param [in] None
* @param [out] None
*
* @return
*
* @history
* 1.Date : 2021-5-27 17:13:28
* Author : panzidong
* Modification : Created function
*/
void bsp_i2c5_eeprom_pin_init(){
CLOCK_EnableClock(kCLOCK_Iomuxc_Lpsr); /* LPCG on: LPCG is ON. */
IOMUXC_SetPinMux(
IOMUXC_GPIO_LPSR_04_LPI2C5_SDA, /* GPIO_LPSR_04 is configured as LPI2C5_SDA */
1U); /* Software Input On Field: Input Path is determined by functionality */
IOMUXC_SetPinMux(
IOMUXC_GPIO_LPSR_05_LPI2C5_SCL, /* GPIO_LPSR_05 is configured as LPI2C5_SCL */
1U);
IOMUXC_SetPinConfig(
IOMUXC_GPIO_LPSR_04_LPI2C5_SDA, /* GPIO_LPSR_04 PAD functional properties : */
0x10U); /* Slew Rate Field: Slow Slew Rate
Drive Strength Field: normal driver
Pull / Keep Select Field: Pull Disable
Pull Up / Down Config. Field: Weak pull down
Open Drain LPSR Field: Enabled */
IOMUXC_SetPinConfig(
IOMUXC_GPIO_LPSR_05_LPI2C5_SCL, /* GPIO_LPSR_05 PAD functional properties : */
0x10U); /* Slew Rate Field: Slow Slew Rate
Drive Strength Field: normal driver
Pull / Keep Select Field: Pull Disable
Pull Up / Down Config. Field: Weak pull down
Open Drain LPSR Field: Enabled */
}
/**
* @brief i2c5 bus init
*
* @param [in] void
* @param [out] None
*
* @return
*
* @history
* 1.Date : 2021-5-27 17:35:18
* Author : panzidong
* Modification : Created function
*/
void bsp_i2c5_eeprom_init(void)
{
lpi2c_master_config_t masterConfig;
/*
* masterConfig.debugEnable = false;
* masterConfig.ignoreAck = false;
* masterConfig.pinConfig = kLPI2C_2PinOpenDrain;
* masterConfig.baudRate_Hz = 100000U;
* masterConfig.busIdleTimeout_ns = 0;
* masterConfig.pinLowTimeout_ns = 0;
* masterConfig.sdaGlitchFilterWidth_ns = 0;
* masterConfig.sclGlitchFilterWidth_ns = 0;
*/
LPI2C_MasterGetDefaultConfig(&masterConfig);
/* Change the default baudrate configuration */
masterConfig.baudRate_Hz = LPI2C_BAUDRATE;
/* Initialize the LPI2C master peripheral */
LPI2C_MasterInit(EEPROM_I2C_MASTER, &masterConfig, 24000000UL);
//LPI2C5_Bus_Driver_Init();
}
/**
* @brief print i2c devices on i2c bus 5
*
* @param [in] None
* @param [out] None
*
* @return
*
* @history
* 1.Date : 2021-6-7 16:3:18
* Author : panzidong
* Modification : Created function
*/
uint32_t bsp_i2c5_bus_detect()
{
lpi2c_master_transfer_t masterXfer = {0};
status_t reVal = kStatus_Fail;
uint8_t temp_buf[1] = {0};
uint8_t i = 0;
for(i = 0 ;i < 127; i++){
masterXfer.slaveAddress = (i<<1) ;
masterXfer.direction = kLPI2C_Read;
masterXfer.subaddress = 0;
masterXfer.subaddressSize = 0x01;
masterXfer.data = temp_buf;
masterXfer.dataSize = 1;
masterXfer.flags = kLPI2C_TransferDefaultFlag;
reVal = LPI2C_MasterTransferBlocking(EEPROM_I2C_MASTER, &masterXfer);
if (reVal == kStatus_Success)
{
PRINTF("find i2c device i2caddr = %x \r\n", i);
}
}
return 0;
}
只要对应的i2c设备地址有回答,才能说明外设工作正常。
虽然官方提供了AT24C02的例程,针对AT24C16的操作还是有所区别。主由容量变大,所以8位地址空间无法满足,操作地址的高位在从设备地址当中。再则原来的接口没有返回值可以判断,最后重新写了一份。
/**
* @brief lpi2c5 wait for standby state
*
* @param [in] uint8_t ClientAddr
* @param [out] None
*
* @return
*
* @history
* 1.Date : 2021-5-27 17:36:19
* Author : panzidong
* Modification : Created function
*/
uint8_t I2C_EEPROM_WaitStandbyState(uint8_t ClientAddr)
{
status_t lpi2c_status;
uint32_t delay_count = 10*256;
do
{
LPI2C_MasterClearStatusFlags(EEPROM_I2C_MASTER, kLPI2C_MasterNackDetectFlag);
lpi2c_status = LPI2C_MasterStart(EEPROM_I2C_MASTER, (ClientAddr>>1), kLPI2C_Write);
SDK_DelayAtLeastUs(40,SystemCoreClock);
}while(EEPROM_I2C_MASTER->MSR & kLPI2C_MasterNackDetectFlag && delay_count-- );
LPI2C_MasterClearStatusFlags(EEPROM_I2C_MASTER, kLPI2C_MasterNackDetectFlag);
lpi2c_status = LPI2C_MasterStop(EEPROM_I2C_MASTER);
SDK_DelayAtLeastUs(10,SystemCoreClock);
if(delay_count == 0 || lpi2c_status != kStatus_Success)
{
return 1;
}
return 0;
}
/**
* @brief at24c16 page innet read/write
*
* @param [in] uint8_t slave_addr
* @param [in] uint32_t subaddr
* @param [in] uint8_t *p_buf
* @param [in] uint32_t len
* @param [in] bool is_read
* @param [out] None
*
* @return
*
* @history
* 1.Date : 2021-5-28 9:49:22
* Author : panzidong
* Modification : Created function
*/
int __eeprom_program_data ( uint8_t slave_addr,
uint32_t subaddr,
uint8_t *p_buf,
uint32_t len,
bool is_read)
{
lpi2c_master_transfer_t masterXfer = {0};
status_t reVal = kStatus_Fail;
if(len > EEPROM_PAGE_SIZE)
{
PRINTF("len > EEPROM_PAGE_SIZE\r\n");
return 1;
}
/*
calculate slave address and register address,
some register bits are embeded in slave address
*/
masterXfer.slaveAddress = (slave_addr>>1) | ((subaddr >> 8) & 0x7);
masterXfer.direction = is_read;
masterXfer.subaddress = (uint16_t)(subaddr & 0xff);
masterXfer.subaddressSize = EEPROM_INER_ADDRESS_SIZE;
masterXfer.data = p_buf;
masterXfer.dataSize = len;
masterXfer.flags = kLPI2C_TransferDefaultFlag;
reVal = LPI2C_MasterTransferBlocking(EEPROM_I2C_MASTER, &masterXfer);
if (reVal != kStatus_Success)
{
return 1;
}
/* add one more tick to make sure has enough time to program */
if(! is_read){
I2C_EEPROM_WaitStandbyState(slave_addr);
}
return 0;
}
/**
* @brief eeprom write/read func
*
* @param [in] int start
* @param [in] uint8_t *p_buf
* @param [in] size_t len
* @param [in] bool is_read
is_read false : eeprom write
is_read true : eeprom read
* @param [out] None
*
* @return 0: success
* other: fail
* @history
* 1.Date : 2021-5-28 9:54:13
* Author : panzidong
* Modification : Created function
*/
int bsp_eeprom_rw ( int start,
uint8_t *p_buf,
size_t len,
bool is_read)
{
int ret = 0;
/* start address beyond this eeprom's capacity */
if (start > EEPROM_MAX_NUM) {
return -1;
}
/* no data will be read or written */
if (len == 0) {
return 0;
}
/* adjust len that will not beyond eeprom's capacity */
if ((start + len) > EEPROM_MAX_NUM) {
len = EEPROM_MAX_NUM - start;
}
/* write the unaligned data of the start */
int len_tmp = (EEPROM_PAGE_SIZE - start%EEPROM_PAGE_SIZE);
if (len < len_tmp) {
len_tmp = len;
}
ret = __eeprom_program_data(LPI2C_MASTER_SLAVE_ADDR_8BIT, start, p_buf, len_tmp, is_read);
if (ret != 0) {
ret = -1;
goto exit;
}
len -= len_tmp;
start += len_tmp;
p_buf += len_tmp;
/* write the rest data */
while (len) {
len_tmp = len > EEPROM_PAGE_SIZE ? EEPROM_PAGE_SIZE : len;
ret = __eeprom_program_data(LPI2C_MASTER_SLAVE_ADDR_8BIT, start, p_buf, len_tmp, is_read);
if (ret != 0) {
ret = -1;
goto exit;
}
len -= len_tmp;
start += len_tmp;
p_buf += len_tmp;
}
exit:
return ret;
}
uint8_t bsp_eeprom_test(void)
{
uint16_t i;
int result = 0;
PRINTF("Write data:\n");
for ( i=0; i<EEPROM_TEST_NUM; i++ )
{
EEPROM_Buffer_Write[i] = i % 256;
PRINTF("0x%02X ", EEPROM_Buffer_Write[i]);
if((i+1)%16 == 0 || i == (EEPROM_TEST_NUM-1))
PRINTF("\r\n");
}
result = bsp_eeprom_rw(0x0,EEPROM_Buffer_Write,EEPROM_TEST_NUM,false);
if(result != 0){
PRINTF("Write Failed \r\n");
return 1;
}
PRINTF("Write SUCCESS \r\n");
PRINTF("Read data: \r\n");
result = bsp_eeprom_rw(0x0,EEPROM_Buffer_Read,EEPROM_TEST_NUM,true);
if(result != 0){
PRINTF("Read Failed \r\n");
return 1;
}
PRINTF("Read SUCCESS \r\n");
for (i=0; i<EEPROM_TEST_NUM; i++)
{
if(EEPROM_Buffer_Read[i] != EEPROM_Buffer_Write[i])
{
PRINTF("0x%02X ", EEPROM_Buffer_Read[i]);
PRINTF("data ERROR!\r\n");
return 1;
}
PRINTF("0x%02X ", EEPROM_Buffer_Read[i]);
if((i+1)%16 == 0 || i == (EEPROM_TEST_NUM-1))
PRINTF("\r\n");
}
PRINTF("I2C(AT24C016) SUCCESS!\r\n");
return 0;
}
以前从来没有写过裸机代码,eeprom的driver在linux下面是很常见的,但是以前也没有细看,主要是通过配置,驱动起来,通过相关的/sys/路径进行访问,在这次机会下重新深入学习。