Need guidance for software SPI with DMA (to drive TLC5947)

Status
Not open for further replies.

Po Ting

Well-known member
Hello community, :)
I'm currently working on a pov project , using SD and TLC5947 as LED driver, on teensy 3.1
the TLC5947 library I'm using is from adafruit : https://github.com/adafruit/Adafruit_TLC5947
TLC5947 uses software SPI with clock, and 12bit for a single output channel, and follows by a clock signal each 12 bit data.
the speed is not fast enough, and one way I came up with, is to read the next picture during displaying

so I think I can rewrite the TLC5947 library with DMA.(another choice is the SD library, which seems to be much harder?):confused:

But there are only few DMA examples around the web, and I'm not yet used in C code yet, can't understand them well.
I read through Paul's octows2812 library, it seems that the DMA uses three channel and controls a port at once,
I still don't know how to use DMA with a single I/O or two.

can anyone provide an example for arduino IDE
like using pin 32 (PTB18) as data, and pin 25 (PTB19) as clock? pins could be modified,
and from the examples, I would need to reserve a pin or few, to process DMA normally?
thanks:eek:
 
thanks, :)
start reading, hope i could came up with something to code tonight.
----
and also, DMA channel seems to push byte for a unit, while TLC5947 takes 12 bit per clock.
cutting the data would be possible choice for me now, but still are there other ways like configuring the DMA setting?
from the POST i found it could be 1,2,4or8 byte, how about bits?
 
Last edited:
after days of studying , I finally have some understanding, but with many confuses and guessing
please, can some DMA master help me:confused:

from the OCTOws2811 library
https://github.com/PaulStoffregen/OctoWS2811/blob/master/OctoWS2811.cpp#L105
#if defined(KINETISK)
// pin 16 triggers DMA(port B) on rising edge (configure for pin 3's waveform)
CORE_PIN16_CONFIG = PORT_PCR_IRQC(1)|PORT_PCR_MUX(3);
pinMode(3, INPUT_PULLUP); // pin 3 no longer needed

// pin 15 triggers DMA(port C) on falling edge of low duty waveform
// pin 15 and 16 must be connected by the user: 16 is output, 15 is input
pinMode(15, INPUT);
CORE_PIN15_CONFIG = PORT_PCR_IRQC(2)|PORT_PCR_MUX(1);

// pin 4 triggers DMA(port A) on falling edge of high duty waveform
CORE_PIN4_CONFIG = PORT_PCR_IRQC(2)|PORT_PCR_MUX(3);

Is the PORT_PCR_MUX() somekind of channel shared inside the MCU, to indicate PWM for DMA triggering?

#if defined(KINETISK)
// route the edge detect interrupts to trigger the 3 channels
dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_PORTB);
dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_PORTC);
dma3.triggerAtHardwareEvent(DMAMUX_SOURCE_PORTA);

// DMA channel #1 sets WS2811 high at the beginning of each cycle
dma1.source(ones);
dma1.destination(GPIOD_PSOR);
dma1.transferSize(1);
dma1.transferCount(bufsize);
dma1.disableOnCompletion();

// DMA channel #2 writes the pixel data at 20% of the cycle
dma2.sourceBuffer((uint8_t *)frameBuffer, bufsize);
dma2.destination(GPIOD_PDOR);
dma2.transferSize(1);
dma2.transferCount(bufsize);
dma2.disableOnCompletion();

// DMA channel #3 clear all the pins low at 48% of the cycle
dma3.source(ones);
dma3.destination(GPIOD_PCOR);
dma3.transferSize(1);
dma3.transferCount(bufsize);
dma3.disableOnCompletion();
dma3.interruptAtCompletion();

#ifdef __MK20DX256__
MCM_CR = MCM_CR_SRAMLAP(1) | MCM_CR_SRAMUAP(0);
AXBS_PRS0 = 0x1032;
#endif
from the quote above, ones = 0xFF , and means to write all the ports to HIGH, or clear all.
the data controlls ws2812 exists on DMA channel 2, with a source of "dma2.sourceBuffer((uint8_t *)frameBuffer, bufsize);"
everytime the PWM edge it transfers a byte to GPIOD_PDOR,PCOR,PSOR, (which controls the eight LED strips)

is the the DMA triggered for everybyte? since controll ws2812 requires timing bit-bang,
and the dma2.sourceBuffer dumps a byte everycycle , I guess there was an internal counter or something, pointing the offset in the buffer?

and also, how did DMA channel 3 know it's over, to call the ISR function?
the ones is only a byte and thus it's used all over the data outputting,
so is the end signal came from dma2.sourceBuffer() after all bytes were done?? won't it overflow??
I didn't see, or I didn't recognize any other ending signal/register than
dma3.interruptAtCompletion();
and this interrupt, I guess, is triggered after all the data in buffer were dumped,
but how did dma3 know the transfer were completed?

and is the transfer only possible for bytes, and not bits?

sadly my TLC5947 works with 12bit everychannel
besides mathematics exchanging,
that will also cause the DMAMEM buffer 8 times bigger(about 5KB for a single 36 pixel line), if I only use one pin for data

or maybe I misunderstood something:confused:

data also referenced from::
https://www.pjrc.com/teensy/td_libs_OctoWS2811.html
https://www.pjrc.com/teensy/K20P64M72SF1RM.pdf (warning! 1377pages)

besides all the confuses, I came up with some ideas to work on

since my project uses software SPI, TLC5947 works with a data line,every bit on data line would follow a clock raise/and lowered before next data,
and finally followed with a latch signal,

I could set up two channel with 1 data buffer, 3 DMA channels, 2 PWM timers? (one for data (PDOR), one for clocking(PSOR,PCOR)) and the ISR with a latch signal every 36*pixel clocks

Oh, the TLC5947 drivers works at 20MHZ data transfer speed,
the reason I need DMA is that I need to read the SD data, while showing pictures
(typically a picture cycles for seconds, that gives plenty of time to read the next)

if Paul's reading, can I modify your octows2811 library for TLD5947? if that technically possilbe.
Thank you :)

Thanks for all other reading, ;)
 
Last edited:
Status
Not open for further replies.
Back
Top