TWI protocol doesn't start (transmit not happen)

Hi, I'm trying to set OV7670 with I2C protocol. To do this, I decided to use TWI. But, when i want to start the transmission, code freezes on waiting the transmission end (waiting for TWINT).

//main.cpp

#include <Arduino.h>

#include "twi.h"

#include "register.h"

struct reg{

  uint8_t reg_num;

  uint16_t value;

};

const struct reg regs[] PROGMEM = {//from the linux driver

  { REG_COM7, COM7_RESET },

  { REG_TSLB, 0x04 }, /* OV */

  { REG_COM7, 4 },  /* RGB */

  /*

  * Set the hardware window.  These values from OV don't entirely

  * make sense - hstop is less than hstart.  But they work...

  */
  { REG_COM3, 0x04 }, { REG_COM14, 0x19 },

  { 0x72, 0x11 }, { 0x73, 0xf1 },

  { REG_HSTART, 0x16 }, { REG_HSTOP, 0x04 },

  { REG_HREF, 0xa4 }, { REG_VSTART, 0x02 },

  { REG_VSTOP, 0x7a }, { REG_VREF, 0x0a },

  /* Mystery scaling numbers */

  { 0x70, 0x3a }, { 0x71, 0x35 },

  { 0x72, 0x11 }, { 0x73, 0xf0 },

  { 0xa2,/* 0x02 changed to 1*/1 }, { REG_COM10, 0x0 },

  /* Gamma curve values */

  { 0x7a, 0x20 }, { 0x7b, 0x10 },

  { 0x7c, 0x1e }, { 0x7d, 0x35 },

  { 0x7e, 0x5a }, { 0x7f, 0x69 },

  { 0x80, 0x76 }, { 0x81, 0x80 },

  { 0x82, 0x88 }, { 0x83, 0x8f },

  { 0x84, 0x96 }, { 0x85, 0xa3 },

  { 0x86, 0xaf }, { 0x87, 0xc4 },

  { 0x88, 0xd7 }, { 0x89, 0xe8 },

  /* AGC and AEC parameters.  Note we start by disabling those features,

  then turn them only after tweaking the values. */

  { REG_COM8, COM8_FASTAEC | COM8_AECSTEP },

  { REG_GAIN, 0 }, { REG_AECH, 0 },

  { REG_COM4, 0x40 }, /* magic reserved bit */

  { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */

  { REG_BD50MAX, 0x05 }, { REG_BD60MAX, 0x07 },

  { REG_AEW, 0x95 }, { REG_AEB, 0x33 },

  { REG_VPT, 0xe3 }, { REG_HAECC1, 0x78 },

  { REG_HAECC2, 0x68 }, { 0xa1, 0x03 }, /* magic */

  { REG_HAECC3, 0xd8 }, { REG_HAECC4, 0xd8 },

  { REG_HAECC5, 0xf0 }, { REG_HAECC6, 0x90 },

  { REG_HAECC7, 0x94 },

  { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_AGC | COM8_AEC },

  { 0x30, 0 }, { 0x31, 0 },//disable some delays

  /* Almost all of these are magic "reserved" values.  */

  { REG_COM5, 0x61 }, { REG_COM6, 0x4b },

  { 0x16, 0x02 }, { REG_MVFP, 0x07 },

  { 0x21, 0x02 }, { 0x22, 0x91 },

  { 0x29, 0x07 }, { 0x33, 0x0b },

  { 0x35, 0x0b }, { 0x37, 0x1d },

  { 0x38, 0x71 }, { 0x39, 0x2a },

  { REG_COM12, 0x78 }, { 0x4d, 0x40 },

  { 0x4e, 0x20 }, { REG_GFIX, 0 },

  /*{0x6b, 0x4a},*/{ 0x74, 0x10 },

  { 0x8d, 0x4f }, { 0x8e, 0 },

  { 0x8f, 0 }, { 0x90, 0 },

  { 0x91, 0 }, { 0x96, 0 },

  { 0x9a, 0 }, { 0xb0, 0x84 },

  { 0xb1, 0x0c }, { 0xb2, 0x0e },

  { 0xb3, 0x82 }, { 0xb8, 0x0a },

  /* More reserved magic, some of which tweaks white balance */

  { 0x43, 0x0a }, { 0x44, 0xf0 },

  { 0x45, 0x34 }, { 0x46, 0x58 },

  { 0x47, 0x28 }, { 0x48, 0x3a },

  { 0x59, 0x88 }, { 0x5a, 0x88 },

  { 0x5b, 0x44 }, { 0x5c, 0x67 },

  { 0x5d, 0x49 }, { 0x5e, 0x0e },

  { 0x6c, 0x0a }, { 0x6d, 0x55 },

  { 0x6e, 0x11 }, { 0x6f, 0x9e }, /* it was 0x9F "9e for advance AWB" */

  { 0x6a, 0x40 }, { REG_BLUE, 0x40 },

  { REG_RED, 0x60 },

  { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_AGC | COM8_AEC | COM8_AWB },

  /* Matrix coefficients */

  { 0x4f, 0x80 }, { 0x50, 0x80 },

  { 0x51, 0 },    { 0x52, 0x22 },

  { 0x53, 0x5e }, { 0x54, 0x80 },

  { 0x58, 0x9e },

  { REG_COM16, COM16_AWBGAIN }, { REG_EDGE, 0 },

  { 0x75, 0x05 }, { REG_REG76, 0xe1 },

  { 0x4c, 0 },     { 0x77, 0x01 },

  { REG_COM13, /*0xc3*/0x48 }, { 0x4b, 0x09 },

  { 0xc9, 0x60 },   /*{REG_COM16, 0x38},*/

  { 0x56, 0x40 },

  { 0x34, 0x11 }, { REG_COM11, COM11_EXP | COM11_HZAUTO },

  { 0xa4, 0x82/*Was 0x88*/ }, { 0x96, 0 },

  { 0x97, 0x30 }, { 0x98, 0x20 },

  { 0x99, 0x30 }, { 0x9a, 0x84 },

  { 0x9b, 0x29 }, { 0x9c, 0x03 },

  { 0x9d, 0x4c }, { 0x9e, 0x3f },

  { 0x78, 0x04 },

  /* Extra-weird stuff.  Some sort of multiplexor register */

  { 0x79, 0x01 }, { 0xc8, 0xf0 },

  { 0x79, 0x0f }, { 0xc8, 0x00 },

  { 0x79, 0x10 }, { 0xc8, 0x7e },

  { 0x79, 0x0a }, { 0xc8, 0x80 },

  { 0x79, 0x0b }, { 0xc8, 0x01 },

  { 0x79, 0x0c }, { 0xc8, 0x0f },

  { 0x79, 0x0d }, { 0xc8, 0x20 },

  { 0x79, 0x09 }, { 0xc8, 0x80 },

  { 0x79, 0x02 }, { 0xc8, 0xc0 },

  { 0x79, 0x03 }, { 0xc8, 0x40 },

  { 0x79, 0x05 }, { 0xc8, 0x30 },

  { 0x79, 0x26 },

  { 0xff, 0xff }, /* END MARKER */

};

void writeToCamera(int addr, int value){
  writeTWI(42, *(bytes(2).add(addr)->add(value)));
  delay(1);
}

void initCamera(){
  const reg* r = regs;
  uint8_t numm, vall;
  while (numm != 0xff)
  {
    numm = pgm_read_byte(&r -> reg_num);
    vall = pgm_read_byte(&r -> value);
    Serial.println(numm);
    Serial.println(vall);
    writeToCamera(numm, vall);
    r++;
  }
  writeToCamera(REG_COM10, 1 << 5); // pclk hblank async
  
}

void setup(){
  cli();
  Serial.begin(9600);
  pinMode(11, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  //Timer 9-11
  TCCR2A = (1 << COM2A0) | (1 << WGM20) | (1 << WGM21);
  TCCR2B = (1 << WGM22) | (1 << CS20); // 8mhz
  OCR2A = 0;

  initCamera();
  
}

void loop(){
  /*Serial.println(analogRead(A0));
  Serial.println(analogRead(A1));
  Serial.println(analogRead(A2));
  Serial.println(analogRead(A3));
  Serial.println();*/
}

//twi.h

#pragma once
#include <Arduino.h>

struct bytes{
private:
    int _index;
public:
    int* _bytes;
    int _len;

    bytes(int len){
        _len = len;
        _index = 0;
        _bytes = new int[len];
    }

    ~bytes(){
        delete _bytes;
    }

    bytes* add(int byte){
        _bytes[_index++] = byte;
        return this;
    }
};

void setupTWI(int khz){
    TWBR = 8000.0 / khz - 8;
    
}

void waitTWINT(){
    while ((TWCR & (1 << TWINT)) <= 0); //freezes there
}

int startTWI(){
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
    waitTWINT();
    return TWSR == 0x08;
}

void stopTWI(){
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}

int enableTWI(int address){
    TWDR = address;
    TWCR = (1 << TWINT) | (1 << TWEN);
}

int writeTWI(int address, bytes _bytes){
    Serial.println("s");
    if (!startTWI())
        return 0;
    Serial.println("sd");
    enableTWI(address);
    for (int i = 0; i < _bytes._len; i++)
    {
        TWDR = (_bytes)._bytes[i];
        TWCR = (1 << TWINT) | (1 << TWEN);
        waitTWINT();
    }
    stopTWI();
    return 1;
}

int readTWI(int address, int stopCode, int* read, int buffer = 128){
    if (!startTWI())
        return 0;
    enableTWI(address);
    read = new int[buffer];

    int r, i = 0;
    while ((r = TWDR) != stopCode)
    {
        read[i++] = r;
    }
    return 1;
}

Why TWI instead of Wire?
Which board?
Did you try i2c_sniffer?

1 Like

Actually I didn't think of Wire. I'll try it.

Arduino UNO with 328P.

No, I didn't.

I just tried Wire.h but, it doesn't work.

void writeToCamera(int addr, int value){
  Wire.beginTransmission(42);
  Wire.write(addr);
  Wire.write(value);
  Wire.endTransmission();
  delay(1);
  //writeTWI(42, *(bytes(2).add(addr)->add(value)));
  //delay(1);
}
void initCamera(){
  Wire.begin();
  const reg* r = regs;
  uint8_t numm, vall;
  while (numm != 0xff)
  {
    numm = pgm_read_byte(&r -> reg_num);
    vall = pgm_read_byte(&r -> value);
    Serial.println(numm); // in serial, this line working
    Serial.println(vall); // but this line not. So, the output is only '18' (numm). after the '18', it freezes.
    writeToCamera(numm, vall);
    r++; // when i comment this line, it works with twi but wire still not work 
  }
  writeToCamera(REG_COM10, 1 << 5); // pclk hblank async
}

Do you have pullups on the SDA/SCL lines?

Yes, these lines connected via 10k resistor with Arduino.

Which Arduino board do you use ?

You need to use the Serial Monitor, to be able to send (debug) messages.

To get it working, make a test-sketch and remove everything that can cause trouble, so please don't use PROGMEM. Show us the full test-sketch.

In setup(), check if the Arduino sees the module:

void setup()
{
  Serial.begin(115200);
  Serial.println("The sketch has started");
  Wire.begin();

  Wire.beginTransmission(42);
  int error = Wire.endTransmission();
  if(error == 0)
    Serial.println("Okay, the camera is on the I2C bus");
  else
    Serial.println("ERROR, I can't see the camera");
}

Interfacing the camera is probably not easy, because when searching online for libraries I found code that I didn't like.
Adafruit has also a OV7670 library, but even they have a disclaimer that there might be problems: https://github.com/adafruit/Adafruit_OV7670

With so many problems, can you use a Raspberry Pi with a webcam for your project ?

I'm using UNO.

I compiled with the test code as you said. It gives error code 2. So, it doesn't see the camera.

Before my own code, i tried this circuit digest project and it worked. But, it has lot of redundant code and it was not as i wanted. Now, I'm using same circuit scheme with circuitdigest but I changed the code.

Unfortunately I can't try with raspberry, i don't have it.

The write address is 0x42 HEX not decimal

The read address is 0x43 HEX not decimal

Then the address to use is 0x21 or 33.

Sorry for late answer. I tried 0x42 but not worked. I'll check all connections again.

Not worked :frowning:

I guess solved a part. In start, there was a cli() function. Probably, it had freeze Serial and prevent make output, so I deleted this line. It printed until RGB register. I'll check registers and try again.

And, address is 0x42. Thanks @jim-p :slight_smile:

If the write address is 0x42 (0100 0010), then the slaveAddress is 010 0001 (0x21) which is to be entered in the instructions.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.