您現在的位置是:首頁 > 網路遊戲首頁網路遊戲
stm32串列埠DMA方式傳送資料
- 2021-05-23
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手冊
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
本網站轉載的所有的文章、圖片、音訊影片檔案等資料的版權歸版權所有人所有,本站採用的非本站原創文章及圖片等內容無法一一聯絡確認版權者。如果本網所選內容的文章作者及編輯認為其作品不宜公開自由傳播,或不應無償使用,請及時透過電子郵件或電話通知我們,以迅速採取適當措施,避免給雙方造成不必要的經濟損失。