Transfer data from parallel GPIO using GPDMA

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Transfer data from parallel GPIO using GPDMA

5,887 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by marco on Fri Jul 27 05:55:22 MST 2012
Hi everyone
(sorry for my English!!)
I'm trying to transfer 8bit parallel data input from GPIO pins to SRAM using GPDMA on LPC1850 at 180mhz CCLK. The DMA request is made by counter match.

When I enable the DMA Channel, the Error Interrupt (INTERRSTAT) is asserted, and the DMA channel is disabled.
If I set the SRCADDR register of Channel0 on a FLASH address or a SRAM address the transfer is enabled and properly terminated.
I don't understand what's wrong in the SRCADDR when I initialize it with GPIO PORT.
Below there is my GPDMA initialization.



// Enable clock and init GPIO inputs
LPC_CCU1->CLK_M3_GPIO_CFG  = (1<<1) | (1<<0);      //enable clock
while (!(LPC_CCU1->CLK_M3_GPIO_STAT & (1<<1)));     //stat run

//for all pins on port 4 I configure input
//...
LPC_SCU->SFSP9_0  = (0 << 0) |     //Function 0 GPIO
                                   (2 << 3) |  //Disable pullup and pulldown
                                   (1 << 5) |  //Fast speed
                                   (1 << 6) |  //Enable input buffer
                                   (1 << 7);   //Disable input glitch filter
//...

LPC_CCU1->CLK_M3_DMA_CFG  = (1<<1) | (1<<0);   //enable clock
while (!(LPC_CCU1->CLK_M3_DMA_STAT & (1<<1)));   //check stat run
 
// Reset all channel configuration register
LPC_GPDMA->C0CONFIG = 0;
LPC_GPDMA->C1CONFIG = 0;
LPC_GPDMA->C2CONFIG = 0;
LPC_GPDMA->C3CONFIG = 0;
LPC_GPDMA->C4CONFIG = 0;
LPC_GPDMA->C5CONFIG = 0;
LPC_GPDMA->C6CONFIG = 0;
LPC_GPDMA->C7CONFIG = 0;

// Clear all DMA interrupt and error flag
LPC_GPDMA->INTTCCLEAR = 0xFF;    //Clear CH0 Count Interrupt flag
LPC_GPDMA->INTERRCLR = 0xFF;    //Clear CH0 Error Interrupt flag   
    
// Clear DMA configure
LPC_GPDMA->C0CONTROL = 0x00;
LPC_GPDMA->C0CONFIG = 0x00;

// Assign Linker List Item value
LPC_GPDMA->C0LLI = 0;

//Assign source address GPIO on port 4 
LPC_GPDMA->C0SRCADDR    = (uint32_t) &LPC_GPIO_PORT->PIN[4]; 
//Assign destination address dest1[256] buffer in SRAM
LPC_GPDMA->C0DESTADDR    = (uint32_t) dest1;

LPC_GPDMA->C0CONTROL    = (uint32_t)(256    //transfer size
            | (0 << 12)                //source burst size - 1
            | (0 << 15)                //destination burst size - 1
            | (0 << 18)                //source width - 8bit
            | (0 << 21)                //dest width - 8bit
            | (0 << 24)
            | (0 << 25)
            | (0 << 26)                //source increment - do not inc
            | (1 << 27)                //destination increment - inc
            | (0 << 28)
            | (0 << 29)
            | (0 << 30)
            | (1 << 31));                //terminal count interrupt - enabled

LPC_GPDMA->CONFIG = 1;                //Enable GPDMA Controller
while (!(LPC_GPDMA->CONFIG & 1));    //check enable
    
LPC_GPDMA->C0CONFIG = 0         //Channel Disable
                | ((1 & 0x1f) << 1)                //source peripheral - Cap0_2
                | (0 << 6)                              //dest request memory - none
                | (2 << 11)                            //flow control - peripheral to memory
                | (1 << 14)                           //(14) - mask out error interrupt
                | (1 << 15)                           //(15) - mask out terminal count interrupt
                | (0 << 16)                          //(16) - no locked transfers
                | (0 << 18);                        //(18) - no HALT
                
//Enable GPDMA interrupt
NVIC_EnableIRQ(DMA_IRQn);
    
LPC_GPDMA->C0CONFIG |= 1;                    //Channel Enable
//Here i received an interrupt error (LPC_GPDMA->INTERRSTAT=1) and the DMA Channel is disabled

Can anyone help me for a correct acquisition and DMA initialization?
Thanks in advance.
0 项奖励
回复
68 回复数

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Wed Oct 01 06:02:23 MST 2014
Hello Parsa,

congratulation!

It took myself several months to get my camera working, but I learned very much.
And I mainly see my robot as a learning platform - if it is slow but works with a clever algorithm it gives me more than a simple but maybe faster robot.

Good luck on your further projects!

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Wed Oct 01 01:40:15 MST 2014
Hi Fred,
The good news, I got an image almost clear.
I wanted to thank you for all the good advice and guidance.
For your robot, I looked in the detection of objects.
Matlab image processing is enough for this case(Because I've seen for face recognition using neural networks).
Note:I think the speed of ​​robot will be less than before(For calculations of MATLAB).
And also trial and error of robot will increase. I think if we have both of camera and IR sensor together, we have better performance.
Parsa
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Mon Sep 29 01:30:41 MST 2014
Hi Parsa, try 85x54 or 86x53, or try other pair, you need a straight vertikal line.

The camera resolution in the output data is a little different to the setup resolution, I had the same problem and I came to a solution by trial & error.

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Mon Sep 29 01:13:11 MST 2014
Hi Fred,
I had 9180 byte and I set the matrix 80*57 in matlab.
So the program works correctly and in your opinion there is problem to display?
I don't work recognition algorithm (I want to learn),but I want to use some Image processing orders in image if that display correctly!!
A few years ago I worked on line follower robot using infrared sensors and AVR micro.
Its performance was similar.
Parsa
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Mon Sep 29 00:42:58 MST 2014
Hi Parsa,

the picture looks good, the only problem (I think) you have is that the data is not really 80x60 but maybe 72x60 (you have to try that).
The black dots you see are simply the black border on each edge of the frame.
Play around with the vertical resolutuion of your display program (matlab?), the black dots should become vertical lines at the edge.
If they are not at the edge you have to insert dummy pixels at the beginning of the frame.

For my C# program (see screenshot):
You need Windows and "Microsoft Visual Studio Express 2013 for Windows Desktop" which is free.
C# is very similar to C++, but my program is not commented so it's maybe hard to implement.
It uses a special serial protocol which can send debug messages and images, depending on a ID field in the first byte.
The LpcXpresso code exists for this protocol, based on Rtos.

I have a question to you: You use Matlab, are you expirienced in mathematics? I am looking for an object recognition algorithm for my robot:
http://www.youtube.com/watch?v=QCR21yhk7g4
to find the black line in the camera picture. Can you help me here?

Fred

0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Sun Sep 28 10:56:03 MST 2014
Hi Fred,
I use this code to capture 10th frame(resolution is 80*60 and RGB565)
void CameraFrameInterrupt(void)
{
CameraFrameCount ++;
CameraByteCountSum = CameraByteCount;
CameraByteCount = 0;
if (CameraFrameCount<=10)
{
LPC_TIM1->MCR = 3;//on match reset counter + interrupt
}
}

void TIMER1_IRQHandler (void)
{LPC_TIM1->IR = 1;  // clear interrupt flag MR0
  if((LPC_GPIO1->FIOPIN&0x100)==0x100){  // Check HREF

CameraBuffer1[CameraByteCount++] = (LPC_GPIO2->FIOPIN);

if (CameraByteCount >=9180)
{  
LPC_TIM1->MCR = 2;//on match reset counter + no interrupt
}
}
}  
main(void){
//Another configuration
OV7670_Reset();
write_ov7670_reg(0x11,0x98); //pclk=800Khz
camera_QQVGA_RGB565();
write_ov7670_reg(0x0c, 0x04);  //scale enable
write_ov7670_reg(0x3e, 0x1b);//PLCK Divider: :0=0x00/ :2=0x19 :4=0x1A :8=0x1B
write_ov7670_reg(0x73, 0xf3);//CLK Divider:  :0=0xF0/ :2=0xF1 :4=0xF2 :8=0xF3
write_ov7670_reg(0x72, 0x33);//Picture Divider: Bit4-7=Vertical, Bit0-3=Horizontal :0=0 :2=1 :4=2 :8=3
CameraInit(); 
while(1)
{

if(CameraFrameCount==11)
{ 

for (t=0; t<=9120;t++)
{ putch2(CameraBuffer1[t]);
           delay(2000); //100us
 }
}
 
} 
} 

I want to know this method is true or not?. I use delay for sending data, because the baud rate is 256000bps and we need that data is correctly sent .
The image is not clear, I've attached two images
when I cover the lens work correctly, we have just black. but when I uncover.....
PCLK and VSYNC work properly. I think there are some problem with code that convert RGB565 to RGB888 for dispaly or
maybe I have problem with hardware .
For C# code that you recommend me, I don't work with C#. Can I use that?
If yes, In the next post I will send you the mail.
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Sat Sep 27 07:41:05 MST 2014
Hi Parsa,

to display the frame I made a C# program which is capable to display debug messages and video frames.
I use a special serial protocol which sends the frame data in blocks of one line with fixed length.

If you are interrested in the code I can send you the code, but not here in the forum. Send me an email with the LPCxpresso Contact function with your email, and I send the code to you personaly.

Fred

0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Sat Sep 27 07:27:56 MST 2014
Hi Fred,
Thanks for some tips that remind me.
I want break the while loop at 10th frame and have for loop to send data out of that.
because the rate of data is high and in Realterm(my terminal)we have error. for example we send 9600 byte
but on screen display 20000 char. and also max rate of Matlab is 256000bps.
Now I have 921600bps rate.
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Sat Sep 27 07:20:40 MST 2014
Hi Parsa,

First thing: I missed someting in code #58 :
void CameraStartDma(void)
{
LPC_GPDMACH0->DMACCSrcAddr = (uint32_t) &LPC_GPIO2->FIOPIN;
LPC_GPDMACH0->DMACCDestAddr = (uintptr_t) CameraBuffer1;
LPC_GPDMACH0->DMACCControl = (BlockSize & 0x0FFF)|0x88408000;
LPC_GPDMACH0->DMACCLLI = 0;
LPC_GPDMACH0->DMACCConfig = 0x0000D015;

LPC_GPDMA->DMACIntTCClear = 0x01<<0;
LPC_GPDMA->DMACIntErrClr = 0x01<<0;
LPC_TIM1->IR = 1;/* clear Timer interrupt flag */
}


We need the AND for every DMA code, because we cannot do if "(LPC_GPIO1->FIOPIN&0x100)" .
Otherwise the DMA code will give the same result like #47 without "if (LPC_GPIO1->FIOPIN&0x100)" - a big amount of data where you don't know what is data and what is blank.

And yes, you can do following:
void CameraFrameInterrupt(void)
{
CameraFrameCount ++;
CameraByteCountSum = CameraByteCount;
CameraByteCount = 0;
if (CameraFrameCount < 10)
{
LPC_TIM1->MCR = 3;//on match reset counter + interrupt
}
}

and send out data if CameraFrameCount is 10 in main loop (make also CameraFrameCount ++ there otherwise you may send the data more than one time)


In my test code it is more complicated: I will capture a frame only if I send a "f" character via the serial terminal. This character will set a variable to 1, when the CameraFrameInterrupt see this he enables the timer for one frame.
The main loop will send the data if the DmaTerminalInterrupt ( in your case "if (CameraByteCount >= 100)" has set another variable to 1. which means the data capture finished.

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Sat Sep 27 06:48:44 MST 2014
Hi Fred,
Thanks, I will try this code today, but I have question from last post.
Can we capture a frame? for example 10th frame with  #47 code and stop timers.
and out of main loop we send out camerabuffer1 to PC and display image?
Do you test like this?
for example we have low resolution 80*60 and RGB565(9600 byte)
Do we need AND in first step of DMA?
Parsa
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Sat Sep 27 06:30:27 MST 2014
Hi Parsa, here is my first try of a DMA-code for you (modified code #47).
Please read the User Manual and check what I am doing, I have to extract this from a much more complex code and can easily forget parts.

Note that DMA  transfer limit is 4095 bytes (0xFFF). If you want to transfer more you have to use Linked List (see User Manual). Because this is complicated this first example is whithout it.


volatile unsigned int CameraFrameCount = 0;
volatile unsigned int CameraDMACount = 0;
volatile unsigned int BlockSize = 0x0FFF;


int main(void)
{
//your generic setup function come here
//your serial setup function come here
//your camera setup functons come here
DMA_Init();
CameraInit();
Serial_printString("***LPC Start*** \r");
unsigned int CameraframeDebugCount =0;
while(1)
{
if (CameraframeDebugCount != CameraFrameCount)
{
CameraframeDebugCount = CameraFrameCount;
Serial_printNumber(CameraframeDebugCount);
putch(09); //tab character
Serial_printNumber(CameraDMACount);
putch(09); //tab character
unsigned int t;
for (t=0; t<=10; t++)
{
Serial_printNumber(CameraBuffer1[t + STARTDEBUGATBYTE]);
putch(59); //; character
}
putch(13); //cr character
}
}
}

void CameraDmaTerminalInterrupt(void)
{
CameraDMACount++;
}

void CameraFrameInterrupt(void)
{
CameraFrameCount ++;
CameraStartDma();
}

void CameraStartDma(void)
{
LPC_GPDMACH0->DMACCSrcAddr = (uint32_t) &LPC_GPIO2->FIOPIN;
LPC_GPDMACH0->DMACCDestAddr = (uintptr_t) CameraBuffer1;
LPC_GPDMACH0->DMACCControl = (BlockSize & 0x0FFF)|0x88408000;
LPC_GPDMACH0->DMACCLLI = 0;
}


void CameraInit(void)
{
...
LPC_TIM1->MCR = 2;//on match reset counter + no interrupt
...
}

void DMA_Init( void )
{
/* Enable CLOCK into GPDMA controller */
LPC_SC->PCONP |= (1 << 29);

/* Select secondary function(Timer) in DMA channels */
LPC_SC->DMAREQSEL = 0xFF;

/* Clear DMA channel 0~3 interrupts. */
LPC_GPDMA->DMACIntTCClear = 0x0F;
LPC_GPDMA->DMACIntErrClr = 0x0F;

LPC_GPDMA->DMACConfig = 0x01;/* Enable DMA channels, little endian */
while ( !(LPC_GPDMA->DMACConfig & 0x01) );

NVIC_SetPriority(DMA_IRQn, 30);
NVIC_EnableIRQ(DMA_IRQn);
}

void DMA_IRQHandler(void)
{
uint32_t regVal;
regVal = LPC_GPDMA->DMACIntTCStat;
if ( regVal )
{
LPC_GPDMA->DMACIntTCClear = regVal;
if ( regVal & (0x01<<0) )
{
CameraDmaTerminalInterrupt();
}
}

regVal = LPC_GPDMA->DMACIntErrStat;
if ( regVal )
{
LPC_GPDMA->DMACIntErrClr = regVal;
}
}



Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Sat Sep 27 02:38:43 MST 2014
Hello Parsa,
congratulation, what was the problem?

You can capture a picture with #47, just increase "if (CameraByteCount >= 100)".
And don't send debug messages in the main loop but real data.

Maybe dont send out the first frame but maybe the 10th, because the camera luminance control and clock pll need some time to stabilise.

One problem: YUYV and RGB565 use a 2 byte format. Maybe you have to insert one dummy byte at the beginning to bring the outbut pair in the right order.

Use a low resolution and framerate not to overwhelm the interrupts.
I think a running interrupt capture is a must before starting DMA, because in the latter we have no control about the data transfer at all, so all problems must be fixed in the interrupt mode.

In the next hours I will prepare the first DMA example code.

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Sat Sep 27 00:32:02 MST 2014
Hi Fred,
Hardware problem is solved. In #53 code and #43 we have a stable PCLK.
In #47, frame rate is stable and in different point(dark and light), bytes have changed.
I think, we can start with DMA and capture a image.
Parsa
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Fri Sep 26 01:46:21 MST 2014
Hi Fred,
I can get Frameinterrupt whithout calling EINT3_IRQHandler(); in the main loop.
I understand that the problem is hardware. Frequency is changed to pin micro.
I check power supply and another connection. There are some loading effect.
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Fri Sep 26 01:33:16 MST 2014
Hi Parsa,

one more point:
DMA is completely dependent on the timer match event. So at least the code in #53 must give stable PCLK count, otherwise it makes no sense to try DMA.
And the AND gate is absolutely neccecary for DMA!

And answer this question from #47:
what about the change in #45, do you get the Frameinterrupt whithout calling EINT3_IRQHandler(); in the main loop?

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Fri Sep 26 00:40:39 MST 2014
Hello Parsa,

do following experiment:
Disable Timer match reset & interrupt, we simply want the timer to count the PCLK cycles (the rest of the code in CameraInit remains unchanged):
void CameraInit(void)
{
...
LPC_TIM1->MCR = 0;//no match reset, no interrupt
...
}


In CameraFrameInterrupt we just save the Timer's counter register and reset the timer.
So we count the PCLK cycles with the hardware timer instead using the interrupt.

void CameraFrameInterrupt (void)
{
CameraFrameCount ++;
CameraByteCountSum = LPC_TIM1->TC;
//ResetTimer1
LPC_TIM1->TCR = 3;
LPC_TIM1->TCR = 1;
}


And use only the camera setup described in #49. And play with the frame rate (register 0x11).
Some problem can be solved by making many tests, maybe one result gives us a clue what the problem is.
And maybe the AND gate helps.
Read the user manual to check what I am doing, maybe I forgot something in my setup routines.

Fred

0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Thu Sep 25 14:42:01 MST 2014
Hi Fred,
Maybe I have problem with hardware. But when I do not shake the camera and just I used a flashlight to shed light into the lens,frame rate and output byte change. My power supply is stable, but when I check VSYNC signal from camera until P0.8, frequency at the end of camera was stable(1Hz),but on P0.8 was unstable.(I use flat cable for connection).I should check it out.
Now in one position can we go to next step by DMA?
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Thu Sep 25 08:29:58 MST 2014
Hi Parsa,

is it possible that you have a loose contact?
Maybe your voltage is not stable?
For me this looks more like a hardware problem.

Fred
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Parsa on Thu Sep 25 08:29:49 MST 2014
Hi Fred,
when the position of camera is stable we have 9180 bytes and change the position at first unstable and after that some second became stable
that is true?!
0 项奖励
回复

1,601 次查看
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Superfred on Thu Sep 25 08:01:07 MST 2014
Hi Parsa,

try to reduce resolution to 80*60 YUYV:
i2cCameraWrite(0x11, 0x9d);//1picture/second
i2cCameraWrite(0x0c, 0x04);  //scale enable
i2cCameraWrite(0x3e, 0x1b);//PLCK Divider: :0=0x00/ :2=0x19 :4=0x1A :8=0x1B
i2cCameraWrite(0x73, 0xf3);//CLK Divider:  :0=0xF0/ :2=0xF1 :4=0xF2 :8=0xF3
i2cCameraWrite(0x72, 0x33);//Picture Divider: Bit4-7=Vertical, Bit0-3=Horizontal :0=0 :2=1 :4=2 :8=3


where i2cCameraWrite is my write function. I use 0x9d for register 0x11, this is 1FPS for my camera.
Note that this values wil not set YUYV mode, but it is the default, so power the camera off/on after sending the new values once.

You must get around 9000 bytes stable, otherwise we cannot proceed.
If it get not stable we will count the PCLK cycles with the timer itself.

Fred
0 项奖励
回复