Problem trying to read OV7670 camera under IRQ Teensy 4.0

Status
Not open for further replies.
Hello,

As far as I can tell, the CPU is crashed and the main loop is not running anymore.
For a while I thought that the problem might be that I would stay in the camera IRQ, but I have put timeouts there now, so it should not happen...
unless of course the IRQ keeps repeating immediately after exiting?
One issue is that I have no HW tools (no loggers), all I have is a multi-meter :-( so that makes life harder...
But anyhow, I have no free pins to use to indicate status either... and of course if the main loop is dead, Serial.write does not work either (I assume at least)..

I need to keep searching...
Cyrille
 
Hello,

As far as I can tell, the CPU is crashed and the main loop is not running anymore.
For a while I thought that the problem might be that I would stay in the camera IRQ, but I have put timeouts there now, so it should not happen...
unless of course the IRQ keeps repeating immediately after exiting?
One issue is that I have no HW tools (no loggers), all I have is a multi-meter :-( so that makes life harder...
But anyhow, I have no free pins to use to indicate status either... and of course if the main loop is dead, Serial.write does not work either (I assume at least)..

I need to keep searching...
Cyrille
 
I hear you,

Which is one reason I am using T4.1... Also I don't leave home with it (Logic Analyzer) ;)

The one thought I had for you, is I don't think I see any I2C communications, after the initial camera settings are done...

So thought about trying to switch the SDA pin (18) to be a standard digital pin... Could potentially use it to signal things... Although again without LA hard to keep track of the state...
Unless you have another Teensy or the like that could monitor it.

Could even try the Teensy Logic Analyzer: https://github.com/LAtimes2/TeensyLogicAnalyzer
It has been a long time since I tried it out, but...

Again assuming one could switch that pin to be a standard IO pin, you might even be able to experiment what would happen if you connected it to the ISR pin for Touch... Can you use it then to see when user has finger on screen and only do SPI then...
 
The main loop() will freeze out if an _isr() is taking too much time ... not sure what is in process - and crash always possible for other reasons.

I dropped a pair of cameras in the amzn cart and they got ordered ...
 
@Cyrille (and @defragster) will try to take a look at your current stuff - is your github reasonably up to date?

Note: with the DMA stuff. I am thinking about rearranging which pins I use for what. May start off with T4.1 version, but can also probably rearrange what does what...

Not sure yet. That is, if I have the DMA run off the PCLK like I show below:
screenshot.jpg
Will I only get the pixels.
But maybe I want some of the other data items like the Horizontal ... to also be captured and as such in the GPIO 1(6) or ...
Will play more.

Note: with T4, especially for debugging one can solder wires to bottom pads to get more pins available. Also if you make your own PCB like this could add in simple SMT pads and add those extra 10 pins, like we do for T3.2 ...

More later
 
Progress

CamImage1.png

I've made reasonable progress getting the OV7670 to work on my T4.1 breadboard. I'm using Cyrille's algorithm where there are interrupts for frame sync and HREF. The HREF service routine then collects the pixels in a polling loop. That loop lasts about 120 microseconds with a 4MHz pixel clock. I also used Cyrille's pin assignments so that the code should be T4.0 compatible.

Once the RGB pixels are collected I upload them to my laptop via USB serial, where I change the RGB565 pixels to an RGB888 bitmap for display. My ImageHost program is built with the free Community version of C++ Builder from Embarcadero.

The following issues are still being worked on:

1. Pixel clock rate is limited by the terrible signal quality of the pixel bits over the plugboard wires. A soldered breadboard should help with that issue, but it will have to wait until I get back from my trailer camping trip next week.
2. The OV7670 Register settings are very important in achieving a good image. I used a register setup from ComputerNerd that I got from GitHub. It is well commented and apparently derives from the Linux camera driver.
3. I still have some problems with color saturation that I will work on over the next few days. My ImageHost allows me to change registers while the camera is running, so I can tweak some settings. I have no Oscilloscope or logic analyzer with me, so the process will be to change a register, look at the image, repeat as needed.
4. I have had no luck getting a full VGA image to display properly. I think part of the problem is that the camera code spends too much time in the interrupt handler when collecting 640 pixels. With QVGA, you get a break of 3 line times between 320-pixel lines and that gives the rest of the code some time to run.

My laptop and the cell phone I'm using for internet need charging, so I'll have to continue after some charging time.
 
@mborgerson - Looks like you are making progress.

Today I have been playing with the first experiment to try to get DMA working. I think I have most of the pieces in place, but not working yet.
Pushed up the WIP to: https://github.com/KurtE/Arduino_OV767X/tree/Teensy_t4

The main work code is:
Code:
//================================================================================
// experiment with DMA
//================================================================================
// Define our DMA structure. 
DMAChannel OV767X::_dmachannel;
DMASetting OV767X::_dmasettings[2];
uint32_t OV767X::_dmaBuffer[DMABUFFER_SIZE];
extern "C" void xbar_connect(unsigned int input, unsigned int output); // in pwm.c

void dumpDMA_TCD(DMABaseClass *dmabc)
{
  Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);

  Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
    dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR, 
    dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
}

void xbar01_isr() {
  // Curious to see if this will signal or not...
  digitalToggleFast(33);
  XBARA1_CTRL0 |=  XBARA_CTRL_STS0;

}

void OV767X::readFrameDMA(void* buffer)
{
  // Lets try to setup the DMA setup...
  // first see if we can convert the _pclk to be an XBAR Input pin...
  // OV7670_PLK   4
  *(portConfigRegister(_pclkPin)) = 3; // set to XBAR mode (xbar 8)

  // route the timer outputs through XBAR to edge trigger DMA request
  CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
  xbar_connect(XBARA1_IN_IOMUX_XBAR_INOUT08, XBARA1_OUT_DMA_CH_MUX_REQ30);

  // Tell XBAR to dDMA on Rising 
  attachInterruptVector(IRQ_XBAR1_01, &xbar01_isr);
  XBARA1_CTRL0 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(1) | XBARA_CTRL_DEN0 | XBARA_CTRL_IEN0;

  IOMUXC_GPR_GPR6 &= ~(IOMUXC_GPR_GPR6_IOMUXC_XBAR_DIR_SEL_8);  // Make sure it is input mode
  IOMUXC_XBAR1_IN08_SELECT_INPUT = 0; // Make sure this signal goes to this pin...

  // Need to switch the IO pins back to GPI1 from GPIO6
  IOMUXC_GPR_GPR26 &= ~(0x0FCC0000u); 


  // lets figure out how many bytes we will tranfer per setting...
  int bytesPerRow = _width * _bytesPerPixel;
  _rows_per_dma = DMABUFFER_SIZE / (bytesPerRow * 2);
  uint16_t bytes_per_dma = _rows_per_dma * bytesPerRow; // 

  // configure DMA channels
  //  _dmasettings[0].begin();
  _pixels_per_dma = bytes_per_dma / _bytesPerPixel;  // probably can hard code to 2...
  _rows_left_dma = _height;
  _frame_buffer_pointer = (uint16_t *)buffer;
  _dma_done = false;
  _dma_index = 0;

  _dmasettings[0].source(GPIO1_DR); // setup source.
  _dmasettings[0].destinationBuffer(_dmaBuffer, bytes_per_dma * 4);  // 32 bits per logical byte
  _dmasettings[0].replaceSettingsOnCompletion(_dmasettings[1]);
  _dmasettings[0].interruptAtCompletion();  // we will need an interrupt to process this.
  _dmasettings[0].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // Don't disable on this one

  _dmasettings[1].source(GPIO1_DR); // setup source.
  _dmasettings[1].destinationBuffer(&_dmaBuffer[bytes_per_dma], bytes_per_dma * 4);  // 32 bits per logical byte
  _dmasettings[1].replaceSettingsOnCompletion(_dmasettings[0]);
  _dmasettings[1].interruptAtCompletion();  // we will need an interrupt to process this.
  _dmasettings[1].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // Don't disable on this one

  _dmachannel = _dmasettings[0];  // setup the first on...
  _dmachannel.attachInterrupt(dmaInterrupt);
  _dmachannel.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);


  // Falling edge indicates start of frame
  while ((*_vsyncPort & _vsyncMask) == 0); // wait for HIGH
  while ((*_vsyncPort & _vsyncMask) != 0); // wait for LOW
  digitalWriteFast(32, HIGH);

  // We have the start of a frame, so lets start the dma.
  dumpDMA_TCD(&_dmachannel);
  dumpDMA_TCD(&_dmasettings[0]);
  dumpDMA_TCD(&_dmasettings[1]);
  Serial.printf("pclk pin: %d config:%x control:%x\n", _pclkPin, *(portConfigRegister(_pclkPin)), *(portControlRegister(_pclkPin)));
  Serial.printf("IOMUXC_GPR_GPR26:%x\n", IOMUXC_GPR_GPR26);
  Serial.printf("XBAR CTRL0:%x CTRL1:%x\n", XBARA1_CTRL0, XBARA1_CTRL1);


  _dmachannel.begin(true);
  _dmachannel.enable();
 
  // clear any previous status. 
  XBARA1_CTRL0 |=  XBARA_CTRL_STS0;

  // hopefully it start here (fingers crossed)
  // for now will hang here to see if completes...
  elapsedMillis em = 0;
  while ((em < 1000) && !_dma_done) ; // wait up to a second...
  if (!_dma_done) Serial.println("Dma did not complete");
  digitalWriteFast(32, LOW);

  dumpDMA_TCD(&_dmachannel);
  dumpDMA_TCD(&_dmasettings[0]);
  dumpDMA_TCD(&_dmasettings[1]);

}

void OV767X::dmaInterrupt() {
  Camera.processDMAInterrupt();  // lets get back to the main object...
}

void OV767X::processDMAInterrupt() {
  _dmachannel.clearInterrupt(); // tell system we processed it.
    digitalToggleFast(33);

  // lets guess which buffer completed.
  _dma_index++;
  uint32_t *buffer = (_dma_index & 1) ? _dmaBuffer : (uint32_t*)_dmasettings[1].TCD->DADDR;
  uint16_t pixels_per_dma = _pixels_per_dma;      
  // process the pixels...
  while (pixels_per_dma--) {
    uint8_t lsb = *buffer++ >> 18;  
    lsb = (lsb & 0x3) | ((lsb & 0x3f0)>>2);
    uint8_t msb = *buffer++ >> 18;  
    msb = (msb & 0x3) | ((msb & 0x3f0)>>2);
    *_frame_buffer_pointer = (uint16_t)(msb << 8) | lsb;
  }      

  // see if we are done or ... 
  if (!_rows_left_dma) {
      _dma_done = true;
  } else {
    _rows_left_dma -= _rows_per_dma;
    if (_rows_left_dma <= (2*_rows_per_dma)) _dmasettings[1].disableOnCompletion(); 
  }

}

The debug output, note I did not put in the bytes in the pixel array here as they were all zero... DMA did not startup ...
Code:
OV767X Camera Capture

OV767X::begin
  VS=2, HR=3, PC=4 XC=5
  _dpins(0)=14
  _dpins(1)=15
  _dpins(2)=17
  _dpins(3)=16
  _dpins(4)=22
  _dpins(5)=23
  _dpins(6)=20
  _dpins(7)=21
arduino_i2c_write: address = 0x21, reg = 0x12, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x11, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x3A, value = 0x4
arduino_i2c_write: address = 0x21, reg = 0x12, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x17, value = 0x13
arduino_i2c_write: address = 0x21, reg = 0x18, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x32, value = 0xB6
arduino_i2c_write: address = 0x21, reg = 0x19, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x1A, value = 0x7A
arduino_i2c_write: address = 0x21, reg = 0x3, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0xC, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x3E, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x70, value = 0x3A
arduino_i2c_write: address = 0x21, reg = 0x71, value = 0x35
arduino_i2c_write: address = 0x21, reg = 0x72, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x73, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0xA2, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x15, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x7A, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x7B, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0x7C, value = 0x1E
arduino_i2c_write: address = 0x21, reg = 0x7D, value = 0x35
arduino_i2c_write: address = 0x21, reg = 0x7E, value = 0x5A
arduino_i2c_write: address = 0x21, reg = 0x7F, value = 0x69
arduino_i2c_write: address = 0x21, reg = 0x80, value = 0x76
arduino_i2c_write: address = 0x21, reg = 0x81, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x82, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x83, value = 0x8F
arduino_i2c_write: address = 0x21, reg = 0x84, value = 0x96
arduino_i2c_write: address = 0x21, reg = 0x85, value = 0xA3
arduino_i2c_write: address = 0x21, reg = 0x86, value = 0xAF
arduino_i2c_write: address = 0x21, reg = 0x87, value = 0xC4
arduino_i2c_write: address = 0x21, reg = 0x88, value = 0xD7
arduino_i2c_write: address = 0x21, reg = 0x89, value = 0xE8
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE0
arduino_i2c_write: address = 0x21, reg = 0x0, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x10, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0xD, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x14, value = 0x18
arduino_i2c_write: address = 0x21, reg = 0xA5, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0xAB, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x24, value = 0x95
arduino_i2c_write: address = 0x21, reg = 0x25, value = 0x33
arduino_i2c_write: address = 0x21, reg = 0x26, value = 0xE3
arduino_i2c_write: address = 0x21, reg = 0x9F, value = 0x78
arduino_i2c_write: address = 0x21, reg = 0xA0, value = 0x68
arduino_i2c_write: address = 0x21, reg = 0xA1, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0xA6, value = 0xD8
arduino_i2c_write: address = 0x21, reg = 0xA7, value = 0xD8
arduino_i2c_write: address = 0x21, reg = 0xA8, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0xA9, value = 0x90
arduino_i2c_write: address = 0x21, reg = 0xAA, value = 0x94
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE5
arduino_i2c_write: address = 0x21, reg = 0xE, value = 0x61
arduino_i2c_write: address = 0x21, reg = 0xF, value = 0x4B
arduino_i2c_write: address = 0x21, reg = 0x16, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x1E, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x21, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x22, value = 0x91
arduino_i2c_write: address = 0x21, reg = 0x29, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x33, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0x35, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0x37, value = 0x1D
arduino_i2c_write: address = 0x21, reg = 0x38, value = 0x71
arduino_i2c_write: address = 0x21, reg = 0x39, value = 0x2A
arduino_i2c_write: address = 0x21, reg = 0x3C, value = 0x78
arduino_i2c_write: address = 0x21, reg = 0x4D, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x4E, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x69, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x6B, value = 0x4A
arduino_i2c_write: address = 0x21, reg = 0x74, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0x8D, value = 0x4F
arduino_i2c_write: address = 0x21, reg = 0x8E, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x8F, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x90, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x91, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x96, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x9A, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0xB0, value = 0x84
arduino_i2c_write: address = 0x21, reg = 0xB1, value = 0xC
arduino_i2c_write: address = 0x21, reg = 0xB2, value = 0xE
arduino_i2c_write: address = 0x21, reg = 0xB3, value = 0x82
arduino_i2c_write: address = 0x21, reg = 0xB8, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x43, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x44, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0x45, value = 0x34
arduino_i2c_write: address = 0x21, reg = 0x46, value = 0x58
arduino_i2c_write: address = 0x21, reg = 0x47, value = 0x28
arduino_i2c_write: address = 0x21, reg = 0x48, value = 0x3A
arduino_i2c_write: address = 0x21, reg = 0x59, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x5A, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x5B, value = 0x44
arduino_i2c_write: address = 0x21, reg = 0x5C, value = 0x67
arduino_i2c_write: address = 0x21, reg = 0x5D, value = 0x49
arduino_i2c_write: address = 0x21, reg = 0x5E, value = 0xE
arduino_i2c_write: address = 0x21, reg = 0x6C, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x6D, value = 0x55
arduino_i2c_write: address = 0x21, reg = 0x6E, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x6F, value = 0x9F
arduino_i2c_write: address = 0x21, reg = 0x6A, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x1, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x2, value = 0x60
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE7
arduino_i2c_write: address = 0x21, reg = 0x4F, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x50, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x51, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x52, value = 0x22
arduino_i2c_write: address = 0x21, reg = 0x53, value = 0x5E
arduino_i2c_write: address = 0x21, reg = 0x54, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x58, value = 0x9E
arduino_i2c_write: address = 0x21, reg = 0x41, value = 0x8
arduino_i2c_write: address = 0x21, reg = 0x3F, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x75, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0x76, value = 0xE1
arduino_i2c_write: address = 0x21, reg = 0x4C, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x77, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x3D, value = 0xC3
arduino_i2c_write: address = 0x21, reg = 0x4B, value = 0x9
arduino_i2c_write: address = 0x21, reg = 0xC9, value = 0x60
arduino_i2c_write: address = 0x21, reg = 0x41, value = 0x38
arduino_i2c_write: address = 0x21, reg = 0x56, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x34, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x3B, value = 0x12
arduino_i2c_write: address = 0x21, reg = 0xA4, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x96, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x97, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x98, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x99, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x9A, value = 0x84
arduino_i2c_write: address = 0x21, reg = 0x9B, value = 0x29
arduino_i2c_write: address = 0x21, reg = 0x9C, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0x9D, value = 0x4C
arduino_i2c_write: address = 0x21, reg = 0x9E, value = 0x3F
arduino_i2c_write: address = 0x21, reg = 0x78, value = 0x4
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xF
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x7E
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xC
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xF
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xD
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x9
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xC0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x26
arduino_i2c_read: address = 0x21, reg = 0x1C, value = 0x7F
arduino_i2c_read: address = 0x21, reg = 0x1D, value = 0xA2
arduino_i2c_read: address = 0x21, reg = 0xA, value = 0x76
arduino_i2c_read: address = 0x21, reg = 0xB, value = 0x73
arduino_i2c_write: address = 0x21, reg = 0x12, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x11, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x3A, value = 0x4
arduino_i2c_write: address = 0x21, reg = 0x12, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x17, value = 0x13
arduino_i2c_write: address = 0x21, reg = 0x18, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x32, value = 0xB6
arduino_i2c_write: address = 0x21, reg = 0x19, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x1A, value = 0x7A
arduino_i2c_write: address = 0x21, reg = 0x3, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0xC, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x3E, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x70, value = 0x3A
arduino_i2c_write: address = 0x21, reg = 0x71, value = 0x35
arduino_i2c_write: address = 0x21, reg = 0x72, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x73, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0xA2, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x15, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x7A, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x7B, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0x7C, value = 0x1E
arduino_i2c_write: address = 0x21, reg = 0x7D, value = 0x35
arduino_i2c_write: address = 0x21, reg = 0x7E, value = 0x5A
arduino_i2c_write: address = 0x21, reg = 0x7F, value = 0x69
arduino_i2c_write: address = 0x21, reg = 0x80, value = 0x76
arduino_i2c_write: address = 0x21, reg = 0x81, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x82, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x83, value = 0x8F
arduino_i2c_write: address = 0x21, reg = 0x84, value = 0x96
arduino_i2c_write: address = 0x21, reg = 0x85, value = 0xA3
arduino_i2c_write: address = 0x21, reg = 0x86, value = 0xAF
arduino_i2c_write: address = 0x21, reg = 0x87, value = 0xC4
arduino_i2c_write: address = 0x21, reg = 0x88, value = 0xD7
arduino_i2c_write: address = 0x21, reg = 0x89, value = 0xE8
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE0
arduino_i2c_write: address = 0x21, reg = 0x0, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x10, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0xD, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x14, value = 0x18
arduino_i2c_write: address = 0x21, reg = 0xA5, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0xAB, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x24, value = 0x95
arduino_i2c_write: address = 0x21, reg = 0x25, value = 0x33
arduino_i2c_write: address = 0x21, reg = 0x26, value = 0xE3
arduino_i2c_write: address = 0x21, reg = 0x9F, value = 0x78
arduino_i2c_write: address = 0x21, reg = 0xA0, value = 0x68
arduino_i2c_write: address = 0x21, reg = 0xA1, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0xA6, value = 0xD8
arduino_i2c_write: address = 0x21, reg = 0xA7, value = 0xD8
arduino_i2c_write: address = 0x21, reg = 0xA8, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0xA9, value = 0x90
arduino_i2c_write: address = 0x21, reg = 0xAA, value = 0x94
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE5
arduino_i2c_write: address = 0x21, reg = 0xE, value = 0x61
arduino_i2c_write: address = 0x21, reg = 0xF, value = 0x4B
arduino_i2c_write: address = 0x21, reg = 0x16, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x1E, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x21, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0x22, value = 0x91
arduino_i2c_write: address = 0x21, reg = 0x29, value = 0x7
arduino_i2c_write: address = 0x21, reg = 0x33, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0x35, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0x37, value = 0x1D
arduino_i2c_write: address = 0x21, reg = 0x38, value = 0x71
arduino_i2c_write: address = 0x21, reg = 0x39, value = 0x2A
arduino_i2c_write: address = 0x21, reg = 0x3C, value = 0x78
arduino_i2c_write: address = 0x21, reg = 0x4D, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x4E, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x69, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x6B, value = 0x4A
arduino_i2c_write: address = 0x21, reg = 0x74, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0x8D, value = 0x4F
arduino_i2c_write: address = 0x21, reg = 0x8E, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x8F, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x90, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x91, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x96, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x9A, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0xB0, value = 0x84
arduino_i2c_write: address = 0x21, reg = 0xB1, value = 0xC
arduino_i2c_write: address = 0x21, reg = 0xB2, value = 0xE
arduino_i2c_write: address = 0x21, reg = 0xB3, value = 0x82
arduino_i2c_write: address = 0x21, reg = 0xB8, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x43, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x44, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0x45, value = 0x34
arduino_i2c_write: address = 0x21, reg = 0x46, value = 0x58
arduino_i2c_write: address = 0x21, reg = 0x47, value = 0x28
arduino_i2c_write: address = 0x21, reg = 0x48, value = 0x3A
arduino_i2c_write: address = 0x21, reg = 0x59, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x5A, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x5B, value = 0x44
arduino_i2c_write: address = 0x21, reg = 0x5C, value = 0x67
arduino_i2c_write: address = 0x21, reg = 0x5D, value = 0x49
arduino_i2c_write: address = 0x21, reg = 0x5E, value = 0xE
arduino_i2c_write: address = 0x21, reg = 0x6C, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x6D, value = 0x55
arduino_i2c_write: address = 0x21, reg = 0x6E, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x6F, value = 0x9F
arduino_i2c_write: address = 0x21, reg = 0x6A, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x1, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x2, value = 0x60
arduino_i2c_write: address = 0x21, reg = 0x13, value = 0xE7
arduino_i2c_write: address = 0x21, reg = 0x4F, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x50, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x51, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x52, value = 0x22
arduino_i2c_write: address = 0x21, reg = 0x53, value = 0x5E
arduino_i2c_write: address = 0x21, reg = 0x54, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x58, value = 0x9E
arduino_i2c_write: address = 0x21, reg = 0x41, value = 0x8
arduino_i2c_write: address = 0x21, reg = 0x3F, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x75, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0x76, value = 0xE1
arduino_i2c_write: address = 0x21, reg = 0x4C, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x77, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x3D, value = 0xC3
arduino_i2c_write: address = 0x21, reg = 0x4B, value = 0x9
arduino_i2c_write: address = 0x21, reg = 0xC9, value = 0x60
arduino_i2c_write: address = 0x21, reg = 0x41, value = 0x38
arduino_i2c_write: address = 0x21, reg = 0x56, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x34, value = 0x11
arduino_i2c_write: address = 0x21, reg = 0x3B, value = 0x12
arduino_i2c_write: address = 0x21, reg = 0xA4, value = 0x88
arduino_i2c_write: address = 0x21, reg = 0x96, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x97, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x98, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x99, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x9A, value = 0x84
arduino_i2c_write: address = 0x21, reg = 0x9B, value = 0x29
arduino_i2c_write: address = 0x21, reg = 0x9C, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0x9D, value = 0x4C
arduino_i2c_write: address = 0x21, reg = 0x9E, value = 0x3F
arduino_i2c_write: address = 0x21, reg = 0x78, value = 0x4
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xF0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xF
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x7E
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xB
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xC
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xF
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0xD
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x9
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x2
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0xC0
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x40
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x5
arduino_i2c_write: address = 0x21, reg = 0xC8, value = 0x30
arduino_i2c_write: address = 0x21, reg = 0x79, value = 0x26
arduino_i2c_write: address = 0x21, reg = 0x12, value = 0x14
arduino_i2c_write: address = 0x21, reg = 0x15, value = 0x20
arduino_i2c_write: address = 0x21, reg = 0x8C, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x4, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x40, value = 0x10
arduino_i2c_write: address = 0x21, reg = 0x14, value = 0x38
arduino_i2c_write: address = 0x21, reg = 0x4F, value = 0xB3
arduino_i2c_write: address = 0x21, reg = 0x50, value = 0xB3
arduino_i2c_write: address = 0x21, reg = 0x51, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x52, value = 0x3D
arduino_i2c_write: address = 0x21, reg = 0x53, value = 0xA7
arduino_i2c_write: address = 0x21, reg = 0x54, value = 0xE4
arduino_i2c_write: address = 0x21, reg = 0x3D, value = 0xC0
arduino_i2c_write: address = 0x21, reg = 0x17, value = 0x15
arduino_i2c_write: address = 0x21, reg = 0x18, value = 0x3
arduino_i2c_read: address = 0x21, reg = 0x32, value = 0xB6
arduino_i2c_write: address = 0x21, reg = 0x32, value = 0x80
arduino_i2c_write: address = 0x21, reg = 0x19, value = 0x3
arduino_i2c_write: address = 0x21, reg = 0x1A, value = 0x7B
arduino_i2c_read: address = 0x21, reg = 0x3, value = 0xA
arduino_i2c_write: address = 0x21, reg = 0x3, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x11, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x11, value = 0x0
arduino_i2c_write: address = 0x21, reg = 0x6B, value = 0x4A
arduino_i2c_write: address = 0x21, reg = 0x11, value = 0x1
arduino_i2c_write: address = 0x21, reg = 0x6B, value = 0x4A
Camera settings:
	width = 320
	height = 240
	bits per pixel = 16

Send the 'c' character to read a frame ...
Send the 'd' character to read a frame using DMA ...
Send the 's' character to start/stop continuous display mode

Reading DMA frame

20027a84 400e9020:SA:401b8000 SO:0 AT:202 NB:4 SL:0 DA:20027b98 DO: 4 CI:500 DL:20027b00 CS:12 BI:500
20027aa0 20027ac0:SA:401b8000 SO:0 AT:202 NB:4 SL:0 DA:20027b98 DO: 4 CI:500 DL:20027b00 CS:12 BI:500
20027ae0 20027b00:SA:401b8000 SO:0 AT:202 NB:4 SL:0 DA:20028f98 DO: 4 CI:500 DL:20027ac0 CS:12 BI:500
pclk pin: 4 config:3 control:38
IOMUXC_GPR_GPR26:f033ffff
XBAR CTRL0:17 CTRL1:0
Dma did not complete
20027a84 400e9040:SA:0 SO:0 AT:0 NB:0 SL:0 DA:0 DO: 0 CI:0 DL:0 CS:0 BI:0
20027aa0 20027ac0:SA:401b8000 SO:0 AT:202 NB:4 SL:0 DA:20027b98 DO: 4 CI:500 DL:20027b00 CS:12 BI:500
20027ae0 20027b00:SA:401b8000 SO:0 AT:202 NB:4 SL:0 DA:20028f98 DO: 4 CI:500 DL:20027ac0 CS:12 BI:500
...
It would be great if someone who has played with DMA and GPIO and the like on T4.x to chime in, if they see somethign I missed or wrong ;)

Note: I hacked up some of the XBAR code to maybe help debug... Again on first run of code not seeing any thing on the last line, the line above is where it tries to start the DMA, and when it goes low it is because I have 1 second timeout...That is in addition to doing the DMA I told it to do ISR as well (maybe don't work at same time)...

screenshot.jpg
But if try running second time while some of the stuff is sort of setup, you see:

screenshot2.jpg
But it is before it starts up the rest of the setup for DMA... And if you look at closeup, I am not sure what it is running from, it shold be running at the speed of the calls for the redish line 5 up, which is real fast... Amost like the Horizontal line? ... Need to investigate.
screenshot3.jpg

To continue next message
 
Continue, in the above code the idea, is that we already have the camera running, so I wish to do DMA from the GPIO to memory where we use the PCLK to drive the DMA ...

Now the way I believe I need to use an external pin to maybe drive DMA is through XBAR:
So we have: #define OV7670_PLK 4
So for this pin I have: 4 EMC_06 4.6 PWM2_A0 2:TX_BCLK IO-08 1:6
So it is XBAR IO-08 pin.

So to initialize XBAR for this pin I have:
Code:
  // OV7670_PLK   4
  *(portConfigRegister(_pclkPin)) = 3; // set to XBAR mode (xbar 8)

  // route the timer outputs through XBAR to edge trigger DMA request
  CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
  xbar_connect(XBARA1_IN_IOMUX_XBAR_INOUT08, XBARA1_OUT_DMA_CH_MUX_REQ30);

  // Tell XBAR to dDMA on Rising 
  attachInterruptVector(IRQ_XBAR1_01, &xbar01_isr);
  XBARA1_CTRL0 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(1) | XBARA_CTRL_DEN0 | XBARA_CTRL_IEN0;

  IOMUXC_GPR_GPR6 &= ~(IOMUXC_GPR_GPR6_IOMUXC_XBAR_DIR_SEL_8);  // Make sure it is input mode
  IOMUXC_XBAR1_IN08_SELECT_INPUT = 0; // Make sure this signal goes to this pin...
Which I believe should change that pin to Mode 3 which I believe is correct for XBAR, This XBAR can be IN or OUT, so tell system to make it input mode, and as this signal can be input on a few pins, tell it to choose this one as the correct one.

I Then Route this XBAR IN/OUT signal to XBARA1_OUT_DMA_CH_MUX_REQ30 which I believe is the first DMA (part 0 of XBAR1_CTRL0)

I also then Tell XBAR to do DMA on EDGE 1 which is rising and debug I have it also doing ISR...


Then To work for GPIO6->1 pins, I need to tell all of these pins to go back to GPIO1 by:

Code:
  // Need to switch the IO pins back to GPI1 from GPIO6
  IOMUXC_GPR_GPR26 &= ~(0x0FCC0000u);

I then setup a DMA chain...
Code:
  _dmasettings[0].source(GPIO1_DR); // setup source.
  _dmasettings[0].destinationBuffer(_dmaBuffer, bytes_per_dma * 4);  // 32 bits per logical byte
  _dmasettings[0].replaceSettingsOnCompletion(_dmasettings[1]);
  _dmasettings[0].interruptAtCompletion();  // we will need an interrupt to process this.
  _dmasettings[0].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // Don't disable on this one

  _dmasettings[1].source(GPIO1_DR); // setup source.
  _dmasettings[1].destinationBuffer(&_dmaBuffer[bytes_per_dma], bytes_per_dma * 4);  // 32 bits per logical byte
  _dmasettings[1].replaceSettingsOnCompletion(_dmasettings[0]);
  _dmasettings[1].interruptAtCompletion();  // we will need an interrupt to process this.
  _dmasettings[1].TCD->CSR &= ~(DMA_TCD_CSR_DREQ); // Don't disable on this one

  _dmachannel = _dmasettings[0];  // setup the first on...
  _dmachannel.attachInterrupt(dmaInterrupt);
  _dmachannel.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);
I dump the information about the DMA settings and some stuff

Then I wait for the start of the page...
Tell dma channel to be enabled

And tried again clearing the old status...
Now more to figure out what I might have missed.
 
@KurtE: Are these the pins in use shown in the INO?:
Code:
      Teensy T4.x using ILI9341_t3n library.
        OV7670_VSYNC 2
        OV7670_HREF  3
        OV7670_PLK   4
        OV7670_XCLK  5
        OV7670_D0    14 // AD_B1_02 1.18
        OV7670_D1    15 // AD_B1_03 1.19
        OV7670_D3    16 // AD_B1_07 1.23
        OV7670_D2    17 // AD_B1_06 1.22
        OV7670_D6    20 // AD_B1_10
        OV7670_D7    21 // AD_B1_11
        OV7670_D4    22 // AD_B1_08
        OV7670_D5    23 // AD_B1_09

Those aren't the ideal DMA pins for a T_4.1 - or even the best data order for DMA on a 4.0?
 
Hello,

I am impressed...

It feels as if I have brought a spark to a rocket stack which is now going full bore to orbit! you guys are just amazing!

I was thinking, when it comes to wiring and the fact that no every teensy project will be able to use the same pins...
This actually might not be too much of a problem.
Let us assume, for example, that the input pins are spread on 2 bytes of IO ports...
At 'init' time, we could compute 2 256 bytes lookup tables that associates IO port bytes to bits of interest.
Then, when we receive a "line", we can, for each pixel do the following transform:

for (int i=0; i<nbPixels; i++)
out= table1[in[2*i]] | table2[in[2*i+1]];
or, in a more optimized way (assuming that the compiler is too dumb)
uint8_t *in= indata;
for (int i=0; i<nbPixels; i++)
{
uint8_t v1= table1[*in++]; uint8_t v2= table2[*in++];
out= v1|v2;
}
With a little bit of loop unrolling, this should be extremely fast, while still being configurable at runtime (or compile time... we can probably precompile the tables using templates if we really wanted to have "fun")

Cyrille
 
Paul does a lot behind the scenes ( and after ) to make a stable environment - but somethings do impressively take on a life of there own ...

I've only been half following - as I didn't figure I'd actually solder the things - but I left the $8 pair in the cart when my wife ordered and they arrived today - so now I need to pick the pins ...

... so not sure where the current _isr() code stands - but the port read and look up table could be tested there during the pixel waits. Getting done faster ( if it does) won't help ... but if it can be coded to allow the processor to dual execute the lookup in parallel the impact could be minimized.

And would this be better? - but one byte needs a shift<<8 for the 'or'?:
Code:
for (int i=0; i<nbPixels*2; i+=2)
  out[i]= table1[in[i]] | table2[in[i+1]];

The compiler has some good smarts.

Not sure if that will let the processor do dual? Is this better or worse?:
Code:
for (int i=0,j=1; i<nbPixels*2; i+=2,j+=2)
  out[i]= table1[in[i]] | table2[in[j]];
 
I see...

I do have a couple of PCb left that I can send around if it helps...
I am I Europe, so there is delay.. but at the moment, I am not using them...

Cyrille
 
Thanks, for the offer of a board... Right now I am just playing and not sure yet of which pins for which thing... So breadboard is not a bad thing... Not great either but...

@defragster. as about the pin numbers. Yes for T4.1 there could be more ideal pins to use, like 8 contiguous. Note: In my Excel document I added two new pages with the Tt and T4.1 pins listed in GPIO pin number order...

From the T4 page:
screenshot.jpg

Note: the ones in RED are the bottom pads and the ones in Green are the SDCard pins.
Also the table of pins mentioned above confused me at first as well as

Teensy T4.x using ILI9341_t3n library.
OV7670_VSYNC 2
OV7670_HREF 3
OV7670_PLK 4
OV7670_XCLK 5
OV7670_D0 14 // AD_B1_02 1.18
OV7670_D1 15 // AD_B1_03 1.19
OV7670_D3 16 // AD_B1_07 1.23
OV7670_D2 17 // AD_B1_06 1.22
OV7670_D6 20 // AD_B1_10
OV7670_D7 21 // AD_B1_11
OV7670_D4 22 // AD_B1_08
OV7670_D5 23 // AD_B1_09

And if you actually reorder you see:
Code:
#define OV7670_D0    14 // AD_B1_02 1.18
#define OV7670_D1    15 // AD_B1_03 1.19
#define OV7670_D2    17 // AD_B1_06 1.22
#define OV7670_D3    16 // AD_B1_07 1.23
#define OV7670_D4    22 // AD_B1_08
#define OV7670_D5    23 // AD_B1_09
#define OV7670_D6    20 // AD_B1_10
#define OV7670_D7    21 // AD_B1_11

Now back to debugging
 
Debugging, OK The routing of the PCLK should be correct. My try of doing the ISR to make sure yesterday did not work as I forgot to enable the interrupt(NVIC).

Have simple sketch that now looks like that part is working:
Code:
static const int _pclkPin = 4;

void xbar01_isr() {
  // Curious to see if this will signal or not...
  digitalToggleFast(13);
  XBARA1_CTRL0 |=  XBARA_CTRL_STS0;
  asm("DSB");

}

extern "C" void xbar_connect(unsigned int input, unsigned int output); // in pwm.c

void setup() {

  while (!Serial && millis() < 4000) ;
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  pinMode(_pclkPin, INPUT);
  analogWriteFrequency(5, 100);
  analogWrite(5, 127);

  // See if we can setup XBAR...
  *(portConfigRegister(_pclkPin)) = 3; // set to XBAR mode (xbar 8)

  // route the timer outputs through XBAR to edge trigger DMA request
  CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
  xbar_connect(XBARA1_IN_IOMUX_XBAR_INOUT08, XBARA1_OUT_DMA_CH_MUX_REQ30);

  // Tell XBAR to dDMA on Rising
  attachInterruptVector(IRQ_XBAR1_01, &xbar01_isr);
  NVIC_ENABLE_IRQ(IRQ_XBAR1_01);
  XBARA1_CTRL0 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(1) | XBARA_CTRL_IEN0;

  IOMUXC_GPR_GPR6 &= ~(IOMUXC_GPR_GPR6_IOMUXC_XBAR_DIR_SEL_8);  // Make sure it is input mode
  IOMUXC_XBAR1_IN08_SELECT_INPUT = 0; // Make sure this signal goes to this pin...
}

void loop() {
}
As I can see under LA:
screenshot.jpg
The first line is connected to 4/5 pins which are connected by jumper, and you see the PWM output.
The second line is connected to 13 and shows it changes on the rising signal....
 
:D I have fixed some of it, and I am starting to get some data... Wrong, but at least some data...

screenshot.jpg
The bottom line is where it is processing the data from DMA interrupt that comes in and converts the 32 bit values captured into pixel color data. It currently captures 2 horizontal lines of data per DMA... The data does not look correct yet, but at least getting closer.
 
More progress after solving the DAH issue of pixel data :eek:

It helps to have enough bits in your variables to hold the data ;)
Code:
   [COLOR="#FF0000"] uint16_t[/COLOR] lsb = *buffer++ >> 18;
    lsb = (lsb & 0x3) | ((lsb & 0x3f0) >> 2);
   [COLOR="#FF0000"] uint16_t msb[/COLOR] = *buffer++ >> 18;
    msb = (msb & 0x3) | ((msb & 0x3f0) >> 2);
    *_frame_buffer_pointer++ = (uint16_t)(msb << 8) | lsb;
These were 8 bits....

Now getting closer, but I am getting some spurious data items in the DMA buffer, that I need to either avoid and/or detect and recover.

The first thing I detected was an extra byte value (32 bits) at the start before the first true rising edge on the PCLK signal. So I thought I would try to see if I added a simple one item DMAChain at start of chain to read one entry and toss it, before continuing to see if that might align everything... Nope... But data is getting closer to be able to be read...

Sorry I may be mostly talking to self :D but I trying to decide an approach to try to align the processing of pixels to the correct data and have a couple of maybe ideas, but not sure which way to go yet...

Again extract from a run:
screenshot.jpg
I am using their Simple parallel analyzer, so you can see where it thinks the triggers are for the data... The line above it is the HREF pin, which I am more or less ignoring right now as it is controlling when the pclk is going...

But I am wondering if I should try to either use that pin, to help make sure I am on the data.

So was thinking of at least two possible ways:

a) switch HREF pin to be on GPIO1... On T4.1 would be easy For T4 and no bottom pins would be either pins 0 or 1...
Then when processing data, skip any entries that do not have this bit set... Would need to add some makeup read for that number of real data items needed... Might cause at times that if I guess to many entries, the DMA wont complete until the next frame begins, which would not be end of world...

b) Maybe some more glue (which so far is less than clear to me...) And may not be possible...
Was wondering if I could feed both IO pins in as for example currently on pin 3 it also is an XBAR pin(7). So then wondered if someway to feed both of these pins in and logically combine them to control the DMA clock. Maybe use the AOI subsystem, but the problem I think is AOI only works with XBARB (2,3) and not XBARA1... And then would would Feed XBARA1 to do DMA...

But so far I don't see any way to feed IO pins including XBAR Pins into XBARB2/3...


Any other hints would be great
 
Today I finally have a version of DMA code that actually appears to get a valid image.
IMG_0277.jpg

next setup continuous update... And two frame buffers...
Moved href pin to gpio1...
 
My Logic Pro has some trouble with the OV7670 logic signals. For one there seems to be some crosstalk from the pixel clock, and in addition the camera runs on 2.8V not 3.3V ...

Kind regards,
Sebastian
 
@wangnick
My Logic Pro is the Pro 8 so does not have enough signals... So I am using my older Logic 16 which is not near as fast. It also at times gives me the error about USB timeout, but usually after I have the data I want.

Which software are you using? These days I am mainly using their Version 2 software... Currently 2.3.9 (https://discuss.saleae.com/)
 
@Kurte: I'm planning to solder up a proto board for the OV7670 in a few days. I intend to use 8 contiguous port pins for the camera data bits, and I thought I'd also have optional wiring to use the CSI hardware. I note that your latest Excel sheet for the T4.1 lists 6 of the 8 bits in the 'Prop' column, but CSI_D0 and CSI_D1 are missing. Is that because they don't go to accessible pins? Or do they require special crossbar programming? (I must admit the crossbar programming is still a mystery to me.)

As shown on the Excel spreadsheet CSI_D2 to CSI_D7 are on AD_B1_15 to AD_B1_10, so a regular NON_CSI use of these pins would have the bit order reversed. I think the OV7670 may have a register setting to reverse bit order in the output bytes, but I'll have to confirm that. Worst case, a 256-byte lookup table could swap the bit order if I CSI_D0 and CSID1 are actually on the right bits of AD_B1. It may also be possible that the CSI hardware can do the bit order swap.
 
The CSI pins:
As you noted B1_10 and B1_11 have not been exposed on the T4 or T4.1 Note: AD_B1_... is different than B1_...

But as was noted earlier in this thread I think. The CSI note:
Code:
The CSI can support connection with the sensor as follows.
• To connect with one 8-bit sensor, the sensor data interface should connect to
CSI_DATA[9:2]

So for 8 pins we need signals 2-9 But I also don't see 8 or 9...
 
The CSI pins:

So for 8 pins we need signals 2-9 But I also don't see 8 or 9...

This code from BrainGram seems to connect signals 2-9 by manipulating the IOMUX (which, like the XBARs is still a mystery to me):
Code:
  // VSYNC
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_06 = 0x4U;
  IOMUXC_CSI_VSYNC_SELECT_INPUT = 0x1U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_06 = 0x0U;
  // HSYNC
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_07 = 0x4U;
  IOMUXC_CSI_HSYNC_SELECT_INPUT = 0x1U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07 = 0x0U;
  // DCLK
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_04 = 0x4U;
  IOMUXC_CSI_PIXCLK_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_04 = 0x0U;
  // D7-D0
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08 = 0x4U;
  IOMUXC_CSI_DATA09_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_09 = 0x4U;
  IOMUXC_CSI_DATA08_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_10 = 0x4U;
  IOMUXC_CSI_DATA07_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_10 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_11 = 0x4U;
  IOMUXC_CSI_DATA06_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_11 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_12 = 0x4U;
  IOMUXC_CSI_DATA05_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_12 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_13 = 0x4U;
  IOMUXC_CSI_DATA04_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_13 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_14 = 0x4U;
  IOMUXC_CSI_DATA03_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_14 = 0x0U;
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_15 = 0x4U;
  IOMUXC_CSI_DATA02_SELECT_INPUT = 0x0U;
  IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_15 = 0x0U;
 
Thanks, for some reason I was not finding that, but I recently changed from V1 of PDF to V2 and I thought CSI_D8 was said to be on GPIO B1_09 instead of AD_B1_09... But looking at V2 it shows the AD... So that is pin 23 and likewise CSI_09 is 22...

Will update my excel document.

Thanks.

IOMUXC is reasonably straight forward, for configuring pins for which which function you wish them to do and the pads for characteristics... The new wrinkle with the IMXRT is that if multiple Pins can do the same function, you may need to configure the SELECT_INPUT to the one you are actually going to use. I have been bit a few times by that when developing something and not getting the data only to find out that it had one of these IOMUXC values and it was not the default (0)...

As for XBar yep - that is a slight bit of confusing stuff. Although not near is bad as ADC_ETC ;)

Updated:
T4.1-Cardlike.jpg
 
I've gotten my soldered breadboard working with the t4.1 wired for the pins needed to use the SCI. The current version of my code follows Cyrille's plan (interrupts for VSync and HSync and polled transfer for each line of pixels). I can successfully get images at QQVGA, QVGA and VGA resolutions. My next venture will be to implement the SCI transfer of the frames to the frame buffers. The polling QVGA settings can transfer a frame with a system clock of 5MHz, and a VGA frame at 2MHz. The limit seems to be in the polled pixel acquisition loop timing.

My host program allows me to change resolutions, adjust registers, and do a continuous transfer of frames at 1 frame/second to see the results of register tweaking. I also have sliders to change brightness and contrast during transfers.

I plan to polish this polling code a bit more and will post it in the next few days. I have to figure out how to include my command handler that makes sense of things like "sr 71 33" which means set register 71(HEX) TO 33(HEX). That command is at the heart of my ability to tweak the OV7670 registers to get better image quality.

Speaking of tweaking registers, I can't believe I just found this app note today: http://web.mit.edu/6.111/www/f2015/tools/OV7670app.pdf It's an explanation of what's gooing on inside the OV7670. It doesn't explain some of the mysterious configuration register settings, but it does give you a better insight into the internal workings of this camera module. I've even found out how to correct the greenish cast of the screen caps in my workroom, which is illuminated by LED fluorescent tube replacements.
 
Status
Not open for further replies.
Back
Top