Hi3861的micropython移植之软件I2C 原创 精华

再见南丫岛
发布于 2022-4-18 18:36
浏览
1收藏

终于有时间整理一下软件模拟I2C在micropython上的移植了。其实Hi3861上已经有两个I2C了。但是考虑到功能的复用,还是移植了其软件I2C的支持。也就是通过IO口模拟I2C。
具体I2C的协议,在这里不做解说。

0、底层框架函数

STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2c_init_obj) },
    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) },

    // primitive I2C operations
    { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_i2c_start_obj) },
    { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_i2c_stop_obj) },
    { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_readinto_obj) },
    { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_write_obj) },

    // standard bus operations
    { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) },
    { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) },
    { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) },
    { MP_ROM_QSTR(MP_QSTR_writevto), MP_ROM_PTR(&machine_i2c_writevto_obj) },

    // memory operations
    { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) },
    { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) },
    { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) },
};

对外可以使用的函数,其实跟硬件I2C的相同,用户可以无感知的使用。

1、协议模拟函数

STATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) {
    // We need to use an accurate delay to get acceptable I2C
    // speeds (eg 1us should be not much more than 1us).
    //mp_hal_delay_us_fast(self->us_delay);
    mp_hal_delay_us_fast(2);
}

STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) {
    //mp_hal_pin_od_low(self->scl);
    IoTGpioSetDir(self->scl, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(self->scl,0);
}

STATIC int mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
    uint32_t count = self->us_timeout;

    mp_hal_pin_od_high(self->scl);
    mp_hal_i2c_delay(self);
    // For clock stretching, wait for the SCL pin to be released, with timeout.
    for (; mp_hal_pin_open_get(self->scl) == 0 && count; --count) {
        mp_hal_delay_us_fast(1);
    }
    if (count == 0) {
        return -MP_ETIMEDOUT;
    }
    return 0; // success
}

STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {
    mp_hal_pin_od_low(self->sda);
}

STATIC void mp_hal_i2c_sda_release(machine_i2c_obj_t *self) {
    mp_hal_pin_od_high(self->sda);
}

STATIC int mp_hal_i2c_sda_read(machine_i2c_obj_t *self) {
    return mp_hal_pin_open_get(self->sda);
}

STATIC int mp_hal_i2c_start(machine_i2c_obj_t *self) {
    mp_hal_i2c_sda_release(self);
    mp_hal_i2c_delay(self);
    int ret = mp_hal_i2c_scl_release(self);
    if (ret != 0) {
        return ret;
    }
    mp_hal_i2c_sda_low(self);
    mp_hal_i2c_delay(self);
    return 0; // success
}

STATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) {
    mp_hal_i2c_delay(self);
    mp_hal_i2c_sda_low(self);
    mp_hal_i2c_delay(self);
    int ret = mp_hal_i2c_scl_release(self);
    mp_hal_i2c_sda_release(self);
    mp_hal_i2c_delay(self);
    return ret;
}

2、读写函数实现

// return value:
//    0 - byte written and ack received
//    1 - byte written and nack received
//   <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
    mp_hal_i2c_delay(self);
    mp_hal_i2c_scl_low(self);

    for (int i = 7; i >= 0; i--) {
        if ((val >> i) & 1) {
            mp_hal_i2c_sda_release(self);
        } else {
            mp_hal_i2c_sda_low(self);
        }
        mp_hal_i2c_delay(self);
        int ret = mp_hal_i2c_scl_release(self);
        if (ret != 0) {
            mp_hal_i2c_sda_release(self);
            return ret;
        }
        mp_hal_i2c_scl_low(self);
    }

    mp_hal_i2c_sda_release(self);
    mp_hal_i2c_delay(self);
    int ret = mp_hal_i2c_scl_release(self);
    if (ret != 0) {
        return ret;
    }

    int ack = mp_hal_i2c_sda_read(self);
    mp_hal_i2c_delay(self);
    mp_hal_i2c_scl_low(self);

    return ack;
}

// return value:
//    0 - success
//   <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {
    mp_hal_i2c_delay(self);
    mp_hal_i2c_scl_low(self);
    mp_hal_i2c_delay(self);

    uint8_t data = 0;
    for (int i = 7; i >= 0; i--) {
        int ret = mp_hal_i2c_scl_release(self);
        if (ret != 0) {
            return ret;
        }
        data = (data << 1) | mp_hal_i2c_sda_read(self);
        mp_hal_i2c_scl_low(self);
        mp_hal_i2c_delay(self);
    }
    *val = data;

    // send ack/nack bit
    if (!nack) {
        mp_hal_i2c_sda_low(self);
    }
    mp_hal_i2c_delay(self);
    int ret = mp_hal_i2c_scl_release(self);
    if (ret != 0) {
        mp_hal_i2c_sda_release(self);
        return ret;
    }
    mp_hal_i2c_scl_low(self);
    mp_hal_i2c_sda_release(self);

    return 0; // success
}

3、关键函数举例

STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
    mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in);
    mp_obj_t list = mp_obj_new_list(0, NULL);
    // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
    for (int addr = 0x08; addr < 0x78; ++addr) {
        int ret = mp_machine_i2c_writeto(self, addr, NULL, 0, true);
        if (ret == 0) {
            mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
        }
    }
    return list;
}

4、Python函数使用

具体函数的使用,请参考 https://ost.51cto.com/posts/10998

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-4-18 18:37:17修改
4
收藏 1
回复
举报
回复
    相关推荐