本文主要是通过迁移的思维,记录本人初次使用NXP MCUXpresso SDK API进行BSP开发
前面调通了SDRAM Flash GPIO之后,接下来调试EEPROM AT24C16功能,硬件设计如下所示
1. 首先阅读原理图
针对EEPROM的调试一般需要配置i2c总线的时钟源,总线的通讯速率,对i2c总脚的引脚进行初始化,发送i2c 地址命令判断i2c设备工作是否正常,接下来就是通过官方的接口对i2c设备进行操作。
2. 调试过程
2. 1 时钟初始化
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);}
2. 2 引脚初始化
/*** @brief i2c5 pin mux init** @param [in] None* @param [out] None* * @return * * @history* 1.Date : -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 RateDrive Strength Field: normal driverPull / Keep Select Field: Pull DisablePull Up / Down Config. Field: Weak pull downOpen Drain LPSR Field: Enabled */IOMUXC_SetPinConfig(IOMUXC_GPIO_LPSR_05_LPI2C5_SCL, /* GPIO_LPSR_05 PAD functional properties : */0x10U); /* Slew Rate Field: Slow Slew RateDrive Strength Field: normal driverPull / Keep Select Field: Pull DisablePull Up / Down Config. Field: Weak pull downOpen Drain LPSR Field: Enabled */}
2.3 总线初始化
/*** @brief i2c5 bus init** @param [in] void * @param [out] None* * @return * * @history* 1.Date : -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();}
2.4 总线设备探测
/*** @brief print i2c devices on i2c bus 5** @param [in] None* @param [out] None* * @return * * @history* 1.Date : -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设备地址有回答,才能说明外设工作正常。
2.5 EEPROM读写
虽然官方提供了AT24C02的例程,针对AT24C16的操作还是有所区别。主由容量变大,所以8位地址空间无法满足,操作地址的高位在从设备地址当中。再则原来的接口没有返回值可以判断,最后重新写了一份。
/*** @brief lpi2c5 wait for standby state** @param [in] uint8_t ClientAddr * @param [out] None* * @return * * @history* 1.Date : -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 : -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_readfalse : eeprom writeis_readtrue : eeprom read* @param [out] None* * @return 0: success* other: fail* @history* 1.Date : -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;}
3. 总结
以前从来没有写过裸机代码,eeprom的driver在linux下面是很常见的,但是以前也没有细看,主要是通过配置,驱动起来,通过相关的/sys/路径进行访问,在这次机会下重新深入学习。