DMAChannel help for reading camera data bus

Status
Not open for further replies.

Eule

New member
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:
PixelTiming.png

and the frame timing:
FrameTiming.png

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:
Status
Not open for further replies.
Back
Top