Страница 1 из 1

STM32F103 (DMA+ADC+USART)

Добавлено: Пн июн 16, 2014 23:25:51
Foxek
Добрый вечер! Программирую связку STM32F103 DMA ADC USART. Одним каналом DMA забирает данные из регистра ADC и помещает в буфер, причем размер данных и буфера и ADC в DMA указаны как 16 бит.
После чего так же при помощи DMA перекладываю данные из буфера в USART. В инициализации DMA для буфера выбрано 16 бит а для USART 8 бит. При такой инициализации данные приходящие в компьютер не соответствуют действительности. Однако создав специальную функцию которая сдвигает значение АЦП на 4 бита вправо, я получаю идеальный синус. Помогите, как решить проблему не заморачиваясь с битовым сдвигом значения регистра АЦП, так как это занимает время которое мне в последствии пригодится. Должен быть способ настроить ДМА так чтобы он сам конвертировал 16 бит буфера в 8 бит USART.
Подскажите решение проблемы)Заранее благодарен

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Вт июн 17, 2014 12:24:45
HHIMERA
Решений нет... Есть референс... и там английским по белому написано что и как может ДМА...

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Вт июн 17, 2014 12:35:11
Myp3ik
У АЦП есть настройка которая указывает как выравнивать данные, по правому или по левому краю. Если по левому, то 4 младших бита из 16 будут пустыми, вот вам и приходится сдвигать на 4 бита вправо. Ну или наоборот :roll:

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Вт июн 17, 2014 14:13:38
uk8amk
Ничего никуда не надо конвертировать.
Укажите правильно размерность данных буфера SRAM 8 бит и USART 8 бит(PSIZE, MSIZE).

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Ср июн 18, 2014 20:24:27
Foxek
Спасибо за советы. Сейчас буду пробовать, завтра отпишусь что помогло а что нет)

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 00:02:25
Foxek
Ни один ни другой совет результатов не дал!((

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 16:44:26
uk8amk
Попробуйте выложить код с описанием того, что делаете и как реальный результат отличается от ожидаемого.

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 19:19:40
Foxek
Я не буду выкладывать весь код(инициализация USART, GPIO и прочего). Так как эти части программы работают сто процентно. Я выложу инициализацию ADC DMA и Прерывание в котором собственно все и происходит:

Код: Выделить всё

void ADC_Configuration(void)// Стандартная инициализация АЦП( по таймеру с ДМА)
uint16_t buffer[0];
{
	RCC->CFGR&= ~RCC_CFGR_ADCPRE;
	RCC->CFGR|=RCC_CFGR_ADCPRE_DIV2;
	RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;

	ADC1->CR2 |= ADC_CR2_CAL;
	while (!(ADC1->CR2 & ADC_CR2_CAL)){ }
	
	ADC1->CR2 &= ~ADC_CR2_ALIGN; //Выравнивание по правому краю
	ADC1->CR2 |= ADC_CR2_CONT;
	ADC1->CR2 |= ADC_CR2_EXTTRIG;
	ADC1->CR2 |= ADC_CR2_EXTSEL_2;
	ADC1->SMPR1 &= ~ADC_SMPR1_SMP14;

	ADC1->SQR3|=(ADC_SQR3_SQ1_1|ADC_SQR3_SQ1_2|ADC_SQR3_SQ1_3);
	ADC1->CR1 |= ADC_CR1_EOCIE;
	ADC1->CR2 |= ADC_CR2_DMA;
	ADC1->CR2|=ADC_CR2_ADON;

}

void DMA_Configuration(void) // Инициализация DMA(Channel1 - ADC1->buffer)(Channel7 - buffer->USART2)
{
  RCC->AHBENR |= RCC_AHBENR_DMA1EN;

	DMA1_Channel1->CPAR |= (uint32_t) &ADC1->DR; 
	DMA1_Channel1->CMAR |= (uint32_t) &Buffer[0]; 
	DMA1_Channel1->CNDTR = 2500;
	DMA1_Channel1->CCR =  0;
	DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; 
	DMA1_Channel1->CCR &= ~DMA_CCR1_PINC; 
	DMA1_Channel1->CCR |= DMA_CCR1_MINC; 	
	DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//16-бит АЦП	
	DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//16-бит БУФЕР
	DMA1_Channel1->CCR |= DMA_CCR1_PL;
	DMA1_Channel1->CCR |= DMA_CCR1_TCIE; 
	DMA1_Channel1->CCR |= DMA_CCR1_EN; 
	
	DMA1_Channel7->CPAR |=  (uint32_t)&USART2->DR;  
	DMA1_Channel7->CMAR |=  (uint32_t)&Buffer[0];   
	DMA1_Channel7->CNDTR =  2500;                      
	DMA1_Channel7->CCR =  0;
	//DMA1_Channel7->CCR |= DMA_CCR7_CIRC; 
	DMA1_Channel7->CCR |=  DMA_CCR7_DIR;
	DMA1_Channel7->CCR &= ~DMA_CCR7_PINC; 
	DMA1_Channel7->CCR &= ~(DMA_CCR7_PSIZE_0|DMA_CCR7_PSIZE_1);// 8-бит USART
	DMA1_Channel7->CCR |= DMA_CCR7_MSIZE_0;
	DMA1_Channel7->CCR |=  DMA_CCR7_MINC; 
	DMA1_Channel7->CCR |= DMA_CCR7_TCIE; 	
}

void DMA1_Channel1_IRQHandler(void)
{
	if(DMA1->ISR & DMA_ISR_TCIF1)// Если АЦП конвертировал 2500 точек
	{
		DMA1_Channel1->CCR &= (uint16_t)(~DMA_CCR1_EN);// отключаем DMA от АЦП
		for (i = 0; i<= 2500; i++)
		{
		Buffer[i]=Buffer[i]>>4;// Сдвигаем на 4 бита	
		}
	DMA1_Channel7->CNDTR =  2500;      
	DMA1_Channel7->CCR |= DMA_CCR7_EN;// запускаем DMA для USART
	DMA1->IFCR |= DMA_IFCR_CTCIF1;
	}
}
}
При данной настройке Программа работает и выдает синус. Однако мне нужно найти выход из положения, как получать синус не сдвигая на 4 бита вправо результат после каждого преобразования

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 20:13:22
uk8amk
Замечание по АЦП:
11.12 ADC registers
The peripheral registers have to be accessed by words (32-bit).
Т.е. размер источника АЦП ДМА надо выставлять как 32 битное слово.

Я не понял что вы в конечном итоге желаете получить:
1) 2500 8-битных выборок
2) 2500 16-битных слов, это будет 2500*2 ДМА транзакций для УСАРТ.

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 21:13:15
Foxek
мне нужно для начала чтобы АЦП сделал 2500 преобразований а ДМА переместил их в буфер после чего ДМА отправил их по UART в компьютер, где я должен получить числа по которым смогу построить синусоиду(или не числа а символы таблицы аски которые потом можно перевести в 10ичное число и построить график в последствии)

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 21:19:27
Foxek
И АЦП не 32 битный, а 12 бит!

12-bit resolution

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Чт июн 19, 2014 21:55:20
uk8amk
Вне зависимости от того, сколько бит в АЦП размер слова в кортексе 32 бит. Он какбы про АЦП ничего не знает. Про это как раз и гласит вышеуказанная цитата из юзермануала.

Смотрите, 12 битное число укладывается в 16-битное полуслово.
УАРТ может выплюнуть только 8 бит. Поэтому для передачи одной выборки надо сделать две 8-битные пересылки. И число данных теперь будет CNDTR=2500*2.
Соответственно для ДМА надо указать размерность буфера 8 бит и размерность регистра УАРТ тоже 8 бит.

Вы же в своём коде указываете размерность приёмника 8 бит, а размерность источника 16 бит. Согласно документации, при этом будет копироваться только младший байт. Поэтому вам приходится сдвигать 16-битное полуслово, чтобы старшие разряды попали в младший байт.

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Пт июн 20, 2014 00:38:38
HHIMERA
uk8amk писал(а):Соответственно для ДМА надо указать размерность буфера 8 бит и размерность регистра УАРТ тоже 8 бит.
Угу... но т.к. буфер объявлен как 16 бит, то всё вывернет на изнанку...

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Пт июн 20, 2014 01:07:36
Foxek
Понятно. А никак нельзя по другому? без отправки 2*2500. мне просто скорость важна.

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Пт июн 20, 2014 08:39:57
uk8amk
то всё вывернет на изнанку...
С какого перепугу? Какая разница ДМА как копировать буфер, побайтово или пословно. И откуда он знает как объявлен int8 buffer[], int16 buffer[] или int32 buffer[]. Единственно что побайтово будет длиннее по времени.
А никак нельзя по другому?
По другому чтобы выделить байт надо провести определенные математические операции. ДМА это не умеет, процессор привлекать вы не хотите.
В качестве бредовой идеи: сделать выравнивание результата налево(ALIGN) и провести невыровненный байтовый доступ к старщему байту регистра ADC_DR. Вдруг получится.

Да и что за задача у вас такая, что отправить через медленный УАРТ у вас времени хватает, а быстро сделать сдвиг - нет?

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Пт июн 20, 2014 09:24:49
balmer
Foxek писал(а):Понятно. А никак нельзя по другому? без отправки 2*2500. мне просто скорость важна.
Что-бы не грузить процессор можно сделать так.
- запустить DAC так, чтобы он через DMA складывал данные в буфер.
- реализовать обработчики прерываний "заполнена половина буфера" и "заполнен весь буыфер"
- когда один из этих обработчиков срабатывает - быстро копируем все готовые данные в DMA буфер для UART и запускаем, чтобы передавал.

А если важна скорость - прикрутите передачу через USB.

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Сб июн 21, 2014 19:07:07
misyachniy
Лирическое отступление:
uk8amk писал(а): С какого перепугу? Какая разница ДМА как копировать буфер, побайтово или пословно. И откуда он знает как объявлен int8 buffer[], int16 buffer[] или int32 buffer[]. Единственно что побайтово будет длиннее по времени.
В STM32F103 DMA не запускал.
Но обычно в микроконтроллерах DMA требует выравнивание на границу равную 4 байта.
Для ATMEL SAM3U - я выравнивал. (директивой pragma data alignment)

По сути:
Foxek писал(а):При данной настройке Программа работает и выдает синус. Однако мне нужно найти выход из положения, как получать синус не сдвигая на 4 бита вправо результат после каждого преобразования.
Тут явно проблема с выравниванием
У вас:

Код: Выделить всё

ADC1->CR2 &= ~ADC_CR2_ALIGN; //Выравнивание по правому краю
В примерах

Код: Выделить всё

//right 12-bit data alignment in ADC data register
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
Может бит только на запись?

Re: STM32F103 (DMA+ADC+USART)

Добавлено: Вт мар 10, 2015 17:31:45
vdavid
Тема, конечно, безнадежно устарела. Но решение есть:

Код: Выделить всё

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR)+1;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;


    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
Может кому и пригодится.