溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SylixOS中怎么實現(xiàn)EEPROM設(shè)備驅(qū)動

發(fā)布時間:2021-08-10 11:46:25 來源:億速云 閱讀:172 作者:Leah 欄目:互聯(lián)網(wǎng)科技

SylixOS中怎么實現(xiàn)EEPROM設(shè)備驅(qū)動,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

1.開發(fā)環(huán)境
操作系統(tǒng):SylixOS 
編程環(huán)境:RealEvo-IDE3.1.5
硬件平臺:SAMA5D2 Xplained開發(fā)板

2.EEPROM簡介
       EEPROM,或?qū)懽鱁2PROM,全稱電子抹除式可復(fù)寫只讀存儲器 (英語:Electrically-Erasable Programmable Read-Only Memory),是一種可以通過電子方式多次復(fù)寫的半導(dǎo)體存儲設(shè)備。相比EPROM,EEPROM不需要用紫外線照射,也不需取下,就可以用特定的電壓,來抹除芯片上的信息,以便寫入新的數(shù)據(jù)。
2.1 存儲結(jié)構(gòu)及設(shè)備地址
        本篇使用的EEPROM芯片型號是AT24MAC402,該芯片提供2Kbit串行電可擦除可編程的存儲單元,即256 bytes,并可通過I2C兼容的串行接口(TWI)進(jìn)行讀寫操作。此外,AT24MAC402可用來存放全球唯一的MAC或EUI地址(EUI-48)。其內(nèi)部存儲組織結(jié)構(gòu)如圖 2-1所示。

             SylixOS中怎么實現(xiàn)EEPROM設(shè)備驅(qū)動

圖 2-1  AT24MAC402內(nèi)部存儲結(jié)構(gòu)

        由圖 2-1可知,AT24MAC402提供了128-bit Serial Number和48-bit(9Ah-9Fh)的擴(kuò)展存儲部分用來存儲序列號和全球唯一的MAC或EUI地址。作為I2C從設(shè)備,可通過兩個不同的設(shè)備地址訪問EEPROM的這兩部分(標(biāo)準(zhǔn)和擴(kuò)展)的內(nèi)部存儲地址。AT24MAC402的芯片手冊對這兩部分的編址如圖 2-2所示。

             SylixOS中怎么實現(xiàn)EEPROM設(shè)備驅(qū)動

圖 2-2  設(shè)備地址

        其中Bit[3:1]由硬件引腳電平?jīng)Q定,在沒有設(shè)置寫保護(hù)的情況下,對于標(biāo)準(zhǔn)EEPROM可進(jìn)行讀寫操作,而擴(kuò)展部分僅支持讀操作。SAMA5D2開發(fā)板EEPROM的電路圖如圖 2-3所示。

             SylixOS中怎么實現(xiàn)EEPROM設(shè)備驅(qū)動

圖 2-3  EEPROM電路圖連線

      結(jié)合圖 2-2可知EEPROM標(biāo)準(zhǔn)部分的設(shè)備地址是‘1010100’,即0x54;擴(kuò)展部分的設(shè)備地址是‘1011100’,即0x5C。
2.2 操作模式
2.2.1 讀操作
        標(biāo)準(zhǔn)EEPROM部分和擴(kuò)展部分均支持讀操作,EEPROM支持以下三種類型的讀操作:
        當(dāng)前地址讀:在當(dāng)前地址讀操作方式時無需發(fā)送讀字節(jié)地址,每次只將當(dāng)前地址所存數(shù)據(jù)讀出,片內(nèi)地址始終保持自加,直到讀完整個EEPROM后又回到0地址。
        隨機(jī)地址讀:主設(shè)備發(fā)送有效從設(shè)備內(nèi)部地址,并且從設(shè)備發(fā)送響應(yīng)信號后將會將該內(nèi)部地址處的數(shù)據(jù)通過I2C發(fā)送給主設(shè)備。
        順序讀:多字節(jié)連續(xù)讀操作既可以是當(dāng)前地址讀,也可以是隨機(jī)地址讀,每次處理器接收到一字節(jié)數(shù)據(jù)都返回一個ACK,EEPROM接收到此ACK后會自動地址加1,接著輸出下一個字節(jié)數(shù)據(jù),直到處理器返回NO ACK時,讀過程結(jié)束。
2.2.2 寫操作
        標(biāo)準(zhǔn)EEPROM部分,在寫保護(hù)被禁止的情況下提供寫操作,并且支持以下兩種寫操作:
        字節(jié)寫:按字節(jié)寫時通常在向EEPROM發(fā)送設(shè)備地址并收到應(yīng)答信號后,發(fā)送寫字節(jié)地址再次收到ACK后開始寫數(shù)據(jù),最后發(fā)送停止位結(jié)束寫操作。
        頁寫:寫頁時EEPROM可一次連續(xù)寫入整頁數(shù)據(jù)(一頁為16字節(jié))。其發(fā)地址過程與寫字節(jié)時完全相同。不同的是,當(dāng)寫完一個數(shù)據(jù)字節(jié)后,處理器發(fā)不發(fā)停止?fàn)顟B(tài),而是在應(yīng)答信號后繼續(xù)寫入數(shù)據(jù),每一個字節(jié)接收完畢后,EEPROM都返回一個ACK,一直到寫完整頁。如果頁寫時寫入數(shù)超出該物理頁邊界,則超出數(shù)據(jù)將重新寫入頁首地址覆蓋之前所寫數(shù)據(jù)。
3.技術(shù)實現(xiàn)
        本篇通過內(nèi)核模塊的方式實現(xiàn)EEPROM的設(shè)備驅(qū)動。
        EEPROM驅(qū)動的編寫同樣是實現(xiàn)設(shè)備文件操作控制塊結(jié)構(gòu)體file_operations的成員函數(shù),在EEPROM設(shè)備驅(qū)動中主要實現(xiàn)了__e2promOpen、__e2promClose、__e2promRead、__e2promWrite、__e2promIoctl函數(shù)功能,__e2promIoctl函數(shù)用來設(shè)置待訪問的EEPROM的內(nèi)部地址。
        應(yīng)用程序可以通過訪問標(biāo)準(zhǔn)文件I/O函數(shù)來讀寫EEPROM設(shè)備,在讀寫EEPROM設(shè)備前,可調(diào)用lseek函數(shù)設(shè)置要讀/寫的eeprom內(nèi)部寄存器地址,然后調(diào)用標(biāo)準(zhǔn)文件I/O對該內(nèi)部地址進(jìn)行讀/寫操作。
EEPROM的讀寫功能,實質(zhì)上是調(diào)用I2C設(shè)備發(fā)送接口的方式實現(xiàn)的。這里使用字符驅(qū)動的框架來實現(xiàn)EEPROM的讀寫操作。由于標(biāo)準(zhǔn)EEPROM和擴(kuò)展部分的設(shè)備地址不同,但是對這兩部分的操作是一樣的,因此本篇僅給出標(biāo)準(zhǔn)EEPROM設(shè)備的驅(qū)動實現(xiàn)。
        標(biāo)準(zhǔn)EEPROM設(shè)備文件操作結(jié)構(gòu)體如程序清單 3-1所示。

程序清單 3-1  e2prom設(shè)備文件操作集

/*********************************************************************************************************  
**  e2prom設(shè)備文件操作集  
*********************************************************************************************************/  
struct file_operations GfileOperate = {  
    .fo_open  = __e2promOpen,  
    .fo_close = __e2promClose,  
    .fo_read  = __e2promRead,  
    .fo_write = __e2promWrite,  
    .fo_ioctl = __e2promIoctl  
};

        通過調(diào)用標(biāo)準(zhǔn)I/O函數(shù),可最終調(diào)用到file_operations結(jié)構(gòu)體中的對應(yīng)的成員函數(shù)。
3.1 讀操作
        __e2promRead讀取EEPROM內(nèi)部數(shù)據(jù),其實現(xiàn)如程序清單 3-2所示。

程序清單 3-2  __e2promRead實現(xiàn)

/*********************************************************************************************************  
** 函數(shù)名稱: __e2promRead  
** 功能描述: 讀取eeprom設(shè)備  
** 輸 入  : pvArg      版本類型選擇參數(shù)  
**           pcBuffer   緩沖區(qū)  
**           stMaxByte  緩沖區(qū)大小  
** 輸 出  : ERROR  
*********************************************************************************************************/  
static ssize_t __e2promRead(PVOID pvArg, PCHAR pcBuffer, size_t stMaxByte)  
{  
    UINT32 uiRet;  
    if(!pcBuffer) {  
        return PX_ERROR;  
    }  
    uiRet   = __at24xxRead(Gi2cDev, Goffset, (UINT8 *)pcBuffer, stMaxByte);  
    Goffset = (Goffset + stMaxByte) % EEPROM_MEM_SIZE;                  /*  內(nèi)部地址計數(shù)器保存值        */  
return (uiRet == ERROR_NONE) ? stMaxByte:PX_ERROR;  
}

__e2promRead將會調(diào)用at24xxRead函數(shù)實現(xiàn)讀操作,at24xxRead實現(xiàn)如程序清單 3-3所示。

程序清單 3-3  at24xxRead實現(xiàn)

/*********************************************************************************************************  

** 函數(shù)名稱: __at24xxRead  
** 功能描述: AT24xx         寄存器讀函數(shù)  
** 輸 入  : pI2cDev         i2c設(shè)備  
**           RegAddress      寄存器地址  
**           buf             數(shù)據(jù)接收緩沖區(qū)  
**           len             需要讀取的數(shù)據(jù)長度  
** 輸 出  : 返回 0 表示函數(shù)執(zhí)行成功  
*********************************************************************************************************/  
static int __at24xxRead (PLW_I2C_DEVICE  pI2cDev, UINT8 ucRegAddress, UINT8 *ucBuf, UINT uiLen)  
{  
    INT      iError;  
  
    LW_I2C_MESSAGE  i2cMsgs[2] = {  
        {  
            .I2CMSG_usAddr    = pI2cDev->I2CDEV_usAddr,  
            .I2CMSG_usFlag    = 0,                                      /*  0表示寫操作                 */  
            .I2CMSG_usLen     = sizeof(ucRegAddress),  
            .I2CMSG_pucBuffer = &ucRegAddress,                          /*  先寫要讀的寄存器地址        */  
        },  
        {  
            .I2CMSG_usAddr    = pI2cDev->I2CDEV_usAddr,  
            .I2CMSG_usFlag    = LW_I2C_M_RD,                         /*  表示讀操作                  */  
            .I2CMSG_usLen     = uiLen,  
            .I2CMSG_pucBuffer = ucBuf,                                  /*  接著讀操作                  */  
        }  
    };  
  
    iError = API_I2cDeviceTransfer(pI2cDev, i2cMsgs, 2);  
    if (iError < 0) {  
        return  (PX_ERROR);  
    }  
  
    return  (ERROR_NONE);  
}

            實質(zhì)上,應(yīng)用層調(diào)用read函數(shù),最終是調(diào)用的API_I2cDeviceTransfer函數(shù)實現(xiàn)接收與發(fā)送操作。
    3.2 寫操作
            __e2promWrite向EEPROM寫入數(shù)據(jù),其實現(xiàn)如程序清單 3-4所示。

    程序清單 3-4  e2promWrite實現(xiàn)

    /*********************************************************************************************************  
    
    ** 函數(shù)名稱: __e2promWrite  
    ** 功能描述: 寫eeprom設(shè)備  
    ** 輸 入  : pvArg      版本類型選擇參數(shù)  
    **           pcBuffer   緩沖區(qū)  
    **           stMaxByte  緩沖區(qū)大小  
    ** 輸 出  : ERROR  
    *********************************************************************************************************/  
    static ssize_t __e2promWrite(PVOID pvArg, PCHAR pcBuffer, size_t stMaxByte)  
    {  
        UINT32 uiRet;  
        if(!pcBuffer) {  
            return PX_ERROR;  
        }  
        uiRet = __at24xxWrite (Gi2cDev, Goffset, (UINT8 *)pcBuffer, stMaxByte);  
        Goffset = (Goffset + stMaxByte) % EEPROM_MEM_SIZE;                  /*  內(nèi)部地址計數(shù)器保存值        */  
    return (uiRet == ERROR_NONE) ? stMaxByte:PX_ERROR;  
    }

              __e2promWrite將會調(diào)用at24xxWrite函數(shù)實現(xiàn)EEPROM的寫操作,at24xxWrite實現(xiàn)如程序清單 3-5所示。

      程序清單 3-5  at24xxWrite實現(xiàn)

      /*********************************************************************************************************  
      
      ** 函數(shù)名稱: __at24xxWrite  
      ** 功能描述: AT24xx         寄存器寫函數(shù)  
      ** 輸 入  : pI2cDev         i2c設(shè)備  
      **           RegAddress      寄存器地址  
      **           buf             需要寫入寄存器的數(shù)據(jù)  
      **           len             寫入數(shù)據(jù)長度  
      ** 輸 出  : 返回 0 表示函數(shù)執(zhí)行成功  
      *********************************************************************************************************/  
      static int __at24xxWrite (PLW_I2C_DEVICE  pI2cDev, UINT8 ucRegAddress, UINT8 *ucBuf, UINT uiLen)  
      {  
          INT             iError;  
          if(!pI2cDev) {  
              return PX_ERROR;  
          }  
          /*  
           * 發(fā)送緩存大小:至少為(數(shù)據(jù)+地址)字節(jié)數(shù)  
           */  
          UINT8  *pui2cBuf = (UINT8 *)malloc(uiLen+1);  
        
          LW_I2C_MESSAGE  i2cMsgs[1] = {  
              {  
                  .I2CMSG_usAddr    = pI2cDev->I2CDEV_usAddr,  
                  .I2CMSG_usFlag    = 0,                                      /*  0表示寫操作                 */  
                  .I2CMSG_usLen     = uiLen + sizeof(ucRegAddress),           /*  (數(shù)據(jù)+地址)字節(jié)數(shù)           */  
                  .I2CMSG_pucBuffer = pui2cBuf,  
              },  
          };  
        
          /*  
           * 發(fā)送緩存開頭存放的是地址信息,然后才是數(shù)據(jù)  
           */  
          pui2cBuf[0] = ucRegAddress;  
          memcpy(&pui2cBuf[1], &ucBuf[0], uiLen);  
        
          iError = API_I2cDeviceTransfer(pI2cDev, i2cMsgs, 1);  
          if (iError < 0) {  
              free(pui2cBuf);  
              printk(KERN_ERR "__at24xxWrite(): failed to i2c transfer!\n");  
              return  (PX_ERROR);  
          }  
          free(pui2cBuf);  
          return  (ERROR_NONE);  
      }

                實質(zhì)上,應(yīng)用層調(diào)用write函數(shù),最終是調(diào)用的API_I2cDeviceTransfer函數(shù)實現(xiàn)接收與發(fā)送操作。
        3.3 設(shè)置讀寫地址
                通過實現(xiàn)__e2promIoctl函數(shù),完成設(shè)置待讀/寫的EEPROM的內(nèi)部寄存器地址,其實現(xiàn)如程序清單 3-6所示。

        程序清單 3-6  __e2promIoctl實現(xiàn)

        /*********************************************************************************************************  
        
        ** 函數(shù)名稱: __e2promIoctl  
        ** 功能描述: 控制eeprom設(shè)備  
        ** 輸 入  : pdevhdrHdr 設(shè)備頭  
        **           iCmd       命令  
        **           lArg       命令參數(shù)  
        ** 輸 出  : ERROR  
        *********************************************************************************************************/  
        static INT __e2promIoctl(PLW_DEV_HDR    pdevhdrHdr, INT  iCmd, LONG  lArg)  
        {  
            INT      iError;  
            struct stat *pstat;  
          
            switch(iCmd) {  
            case FIOSEEK:                                                       /*  獲取e2prom內(nèi)部地址偏移      */  
                Goffset = *(off_t *)lArg;  
                break;  
            case FIOFSTATGET:                                                   /*  獲得文件屬性                */  
                pstat = (struct stat *)lArg;  
                pstat->st_dev     = (dev_t)pdevhdrHdr;  
                pstat->st_ino     = (ino_t)0;                                   /*  相當(dāng)于唯一節(jié)點              */  
                pstat->st_mode    = 0644 | S_IFCHR;                             /*  默認(rèn)屬性                    */  
                pstat->st_nlink   = 1;  
                pstat->st_uid     = 0;  
                pstat->st_gid     = 0;  
                pstat->st_rdev    = 1;  
                pstat->st_size    = 0;  
                pstat->st_blksize = 0;  
                pstat->st_blocks  = 0;  
                pstat->st_atime   = API_RootFsTime(LW_NULL);                    /*  默認(rèn)使用 root fs 基準(zhǔn)時間   */  
                pstat->st_mtime   = API_RootFsTime(LW_NULL);  
                pstat->st_ctime   = API_RootFsTime(LW_NULL);  
                break;  
            default:  
                errno  = ENOSYS;  
                iError = PX_ERROR;  
                break;  
            }  
            return ERROR_NONE;  
        }

                  通過在應(yīng)用層調(diào)用lseek,可以調(diào)用到底層的__e2promIoctl函數(shù),在__e2promIoctl函數(shù)中通過給全局變量Goffset賦值,在調(diào)用read/write函數(shù)時,底層相應(yīng)的__e2promRead/ __e2promWrite便可獲得Goffset的偏移值,進(jìn)而讀取/寫入到EEPROM內(nèi)部寄存器中。
          3.4 驅(qū)動模塊初始化及卸載
                  驅(qū)動模塊初始化實現(xiàn)如程序清單 3-7所示。

          程序清單 3-7  模塊初始化

          /*********************************************************************************************************  
          ** 函數(shù)名稱: module_init  
          ** 功能描述: 驅(qū)動加載模塊  
          ** 輸 入  : NONE  
          ** 輸 出  : ERROR_CODE  
          *********************************************************************************************************/  
          int module_init (void)  
          {  
              printk("hello_module init!\n");  
              INT iDrvNum    = API_IosDrvInstallEx(&GfileOperate);                 /*  安裝驅(qū)動程序                */  
              API_IosDevAdd (&GdevhdrHdr, "/dev/eeprom", iDrvNum);                /*  安裝設(shè)備                    */  
              Gi2cDev = API_I2cDeviceCreate("/bus/i2c/1",  
                                            "/dev/eeprom",  
                                            DEVICE_ADDR,  
                                            0);  
              return ERROR_NONE;  
          }

                  模塊卸載實現(xiàn)如程序清單 3-8所示。

          程序清單 3-8  模塊卸載

          /*********************************************************************************************************  
          
          ** 函數(shù)名稱: module_exit  
          ** 功能描述: 驅(qū)動卸載模塊  
          ** 輸 入  : NONE  
          ** 輸 出  : NONE  
          *********************************************************************************************************/  
          void module_exit (void)  
          {  
              printk("hello_module exit!\n");  
            
              API_IosDevDelete(&GdevhdrHdr);                                      /*  刪除設(shè)備                    */  
              API_I2cDeviceDelete(Gi2cDev);                                        /*  刪除指定的 i2c 設(shè)備          */  
              return ;  
          }

            看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

            向AI問一下細(xì)節(jié)

            免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

            AI