精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MM32F0140 SPI學習筆記

jf_pJlTbmA9 ? 來源:靈動MM32MCU ? 作者:靈動MM32MCU ? 2023-09-26 16:51 ? 次閱讀

SPI簡介

SPI為串行外設接口,全稱Serial Peripheral interface,是一種全雙工、同步的通信總線,廣泛用于不同設備之間的板級通訊。

MM32F0140的SPI支持接收和發送1 ~ 32位數據同時進行,主模式最大速率24Mbps,從模式最大速率12Mbps,支持一個主機與多個從機操作,支持DMA操作。

數據通信

在進行SPI數據通信時,通常由MOSI、MISO、SCK、NSS四個管腳與外部器件相連。如圖1所示,MOSI管腳將來自主設備的數據輸入到從設備,MISO管腳將從設備響應的數據傳入主設備,從設備通過SCK管腳獲得主設備提供的時鐘信號,使發送和接收部分使用相同的時鐘,保證數據傳輸的可靠性。NSS管腳進行從設備選擇,使主設備可以和某個從設備一對一單獨通信。

主設備數據輸入(MISO)

MISO為主設備輸入從設備輸出管腳,傳輸方向為從設備發送到主設備。

主設備數據輸出(MOSI)

MOSI為主設備輸出從設備輸入管腳,傳輸方向為主設備發送到從設備。

時鐘(SCK)

SCK為串口時鐘,控制數據交換的速率,由主設備產生,通過SCK引腳傳輸供從設備使用。

片選(NSS)

NSS為從設備選擇管腳,SPI通過控制片選管腳NSS來控制多個從設備。當NSS引腳功能被激活后,配置作為主設備的SPI進入主模式,將會拉低NSS引腳,其余連接到主設備NSS的SPI設備由于檢測到了NSS拉低的信號,會自動進入從設備模式。

wKgaomUD7NSAYybIAAD2wJEt3CA848.png 圖1.SPI數據通信

數據傳輸時序

SPI可以通過配置時鐘極性(CPOL)與相位(CPHA)選擇四種不同的數據傳輸時序,即四種工作方式。

時鐘極性(CPOL)

時鐘極性是SCK在空閑時保持的電平狀態,當CPOL配置為0時,SCK在空閑狀態為低電平,即兩次傳輸之間為低電平;當CPOL配置為1時,SCK在空閑狀態為高電平,即兩次傳輸之間為高電平。

時鐘相位(CPHA)

時鐘相位用于決定采樣時刻,當CPHA配置為0時,第一個數據位采樣從第一個時鐘邊沿開始;當CPHA配置為1時,第一個數據位采樣從第二個時鐘邊沿開始;對數據進行邊沿采樣需要CPOL與CPHA的共同配置決定。

SCK低電平空閑,第一個沿采樣

當CPOL=0且CPHA=0,第一位數據位在SCK時鐘的第一個時鐘上升沿被采樣,如圖2所示。

wKgZomUD7NWAGhTcAAFIWpCzwxc222.png 圖2.SCK低電平空閑且第一個沿采樣

SCK高電平空閑,第一個沿采樣

當CPOL=1且CPHA=0,第一位數據位的SCK時鐘的第一個時鐘下降沿被采樣,如圖3所示。

wKgZomUD7NeAKyPoAAFKhzM4Jn0770.png 圖3.SCK高電平空閑且第一個沿采樣

SCK低電平空閑,第二個沿采樣

當CPOL=0且CPHA=1,第一個數據位在SCK時鐘的第二個時鐘下降沿被采樣,如圖4所示。

wKgZomUD7NiAPxsAAAFDyuNPONI743.png 圖4.SCK低電平空閑且第二個沿采樣

SCK高電平空閑,第二個沿采樣

當CPOL=1且CPHA=1,第一個數據位在SCK時鐘的第二個時鐘上升沿被采樣,如圖5所示。

wKgZomUD7NqADovGAAFEAXJcJHI204.png 圖5.SCK高電平空閑且第二個沿采樣

SPI配置

主模式

通過配置波特率發生器(SPI_I2S_SPBREG)設定串行時鐘波特率,公式為:波特率=fpclk/SPBRG (fpclk是APB時鐘頻率)。配置通用控制寄存器(SPI_I2S_CCTL)的SPI數據寬度位(SPILEN),決定數據幀的長度是7位還是8位;配置時鐘相位選擇位(CPHA)與時鐘極性標志位(CPOL),確定時序模式,為保證數據正常傳輸,主從設備的時序模式應保持配置一致;配置LSB在前使能位(LSBFE),決定數據位的輸出順序。操作全局控制寄存器(SPI_I2S_GCTL)的DW8_32位進行發送和接收數據寄存器有效數據選擇,可配置為只有低8位有效或32位數據都有效;操作主機模式位(MODE)為1,選擇主機模式;配置SPI/I2S選擇位(SPIEN)為1,使能SPI。

若只接收而不發送數據,則配置接收數據個數寄存器(SPI_I2S_RXDNR),定義下次接收過程中需要接收字節的個數。

從模式

配置通用控制寄存器(SPI_I2S_CCTL)的LSB在前使能位(LSBFE),決定數據位的輸出順序是從最低有效位到最高有效位或從最高有效位到最低有效位;配置SPI數據寬度位(SPILEN),決定數據幀的長度是7位還是8位;配置時鐘相位選擇位(CPHA)與時鐘極性標志位(CPOL),決定時序模式。配置全局控制寄存器(SPI_I2S_GCTL)的主機模式位(MODE)為0,選擇從機模式;配置SPI/I2S選擇位(SPIEN)為1,使能SPI。

數據發送

主模式

將需要發送的數據寫入發送數據寄存器(SPI_I2S_TXREG),該寄存器的有效位由全局控制器(SPI_I2S_GCTL)的DW8_32位控制。在發送第一個數據位時,整個數據被傳輸到移位寄存器,后續數據通過移位寄存器串行輸出到MOSI引腳。當中斷狀態寄存器(SPI_I2S_INTSTAT)的發送緩沖器有效中斷標志位(TX_INTF)被置1,數據已從發送緩沖器被傳輸到移位寄存器。

從模式

當從設備收到SCK傳來的時鐘信號,同時接收到MOSI引腳傳輸的第一個數據位,從設備開始發送,第一個位被發送到MISO引腳,其余bit位被傳輸到移位寄存器,通過移位寄存器將數據串行發送。當中斷狀態寄存器(SPI_I2S_INTSTAT)的發送緩沖器有效中斷標志位(TX_INTF)被置1,表示第一位已發送,其余位被傳輸到移位寄存器。

數據接收

主模式

從MISO引腳接收數據,數據通過移位寄存器,在最后一個采樣時鐘邊沿后,數據字節被傳輸到接收緩沖器中。當中斷狀態寄存器(SPI_I2S_INTSTAT)的接收端數據有效中斷標志位(RX_INTF)置1,數據接收完成,主模式下不再發送時鐘信號。

從模式

從MOSI引腳接收數據,數據通過移位寄存器,在最后一個采樣時鐘邊沿后,數據字節被傳輸到接收緩沖器中。當中斷狀態寄存器(SPI_I2S_INTSTAT)的接收端數據有效中斷標志位(RX_INTF)置1,數據接收完成。

實驗

本實驗為回環測試,通過使用杜邦線連接SPI的MISO與MOSI引腳,實現數據的發送與接收。配置SPI主機,SPI進行一次數據發送與接收并對發送與接收信息進行驗證,并通過串口打印傳輸情況,若有發送與接收數據不同的情況,串口打印出錯信息與出錯個數,若驗證成功則打印"spi loopback xfer done."。

啟用外設時鐘 enable_clock()

實驗使用SPI1,且需要通過串口打印實驗現象,因此需啟用SPI1與UART的外設時鐘。

{
    /* Enable UART1 clock. */
    RCC->APB2ENR |= RCC_APB2_PERIPH_UART1;
    /* Enable GPIOA clock. */
    RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA;
    /* Enable SPI1 clock. */
    RCC->APB2ENR |= RCC_APB2_PERIPH_SPI1;
}

配置引腳 pin_init()

配置SPI的NSS(PA4)、MOSI(PA7)、MISO(PA6)、SCK(PA5)引腳,因為實驗現象通過串口顯示,所以配置UART的TX(PA9)與RX(PA10)引腳。

void pin_init()
{
    /* Setup NSS(PA4). */
    GPIOA->CHL  = ~GPIO_CRL_MODE4_MASK;
    GPIOA->CHL |= (GPIO_PinMode_AF_PushPull << GPIO_CRL_MODE4_SHIFT);  /* PA4 multiplexed push-pull output. */
    GPIOA->AFRL  = ~GPIO_AFRL_AFR_MASK;
    GPIOA->AFRL |= (GPIO_AF_0 << GPIO_CRL_MODE4_SHIFT);   /* Use AF0. */

    /* Setup MOSI(PA7). */
    GPIOA->CHL  = ~GPIO_CRL_MODE7_MASK;
    GPIOA->CHL |= (GPIO_PinMode_AF_PushPull << GPIO_CRL_MODE7_SHIFT);  /* PA7 multiplexed push-pull output. */
    GPIOA->AFRL |= (GPIO_AF_0 << GPIO_CRL_MODE7_SHIFT);   /* Use AF0. */

    /* Setup MISO(PA6). */
    GPIOA->CHL  = ~GPIO_CRL_MODE6_MASK;
    GPIOA->CHL |= (GPIO_PinMode_In_Floating << GPIO_CRL_MODE6_SHIFT);  /* PA6 floating input. */
    GPIOA->AFRL |= (GPIO_AF_0 << GPIO_CRL_MODE6_SHIFT);   /* Use AF0. */

    /* Setup SCK(PA5). */
    GPIOA->CHL  = ~GPIO_CRL_MODE5_MASK;
    GPIOA->CHL |= (GPIO_PinMode_AF_PushPull << GPIO_CRL_MODE5_SHIFT);  /* PA5 floating input. */
    GPIOA->AFRL |= (GPIO_AF_0 << GPIO_CRL_MODE5_SHIFT);   /* Use AF0. */

    /* Setup PA9, PA10. */
    GPIOA->CRH  = ~GPIO_CRH_MODE9_MASK;
    GPIOA->CRH |= (GPIO_PinMode_AF_PushPull << GPIO_CRH_MODE9_SHIFT);  /* PA9 multiplexed push-pull output. */
    GPIOA->AFRH  = ~GPIO_AFRH_AFR_MASK;
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE9_SHIFT);   /* Use AF1. */

    GPIOA->CRH  = ~GPIO_CRH_MODE10_MASK;
    GPIOA->CRH |= (GPIO_PinMode_In_Floating << GPIO_CRH_MODE10_SHIFT);  /* PA10 floating input. */
    GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE10_SHIFT);  /* Use AF1. */
}

UART初始化 uart_init()

初始化UART,配置時鐘頻率、波特率、數據長度、停止位、傳輸模式及是否使用校驗。

void uart_init()
{
    /* Clear the corresponding bit to be used. */
    UART1->CCR  = ~( UART_CCR_PEN_MASK | UART_CCR_PSEL_MASK | UART_CCR_SPB0_MASK | UART_CCR_SPB1_MASK | UART_CCR_CHAR_MASK );
    UART1->GCR  = ~( UART_GCR_AUTOFLOWEN_MASK | UART_GCR_RXEN_MASK | UART_GCR_TXEN_MASK );
    /* WordLength. */
    UART1->CCR |= UART_CCR_CHAR_MASK;
    /* XferMode. */
    UART1->GCR |= (UART_XferMode_RxTx << UART_GCR_RXEN_SHIFT);
    /* Setup baudrate, BOARD_DEBUG_UART_FREQ = 48000000u, BOARD_DEBUG_UART_BAUDRATE = 9600u. */
    UART1->BRR = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) / 16u;
    UART1->FRA = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) % 16u;
    /* Enable UART1. */
    UART1->GCR |= UART_GCR_UARTEN_MASK;
}

SPI初始化 spi_init()

操作全局控制寄存器(SPI_I2S_GCTL)的MODE位,配置SPI為主模式,操作波特率發生器(SPI_I2S_SPBREG)配置波特率為400KHz,總線時鐘頻率為48MHz,操作通用控制寄存器(SPI_I2S_CCTL)的CPOL位與CPHA位配置通信模式,操作LSB在前使能位(LSBFE)令數據發送或接收最高位在前,操作全局控制寄存器對發送和接收數據寄存器有效數據進行選擇(DW8_32),配置為只有低8位有效,設置NSS位置1,使硬件控制主模式下的NSS輸出,配TXEN位與RXEN位置1,使能發送與接收;置SPI/I2S選擇位(SPIEN)為1,使能SPI。

void spi_init()
{
    /* Master. */
    SPI1->GCTL = SPI_I2S_GCTL_MODE_MASK; /* Master mode. */
    /* XferMode. */
    SPI1->GCTL |= (SPI_I2S_GCTL_RXEN_MASK | SPI_I2S_GCTL_TXEN_MASK);  /* Enable TX and RX. */
    /* AutoCS. */
    SPI1->GCTL |= SPI_I2S_GCTL_NSS_MASK;  /* NSS select signal that from hardware. */
    /* BaudRate. */
    SPI1->SPBRG = 120u;  /* SPBRG = fpclk / baudrate = 48000000 / 400000 = 120. */
    SPI1->CCTL  = ~(SPI_I2S_CCTL_TXEDGE_MASK | SPI_I2S_CCTL_RXEDGE_MASK);  /* Sampling data in the middle of transmission data bits. */
    /* DataWidth. */
    SPI1->GCTL  = ~SPI_I2S_GCTL_DW832_MASK;  /* Only the lower 8 bits are valid. */
    /* CPOL   CPHA. */
    SPI1->CCTL  = ~(SPI_I2S_CCTL_CPHA_MASK | SPI_I2S_CCTL_CPOL_MASK);  /* CPOL = 0, CPHA = 0. */
    /* LSB first enable bit. */
    SPI1->CCTL  = ~SPI_I2S_CCTL_LSBFE_MASK;  /* The highest bit of data transmission or reception comes first. */
    /* Enbale SPI. */
    SPI1->GCTL |= SPI_I2S_GCTL_SPIEN_MASK;
}

SPI發送數據 spi_putbyte()

當發送緩沖器未滿時,將數據傳入發送數據寄存器(SPI_I2S_TXRFG),根據初始化配置,數據低8位有效,通過MOSI引腳串行輸出。

void spi_putbyte(uint8_t c)
{
    while (SPI_I2S_CSTAT_TXFULL_MASK   SPI1->CSTAT)
    {}
    SPI1->TXREG = c;
}

SPI接收數據 spi_getbyte()

當接收端緩沖器接收了一個完整字節時,讀接收數據寄存器(SPI_I2S_RXREG),返回接收數據。

uint8_t spi_getbyte() 
{
    while (0u == (SPI_I2S_CSTAT_RXAVL_MASK   SPI1->CSTAT) )
    {}
    return SPI1->RXREG;
}

main()函數

main()函數結合上述操作,初始化SPI,定義發送數組spi_tx_buf[16]并賦值,將spi_tx_buf[16]數組中的數值進行發送,定義接收數組spi_rx_buf[16]對數據進行接收。本實驗使用杜邦線將MOSI引腳與MISO相連,因此,發送數據與接收數據應相同,將發送數組與接收數組的數值進行比較,定義變量spi_xfer_err_count用于計數發送與接收數值不同的數據個數。若發送與接收數值相同則串口輸出"spi loopback xfer done.",若不同則串口輸出傳輸錯誤與出錯個數。實驗現象如圖6所示。

int main()
{
    enable_clock();
    pin_init();
    uart_init();
    printf("spi_basic example.rn");

    spi_init();

    for (uint32_t i = 0u; i < 16u; i++)
    {
        spi_tx_buf[i] = i;
    }

    /* SPI xfer once. */
    for (uint32_t i = 0u; i < 16u; i++)
    {
        spi_putbyte(spi_tx_buf[i]);
        spi_rx_buf[i] = spi_getbyte();
    }

    /* validation. */
    spi_xfer_err_count = 0u;
    for (uint32_t i = 0u; i < 16u; i++)
    {
        if (spi_rx_buf[i] != spi_tx_buf[i])
        {
            spi_xfer_err_count++;
        }
    }
    if (spi_xfer_err_count == 0u)
    {
        printf("spi loopback xfer done.rn");
    }
    else
    {
        printf("spi loopback xfer error. spi_xfer_err_count = %urn", (unsigned)spi_xfer_err_count);
    }
    while (1)
    {}
}

wKgaomUD7NuAXzTEAABhukcyQT8942.png 圖6.實驗現象

來源: 靈動MM32MCU

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • mcu
    mcu
    +關注

    關注

    146

    文章

    17019

    瀏覽量

    350373
  • 接口
    +關注

    關注

    33

    文章

    8526

    瀏覽量

    150862
  • SPI
    SPI
    +關注

    關注

    17

    文章

    1701

    瀏覽量

    91345
  • 通信總線
    +關注

    關注

    0

    文章

    44

    瀏覽量

    9844
收藏 人收藏

    評論

    相關推薦

    基于MM32F0140SPI與W25Q80通信

    查看MM32F0140的MiniBoard原理圖,SPI掛載了W25Q80。
    的頭像 發表于 09-21 17:26 ?1623次閱讀
    基于<b class='flag-5'>MM32F0140</b>的<b class='flag-5'>SPI</b>與W25Q80通信

    靈動微課堂 (第205講) | MM32F0140 SPI 學習筆記

    SPI簡介SPI為串行外設接口,全稱Serial Peripheral interface,是一種全雙工、同步的通信總線,廣泛用于不同設備之間的板級通訊。MM32F0140SPI支持
    發表于 03-17 19:09

    AN0052從MM32F0130移植到MM32F0140(英文版)

    AN0052 從MM32F0130移植到MM32F0140(英文版)
    發表于 02-22 18:43 ?0次下載
    AN0052從<b class='flag-5'>MM32F</b>0130移植到<b class='flag-5'>MM32F0140</b>(英文版)

    MM32F0140 產品手冊(中文版)

    MM32F0140 產品手冊(中文版)
    發表于 02-22 18:45 ?0次下載
    <b class='flag-5'>MM32F0140</b> 產品手冊(中文版)

    MM32F0140 用戶手冊(中文版)

    MM32F0140 用戶手冊(中文版)
    發表于 02-22 18:46 ?0次下載
    <b class='flag-5'>MM32F0140</b> 用戶手冊(中文版)

    MM32F0140 用戶手冊(英文版)

    MM32F0140 用戶手冊(英文版)
    發表于 02-22 18:46 ?0次下載
    <b class='flag-5'>MM32F0140</b> 用戶手冊(英文版)

    MM32F0140 勘誤表(中文版)

    MM32F0140 勘誤表(中文版)
    發表于 02-22 18:47 ?0次下載
    <b class='flag-5'>MM32F0140</b> 勘誤表(中文版)

    MM32F0140 勘誤表(英文版)

    MM32F0140 勘誤表(英文版)
    發表于 02-22 18:48 ?0次下載
    <b class='flag-5'>MM32F0140</b> 勘誤表(英文版)

    基于MM32F0140的UDS Bootloader學習筆記

    基于MM32F0140的UDS Bootloader學習筆記
    的頭像 發表于 10-30 17:11 ?727次閱讀
    基于<b class='flag-5'>MM32F0140</b>的UDS Bootloader<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    MM32F0140學習筆記——CRC

    MM32F0140學習筆記——CRC
    的頭像 發表于 11-10 18:27 ?580次閱讀
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>——CRC

    MM32F0140學習筆記——窗口看門狗(WWDG)

    MM32F0140學習筆記——窗口看門狗(WWDG)
    的頭像 發表于 10-27 09:45 ?591次閱讀
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>——窗口看門狗(WWDG)

    MM32F0140學習筆記——FlexCAN 控制器局域網

    MM32F0140學習筆記——FlexCAN 控制器局域網
    的頭像 發表于 10-27 09:25 ?1437次閱讀
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>——FlexCAN 控制器局域網

    MM32F0140 DMA學習筆記

    MM32F0140 DMA 學習筆記
    的頭像 發表于 09-18 16:57 ?687次閱讀
    <b class='flag-5'>MM32F0140</b> DMA<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    MM32F0140 UART學習筆記

    MM32F0140 UART學習筆記
    的頭像 發表于 09-26 16:45 ?739次閱讀
    <b class='flag-5'>MM32F0140</b> UART<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>

    MM32F0140 GPIO學習筆記

    MM32F0140 GPIO學習筆記
    的頭像 發表于 09-26 16:42 ?531次閱讀
    <b class='flag-5'>MM32F0140</b> GPIO<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>