Blogs

Direct Memory Access ( Dma Là Gì ? Nghĩa Của Từ Dma Trong Tiếng Việt

 – DMA (Direct memory access): là một cơ chế truyền dữ liệu tốc độ cao từ ngoại vi tới bộ nhớ cũng như từ bộ nhớ tới bộ nhớ. Dữ liệu có thể được di chuyển một cách nhanh chóng mà không cần tới tác vụ từ CPU, tiết kiệm tài nguyên CPU cho các hoạt động khác.Bạn đang xem: Dma là gì

– Trong nhiều project mcu bạn cần đọc và ghi dữ liệu. Chẳng hạn bạn cần đọc dữ liệu từ ngoại vi như ADC và ghi các giá trị đọc được vào RAM. Hoặc trong trường hợp khác bạn cần gửi 1 khối dữ liệu sử dụng SPI. Khi đó bạn cần phải thực hiện đọc dữ liệu từ RAM và ghi nó vào thanh ghi SPI data. Bình thường nếu sử dụng cpu để làm việc này thì nó sẽ bị mất một khoảng thời gian đáng kể để xử lý. Trong những trường hợp này, để tránh việc cpu bận rộn và giành thời gian cho những thao tác khác thì ở những mcu phổ biến đều có hỗ trợ DMA (direct memory access). Nó sẽ thực hiện việc giao tiếp với memory mà không cần dùng đến cpu.

Đang xem: Dma là gì

* DMA của STM32 :

STM32 có 2 bộ DMA với 12 kênh (7 kênh DMA1 và 5 kênh DMA2), mỗi bộ quản lý việc truy cập bộ nhớ từ một hoặc nhiều ngoại vi. DMA cũng có chức năng phân xử độ ưu tiên giữa các DMA request.

– 12 kênh DMA độc lập, có thể thiết lập được. 7 kênh DMA1 và 5 kênh DMA2

– Software trigger được hỗ trợ cho mỗi kênh, và được lập trình bởi phần mềm.

– Độ ưu tiên giữa các kênh DMA có thể lập trình bởi phần mềm (có 4 cấp ưu tiên là very high, high, medium, low) hoặc phần cứng.

– Phụ thuộc vào kích thước giữa nguồn và đích (byte, half word, word). Địac chỉ nguồn/đích phải phù hợp với kích thước dữ liệu.

– Hỗ trợ truyền tải giữa:

+ Memory to memory

+ Peripheral to memory

XEM THÊM:  How To Fix Generic Non - : Online Support Center

+ Memory to peripheral

+ Peripheral to peripheral

– Có thể truy cập vào Flash, Sram, APB1, APB2 và AHB như nguồn và đích.

– Dữ liệu truyền nhận hỗ trợ tới 65536

 

 

*

2. Tìm hiểu cách lập trình DMA trong STM32 thông qua ví dụ cụ thể

Mỗi channel được điều khiển bởi 4 thanh ghi : Memory address, peripheral address, number of data and configuration. Và tất cả các channel đều có 2 thanh ghi được giành riêng là : DMA interrupt status register and interrupt flag clear register. Các channel của DMA có thể tạo ra 3 interupt là : transfer finished, half-finished and transfer error.

Bắt đầu với 1 ví dụ là thực hiện công việc chuyển dữ liệu giữa 2 mảng. Trong đó có 2 trường hợp là có sử dụng DMA và không sử dụng DMA mà để cpu thực hiện bình thường. Sau đó so sánh thời gian trong 2 trường hợp trên.

Trước khi đi vào phân tích code của ví dụ thì mình sẽ tìm hiểu biến cấu trúc của DMA đã được định nghĩa sẵn bao gồm những thanh ghi chức năng như thế nào :

Cấu trúc biến init DMA gồm 11 thành phần và ý ngh ĩa của từng thành phần như sau :– DMA_PeripheralBaseAddr , DMA_MemoryBaseAddr : Xác định địa chỉ của ngoại vi và địa chỉ của bộ nhớ cho DMA channel, hay nói cách khác là xác định địa chỉ nguồn và đích trong việc trao đổi dữ liệu. –DMA_DIR : Chọn hướng chuyển dữ liệu từ ngoại vi đến bộ nhớ hay từ bộ nhớ đến ngoại vi.

/** defgroup DMA_data_transfer_direction **/ #define DMA_DIR_PeripheralDST ((uint32_t)0x00000010) #define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000)

DMA_BufferSize : Kích thước của mảng dữ liệu.

Xem thêm:

DMA_PeripheralInc, DMA_MemoryInc :

+ DMA_PeripheralInc : Đối với ngoại vi bạn nên disable mode này do nếu bạn bật mode này thì mỗi lần chuyển dữ liệu thì địa chỉ ngoại vi sẽ tăng dần, điều này là không cần thiết và rất nguy hiểm nếu nh ư bạn không nắm rõ địa chỉ trỏ đến tiếp theo. + DMA_MemoryInc : Đối với memory bạn cần enable mode này, mỗi khi chuy ển đổi xảy ra bạn cần tăng địa chỉ bộ nhớ của bạn bởi ví dụ biến ADCValue có đến 3 phần tử, nếu không tăng địa chỉ lên thì chỉ duy nhất có biến ADCValue là có dữ liệu.– DMA_PeripheralDataSize , DMA_MemoryDataSize : Chọn kích thước mảng dữ liệu ADCValue gồm : Byte, Haftword và Word.

XEM THÊM:  Hướng Dẫn Sử Dụng Lingoes 2.9.2, Hướng Dẫn Download Cài Đặt Lingoes 2

/** defgroup DMA_peripheral_data_size */ #define DMA_PeripheralDataSize_Byte ((uint32_t)0x00000000) #define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100) #define DMA_PeripheralDataSize_Word ((uint32_t)0x00000200)– DMA_Mode : Circular mode & NonCircular mode

+ Chọn mode DMA chế độ vòng tròn, có nghĩa là việc chuyển đổi liên tục lặp lại. Khi circular mode được actived thì số dữ liệu được transfer sẽ tự động reload lại với những thiết lập đã được lập trình theo những thông số config cho channel. + Nếu channel được config ở chế độ concircular mode thì sẽ không có DMA request được tạo sau mỗi lần transfer. /** defgroup DMA_circular_normal_mode */ #define DMA_Mode_Circular ((uint32_t)0x00000020) #define DMA_Mode_Normal ((uint32_t)0x00000000)– DMA_Priority : Xác định độ ưu tiên của kênh DMA ,có 4 độ ưu tiên bao gồm :

+ DMA_Priority_High + DMA_Priority_Low + DMA_Priority_Medium + DMA_Priority_VeryHigh

DMA_M2M : Kênh DMA cũng có thể được kích hoạt mà không cần request từ ngoại vi, chế độ này được gọi là memory to memory mode. Nếu bit MEM2MEM trong thanh ghi DMA_CCRx được set thì channel sẽ init transfer ngay sau khi được enable bằng software nghĩa là enable bit EN trong thanh ghi DMA_CCRx. Quá trình transfer sẽ ngừng mỗi khi thanh ghi DMA_CNDTRx zero. Memory to memory mode không được sử dụng đồng thời với Circular mode./** defgroup DMA_memory_to_memory **/#define DMA_M2M_Enable ((uint32_t)0x00004000)#define DMA_M2M_Disable ((uint32_t)0x00000000)Đây là code DMA chuyển dữ liệu trong trường hợp từ memory đến memory :

#include “stm32f10x.h”#include “leds.h”#define ARRAYSIZE 800volatile uint32_t status = 0;volatile uint32_t i;int main(void){//initialize source and destination arraysuint32_t source;uint32_t destination;//initialize arrayfor (i=0; i Bắt đầu phân tích :

Đầu tiên chúng ta tạo ra 2 mảng dữ liệu là : source và destination. Kích thước của mảng được xác định bởi ARRAYSIZE, trong ví dụ này kích thước là 800.Trong ví dụ này,ta sử dụng trạng thái của Led để báo hiệu quá trình transfer dữ liệu start và stop trong cả 2 mode : DMA và CPU. 

+ Sau đó bắt đầu cấu hình thông qua cấu trúc DMA_InitStructure như đã phân tích bên trên. Trong ví dụ này ta chọn DMA1 channel1, gọi hàm DMA_DeInit(DMA1_Channel1) để chắc chắn rằng DMA được reset về giá trị mặc định ban đầu.

XEM THÊM:  Hướng Dẫn Đăng Ký Thi Toeic Trên Iiig 2021, Attention Required!

+ Sau đó chọn DMA mode memory to memory(DMA_InitStructure.DMA_M2M = DMA_M2M_Enable)

+ Chọn normal DMA mode hay còn gọi là nonCircular mode(DMA_InitStructure.DMA_Mode = DMA_Mode_Normal).

+ Chọn chế độ ưu tiên cho kênh DMA này laafe Medium (DMA_InitStructure.DMA_Priority = DMA_Priority_Medium).

+ Chọn kích thước mảng dữ liệu để transfer là 32-bit world (DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word). Tương tự với cả peripheral và memory address.

Chú ý : Nếu kích thước dữ liệu của 2 thành phần trên không giống nhau,chẳng hạn 32-bit source và 8-bit destination thì DMA sẽ thực hiện thành 4 chu kỳ với mỗi chu kỳ là 8 bit.

+ Sau khi đã cấu hình địa chỉ source và destination, cũng như kích thước dữ liệu để gửi. Ta sử dụng hàm

DMA_Init(DMA_Channel1, &DMA_InitStructure) để init các thông số cấu hình bên trên vào thanh ghi.

+ Bây giờ thì DMA có thể sẵn sàng để transfer dữ liệu, bất cứ khi nào lệnh sau được thực thi DMA_Cmd(DMA_Channel1, ENABLE).

Xem thêm:

+ Để bắt interrupt khi quá trình DMA transfer complete trên channel1. Ta cấu hình interrupt như sau :

NVIC_InitTypeDef NVIC_InitStructure;

//Enable DMA1 channel IRQ Channel */

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

Trước khi bắt đầu chuyển đổi bằng DMA thì ta bật led on để báo trạng thái bắt đầu LEDToggle(LEDG) . Khi quá trình chuyển đổi vừa xong thì nó sẽ tạo ra 1 interrupt complete và thực hiển đảo trạng thái led trong interrupt này để báo hiệu.

voidDMA1_Channel1_IRQHandler(void){

//Test on DMA1 Channel1 Transfer Complete interrupt

if(DMA_GetITStatus(DMA1_IT_TC1))

{

status=1;

LEDToggle(LEDG);

//Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits

DMA_ClearITPendingBit(DMA1_IT_GL1);

}

}

//wait for DMA transfer to be finished

while(status==0) {};

LEDToggle(LEDB);

for (i=0; i

{

destination=source;

}

LEDToggle(LEDB);

– Trong ví dụ này, LEDG (DMA) được kết nối đến GPIOC pin 9 và LEDB (CPU) được kết nối đến GPIOC pin 8, Để quan sát rõ hơn quá trình transfer ta kết nối 2 pin này với OSC như sau :

Related Articles

Trả lời

Email của bạn sẽ không được hiển thị công khai.

Back to top button