直接存儲器訪問(DMA,Direct Memory Access)的優(yōu)點
· 提高系統(tǒng)效率:通過繞過CPU,DMA顯著減少了數(shù)據(jù)傳輸對CPU資源的占用,使得CPU能夠專注于其他計算任務,提升了系統(tǒng)整體的響應速度和處理能力。
·加快數(shù)據(jù)傳輸速度:針對多總線高性能MCU,DMA可以避免不同總線同步問題,提供更高的數(shù)據(jù)傳輸速率。
·降低系統(tǒng)延遲:由于減少了CPU參與數(shù)據(jù)搬運的環(huán)節(jié),系統(tǒng)延遲顯著降低,這對于實時系統(tǒng)和高性能計算應用至關重要,確保了數(shù)據(jù)的即時處理和反饋。
·簡化軟件設計:DMA控制器的硬件自動化處理降低了軟件層面對數(shù)據(jù)傳輸?shù)膹碗s管理,使得軟件設計更為簡潔,降低了開發(fā)難度和維護成本。
先楫產品中,有大量支持DMA的設備,其中USB、Ethernet、ADC、DAC等有自己的內部DMA,AHB和AXI總線上還有公共的DMA設備——HDMA、XDMA。
HDMA、XDMA都是多通道DMA,可以通過DMAMUX實現(xiàn)多通道的數(shù)據(jù)傳輸。
HDMA、XDMA分別接入AHB和AXI總線,在總線內部傳輸效率更高,可以支持8-64bit數(shù)據(jù)寬度的傳輸。
本文將通過兩個應用案例,說明DMA在如何在實時控制中提高系統(tǒng)的穩(wěn)定性和實時性。
DMA準確控制
下圖是典型伺服三環(huán)的控制框圖,其中編碼器是控制的關鍵反饋,除了準確讀取位置之外,還需要通過不同時刻讀取位置計算轉速。讀取位置的時刻在伺服閉環(huán)中占非常關鍵的作用。
常見位置讀取方式是在定時中斷中讀取位置,確保讀取間隔時刻一致。但由于軟件響應時間不確定,讀取間隔很難保證一致。
本文通過DMA+鏈表方式實現(xiàn)HPM6200用串口與多摩川編碼器定時通訊的方式。多摩川編碼器通訊協(xié)議見下圖:
例程通過PWM定期觸發(fā)DMA,由DMA啟動串口讀取動作。DMA動作完成后利用鏈式傳輸,可以在處理器不介入的情況下,連續(xù)完成多個不同配置的傳輸任務。
程序中使用了PWM、DMA、UART三個模塊
· PWM負責定時輸出DMA觸發(fā)信號;
· DMA接收觸發(fā)信號后將采樣命令寫入UART的THR寄存器;
· UART負責收發(fā)位置傳感器信息,其中接收建議使用硬件idle+FIFO模式。
先楫的UART有硬件收發(fā)使能控制,只需要DE設置為有效,485通訊可以自動實現(xiàn)收發(fā)方向控制,無須CPU干預。
HPMICRO
HPM6280集成了9個UART模塊:
除了常規(guī)配置之外,還支持硬件空閑中斷
支持16 字節(jié)的 TXFIFO 和 RXFIFO
硬件收發(fā)使能自動控制
通過簡單配置即可實現(xiàn)2.5Mbps通訊、RS485自動收發(fā)使能控制、硬件空閑中斷接收數(shù)據(jù)等功能。
void config_uart(void)
{
hpm_stat_t stat;
uart_config_t config = {0};
/* if TEST_UART is same as BOARD_CONSOLE_BASE, it has been initialized in board_init(); */
uart_default_config(HPM_UART7, &config);
config.baudrate = 2500000UL;
config.fifo_enable = true;
//config.dma_enable = true;
clock_set_source_divider(clock_uart7, clk_src_pll0_clk0, 5);//80Mhz
clock_add_to_group(clock_uart7, 0);
config.src_freq_in_hz = clock_get_frequency(clock_uart7);//clock_get_frequency(clock_uart0);
config.rx_fifo_level = uart_rx_fifo_trg_gt_three_quarters;/* this config should not change *///uart_rx_fifo_trg_not_empty;
config.rxidle_config.detect_enable = true;
config.rxidle_config.detect_irq_enable = true;
config.rxidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;
config.rxidle_config.threshold = 20U; /* 20bit */
stat = uart_init(HPM_UART7, &config);
if (stat != status_success) {
printf("failed to initialize uart\n");
}
//uart_enable_irq(HPM_UART0, uart_intr_rx_data_avail_or_timeout);
intc_m_enable_irq_with_priority(IRQn_UART7, 1);
}
HPMICRO
下面DMA配置啟用了鏈式傳輸,實現(xiàn)DMA循環(huán)觸發(fā)UART讀取位置信息。
構建兩個相互鏈接的 DMA 任務描述符列表。DMA控制器會在完成當前任務描述符的相應任務后,從 ChnLLPointer指向地址取下一個任務描述符。下一個任務描述符又關聯(lián)當前描述符,如此互鎖,無限循環(huán)。
描述符中DMA配置目標數(shù)據(jù)為握手模式,UART設備返回接收數(shù)據(jù)完畢信號。
為確保uart數(shù)據(jù)可以準確傳輸,DMA的高優(yōu)先級標志位要設置為1。
{
hpm_stat_t stat;
dma_channel_config_t rx_ch_config = { 0 };
dmamux_config(HPM_DMAMUX, ch_num, HPM_DMA_SRC_MOT0_0, true);
/* 1.1 config chain descriptors */
dma_default_channel_config(HPM_HDMA, &rx_ch_config);
rx_ch_config.src_addr = src;
rx_ch_config.src_width = DMA_TRANSFER_WIDTH_BYTE; /* In DMA handshake case, source width and destination width must be BYTE. */
rx_ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
rx_ch_config.src_mode = DMA_HANDSHAKE_MODE_NORMAL;
rx_ch_config.dst_addr = (uint32_t)&uart_ptr->THR;
rx_ch_config.dst_width = DMA_TRANSFER_WIDTH_BYTE; /* In DMA handshake case, source width and destination width must be BYTE. */
rx_ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
rx_ch_config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
rx_ch_config.size_in_byte = 1;
rx_ch_config.priority = 1;
rx_ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T; /* In DMA handshake case, source burst size must be 1 transfer, that is 0. */
rx_ch_config.linked_ptr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&descriptors[1]);//link to next dma action
stat = dma_config_linked_descriptor(HPM_HDMA, &descriptors[0], ch_num, &rx_ch_config);
if (stat != status_success) {
while (1) {
};
}
rx_ch_config.linked_ptr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&descriptors[0]);
stat = dma_config_linked_descriptor(HPM_HDMA, &descriptors[1], ch_num, &rx_ch_config);
if (stat != status_success) {
while (1) {
};
}
HPMICRO
在PWM中配置DMA定期觸發(fā),配置比較器匹配觸發(fā),配置DMA輸出使能。
互聯(lián)管理器TRGM是HPM MCU中非常有特色的外設,可以通過配置實現(xiàn)多個外設的輸入輸出相互連接,使得多個外設可以相互配合使用。
HPM6200中TRGM支持4個DMA 請求輸出,用戶可以配置TRGM,從多個DMA請求輸入中,選擇4個連接到 DMAMUX。本文選擇了PWM0的CMP14。
pwm_set_reload(HPM_PWM0, 0, reload);
pwm_set_start_count(HPM_PWM0, 0, 0);
pwm_set_load_counter_shadow_register_trigger(HPM_PWM0,pwm_shadow_register_update_on_modify,0);
/*
* config cmp1 and cmp2
*/
cmp_config[0].mode = pwm_cmp_mode_output_compare;
cmp_config[0].cmp = reload + 1;
cmp_config[0].update_trigger = pwm_shadow_register_update_on_hw_event;
cmp_config[1].mode = pwm_cmp_mode_output_compare;
cmp_config[1].cmp = reload + 1;
cmp_config[1].update_trigger = pwm_shadow_register_update_on_hw_event;
cmp_config[2].mode = pwm_cmp_mode_output_compare;//channel to update compare shadow
cmp_config[2].cmp = reload;
cmp_config[2].update_trigger = pwm_shadow_register_update_on_modify;
cmp_config[3].mode = pwm_cmp_mode_output_compare;//dma trigger channel
cmp_config[3].cmp = reload-100;
cmp_config[3].update_trigger = pwm_shadow_register_update_on_modify;
pwm_get_default_pwm_pair_config(HPM_PWM0, &pwm_pair_config);
pwm_pair_config.pwm[0].enable_output = true;
pwm_pair_config.pwm[0].dead_zone_in_half_cycle = 8000;
pwm_pair_config.pwm[0].invert_output = false;
pwm_pair_config.pwm[1].enable_output = true;
pwm_pair_config.pwm[1].dead_zone_in_half_cycle = 16000;
pwm_pair_config.pwm[1].invert_output = false;
/*
* config pwm
*/
if (status_success != pwm_setup_waveform_in_pair(HPM_PWM0, 0, &pwm_pair_config, cmp_index, cmp_config, 2)) {
printf("failed to setup waveform\n");
while(1);
}
//====================set dma trriger from cmp[14]============================
pwm_config_cmp(HPM_PWM0, 14, &cmp_config[3]);//dma trigger
pwm_enable_dma_request(HPM_PWM0,1<<14);//enable pwm signal output to dma
trgm_dma_request_config(HPM_TRGM0,0,14);//connect cmp14 to HPM_DMA_SRC_MOT0_0
HPMICRO
下圖是DMA以20kHz觸發(fā)UART定期輸出的波形,定期輸出0X1A,讀取多摩川傳感器中全部信息。
DMA加速傳輸
HPM5300、HPM6800、HPM6E00引入了DMAv2,增加了無限循環(huán)、DMA傳輸一半中斷,并修改了burst傳輸長度定義。
下文將列舉一個buck-boost電源應用通過DMAv2更新PWM的例子,演示DMA加速傳輸?shù)姆椒ê托Ч?/span>
例程選用了兩路交錯buck-boost電路。
高效電源對功率密度有更高的要求,更高的開關頻率可以降低主回路中電感和電容體積,實際應用中,中小功率的電源開關頻率可達100khz以上,頻繁的調節(jié)對CPU的運算能力和讀寫外設的速度有更高的要求。
HPM5300單次寫PWM寄存器至少需要5個AHB時鐘(HPM6700、HPM6300時間更長),例程使用了8個PWM比較寄存器,CPU時鐘為480Mhz、AHB總線為160Mhz,連續(xù)寫入時至少0.25us,相當于120條CPU clock。
修改PWM刷新方式后,將PWM比較器寄存器的值放入DLM內存中,更新PWM只是占用了CPU 8個訪問高速RAM的時間。
HPMICRO
與HPM6200不同,DMAv2直接支持無限循環(huán)模式,CHCTRL[CTRL].INFINITELOOP設置為1即可,不需要鏈表實現(xiàn)無限循環(huán)。
將CHCTRL[CTRL].burst_opt配置為1,burst傳輸個數(shù)不再是2的指數(shù)次方,可以根據(jù)實際需要配置。
PWM配置需要清零SHLK[SHLK],影子寄存器鎖定功能。
其它設置與前文配置相同。
void dma_transfer_config(uint8_t DMA_chn, uint8_t PWM_num, uint32_t* CMP0)
{
//---------------configure dma channel-----------------
dma_channel_config_t ch_config = {0};
DMA_chn &= 0x1F;
dma_disable_channel(HPM_HDMA, DMA_chn);//stop channel
dmamux_config(HPM_DMAMUX, DMA_chn, HPM_DMA_SRC_MOT_0, true);//trigger source is from trgms dmacfg0
//dma_reset(APP_GPTMR_DMA);
//---------------configure dma chn0-----------------
dma_default_channel_config(HPM_HDMA, &ch_config);
ch_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&PWM_DMA_struct);//source address
//ch_config.dst_addr = (uint32_t)&HPM_PWM0->CMP[0];//destination address
ch_config.dst_addr = (uint32_t)CMP0;//destination address
ch_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;//hand shake mode waiting trigger signal
ch_config.src_width = DMA_TRANSFER_WIDTH_WORD;// 32bit
ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
ch_config.burst_opt = DMA_SRC_BURST_OPT_CUSTOM_SIZE;//burst size is actural number rather than 2^num
ch_config.src_burst_size = PWM_num;
ch_config.dst_width = DMA_TRANSFER_WIDTH_WORD;//32bit
ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
ch_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;//normal
ch_config.en_infiniteloop = true;//dma will react if transize has been completed
ch_config.size_in_byte = PWM_num*4;
ch_config.linked_ptr = 0;//no link
if (status_success != dma_setup_channel(HPM_HDMA, DMA_chn, &ch_config, true)) {
printf(" dma setup channel failed\n");
return;
}
}
HPM系列MCU包含了強大互聯(lián)管理器和DMA模塊,可以輕松實現(xiàn)外設無限循環(huán)的觸發(fā)DMA,不需要占用CPU時間每次配置DMA觸發(fā)外設。
DMA直接觸發(fā)外設動作,將極大提高系統(tǒng)動作的一致性。伺服客戶對比之前中斷觸發(fā)讀取位置與DMA觸發(fā)讀取位置效果:在2000rpm時,中斷觸發(fā)讀取位置得到的計算最大瞬時轉速波動為20rpm,改為DMA觸發(fā)后波動降為2rpm。
微逆應用中,同時變頻、變占空比時,通過DMA定時修改PWM比較器和周期寄存器數(shù)值消除了同時修改后造成的波形偶發(fā)異常問題。
電源應用中,開關頻率往往超過100kHz,對CPU的利用率要求更高,且對PWM、ACMP讀寫頻率和內容更多,DMA讀寫可以有限減輕CPU負擔,提高CPU效率。
-
mcu
+關注
關注
146文章
17148瀏覽量
351183 -
存儲器
+關注
關注
38文章
7492瀏覽量
163828 -
dma
+關注
關注
3文章
561瀏覽量
100583 -
實時控制
+關注
關注
0文章
29瀏覽量
9516
發(fā)布評論請先 登錄
相關推薦
評論