Goofy 0 1 февраля, 2014 Опубликовано 1 февраля, 2014 (изменено) · Жалоба Коллеги, пытаюсь запустить АЦП в режиме опроса нескольких каналов через 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 () ). Измерения носят диагностический характер и частота их опроса критичной не являются. Изменено 1 февраля, 2014 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Goofy 0 4 февраля, 2014 Опубликовано 4 февраля, 2014 · Жалоба Вопрос решился сменой Stream"а, который АЦП делил с SPI. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться