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

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

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

3天內不再提示

MM32F0140 DMA學習筆記

jf_pJlTbmA9 ? 來源:jf_pJlTbmA9 ? 作者:jf_pJlTbmA9 ? 2023-09-18 16:57 ? 次閱讀

DMA簡介

DMA全稱為Direct Memory Access,即直接存儲器訪問。在進行DMA傳輸前,CPU將總線控制權交給DMA,通過共享系統總線,實現無需CPU參與的快速數據傳輸,能夠直接將數據從一個地址空間復制到另一個地址空間,DMA在數據傳輸結束后將總線控制權交回CPU。

MM32F0140內置5路通用DMA,可以管理設備到存儲器、存儲器到設備與存儲器到存儲器的數據傳輸,每個通道都有專門的硬件DMA請求邏輯,也可以通過軟件配置來觸發每個通道。

MM32F0140的DMA模塊所支持的外設類型包括UARTI2C、SPI、ADC與通用、高級和基礎定時器,當DMA從外設產生的請求通過邏輯或輸入DMA控制器時,為避免沖突,在一個通道中,同時只能有一個外設DMA請求有效,詳細各通道DMA請求如圖1所示。

wKgZomUD7deAA_WyAAI_-gCmRpA486.png 圖1.各通道DMA外設請求

DMA配置

DMA的配置涉及到傳輸模式、數據寬度、外設地址、存儲器地址、通道優先級、數據傳輸數量、中斷使能、自動重裝載及指針增量。

傳輸模式

存儲器到外設模式

配置DMA_CCRx寄存器(x由1 ~ 7)的DIR位選擇傳輸方向,該位置1,傳輸方向為從存儲器讀;DMA_CCRx寄存器的MEM2MEM位置0,關閉存儲器到存儲器模式。

外設到存儲器模式

配置DMA_CCRx寄存器的DIR位選擇傳輸方向,該位置0,傳輸方向為從外設讀;DMA_CCRx寄存器的MEM2MEM位置0,關閉存儲器到存儲器模式。

存儲器到存儲器模式

數據傳輸方向為外設地址到存儲器地址:DMA_CCRx寄存器的MEM2MEM位置1,使能存儲器到存儲器模式;DIR位置0,從外設讀。

數據傳輸方向為存儲器地址到外設地址:DMA_CCRx寄存器的MEM2MEM位置1,使能存儲器到存儲器模式;DIR位置1,從存儲器讀。

注意,存儲器到存儲器模式不能與循環模式同時使用。

循環模式

若需要循環讀寫緩沖區或進行連續的數據傳輸,則可以進入循環模式。配置DMA通道x配置寄存器(DMA_CCRx)中的CIRC位為1,使能循環模式。在循環模式下,若DMA傳輸數量遞減為0,則重新加載先前配置的數值,繼續進行DMA數據傳輸。

自動重新加載

DMA通道x配置寄存器(DMA_CCRx)的ARE位控制自動重裝載,若ARE位置1,則使能自動重裝載傳輸數量,當DMA通道x傳輸數量寄存器(DMA_CNDTRx)中數值為0時,會自動將DMA_CNDTRx寄存器中的值加載為之前配置的數值;若ARE位置0,則禁止自動重裝載傳輸數量。

數據寬度

DMA的數據寬度配置包含:存儲器數據寬度配置與外設數據寬度配置,可獨立配置為字節、半字、全字。

存儲器數據寬度由DMA通道x配置寄存器(DMA_CCRx)的MSIZE位控制,MSIZE[1:0]為00則數據寬度為8bit,MSIZE[1:0]為01則數據寬度為16bit,MSIZE[1:0]為10則數據寬度為32bit。

外設數據寬度配置由DMA通道x配置寄存器(DMA_CCRx)的PSIZE位控制,可配置為8bit, 16bit或32bit,MSIZE位與PSIZE位如圖2所示。

wKgaomUD7dqAa9wmAADV7C_O_Kk769.png 圖2.數據寬度對應位

存儲器/外設地址

DMA的地址配置包含:存儲器地址的配置與外設地址的配置。

對DMA通道x存儲器地址寄存器(DMA_CMARx)進行賦值,從而配置存儲器地址,存儲器地址可作為數據傳輸的源或目標。

對DMA通道x外設地址寄存器(DMA_CPARx)進行賦值,從而配置外設地址,外設地址是外設數據寄存器的基地址,作為數據傳輸的源或目標。

源和目標地址必須根據各自配置的數據傳輸寬度對齊。

指針增量

指針增量配置:每次傳輸后指針自動向后遞增或保持不變。

操作DMA通道x配置寄存器(DMA_CCRx)的MINC位,若MINC位置1,則DMA配置為存儲器地址遞增模式,存儲器的訪問地址可以按照步長累加,不需要每次都去設置訪問地址;若MINC位置0,則每次DMA傳輸固定訪問同一個地址。

設置DMA通道x配置寄存器(DMA_CCRx)的PINC位,若PINC位置1,則DMA配置為外設地址遞增模式,外設的訪問地址可以按照步長累加;若PINC位置0,則每次DMA傳輸固定訪問同一個地址。

外設或存儲器配置為增量模式時,下一個要傳輸的地址將是前一個地址加上步長,步長取決于所選的數據寬度,首個傳輸的地址存放在DMA通道x外設地址寄存器(DMA_CPARx)/DMA通道x存儲器地址寄存器(DMA_CMARx)中。

優先級

仲裁器根據通道請求的優先級來啟動外設或存儲器的訪問,優先處理軟件優先級高的請求,當軟件優先級相同時,默認編號更低的通道優先處理。每個通道的優先級可在DMA通道x配置寄存器(DMA_CCRx)中的PL位配置,優先級分為四種:最高優先級(PL[1:0]=11)、高優先級(PL[1:0]=10)、中等優先級(PL[1:0]=01)與低優先級(PL[1:0]=00)。

數據傳輸數量

數據傳輸數量的最大值為65535,將數據傳輸數量值賦值到DMA通道x傳輸數量寄存器(DMA_CNDTRx),每次傳輸后,DMA_CNDTRx遞減,表示剩余多少次DMA傳輸。

當數值遞減為0時,數據全部傳輸完畢。若對應通道配置為自動重加載模式時,DMA_CNDTRx寄存器中的內容將被自動重新加載為之前配置時的數值。

中斷

每個通道支持3種事件標志:DMA半傳輸(HTIF)、DMA傳輸完成(TCIF)和DMA傳輸出錯(TEIF),各通道單獨的中斷請求由這3種事件標志邏輯或起來。可通過配置DMA通道x配置寄存器(DMA_CCRx)的TCIE位為1使能傳輸完成中斷,配置HTIE位為1使能半傳輸中斷,配置TEIE位為1使能傳輸錯誤中斷。

實驗

本實驗演示DMA burst搬運模式的中斷行為,配置DMA的傳輸模式為存儲器到存儲器模式且傳輸方向為從存儲器讀,開啟自動重裝載,寬度配置為全字,指針遞增,優先級為低優先級,設置兩數組為DMA數據傳輸地址,配置傳輸數量為16。DMA配置完成后,進行DMA數據傳輸,使能DMA通道,當產生半傳輸中斷,設置半傳輸標志為true,當產生傳輸完成中斷,設置傳輸完成標志為true,清除中斷標志位。本實驗可通過串口調試工具觀察數據傳輸現象,當DMA傳輸已到一半時串口打印"half",當DMA傳輸完成時串口打印"done"。

啟用外設時鐘 enable_clock()

實驗使用DMA1,并通過UART串口顯示實驗結果,因此需要啟用DMA與UART的外設時鐘。

void enable_clock()
{
    /* Enable UART1 clock. */
    RCC->APB2ENR |= RCC_APB2_PERIPH_UART1;
    /* Enable GPIOA clock. */
    RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA;
    /* Enable DMA1 clock. */
    RCC->AHB1ENR |= RCC_AHB1_PERIPH_DMA1;
}

配置引腳 pin_init()

實驗現象通過串口顯示,因此配置UART的TX(PA9)與RX(PA10)引腳。

void pin_init()
{
    /* Setup PA9, PA10. */
    GPIOA->CRH  = ~GPIO_CRH_MODE9_MASK;
    GPIOA->CRH |= GPIO_PinMode_AF_PushPull;     /* 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;     /* 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;
}

DMA初始化 dma_init()

操作DMA_CCRx寄存器,配置輸出傳輸模式、傳輸方向、外設和存儲器的增量模式、外設和存儲器的數據寬度、通道優先級和指針增量;操作DMA_CNDTRx寄存器,配置DMA傳輸數量,DMA傳輸完成一次,該數值減1,且在DMA傳輸期間DMA_CNDTRx寄存器不可被寫入;操作DMA_CPARx寄存器,配置外設寄存器地址,由于本實驗配置DMA傳輸方向為從存儲器讀,因此該外設地址在DMA傳輸時作為目標地址;操作DMA_CMARx寄存器,配置數據存儲器的地址,DMA傳輸時從該存儲器地址加載數據。

void dma_init()
{
    uint32_t ccr = 0u;
    ccr |= DMA_CCR_DIR_MASK;  /* Data transmission direction is: read from memory. */
         | DMA_CCR_MEM2MEM_MASK;  /* Xfer mode: memory to memory. */
         | DMA_CCR_ARE_MASK;   /* Enable automatic reloading. */
         | DMA_CCR_PINC(DMA_AddrIncMode_IncAfterXfer)  /* DMA_AddrIncMode_IncAfterXfer=1u, peripheral increment mode. */
         | DMA_CCR_MINC(DMA_AddrIncMode_IncAfterXfer)  /* Memory increment mode. */
         | DMA_CCR_PSIZE(DMA_XferWidth_32b)  /* DMA_XferWidth_32b = 2u, peripheral size 32 bits. */
         | DMA_CCR_MSIZE(DMA_XferWidth_32b)  /* Memory size 32 bits. */
         | DMA_CCR_PL(DMA_Priority_Low)  /* DMA_Priority_Low = 0u, low priority. */
         ;
    DMA1->CH[0].CCR = ccr;  /* channel number = 0 refer to DMA1_CH1. */
    DMA1->CH[0].CNDTR = DMA_BUFF_COUNT;  /* DMA_BUFF_COUNT = 16u, data transmission quantity. */
    DMA1->CH[0].CPAR = (uint32_t)app_dma_buff_to;  /* Set arry app_dma_buff_to as peripheral address. */
    DMA1->CH[0].CMAR = (uint32_t)app_dma_buff_from;  /* Set arry app_dma_buff_from as memory address. */
}

使能DMA enable_dma()

操作DMA_CCRx寄存器的ENABLE位,使能通道1,在通道使能后可進行DMA傳輸。

void enable_dma()
{
    DMA1->CH[0].CCR |= DMA_CCR_EN_MASK;  /* Enable DMA1 channel 1. */
}

使能中斷 enable_interrupt()

操作DMA_CCRx寄存器的TCIE位置1,使能傳輸完成中斷;HTIE位置1,使能半傳輸中斷。

void enable_interrupt()
{
    DMA1->CH[0].CCR |= (DMA_CHN_INT_XFER_HALF_DONE   0xEu);  /* DMA half transfer interrupt. */
    DMA1->CH[0].CCR |= (DMA_CHN_INT_XFER_DONE   0xEu);  /* DMA end of transfer interrupt. */
}

配置NVIC NVIC_EnableIRQ()

使用Cortex-M0 core_cm0.h頭文件中的NVIC_EnableIRQ使能中斷,由于DMA初始化時配置使用通道1,因此使用DMA1通道1全局中斷DMA1_CH1_IRQn.

NVIC_EnableIRQ(DMA1_CH1_IRQn)

編寫中斷服務程序DMA1_CH1_IRQHandler()

讀DMA中斷狀態寄存器(DMA_ISR)獲取當前中斷狀態,當產生半傳輸中斷,令定義的半傳輸標志app_dma_xfer_half_done為true;當產生傳輸完成中斷,令定義的傳輸完成標志app_dma_xfer_done為true。操作DMA中斷標志清除寄存器(DMA_IFCR)對應位置1,清除對應中斷。

void DMA1_CH1_IRQHandler()
{
    uint32_t flags = DMA1->ISR   0xFu;

    if (flags   DMA_CHN_INT_XFER_HALF_DONE)  /* DMA half transfer interrupt. */
    {
        app_dma_xfer_half_done = true;
    }

    if (flags   DMA_CHN_INT_XFER_DONE)  /* DMA end of transfer interrupt. */
    {
        app_dma_xfer_done = true;
    }

    DMA1->IFCR = (flag   0xFu);  /* Clear interrupt. */
}

main()函數

main()函數結合上述操作,初始化DMA,設置變量app_dma_xfer_done為傳輸完成標志,設置變量app_dma_xfer_half_done為DMA已傳輸一半的標志,設置數組app_dma_buff_from[]為源,即DMA傳輸時從該存儲器地址加載數據,設置數組app_dma_buff_to[]為數據存儲地址,設置變量DMA_BUFF_COUNT為數據傳輸數量,傳輸數量為16,每次傳輸后,該數值遞減,當數值遞減為0時,數據傳輸完畢,配置自動重加載模式,數據傳輸數量會被自動重新加載為之前配置時的數值。當檢測到半傳輸中斷標志產生,串口打印"half",檢測到傳輸完成中斷標志產生,串口打印"done"。本實驗在串口輸入數據時進行DMA傳輸,將源地址app_dma_buff_from[]中的數據通過DMA傳輸到app_dma_buff_to[]地址中。實驗現象如圖3所示。

int main()
{
    uint8_t c;

    enable_clock();
    pin_init();
    uart_init();

    printf("rndma_burst_interrupt example.rn");

    dma_init();
    NVIC_EnableIRQ(DMA1_CH1_IRQn);
    enable_interrupt();

    for (uint32_t i = 0u; i < DMA_BUFF_COUNT; i++)
    {
        app_dma_buff_from[i] = i;
        app_dma_buff_to[i] = 0u;
    }

    while (1)
    {
        c = getchar();
        putchar(c);

        for (uint32_t i = 0u; i < DMA_BUFF_COUNT; i++)
        {
            app_dma_buff_to[i] = 0u;
        }
        app_dma_xfer_done = false;
        app_dma_xfer_half_done = false;

        enable_dma();

        while (!app_dma_xfer_half_done)
        {}
        printf("half.rn");
        app_dma_xfer_half_done = false;        

        while (!app_dma_xfer_done)
        {}
        printf("done.rn");
        app_dma_xfer_done = false;
    }
}

wKgZomUD7eCAUyx_AADBaK6JcXM006.png 圖3.實驗現象

審核編輯:彭菁

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

    關注

    38

    文章

    7452

    瀏覽量

    163598
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10824

    瀏覽量

    211136
  • dma
    dma
    +關注

    關注

    3

    文章

    559

    瀏覽量

    100420
收藏 人收藏

    評論

    相關推薦

    靈動微課堂 (第204講) | MM32F0140 DMA 學習筆記

    從一個地址空間復制到另一個地址空間,DMA在數據傳輸結束后將總線控制權交回CPU。MM32F0140內置5路通用DMA,可以管理設備到存儲器、存儲器到設備與存儲器到存儲器的數據傳輸,每個通道都有專門
    發表于 03-17 19:04

    MM32F0140 DMA學習筆記

    從一個地址空間復制到另一個地址空間,DMA在數據傳輸結束后將總線控制權交回CPU。MM32F0140內置5路通用DMA,可以管理設備到存儲器、存儲器到設備與存儲器到存儲器的數據傳輸,每個通道都有專門
    發表于 10-12 15:42

    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 ?722次閱讀
    基于<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 ?577次閱讀
    <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 ?587次閱讀
    <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 ?1424次閱讀
    <b class='flag-5'>MM32F0140</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>——FlexCAN 控制器局域網

    MM32F0140 SPI學習筆記

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

    MM32F0140 UART學習筆記

    MM32F0140 UART學習筆記
    的頭像 發表于 09-26 16:45 ?738次閱讀
    <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 ?529次閱讀
    <b class='flag-5'>MM32F0140</b> GPIO<b class='flag-5'>學習</b><b class='flag-5'>筆記</b>