http://mycontroller.ru/stm32-dma-initsializatsiya/
http://emproj.com/1_5_To_90
http://electronics-archive.ru/stm32-dma-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5.html
http://eddy-em.livejournal.com/tag/stm32


DMA_Mode – режим работы канала DMA
DMA_Priority – приоритет для канала DMA
DMA_M2M – используем ли передачу память->память
Рассматриваем отдельно то, что касается DMA:
аналогично ) адрес нулевого элемента массива
dma.DMA_DIR = DMA_DIR_PeripheralDST;
шлем в периферию, а не из нее
dma.DMA_BufferSize = DMA_BUFFER_SIZE;
буфер – 16 байт (#define DMA_BUFFER_SIZE 16)
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
шлем байтами
Тут все понятно:
USART_Cmd(USART1, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
Включаем USART и DMA
Тут могла быть ваша программа
Процессор свободен.
Запускаем программу в отладчике:

Данные пришли туда, куда и требовалось =)
http://emproj.com/1_5_To_90
http://electronics-archive.ru/stm32-dma-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5.html
http://eddy-em.livejournal.com/tag/stm32
Пришло время рассказать об одной
потрясающей штуке под названием DMA – то есть прямой доступ к памяти
(Direct Memory Access). Поясню что же это такое.
В двух словах – DMA позволяет перемещать
данные без(!) участия центрального процессора. То есть процессор
работает себе преспокойненько, не отвлекается ни на что, а DMA в этот
момент может пересылать огромные массивы данных, например, в UART. Думаю
сразу понятно насколько это полезно, ведь процессору теперь не надо
отвлекаться от основной полезной работы.
А в контроллерах STM32F10x даже не один,
а два контроллера DMA! И, соответственно, у каждого несколько каналов
(у DMA1 – 7, а у DMA2 – 5). Вот как выглядит разделение каналов между
периферийными устройствами:
Я когда то упорно пытался подключить
USART не к тому каналу DMA к которому нужно, и совершенно не втыкал
почему не работает. С тех пор очень люблю эти картинки )
Давайте-ка теперь рассмотрим процесс настройки DMA. Открываем файлы stm32f10x_dma.h и stm32f10x_dma.c из SPL. В первом находим структуру:
typedef struct { uint32_t DMA_PeripheralBaseAddr; uint32_t DMA_MemoryBaseAddr; uint32_t DMA_DIR; uint32_t DMA_BufferSize; uint32_t DMA_PeripheralInc; uint32_t DMA_MemoryInc; uint32_t DMA_PeripheralDataSize; uint32_t DMA_MemoryDataSize; uint32_t DMA_Mode; uint32_t DMA_Priority; uint32_t DMA_M2M; }DMA_InitTypeDef; |
В самом файле все довольно подробно откомментировано, правда, на английском. Итак:
uint32_t DMA_PeripheralBaseAddr – сюда мы должны записать адрес периферийного устройства, которое будет участвовать в обмене информацией
uint32_t DMA_MemoryBaseAddr – а сюда записываем адрес области памяти, где лежат данные (ну или куда их надо положить, в зависимости от направления обмена)
uint32_t DMA_DIR – тут устанавливаем, является ли периферия источником или местом назначения
uint32_t DMA_BufferSize – размер буфера для хранения данных
uint32_t DMA_PeripheralInc,
uint32_t DMA_MemoryInc – тут задаем надо ли инкрементировать указатели на данные в периферии и в памяти соответственно
Остановимся на этом поподробнее. Допустим, мы забираем данные из регистра данных АЦП и пишем их в массив в памяти. Так как мы хотим записывать результат преобразования в разные элементы массива, то необходимо инкрементировать указатель, следовательно DMA_MemoryInc = Enable. В то же время регистр данных АЦП у нас один и он никуда не перемещается, а что это значит? Правильно, uint32_t DMA_PeripheralInc = Disable )
uint32_t DMA_PeripheralBaseAddr – сюда мы должны записать адрес периферийного устройства, которое будет участвовать в обмене информацией
uint32_t DMA_MemoryBaseAddr – а сюда записываем адрес области памяти, где лежат данные (ну или куда их надо положить, в зависимости от направления обмена)
uint32_t DMA_DIR – тут устанавливаем, является ли периферия источником или местом назначения
uint32_t DMA_BufferSize – размер буфера для хранения данных
uint32_t DMA_PeripheralInc,
uint32_t DMA_MemoryInc – тут задаем надо ли инкрементировать указатели на данные в периферии и в памяти соответственно
Остановимся на этом поподробнее. Допустим, мы забираем данные из регистра данных АЦП и пишем их в массив в памяти. Так как мы хотим записывать результат преобразования в разные элементы массива, то необходимо инкрементировать указатель, следовательно DMA_MemoryInc = Enable. В то же время регистр данных АЦП у нас один и он никуда не перемещается, а что это значит? Правильно, uint32_t DMA_PeripheralInc = Disable )
Идем дальше:
DMA_PeripheralDataSize – размер единицы данных в периферии, аналогично – DMA_MemoryDataSize
Возможные значения этих полей:
DMA_PeripheralDataSize – размер единицы данных в периферии, аналогично – DMA_MemoryDataSize
Возможные значения этих полей:
DMA_PeripheralDataSize_Byte DMA_PeripheralDataSize_HalfWord DMA_PeripheralDataSize_Word DMA_MemoryDataSize_Byte DMA_MemoryDataSize_HalfWord DMA_MemoryDataSize_Word |
DMA_Priority – приоритет для канала DMA
DMA_M2M – используем ли передачу память->память
Заполнив эти поля нужным образом можно быстро и легко настроить DMA.
Пришло время немного поиграться ) Будем
писать пример. Давайте объявим массив с данными в памяти и перекинем их с
помощью прямого доступа к памяти в регистр данных USART, откуда они и
вылетят во внешний мир.
/*******************************************************************/ #define BAUDRATE 9600 #define DMA_BUFFER_SIZE 16 /*******************************************************************/ GPIO_InitTypeDef port; ADC_InitTypeDef adc; USART_InitTypeDef usart; uint16_t inputData; uint16_t outputData; DMA_InitTypeDef dma; uint8_t dataBuffer[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /*******************************************************************/ |
dataBuffer – массив с данными,
которые надо отправить по USART’у. Не самый информативный набор данных в
этом примере, но для тестирования покатит )
Инициализация:
Инициализация:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_StructInit(&dma); dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0]; dma.DMA_DIR = DMA_DIR_PeripheralDST; dma.DMA_BufferSize = DMA_BUFFER_SIZE; dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; dma.DMA_MemoryInc = DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_Init(DMA1_Channel4, &dma); GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port); port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = GPIO_Pin_10; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port); USART_StructInit(&usart); usart.USART_BaudRate = BAUDRATE; USART_Init(USART1, &usart); |
dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
это адрес регистра данных USART
dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];это адрес регистра данных USART
аналогично ) адрес нулевого элемента массива
dma.DMA_DIR = DMA_DIR_PeripheralDST;
шлем в периферию, а не из нее
dma.DMA_BufferSize = DMA_BUFFER_SIZE;
буфер – 16 байт (#define DMA_BUFFER_SIZE 16)
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
в периферии не инкрементируем, в памяти – инкрементируем, прям как в примере про АЦП чуть выше
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
в периферии не инкрементируем, в памяти – инкрементируем, прям как в примере про АЦП чуть выше
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
шлем байтами
DMA_Init(DMA1_Channel4, &dma);
Идем в таблицу с каналами – USART1_TX – 4 канал, все верно =)
Идем в таблицу с каналами – USART1_TX – 4 канал, все верно =)
int main() { __enable_irq(); initAll(); USART_Cmd(USART1, ENABLE); USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); DMA_Cmd(DMA1_Channel4, ENABLE); while(1) { __NOP(); } } |
USART_Cmd(USART1, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
Включаем USART и DMA
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
Активируем передачу в последовательный порт по запросу DMA
Активируем передачу в последовательный порт по запросу DMA
while(1) { __NOP(); } |
Запускаем программу в отладчике:
Данные пришли туда, куда и требовалось =)
На этом, собственно, все, с прямым доступом к памяти мы разобрались!
Ссылка на источник: http://microtechnics.ru/stm32-uchebnyj-kurs-dma/
Комментариев нет:
Отправить комментарий