Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 ADC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
uriy
Не могу понять как получать данные с двух каналов АЦП. Интересует ADC1. Регистр данных всего лишь один, хочу использовать regular режим. С одним каналом сейчас все работает, снимаю данные по таймеру. Где-то встречал упоминание что можно настроить DMA на работу с несколькими каналами АЦП. При этом определяется несколько буферов по количеству опрашиваемых каналов. Дальше АЦП (или DMA) как-то сам складывает семплы в свой буфер и генерит прерывание по заполнению буфера. Такой вариант был бы для меня идеальным. Может быть есть у кого примеры кода?
Сергей Борщ
QUOTE (uriy @ Mar 1 2012, 15:30) *
Где-то встречал упоминание что можно настроить DMA на работу с несколькими каналами АЦП. При этом определяется несколько буферов по количеству опрашиваемых каналов. Дальше АЦП (или DMA) как-то сам складывает семплы в свой буфер и генерит прерывание по заполнению буфера.
Нет, буфер один, общий. И АЦП складывает в него данные по очереди от первого, второго и т.д. каналов.

Готового кода у меня нет - я использую один канал, по его мотивам для двух каналов должно быть что-то такое:
CODE

extern "C" void DMA1_Channel1_IRQHandler();

class adc
{

public:
typedef uint8_t sample_t[2];
static size_t const ADC_BUFFER_SIZE = 128;
sample_t const * result() { Ready.wait(); return Ready; }
private:
void dma_handler();
friend void DMA1_Channel1_IRQHandler();
private:
typedef sample_t buffer_t[ADC_BUFFER_SIZE];
buffer_t Buffer[2]; // twice the buffer size, to get DMA "half ready" int in the middle
OS::message<sample_t *> Ready;
}

adc::adc()
{
// --------- ADC setup -----------
ADC1->CR1 = 0
| 15 * ADC_CR1_AWDCH_0 // Analog watchdog channel, unused channel
| 0 * ADC_CR1_EOCIE // EOC interrupt disabled
| 0 * ADC_CR1_AWDIE // Analog Watchdog interrupt disabled
| 0 * ADC_CR1_JEOCIE // Injected channels interrupt disabled
| 1 * ADC_CR1_SCAN // Scan mode, enabled
| 1 * ADC_CR1_AWDSGL // watchdog on a single (AWDCH) channel in scan mode
| 0 * ADC_CR1_JAUTO // Automatic injected group conversion
| 1 * ADC_CR1_DISCEN // Discontinuous mode on regular channels, enabled. One pulse=all conversions
| 0 * ADC_CR1_JDISCEN // Discontinuous mode on injected channels
| 1 * ADC_CR1_DISCNUM_0 // Discontinuous mode channel count = 2
| 0 * ADC_CR1_JAWDEN // Analog watchdog disabled on injected channels
| 0 * ADC_CR1_AWDEN // Analog watchdog disabled on regular channels
;
// calibrate ADC
ADC1->CR2 = 0
| 1 * ADC_CR2_ADON // A/D Converter ON
| 0 * ADC_CR2_CONT // Continuous Conversion disabled
| 1 * ADC_CR2_CAL // A/D Calibration
| 0 * ADC_CR2_RSTCAL // Reset Calibration
| 0 * ADC_CR2_DMA // Direct Memory access mode
| 0 * ADC_CR2_ALIGN // Data Alignment: right
| 0 * ADC_CR2_JEXTSEL_0 // External event for injected group: TIM2CC1
| 0 * ADC_CR2_JEXTTRIG // External Trigger Conversion mode for injected channels: disabled
| 0 * ADC_CR2_EXTSEL_0 // External Event for regular group: TIM2CC2
| 0 * ADC_CR2_EXTTRIG // External Trigger Conversion mode for regular channels: enabled
| 0 * ADC_CR2_JSWSTART // Start Conversion of injected channels
| 0 * ADC_CR2_SWSTART // Start Conversion of regular channels
| 0 * ADC_CR2_TSVREFE // Temperature Sensor and VREFINT disabled
;
/* default values
ADC1->SMPR1 = 0
| 0 * ADC_SMPR1_SMP10_0 // Channel 10 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP11_0 // Channel 11 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP12_0 // Channel 12 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP13_0 // Channel 13 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP14_0 // Channel 14 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP15_0 // Channel 15 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP16_0 // Channel 16 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP17_0 // Channel 17 Sample time - 1.5 ticks
;
*/
ADC1->SMPR2 = 0
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP0_0 // Channel 0 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP1_0 // Channel 1 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP2_0 // Channel 2 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP3_0 // Channel 3 Sample time
| 0 * ADC_SMPR2_SMP4_0 // Channel 4 Sample time - 1.5 ticks
| 0 * ADC_SMPR2_SMP5_0 // Channel 5 Sample time - 1.5 ticks
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP6_0 // Channel 6 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP7_0 // Channel 7 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP8_0 // Channel 8 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP9_0 // Channel 9 Sample time
;
/* default values
ADC1->JOFR1 = 0; // Injected channel offset
ADC1->JOFR2 = 0;
ADC1->JOFR3 = 0;
ADC1->JOFR4 = 0;
ADC1->HTR = 0xFFF;
ADC1->LTR = 0;
*/
ADC1->SQR1 = 0
| 0 * ADC_SQR1_SQ13_0 // 13th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ14_0 // 14th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ15_0 // 15th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ16_0 // 16th conversion in regular sequence channel: default
| 1 * ADC_SQR1_L_0 // Regular channel sequence length: 2
;
/* default
ADC1->SQR2 = 0
| 0 * ADC_SQR2_SQ12_0 // 12th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ11_0 // 11th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ10_0 // 10th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ9_0 // 9th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ8_0 // 8th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ7_0 // 7th conversion in regular sequence channel: default
;
*/
ADC1->SQR3 = 0
| 0 * ADC_SQR3_SQ6_0 // 6th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ5_0 // 5th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ4_0 // 4th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ3_0 // 3rd conversion in regular sequence channel: default
| 8 * ADC_SQR3_SQ2_0 // 2nd conversion in regular sequence channel: ADC_IN8
| 9 * ADC_SQR3_SQ1_0 // 1st conversion in regular sequence channel: ADC_IN9
;
/* default value
ADC1->JSQR = 0;
*/

// --------- DMA setup -----------
DMA1_Channel1->CPAR = uintptr_t(((uint8_t *)&ADC1->DR) + 1); // hi byte of left-aligned result
DMA1_Channel1->CMAR = uintptr_t(Buffer[0]);
DMA1_Channel1->CNDTR = sizeof(Buffer) / sizeof(Buffer[0][0]);
DMA1_Channel1->CCR = 0
| 1 * DMA_CCR1_EN // Channel enable
| 1 * DMA_CCR1_TCIE // Transfer complete interrupt enable
| 1 * DMA_CCR1_HTIE // Half Transfer interrupt enable
| 0 * DMA_CCR1_TEIE // Transfer error interrupt enable
| 0 * DMA_CCR1_DIR // Data transfer direction: Peripheral->Memory
| 1 * DMA_CCR1_CIRC // Circular mode
| 0 * DMA_CCR1_PINC // Peripheral increment mode
| 1 * DMA_CCR1_MINC // Memory increment mode
| 0 * DMA_CCR1_PSIZE_0 // Peripheral size: 8 bits
| 0 * DMA_CCR1_MSIZE_0 // Memory size: 8 bits
| 0 * DMA_CCR1_PL_0 // Channel Priority level: lowest, conversion frequency is low enough
| 0 * DMA_CCR1_MEM2MEM // Memory to memory mode disabled
;

// wait until calibration is complete
while(ADC1->CR2 & ADC_CR2_CAL)
;
// start conversions
ADC1->CR2 = 0
| 1 * ADC_CR2_ADON // A/D Converter ON
| 0 * ADC_CR2_CONT // Continuous Conversion disabled
| 0 * ADC_CR2_CAL // A/D Calibration
| 0 * ADC_CR2_RSTCAL // Reset Calibration
| 1 * ADC_CR2_DMA // Direct Memory access enabled
| 1 * ADC_CR2_ALIGN // Data Alignment: left
| 3 * ADC_CR2_JEXTSEL_0 // External event for injected group: TIM2CC1
| 0 * ADC_CR2_JEXTTRIG // External Trigger Conversion mode for injected channels: disabled
| 3 * ADC_CR2_EXTSEL_0 // External Event for regular group: TIM2CC2
| 1 * ADC_CR2_EXTTRIG // External Trigger Conversion mode for regular channels: enabled
| 0 * ADC_CR2_JSWSTART // Start Conversion of injected channels
| 0 * ADC_CR2_SWSTART // Start Conversion of regular channels
| 0 * ADC_CR2_TSVREFE // Temperature Sensor and VREFINT disabled
;
}


INLINE void adc::dma_handler()
{
if(DMA1->ISR & DMA_ISR_HTIF1)
{
Ready = Buffer[0];
Ready.send_isr();
DMA1->IFCR = DMA_IFCR_CHTIF1;
}
if(DMA1->ISR & DMA_ISR_TCIF1)
{
Ready = Buffer[1];
Ready.send_isr();
DMA1->IFCR = DMA_IFCR_CTCIF1;
}
}

extern "C" void DMA1_Channel1_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
ADC.dma_handler();
}

scifi
Для таких целей я включаю режим continuous mode + auto-injection. Так можно сканировать до 5 каналов: 1 regular и 4 injected (там как раз 4 регистра ADC_JDRx).
Ну а если хочется через DMA, то вот пример кода:
CODE
#define AVERAGING 128
#define ADC_NCHANNELS 6

static uint16_t volatile buf[AVERAGING][ADC_NCHANNELS];

void
adc_init(void)
{
/* enable clocking of ADC1, PORT A */
RCC_APB2ENR |= 0x00000204;
/* configure PA0,1,2,3,4,6 as analog inputs */
GPIOA_CRL &= 0xF0F00000;
/* enable clocking of DMA1 */
REGBIT(RCC_AHBENR, 0) = 1;
ADC1_CR2 = 0; /* turn ADC off */
timer_delay(2); /* wait at least 2 ADC clock cycles before calibration */
ADC1_CR1 = (1 << 8); /* enable scan mode */
ADC1_CR2 = (1 << 23) /* enable Vrefint */
| (1 << 8) /* enable DMA mode */
| (1 << 1) /* enable continuous conversion mode */
| (1 << 0);/* switch ADC on */
ADC1_SMPR2 = 0x3FFFFFFF; /* sample time 239.5 cycles for ch. 0-9 */
/* conversion sequence: ch. 0, 1, 2, 3, 6, 17 */
ADC1_SQR3 = (0 << 0) | (1 << 5) | (2 << 10)
| (3 << 15) | (6 << 20) | (17 << 25);
ADC1_SQR1 = ((ADC_NCHANNELS - 1) << 20); /* sequence length */
REGBIT(ADC1_CR2, 2) = 1; /* start ADC calibration */
while (REGBIT(ADC1_CR2, 2) != 0)
{
/* wait for calibration to complete */
}
DMA1_CNDTR(1) = AVERAGING * ADC_NCHANNELS;
DMA1_CPAR(1) = (uint32_t)&ADC1_DR;
DMA1_CMAR(1) = (uint32_t)buf;
DMA1_CCR(1) = (1 << 10) /* memory size 16 bits */
| (1 << 8) /* peripheral size 16 bits */
| (1 << 7) /* memory increment mode */
| (1 << 5) /* circular mode */
| (1 << 1) /* transfer complete interrupt enable */
| (1 << 0);/* channel enable */
REGBIT(ADC1_CR2, 0) = 1; /* start ADC conversions */
}
Сергей Борщ
QUOTE (scifi @ Mar 1 2012, 16:31) *
Для таких целей я включаю режим continuous mode + auto-injection.
Интересное решение. Таким образом можно двумя каналами DMA складывать два канала в два буфера. Спасибо, возьму на заметку.

Добавлено: Ан нет, нельзя - АЦП заведен только на один канал DMA.
uriy
Жаль что не получится загнать в DMA. Придется делать по прерываниям. И тут похоже уже нет разницы какой режим regular или injected. Только не могу понять одну вещь. Прерывание называется: End of conversion regular group. Правильно ли я понимаю что в обработчике прерывния я должен несколько раз прочитать регистр ADC_DR? И данные будут читаться в том же порядке что были заданы в регистрах ADC_SQR.
-----------------
Что-то не выходит. Делаю следующим образом:
Имеется обработчик прерываний таймера - 8 КГц.
В нем запускаю
Код
val_1 = ADC_GetConversionValue(ADC1);
val_2 = ADC_GetConversionValue(ADC1);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

В val_1 и val_2 получаю одинаковые значения. Данные соответствуют выводу ADC_Channel_11. Они корректы, я их использую для декодирования DTMF.

Инициализация ADC
Код
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channels configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_28Cycles5);    
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_28Cycles5);

Многие не доверяют библиотекам ST поэтому привожу картинку из KEIL.
Нажмите для просмотра прикрепленного файла
Сергей Борщ
QUOTE (uriy @ Mar 2 2012, 07:27) *
Жаль что не получится загнать в DMA.
? Получится. Просто данные будут идти первый-второй-первый-второй...
QUOTE (uriy @ Mar 2 2012, 07:27) *
Придется делать по прерываниям. И тут похоже уже нет разницы какой режим regular или injected.
Как нету? injected раскладывает каждый канал в свой регистр, regular - все валит в один.

QUOTE (uriy @ Mar 2 2012, 07:27) *
Прерывание называется: End of conversion regular group. Правильно ли я понимаю что в обработчике прерывния я должен несколько раз прочитать регистр ADC_DR? И данные будут читаться в том же порядке что были заданы в регистрах ADC_SQR.
Конечно нет. Там нет никакого буфера. Поэтому если вы хотите по одному импульсу запуска преобразовывать оба канала - вам надо либо использовать regular group и DMA, либо использовать injected group и прерывание.
uriy
Т.е. при использовании regular group нет способа складывать данные в разные буферы? В свой буфер для каждого канала.
Хорошо буду добавлять injected.
Vladimir Prokofiev
Цитата
Ну а если хочется через DMA, то вот пример кода:


Я попробовал повторить это через библиотечные вызовы, получилось что один канал ацп влияет на другой. Почему так происходит?
Т.е. если читать один канал, он начитывает ~49000, если два канала, то в первом ~43000 во втором ~5000. А так все почти работает)

CODE
void APADC_Init( void ){
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

/* DMA2 Stream0 channel2 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_2;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC3ConvertedValues;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 2;
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);

/* Configure ADC3 Channel7 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &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);

/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 2;
//ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC3, &ADC_InitStructure);

/* ADC3 regular channel7 configuration *************************************/
ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 2, ADC_SampleTime_3Cycles);

/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

/* Enable ADC3 DMA */
ADC_DMACmd(ADC3, ENABLE);

/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);

ADC_SoftwareStartConv(ADC3);
}
maksimp
Цитата(Vladimir Prokofiev @ Apr 9 2012, 18:57) *
Я попробовал повторить это через библиотечные вызовы, получилось что один канал ацп влияет на другой. Почему так происходит?
Т.е. если читать один канал, он начитывает ~49000, если два канала, то в первом ~43000 во втором ~5000. А так все почти работает)

Нужно снизить выходное сопротивление источников сигнала, поставить конденсаторы на землю. Или увеличить время выборки АЦП. Вход АЦП - конденсатор около 6 пф, который подключается по очереди к выходам двух источников сигнала, и при этом на себе переносит заряд из одного в другой. Чем больше частота переключения каналов тем больше средний результирующий ток и больше погрешность.
Vladimir Prokofiev
Цитата(maksimp @ Apr 9 2012, 21:10) *
Нужно снизить выходное сопротивление источников сигнала, поставить конденсаторы на землю. Или увеличить время выборки АЦП. Вход АЦП - конденсатор около 6 пф, который подключается по очереди к выходам двух источников сигнала, и при этом на себе переносит заряд из одного в другой. Чем больше частота переключения каналов тем больше средний результирующий ток и больше погрешность.

Круто, спасибо, помогло!
MiklPolikov
STM32L151.
Ни как не могу понять, чем отличаются Regular и Injected каналы АЦП ? Включил канал 0 Regular , работает . Физически он соответствует ноге ADC_IN0. А на каких ногах Injected каналы ?
MiklPolikov
Колеги, помогите разобратся с injected каналами в STM32L151

Нужно не часто получать значения по двум каналам. Нстраиваю injected каналы как показано ниже, и жду что после выставления бита
JSWSTART в регистрах JDR4 JDR3 появятся значения каналов 0 и 8.

Вместо этого значение почему-то появляется в регистре JDR1 , в остальных JDR нули.
Причём,
Если сделать так ADC1->JSQR|=(0<<10)|(8<<15); , то в JDR1 ,будет значение канала 8.
Если сделать так ADC1->JSQR|=(8<<10)|(0<<15); , то в JDR1 будет значение канала 0

То есть, работает так, как будно в цепочке только одно преобразование. Но ведь их два , указано и в битах ADC_JSQR_JL, и в битах
ADC_CR1_DISCNUM . Чего я не понимаю ?



Код
ADC1->CR1|=ADC_CR1_JDISCEN;//включаем Discontinuous mode , что бы преобразовывалась вся цепочка за раз
ADC1->CR1|=ADC_CR1_DISCNUM_0;//2 преобразования в цепочке
  
ADC1->JSQR|=ADC_JSQR_JL_0; //2 преобразования в цепочке injectid каналов
ADC1->JSQR|=(0<<10)|(8<<15); //injected каналы 1 и 8

......................

ADC->CR2|=ADC_CR2_JSWSTART; //запускаем преобразование injectid каналов
spasbyspas
Для STM32L151 с "injected channels" можно так:
CODE
void ADC_Config( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStruct;

//+ Enable The HSI (16Mhz)
RCC_HSICmd(ENABLE);
//+ Check that HSI oscillator is ready
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

//+ Enable the GPIOB Clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
//+ Configure PB.0 PB.1(ADC Channel8 and 9) in analog mode
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* ADC1 Configuration ------------------------------------------------------*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* ADC1 DeInit */
ADC_DeInit(ADC1);

ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInit(&ADC_CommonInitStruct);

/* ADC1 Configuration of channel8 and channel9 */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 2;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_InjectedSequencerLengthConfig(ADC1, 2);
//+ ADC1 Injected Channel Config
ADC_InjectedChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_24Cycles);
ADC_InjectedChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_24Cycles);

//+ Enables the ADC1 Power Down during Delay
ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
//+ Delay until the converted data has been read
ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_None);

//+ Enable ADC1
ADC_Cmd(ADC1, ENABLE);

//+ Wait until the ADC1 is ready
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET);
}


.....................
//запускаем преобразование "injected" каналов
while(ADC_GetSoftwareStartInjectedConvCmdStatus(ADC1) == SET);
ADC_SoftwareStartInjectedConv(ADC1);

//+ Wait until ADC Channel 8 end of conversion
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC) == RESET);

adc_ch0 = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
adc_ch1 = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);

.....................
MiklPolikov

spasbyspas , спасибо !

Заменил в своём коде
ADC1->CR1|=ADC_CR1_JDISCEN;
на
ADC1->CR1|=ADC_CR1_SCAN;

и всё заработало как я хотел ! Семплирую два injectid канала программным тригером, получаю за раз два значения в регистрах
JDR1 JDR2 , и одновременно с этим regular канал работает непрерывно с запросами DMA и одно другому не мешает !
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.