Google_links

суббота, 9 ноября 2013 г.

STM32 программируем связку DMA (ПДП) и ADC (АЦП) и сохранить значения по нужному адресу в память.

STM32 программируем связку DMA (ПДП) и ADC (АЦП). В качестве проверки и отладки была выбрана плата STM32L Discovery с контроллером STM32L152. Оболочка для программирования IAR.
Данные пример использует 8 каналов для измерения с последующим сохранением замечаний в SRAM память контроллера с использованием указателя на массив.

Вот непосредственно сама инициализация  DMA (ПДП) и ADC (АЦП) :

void SUPER_ADC_DMA_Init (void)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //Разрешаем тактирование DMA
DMA1_Channel1->CPAR |= ADC1_DR_ADDRESS;//Задаем адрес периферии - регистр результата преобразования АЦП для регулярных каналов.
DMA1_Channel1->CMAR |= (uint32_t) & strADC;//(uint32_t)strADC;//MEMORY_ARRAY_ADDRESS; //Задаем адрес памяти - базовый адрес массива в RAM.
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //Направление передачи данных - чтение из периферии, запись в память.
DMA1_Channel1->CNDTR = 8; // кол-во переселаемых данных
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_CIRC; //Циклический режим - постоянная передач
DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий (Very High)
DMA1_Channel1->CCR &= ~DMA_CCR1_MEM2MEM;//Передача из переферии в память
DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу канала 1 DMA

RCC->CR |= RCC_CR_HSION; //Включаем внутренний генератор HSI - 16МГц
while(!(RCC->CR&RCC_CR_HSIRDY)); //Ждем его стабилизации
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //Разрешаем тактирование АЦП


//NVIC_EnableIRQ(DMA1_Channel1_IRQn); //разрешение прерывания Chanal_1
//NVIC_SetPriority(DMA1_Channel1_IRQn, 2); //задаем приоритет прерывания
//DMA1->IFCR |= DMA_IFCR_CGIF1; /* Clear all interrupt flags */
//DMA1_Channel1->CCR |= DMA_CCR1_TCIE; // Разрешение прерывания


// CCR->CFGR |= ADC_CCR_ADCPRE_1; // предделитель на 4 ADCCLK 16мгц/4=4мгц
ADC1->CR1 |= ADC_CR1_SCAN; // Сканирование группы каналов - без него больше одного канала не запустить
// ADC1->CR2 |= ADC_CR2_CONT; // Преобразования запускаются одно за другим
ADC1->CR2 &= ~ADC_CR2_EXTEN;// Выключить внешний триггер
ADC1->CR2 &= ~ADC_CR2_ALIGN; //Выравнивание результата вправо
ADC1->SQR1 |= (ADC_SQR1_L_2 | ADC_SQR1_L_1 | ADC_SQR1_L_0); // кол-во последовательностей 111 - т.е 8
ADC1->CR2 &= ~ADC_CR2_ALIGN; //Выравнивание результата вправо
ADC1->SQR1 |= (ADC_SQR1_L_2 | ADC_SQR1_L_1 | ADC_SQR1_L_0); // кол-во последовательностей 111 - т.е 8
ADC1->SQR5 |= (ADC_SQR5_SQ1_2); // V_REF, ADC4 - 00100
ADC1->SQR5 |= (ADC_SQR5_SQ2_3 | ADC_SQR5_SQ2_1);// V_OUT, ADC10 -01010
ADC1->SQR5 |= (ADC_SQR5_SQ3_3 | ADC_SQR5_SQ3_1 | ADC_SQR5_SQ3_0);// V_IN, ADC11 -01011
ADC1->SQR5 |= (ADC_SQR5_SQ4_3 | ADC_SQR5_SQ4_2); // I_OUT, ADC12 -01100
ADC1->SQR5 |= (ADC_SQR5_SQ5_3 | ADC_SQR5_SQ5_2 | ADC_SQR5_SQ5_0);// I_IN, ADC13 -01101
ADC1->SQR5 |= (ADC_SQR5_SQ6_2 | ADC_SQR5_SQ6_0); // TEMP_1, ADC5 -00101
ADC1->SQR4 |= (ADC_SQR4_SQ7_2 | ADC_SQR4_SQ7_1); // TEMP_2, ADC6 -00110
ADC1->SQR4 |= (ADC_SQR4_SQ8_2 | ADC_SQR4_SQ8_1 | ADC_SQR4_SQ8_0);// TEMP_3, ADC7 -00111

ADC1->SMPR3 |= (ADC_SMPR3_SMP0_2 | ADC_SMPR3_SMP0_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP1_2 | ADC_SMPR3_SMP1_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP2_2 | ADC_SMPR3_SMP2_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP3_2 | ADC_SMPR3_SMP3_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP4_2 | ADC_SMPR3_SMP4_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP5_2 | ADC_SMPR3_SMP5_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP6_2 | ADC_SMPR3_SMP6_1); // Sample Time 010 - 16 cycles
ADC1->SMPR3 |= (ADC_SMPR3_SMP7_2 | ADC_SMPR3_SMP7_1); // Sample Time 010 - 16 cycles

  ADC1->CR2 |= (ADC_CR2_DELS_2 | ADC_CR2_DELS_0);// Задержка в 63 такта между преобразованиями


ADC1->CR2 |= ADC_CR2_DDS; // ВОПРОС??? DMA request (запрос)
ADC1->CR2 |= ADC_CR2_DMA; // Подключаем DMA
ADC1->CR2 |= ADC_CR2_ADON; //Включаем АЦП
while(!(ADC1->SR&ADC_SR_ADONS)); //Ждем готовности АЦП
}


Это обьявляем где-то в начале прогармымм:
#define ADC1_DR_ADDRESS 0x40012458 //Адрес регистра данных регулярных каналов АЦП в пространстве памяти.(это адрес ADC_DR)

__IO uint16_t strADC[8]; // Буфер для данных АЦП
unsigned short strV_IN[500]; // объявляем массивы unsigned short strV_OUT[500];
unsigned short strI_IN[500];
unsigned short strI_OUT[500];
unsigned short strV_REF[500];
unsigned short strTEMP_1[500];
unsigned short strTEMP_2[500];
unsigned short strTEMP_3[500];




Теперь можно где-то в MAIN запустить и сохранить значения 8 каналов АЦП в массивы данных:
//***Подпрограмма выборки и хранения для Синуса***
for(Sample = 0; Sample <= 225; Sample++)
{
ADC1->CR2 |= ADC_CR2_SWSTART;//Запуск преобразовании АЦП 8 измерений
while((DMA1->ISR & DMA_ISR_TCIF1)==0); //ждать окончания передачи
DMA1->IFCR |= DMA_IFCR_CGIF1; // Сбросить все флаги прерывания
strV_REF[Sample] = strADC[0]; // Записать данные в масив
strV_OUT[Sample] = strADC[1]; // Записать данные в масив
strV_IN[Sample] = strADC[2]; // Записать данные в масив
strI_OUT[Sample] = strADC[3]; // Записать данные в масив
strI_IN[Sample] = strADC[4]; // Записать данные в масив
strTEMP_1[Sample] = strADC[5]; // Записать данные в масив
strTEMP_2[Sample] = strADC[6]; // Записать данные в масив
strTEMP_3[Sample] = strADC[7]; // Записать данные в масив
}


Для данного примера период измерения 8 каналов с выборкой 225 раз для каждого канала занимает 18mS. Для это были использованы задержки регистра АЦП  ADC1->SMPR3 и  ADC1->CR2 16 циклов и 63 циклов 


Григорий Анофриев, Украина 
+380937807314