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
}