Перейти к содержанию
    

STM32F415RG измерение линейки каналов - ADC overrun

Коллеги, пытаюсь запустить АЦП в режиме опроса нескольких каналов через DMA.

 

 

#include "stm32f4xx_rcc.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_adc.h"
#include "ADC.h"

#define min(a,B) ( ( (a) > (B) ) ? (B) : (a) )

// Длина выборки для скользящего среднего
#define SELECTION_SIZE 1

// Количество каналов которое опрашивается АЦП
// должно равнятся числу регистрируемых к опросу линий:
// ADC_RegularChannelConfig ( ADC1, ADC_Channel_10, rank++, ADC_SampleTime_480Cycles );
#define CHANNELS_NUMBER 8
#define BUFFER_SIZE ( SELECTION_SIZE * CHANNELS_NUMBER )

volatile uint16_t adc_buffer [ BUFFER_SIZE ];

int adc_init (  ) {

RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2, ENABLE );
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE );

GPIO_InitTypeDef GPIO_InitStruct;

GPIO_StructInit ( &GPIO_InitStruct );
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
GPIO_Init ( GPIOC, &GPIO_InitStruct );


RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2 , ENABLE );
DMA_InitTypeDef DMA_InitStructure;

DMA_DeInit(DMA2_Stream0);
DMA_StructInit ( &DMA_InitStructure );
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) adc_buffer;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC1 -> DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init ( DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd ( DMA2_Stream0 , ENABLE );

ADC_InitTypeDef 		ADC_InitStruct;
ADC_CommonInitTypeDef 	ADC_CommonInitStructure;

ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit( &ADC_CommonInitStructure );

ADC_StructInit ( &ADC_InitStruct );
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_NbrOfConversion = CHANNELS_NUMBER; //CHANNELS_NUMBER;
ADC_InitStruct.ADC_ExternalTrigConv = 0x00;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_Init ( ADC1, &ADC_InitStruct );

ADC_TempSensorVrefintCmd ( ENABLE );

ADC_Cmd ( ADC1, ENABLE );

uint8_t rank = 1;
ADC_RegularChannelConfig ( ADC1, ADC_Channel_10, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_11, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_12, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_13, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_14, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_15, 		rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_TempSensor,rank++, ADC_SampleTime_56Cycles );
ADC_RegularChannelConfig ( ADC1, ADC_Channel_Vrefint, 	rank++, ADC_SampleTime_56Cycles );

ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd ( ADC1 , ENABLE );

ADC_SoftwareStartConv ( ADC1 );
return 0;
}

int adc_moving_average_read_all_channels ( volatile uint16_t *channels, uint32_t n ) {
uint32_t sum;
int i, j;
int chn = min ( n, CHANNELS_NUMBER );

for ( i = 0; i < chn; i++ ) {
	sum = 0;
	for ( j = 0; j < SELECTION_SIZE; j++ ) {
		sum += adc_buffer [ i + j * ( CHANNELS_NUMBER ) ];
	}
	channels [ i ] = sum / SELECTION_SIZE;
}

return 0;
}

 

Проблема в том, что конвертация затыкается (глядя отладчиком данные не обновляются).

В ADC_SR устанавливается флаг ADC_SR_OVR.

Пытаюсь в прерывании по ADC_IT_OVR сбрасывать DMA и ADC (код ниже, на сколько понял из датащита), однако ничего не меняется.

 

if (  ADC1 ->SR & ADC_SR_OVR ) {

    ADC1 ->SR &= ~ADC_SR_OVR;

    DMA_Cmd ( DMA2_Stream0 , DISABLE );

    DMA2_Stream0 -> M0AR = adc_buffer;
    DMA2_Stream0 -> NDTR = BUFFER_SIZE;

    DMA_Cmd ( DMA2_Stream0 , ENABLE );
    ADC_SoftwareStartConv ( ADC1 );
    overruns_num++;
}

 

Частота тактирования модуля АЦП - 10,5 МГц ( SYSCLK = ( ( 16 МГЦ / 20 ) * 210 ) / 2, где 20, 210, 2 - PLL_M, PLL_N, PLL_P соответственно ).

Корректно ли я сбрасываю overrun ситуацию?

Отчего происходит оверран, когда приоритет DMA stream выставлен самый большой?

При этом число остальных DMA запросов в системе не велико: 1Гц 128 байт по SPI, 20 байт по USART.

 

В целом прошу совета как организоваться опрос.

Рассчитывал на то, что АЦП будет всегда формировать в памяти выборку для каждого канала для фильтрации скользящим среднем (увеличивая SELECTION_SIZE), а поток (таск) сервиса телеметрии будет эту выборку считывать ( adc_moving_average_read_all_channels () ).

Измерения носят диагностический характер и частота их опроса критичной не являются.

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...