cancel
Showing results for 
Search instead for 
Did you mean: 

DMA-> GPIO STM32f103

parisa
Senior

Hello,

I need to transfer 42 pulses (with 1 pin of a port) and read incoming bits from 1 pin of a port( such as SPI communication). As this forum member trained me I am curious to use DMA to generate 42 pulses with sending a specific value(10101...). I need to know

1)Is is possible to couple DMA with GPIO(one pin?)

2)Is there any delay between each byte(Such as SPI)?

0690X00000DA16WQAT.png

3)Could you provide me a sample ?

6 REPLIES 6
KnarfB
Principal III

Don't know or have code ready for STMF1xx, but in general:

1)Is is possible to couple DMA with GPIO(one pin?)

yes

2)Is there any delay between each byte(Such as SPI)?

no.

You setup a timer. The timer triggers a DMA. the DMA destination is the ODR register of a GPIO port. So, you cannot use other pins of that port for GPIO (maybe you can when using BSRR instead of ODR, didn't try that).

You have to check the reference manual for what timer event goes with what DMA channel.

Code snippets for STM32F042 using HAL:

 __HAL_TIM_ENABLE_DMA(&htim3, TIM_DMA_CC3);
 HAL_DMA_Start_IT( htim3.hdma[TIM_DMA_ID_CC3], (uint32_t)buffer, (uint32_t)&(GPIOA->ODR), BUFFER_LEN );
 HAL_TIM_Base_Start(&htim3);
 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);

In this code, TIM3 CH3 was configured for PWM and DMA1 Channel 2 enabled in STMCubeIDE.

AFAIK similar topics have been discussed in the forum.

hth

KnarfB

parisa
Senior

Thank you KnarfB for your answer and your example. I appreciate.

Unfortunately. I have used all pins of my port so it is impossible to disable a port for just using DMA<->GPIO only for two pins.

berendi
Principal

1.)

  • prepare an array of uint32_t values to be written to the BSRR register. Using BSRR, you can select exactly which pins are to be set or cleared, and the rest of the pins will be left alone. E.g. to output a pulse on pin 5
uint32_t outputbuffer[] = {
0x00000020, 0x00200000,
0x00000020, 0x00200000,
0x00000020, 0x00200000,
0x00000020, 0x00200000,
0x00000020, 0x00200000,
0x00000020, 0x00200000,
/* ... */
};

Of course it's possible output on more pins of the same GPIO port, setting more bits at once.

  • Set the timer ARR register to a period that equals the required output rate, i.e. double the frequency. E.g. if the timer clock is 36 MHz, and you want a 2 MHz signal, then ARR = 36 / 2 / 2 - 1.
  • To enable DMA requests from the timer, set the TIM_DIER_UDE bit.
  • Find the DMA channel which is mapped to the timer update event in the DMA request mapping table in the reference manual
  • Set up the DMA channel registers. Memory address is the buffer above, peripheral address is the address of the GPIO BSRR register, number of data ... well, guess it:). Set the channel configuration register to do 32 bits transfers (both memory and peripheral side), read from memory, and if necessary, transfer complete interrupt (enable it in NVIC to).
  • Set the DMA channel enable bit (DMA_CCR_EN) and start the timer (TIM_CR1_CEN). Now you should be able to observe the output signal on the pin.

To read a pin synchronized to the output above, you have to set up a timer channel DMA in addition to the above

  • Find a DMA channel which is mapped to a timer channel request
  • Enable the corresponding channel DMA request in the timer DIER register
  • Set up this DMA channel similar to the one above, but the memory buffer should be an empty array receiving data, peripheral address is the address of the GPIO IDR register, and the DMA direction bit is cleared.
  • Then you can examine the data in the receive buffer, amsk out the uninteresting bits, and piece together the received data bytes. Ignore every other word (even or odd numbered ones depending on the clock phase) in the buffer, as data is sampled at clock edges, not whole periods.
berendi
Principal

To answer the 2nd question,

SPI should transmit without gaps if the transmit register is properly handled, but I'm not 100% sure of that.

The timer won't make any gaps, it is designed to generate equally timed periodic events. If you want to have a gap, include it in the bit pattern to be sent.

You still can use the other pins of that port for alternate functions (SPI,I2C,...) or GPIO when using BSRR register as described by @berendi below.

parisa
Senior

I really appreciate berendi your help and your complete explanation. And also KnarfB for cooperation in this question.

I got involved with the programming and I hope handle this problem by your help.

Thanks again for everything that you teach to me.