zoukankan      html  css  js  c++  java
  • 嵌入式实操----基于RT1170 首板硬件之EEPROM AT24C16调试(十五)

    本文主要是通过迁移的思维,记录本人初次使用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         : 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 
    ", 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
    ");
        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:
    ");
        
      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("
    ");    
       }
      
      
      result = bsp_eeprom_rw(0x0,EEPROM_Buffer_Write,EEPROM_TEST_NUM,false);
      if(result != 0){
          PRINTF("Write Failed 
    ");
          return 1;
      }
      
      PRINTF("Write SUCCESS 
    ");
       
      PRINTF("Read data: 
    ");
      result = bsp_eeprom_rw(0x0,EEPROM_Buffer_Read,EEPROM_TEST_NUM,true);
      if(result != 0){
          PRINTF("Read Failed 
    ");
          return 1;
      }
      
      PRINTF("Read SUCCESS 
    ");
       
      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!
    ");
          return 1;
        }
        PRINTF("0x%02X ", EEPROM_Buffer_Read[i]);
        if((i+1)%16 == 0 || i == (EEPROM_TEST_NUM-1))    
            PRINTF("
    ");
        
      }
      
      PRINTF("I2C(AT24C016) SUCCESS!
    ");
      return 0;
    }
    

    3. 总结

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

  • 相关阅读:
    vs2019+GLFW+GLAD出现无法解析的外部符号
    图的着色算法
    Head First C# 实验室2(冒险游戏)
    击中和击不中变换
    开运算和闭运算
    膨胀与腐蚀
    两数相加(C#数据结构和算法练习)
    C# 特性和索引(C#学习笔记06)
    C# 索引器(C#学习笔记05)
    C# yield checked,unchecked lock语句(C#学习笔记04)
  • 原文地址:https://www.cnblogs.com/lianghong881018/p/15169578.html
Copyright © 2011-2022 走看看