gpio-based i2c for eCos

#include <cyg/io/io.h>
#include <cyg/infra/diag.h>
#include "cyg/kernel/kapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ADDR(x)     (*((unsigned long *)x))
#define API
#define SCL  11
#define SDA  12
#define XIP_FUNC

#define SCL_0         gpio_set_value(SCL, 0)
#define SCL_1         gpio_set_value(SCL, 1)
#define SDA_0         gpio_set_value(SDA, 0)
#define SDA_1         gpio_set_value(SDA, 1)

static void  i2c_start(void);
static void  i2c_stop(void);
static void  wait_ack(void);
static void  i2c_writebyte(unsigned char a);
static unsigned char  i2c_readbyte(void);
static void SDAIN(void);
static void SDAOUT(void);
static void sendack(void);
static void sendnack(void);
static void i2c_writebit(unsigned char a);

void  i2c_init(void);
void  i2c_byte_write(unsigned char sadd, unsigned char reg, unsigned char val);
unsigned char   i2c_byte_read(unsigned char sadd, unsigned char reg);

static int gpio_get_value(int gpio)
{
    int reg_val;

    if (gpio <= 31) {
        // GPIO_DATA_0
        reg_val = ADDR(0x10000620);
        return ((reg_val >> gpio) & 0x1);
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_DATA_1
        reg_val = ADDR(0x10000624);
        return ((reg_val >> (gpio - 32)) & 0x1);
    } else {
        // 64 ... 95
        // GPIO_DATA_2
        reg_val = ADDR(0x10000628);
        return ((reg_val >> (gpio - 64)) & 0x1);
    }

    return 0;
}

static void gpio_set_value(int gpio, int value)
{
    if (gpio <= 31) {
        if (value > 0) {
            // GPIO_DSET_0
            ADDR(0x10000630) |= 1 << gpio;
        } else {
            // GPIO_DCLR_0
            ADDR(0x10000640) |= 1 << gpio;
        }
    } else if (gpio >= 32 && gpio <= 63) {
        if (value > 0) {
            // GPIO_DSET_1
            ADDR(0x10000634) |= 1 << (gpio - 32);
        } else {
            // GPIO_DCLR_1
            ADDR(0x10000644) |= 1 << (gpio - 32);
        }
    } else {
        // 64 ... 95
        if (value > 0) {
            // GPIO_DSET_2
            ADDR(0x10000638) |= 1 << (gpio - 64);
        } else {
            // GPIO_DCLR_2
            ADDR(0x10000648) |= 1 << (gpio - 64);
        }
    }
}

/**
 * @brief realese the SDA
 */
static void SDAIN(void)
{
    int gpio = SDA;

    if (gpio <= 31) {
        // GPIO_CTRL_0
        ADDR(0x10000600) &= ~(1 << gpio);
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_CTRL_1
        ADDR(0x10000604) &= ~(1 << (gpio - 32));
    } else {
        // 64 ... 95
        // GPIO_CTRL_2
        ADDR(0x10000608) &= ~(1 << (gpio - 64));
    }
}

/**
 * @brief get the control of SDA
 */
static void SDAOUT(void)
{
    int gpio = SDA;

    if (gpio <= 31) {
        // GPIO_CTRL_0
        ADDR(0x10000600) |= 1 << gpio;
    } else if (gpio >= 32 && gpio <= 63) {
        // GPIO_CTRL_1
        ADDR(0x10000604) |= 1 << (gpio - 32);
    } else {
        // 64 ... 95
        // GPIO_CTRL_2
        ADDR(0x10000608) |= 1 << (gpio - 64);
    }
}

/*
 * MT7628K CPU freq = 580/575 MHz, about 1.72 ns, 1 us = 581 clock
 * ESP8266 CPU freq = 80 MHz, about 12.5 ns, 1 us = 80 clock
 *
 * 100 kHz = 100,000, about 10 us
 * 400 kHz = 400,000, about 2.5 us
 *
 */
static void delay5us(void)
{
    unsigned short i;
    i=50;

    while(i--);
}

/**
 * @brief send ack signal at i2c bus
 */
static void sendack(void)
{
    i2c_writebit(0);
}
/**
 * @brief send nack signal at i2c bus
 */
static void sendnack(void)
{
    i2c_writebit(1);
}

/**
 * @brief realese the SDA
 */
/**
 * @brief send start signal at i2c bus
 */
static void i2c_start(void)
{
    SDAOUT();  
    SDA_1;
    delay5us();
    SCL_1;
    delay5us();
    SDA_0;
    delay5us();
    SCL_0;
    delay5us();
}

/**
 * @brief send stop signal at i2c bus
 */
static void i2c_stop(void)
{
    SDAOUT();
    SDA_0;
    delay5us();
    SCL_1;
    delay5us();
    SDA_1;
    delay5us();
    SCL_0;
    delay5us();
}
/**
 * @brief recieve ack signal at i2c bus
 */
static void  wait_ack(void)
{  
    int i;    

    SCL_0;
    delay5us;
    SDAIN();
    delay5us;
    SCL_1;
    delay5us();
    while(gpio_get_value(SDA)&&(i<0x2b0)) {
        i++;
    }

    SCL_0;
    delay5us();
}

/**
 * @brief write a byte at i2c bus
 *
 * @param the data to write
 */
static void  i2c_writebyte(unsigned char a)
{
    unsigned short i;

    SDAOUT();
    for (i=0; i<8; i++) {
        SCL_0;
        delay5us();
        if (a&0x80) {
            SDA_1;
        } else {
            SDA_0;
        }
        a = a<<1;
        delay5us();
        SCL_1;
        delay5us();
    }
}
/**
 * @brief write a bit at i2c bus
 *
 * @param the data to write
 */
static void i2c_writebit(unsigned char a)
{
    SDAOUT();
    SCL_0;
    delay5us();
    if (a==0) {
        SDA_0;
    } else {
        SDA_1;
    }
    delay5us();
    SCL_1;
    delay5us();
    SCL_0;
    delay5us();
}


/**
 * @brief read a byte at i2c bus
 *
 * @retval the data read
 */
static unsigned char i2c_readbyte()
{
    unsigned char i, temp;
    temp=0;

    SDAIN();
    SCL_0;      
    delay5us();
    for (i=0; i<8; i++) {
        SCL_1;  
        delay5us();
        temp=(temp<<1)|gpio_get_value(SDA);
        delay5us();
        SCL_0;  
        delay5us();
    }
    return temp;
}

/**
 * @brief initial the i2c related gpios
 */
API void i2c_init(void)
{       
    // pin mux
    // Reference to "MT7628 PROGRAMMING GUIDE", p15 of System Control
    // GPIO1_MODE 0x10000060
    // GPIO2_MODE 0x10000064
    gpio_set_value(SDA, 1);
    gpio_set_value(SCL, 1);
}

/**
 * @brief write data at certain address on MPU6050
 *
 * @param add the in-chip address of the data
 * @param Achar the data to write
 */
API void  i2c_byte_write(unsigned char sadd, unsigned char reg, unsigned char val)
{
    i2c_start();
    i2c_writebyte(sadd);
    wait_ack();
    i2c_writebyte(reg);
    wait_ack();
    i2c_writebyte(val);
    wait_ack();
    i2c_stop();
}
/**
 * @brief read data from certain address of MPU6050
 *
 * @param add the in-chip address of the data
 * @retval the data read
 */
API unsigned char  i2c_byte_read(unsigned char sadd, unsigned char reg)
{
    unsigned char temp;

    i2c_start();
    i2c_writebyte(sadd);
    wait_ack();
    delay5us();
    i2c_writebyte(reg);
    wait_ack();
    i2c_start();
    i2c_writebyte(sadd+1);
    wait_ack();
    temp=i2c_readbyte();
    sendnack();
    i2c_stop();

    return temp;
}

你可能感兴趣的:(GPIO,i2c)