Простой пример АЦП+ПДП (ADC+DMA) для STM32F4-Discovery
Привожу простой пример совместной работы АЦП+ПДП для платы STM32F4-Discovery.
Задача (источник http://kazus.ru/forums/showthread.php?t=104295):
- По событию от таймера запускать преобразования регулярного канала АЦП.
- По окончании преобразования АЦП, контроллер ПДП должен скопировать данные в ОЗУ.
Запускать преобразования АЦП в STM32F4 можно от нескольких источников, для примера я выбрал Таймер 3:
Запросы от АЦП “подключены” к нулевому каналу нулевого потока контроллера ПДП:
Примечание: Возможно “поток” не очень хороший перевод в данном случае.
Исходный код:
/*
* File: main.c
* Date: 29.04.2013
* Denis Zheleznyakov http://ziblog.ru
*/
#include "main.h"
uint16_t adc_buffer[8];
//------------------------------------------------------------------------------
inline static void gpio(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIODEN;
// светодиод
PIN_CONFIGURATION(PIN_LED);
// кнопка
PIN_CONFIGURATION(PIN_BUTTON);
// АЦП
PIN_CONFIGURATION(PIN_ADC_CH1);
}
//------------------------------------------------------------------------------
inline static void adc(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
// разрешаем тактирование
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_Init(ADC1, &ADC_InitStructure);
// выбор канала
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);
// базовая настройка
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
//
ADC_DiscModeCmd(ADC1, DISABLE);
ADC_EOCOnEachRegularChannelCmd(ADC1, ENABLE);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
// включаем АЦП
ADC_Cmd(ADC1, ENABLE);
}
//------------------------------------------------------------------------------
inline static void dma(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
// АЦП
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &adc_buffer[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(adc_buffer);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
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(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
//------------------------------------------------------------------------------
inline static void timer(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// базовая нстйрока
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 625 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 2000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// выход синхронизации
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
// запуск таймера
TIM_Cmd(TIM3, ENABLE);
}
//------------------------------------------------------------------------------
void main(void)
{
gpio();
adc();
dma();
timer();
while (1)
{
if (PIN_SIGNAL(PIN_BUTTON))
{
PIN_ON(PIN_LED);
}
else
{
PIN_OFF(PIN_LED);
}
}
}
Полный проект можно получить используя данный код совместно с шаблоном к конце записи:
http://ziblog.ru/2012/09/09/linii-vvoda-vyivoda-stm32-chast-3.html
2013-05-08
Небольшое дополнение от читателя блога (http://kazus.ru/forums/showthread.php?t=104295&page=4).
Кстати по поводу статьи, для полного эффекта если будет время то добавьте в статью этот код(использование только CMSIS):
void DMA2_Stream4_IRQHandler(void)
{
GPIOD->ODR ^=((1>>12)|(1>>13)|(1>>14)|(1>>15));
}
uint16_t BUFF[100];
int main(void)
{
SystemInit();
//*********************GPIO*************************
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
GPIOA->MODER |= GPIO_MODER_MODER6; //ADC1 CH6 PA6
//*********************TIM3*************************
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // тактирование таймера
TIM3->PSC = 160-1; // предделитель
TIM3->ARR = 1000-1; // переполнение
TIM3->CR2 |= TIM_CR2_MMS_1; // output (TRGO)
TIM3->DIER |= TIM_DIER_UDE;
TIM3->CR1 |= TIM_CR1_CEN; //запуск счета
//********************DMA***************************
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
DMA2_Stream4->CR&=~ DMA_SxCR_CHSEL; // 000: channel 0 selected
DMA2_Stream4->PAR= (uint32_t)&ADC1->DR; //
DMA2_Stream4->M0AR=(uint32_t)&BUFF[0]; // Массив
DMA2_Stream4->NDTR=100; // Длина буфера
DMA2_Stream4->CR|= DMA_SxCR_MINC; // Инкремент адреса
DMA2_Stream4->CR|= DMA_SxCR_MSIZE_0; // 16 бит
DMA2_Stream4->CR|= DMA_SxCR_PSIZE_0; // 16 бит
DMA2_Stream4->CR|= DMA_SxCR_CIRC; // Непрерывный режим
DMA2_Stream4->CR&=~ DMA_SxCR_DIR; // 01: peripheral-to-Memory
DMA2_Stream4->CR|= DMA_SxCR_PL; // 11: Very high приоритет
DMA2_Stream4->CR|= DMA_SxCR_TCIE; // Transfer complete interrupt enable
DMA2_Stream4->CR|= DMA_SxCR_EN; // Вкл. передачу
NVIC_EnableIRQ(DMA2_Stream4_IRQn);
NVIC_SetPriority(DMA2_Stream4_IRQn,5);
//********************ADC1**CH6 PA6***************
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
ADC1->CR1 |=ADC_CR1_SCAN; // Scan mode
ADC1->CR2 |=(ADC_CR2_EXTSEL_3); //tim 3 (TRGO)
ADC1->SQR3 =6; //выбор канала PA6
ADC1->CR2 |=ADC_CR2_DMA; //разрешаем рабуту DMA
ADC1->CR2 |=ADC_CR2_DDS; //DMA disable selection (for single ADC mode)
ADC1->CR2 &=~ADC_CR2_CONT; //Continuous conversion
ADC1->CR2 |=ADC_CR2_EXTEN_0; //01: Trigger detection on the rising edge
ADC1->CR2 |= ADC_CR2_EOCS; //разрешаем прерывания
ADC1->CR2 |=ADC_CR2_ADON; //Вкл. переобразования
comments powered by Disqus