Привет всем.
Надо запускать ADC1 по таймеру, забирать результаты через DMA с получением какого-нибудь прерывания по заполнению буфера.
По мотивам доки и форумов написал:
CODE
volatile uint16_t adcBuffer[4096]; // <- the results are here
........................................
// ADC1 CH0 - PA0
void adcInit ( void )
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// Enable ADC3, DMA2 and GPIO clocks
RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE );
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1, ENABLE );
// DMA2 Stream0 channel0 configuration
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)&adcBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 4096;
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 );
// Enable the DMA Stream IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init ( &NVIC_InitStructure );
DMA_ITConfig ( DMA2_Stream0, DMA_IT_HT | DMA_IT_TC, ENABLE );
// Configure ADC1 Channel1 (PA0) pin as analog input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init ( GPIOA, &GPIO_InitStructure );
// ADC Common Init
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 );
// ADC1 Init
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 0;
ADC_Init ( ADC1, &ADC_InitStructure );
// ADC1 regular channel1 configuration
ADC_RegularChannelConfig ( ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles );
// Enable DMA request after last transfer (Single-ADC mode)
ADC_DMARequestAfterLastTransferCmd ( ADC1, ENABLE );
// Enable ADC1 DMA
ADC_DMACmd ( ADC1, ENABLE );
// Enable ADC1
ADC_Cmd ( ADC1, ENABLE );
// Инициализация TIM8, запускающего АЦП
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM8, ENABLE );
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// делитель 33600 - частота прерываний = 84MHz/33600= 2500 = 2.5 kHz
TIM_TimeBaseStructure.TIM_Prescaler = 33600-1;
// Период загружается в ARR - значение перезагрузки. Счётчик считает 0..ARR
TIM_TimeBaseStructure.TIM_Period = 2; //период 2 импульсов - частота 1250 гц
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit ( TIM8, &TIM_TimeBaseStructure );
TIM_SelectOutputTrigger ( TIM8, TIM_TRGOSource_Update );
} // adcInit
// Старт
void adcStart ( void )
{
TIM_Cmd ( TIM8, ENABLE );
} // adcStart
Из main-а вызываю adcInit, adcStart (т.е. запускаю таймер).
Результат - зависание на последней команде adcInit
TIM_SelectOutputTrigger ( TIM8, TIM_TRGOSource_Update );До запуска и всего прочего дело не доходит ....
Наверное в инициализации накосячил. Но не пойму где.
Пробовал ручной запуск, типа как здесь -
http://electronix.ru/forum/index.php?showtopic=104701 и в примерах от ST, т.е. вместо таймера команда
ADC_SoftwareStartConv(ADC1); // start ADC conversions
Не виснет, но в буфере нули ... В той теме пошли разговоры на религиозные темы - "регистры против библиотек и функций"

.
Да и нужен мне не ручной запуск, а по таймеру, с определённой частотой. Сам таймер работает, если убрать триггер и повесить прерывание, то оно исправно тикает с указанной частотой.
Я также пытался ставить ADC_SoftwareStartConv(ADC1); в прерывание таймера (метод а-ля AVR), получил пустой буфер с нулями.
На ноге PA0 (канал 0) висит потенциометр для отладки. От его положения соответственно ничего не зависит.
Также интересует, как установить прерывание DMA по заполнению буфера. Примеров не нашёл. В примере ADC3_DMA от ST (архив STM32F4xx_DSP_StdPeriph_Lib_V1.0.1) тупо выводит на дисплей 2-байтовую переменную, которую заполняет DMA. Но это ж некошерно ...
Помогите, кто может.
Спасибо.
PS. Плата STM32F4Discovery, проц STM32F4VGT6. Дисплей графический, ILI9320, работает по FSMC. С этим всё в норме.
Чтобы возить такого пассажира, необходим лимузин другого класса.
(с) Мария Эдуарда