پریفرال DMA (Direct Memory Access) یکی از مهمترین و پرکاربردترین ویژگیهای موجود در میکروکنترلرها است که به آنها امکان میدهد دادهها را بین حافظه و پریفرالهای مختلف (مانند ADC، DAC، USART، SPI و غیره) بدون نیاز به مداخله CPU انتقال دهند. این قابلیت به شدت کارایی و عملکرد سیستم را افزایش میدهد و CPU را آزاد میکند تا وظایف دیگری را انجام دهد.
مزایا و کاربردهای DMA
افزایش کارایی سیستم: با استفاده از DMA، CPU میتواند به جای انتقال دادهها به وظایف دیگری بپردازد، که این موضوع منجر به افزایش کارایی کلی سیستم میشود.
کاهش زمان تأخیر: DMA انتقال دادهها را بدون نیاز به دخالت CPU و با سرعت بالا انجام میدهد، که این امر زمان تأخیر در عملیات ورودی/خروجی را کاهش میدهد.
پشتیبانی از انتقال دادههای حجیم: DMA برای انتقال دادههای حجیم یا مستمر بسیار مفید است، به ویژه در کاربردهایی مانند پردازش سیگنال دیجیتال، پخش ویدئو، و غیره.
صرفهجویی در توان مصرفی: با آزاد کردن CPU از وظایف انتقال داده، مصرف انرژی کاهش مییابد و بهینهسازی مصرف توان صورت میگیرد.
عملکرد DMA
DMA با استفاده از کانالهای مختلف عمل میکند که هر کدام از آنها میتوانند به یک پریفرال خاص یا حافظه تخصیص داده شوند. عملکرد DMA معمولاً شامل مراحل زیر است:
تنظیمات اولیه: ابتدا باید DMA را تنظیم کنید، شامل تنظیم منبع داده، مقصد داده، تعداد بایتها برای انتقال و تنظیمات مختلفی مانند حالتهای افزایش آدرس و غیره.
شروع انتقال: با فعال کردن کانال DMA، انتقال دادهها آغاز میشود.
پایان انتقال: پس از اتمام انتقال، یک وقفه (Interrupt) برای اطلاعرسانی به CPU ارسال میشود تا عملیاتهای بعدی انجام شود.
نمونه کد برای راهاندازی DMA
در زیر یک مثال ساده برای استفاده از DMA در میکروکنترلر STM32 برای انتقال دادهها از حافظه به یک پریفرال (مثلاً USART) آورده شده است:
در این کد، دادهها از یک آرایه در حافظه به USART با استفاده از DMA منتقل میشوند. این تنها یک مثال ساده است و بسته به میکروکنترلر و پریفرالهای مورد استفاده، ممکن است تنظیمات بیشتری نیاز باشد.
مزایا و کاربردهای DMA
افزایش کارایی سیستم: با استفاده از DMA، CPU میتواند به جای انتقال دادهها به وظایف دیگری بپردازد، که این موضوع منجر به افزایش کارایی کلی سیستم میشود.
کاهش زمان تأخیر: DMA انتقال دادهها را بدون نیاز به دخالت CPU و با سرعت بالا انجام میدهد، که این امر زمان تأخیر در عملیات ورودی/خروجی را کاهش میدهد.
پشتیبانی از انتقال دادههای حجیم: DMA برای انتقال دادههای حجیم یا مستمر بسیار مفید است، به ویژه در کاربردهایی مانند پردازش سیگنال دیجیتال، پخش ویدئو، و غیره.
صرفهجویی در توان مصرفی: با آزاد کردن CPU از وظایف انتقال داده، مصرف انرژی کاهش مییابد و بهینهسازی مصرف توان صورت میگیرد.
عملکرد DMA
DMA با استفاده از کانالهای مختلف عمل میکند که هر کدام از آنها میتوانند به یک پریفرال خاص یا حافظه تخصیص داده شوند. عملکرد DMA معمولاً شامل مراحل زیر است:
تنظیمات اولیه: ابتدا باید DMA را تنظیم کنید، شامل تنظیم منبع داده، مقصد داده، تعداد بایتها برای انتقال و تنظیمات مختلفی مانند حالتهای افزایش آدرس و غیره.
شروع انتقال: با فعال کردن کانال DMA، انتقال دادهها آغاز میشود.
پایان انتقال: پس از اتمام انتقال، یک وقفه (Interrupt) برای اطلاعرسانی به CPU ارسال میشود تا عملیاتهای بعدی انجام شود.
نمونه کد برای راهاندازی DMA
در زیر یک مثال ساده برای استفاده از DMA در میکروکنترلر STM32 برای انتقال دادهها از حافظه به یک پریفرال (مثلاً USART) آورده شده است:
کد:
#include "stm32f4xx.h" void DMA_Config(void); void USART_Config(void); uint8_t data[] = "Hello DMA!"; int main(void) { // تنظیمات اولیه SystemInit(); USART_Config(); DMA_Config(); // شروع انتقال DMA_Cmd(DMA1_Stream6, ENABLE); while (1) { // حلقه اصلی برنامه } } void USART_Config(void) { // تنظیمات USART RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART2, &USART_InitStructure); USART_Cmd(USART2, ENABLE); } void DMA_Config(void) { // تنظیمات DMA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Stream6); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)data; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = sizeof(data) - 1; 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_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream6, &DMA_InitStructure); USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); }