CODE
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_adc.h"
#include "ADC.h"
#define min(a,
( ( (a) > (
) ? (
: (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;
}
#include "stm32f4xx_dma.h"
#include "stm32f4xx_adc.h"
#include "ADC.h"
#define min(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++;
}
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 () ).
Измерения носят диагностический характер и частота их опроса критичной не являются.