概述
本章主要配置printf進(jìn)行打印。 查閱手冊(cè)可以得知,PA9、PA10為串口0的輸出和輸入口。需要GD樣片的可以加群申請(qǐng):615061293。
硬件準(zhǔn)備
這里準(zhǔn)備了1塊開(kāi)發(fā)板進(jìn)行驗(yàn)證,分別是GD32303C_START開(kāi)發(fā)板。
DMA
DMA 控制器提供了一種硬件的方式在外設(shè)和存儲(chǔ)器之間或者存儲(chǔ)器和存儲(chǔ)器之間傳輸數(shù)據(jù),而無(wú)需 CPU 的介入,從而使 CPU 可以專注在處理其他系統(tǒng)功能上。DMA 控制器有 12 個(gè)通道(DMA0 有 7 個(gè)通道,DMA1 有 5 個(gè)通道)。每個(gè)通道都是專門用來(lái)處理一個(gè)或多個(gè)外設(shè)的存儲(chǔ)器訪問(wèn)請(qǐng)求的。DMA 控制器內(nèi)部實(shí)現(xiàn)了一個(gè)仲裁器,用來(lái)仲裁多個(gè) DMA 請(qǐng)求的優(yōu)先級(jí)。 DMA 控制器和 Cortex?-M4 內(nèi)核共享系統(tǒng)總線。當(dāng) DMA 和 CPU 訪問(wèn)同樣的地址空間時(shí),DMA 訪問(wèn)可能會(huì)阻擋 CPU 訪問(wèn)系統(tǒng)總線幾個(gè)總線周期??偩€矩陣中實(shí)現(xiàn)了循環(huán)仲裁算法來(lái)分配 DMA 與 CPU 的訪問(wèn)權(quán),它可以確保 CPU 得到至少一半的系統(tǒng)總線帶寬。 主要特性:
- 傳輸數(shù)據(jù)長(zhǎng)度可編程配置,最大到 65536;
- 12 個(gè)通道,并且每個(gè)通道都可配置(DMA0 有 7 個(gè)通道,DMA1 有 5 個(gè)通道);
- AHB 和 APB 外設(shè),片上閃存和 SRAM 都可以作為訪問(wèn)的源端和目的端;
- 每個(gè)通道連接固定的硬件 DMA 請(qǐng)求;
- 支持軟件優(yōu)先級(jí)(低、中、高、極高)和硬件優(yōu)先級(jí)(通道號(hào)越低,優(yōu)先級(jí)越高);
- 存儲(chǔ)器和外設(shè)的數(shù)據(jù)傳輸寬度可配置:字節(jié),半字,字;
- 存儲(chǔ)器和外設(shè)的數(shù)據(jù)傳輸支持固定尋址和增量式尋址;
- 支持循環(huán)傳輸模式;
- 支持外設(shè)到存儲(chǔ)器,存儲(chǔ)器到外設(shè),存儲(chǔ)器到存儲(chǔ)器的數(shù)據(jù)傳輸;
- 每個(gè)通道有 3 種類型的事件標(biāo)志和獨(dú)立的中斷;
- 支持中斷的使能和清除。
DMA0對(duì)應(yīng)通道。
DMA1對(duì)應(yīng)通道。
keil配置
microlib 進(jìn)行了高度優(yōu)化以使代碼變得很小。 它的功能比缺省 C 庫(kù)少,并且根本不具備某些 ISO C 特性。 某些庫(kù)函數(shù)的運(yùn)行速度也比較慢,如果要使用printf(),必須開(kāi)啟。
定義發(fā)送數(shù)據(jù)
#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的時(shí)鐘 */
rcu_periph_clock_enable(RCU_USART0);
/*配置USARTx_Tx(PA9)為復(fù)用推挽輸出*/
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);//設(shè)置串口0的波特率為115200
usart_word_length_set(USART0, USART_WL_8BIT); // 幀數(shù)據(jù)字長(zhǎng)
usart_stop_bit_set(USART0, USART_STB_1BIT); // 停止位1位
usart_parity_config(USART0, USART_PM_NONE); // 無(wú)奇偶校驗(yàn)位
usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能接收器
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能發(fā)送器
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進(jìn)行打印。
發(fā)送DMA初始化
在DMA初始化的時(shí)候,可以將需要發(fā)送的數(shù)據(jù)填充在memory_addr中,注意需要填上長(zhǎng)度number。
/*DMA初始化*/
dma_parameter_struct dma_init_struct;
// 時(shí)鐘開(kāi)啟
rcu_periph_clock_enable(RCU_DMA0);
dma_deinit(DMA0, DMA_CH3);//dma寄存器初始化
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;//傳輸模式,存儲(chǔ)到外設(shè)(發(fā)送)
dma_init_struct.memory_addr = (uint32_t)txbuffer1;//dma內(nèi)存地址
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //內(nèi)存地址增量模式
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;//dma外設(shè)寬度8位
dma_init_struct.number = ARRAYNUM(txbuffer1)-1; //長(zhǎng)度
dma_init_struct.periph_addr =(uint32_t)(&USART_DATA(USART0));//外設(shè)基地址( (uint32_t)USART_DATA(USART0) )
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外設(shè)地址增量禁用
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH; //優(yōu)先級(jí)高
dma_init(DMA0, DMA_CH3 , &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH3);//循環(huán)模式禁用
dma_memory_to_memory_disable(DMA0, DMA_CH3);//通道3 USART0_TX
使能DMA發(fā)送
開(kāi)啟DMA0_3通道,這個(gè)通道位串口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); //發(fā)送
/* wait until USART0 TX DMA0 channel transfer complete */
while(RESET == dma_flag_get(DMA0, DMA_CH3, DMA_INTF_FTFIF)){
}
dma_flag_get()函數(shù)說(shuō)明
dma_flag_get()函數(shù)功能是獲取DMAx通道y標(biāo)志位狀態(tài)。 主要的輸入參數(shù)有4個(gè)。
在GD303固件庫(kù)中,使用DMA_INTF_FTFIF和DMA_FLAG_FTF是一樣的。
DMA發(fā)送測(cè)試代碼
while(1)
{
uint8_t txbuffer22[] = "123456";
dma_channel_disable(DMA0, DMA_CH3);//使能DMA0_CH3
dma_flag_clear(DMA0, DMA_CH3, DMA_FLAG_FTF);//清除DMA通道傳輸完成標(biāo)志
dma_memory_address_config(DMA0, DMA_CH3, (uint32_t)txbuffer22);//配置存儲(chǔ)器基地址
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發(fā)送測(cè)試結(jié)果
DMA循環(huán)發(fā)送
修改代碼。
dma_circulation_disable(DMA0, DMA_CH3);
修改為。
dma_circulation_enable(DMA0, DMA_CH3);
結(jié)果如下。
定義接收數(shù)組
/* DMA接收緩沖區(qū) */
uint8_t dma_buffer[10];
/* 待處理數(shù)據(jù)個(gè)數(shù):大于1為有數(shù)據(jù)待處理,0為沒(méi)有數(shù)據(jù)待處理*/
uint32_t USART_RX_NUM = 0;
接收DMA初始化
在DMA初始化的時(shí)候,可以將需要接收的數(shù)據(jù)填充在memory_addr中,注意需要填上長(zhǎng)度number。
/* USART0 DMA 接收配置*/
dma_deinit(DMA0, DMA_CH4);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; /* 外設(shè)到內(nèi)存 */
dma_init_struct.memory_addr = (uint32_t)dma_buffer; /* 設(shè)置內(nèi)存接收基地址 */
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; /* 內(nèi)存地址遞增 */
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; /* 8位內(nèi)存數(shù)據(jù) */
dma_init_struct.number = sizeof(dma_buffer);
dma_init_struct.periph_addr = ((uint32_t)0x40013804); /* 外設(shè)基地址,USART數(shù)據(jù)寄存器地址 */
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; /* 外設(shè)地址不遞增 */
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; /* 8位外設(shè)數(shù)據(jù) */
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; /* 最高DMA通道優(yōu)先級(jí) */
dma_init(DMA0, DMA_CH4, &dma_init_struct); /* 按照結(jié)構(gòu)體的配置初始化DMA */
dma_circulation_disable(DMA0, DMA_CH4); /* 關(guān)閉DMA循環(huán)模式 */
dma_memory_to_memory_disable(DMA0, DMA_CH4); /* DMA內(nèi)存到內(nèi)存模式不開(kāi)啟 */
dma_channel_enable(DMA0, DMA_CH4); /* 使能DMA傳輸 */
usart_dma_receive_config(USART0, USART_DENR_ENABLE); /* USART0 DMA接收模式開(kāi)啟 */
使能串口空閑中斷
當(dāng)接收完數(shù)據(jù)之后,會(huì)進(jìn)入空閑中斷。
nvic_irq_enable(USART0_IRQn, 0, 0); /* USART中斷設(shè)置,搶占優(yōu)先級(jí)0,子優(yōu)先級(jí)0 */
usart_interrupt_enable(USART0, USART_INT_IDLE); /* 使能USART0空閑中斷 */
USART0_IRQHandler()函數(shù)
定義串口的中斷服務(wù)函數(shù),當(dāng)DMA接收完畢會(huì)進(jìn)入。
/* 串口0中斷服務(wù)程序 */
void USART0_IRQHandler(void)
{
if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) //空閑中斷
{
usart_interrupt_flag_clear(USART0,USART_INT_FLAG_IDLE); /* 清除空閑中斷標(biāo)志位 */
usart_data_receive(USART0); /* 清除接收完成標(biāo)志位 */
dma_channel_disable(DMA0, DMA_CH4); /* 關(guān)閉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));
/* 重新設(shè)置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); /* 開(kāi)啟DMA傳輸 */
}
}
DMA接收測(cè)試結(jié)果
由于不是循環(huán)接收,當(dāng)接收長(zhǎng)度超過(guò)數(shù)組的長(zhǎng)度,就會(huì)照成數(shù)據(jù)混亂。 解決辦法可以增加接受數(shù)組的長(zhǎng)度或者設(shè)用循環(huán)接收,但是循環(huán)接收會(huì)覆蓋之前接收到的數(shù)據(jù)。
DMA循環(huán)接收
修改代碼。
dma_circulation_disable(DMA0, DMA_CH4);
修改為
dma_circulation_enable(DMA0, DMA_CH4);
結(jié)果如下。
審核編輯:湯梓紅
-
串口
+關(guān)注
關(guān)注
14文章
1540瀏覽量
76080 -
dma
+關(guān)注
關(guān)注
3文章
558瀏覽量
100367 -
USART
+關(guān)注
關(guān)注
1文章
195瀏覽量
30768 -
固件庫(kù)
+關(guān)注
關(guān)注
2文章
97瀏覽量
14918
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論