Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 1 of 1

Thread: DMAChannel help for reading camera data bus

  1. #1
    Junior Member
    Join Date
    Aug 2017
    Posts
    2

    DMAChannel help for reading camera data bus

    Hi

    I am trying to read the data bus (pins d0 to d7) from an OV2640 camera using DMA on a Teensy 3.6. I am using Teensduino 1.37.

    I currently have this implemented without DMA but am restricted to what speed I can run the pixel clock (PCLK) of the camera at.
    The current the system is working at a PCLK of about 1MHz, but I would like to increase this by using DMA.
    I have organised the data pins so that d0 to d7 are the first 8 pins on Port D of the teensy (GPIOD_PDIR).
    Essentially the data is clock out and should be read on the rising edge of the PCLK.

    Here the pixel timing:
    Click image for larger version. 

Name:	PixelTiming.png 
Views:	141 
Size:	458.8 KB 
ID:	11417

    and the frame timing:
    Click image for larger version. 

Name:	FrameTiming.png 
Views:	136 
Size:	375.0 KB 
ID:	11418

    There is a lot of I2C code involved in setting up the camera.
    In my case the camera is set to transfer jpg raw data so the data is not read out line by line but in just one single block.
    The following code snipped receives the data and loads it into the image buffer.

    Code:
    // Pins
    const byte VSYNC = 9;
    const byte HREF = 10;
    const byte PCLK = 11;
    
    static const uint16_t bufferSize = 100000;
    uint16_t imageBytes = 0;
    uint8_t image[bufferSize]; // max space, should be enough since data is jpg compressed.
    
    
    inline bool checkVSync(void) {
    	return digitalReadFast(VSYNC);
    }
    
    inline bool checkHRef(void) {
    	return digitalReadFast(HREF);
    }
    
    inline bool checkPClk(void) {
    	return digitalReadFast(PCLK);
    }
    
    void acquireJPGImage(void) {
    	imageBytes = 0;
    	uint8_t imageByte;
    	while (checkVSync());    // Wait for the old frame to end
    	while (!checkVSync());  // Wait for a new frame to start
    
    	while (checkVSync()) {
    		while (checkVSync() && !checkHRef()); // Wait for a line to start
    		if (!checkVSync()) {
    			break;  // Line didn't start, but frame ended
    		}
    		while (!checkPClk()); // Wait for clock to go high
    		imageByte = GPIOD_PDIR & 0xFF; // read the data
    		if (imageBytes < bufferSize)
    			image[imageBytes++] = imageByte;
    		while (checkPClk());   // Wait for clock to go back low
    	}
    }
    I want to use the DMAChannel library but am stuck on the detail. I have no experience with DMA so any help would be great.
    Below is a small code snipped that I put together for initialising the DMA (it is nowhere ready yet).
    The trigger on pin 6 part is set to falling edge and needs to change to rising edge (I found that in another post).

    Code:
    DMAChannel dma;       // dma Channel
    
    void dmaInit(void) {
    	// const byte PCLK = 11; native C6
    	// Configure to trigger DMA of falling edge of signal applied to Pin 6
    	SIM_SCGC5 |= SIM_SCGC5_PORTC;
    	CORE_PIN2_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_IRQC(6);
    	SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
    	SIM_SCGC7 |= SIM_SCGC7_DMA;
    
    
    	dma.source(*(uint8_t*)&GPIOD_PDIR);
    	dma.destinationBuffer(image, sizeof(image));
    	// An interrupt routine can be run when the DMA channel completes
    	// the entire transfer, and also optionally when half of the
    	// transfer is completed.
    	dma.attachInterrupt(dma_isr); 
    	dma.interruptAtCompletion();
    	// Triggers cause the DMA channel to actually move data.  Each
    	// trigger moves a single data unit, which is typically 8, 16 or
    	// 32 bits.  If a channel is configured for 200 transfers
    	// Use a hardware trigger to make the DMA channel run
    	// const byte PCLK = 11; native C6
    	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PORTD);
    	dma.enable();
    }
    
    void dma_isr() {
    	dma.detachInterrupt();
    	dma.disable();
    }
    I want to receive a single image and then stop.
    How do I specify that I want to only read the first 8 pins of Port D?
    How do I tell the DMA to transfer that byte into the memory buffer (rather than a larger word)?
    How do I implement the VSYNC (frame start) and HREF (first line start) part into the DMA transfer?
    If you have any other suggestions on how to speed this up, please let me know.

    Thanks a lot for your help in advance.

    Regards
    Last edited by Eule; 08-30-2017 at 03:14 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •