common/util/hal_i2c.c (209 lines of code) (raw):

#include <zephyr.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "cmsis_os2.h" #include "hal_i2c.h" #include "timer.h" static const struct device *dev_i2c[MAX_I2C_BUS_NUM]; struct k_mutex i2c_mutex[MAX_I2C_BUS_NUM]; /* * @brief Construct an I2C message buffer. * * @param bus_id The I2C bus ID. * @param address Target device address(7-bit address). * @param tx_len the data length that transmits to target device. * @param data the data buffer that ready to transmit to target. * @param rx_len the data length that receive the response from target device. * * @retval The I2C message buffer. */ I2C_MSG construct_i2c_message(uint8_t bus_id, uint8_t address, uint8_t tx_len, uint8_t *data, uint8_t rx_len) { I2C_MSG i2c_msg; i2c_msg.bus = bus_id; i2c_msg.slave_addr = address; i2c_msg.tx_len = tx_len; memcpy(i2c_msg.data, data, tx_len); i2c_msg.rx_len = rx_len; return i2c_msg; } void i2c_freq_set(uint8_t i2c_bus, uint8_t i2c_speed_mode) { uint32_t dev_config_raw; dev_config_raw = I2C_MODE_MASTER | I2C_SPEED_SET(i2c_speed_mode); i2c_configure(dev_i2c[i2c_bus], dev_config_raw); } int i2c_master_read(I2C_MSG *msg, uint8_t retry) { uint8_t i; uint8_t *txbuf, *rxbuf; int ret, status; if (DEBUG_I2C) { printf("i2c_master_read: bus %d, addr %x, rxlen %d, txlen %d, txbuf:", msg->bus, msg->slave_addr, msg->rx_len, msg->tx_len); for (int i = 0; i < msg->tx_len; i++) { printf(" %x", msg->data[i]); } printf("\n"); } if (msg->rx_len == 0) { printf("i2c_master_read with rx_len = 0\n"); return EMSGSIZE; } do { // break while getting mutex success but tranmission fail status = k_mutex_lock(&i2c_mutex[msg->bus], K_MSEC(1000)); if (status == osOK) { for (i = 0; i < retry; i++) { txbuf = (uint8_t *)malloc(I2C_BUFF_SIZE * sizeof(uint8_t)); rxbuf = (uint8_t *)malloc(I2C_BUFF_SIZE * sizeof(uint8_t)); memcpy(txbuf, &msg->data[0], msg->tx_len); ret = i2c_write_read(dev_i2c[msg->bus], msg->slave_addr, txbuf, msg->tx_len, rxbuf, msg->rx_len); memcpy(&msg->data[0], rxbuf, msg->rx_len); if (DEBUG_I2C) { printf("rxbuf:"); for (int i = 0; i < msg->rx_len; i++) { printf(" %x", msg->data[i]); } printf("\n"); } free(txbuf); free(rxbuf); status = k_mutex_unlock(&i2c_mutex[msg->bus]); if (status != osOK) { printf("I2C %d master read release mutex fail\n", msg->bus); } return ret; // i2c write and read success } printf("I2C %d master read retry reach max\n", msg->bus); status = k_mutex_unlock(&i2c_mutex[msg->bus]); if (status != osOK) { printf("I2C %d master read release mutex fail\n", msg->bus); } return EPIPE; } else { printf("I2C %d master read get mutex timeout\n", msg->bus); return ENOLCK; } } while (0); return ECANCELED; // should not reach here } int i2c_master_write(I2C_MSG *msg, uint8_t retry) { uint8_t i; uint8_t *txbuf; int status, ret; if (DEBUG_I2C) { printf("i2c_master_write: bus %d, addr %x, txlen %d, txbuf:", msg->bus, msg->slave_addr, msg->tx_len); for (int i = 0; i < msg->tx_len; i++) { printf(" %x", msg->data[i]); } printf("\n"); } status = k_mutex_lock(&i2c_mutex[msg->bus], K_MSEC(1000)); if (status == osOK) { for (i = 0; i < retry; i++) { txbuf = (uint8_t *)malloc(I2C_BUFF_SIZE * sizeof(uint8_t)); memcpy(txbuf, &msg->data[0], msg->tx_len); ret = i2c_write(dev_i2c[msg->bus], txbuf, msg->tx_len, msg->slave_addr); if (ret) { free(txbuf); continue; } else { // i2c write success status = k_mutex_unlock(&i2c_mutex[msg->bus]); if (status != osOK) { printf("I2C %d master write release mutex fail\n", msg->bus); } free(txbuf); return ret; } } printf("I2C %d master write retry reach max\n", msg->bus); status = k_mutex_unlock(&i2c_mutex[msg->bus]); if (status != osOK) { printf("I2C %d master write release mutex fail\n", msg->bus); } return EPIPE; } else { printf("I2C %d master write get mutex timeout\n", msg->bus); return ENOLCK; } return ECANCELED; } void i2c_scan(uint8_t bus, uint8_t *slave_addr, uint8_t *slave_addr_len) { uint8_t first = 0x04, last = 0x77; for (uint8_t i = 0; i <= last; i += 16) { for (uint8_t j = 0; j < 16; j++) { if (i + j < first || i + j > last) { continue; } struct i2c_msg msgs[1]; uint8_t dst; /* Send the address to read from */ msgs[0].buf = &dst; msgs[0].len = 0U; msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; if (i2c_transfer(dev_i2c[bus], &msgs[0], 1, i + j) == 0) { slave_addr[*slave_addr_len] = (i + j) << 1; (*slave_addr_len)++; } } } } void util_init_I2C(void) { int status; #ifdef DEV_I2C_0 dev_i2c[0] = device_get_binding("I2C_0"); status = k_mutex_init(&i2c_mutex[0]); if (status) printk("i2c0 mutex init fail\n"); #endif #ifdef DEV_I2C_1 dev_i2c[1] = device_get_binding("I2C_1"); status = k_mutex_init(&i2c_mutex[1]); if (status) printk("i2c1 mutex init fail\n"); #endif #ifdef DEV_I2C_2 dev_i2c[2] = device_get_binding("I2C_2"); status = k_mutex_init(&i2c_mutex[2]); if (status) printk("i2c2 mutex init fail\n"); #endif #ifdef DEV_I2C_3 dev_i2c[3] = device_get_binding("I2C_3"); status = k_mutex_init(&i2c_mutex[3]); if (status) printk("i2c3 mutex init fail\n"); #endif #ifdef DEV_I2C_4 dev_i2c[4] = device_get_binding("I2C_4"); status = k_mutex_init(&i2c_mutex[4]); if (status) printk("i2c4 mutex init fail\n"); #endif #ifdef DEV_I2C_5 dev_i2c[5] = device_get_binding("I2C_5"); status = k_mutex_init(&i2c_mutex[5]); if (status) printk("i2c5 mutex init fail\n"); #endif #ifdef DEV_I2C_6 dev_i2c[6] = device_get_binding("I2C_6"); status = k_mutex_init(&i2c_mutex[6]); if (status) printk("i2c6 mutex init fail\n"); #endif #ifdef DEV_I2C_7 dev_i2c[7] = device_get_binding("I2C_7"); status = k_mutex_init(&i2c_mutex[7]); if (status) printk("i2c7 mutex init fail\n"); #endif #ifdef DEV_I2C_8 dev_i2c[8] = device_get_binding("I2C_8"); status = k_mutex_init(&i2c_mutex[8]); if (status) printk("i2c8 mutex init fail\n"); #endif #ifdef DEV_I2C_9 dev_i2c[9] = device_get_binding("I2C_9"); status = k_mutex_init(&i2c_mutex[9]); if (status) printk("i2c9 mutex init fail\n"); #endif }