0
\$\begingroup\$

I'm looking for a SCCB library for the camera OV7670 and I have been looking everywere for C code that fits OV7670. But the problem is that my SIO_D (Data line) is always 1 when I read the data line.

This type of question is a very common question about the communication problem many SCCB users facing. So my questions are:

  1. Why are my code only reading the data line as active high?
  2. Do you know a good working easy to use SCCB library that works?

enter image description here

Codes that I found useful:

https://gist.github.com/muhammadyaseen/75490348a4644dcbc70f https://github.com/ctc8631/ov7670/blob/master/src/OV7670.c#L338

Datasheet for OV7670: http://www.voti.nl/docs/OV7670.pdf

User manual for OV7670: http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf

My Code:

#define INPUT false
#define OUTPUT true
#define WRITE_ADDRESS 0x42
#define READ_ADDRESS 0x43
#define SIO_CLOCK_DELAY 1

static void delayMicroseconds(uint16_t ms){
    HAL_Delay(ms); // TODO: Fixa så det blir ms
}

static void DirSCCB(bool output){
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin =  SIO_D_Pin;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
    GPIO_InitStructure.Mode = output == false ? GPIO_MODE_INPUT : GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(SIO_D_GPIO_Port, &GPIO_InitStructure);
}

static void StartSCCB() {
    DirSCCB(OUTPUT);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);
}

static void StopSCCB() {
    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);
}

void NoAckSSCB(){

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);
}

static bool SCCBWrite(uint8_t m_data){
    uint8_t j;
    bool success;

    //Loop transmit data 8 times
    for (j = 0; j < 8; j++){
        if((m_data << j) & 0x80 )
            HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_SET);
        else
            HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_RESET);

        delayMicroseconds(SIO_CLOCK_DELAY);

        HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
        delayMicroseconds(SIO_CLOCK_DELAY);

        HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_RESET);
        delayMicroseconds(SIO_CLOCK_DELAY);
    }

    HAL_GPIO_WritePin(SIO_D_GPIO_Port, SIO_D_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Change to input
    DirSCCB(INPUT);
    delayMicroseconds(SIO_CLOCK_DELAY);

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    if(HAL_GPIO_ReadPin(SIO_D_GPIO_Port, SIO_D_Pin) == GPIO_PIN_SET)
        success = false;
    else
        success = true;

    HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Change to output
    DirSCCB(OUTPUT);
    delayMicroseconds(SIO_CLOCK_DELAY);

    return success;
}

static uint8_t SCCBRead(){
    // Prepare
    uint8_t data = 0;
    DirSCCB(INPUT);
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Loop
    for(uint8_t i = 8; i > 0; i--){
        delayMicroseconds(SIO_CLOCK_DELAY);
        HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_SET);
        delayMicroseconds(SIO_CLOCK_DELAY);
        data = data << 1;
        if(HAL_GPIO_ReadPin(SIO_D_GPIO_Port, SIO_D_Pin))
            data++;
        HAL_GPIO_WritePin(SIO_C_GPIO_Port, SIO_C_Pin, GPIO_PIN_RESET);
        delayMicroseconds(SIO_CLOCK_DELAY);
    }

    return data;
}

bool InitOV7670(){
    // Hardware reset
    HAL_GPIO_WritePin(CAMERA_RESET_GPIO_Port, CAMERA_RESET_Pin, GPIO_PIN_SET);
    delayMicroseconds(SIO_CLOCK_DELAY);
    HAL_GPIO_WritePin(CAMERA_RESET_GPIO_Port, CAMERA_RESET_Pin, GPIO_PIN_RESET);
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Software reset
    if(!WriteOV7670(COM7, COM7_VALUE_RESET))
        return false;
    else
        return true;
}


bool WriteOV7670(uint8_t reg, uint8_t data){
    StartSCCB();
    if(!SCCBWrite(WRITE_ADDRESS)){
        StopSCCB();
        return false;
    }

    delayMicroseconds(SIO_CLOCK_DELAY);
    if(!SCCBWrite(reg)){
        StopSCCB();
        return false;
    }

    delayMicroseconds(SIO_CLOCK_DELAY);
    if(!SCCBWrite(data)){
        StopSCCB();
        return false;
    }

    StopSCCB();

    return true;
}

bool ReadOV7670(uint8_t reg, uint8_t *data){
    StartSCCB();

    if(!SCCBWrite(WRITE_ADDRESS)){
        StopSCCB();
        return false;
    }
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Write data (Address of register in Camera Module)on SCCB/I2C interface
    if(!SCCBWrite(reg)){
        StopSCCB();
        return false;
    }
    delayMicroseconds(SIO_CLOCK_DELAY);

    StopSCCB();
    delayMicroseconds(SIO_CLOCK_DELAY);
    StartSCCB();

    // Write data (Address of slave device for Read) on SCCB/I2C interface
    if(!SCCBWrite(READ_ADDRESS)){
        StopSCCB();
        return false;
    }
    delayMicroseconds(SIO_CLOCK_DELAY);

    // Received data from Camera Module (SCCB/I2C)
    *data = SCCBRead();

    NoAckSSCB();

    StopSCCB();

    return true;
}
\$\endgroup\$
3
  • \$\begingroup\$ I gues you do not provided clock for camera. Do your OV7670 ACK I2C address (0x42/0x43)? I recommend using I2C driver instead of manaually bitband SCCB (I2C) bus. OV7670 do not work unless you provide clock (main clock - ususally refered as MCLK or XCLK). Note that main clock is not the pixel clock (usualy refered PCLK). PCLK is output from camera. \$\endgroup\$
    – Misaz
    Commented Jul 12, 2022 at 11:25
  • \$\begingroup\$ @Misaz I have 24 Mhz clock at XCLK and PCLK which is Pixel-clock is connected to my STM32. Ok. I will try to make I2C bus working with my camera. Do you have any sample code I can use? \$\endgroup\$
    – euraad
    Commented Jul 13, 2022 at 13:29
  • \$\begingroup\$ I was using OV7670 camera on different platform, but when I was experimenting with STM32 this project worked for me: radio.feec.vutbr.cz/MPOA/2014/cam-ov7670 But unluckily description is Czech Language only, so you need to use translator. Code examples as part of this project and bundled project works. \$\endgroup\$
    – Misaz
    Commented Jul 15, 2022 at 7:16

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.