cancel
Showing results for 
Search instead for 
Did you mean: 

What's the best way to do bit-banging with timers and DMA?

PPles.1
Associate

Hello,

I want to implement VGA signal generation on my STM32L432KC board. For start, getting the vertical sync and horizontal sync timings right would be great. I found a nice website with hsync, vsync and pixel timings and I thought that using resolution of 800x600 pixels at 60 Hz would be the easiest, since the clock frequency is easily divisible to smaller integer numbers (eg. instead of having 800 pixels of horizontal resolution with 40 MHz pixel clock, I can have 10 MHz pixel clock at the cost of smaller 200 px horizontal resolution).

To achieve precise timings, I want to use a timer (let's say, running at 10 MHz) and some counters, so I will know where am I on horizontal and vertical axes (eg. I know I'm in the start of the visible area in 3rd line, so I need to start displaying proper buffer of pixels). Also, I'd like to have some interrupts, so eg. when I start drawing a line, I want to generate the next line [so I won't be using a frame buffer, at least for now]).

I tried to toggle a GPIO pin really fast with DMA, like this:

  /* DMA configuration code from dma.c file */
  hdma_memtomem_dma2_channel1.Instance = DMA2_Channel1;
  hdma_memtomem_dma2_channel1.Init.Request = DMA_REQUEST_0;
  hdma_memtomem_dma2_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY;
  hdma_memtomem_dma2_channel1.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_memtomem_dma2_channel1.Init.MemInc = DMA_MINC_ENABLE;
  hdma_memtomem_dma2_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_memtomem_dma2_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_memtomem_dma2_channel1.Init.Mode = DMA_CIRCULAR;
  hdma_memtomem_dma2_channel1.Init.Priority = DMA_PRIORITY_HIGH;
  
  /* this piece of code is placed before the infinite while loop */
  HAL_DMA_Start(&hdma_memtomem_dma2_channel1, (uint32_t)LUT, ((uint32_t)&(GPIOB->BSRR)), 4);

LUT is an array that contains four words that just specifies which pins in GPIOB register to turn on or off. The code works, it toggles a pin at 4 MHz frequency (I have no idea why exactly this frequency) and it doesn't work for 2 element array for some reason.

Now, how can I use a timer to execute DMA copy at some set frequency? Can I do it faster than 4 MHz? Also, is there a better way to manipulate GPIO pins with DMA or is my hacky method enough? Where do I go from here? And lastly, I'd be really grateful for some resources that could help me.

4 REPLIES 4
TDK
Guru

You are at or approaching the limits of the chip in terms of DMA throughput. Enabling the FIFO may get you a slightly higher frequency. You'll need to trigger it off of a timer to get the clock to be consistent.

The MCU is also limited in its processing capability and I don't think dynamically generating each line as it's needed is going to be doable. At 800x600, it's probably too much to fit the entire buffer in RAM and use circular DMA to send it out. The bus can only handle so many memory accesses at a time and they're all competing for the same resources.

There are display-specific peripherals that I would consider as alternatives. The TouchGFX library seems popular.

If you feel a post has answered your question, please click "Accept as Solution".

Thanks for the reply, I expected this task to be a bit too much for a small microcontroller, but on the other hand I've seen people doing things like this on some even less capable uCs

>>..but on the other hand I've seen people doing things like this on some even less capable uCs

Yeah, but then that's usually the ONLY thing the chip can do, but then why not commit an IC or FPGA/CPLD to the task?

The requirements for 640x480 are significantly less than 800x600

https://www.ftdichip.com/Products/ICs.htm

The STM32L4R can drive displays, and HW optimized to do the job

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

> Enabling the FIFO may get you a slightly higher frequency.

The single-port DMA an 'L4 does not have FIFO.

To understand the limitations of DMA, read the respective appnote.

+1 to what Clive said above. As a hobby experiment it may be valuable, but also it may be a frustrating experience of you are a novice.

It may be more rewarding to pull it out as monochrome, using a naturally clocked interface, i.e. SPI. It is still a challenge and lord of learning, but more likely to lead to working end.

JW