Top.Mail.Ru

STM32 с нуля. Использование модулей DMA и USART.

Пришло время рассказать об одной потрясающей штуке под названием DMA – то есть прямой доступ к памяти (Direct Memory Access). Поясню что же это такое.

В двух словах – прямой доступ к памяти позволяет перемещать данные без (!) участия центрального процессора. То есть процессор работает себе спокойно над своими задачами, не отвлекается ни на что, а DMA в этот момент может пересылать огромные массивы данных, например, в USART или SPI. Либо, при использовании АЦП можно настроить DMA на автоматическое помещение результатов измерений в некий буфер. Думаю сразу понятно насколько это полезно, ведь процессору теперь не надо отвлекаться от основной полезной работы.

Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также небольшая подборка на смежную тему из нового курса:

А в контроллерах STM32F10x даже не один, а два контроллера прямого доступа к памяти. И, соответственно, у каждого несколько каналов (у DMA1 – 7, а у DMA2 – 5). Вот как выглядит разделение каналов между периферийными устройствами:

Список каналов DMA1 в STM32.
Список каналов DMA2 в STM32.

Я когда-то упорно пытался подключить USART не к тому каналу, к которому нужно, и совершенно не понимал, почему не работает. С тех пор очень люблю эти картинки )

Давайте-ка теперь рассмотрим процесс настройки в DMA в STM32. Открываем файлы 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.

Идем дальше:

  • DMA_PeripheralDataSize – размер единицы данных в периферии, аналогично – DMA_MemoryDataSize.

Возможные значения этих полей:

DMA_PeripheralDataSize_Byte
DMA_PeripheralDataSize_HalfWord
DMA_PeripheralDataSize_Word
DMA_MemoryDataSize_Byte
DMA_MemoryDataSize_HalfWord
DMA_MemoryDataSize_Word
  • DMA_Mode – режим работы канала DMA
  • DMA_Priority – приоритет для канала
  • 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[DMA_BUFFER_SIZE] = {'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. Адрес регистра данных USART:

dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);

Аналогично, адрес нулевого элемента массива:

dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];

Шлем в периферию, а не из нее:

dma.DMA_DIR = DMA_DIR_PeripheralDST;

Размер буфера – 16 байт (у нас определено #define DMA_BUFFER_SIZE 16):

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);

Идем в таблицу с описанием каналов DMA – 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. И активируем передачу в последовательный порт по запросу DMA:

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
while(1)
{
	__NOP();
}

Тут могла быть ваша программа... Процессор свободен! Запускаем программу в отладчике:

DMA пример.

Данные пришли туда, куда и требовалось 👍 На этом, собственно, все, сегодня мы успешно освоили работу с DMA.

Подписаться
Уведомить о
guest

47 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Алиса Алексеева
11 лет назад

Ну, у меня прогресс - я поняла половину печатного текста :), правда код - это мрак, но остальное - вроде бы да:)

MS24
MS24
11 лет назад

Т.е как я понимаю, у нас теперь процессор может не только одну инструкцию в один такт выполнять? Некое подобие ПЛИС что ли получается?

Денис
Денис
11 лет назад

Спасибо) Очень хорошая статья) Продолжайте в том же духе и мы с вами продолжать будем)) Ещё раз спасибо)

Иван
Иван
11 лет назад

5 балов!

Ssssoom
Ssssoom
11 лет назад

Помогите плииз, не могу уйти в прерывание ни по одному событию, хотя флаги выставляются HTIF1 TCIF. Проект для STM32L-Discovery

#include "stm32l1xx.h"
#include "stm32l1xx_gpio.h"

#define ADC1_DR_ADDRESS 0x40012458
#define MEMORY_ARRAY_ADDRESS 0x20000000;

#define Led_Port GPIOB
#define Led_Blue GPIO_Pin_6
#define Led_Green GPIO_Pin_7
#define Led_High(a,b) a -> BSRRL = b
#define Led_Low(a,b) a -> BSRRH = b

void SetNVIC(void);
void adc_init(void);
void dma_init(void);
void InitUART(void);
void DMA1_Channel1_IRQHandler(void);
void Delay(uint32_t time);

int main()
{
SetNVIC();
adc_init();
dma_init();
InitUART();
ADC1->CR2 |= ADC_CR2_SWSTART;
DMA1_Channel1->CCR |= DMA_CCR1_EN;
while(1)
{
Led_High(Led_Port,Led_Blue);
Delay(0x1FFFF);
Led_Low(Led_Port,Led_Blue);
Delay(0x1FFFF);
Led_High(Led_Port,Led_Green);
Delay(0x1FFFF);
Led_Low(Led_Port,Led_Green);
Delay(0x1FFFF);
}
}

void adc_init(void)
{

RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

GPIOA->MODER |= GPIO_MODER_MODER15;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;

GPIOB->MODER |= GPIO_MODER_MODER6_0;
GPIOB->OTYPER &= ~GPIO_OTYPER_OT_6;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR6;

GPIOB->MODER |= GPIO_MODER_MODER7_0;
GPIOB->OTYPER &= ~GPIO_OTYPER_OT_7;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR7;

RCC->CR |= RCC_CR_HSION;
while(!(RCC->CR&RCC_CR_HSIRDY));

RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->SQR1 &= ~ADC_SQR1_L;
ADC1->SQR5 |= (ADC_SQR5_SQ1_0 | ADC_SQR5_SQ1_2);
ADC1->CR1 |= ADC_CR1_SCAN;
ADC1->CR2 |= ADC_CR2_CONT;
ADC1->CR2 |= ADC_CR2_DELS_0;
ADC1->CR1 &= ~ADC_CR1_RES;
ADC1->CR2 &= ~ADC_CR2_ALIGN;
ADC1->CR2 |= ADC_CR2_DMA;
ADC1->CR2 |= ADC_CR2_ADON;

while(!(ADC1->SR&ADC_SR_ADONS));
}

void dma_init(void)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CPAR |= ADC1_DR_ADDRESS;
DMA1_Channel1->CMAR |= MEMORY_ARRAY_ADDRESS;
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR;
DMA1_Channel1->CNDTR = 10;
DMA1_Channel1->CCR &= ~DMA_CCR1_PINC;
DMA1_Channel1->CCR |= DMA_CCR1_MINC;
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;
DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;
DMA1_Channel1->CCR |= DMA_CCR1_PL;
DMA1_Channel1->CCR |= DMA_CCR1_TCIE;
DMA1_Channel1->CCR |= DMA_CCR1_HTIE;
DMA1->IFCR |= DMA_IFCR_CGIF1;
}

void SetNVIC(void)
{
NVIC_EnableIRQ(DMA2_Channel1_IRQn);
NVIC_SetPriority(DMA2_Channel1_IRQn,1);
}

void InitUART()
{
RCC->CR |= RCC_CR_HSION;
while(!(RCC_CR_HSIRDY));
RCC->CFGR |= RCC_CFGR_SW_HSI;
RCC->CR &= ~RCC_CR_MSION;

RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER |= GPIO_MODER_MODER9_1;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9;
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR9);
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;

GPIOA->AFR[1] |= (0x7<APB2ENR |= RCC_APB2ENR_USART1EN;
USART1->CR1 |= USART_CR1_UE;
USART1->CR1 &= ~USART_CR1_M;
USART1->CR2 &= ~USART_CR2_STOP;
USART1->BRR = 0x683;
USART1->CR1 |= USART_CR1_TE;
}

void Delay(uint32_t time)
{
while(time>>0)
{
--time;
}
}
void DMA1_Channel1_IRQHandler(void)
{
if (DMA1->ISR & DMA_ISR_HTIF1)
{
Led_High(Led_Port,Led_Blue);
Delay(0x1FFFF);
Led_Low(Led_Port,Led_Blue);
Delay(0x1FFFF);
Led_High(Led_Port,Led_Green);
Delay(0x1FFFF);
Led_Low(Led_Port,Led_Green);
Delay(0x1FFFF);
}
if (DMA1->ISR & DMA_ISR_TCIF1)
{
Led_High(Led_Port,Led_Green);
Delay(0x1FFFF);
Led_Low(Led_Port,Led_Green);
Delay(0x1FFFF);
}
}

AkaUfo
AkaUfo
11 лет назад

А если нужно периодически отсылать через USART посылки различной длины? Каждый раз инициализировать порт и канал DMA по-новому? Или можно как-то указать новую длину данных в буфере и снова инициализировать передачу?

AkaUfo
AkaUfo
Ответ на комментарий  Aveal
11 лет назад

Спасибо, буду пробовать

Тарас
Тарас
11 лет назад

Снимаю шапку, в благодарность за то что Вы делаете.
Все просто и почти понятно. Вопрос: В приведенном выше примере, зачем вот это ADC_InitTypeDef adc;
И для чего включили прерывания ? __enable_irq();

lal
lal
10 лет назад

Почему не происходит overrun? Где здесь ожидание завеошения передачи байта по usart?

Artem
Artem
10 лет назад

Спасибо за доходчивую статью! Модуль DMA в связке с АЦП заносил в память одно значение, а остальные ячейки массива заполнял нулями. Помогло
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable у меня DMA модуль заносил в память

DVF
DVF
10 лет назад

У STM32 DMA не позволяет работать с GPIO как периферией? Жесть какая-то.

DVF
DVF
10 лет назад

В прямом. Из datasheet LPC1754 (NXP):
"GPDMA supports the SSP, I2S, UART, A/D Converter, and D/A Converter peripherals. DMA can also be triggered by a timer match condition. Memory-to-memory transfers and transfers to or from GPIO are also supported."
В STM32 я такого не увидел.

DVF
DVF
10 лет назад

Ну, это Вы зря. Например многие LCD TFT небольших диагоналей имеют 8-16-ти битную шину. Есть два пути: брать LCD без контроллера и цеплять к нему МК со встроенным драйвером с кучей ног (как правило, от 144) или менее дорогой плюс МК с возможностью отправлять данные из памяти в порт.

CrazyPit
10 лет назад

облазил оч. много сайтов.. и ни одного
рабочего примера под stm32f10x
если вас не затруднит. буду очень благодарен

CrazyPit
10 лет назад

я где то делаю ошибку. и чегото недопанимаю.
поправьте если что..
1 настраиваем пины для уарта
2 активируем уарт
3 настраиваем дма из памяти в уарт с длиной передачи указанной нами.
передача один раз.
3 активируем дма.
4 разрешаем прерывания для дма..

1 вопрос а какой командой передача то осуществляется.
2 для передачи данных второй раз что настраивать в дма.
3 какие флаги надо скидывать. и когда.

п.с. передо мной стоит задача получать данные по одному протоколу
передавать данные в другой уарт по другому. может можно решить по другому как то..
спс

CrazyPit
10 лет назад

нашел следующее.
Чтобы включить DMA набираем:

DMA1_Channel4->CCR |= DMA_CCR1_EN;

Если же вы хотите перезапустить DMA, то придётся несколько усложнить функцию:
DMA1_Channel4->CCR &= (uint16_t)(~DMA_CCR1_EN);//Выключаем DMA.
DMA1_Channel4->CNDTR = sizeof(text);//Устанавливаем размер передаваемого буфера заново.
DMA1_Channel4->CCR |= DMA_CCR1_EN;//Включаем DMA

После этих строк DMA, будет работать и в конце выдаст прерывание вида:

void DMA1_Channel4_IRQHandler(void)
{
DMA1->IFCR |= DMA_ISR_TCIF4;//очистить флаг окончания обмена.
}

завтра буду пробовать

Виталий
Виталий
10 лет назад

Вы не могли бы выложить полный код программы, я попытался разобрать пример, но моя программа отказалась собираться, выдав кучу ошибок.

Текст внутри спойлера

Виталий
Виталий
10 лет назад

dma.c(23): error: #79: expected a type specifier
dma.c(23): error: #757: constant "ENABLE" is not a type name
dma.c(23): warning: #77-D: this declaration has no storage class or type specifier
dma.c(23): error: #147: declaration is incompatible with "void RCC_APB2PeriphClockCmd(uint32_t, FunctionalState)" (declared at line 693 of ".\STM32_SPL\STM32_SPL\inc\stm32f10x_rcc.h")
dma.c(24): error: #79: expected a type specifier
dma.c(24): error: #757: constant "ENABLE" is not a type name
dma.c(24): warning: #77-D: this declaration has no storage class or type specifier
dma.c(25): error: #79: expected a type specifier
dma.c(25): error: #757: constant "ENABLE" is not a type name
dma.c(25): warning: #77-D: this declaration has no storage class or type specifier
dma.c(25): error: #147: declaration is incompatible with "void RCC_AHBPeriphClockCmd(uint32_t, FunctionalState)" (declared at line 692 of ".\STM32_SPL\STM32_SPL\inc\stm32f10x_rcc.h")
dma.c(27): error: #79: expected a type specifier
dma.c(27): warning: #77-D: this declaration has no storage class or type specifier
dma.c(27): error: #147: declaration is incompatible with "void DMA_StructInit(DMA_InitTypeDef *)" (declared at line 412 of ".\STM32_SPL\STM32_SPL\inc\stm32f10x_dma.h")
dma.c(28): error: #77-D: this declaration has no storage class or type specifier
dma.c(28): error: #147: declaration is incompatible with "DMA_InitTypeDef dma" (declared at line 17)
dma.c(28): error: #65: expected a ";"
dma.c(29): error: #77-D: this declaration has no storage class or type specifier
dma.c(29): error: #65: expected a ";"
dma.c(30): error: #77-D: this declaration has no storage class or type specifier
dma.c(30): error: #65: expected a ";"
dma.c(31): error: #77-D: this declaration has no storage class or type specifier
dma.c(31): error: #65: expected a ";"
dma.c(32): error: #77-D: this declaration has no storage class or type specifier
dma.c(32): error: #65: expected a ";"
dma.c(33): error: #77-D: this declaration has no storage class or type specifier
dma.c(33): error: #65: expected a ";"
dma.c(34): error: #77-D: this declaration has no storage class or type specifier
dma.c(34): error: #65: expected a ";"
dma.c(35): error: #77-D: this declaration has no storage class or type specifier
dma.c(35): error: #65: expected a ";"
dma.c(36): error: #79: expected a type specifier
dma.c(36): error: #79: expected a type specifier
dma.c(36): warning: #77-D: this declaration has no storage class or type specifier
dma.c(36): error: #147: declaration is incompatible with "void DMA_Init(DMA_Channel_TypeDef *, DMA_InitTypeDef *)" (declared at line 411 of ".\STM32_SPL\STM32_SPL\inc\stm32f10x_dma.h")

Я так понимаю Кейл не может найти какие-то определения в файлах заголовках или я неправильно код собрал(

Виталий
Виталий
10 лет назад

нет, в четвертом, с большей частью разобрался, осталось только вот

dma.c(70): warning: #128-D: loop is not reachable
linking...
.
\usart_dma.axf: Error: L6218E: Undefined symbol assert_param (referred from stm32f10x_dma.o).

.\usart_dma.axf" - 1 Errors, 1 Warning(s).

Виталий
Виталий
10 лет назад

Вы правы, я пропустил USE_STDPERIPH_DRIVER, все ошибок больше нет, пример ещё поковыряю, весьма не все понятно, спасибо большое.

Nick
Nick
9 лет назад

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); - Так не бывает GPIOА тактируется AHB1

Алексей
Алексей
8 лет назад

Добрый день. У меня возник вот какой вопрос. Я хочу принимать данные с UART через DMA . Настраивал проект в MXCube (использую HAL ). Мне надо что бы прерывание void DMA1_Channel5_IRQHandler(void) вызывалось только после окончания передачи. Сейчас оно вызывается по половине и по окончанию передачи. Не нашел как и где это выставляется в кубе, ну или подскажите в каком месте ручками подправить.

Алексей
Алексей
8 лет назад

пробовал комментировать строку
huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; в HAL_UART_Receive_DMA - не помогло.
решил вопрос так:
запустил выполнение в функции void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle).
в принципе заработало. У меня идет обмен данными туда-сюда и периодически зависает прием, хотя данные поступают. Сейчас буду осваивать как просмотреть регистры, что бы увидеть на чем затыкается.

Lexa
Lexa
8 лет назад

Добрый день
.
По-поводу последнего комментария есть такой вопрос:
Как организовать работу ПДП с помощью библиотеки HAL в режиме двойной буферизации. Задача - принять данные от периферии по I2C в буфер, обработать его и передать по SPI, а во время передачи записать данные во второй буфер.

Как не пытался настроить в Cube, так и не удалось реализовать двойную буферизацию. Режим circular отказывается работать, а бит DBM, почему-то сбрасывается в функции стандартного обработчика.

Pilot_red
Pilot_red
8 лет назад

Доброго времени суток!
У меня такой вопрос: допустим у меня есть огромный массив данных, который я хочу передать(например в uart), используя dma. При этом, идет постоянный расчет этих данных. Может ли получится так, что во время передачи данных, некоторые элементы массива перерасчетаются, и попадут в конечный буффер не со своей очередью. Если да, то как этого избежать, может быть есть встроенные механизмы, или все таки придется самому колхозить организацию доступа.? Кто не понял объясню на примере огромной светодиодной ленты . Например, в один момент у меня происходит дикий расчет, и вся лента должна загорется красным цветом, данные о цвете ленты мы передаем dma, dma что-то сам по себе делает, в это время мы опять проваливаемя в расчет цвета ленты, на этот раз лента должна окрасится в синий цвет, расчет по сути дела уже произошел, но данные о первом состоянии ленты еще не передались, но уже изменились, т.е. на выходе мы получим абрукадабру. Вот как грамотно действовать в таких случаях?

Pilot_red
Pilot_red
Ответ на комментарий  Aveal
8 лет назад

Так тогда смысл использования dma теряется, т.е. Пока данные не передадутся процессор будет курить, а хотелось бы чтобы и вычисления производились и передача данных была. кроме использования еще одного буфера мне в голову не приходит т.е. Пока происходит отправка данных производим преобразование со вторым буфером, как только передача произошла, передаем второй буфер, а с первым вычисляем, и.т.д.

Pilot_red
Pilot_red
Ответ на комментарий  Aveal
8 лет назад

Ок, спасибо, за инфу! Просто только начинаю осваивать arm МК, думал что есть какие-нибудь хитрые механизмы для обработки таких ситуаций, а в инете в основном примеры как передать данные, про целосность и разгроничении доступа к передаваемым данным пока ничего не нашел..

Anna
8 лет назад

Здраствуйте,
У меня такая задача:
Принимаю масив даних с микрофона, каждую мили секунду заполняю буфер, обрабативаю даниые и тут надо их послат на SDIO и записат на карту памяти.
для етова хачу сделот:
2 буфера , один накапливаыет и пишет , пока первый пишет накапливаю второй.
вопроса 2 :
1. если предават через ДМА заполниный буфер то протсесор может далше обрабативат поралельно не мешая друг другу?
2. Как склеет SDIO и DMA ? пробивала и через CUBE и через примери не получаытся чтото... может ест опыт работи или пример на ету тему?

Спасибо зараниые и прошу прощение за ошибки - написано на транслите.

Денис
Денис
7 лет назад

dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];
dataBuffer уже является адресом, так что можно написать:
dma.DMA_MemoryBaseAddr = (uint32_t)dataBuffer;

47
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x