PSOC5LP DMA from RAM to peripheral

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
s1m1ch
Level 1
Level 1
5 sign-ins First reply posted First question asked

Hi.

I'm working on a custom LCD driver where I want to transfer a predefined amount of 16-bit data from RAM to two 8-bit control registers, where every single element transfer is synchronous to the LCD clock. 

Due to LCD size, the amount of data to be sequentially transferred could be up to 130,560 elements (for 480x272 pix) of course if external RAM is used and at least 32 descriptors defined.

Everything working fine if I define it to transfer less than or equal 4095 elements which is the amount of one descriptor, but if I generate more than one descriptor DMA is not working as expected, the data seems to get corrupted on the control registers side.

I'm new to PSOC5LP so maybe I'm missing something. Please see a part of the code and the schematic in the attachment.

Any hints or suggestions would be grateful.

BR Simon

0 Likes
4 Replies
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

Simon,

The DMA already has all necessary counters, so external counters (PWM_1, PWM_2 and extra logic) are unnecessary. Just the clock and DMA_1. The DMA TermIn is very seldomly used due to its implementation; it is unnecessary in this case.

The simple way is to slice DMA TDs into equal portions, like

480x272 = 480x8x34=3840x34 (34 TDs of 3840 length each)

#define DESCRIPTOR_LEN       3840
#define N_OF_DESCRIPTORS 34
 
And corrected lines of code should look like:
 
for(...){
...
CyDmaTdSetConfiguration(DMA_1_TD[i], 2*DESCRIPTOR_LEN, DMA_1_TD[i+1], CY_DMA_TD_INC_SOURCE_ADDR | C_DMA_AUTO_EXECUTE_NEXT);
...
}
 
CyDmaTdSetConfiguration(DMA_1_TD[i], 2*DESCRIPTOR_LEN, DMA_1_TD[0], CY_DMA_TD_INC_SOURCE_ADDR | C_DMA_AUTO_EXECUTE_NEXT | DMA_1__TD_TERMOUT_EN);
 
Note that transfer amount equals (2 bytes) *DESCRIPTOR_LEN, and DMA is not terminated; it returns back to the start (TD[0]) and loops continuously. The DMA_termin pin should be disabled, it is not used here. The TERM_OUT is enabled only for the last TD so the signal shoots only once after the completion of the entire DMA loop. 
 
/odissey1
P.S. I suggest embedding images in the post, so there is no need to download them
0 Likes
s1m1ch
Level 1
Level 1
5 sign-ins First reply posted First question asked

Thank you for your reply and your suggestions.

I think I owe you an explanation about those PWM blocks in the schematics. Due to a specific TFT Driver IC on the LCD side, I have to generate a special pattern for the CS signal to generate a new line or return to LCD's starting point. See the diagram below (DE = CS signal)...

LCD_Driver_Timming_diagram.PNG

The "DATA" line is actually in my case two 8-bit control registers, which have to be updated with one DMA element (or pixel), synchronously every CLK cycle (8Mhz).

LCD_Driver_sch.PNG

So, actually, I even don't want DMA to loop continuously due to synchronization to CS signal special patterns but only for a predefined amount of data.

If I'm correct, the maximum amount of data to transfer in one descriptor is 4095 bytes? So the formula should be: 480x272 = 130560 (16-bit) = 261120 (8-bit) = 64 * 4080  (64 TDs of 4080 length each) Right? 

I'm not sure how much data is transferred at one DMA transaction request (drq), it should be 2 bytes as it is set in:

#define DMA_1_BYTES_PER_BURST 2
#define DMA_1_REQUEST_PER_BURST 1
#define DMA_1_SRC_BASE (aMemory)
#define DMA_1_DST_BASE (CYDEV_PERIPH_BASE)

DMA_1_Chan =DMA_1_DmaInitialize(DMA_1_BYTES_PER_BURST,DMA_1_REQUEST_PER_BURST,HI16(DMA_1_SRC_BASE), HI16(DMA_1_DST_BASE));
    

So is this the correct way to transfer data, where for each CLK cycle (DMA transfer request input (drq)) 2 bytes at the time have to be transferred from RAM to a peripheral for the amount of 261120 bytes which are divided into 64 descriptors of 4080 elements?


I hope I didn't overcomplicate the substance too much.. 😃

0 Likes

There are many ways to slice a cat. I believe that your split of TDs is correct

480x272 = 130560 (16-bit) = 261120 (8-bit) = 64 * 4080  (64 TDs of 4080).

The (68 TDs x 3840) will also work. 

#define DESCRIPTOR_LEN       4080
#define N_OF_DESCRIPTORS 64

The initialization seems to be correct, and should result in 2 bytes transferred to the Control Registers 1 & 2 on each DMA clock.

#define DMA_1_BYTES_PER_BURST        2
#define DMA_1_REQUEST_PER_BURST 1
#define DMA_1_SRC_BASE                          (aMemory)
#define DMA_1_DST_BASE                         (CYDEV_PERIPH_BASE)

DMA_1_Chan =DMA_1_DmaInitialize(DMA_1_BYTES_PER_BURST, DMA_1_REQUEST_PER_BURST, HI16(DMA_1_SRC_BASE),  HI16(DMA_1_DST_BASE));

Note that once TERMIN signal is captured, the DMA had to be restarted. The TERMIN signal will capture only during DMA clock, which makes it hard to synchronize. On the other side, if DMA chain automatically terminates at completion, then no hardware TERMIN is needed. With the above schematic, the DMA and PWMs have to be reset on each screen refresh cycle, which defeats the purpose of DMA. Typically, DMA is left to continuously stream data from the buffer, while CPU is populating buffer at its own pace.

 

P.S. There is one more pitfall, its the DMA clock speed, which is currently set to 8MHz. I believe that each 2-byte DMA transfer will take 10-11 BUS clocks, which brings PSoC BUS_CLK frequency to 80-90MHz, which is over the specs limit. If possible, reduce the DMA clock to test the design first, and then rise it up. Also, current schematic with 2 PWMs may have clock limitation below 80 MHz. When duplicated, the schematic showed maximum BUS_CLK for design as 62.680 MHz.

0 Likes
s1m1ch
Level 1
Level 1
5 sign-ins First reply posted First question asked

Thank you for your tips.

I still have the same problems, but I will test the clock issue you mentioned, which sounds resonable. I'll feedback on the results found.

0 Likes