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

STM32 ADC

Не могу понять как получать данные с двух каналов АЦП. Интересует ADC1. Регистр данных всего лишь один, хочу использовать regular режим. С одним каналом сейчас все работает, снимаю данные по таймеру. Где-то встречал упоминание что можно настроить DMA на работу с несколькими каналами АЦП. При этом определяется несколько буферов по количеству опрашиваемых каналов. Дальше АЦП (или DMA) как-то сам складывает семплы в свой буфер и генерит прерывание по заполнению буфера. Такой вариант был бы для меня идеальным. Может быть есть у кого примеры кода?

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


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

Где-то встречал упоминание что можно настроить DMA на работу с несколькими каналами АЦП. При этом определяется несколько буферов по количеству опрашиваемых каналов. Дальше АЦП (или DMA) как-то сам складывает семплы в свой буфер и генерит прерывание по заполнению буфера.
Нет, буфер один, общий. И АЦП складывает в него данные по очереди от первого, второго и т.д. каналов.

 

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

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();
}

 

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


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

Для таких целей я включаю режим continuous mode + auto-injection. Так можно сканировать до 5 каналов: 1 regular и 4 injected (там как раз 4 регистра ADC_JDRx).

Ну а если хочется через DMA, то вот пример кода:

#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 */
}

Изменено пользователем IgorKossak
[codebox]!!!

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


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

Для таких целей я включаю режим continuous mode + auto-injection.
Интересное решение. Таким образом можно двумя каналами DMA складывать два канала в два буфера. Спасибо, возьму на заметку.

 

Добавлено: Ан нет, нельзя - АЦП заведен только на один канал DMA.

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


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

Жаль что не получится загнать в 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.

post-11606-1330669337_thumb.jpg

 

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


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

Жаль что не получится загнать в DMA.
? Получится. Просто данные будут идти первый-второй-первый-второй...

Придется делать по прерываниям. И тут похоже уже нет разницы какой режим regular или injected.
Как нету? injected раскладывает каждый канал в свой регистр, regular - все валит в один.

 

Прерывание называется: End of conversion regular group. Правильно ли я понимаю что в обработчике прерывния я должен несколько раз прочитать регистр ADC_DR? И данные будут читаться в том же порядке что были заданы в регистрах ADC_SQR.
Конечно нет. Там нет никакого буфера. Поэтому если вы хотите по одному импульсу запуска преобразовывать оба канала - вам надо либо использовать regular group и DMA, либо использовать injected group и прерывание.

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


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

Т.е. при использовании regular group нет способа складывать данные в разные буферы? В свой буфер для каждого канала.

Хорошо буду добавлять injected.

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


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

Ну а если хочется через DMA, то вот пример кода:

 

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

Т.е. если читать один канал, он начитывает ~49000, если два канала, то в первом ~43000 во втором ~5000. А так все почти работает)

 

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);  
}

Изменено пользователем Vladimir Prokofiev

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


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

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

Т.е. если читать один канал, он начитывает ~49000, если два канала, то в первом ~43000 во втором ~5000. А так все почти работает)

Нужно снизить выходное сопротивление источников сигнала, поставить конденсаторы на землю. Или увеличить время выборки АЦП. Вход АЦП - конденсатор около 6 пф, который подключается по очереди к выходам двух источников сигнала, и при этом на себе переносит заряд из одного в другой. Чем больше частота переключения каналов тем больше средний результирующий ток и больше погрешность.

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


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

Нужно снизить выходное сопротивление источников сигнала, поставить конденсаторы на землю. Или увеличить время выборки АЦП. Вход АЦП - конденсатор около 6 пф, который подключается по очереди к выходам двух источников сигнала, и при этом на себе переносит заряд из одного в другой. Чем больше частота переключения каналов тем больше средний результирующий ток и больше погрешность.

Круто, спасибо, помогло!

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


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

STM32L151.

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

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


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

Колеги, помогите разобратся с 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 каналов

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


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

Для STM32L151 с "injected channels" можно так:

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);

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

Изменено пользователем spasbyspas
[codebox] для длинного кода!!!

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


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

 

spasbyspas , спасибо !

 

Заменил в своём коде

ADC1->CR1|=ADC_CR1_JDISCEN;

на

ADC1->CR1|=ADC_CR1_SCAN;

 

и всё заработало как я хотел ! Семплирую два injectid канала программным тригером, получаю за раз два значения в регистрах

JDR1 JDR2 , и одновременно с этим regular канал работает непрерывно с запросами DMA и одно другому не мешает !

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


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

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

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

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

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

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

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

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

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

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