博客專欄

        EEPW首頁 > 博客 > 樹莓派開源驅動庫BCM2835之SPI

        樹莓派開源驅動庫BCM2835之SPI

        發布人:電子禪石 時間:2019-11-26 來源:工程師 發布文章

        官網:http://www.airspayce.com/mikem/bcm2835/index.html

         注意事項:

        1.

        In order for bcm2835 library SPI to work, you may need to disable the SPI kernel module using:

        sudo raspi-config
        under Advanced Options - enable Device Tree
        under Advanced Options - disable SPI
        Reboot.

        Since bcm2835 accesses the lowest level hardware interfaces (in eh intererests of speed and flexibility) there can be intercations with other low level software trying to do similar things.

        2.Real Time performance constraints


        The bcm2835 is a library for user programs (i.e. they run in 'userland'). Such programs are not part of the kernel and are usually subject to paging and swapping by the kernel while it does other things besides running your program. This means that you should not expect to get real-time performance or real-time timing constraints from such programs. In particular, there is no guarantee that the bcm2835_delay() and bcm2835_delayMicroseconds() will return after exactly the time requested. In fact, depending on other activity on the host, IO etc, you might get significantly longer delay times than the one you asked for. So please dont expect to get exactly the time delay you request.

        Arjan reports that you can prevent swapping on Linux with the following code fragment:

        #define <sched.h>
        #define <sys/mman.h>
        struct sched_param sp;
        memset(&sp, 0, sizeof(sp));
        sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
        sched_setscheduler(0, SCHED_FIFO, &sp);
        mlockall(MCL_CURRENT | MCL_FUTURE);



        一、前言

        本文是樹莓派外圍io操作的入門介紹,高手跳過。

        前一篇介紹了BCM2835庫的init部分,這里接著介紹一下BCM2835的SPI. SPI在BCM2835庫文件中有兩個相關的文件,一個是spi.c和spin. c; spin.c是多字節連續發送接收的demo。Spin.c是單字節發送的demo。這里主要講一下spin.c。

        BCM2835庫的主要代碼實現都目錄下面的bcm2835.c這個文件里面。Spi部分相關的代碼接口一共有11個,分別是:

        int bcm2835_spi_begin(void); //

        void bcm2835_spi_end(void);

        void bcm2835_spi_setBitOrder(uint8_t order);

        void bcm2835_spi_setBitOrder(uint8_t order);

        void bcm2835_spi_setClockDivider(uint16_t divider);

        void bcm2835_spi_setDataMode(uint8_t mode);

        void bcm2835_spi_chipSelect(uint8_t cs);

        void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active);

        uint8_t bcm2835_spi_transfer(uint8_t value);

        void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len);

        void bcm2835_spi_transfern(char* buf, uint32_t len);

        void bcm2835_spi_writenb(char* buf, uint32_t len);

        二、代碼分析

        下面主要來分析一下spin.c里面的main函數及其所調用的接口函數

        int main(int argc, char **argv)

        {

        if (!bcm2835_init())//所有外圍io引腳初始化,之前已經分析過了

        {

        printf("bcm2835_init failed. Are you running as root??\n");

        return 1;

        }

        /*spi相關的功能引腳初始化,主要的是將spi對應的io設置成spi功能,將CS寄存器清0,

        清spi TX和RX的接收發送緩存。

        */

        if (!bcm2835_spi_begin())    {

        printf("bcm2835_spi_begin failed. Are you running as root??\n");

        return 1;

        }

        bcm2835_spi_begin();

        bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default

        /*將SPI的數據通信模式設置為模式BCM2835_SPI_MODE0,即CPOL = 0, CPHA = 0

        CPOL = 0通信空閑狀態時時鐘線為高電平,CPHA = 0第二個時鐘邊沿采樣數據。

        */

        bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default

        // 時鐘分頻

        bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);

        //拉低片選引腳

        bcm2835_spi_chipSelect(BCM2835_SPI_CS0);

        bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default

        char buf[] = { 0x01, 0x02, 0x11, 0x33 }; // Data to send

        bcm2835_spi_transfern(buf, sizeof(buf));//數據發送和接收

        // buf will now be filled with the data that was read from the slave

        printf("Read from SPI: %02X  %02X  %02X  %02X \n", buf[0], buf[1], buf[2], buf[3]);

        bcm2835_spi_end();

        bcm2835_close();

        return 0;

        }

        bcm2835_spi_transfern是通過調用bcm2835_spi_transfernb來完成數據的發送的。

        void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)

        {

        volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;

        volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;

        uint32_t TXCnt=0;

        uint32_t RXCnt=0;

        /* Clear TX and RX fifos */

        bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);

        /* Set TA = 1,設置TA將SPI恢復到未通信狀態 */

        bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);

        /* Use the FIFO's to reduce the interbyte times */

        while((TXCnt < len)||(RXCnt < len))//發送和接收循環

        {

        /* TX fifo not full, so add some more bytes */

        while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len ))

        {

        bcm2835_peri_write_nb(fifo, tbuf[TXCnt]);

        TXCnt++;

        }

        /* Rx fifo not empty, so get the next received bytes */

        while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len ))

        {

        rbuf[RXCnt] = bcm2835_peri_read_nb(fifo);

        RXCnt++;

        }

        }

        /* Wait for DONE to be set */

        //等待通信結束

        while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))

        ;

        /* Set TA = 0, and also set the barrier */

        bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);//設置TA位結束通信

        }

        三、實例效果

        1.png

        上圖是用邏輯分析儀抓到的數據,channel1和channel2分別是MOSI和MISO,channel3是時鐘信號,時鐘模式為CPOL = 0, CPHA = 0。CS片選為channel4,通信時將其拉低使能SPI。

        下圖是樹莓派3的外圍IO圖,左紅色方框是spi的主要三個引腳,右邊CE可不接,做loop是將MOSI和MISO互連,GDN和邏輯分析儀互連(最好相連,否則參考電平不同可能會出現解碼錯誤)。

        2.png

        原文鏈接:https://blog.csdn.net/housezhu/article/details/77926641

        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。

        dc相關文章:dc是什么


        低通濾波器相關文章:低通濾波器原理


        鎖相環相關文章:鎖相環原理
        鎖相放大器相關文章:鎖相放大器原理


        關鍵詞:

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 凌海市| 富川| 比如县| 桓台县| 会理县| 六枝特区| 公主岭市| 呈贡县| 天峻县| 茶陵县| 灌阳县| 元谋县| 平山县| 政和县| 晋江市| 九江市| 海伦市| 漯河市| 汉中市| 姚安县| 临武县| 昌邑市| 涿州市| 台东县| 疏附县| 白银市| 禄丰县| 农安县| 罗甸县| 庄河市| 顺义区| 岚皋县| 乌海市| 万宁市| 墨江| 双鸭山市| 常宁市| 安龙县| 西充县| 喀喇沁旗| 博罗县|