stm32f103 Dual mode ADC+DMA по таймеру4

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение КРАМ »

[uquote="kote52",url="/forum/viewtopic.php?p=4331321#p4331321"]куда именно[/uquote]
:shock:
Стесняюсь спросить - а вы вообще рефмануал открывали?
В ДМА совсем немного регистров.
Например в F0 для второго канала DMA это будет DMA1_Channel2->CNDTR.
Например в F4 для первого потока второго контроллера DMA это будет DMA2_Stream1->NDTR.
Реклама
kote52
Встал на лапы
Сообщения: 120
Зарегистрирован: Пт мар 19, 2021 08:58:45

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение kote52 »

[uquote="КРАМ",url="/forum/viewtopic.php?p=4331331#p4331331"]Стесняюсь спросить - а вы вообще рефмануал открывали?
В ДМА совсем немного регистров.
Например в F0 для второго канала DMA это будет DMA1_Channel2->CNDTR.
Например в F4 для первого потока второго контроллера DMA это будет DMA2_Stream1->NDTR.[/uquote]
Нет, но понял к чему вы ведете, эти регистры хрянят число, и оно по кругу изменяется до переполнения и опять обнуляется. Читал где то, уже не помню. Будет читать по DMA что к чему)
Реклама
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение КРАМ »

[uquote="kote52",url="/forum/viewtopic.php?p=4331342#p4331342"]оно по кругу изменяется до переполнения[/uquote]
Нет, оно ДЕКРЕМЕНТИРУЕТСЯ до нуля. Для однократного режима. В непрерывном режиме оно автоматически восстанавливается одновременно с автоматическим перезапуском ДМА.
Рефмануал надо читать полностью, а не только про ДМА. Значительная часть сопряженной информации находится в других модулях. Так при работе АЦП с ДМА нужно в модуле АЦП включить реквесты от АЦП, например... Помимо выбора канала или стрима работающего с реквестами АЦП в модуле ДМА.
kote52
Встал на лапы
Сообщения: 120
Зарегистрирован: Пт мар 19, 2021 08:58:45

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение kote52 »

Продолжаю ковыряться, плюнул я CUBE IDE... решил сразу с CMSIS начать, т.к. в кубе много не понятного для меня... и вообще держать в голове байду от куба не хочется... Вообщем поизучал и настроил через CMSIS - RCC, системный таймер, таймер 4 с тем же конфигом, порты ввода/вывода, а вот с ацп+дма у меня проблемы начались.... Точнее с ацп2, при отладке я не вижу в регистрах CR2 установок которые я задал((( Ставлю 0110: Dual regular simultaneous mode only по факту вижу 0000. Гляньте профессиональным взглядом что не так делаю или я может чего не дочитал в референс мануале? Вообщем пытяюсь запустить парный режим преобразования ацп + дма по таймеру 4.
Спойлер

Код: Выделить всё

void DMA1_Init(void) {
	SET_BIT(RCC->AHBENR, RCC_AHBENR_DMA1EN); //(1)Включение тактирования DMA1
	DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR); //Задаем адрес периферийного устройства
	DMA1_Channel1->CMAR = (uint32_t)ADC_Data; //Задаем адрес в памяти, куда будем кидать данные.
	DMA1_Channel1->CNDTR = 1; //Настроим количество данных для передачи. После каждого периферийного события это значение будет уменьшаться.
	MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_PL_Msk, 0b00 << DMA_CCR_PL_Pos); //(00) Зададим приоритет канала на LOW
	CLEAR_BIT(DMA1_Channel1->CCR, DMA_CCR_DIR); //(0) Чтение будем осуществлять с периферии
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_CIRC); //(1) Настроим DMA в Circular mode
	MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_PSIZE_Msk, 0b10 << DMA_CCR_PSIZE_Pos); // (10) Размер данных периферийного устройства 32 бит
	MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_MSIZE_Msk, 0b10 << DMA_CCR_MSIZE_Pos); //(10) Размер данных в памяти 32 бит
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_TCIE); //(1)Включим прерывание по полной передаче
	CLEAR_BIT(DMA1_Channel1->CCR, DMA_CCR_HTIE); //(0)Отключим прерывание по половинной передаче
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_TEIE); //(1)Включим прерывание по ошибке передачи.
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_MINC); //(1)Включим инкрементирование памяти
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_EN); //(1) DMA Вкл
}


void ADC1_Init(void) {
	
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_ADC1EN); //Включение тактирования ADC1
	
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN); //Включение тактирования PORT А
	//Настраиваем 3 порт
	MODIFY_REG(GPIOC->CRL, GPIO_CRL_CNF3_Msk, 0b00 << GPIO_CRL_CNF3_Pos); //(00) Analog mode
	MODIFY_REG(GPIOC->CRL, GPIO_CRL_MODE3_Msk, 0b00 << GPIO_CRL_MODE3_Pos); //(00) Input mode (reset state)

	/*11.12 ADC registers(страница 237)*/
	//11.12.2 ADC control register 1 (ADC_CR1)(страница 238)
	CLEAR_BIT(ADC1->CR1, ADC_CR1_EOCIE);	//(0) Вкл/Вылк прерывания по окончанию преобразования
	CLEAR_BIT(ADC1->CR1, ADC_CR1_AWDIE);	//(0) Прерывания от Ватчдога
	CLEAR_BIT(ADC1->CR1, ADC_CR1_JEOCIE);	//(0) Прерывания от инжекктированых каналов
	SET_BIT(ADC1->CR1, ADC_CR1_SCAN);		//(1) Вкл/Выкл режима сканирования
	
	/* Примечание:
	* Прерывание EOC или JEOC генерируется только в конце преобразования последнего канала, 
	* если установлен соответствующий бит EOCIE или JEOCIE.*/
	CLEAR_BIT(ADC1->CR1, ADC_CR1_AWDSGL);	//(0) Analog watchdog enabled on all channels
	CLEAR_BIT(ADC1->CR1, ADC_CR1_JAUTO);	//(0) Automatic injected group conversion disabled
	CLEAR_BIT(ADC1->CR1, ADC_CR1_DISCEN);	//(0) Discontinuous mode on regular channels disabled
	CLEAR_BIT(ADC1->CR1, ADC_CR1_JDISCEN);	//(0) Discontinuous mode on injected channels disabled
	MODIFY_REG(ADC1->CR1, ADC_CR1_DUALMOD_Msk, 0b0110 << ADC_CR1_DUALMOD_Pos); //0110: Dual regular simultaneous mode only
	CLEAR_BIT(ADC1->CR1, ADC_CR1_JAWDEN);	//(0) Analog watchdog disabled on injected channels
	CLEAR_BIT(ADC1->CR1, ADC_CR1_AWDEN);	//(0) Analog watchdog disabled on regular channels
	
	/*11.12.3 ADC control register 2 (ADC_CR2)(страница 240)*/
	SET_BIT(ADC1->CR2, ADC_CR2_ADON); //(1) Запустить АЦП
	
	/* Примечание:
	* Если в этот же момент изменяется какой-либо другой бит в этом регистре, 
	* кроме ADON, то конверсия не запускается. 
	* Это сделано для предотвращения ошибочного преобразования.*/
	CLEAR_BIT(ADC1->CR2, ADC_CR2_CONT);	//(0) Continuous conversion mode(непрерывные преобразования) 
	SET_BIT(ADC1->CR2, ADC_CR2_CAL);	//(1) Enable calibration (Калибровка)
	
	/*Примечание:
    * Этот бит устанавливается программой для запуска калибровки. 
    * Он сбрасывается аппаратно после завершения калибровки.*/
	while (READ_BIT(ADC1->CR2, ADC_CR2_CAL)) ;//Подождем окончания калибровки
	Delay_ms(1); //Задержка
	
	SET_BIT(ADC1->CR2, ADC_CR2_DMA);		//(1) режима использования DMA
	SET_BIT(ADC1->CR2, ADC_CR2_ALIGN);		//(1) Выравнивание по левому краю
	MODIFY_REG(ADC1->CR2, ADC_CR2_EXTSEL_Msk, 0b101 << ADC_CR2_EXTSEL_Pos); //101: Timer4 CC4
	SET_BIT(ADC1->CR2, ADC_CR2_EXTTRIG);	//(1) Conversion on external event disabled
	SET_BIT(ADC1->CR2, ADC_CR2_SWSTART);	//(1) Начать преобразование
	CLEAR_BIT(ADC1->CR2, ADC_CR2_TSVREFE);	//(0)Temperature sensor and VREFINT channel enabled
	
	// 11.12.5 ADC sample time register 2 (ADC_SMPR2)(страница 245)
	MODIFY_REG(ADC1->SMPR2, ADC_SMPR2_SMP3_Msk, 0b000 << ADC_SMPR2_SMP3_Pos); //(000) - 1.5 cycles 
	
	// 11.12.9 ADC regular sequence register 1 (ADC_SQR1)(страница 247)
	MODIFY_REG(ADC1->SQR1, ADC_SQR1_L_Msk, 0b0000 << ADC_SQR1_L_Pos); //1 преобразования - т.к. 1 преобразования
	
	// 11.12.11 ADC regular sequence register 3 (ADC_SQR3)(страница 249)
	MODIFY_REG(ADC1->SQR3, ADC_SQR3_SQ1_Msk, 3 << ADC_SQR3_SQ1_Pos); //линии ввода, которую нужно подключить к каналу x группы обычных каналов	
}

void ADC2_Init(void) {
		
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_ADC2EN); //Включение тактирования ADC2
	
	//Настраиваме 4 порт
	MODIFY_REG(GPIOC->CRL, GPIO_CRL_CNF4_Msk, 0b00 << GPIO_CRL_CNF4_Pos); //(00) Analog mode
	MODIFY_REG(GPIOC->CRL, GPIO_CRL_MODE4_Msk, 0b00 << GPIO_CRL_MODE4_Pos); //(00) Input mode (reset state)
	
	/*11.12 ADC registers(страница 237)*/
	//11.12.2 ADC control register 1 (ADC_CR1)(страница 238)
	
	CLEAR_BIT(ADC2->CR1, ADC_CR1_EOCIE); //(0) Вкл/Вылк прерывания по окончанию преобразования
	CLEAR_BIT(ADC2->CR1, ADC_CR1_AWDIE); //(0) Прерывания от Ватчдога
	CLEAR_BIT(ADC2->CR1, ADC_CR1_JEOCIE); //(0) Прерывания от инжекктированых каналов
	SET_BIT(ADC2->CR1, ADC_CR1_SCAN); //(1) Вкл/Выкл режима сканирования
	
	/* Примечание:
	* Прерывание EOC или JEOC генерируется только в конце преобразования последнего канала, 
	* если установлен соответствующий бит EOCIE или JEOCIE.*/
	
	CLEAR_BIT(ADC2->CR1, ADC_CR1_AWDSGL); //(0) Analog watchdog enabled on all channels
	CLEAR_BIT(ADC2->CR1, ADC_CR1_JAUTO); //(0) Automatic injected group conversion disabled
	CLEAR_BIT(ADC2->CR1, ADC_CR1_DISCEN); //(0) Discontinuous mode on regular channels disabled
	CLEAR_BIT(ADC2->CR1, ADC_CR1_JDISCEN); //(0) Discontinuous mode on injected channels disabled
	MODIFY_REG(ADC2->CR1, ADC_CR1_DUALMOD_Msk, 0b0110 << ADC_CR1_DUALMOD_Pos); //0110: Dual regular simultaneous mode only
	CLEAR_BIT(ADC2->CR1, ADC_CR1_JAWDEN); //(0) Analog watchdog disabled on injected channels
	CLEAR_BIT(ADC2->CR1, ADC_CR1_AWDEN); //(0) Analog watchdog disabled on regular channels
	
	/*11.12.3 ADC control register 2 (ADC_CR2)(страница 240)*/
	SET_BIT(ADC2->CR2, ADC_CR2_ADON); //(1) Запустить АЦП
	
	/* Примечание:
	* Если в этот же момент изменяется какой-либо другой бит в этом регистре, 
	* кроме ADON, то конверсия не запускается. 
	* Это сделано для предотвращения ошибочного преобразования.*/
	CLEAR_BIT(ADC2->CR2, ADC_CR2_CONT); //(0) Continuous conversion mode(непрерывные преобразования) 
	SET_BIT(ADC2->CR2, ADC_CR2_CAL); //(1) Enable calibration (Калибровка)
	
	/*Примечание:
    * Этот бит устанавливается программой для запуска калибровки. 
    * Он сбрасывается аппаратно после завершения калибровки.*/
	while (READ_BIT(ADC2->CR2, ADC_CR2_CAL)) ;//Подождем окончания калибровки
	Delay_ms(1); //Задержка 
	
	CLEAR_BIT(ADC2->CR2, ADC_CR2_ALIGN); //(0) Выравнивание по правому краю
	/* Примечание:
	* В двойном режиме при настройке преобразования для запуска внешним событием пользователь должен установить триггер 
	* только для ведущего(ADC1) и установить программный триггер для ведомого (ADC2), чтобы предотвратить ложные триггеры для запуска 
	* нежелательного преобразования ведомого. Однако внешние триггеры должны быть включен как на ведущем, так и на ведомом АЦП.*/
	MODIFY_REG(ADC2->CR2, ADC_CR2_EXTSEL_Msk, 0b111 << ADC_CR2_EXTSEL_Pos); // 111: бит SWSTART регистра ADC_CR2
	SET_BIT(ADC2->CR2, ADC_CR2_EXTTRIG); //(1) Conversion on external event disabled
	SET_BIT(ADC2->CR2, ADC_CR2_SWSTART); //(1) Начать преобразование
	CLEAR_BIT(ADC2->CR2, ADC_CR2_TSVREFE); //(0)Temperature sensor and VREFINT channel enabled
	
	// 11.12.5 ADC sample time register 2 (ADC_SMPR2)(страница 245)
	MODIFY_REG(ADC2->SMPR2, ADC_SMPR2_SMP4_Msk, 0b000 << ADC_SMPR2_SMP4_Pos); //(000) - 1.5 cycles 
	
	// 11.12.9 ADC regular sequence register 1 (ADC_SQR1)(страница 247)
	MODIFY_REG(ADC2->SQR1, ADC_SQR1_L_Msk, 0b0000 << ADC_SQR1_L_Pos); //1 преобразования - т.к. 1 преобразования
	
	// 11.12.11 ADC regular sequence register 3 (ADC_SQR3)(страница 249)
	MODIFY_REG(ADC2->SQR3, ADC_SQR3_SQ1_Msk, 4 << ADC_SQR3_SQ1_Pos); //линии ввода, которую нужно подключить к каналу x группы обычных каналов
}
Реклама
Эиком - электронные компоненты и радиодетали
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение Dimon456 »

kote52, я не силен в этом, может быть и можно посадить ADC1 на T4_CC4, но как выходит из моих экспериментов с f030, нужен бит Tx_TRGO, а он только у TIM3.

То есть в ADC1 в External Trigger Conversion нужно поставить Timer 3 Trigger Out event,
а в TIM3 в Trigger Event Selection нужно поставить Update Event.

или в регитрах ADC1 ищите бит ADC_ExternalTrigConv_T3_TRGO, а в TIM3->CR2 бит TIM_TRGOSource_Update.
Реклама
kote52
Встал на лапы
Сообщения: 120
Зарегистрирован: Пт мар 19, 2021 08:58:45

Re: stm32f103 Dual mode ADC+DMA по таймеру4

Сообщение kote52 »

[uquote="Dimon456",url="/forum/viewtopic.php?p=4352613#p4352613"]kote52, я не силен в этом, может быть и можно посадить ADC1 на T4_CC4, но как выходит из моих экспериментов с f030, нужен бит Tx_TRGO, а он только у TIM3.

То есть в ADC1 в External Trigger Conversion нужно поставить Timer 3 Trigger Out event,
а в TIM3 в Trigger Event Selection нужно поставить Update Event.

или в регитрах ADC1 ищите бит ADC_ExternalTrigConv_T3_TRGO, а в TIM3->CR2 бит TIM_TRGOSource_Update.[/uquote]
Приветствую Dimon456! Я понял о вашем подходе. Это один из методов как можно прицепиться к таймеру. Свой пытаю как запуск в режиме сравнения на определённом канале таймера 4. Таймер будет переполнятся, а сравнение будет происходить в момент обнуления и «толкать» АЦП.

и там есть регистры:
ADC->CR2
EXTSEL[2:0]: выбор внешнего события для срабатывания триггера запуска оцифровки обычных каналов. Для ADC1,2:
000: Timer1 CC1
001: Timer1 CC2
010: Timer1 CC3
011: Timer2 CC2
100: Timer3 TRGO
101: Timer4 CC4 //выбран
110: EXTI line11/TIM8_TRGO
111: бит SWSTART регистра ADC_CR2

Вот кое что почитав нашел - что, хоть сэмплирования и по таймеру, но первый старт вручную... т.е.

Код: Выделить всё

ADC1->CR2 |=ADC_CR2_SWSTART;
SET_BIT(ADC1->CR2, ADC_CR2_EXTTRIG);
ADC2->CR2 |=ADC_CR2_SWSTART;
SET_BIT(ADC2->CR2, ADC_CR2_EXTTRIG);
так по кирпичику можеи и дойду :))
Реклама
Ответить

Вернуться в «ARM»