cancel
Showing results for 
Search instead for 
Did you mean: 

How to read gpio using dma in Input Capture mode

Amal Babu
Associate III

Hi,

I want to  configure the DMA so that it transfers data from the GPIO lines (8 bit data lines) to the RAM buffer upon receiving a trigger signal on the timer capture input channel TIM1_CHI (PE9) . I am using stm32f446ze.We nees to acquire data register on rising edge of clock.

''https://www.st.com/content/ccc/resource/technical/document/application_note/7a/88/df/e3/d3/36/40/29/DM00169730.pdf/files/DM00169730.pdf/jcr:content/translations/en.DM00169730.pdf''

Based on above datasheet ( 1.2.1 Data reception (using DMA) ) , configurations made are as follows

void DMA_Init()

{

/* TIM1_CH1 : Stream 6 Channel 0 */

RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

DMA2_Stream6->CR &= ~DMA_SxCR_EN;

DMA2_Stream6->CR &= ~DMA_SxCR_CHSEL;       // Channel 0 selected 

DMA2_Stream6->CR |= DMA_SxCR_MINC | DMA_SxCR_PL_1 | DMA_SxCR_CIRC | DMA_SxCR_TCIE;

                         // Memory address pointer is incremented after each data transfer

                         // Priority level high

                         // Circular mode enabled

                         // TC interrupt enabled

DMA2_Stream6->NDTR = 1;

DMA2_Stream6->PAR = (uint32_t)&GPIOC->IDR;    /* Read fron GPIO input data register */

DMA2_Stream6->M0AR = (uint32_t)&GPIO_DATA;    /* Send the data to the RAM buffer */

DMA2_Stream6->CR |= DMA_SxCR_EN;         // Stream enabled

NVIC_EnableIRQ(DMA2_Stream6_IRQn);        // DMA2 Stream 6 global interrupt

}

void Timer_InputCapture_Init()

{

/* TIM1 channel 1 pin (PE9) configuration */

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;

GPIOE->MODER |= BIT(19);

GPIOE->MODER &= ~BIT(18);

GPIOE->AFR[1] = BIT(4);

 /* Timer1 configurations */

RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;                   // TIM4 clock enable

TIM1->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_1;  // CC1S = 01

                                     // IC1F = 0011

TIM1->CCER |= TIM_CCER_CC1P | TIM_CCER_CC1E;               // rising edge

                                     // Capture enabled

TIM1->DIER |= TIM_DIER_CC1DE;                      // CC1 DMA request enabled

TIM1->CR1 |= TIM_CR1_CEN;                        // TIM enable counter

}

void DMA2_Stream6_IRQHandler(void) 

{

GPIOA->ODR ^= BIT(2);

gpio_readdata = GPIO_DATA;

   DMA2->LIFCR =0xffffffff;

DMA2->HIFCR =0xffffffff;

}

but we are not sure , whether the program enters the ISR on the rising edge of the external clock input.We are having this doubt because we tried toggling a pin in ISR and we found that the pin toggles on the falling edge of the Clock.

How can i verify this?Please reply asap......

1 ACCEPTED SOLUTION

Accepted Solutions

> TIM1->CCER |= TIM_CCER_CC1P | TIM_CCER_CC1E;               // rising edge

No.

0690X000006D6rmQAC.png

JW

View solution in original post

8 REPLIES 8

This looks like a total hack..

Qualify the IRQ source before toggling, and then clear the specific source.

What frequency is the clock? If you make it much slower does the latency of the DMA IRQ become more apparent?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

> TIM1->CCER |= TIM_CCER_CC1P | TIM_CCER_CC1E;               // rising edge

No.

0690X000006D6rmQAC.png

JW

Amal Babu
Associate III

Thanks for your support . The program worked fine when changing the trigger edge of external clock pulse .

Please mark as solved (chosing best).

JW

Amal Babu
Associate III

shown below is the ISR for DMA to read gpio register when input capture occurs."GPIO_DATA" is the destination address and "gpio_readdata" is an integer variable declared globally."gpio_readdata = GPIO_DATA;" After executing this instruction we checked the value of both and found the following result.

We are obtaining the data in GPIO_DATA but found that the value is not being assigned to the variable "gpio_readdata".Why is that so? To confirm this we happen to change the frequencies of external clock from low to high and found that the assignment operation works well till 500KHz. But the operation was found working improperly at 3MHz.Our requirement as per design is to operate at 3MHz. At 3Mhz the value of "gpio_readdata" is either 0x00 or 0xFE;

But the value of the GPIO_DATA during this read is not either of them.STM operates at 180MHz.Please share your suggestions regarding this issue?

void DMA2_Stream6_IRQHandler(void) 

gpio_readdata = GPIO_DATA;

flag_clear = TIM1->CCR1;

DMA2->HIFCR |= DMA_HIFCR_CTCIF6;

}

 

You may need to qualify GPIO_DATA as volatile. Otherwise, the compiler does not "see" any code which would change its value, so can safely assume it never changes and from that assumption generate code which has surprising results.

Also, having NDTR=1 you interrupt after every edge. The interrupt takes up a lot of time - only the entry and exit lasts 24 cycles, and that assuming there are no bus coolisions and other interrupts etc.; and depending on compiler settings the body of interrupt may easily take up to several tens of cycles; so by the time you read the data they may have already changed, maybe even several times. What you want is a larger DMA buffer, capture into that buffer, and then process it afterwards.

JW

We have already defined "GPIO_DATA" as volatile . What you meant DMA buffer, is it Double buffer mode or Peripheral data size .

I mean a large array in the memory, and NDTR mathing that array's size. Capture data into that array and process them afterwards.

If you want to capture data continuously, first make sure that the routine for processing is fast enough so that it can execute within the timeslot allowed for one sample. But start just with acquiring one buffer long data and try to process that without acquiring further data.

JW