您現在的位置是:首頁 > 網路遊戲首頁網路遊戲

stm32串列埠DMA方式傳送資料

簡介DMA_InitStructure

dma請求是什麼

DMA傳送資料

啟動DMA併發送完成後,產生DMA傳送完成中斷,在DMA中斷服務函式中執行以下操作:

在資料傳送緩衝區內放好要傳送的資料(此資料緩衝區的首地址必須要在DMA初始化時寫入到DMA配置中去)

將資料緩衝區內要傳送的資料位元組數傳給DMA通道(串列埠傳送和接收不是同一個通道)

開啟DMA,一旦開啟,則DMA開始傳送資料,

等待資料傳送完成標誌!

判斷資料傳送完成:

清DMA傳送完成標誌

關閉串列埠傳送DMA通道

給前臺(應用)程式設定一個軟體標誌位,說明資料傳送完成。

DMA接收資料串列埠接收DMA在初始化時就處於開啟狀態,一直等待資料的到來,串列埠中斷IDLE在串列埠一直沒有資料時,是不會產生的,產生的條件是:當清除IDLE標誌位後,必須有接收到第一個資料後才觸發,一旦接收的資料斷流,即產生IDLE中斷。這裡判斷接收資料完成是透過串列埠的空閒方式實現,即當串列埠的資料流停止後,就會產生IDLE中斷,在中斷裡做

關閉串列埠接收的DMA通道。一是防止又有資料接收到,產生干擾;二是便於DMA重新配置賦值。

清除DMA中斷標誌位

從DMA暫存器中獲取接收到的資料位元組數(對於上層應用很有必要)

重新設定DMA下次需要接收到的資料位元組數(必須大於預期的接收值長度,否則計數減到0時又會復位,覆蓋接收緩衝區中的資料,導致資料丟失!)

開啟DMA通道,等待下一次的資料接收

可以設定訊號量,通知應用程式資料接收完成,傳遞接收的資料長度,便於應用程式對資料的處理。

有待思考的!!! 此處的接收緩衝區時來自哪裡? uart1的資料緩衝區,還是DMA的接收資料緩衝區,最大支援多少個位元組???

!!! DMA傳送資料,網上也有看到將配置封裝在傳送函式中,如uart1_dma_send_data(uint8_t* buf, uint32_t len),這個好處是,可以變化mem地址(buf陣列,以及長度可以適當配置變化),不錯!

!!! DMA接收函式,應用DMA中斷判斷接收完成只能依賴於DMA配置中位元組長度,支援DMA傳輸完成,傳輸過半,傳輸錯誤,但對於不固定長度接收資料,this is a question。注意:

DMA外設和DMA通道有對應關係,需要參考stm32手冊

stm32串列埠DMA方式傳送資料

stm32串列埠DMA方式傳送資料

DMA傳輸資料時,需要明確傳輸的位元組數目

DMA使能情況下,不能配置傳輸位元組數到DMA暫存器,所以也不會產生DMA資料傳輸(因為傳輸位元組數目為0)

hal_uart_dma。c

#include “includes。h”

/*

DMA方式介紹:

DMA使用流程:

1。 配置

外設端:

-串列埠引腳GPIO配置

-串列埠功能引數配置(資料位格式,波特率等),此處還需要**配置對應的DMA請求允許**。

-如果有中斷,還需要配置中斷優先順序

DMA端:

-DMA功能配置

-初始化DMA通道DMA_Init(DMA1_Channel4,DMA_InitStructure);

。 DMA源(Memory)/目的(外設)地址

。 DMA的傳輸方向

。 DMA的buffer size

。 DMA外設(DISABLE)/Memory(ENABLE)地址自增使能配置

。 DMA傳輸位元組格式(支援byte,half-word,word)

。 DMA傳輸方式(Normal和Circle)

。 DMA傳輸優先順序(共有四種,)

。 DMA m2m使能/失能配置(此處不是用於m2m所以配置為DISABLE)

-清除中斷標誌位

-此處應DISABLE DMA通道,否則配置完成即會產生DMA資料傳輸(非期望資料)

-使能DMA傳送完成中斷

-DMA中斷服務函式

傳送資料完成後,即關閉DMA通道,傳送訊號量到應用程式

外設部分配置

2。 使能(使用)

應用程式需要傳送資料時:

-將要傳送的資料準備好,並且要知道傳送多少單位資料(傳送位元組數)

-配置DMA要傳送的位元組數,使能DMA即可。

*/

//#define DMA_USART1_DR_Base (USART1_BASE + 0x4) //0x40013804

#define DMA_USART1_DR_Base 0x40013804

//1。 串列埠1埠配置

void hal_debug_gpio_config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

//DBTX PA9 uart1_tx

GPIO_InitStructure。GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure。GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure。GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,GPIO_InitStructure);

//DBRX PA10 uart1_rx

GPIO_InitStructure。GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure。GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,GPIO_InitStructure);

}

//2。 串列埠功能配置

void hal_debug_func_config(void)

{

USART_InitTypeDef USART_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

USART_InitStructure。USART_BaudRate = 115200;

USART_InitStructure。USART_WordLength = USART_WordLength_8b;

USART_InitStructure。USART_StopBits = USART_StopBits_1;

USART_InitStructure。USART_Parity = USART_Parity_No;

USART_InitStructure。USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_InitStructure。USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_Init(USART1,USART_InitStructure);

//config uart DMA request

USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//enable usart1 dma send request

USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //enable usart1 dma recieve request

USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //enable usart1 idle interrupt

USART_Cmd(USART1,ENABLE);

}

//

void hal_debug_nvic_config(void){

NVIC_InitTypeDef NVIC_InitStructure;

//uart1 interrupt

NVIC_InitStructure。NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure。NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure。NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure。NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(NVIC_InitStructure);

//dma interrupt

NVIC_InitStructure。NVIC_IRQChannel = DMA1_Channel4_IRQn; //

NVIC_InitStructure。NVIC_IRQChannelPreemptionPriority = 2; //

NVIC_InitStructure。NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure。NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(NVIC_InitStructure);

}

//3。 串列埠初始化

void hal_debug_init(void)

{

hal_debug_gpio_config();

hal_debug_func_config();

hal_debug_nvic_config();

}

//////////////////////DMA config/////////////////////////////////

//1。 uart dma configs

void uart_dma_init(void){

DMA_InitTypeDef DMA_InitStructure;

//Tx DMA CONFIG

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //enable DMA1 clock

DMA_Cmd(DMA1_Channel4,DISABLE); //close DMA Channel

DMA_DeInit(DMA1_Channel4);

DMA_InitStructure。DMA_PeripheralBaseAddr = DMA_USART1_DR_Base; //(uint32_t)(USART1->DR)

DMA_InitStructure。DMA_MemoryBaseAddr = (uint32_t)USART1_Tx_Buf;

DMA_InitStructure。DMA_DIR = DMA_DIR_PeripheralDST;

DMA_InitStructure。DMA_BufferSize = USART1_TX_BSIZE;

DMA_InitStructure。DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure。DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure。DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure。DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure。DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure。DMA_Priority = DMA_Priority_VeryHigh;

DMA_InitStructure。DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel4,DMA_InitStructure);

DMA_ClearFlag(DMA1_FLAG_GL4); // clear all DMA flags

//DMA_Cmd(DMA1_Channel4,ENABLE); // close DMA Channel

DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //open DMA send inttrupt

//Rx DMA CONFIG

DMA_Cmd(DMA1_Channel5, DISABLE); //

DMA_DeInit(DMA1_Channel5);

DMA_InitStructure。DMA_PeripheralBaseAddr = (uint32_t)(USART1->DR);

DMA_InitStructure。DMA_MemoryBaseAddr = (uint32_t)USART1_Rx_Buf;

DMA_InitStructure。DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure。DMA_BufferSize = USART1_RX_BSIZE;

DMA_InitStructure。DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure。DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure。DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure。DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure。DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure。DMA_Priority = DMA_Priority_VeryHigh;

DMA_InitStructure。DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5, DMA_InitStructure);

DMA_ClearFlag(DMA1_FLAG_GL5);

DMA_Cmd(DMA1_Channel5, ENABLE);

}

///////////////////////uart dma send//////////////////////

void DMA1_Channel4_IRQHandler(void)

{

if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)

{

DMA_ClearFlag(DMA1_FLAG_GL4);

DMA_Cmd(DMA1_Channel4, DISABLE);

OSMboxPost(mbLumModule_Tx, (void*)1);

}

}

void uart_dma_send_enable(uint16_t size)

{

DMA1_Channel4->CNDTR = (uint16_t)size;

DMA_Cmd(DMA1_Channel4, ENABLE);

}

void uart1_dma_send_data(void)

{

uint8_t err;

uint16_t i;

uint16_t USART1_Tx_Index=0;

for(i=0;i

USART1_Tx_Buf[USART1_Tx_Index++]=i;

}

uart_dma_send_enable(USART1_Tx_Index);

OSMboxPend(mbLumModule_Tx, 5000, err);

}

///////////////////////uart dma send//////////////////////

///////////////////////uart dma recv//////////////////////

void uart1_dma_recv_data(void)

{

uint16_t index = 0;

DMA_Cmd(DMA1_Channel5, DISABLE);

DMA_ClearFlag(DMA1_FLAG_GL5);

//index = USART1_RX_BSIZE - DMA_GetCurrDataCounter(DMA1_Channel5);

DMA1_Channel5->CNDTR = USART1_RX_BSIZE;

DMA_Cmd(DMA1_Channel5, ENABLE);

//OSMboxPost(mbLumModule_Rx,USART1_Rx_Buf);

}

void USART1_IRQHandler(void)

{

if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)

{

uart1_dma_recv_data();

USART_ClearITPendingBit(USART1,USART_IT_IDLE);

}

}

///////////////////////uart dma recv//////////////////////

2。 app_test。c

該檔案為app_test執行緒,用於1s傳送一次串列埠資料,其中傳送串列埠資料中應用了訊號量,如果沒有等待到訊號量,最大等待時間為5s(加上此處的1s週期則為6s)。

#include “includes。h”

OS_STK gTest[APP_TEST_STK_SIZE];

uint8_t USART1_Tx_Buf[USART1_TX_BSIZE] = {0};

OS_EVENT *gSemEvent1 = NULL;

OS_EVENT *mbLumModule_Tx = NULL;

void app_test(void* p_arg){

(void)p_arg;

//create new event

gSemEvent1 = OSSemCreate(2);

mbLumModule_Tx = OSMboxCreate((void*)0);

while(1){

//OSSemPost(gSemEvent1);

OSTimeDly(1000);

//printf(“hello world!\r\n”);

uart1_dma_send_data();

}

}

ucos_main。c

該函式用於建立ucos任務,一個main函式,一個建立任務的任務函式。

其中app_test任務就是這邊uart DMA傳送資料的任務。

#include “includes。h”

/*

1。 主函式

用於啟動ucos-ii作業系統,啟動第一個啟動任務

2。 啟動任務啟動其他的任務

*/

static OS_STK gTaskStartStk[APP_TASK_START_STK_SIZE]; //定義棧

static void App_TaskStart(void *p_arg);

static void app_task_create (void);

//1。 main

int main(void){

INT8U os_err;

OSInit();

os_err = OSTaskCreateExt((void (*)(void *)) App_TaskStart, /* Create the start task。 */

(void * ) 0,

(OS_STK * )gTaskStartStk[APP_TASK_START_STK_SIZE - 1],

(INT8U ) APP_TASK_START_PRIO,

(INT16U ) APP_TASK_START_PRIO,

(OS_STK * )gTaskStartStk[0],

(INT32U ) APP_TASK_START_STK_SIZE,

(void * )0,

(INT16U )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));

#if (OS_TASK_NAME_SIZE >= 11)

OSTaskNameSet(APP_TASK_START_PRIO, (INT8U *)“Start Task”, os_err);

#endif

OSStart();

}

//2。 start task

static void App_TaskStart(void *p_arg)

{

(void)p_arg;

/*hal init*/

hal_dirvers_init();

//printf(“uCos-II V2。86 FM。\r\n”);

#if (OS_TASK_STAT_EN > 0)

OSStatInit(); /* Determine CPU capacity。*/

#endif

//printf(“Create App Task。\r\n”);

/*creat other app*/

app_task_create();

while(1){

OSTimeDly(1000);

hal_led_toggle(1); //led_toggle

}

}

/*

Create APP Task

*/

static void app_task_create (void){

INT8U os_err;

//test task

os_err = OSTaskCreate(app_test,

(void *)0,

gTest[APP_TEST_STK_SIZE-1],

APP_TEST_PRIO);

#if (OS_TASK_NAME_SIZE >= 20)

OSTaskNameSet(APP_TEST_PRIO, (INT8U *)“test task”, os_err);

#endif

//led toggle task

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

os_err = OSTaskCreate((void (*)(void *))app_led_toggle,

(void*)0,

(OS_STK*)gTaskLedToggle[APP_TASK_LED_STK_SIZE-1],

(INT8U)APP_TASK_LED_PRIO

);

#if (OS_TASK_NAME_SIZE >= 20)

OSTaskNameSet(APP_TASK_LED_PRIO, (INT8U *)“led_toggle”, os_err);

#endif

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

#if 0

//task 1

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

os_err = OSTaskCreate(app_task1,

(void*)0,

gTask1[APP_TASK1_STK_SIZE-1],

APP_TASK1_PRIO);

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

//task 2

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

os_err = OSTaskCreate(app_task2,

(void*)0,

gTask2[APP_TASK2_STK_SIZE-1],

APP_TASK2_PRIO);

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

//task 3

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

os_err = OSTaskCreate(app_task3,

(void*)0,

gTask3[APP_TASK3_STK_SIZE-1],

APP_TASK3_PRIO);

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

#endif

}

關鍵字:

stm32串列埠DMA方式傳送資料

編輯:什麼魚 引用地址:http://news。eeworld。com。cn/mcu/2018/ic-news090941198。html

本網站轉載的所有的文章、圖片、音訊影片檔案等資料的版權歸版權所有人所有,本站採用的非本站原創文章及圖片等內容無法一一聯絡確認版權者。如果本網所選內容的文章作者及編輯認為其作品不宜公開自由傳播,或不應無償使用,請及時透過電子郵件或電話通知我們,以迅速採取適當措施,避免給雙方造成不必要的經濟損失。

Top