嵌入式实操----基于RT1170 首板硬件之EEPROM AT24C16调试(十五)

本文主要是通过迁移的思维,记录本人初次使用NXP MCUXpresso SDK API进行BSP开发

前面调通了SDRAM Flash GPIO之后,接下来调试EEPROM AT24C16功能,硬件设计如下所示

1. 首先阅读原理图

嵌入式实操----基于RT1170 首板硬件之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         : 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 */
}

2.3 总线初始化

/**
 * @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();

}

2.4 总线设备探测

/**
 * @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设备地址有回答,才能说明外设工作正常。

2.5 EEPROM读写

虽然官方提供了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;
}

3. 总结

以前从来没有写过裸机代码,eeprom的driver在linux下面是很常见的,但是以前也没有细看,主要是通过配置,驱动起来,通过相关的/sys/路径进行访问,在这次机会下重新深入学习。

你可能感兴趣的:(05-RT1170,开发)