博客專欄

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

樹莓派開源驅(qū)動庫BCM2835之SPI

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

官網(wǎng):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庫文件中有兩個相關(guān)的文件,一個是spi.c和spin. c; spin.c是多字節(jié)連續(xù)發(fā)送接收的demo。Spin.c是單字節(jié)發(fā)送的demo。這里主要講一下spin.c。

BCM2835庫的主要代碼實現(xiàn)都目錄下面的bcm2835.c這個文件里面。Spi部分相關(guān)的代碼接口一共有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函數(shù)及其所調(diào)用的接口函數(shù)

int main(int argc, char **argv)

{

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

{

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

return 1;

}

/*spi相關(guān)的功能引腳初始化,主要的是將spi對應(yīng)的io設(shè)置成spi功能,將CS寄存器清0,

清spi TX和RX的接收發(fā)送緩存。

*/

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的數(shù)據(jù)通信模式設(shè)置為模式BCM2835_SPI_MODE0,即CPOL = 0, CPHA = 0

CPOL = 0通信空閑狀態(tài)時時鐘線為高電平,CPHA = 0第二個時鐘邊沿采樣數(shù)據(jù)。

*/

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));//數(shù)據(jù)發(fā)送和接收

// 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是通過調(diào)用bcm2835_spi_transfernb來完成數(shù)據(jù)的發(fā)送的。

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,設(shè)置TA將SPI恢復(fù)到未通信狀態(tài) */

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))//發(fā)送和接收循環(huán)

{

/* 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 */

//等待通信結(jié)束

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);//設(shè)置TA位結(jié)束通信

}

三、實例效果

1.png

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

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

2.png

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

*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。

dc相關(guān)文章:dc是什么


低通濾波器相關(guān)文章:低通濾波器原理


鎖相環(huán)相關(guān)文章:鎖相環(huán)原理
鎖相放大器相關(guān)文章:鎖相放大器原理


關(guān)鍵詞:

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉