2024-09-22 09:21 AM - edited 2024-09-23 08:04 PM
I'm trying to acquire data from 3 sensor simultaneously using Triple Mode. Im using TIM 2 TRGO as a trigger for starting ADC. my data are getting correctly generated in the respective DR registers of ADCs but not in Common register ADC->CDR where it is supposed to have the data
void adc_init(void){
// Enable clock
RCC -> AHB1ENR |= (1U << 0); //Clock For GPIOA
RCC -> AHB1ENR |= (1U << 22); //Clock for DMA2
RCC -> APB2ENR |= (1U << 8); //Clock for ADC1
RCC -> APB2ENR |= (1U << 9); //Clock for ADC2
RCC -> APB2ENR |= (1U << 10); //Clock for ADC3
//Config GPIO
GPIOA -> MODER |= (1U << 2) | (1U <<3); //Analog mode PA1
GPIOA -> MODER |= (1U << 4) | (1U <<5); //Analog mode PA2
GPIOA -> MODER |= (1U << 6) | (1U << 7); //Analog mode PA3
//Triple Mode ADC1, ADC2, ADC3
ADC->CCR |= (0x0016); // Triple Regular Simultaneous Mode
//ADC1 Config
//Select channel
ADC1 -> SQR3 &= ~( (1U << 1) | (1U << 2) | (1U << 3) | (1U << 4));
ADC1 -> SQR3 |= (1U << 0);
ADC1->SMPR2 |= (1U << 0);
ADC1 -> CR2 |= (1U << 28); //Enable External trigger
ADC1 -> CR2 &= ~(1U << 29);
ADC1 -> CR2 |= ( 1U << 28 ); // Enable external trigger on rising edge for ADC1
ADC1 -> CR2 |= ( 1U << 29 );
ADC1 -> CR2 &= ~(1U << 24); // Select TIM2 TRGO event for external trigger
ADC1 -> CR2 |= (1U << 25);
ADC1 -> CR2 |= (1U << 26);
ADC1 -> CR2 &= ~(1U << 27);
ADC1 -> CR2 |= (1U << 0);
// ADC1 -> CR2 |= (1U << | (1U << 9); // Select to use DMA
//ADC2 Config
//Select channel
ADC2 -> SQR3 &= ~( (1U << 0) | (1U << 2) | (1U << 3) | (1U << 4));
ADC2 -> SQR3 |= (1U << 1);
ADC2->SMPR2 |= (1U << 0);
ADC2 -> CR2 |= (1U << 0);
//ADC3 Config
ADC3 -> SQR3 &= ~( (1U << 2) | (1U << 3) | (1U << 4));
ADC3 -> SQR3 |= (1U << 0) | (1U << 1);
ADC2->SMPR2 |= (1U << 0);
ADC3 -> CR2 |= (1U << 0);
/* CONFIG TIMER FOR TRIGGER */
RCC -> APB1ENR |= ( 1U << 0); // Enable clock for TIM2
TIM2 -> PSC = (8400 - 1); // Set prescaler for 10000Hz timer frequency
TIM2 -> ARR = (1000-1); // Set auto reload value
TIM2 -> CR2 &= ~(( 1U << 4) | ( 1U << 6)); // Select update event for TRGO
TIM2 -> CR2 |= ( 1U << 5);
}
void adc_start(void){
TIM2 -> CR1 |= ( 1U << 0); // Enable TIM2
}
Solved! Go to Solution.
2024-09-23 09:37 AM
Now I've configured for triple mode and one thing i noticed is that if increase the sampling rate using TIM2 trigger the all ADCs stops and OVERRUN bit is getting set.
I'll try with larger array and update
thank you
2024-09-23 09:53 AM
Still the DMA mode 1 is not working as before. DMA Mode 2 works only when we increase the time of the TIM2 trigger. Is there any other simpler way to acquire data from 3 FRS sensor simultaneously with same sampling rate.
2024-09-23 10:09 AM - edited 2024-09-23 10:10 AM
> Still the DMA mode 1 is not working as before.
What do you observe and how, and how is it different from your expectations?
> DMA Mode 2 works only when we increase the time of the TIM2 trigger.
TIM2 triggers once per second with the settings above (PSC=8400-1, ARR=10000-1, assuming 168MHz system clock). I don't believe this prevents DMA mode 2 from working. So again, what do you do exactly, what are the observations and what are the results?
JW
2024-09-23 10:33 AM - edited 2024-09-23 10:43 AM
In DMA mode 1 the the CDR register is only getting values from ADC3 in the 16 bit LSB where as the MSB always stays 0.
DMA Mode 2:
For 1Hz trigger it's working as expected but when i increase thee tigger for example like 1KHz or 500Hz the ADCs stops after like 1or2 conversion and OVERRUN Flag sets
I disabled DDS in ADC_CCR and used a array of 30 for saving data
In Dual ADC mode for DMA mode 1 is sama as in triple Mode expect instead of ADC 3 data in 16bit LSB its ADC2 data. The DMA mode 2 is working as expected even with higher sampling rate 1 or 2 KHz only in DUAL mode
2024-09-23 06:10 PM - edited 2024-09-23 06:34 PM
This code is working as expected for DMA mode1, where the data are transferred to a adc_data[3], adc_data[0] = ADC1 value and so on. it is also working for higher sampling frequency 1 or 2 KHz. Also working when using other DMA mode
@waclawek.janthank you for your insights and help
/*
* adc.c
*
* Created on: Sep 21, 2024
* Author: Vishnu
*/
#include <adc.h>
volatile uint32_t adc_data[3];
volatile uint16_t dma2_status;
void adc_init(void){
/* Enable Clock */
RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC -> AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC -> APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC -> APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC -> APB2ENR |= RCC_APB2ENR_ADC2EN;
RCC -> APB2ENR |= RCC_APB2ENR_ADC3EN;
/* Set PA1, PA2, PA3, as Analog port */
GPIOA -> MODER |= (GPIO_MODER_MODER1_0) | (GPIO_MODER_MODER1_1);
GPIOA -> MODER |= (GPIO_MODER_MODER2_0) | (GPIO_MODER_MODER2_1);
GPIOA -> MODER |= (GPIO_MODER_MODER3_0) | (GPIO_MODER_MODER3_1);
/* Configure ADC */
//ADC1
ADC1 -> SQR3 |= (0X01); // Select Ch 1
ADC1 -> CR2 |= (ADC_CR2_EXTEN_1); // Enable External trigger
ADC1 -> CR2 &= ~(ADC_CR2_EXTEN_0);
ADC1 -> CR2 &= ~( (ADC_CR2_EXTSEL_0) | (ADC_CR2_EXTSEL_3)); // Select TIM2 TRGO event
ADC1 -> CR2 |= (ADC_CR2_EXTSEL_1) | (ADC_CR2_EXTSEL_2);
ADC1 -> CR2 |= (ADC_CR2_ADON); //Enable ADC1
//ADC2
ADC2 -> SQR3 |= (0X02); // Select Ch 2
ADC2 -> CR2 |= (ADC_CR2_ADON); //Enable ADC1
//ADC3
ADC3 -> SQR3 |= (0X03); // Select Ch 3
ADC3 -> CR2 |= (ADC_CR2_ADON); //Enable ADC1
/* Config DMA2 */
DMA2_Stream0 -> CR &= ~(DMA_SxCR_EN); //Disable DMA
while(( (DMA2_Stream0 -> CR) & (DMA_SxCR_EN) )){} // Wait till stream is disable
//Select Ch0
DMA2_Stream0 -> CR &= ~( (DMA_SxCR_CHSEL_0) | (DMA_SxCR_CHSEL_1) | (DMA_SxCR_CHSEL_2) );
DMA2_Stream0 -> CR |= (DMA_SxCR_PL_0) | (DMA_SxCR_PL_1); // Set very high Priority level
DMA2_Stream0 -> CR &= ~(DMA_SxCR_MSIZE_0); //Set MSize 32-bit
DMA2_Stream0 -> CR |= (DMA_SxCR_MSIZE_1);
DMA2_Stream0 -> CR &= ~(DMA_SxCR_PSIZE_0); //Set PSize 32-bit
DMA2_Stream0 -> CR |= (DMA_SxCR_PSIZE_1);
DMA2_Stream0 -> CR |= (DMA_SxCR_MINC); //Enable Memory Inc
DMA2_Stream0 -> CR |= (DMA_SxCR_CIRC); //Enable circular mode
DMA2_Stream0 -> CR &= ~( (DMA_SxCR_DIR_0) | (DMA_SxCR_DIR_1)); //Set transfer direction
DMA2_Stream0 -> NDTR = 3; //Set no.of data register
DMA2_Stream0 -> PAR = (uint32_t) (&(ADC -> CDR)); //Set Peri Address
DMA2_Stream0 -> M0AR = (uint32_t) (&adc_data); //Set Mem Address
// Enable DMA transfer complete interrupt
DMA2_Stream0 -> CR |= DMA_SxCR_TCIE; // Enable transfer complete interrupt
// Enable DMA interrupt in NVIC
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
/* CONFIG TIMER FOR TRIGGER */
TIM2 -> PSC = (8400 - 1); // Set prescaler for 10000Hz timer frequency
TIM2 -> ARR = (100-1); // Set auto reload value
TIM2 -> CR2 &= ~((TIM_CR2_MMS_0) | (TIM_CR2_MMS_2)); // Select update event for TRGO
TIM2 -> CR2 |= (TIM_CR2_MMS_1);
/* Triple ADC mode */
ADC -> CCR |= (ADC_CCR_DDS); //Set Contin DMA Request
ADC -> CCR |= (ADC_CCR_DMA_0); //Set DMA Mode
ADC -> CCR |= (0x0016); // Enable Dual Mode
}
void adc_start(void){
DMA2_Stream0 -> CR |= (DMA_SxCR_EN); // Enable DMA
TIM2 -> CR1 |= ( TIM_CR1_CEN); // Enable TIM2
}
// Interrupt Service Routine for DMA2 Stream 0
void DMA2_Stream0_IRQHandler(void) {
// Check for DMA transfer complete interrupt flag
if(DMA2->LISR & DMA_LISR_TCIF0) {
// Clear the interrupt flag
DMA2->LIFCR |= DMA_LIFCR_CTCIF0;
dma2_status = 1;
}
}