New VGA 640x400 70Hz library

29 Aug 2011

The burst size is the amount of data that is transferred when the DMACBREQ signal goes active in the source peripheral. So in the case of 4 it transfers 4 times 32-bits. 32-bits is the width of both source and destination, i.e. 1 32-bits word is transferred each clockcycle.

With a transfersize of 25, each LLI transfers 25 times 32-bits, in bursts of 4 words, which equals to 800 bits, which are the number of dotclock-cycles per scanline.

The numbers you quote are from Gert's code I suppose. A transfersize of 20 equals to 20*32-bits=640 bits, which are only the visible pixels.

David Joseph Ariando wrote:

Also I can't understand why have you set blanking with 32 char size. Cause I2STXFIFO is just 32-bit accessible, why don't you set blanking with just one word size?

Yes, that should be possible. The array can be smaller and the transfer limited to one word.

29 Aug 2011

If you set transfer size with 20 because of 20*4*1 bytes = 640 (pixel/row). How do you make sure that this pixel timing is on right hsync visible lines timing?

And what triggers the DMA channel to send data to IS2TXFIFO? You set tx_depth_dma_1 on I2SDMA1 with 2, but I don't understand what is this mean. I try to fill I2STXFIFO with 2 (equal with tx_depth_dma_1) but can't get any DMA channel to send data to I2STXFIFO.

Thank you.

29 Aug 2011

The 20 bytes is an arbitrary value, the 'increment source function' is not even active on the blanking part so it can just as easily be a single word, I just wanted to be sure that the I2S fifo is filled with zeroes. You may try shortening this or even set it to a single word.

The most important part is that the active bits are shifted out in the right order and that right after sending the active bits out the I2S output goes to zero (black), that is why the active list is linked to the 'zero' list.

The PWM output sets the hsync position by generating an interrupt which activates HSYNC and sets up the active/visible DMA list for the current line, this active list is linked to the blank list which is linked to NULL and therefore DMA stops somewhere between the last active bit and the start of the next PWM interrupt which starts the sequence all over for the next line.

All this time the I2S will emit zeroes for everything but the active display area. After counting 400/480 lines the VSYNC is activated and all the pointers are reset to the start of the screen and so on and so on :-)

29 Aug 2011

Oh, sorry, I have edited my last post just after your answer. Here is my question.

And what triggers the DMA channel to send data to IS2TXFIFO? You set tx_depth_dma_1 on I2SDMA1 with 2, but I don't understand what is this mean. I try to fill I2STXFIFO with 2 (equal with tx_depth_dma_1) but can't get any DMA channel to send data to I2STXFIFO.

29 Aug 2011

David do you have the UM10360 pdf ? (the LPC17xx user manual)

Quote:

20.5.6 DMA Configuration Register 1 (I2SDMA1 - 0x400A 8014)

The I2SDMA1 register controls the operation of DMA request 1. The function of bits in I2SDMA1 are shown in Table 410. Refer to the General Purpose DMA Controller chapter for details of DMA operation.

Table 410: DMA Configuration register 1 (I2SDMA1 - address 0x400A 8014) bit description

Bit Symbol Description

0 rx_dma1_enable When 1, enables DMA1 for I2S receive.

1 tx_dma1_enable When 1, enables DMA1 for I2S transmit.

7:2 - Reserved, user software should not write ones to reserved bits. The value read from a 0 reserved bit is not defined.

11:8 rx_depth_dma1 Set the FIFO level that triggers a receive DMA request on DMA1.

15:12 - Reserved, user software should not write ones to reserved bits. The value read from a NA reserved bit is not defined.

19:16 tx_depth_dma1 Set the FIFO level that triggers a transmit DMA request on DMA1.

31:20 - Reserved, user software should not write ones to reserved bits. The value read from a NA reserved bit is not defined.

UM10360 User manual

What I understand from this is that every 2 words (?) there will be a DMA transfer to the I2S FIFO from the source. You can read out the current level from the Status Feedback Register (I2SSTATE)

29 Aug 2011

A transfer depth of 2 means that a DMA transfer will be requested when 2 words are left in the FIFO.

So, for example, you fill up the FIFO with 8 words. I2S starts putting out its data and the FIFO shrinks, 7, 6, 5, 4, 3, 2 ==> trigger DMA request.

30 Aug 2011

Oh yes, Mr.Gert, I have the manual, but quite don't understand what this "tx_depth_dma1" mean and how DMA is triggered. :)

Is that mean, when I enable DMA channel with tx_depth_dma1 = 2, for there is no data in FIFO at first, DMA request automatically triggered?

I use this code to try simple DMA to I2S, and I want to send data from framebuffer (not incrementing) to I2STXFIFO. But so far, I can't get any data sent, or DMA to be triggered.

#include "mbed.h"

#define FL_PCON         ((volatile uint32_t *) 0x400FC0C0)  // Power Control Registers
#define FL_PCONP        ((volatile uint32_t *) 0x400FC0C4)  // Power Control For Peripheral Registers
#define FL_CLKSRCSEL    ((volatile uint32_t *) 0x400FC10C)  // Clock Source Select Register
#define FL_PCLKSEL0     ((volatile uint32_t *) 0x400FC1A8)  // Peripheral Clock Selection Register 0
#define FL_PCLKSEL1     ((volatile uint32_t *) 0x400FC1AC)  // Peripheral Clock Selection Register 1
#define FL_PLL0CON      ((volatile uint32_t *) 0x400FC080)  // PLL0 Control Register
#define FL_PLL0FEED     ((volatile uint32_t *) 0x400FC08C)  // PLL0 Feed Register (for changing in PLL0CON and PLL0CFG to take effect)
#define FL_PLL0STAT     ((volatile uint32_t *) 0x400FC088)  // PLL0 Status Register
#define FL_PLL0CFG      ((volatile uint32_t *) 0x400FC084)  // PLL0 Configuration Register
#define FL_CCLKCFG      ((volatile uint32_t *) 0x400FC104)  // CPU Clock Configuration Register

#define FL_ISER0        ((volatile uint32_t *) 0xE000E100)  // Interrupt Set-Enable Register 0

#define FL_PINSEL0      ((volatile uint32_t *) 0x4002c000)  // Pin Function Select Register 0
#define FL_PINSEL4      ((volatile uint32_t *) 0x4002c010)  // Pin Function Select Register 4
#define FL_PINMODE0     ((volatile uint32_t *) 0x4002c040)  // Pin Mode Select Register 0
#define FL_PINMODE4     ((volatile uint32_t *) 0x4002C050)  // Pin Mode Select Register 4
#define FL_PINMODE_OD2  ((volatile uint32_t *) 0x4002C070)  // Open Drain Pin Mode Select

#define FL_FIO0DIR      ((volatile uint32_t *) 0x2009C000)  // Fast GPIO Port Direction Control Register
#define FL_FIO0CLR      ((volatile uint32_t *) 0x2009C01C)  // Fast Port Output Set Register
#define FL_FIO0SET      ((volatile uint32_t *) 0x2009C018)  // Fast Port Output Set Register

#define FL_I2STXRATE    ((volatile uint32_t *) 0x400A8020)  // Transmit Clock Rate Register
#define FL_I2SDAO       ((volatile uint32_t *) 0x400A8000)  // Digital Audio Output Register
#define FL_I2STXFIFO    ((volatile uint32_t *) 0x400A8008)  // Transmit FIFO Register
#define FL_I2SDMA1      ((volatile uint32_t *) 0x400A8014)  // DMA Configuration Register 1
#define FL_I2SSTATE     ((volatile uint32_t *) 0x400A8010)  // Status Feedback Register

#define FL_PWM1PR       ((volatile uint32_t *) 0x4001800C)  // PWM Prescale Register
#define FL_PWM1MR0      ((volatile uint32_t *) 0x40018018)  // PWM Match Register 0
#define FL_PWM1MR1      ((volatile uint32_t *) 0x4001801C)  // PWM Match Register 1
#define FL_PWM1MR2      ((volatile uint32_t *) 0x40018020)  // PWM Match Register 2
#define FL_PWM1MCR      ((volatile uint32_t *) 0x40018014)  // PWM Match Control Register
#define FL_PWM1PCR      ((volatile uint32_t *) 0x4001804C)  // PWM Control Register
#define FL_PWM1TCR      ((volatile uint32_t *) 0x40018004)  // PWM Timer Control Register

#define FL_DMACConfig   ((volatile uint32_t *) 0x50004030)  // DMA Configuration Register
#define FL_DMACC0SrcAddr ((volatile uint32_t *) 0x50004100) // DMA Channel 0 Source Register
#define FL_DMACC0DestAddr ((volatile uint32_t *) 0x50004104)// DMA Channel 0 Destination Address 
#define FL_DMACC0LLI    ((volatile uint32_t *) 0x50004108)  // DMA Channel 0 Link List Item Register
#define FL_DMACC0Control ((volatile uint32_t *) 0x5000410C) // DMA Channel 0 Control Register
#define FL_DMACC0Config ((volatile uint32_t *) 0x50004100)  // DMA Channel 0 Configuration Register



unsigned char *framebuffer = (unsigned char *)(0x2007C000);



int main() {

    
    *FL_PCONP = 0;                              // power off all peripherals
    
    // SET CLOCK TO 100MHz
    *FL_CLKSRCSEL = 1;                          // select main oscilator as the PLL0 clock source
    *FL_PLL0CON = 1;                            // disconnect PLL0
    *FL_PLL0FEED = 0xAA;*FL_PLL0FEED = 0x55;    // feed for PLL0CON changes
    while (*FL_PLL0STAT&(1U<<25));              // wait until PLL0CON changes
    *FL_PLL0CON = 0;                            // disabling PLL0
    *FL_PLL0FEED = 0xAA;*FL_PLL0FEED = 0x55;    // feed for PLL0CON changes
    while (*FL_PLL0STAT&(1U<<24));              // wait until PLL0CON changes
    *FL_PLL0CFG = (1U<<16 | 24U);               // set N = 2 and M = 25, but PLL0CFG number is set by (N-1) and (M-1) for this purpose
    *FL_PLL0FEED = 0xAA;*FL_PLL0FEED = 0x55;    // feed for PLL0CFG changes
    *FL_PLL0CON = 1;                            // enabling PLL0
    *FL_PLL0FEED = 0xAA;*FL_PLL0FEED = 0x55;    // feed for PLL0CON changes
    while (!(*FL_PLL0STAT&(1U<<24)));           // wait until PLL0CON changes
    *FL_CCLKCFG = 2;                            // set cpu divider with 3, number sent tu CCLKCFG is (N-2) where N = 3
    while (!(*FL_PLL0STAT&(1U<<26)));           // wait until PLL0 locked
    *FL_PLL0CON = 3;                            // connect PLL0
    *FL_PLL0FEED = 0xAA;*FL_PLL0FEED = 0x55;    // feed for PLL0CON changes
    while (!(*FL_PLL0STAT&(1U<<25)));           // wait until PLL0CON changes
    
    // INIT I2S
    *FL_PCONP |= (1U<<27);                      // power up i2s
    *FL_PCLKSEL1 |= (1U<<22);                   // select PCLK = CCLK
    *FL_PINSEL0 |= (1U<<14);                    // P0.7 = i2stx_clk
    *FL_PINSEL0 |= (1U<<16);                    // P0.8 = i2stx_ws
    *FL_PINSEL0 |= (1U<<18);                    // P0.9 = i2stx_sda
    *FL_I2STXRATE = 4U | (1U<<8);               // produce MCLK with X = 1, Y = 4
    *FL_I2SDAO = (0U | (0U<<2) | (7U<<6) );     // set 8-bit data i2s, stereo format, ws_halfperiod = 7 or ws 16clk period

    // INIT DMA
    *FL_PCONP |= (1U<<29);                      // power up gpdma
    *FL_DMACConfig |= 1U;                       // enable DMA
    while (!(*FL_DMACConfig & 1)) {};              // wait until DMA enabled
    *FL_DMACC0SrcAddr = 0x2007C000;             // source address is framebuffer, pointer to peripheral SRAM
    *FL_DMACC0DestAddr = *framebuffer;         // destination address is i2s tx fifo 8x32bit
    *FL_DMACC0LLI = 0;                         
    *FL_DMACC0Control =    (0xfff&20U)          // 0xfff transfer size
                        |(1U<<12)               // source burst size 4
                        |(1U<<15)               // destination burst size 4
                        |(2U<<18)               // source transfer width 32
                        |(2U<<21)               // destination transfer width 32
                        |(0U<<26)               // source not increment
                        |(0U<<27)               // destination not increment
                        |(0U<<31);              // interrupt disabled
    
    
    *FL_I2SDMA1 |= 2U<<16;                      // set fifo level that triggers a transmit DMA request on DMA1
    *FL_I2SDMA1 |= 2U;                          // enable DMA1 for i2s transmit
    
    
    *FL_DMACC0Config = 5U<<6 | 1U<<11 | 1U<<14 | 1U<<15;    // source is memory, destination is i2s, transfer type memory to peripheral, IE & ITC mask
    *FL_DMACC0Config |= 1U;                                 // channel enabled
    
    // This is data I want to send initially to check I2S connection, but why can't I get these data sent by I2S if I don't put this on 'while(1) {}' section below?
    *FL_I2STXFIFO = 0x10;
    *FL_I2STXFIFO = 0x20;
    *FL_I2STXFIFO = 0x30;
    *FL_I2STXFIFO = 0x40;
    
    *framebuffer = 0xFF;    // this is data i want to send to *I2STXFIFO
    
    while (1) {
        
    }

}

30 Aug 2011

Hi David,

I see that you have the 'source increment' bit not set so it will not advance through your framebuffer:

                        |(0U<<26)               // source not increment

I use the 'no increment' option so the DMA engine reads only 'null' bytes/words into the fifo, but that is only for the blanking part. Furthermore you start the DMA engine and then you insert bytes by yourself into the FIFO, that might confuse things. The DMA engine itself will read bytes from the source address as soon as you have setup the right parameters. Ivo has made the fastlib routines especially to simplify this complicated sequence.

31 Aug 2011

David, In your code, in the main() routine, the line -

//  *FL_DMACC0DestAddr = *framebuffer;         // destination address is i2s tx fifo 8x32bit
// should be
    *FL_DMACC0DestAddr = framebuffer;          // destination address is i2s tx fifo 8x32bit

The second asterisk gets you the byte pointed to by framebuffer, not the address as you want.

31 Aug 2011

Fred Scipione wrote:

David, In your code, in the main() routine, the line -

//  *FL_DMACC0DestAddr = *framebuffer;         // destination address is i2s tx fifo 8x32bit
// should be
    *FL_DMACC0DestAddr = framebuffer;          // destination address is i2s tx fifo 8x32bit

The second asterisk gets you the byte pointed to by framebuffer, not the address as you want.

You are both right and wrong here :) The * should indeed be removed if the framebuffer is to be the destination address. But the destination address should be the I2S FIFO.

11 Dec 2013

Im trying to display a snake game using your code, the input is coming from accelerometer.. but whenever i read the analog input, the screen goes blank, any suggestion?