foss-for-synopsys-dwc-arc-processors / embarc_osp

embARC Open Software Platform (OSP) - An embedded software distribution for IoT and other embedded applications for ARC
https://www.embarc.org/
BSD 3-Clause "New" or "Revised" License
70 stars 62 forks source link

I2C interface for IoTdk board #93

Closed ericwu13 closed 5 years ago

ericwu13 commented 5 years ago

Issue Summary


Development Environment


Question

I want to use I2C ports in Iotdk board, however, I don't know how to use it. I referred to the ARC IoTdk documentation, seeing that in 2x18 extension header, there are I2C0 and I2C1 ports image So, I used DFSS_iic_0_id, and connected my I2C ports to I2C0. Below is my implementation. And, it turned out that I always got "Write Fail" command, and the program would be stuck at ov7670_iic->iic_write(&send_data, 1); I don't know how to fix it? Is my iic_id wrong? Thanks

#include "embARC.h"
#include "embARC_debug.h"
#include "embARC_error.h"
#include "stdio.h"
#define OV7670_IIC_ADDR  0x42
#define OV7670_CHECK_EXP_NORTN(EXPR)       CHECK_EXP_NOERCD(EXPR, error_exit)

DEV_IIC_PTR ov7670_iic = NULL;

static uint8_t seq1[] = {
    0x11,
    0x03
};
int main(void) {
    int ercd = E_OK;
    ov7670_iic = iic_get_dev(DFSS_IIC_0_ID);

    OV7670_CHECK_EXP_NORTN(ov7670_iic!=NULL);

    ercd = ov7670_iic->iic_open(DEV_MASTER_MODE, IIC_SPEED_STANDARD);
    ercd = ov7670_iic->iic_control(IIC_CMD_ENA_DEV, (void *)OV7670_IIC_ADDR);
    ercd = ov7670_iic->iic_control(IIC_CMD_MST_SET_TAR_ADDR, (void  *)(OV7670_IIC_ADDR));

    if ((ercd == E_OK) || (ercd == E_OPNED)) {
        EMBARC_PRINTF("Init DONE!\n");
        ov7670_iic->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
        ercd = ov7670_iic->iic_write(seq1, 2);
        if(ercd == E_OK || ercd == E_OPNED) {
            EMBARC_PRINTF("Write Success\n");
        } else {
            EMBARC_PRINTF("Write Fail\n");
        }

        uint8_t send_data = 0x11;
        uint8_t *REG_data;

        ov7670_iic->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_RESTART));
        ov7670_iic->iic_write(&send_data, 1);
        ov7670_iic->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
        ov7670_iic->iic_read(REG_data, 1);

        EMBARC_PRINTF("Read %2x\n", *REG_data);
    } else {
        EMBARC_PRINTF("Read fail\n");
    }

error_exit:
        return ercd;
}
IRISZZW commented 5 years ago

I have reviewed and run you code, I think the device did not answer, so it return E_SYS. when you write success, it will return the length you write.

uint8_t *REG_data; ---> uint8_t REG_data;

ericwu13 commented 5 years ago

I have reviewed and run you code, I think the device did not answer, so it return E_SYS. when you write success, it will return the length you write.

uint8_t *REG_data; ---> uint8_t REG_data;

I print out ercd, it said "-5". And Why I should change *REG_data to REG_data? I use it as a pointer

IRISZZW commented 5 years ago

when you use a pointer, you should initialize it, such as: uint8_t data; uint8_t *p = &data;

ericwu13 commented 5 years ago

Oh, I got stupid. BTW, I still can''t communicate through I2C interface... Do you have solution? By the way, My device can communicate with Arduino

IRISZZW commented 5 years ago

read the ov7670 datasheet to see is there anything wrong. and below is the pin signal scope: image image

ericwu13 commented 5 years ago

Sorry, could you elaborate on the picture? (the name of each signal) And What is S and P stand for? Thanks!!! BTW, OV7670 is using I2C, I'm confused why it can't work naturally... Does it mean that I'll have to revise the i2c library code in arc? Very thankful to your help!

ericwu13 commented 5 years ago

Hi IRISZZW, I now found the I2C address of my device, which is at 0x21. And I can write data to it. However, now the problem is, when I iic_write the register address, and then I do iic_read to read the value out, my device is stuck. Could you help me out?

PS: It is stuck at this line while (ctx->flags & SS_IIC_MASTER_FLAG_RX); in ss_i2c_master.c

---------------------------UPDATED SUCCESSFUL VERSION---------------------------

#include "embARC.h"
#include "embARC_debug.h"
#include "embARC_error.h"
#include "stdio.h"

#define OV7670_IIC_ADDR  0x21
#define OV7670_CHECK_EXP_NORTN(EXPR)       CHECK_EXP_NOERCD(EXPR, error_exit)

DEV_IIC_PTR ov7670_iic = NULL;

static uint32_t point = (OV7670_IIC_ADDR);
static uint8_t seq1[] = {
    0x11,
    0x03
};

int main(void) {
    int ercd = E_OK;
    ov7670_iic = iic_get_dev(0);
    OV7670_CHECK_EXP_NORTN(ov7670_iic!=NULL);

    ercd = ov7670_iic->iic_open(DEV_MASTER_MODE, IIC_SPEED_STANDARD);
    ercd = ov7670_iic->iic_control(IIC_CMD_MST_SET_TAR_ADDR, (void*)(point));

    if ((ercd == E_OK) || (ercd == E_OPNED)) {
        ov7670_iic->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
        ercd = ov7670_iic->iic_write(seq1, 2);
        if(ercd == 2) {
            EMBARC_PRINTF("Write Success Addr = 0x%x\n", point);
            uint8_t send_data = 0x11;
            uint8_t reg_data;
            ov7670_iic->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
            ov7670_iic->iic_write(&send_data, 1);
            ov7670_iic->iic_read(&reg_data, 1);
            EMBARC_PRINTF("Read 0x%x\n", reg_data); 
        } 
    }

error_exit:
        return ercd;
}
ericwu13 commented 5 years ago

Oh, I found the solution!!! The previous code I used is referred from IMU sensor code. It seems to not work for OV7670 in IoTdk.

First, for i2c write, we should first iic_control IIC_MODE_STOP and write data.

iic_dev_ptr->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
iic_dev_ptr->iic_write(seq1, 2);

For i2c read, however, in EMSK, they need RESTART and STOP (referred from sample code), like this:

iic_dev_ptr->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_RESTART));
iic_dev_ptr->iic_write(&reg_addr, 1);
iic_dev_ptr->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
iic_dev_ptr->iic_read(&reg_data, 1);

But in IoTdk, the above will fail, we only need to do this, and it works.

iic_dev_ptr->iic_control(IIC_CMD_MST_SET_NEXT_COND, (void*)(IIC_MODE_STOP));
iic_dev_ptr->iic_write(&reg_addr, 1);
iic_dev_ptr->iic_read(&reg_data, 1);

I don't know why there is a difference?

  1. Would it because of my device (OV7670) using different I2C protocol than imu sensor? However, my device works perfectly on arduino I2C.
  2. Or is it because different board would have different usage?
ericwu13 commented 5 years ago

Finally, It should be the difference between SCCB and I2C, I thought there are the same. Their write operation are the same. But read operations are different. In I2C, it needs a repeated start condition to read the I2C register, but in SCCB, it doesn't. So, the problem is solved! Thanks!