Recommendation STM32 mcu with multiple DMA -> GPIO access  - Page 1
Forum section: electronics / general

author: Psi
author_rank: Super Contributor
timestamp: December 28, 2017, 11:24:44 pm
content: I'm running into issues with the STMF407 due to only DMA2 being able to copy to GPIO ports.It seems to be a bit under-documented but you can only use DMA2 to copy anything -> GPIO port, not DMA1Also the limitation of only having two timers to start a DMA transfer on DMA2 (TIM1 and TIM8) is also an issue.Does anyone know of a STM32 micros with features for lots of DMA to/from GPIO triggered from more than 2 timers?My application is DMA from Memory -> GPIO to drive a string of P5 LED arrays. And DMA GPIO->Memory to load RGB bitmap data to populate memory.*Tech details*A block of memory is copied to the port via DMA2 at 10mhz to refresh the display and mix colours.This uses both TIM1 and TIM8 and two DMA2 streams.One timer generates the clock for the DMA to copy Mem to GPIO and the other timer is clocked by the first and calls another DMA to copy 0 into the enable bit of the first timer on CCmatch. This stop the timer in hardware after the exact number of pixels have been clocked out.(it's only way i found to get a hardware-locked fixed number of pulses at 10mhz when you have more than 256 pulses so cannot use the 8bit RepetitionCounter register)Ideally i want a second DMA to clock in some RGB 16bit pixel data which gets processed at a slower rate and updates the memory being used to draw the display. However since DMA1 doesn't have GPIO access this isn't possible

author: Yansi
author_rank: Super Contributor
timestamp: December 28, 2017, 11:43:55 pm
content: I do not think you are driving the RGB matrix right. It should be possible using a single timer in one pulse mode + interrupt and a bunch of SPIs via DMA. I do not understand your principle.Watch this, if you do not know it already:Or have I missed here anything?Please make sure you know that each DMA controller can run up to 8 data streams together. Not only one per controller.//EDIT: BTW it is well documented, what which DMA controller can do or not. See fig 33 in the RM0090!//EDIT2: Note that driving large RGB matrices is a work more for an FPGA, not MCU. You can drive RGB matrix with MCU too, but you need to be aware of the limitations. Don't be afraid of using FPGA, it is not thaaaaat complicated.

author: dgtl
author_rank: Regular Contributor
timestamp: December 28, 2017, 11:44:09 pm
content: Look at the device block diagram in DS. Also the same is shown in DMA controller doc fig33 of RM. The DMA ha 2 ports, one for the "device" side and one for "memory" side. If you look at the connections in the ds, there are direct connections from DMA controllers to APB bus so that the DMA would have smaller impact on the bus load. Beside DMA1 connecting to APB1 and DMA2 connecting to APB2, the DMA2 has an extra connection to bus matrix, so that it could access any address in the address space. The GPIOs are connected to AHB1, so they can only be accessed via bus matrix (for extra speed, lower latency from cpu). Bus matrix connections cost some silicon, so probably they have omitted the other DMA master port in the bus matrix to reduce silicon size. Also notice that the peripherals are divided between DMA controllers depending on which APB bus they are.There are interconnections between timers, that can be used for stopping timers (ie gated mode). Perhaps you can set up the timer slave mode to stop the timer?

author: Psi
author_rank: Super Contributor
timestamp: December 28, 2017, 11:59:01 pm
content: I played around with gated mode but i couldn't get it to work with exact timing.Maybe i should have another look at it.Thanks for linking me to Mike's video, i'm going to restructure how the DMA colour mixing works.Thanks for the info that 1 DMA controller can do multiple streams at once. i had just assumed it could do one at a time.

author: Yansi
author_rank: Super Contributor
timestamp: December 29, 2017, 12:13:08 am
content: Being able to do only 2 DMA streams at once on such a rather larger MCU would be quite useless for many applicationsWatch the Mike's video, it is exactly what you need.You need to do it something like this:Divide a row time in a (2^N)-1 pulse times (where N is the brightness bit resolution).Start a timer to enable the shift register outputs for the appropriate pulse length (produce pulse lengths of 1, 2, 4, 8, ..., 2^(N-1) pulse times) and start transferring data on the SPI to the shift registers for the next pulse length.After the /OE pulse is done, you get your interrupt. Modify the pulse length to the new one, start the pulse (data in the shift registers already in there from previous pulse) and start transferring new data.Be aware of the SPI transfer speed limitation. You need to be able to shift the new data in one "pulse time" of the LSB - that actually dictates the achievable brightness bit depth, together with the refresh rate aka row period time. Calculate carefully how big matrix you can manage using this method. Note you can drive multiple matrix sections with the same single timer, but using multiple SPI peripherals.Repeat for each row. Do not multiplex more than 8 rows, otherwise the brightness will drop significantly, as you can not increase the LED current more. Even the 1/8th multiplexing beats the crap out of the LEDs and the drivers.//EDIT: Fixed typos.

author: Psi
author_rank: Super Contributor
timestamp: December 29, 2017, 12:22:02 am
content: Yep, Mikes video was really helpful.Sadly it needs to be done as DMA to a GPIO port since the mcu doesnt have 6 SPI ports needed for the 6 serial inputs on the LED display.

author: Yansi
author_rank: Super Contributor
timestamp: December 29, 2017, 12:23:50 am
content: Connect the section two in series, so you will end up with only 3 SPIs needed. And calculate what timing it will get you.What length (number of LEDs) does one row have?

author: Yansi
author_rank: Super Contributor
timestamp: December 29, 2017, 12:28:41 am
content: If I got that right, you have a 64 by 32 RGB matrix, i.e. two of those:https://cdn-shop.adafruit.com/product-files/2277/MI-T35P5RGBE-AE.pdfThat means each row is 64 LEDs long, as it does utilize 1/16 scan. (the 32x32 panel is electrically a matrix of 64 columns by 16 rows)Connect each two rows in series. 128 leds per row is pretty manageable I think.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: December 29, 2017, 12:58:51 am
content: 1/16 scan is pretty common for RGB modules - higher density ones (<=3mm pitch) with small LEDs sometimes use 1/32.The LED density means you rarely need ( or can) run the LEDs at maximum avarage power, so mux rate only impacts how fast you need to send the data.For lower densities where you can/want to run the LEDs as bright as possible, 8 or 4:1 has advantages.This is way easier to do in an FPGA, especially if your image buffer fits in internal BRAM, but a small FPGA or CPLD may help accelerate a CPU based solution.

author: Psi
author_rank: Super Contributor
timestamp: December 29, 2017, 02:45:42 am
content: Quote from: Yansi on December 29, 2017, 12:28:41 amEach stm32f4 has four 32x32 pixel RGB blocks.Each block has two RGB inputs, for top half and bottom half.For each half you clock 64 pixels for each address (there are 8 addresses).So R1 G1 B1 clock in line 0 and then loop back and clock in line 8.R2 G2 B2 clock in line 16 and then loop back and clock in line 24.(the loop back is done inside the module as part of the hardware).Hence for a 4 block display (32x128) you have two separate RGB feeds each clocking in 256 pixels 8 times to cover the entire display.

author: Psi
author_rank: Super Contributor
timestamp: December 30, 2017, 10:33:15 am
content: Ok, so with some effort i converted the design to use the PWM colour mixing approach in Mike's video.Loading in the data, latching it and holding for 1,2,4,8,16,32,64,128 time periods.Much better approach, i now have 8 bits for each colour and can convert that to a true 5/6bit gradient.Which is all i need for my goal of 16bit colour.32x128 RGB display update rate is 291Hz, which is overkill, but provides some room for additional processing without causing flicker. Or stretching out the updates with dead time to add a global brightness control.It also uses a butt load less ram to latch and hold, compared to how i had it working before.So i now have enough room to double buffer the video memory arrayMight take another look at using gated timer mode tomorrow, see if that has any advantages.Thanks everyone, especially Mike

author: Yansi
author_rank: Super Contributor
timestamp: December 30, 2017, 10:43:59 am
content: 64x32 RGB (or 128 x 16 respecively) should take exactly 16*128*3 bits, which is 6114 bits per pulse frame, 48912 bits per whole frame, which is almost 6 kB.