概述
本章主要配置printf進行打印。 查閱手冊可以得知,PA9、PA10為串口0的輸出和輸入口。需要GD樣片的可以加群申請:615061293。
硬件準備
這里準備了1塊開發板進行驗證,分別是GD32303C_START開發板。
DMA
DMA 控制器提供了一種硬件的方式在外設和存儲器之間或者存儲器和存儲器之間傳輸數據,而無需 CPU 的介入,從而使 CPU 可以專注在處理其他系統功能上。DMA 控制器有 12 個通道(DMA0 有 7 個通道,DMA1 有 5 個通道)。每個通道都是專門用來處理一個或多個外設的存儲器訪問請求的。DMA 控制器內部實現了一個仲裁器,用來仲裁多個 DMA 請求的優先級。 DMA 控制器和 Cortex?-M4 內核共享系統總線。當 DMA 和 CPU 訪問同樣的地址空間時,DMA 訪問可能會阻擋 CPU 訪問系統總線幾個總線周期。總線矩陣中實現了循環仲裁算法來分配 DMA 與 CPU 的訪問權,它可以確保 CPU 得到至少一半的系統總線帶寬。 主要特性:
- 傳輸數據長度可編程配置,最大到 65536;
- 12 個通道,并且每個通道都可配置(DMA0 有 7 個通道,DMA1 有 5 個通道);
- AHB 和 APB 外設,片上閃存和 SRAM 都可以作為訪問的源端和目的端;
- 每個通道連接固定的硬件 DMA 請求;
- 支持軟件優先級(低、中、高、極高)和硬件優先級(通道號越低,優先級越高);
- 存儲器和外設的數據傳輸寬度可配置:字節,半字,字;
- 存儲器和外設的數據傳輸支持固定尋址和增量式尋址;
- 支持循環傳輸模式;
- 支持外設到存儲器,存儲器到外設,存儲器到存儲器的數據傳輸;
- 每個通道有 3 種類型的事件標志和獨立的中斷;
- 支持中斷的使能和清除。
DMA0對應通道。
DMA1對應通道。
keil配置
microlib 進行了高度優化以使代碼變得很小。 它的功能比缺省 C 庫少,并且根本不具備某些 ISO C 特性。 某些庫函數的運行速度也比較慢,如果要使用printf(),必須開啟。
定義發送數據
#define ARRAYNUM(arr_nanme) (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
uint8_t txbuffer1[] = "
USART DMA transmit example
";
使能串口
/* 使能GPI0A,用PA9、PA10為串口 */
rcu_periph_clock_enable(RCU_GPIOA);
/*使能串口0的時鐘 */
rcu_periph_clock_enable(RCU_USART0);
/*配置USARTx_Tx(PA9)為復用推挽輸出*/
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
/*配置USARTx_RxPA9)為浮空輸入 */
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* USART 配置 */
usart_deinit(USART0);//重置串口0
usart_baudrate_set(USART0, 115200U);//設置串口0的波特率為115200
usart_word_length_set(USART0, USART_WL_8BIT); // 幀數據字長
usart_stop_bit_set(USART0, USART_STB_1BIT); // 停止位1位
usart_parity_config(USART0, USART_PM_NONE); // 無奇偶校驗位
usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能接收器
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能發送器
usart_enable(USART0);//使能USART
串口重定向
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
串口重定向后就可以使用printf進行打印。
發送DMA初始化
在DMA初始化的時候,可以將需要發送的數據填充在memory_addr中,注意需要填上長度number。
/*DMA初始化*/
dma_parameter_struct dma_init_struct;
// 時鐘開啟
rcu_periph_clock_enable(RCU_DMA0);
dma_deinit(DMA0, DMA_CH3);//dma寄存器初始化
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;//傳輸模式,存儲到外設(發送)
dma_init_struct.memory_addr = (uint32_t)txbuffer1;//dma內存地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //內存地址增量模式
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;//dma外設寬度8位
dma_init_struct.number = ARRAYNUM(txbuffer1)-1; //長度
dma_init_struct.periph_addr =(uint32_t)(&USART_DATA(USART0));//外設基地址( (uint32_t)USART_DATA(USART0) )
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外設地址增量禁用
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH; //優先級高
dma_init(DMA0, DMA_CH3 , &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH3);//循環模式禁用
dma_memory_to_memory_disable(DMA0, DMA_CH3);//通道3 USART0_TX
使能DMA發送
開啟DMA0_3通道,這個通道位串口0的TX。
/* enable USART0 DMA channel transmission and reception */
dma_channel_enable(DMA0, DMA_CH3);
/* USART DMA enable for transmission and reception */
usart_dma_transmit_config(USART0, USART_DENT_ENABLE); //發送
/* wait until USART0 TX DMA0 channel transfer complete */
while(RESET == dma_flag_get(DMA0, DMA_CH3, DMA_INTF_FTFIF)){
}
dma_flag_get()函數說明
dma_flag_get()函數功能是獲取DMAx通道y標志位狀態。 主要的輸入參數有4個。
在GD303固件庫中,使用DMA_INTF_FTFIF和DMA_FLAG_FTF是一樣的。
DMA發送測試代碼
while(1)
{
uint8_t txbuffer22[] = "123456";
dma_channel_disable(DMA0, DMA_CH3);//使能DMA0_CH3
dma_flag_clear(DMA0, DMA_CH3, DMA_FLAG_FTF);//清除DMA通道傳輸完成標志
dma_memory_address_config(DMA0, DMA_CH3, (uint32_t)txbuffer22);//配置存儲器基地址
dma_transfer_number_config(DMA0, DMA_CH3, ARRAYNUM(txbuffer22)-1);
dma_channel_enable(DMA0, DMA_CH3);
/* wait until USART0 TX DMA0 channel transfer complete */
while(RESET == dma_flag_get(DMA0, DMA_CH3, DMA_INTF_FTFIF)){
}
delay_1ms(1000);
}
DMA發送測試結果
DMA循環發送
修改代碼。
dma_circulation_disable(DMA0, DMA_CH3);
修改為。
dma_circulation_enable(DMA0, DMA_CH3);
結果如下。
定義接收數組
/* DMA接收緩沖區 */
uint8_t dma_buffer[10];
/* 待處理數據個數:大于1為有數據待處理,0為沒有數據待處理*/
uint32_t USART_RX_NUM = 0;
接收DMA初始化
在DMA初始化的時候,可以將需要接收的數據填充在memory_addr中,注意需要填上長度number。
/* USART0 DMA 接收配置*/
dma_deinit(DMA0, DMA_CH4);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; /* 外設到內存 */
dma_init_struct.memory_addr = (uint32_t)dma_buffer; /* 設置內存接收基地址 */
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; /* 內存地址遞增 */
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; /* 8位內存數據 */
dma_init_struct.number = sizeof(dma_buffer);
dma_init_struct.periph_addr = ((uint32_t)0x40013804); /* 外設基地址,USART數據寄存器地址 */
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; /* 外設地址不遞增 */
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; /* 8位外設數據 */
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; /* 最高DMA通道優先級 */
dma_init(DMA0, DMA_CH4, &dma_init_struct); /* 按照結構體的配置初始化DMA */
dma_circulation_disable(DMA0, DMA_CH4); /* 關閉DMA循環模式 */
dma_memory_to_memory_disable(DMA0, DMA_CH4); /* DMA內存到內存模式不開啟 */
dma_channel_enable(DMA0, DMA_CH4); /* 使能DMA傳輸 */
usart_dma_receive_config(USART0, USART_DENR_ENABLE); /* USART0 DMA接收模式開啟 */
使能串口空閑中斷
當接收完數據之后,會進入空閑中斷。
nvic_irq_enable(USART0_IRQn, 0, 0); /* USART中斷設置,搶占優先級0,子優先級0 */
usart_interrupt_enable(USART0, USART_INT_IDLE); /* 使能USART0空閑中斷 */
USART0_IRQHandler()函數
定義串口的中斷服務函數,當DMA接收完畢會進入。
/* 串口0中斷服務程序 */
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) //空閑中斷
{
usart_interrupt_flag_clear(USART0,USART_INT_FLAG_IDLE); /* 清除空閑中斷標志位 */
usart_data_receive(USART0); /* 清除接收完成標志位 */
dma_channel_disable(DMA0, DMA_CH4); /* 關閉DMA傳輸 */
USART_RX_NUM = sizeof(dma_buffer) - dma_transfer_number_get(DMA0,DMA_CH4);
printf("RECV %d date:%s
", USART_RX_NUM, dma_buffer);
memset(&dma_buffer ,'',sizeof(dma_buffer));
/* 重新設置DMA傳輸 */
dma_memory_address_config(DMA0,DMA_CH4,(uint32_t)dma_buffer);
dma_transfer_number_config(DMA0,DMA_CH4,sizeof(dma_buffer));
dma_channel_enable(DMA0, DMA_CH4); /* 開啟DMA傳輸 */
}
}
DMA接收測試結果
由于不是循環接收,當接收長度超過數組的長度,就會照成數據混亂。 解決辦法可以增加接受數組的長度或者設用循環接收,但是循環接收會覆蓋之前接收到的數據。
DMA循環接收
修改代碼。
dma_circulation_disable(DMA0, DMA_CH4);
修改為
dma_circulation_enable(DMA0, DMA_CH4);
結果如下。
審核編輯:湯梓紅
-
串口
+關注
關注
14文章
1586瀏覽量
78928 -
dma
+關注
關注
3文章
573瀏覽量
102404 -
USART
+關注
關注
1文章
200瀏覽量
31665 -
固件庫
+關注
關注
2文章
97瀏覽量
15210
發布評論請先 登錄
STM32CUBEMX開發GD32F303(9)----USART通過DMA收發

【GD32F303】星空派介紹
【星空派GD32F303開發板試用體驗】開箱+環境搭建
GD32F303固件庫開發(1)----前期準備與燒錄

GD32F303固件庫開發(3)----使用固件庫點亮LED

GD32F303固件庫開發(5)----GPIO輸出模式,速率測試、開漏和輸出說明

STM32CUBEMX開發GD32F303(11)----ADC在DMA模式下掃描多個通道

GD32F303固件庫開發(12)----輸出PWM及修改PWM頻率與占空比

【GD32F303紅楓派開發板使用手冊】第十六講 USART-DMA串口收發實驗

評論