项目上用到的一款蓝牙芯片引脚太少,选择了PCA9557扩展IO,通过一路i2c可以扩展出8个IO。这款芯片没有中断输入,所以更适合做扩展输出引脚用,内部寄存器也比较少,只有4个,使用起来很容易。
输入寄存器
输出寄存器
极性颠倒寄存器
配置寄存器
参考代码
/*
* pca9557.c
*
* Created on: 2021-07-15
* Author: shynan
*/
#include "sl_i2cspm.h"
#include "sl_i2cspm_instances.h"
#include "pca9557.h"
#define PCA9557_I2C_DEVICE sl_i2cspm_sensor
#define PCA9557_I2C_BUS_ADDR 0x18
#define PCA9557_INPUT_PORT_REG 0x00
#define PCA9557_OUTPUT_PORT_REG 0x01
#define PCA9557_POLARITY_INVERSION_REG 0x02
#define PCA9557_CONFIG_REG 0x03
#define POLARITY_INVERSION_DEFAULT 0xF0
#define CONFIG_DEFAULT 0xFF
static I2C_TransferReturn_TypeDef pca9557_read(uint8_t reg, uint8_t* val, uint8_t len)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
seq.addr = PCA9557_I2C_BUS_ADDR << 1;
seq.flags = I2C_FLAG_WRITE_READ;
seq.buf[0].data = ®
seq.buf[0].len = 1;
seq.buf[1].data = val;
seq.buf[1].len = len;
// Perform the transfer and return status from the transfer
ret = I2CSPM_Transfer(PCA9557_I2C_DEVICE, &seq);
return ret;
}
static I2C_TransferReturn_TypeDef pca9557_write(uint8_t reg, uint8_t* val, uint8_t len)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
seq.addr = PCA9557_I2C_BUS_ADDR << 1;
seq.flags = I2C_FLAG_WRITE_WRITE;
seq.buf[0].data = ®
seq.buf[0].len = 1;
seq.buf[1].data = val;
seq.buf[1].len = len;
// Perform the transfer and return status from the transfer
ret = I2CSPM_Transfer(PCA9557_I2C_DEVICE, &seq);
return ret;
}
int pca9557_init(void)
{
uint8_t reg = PCA9557_POLARITY_INVERSION_REG;
uint8_t polarity = 0;
I2C_TransferReturn_TypeDef status;
status = pca9557_write(reg, &polarity, 1);
if (status != i2cTransferDone)
{
/* read polarity fail */
return -1;
}
return 0;
}
int pca9557_set_mode(const uint8_t pin, const uint8_t mode)
{
uint8_t io_mode = 0;
uint8_t reg = PCA9557_CONFIG_REG;
I2C_TransferReturn_TypeDef status;
status = pca9557_read(reg, &io_mode, 1);
if (status != i2cTransferDone)
{
/* read config fail */
return -1;
}
if (mode == EXTAND_IO_OUTPUT)
{
io_mode &= (~pin);
} else {
io_mode |= pin;
}
status = pca9557_write(reg, &io_mode, 1);
if (status != i2cTransferDone)
{
/* read config fail */
return -1;
}
return 0;
}
int pca9557_setOutputValue(const uint8_t pin, const uint8_t val)
{
uint8_t io_val = 0;
uint8_t reg = PCA9557_OUTPUT_PORT_REG;
I2C_TransferReturn_TypeDef status;
status = pca9557_read(reg, &io_val, 1);
if (status != i2cTransferDone)
{
/* read config fail */
return -1;
}
if (val == 0)
{
io_val &= (~pin);
} else {
io_val |= pin;
}
status = pca9557_write(reg, &io_val, 1);
if (status != i2cTransferDone)
{
/* read config fail */
return -1;
}
return 0;
}
int pca9557_getInputValue(uint8_t* val)
{
uint8_t reg = PCA9557_INPUT_PORT_REG;
I2C_TransferReturn_TypeDef status;
if (val == NULL)
{
return -1;
}
status = pca9557_read(reg, val, 1);
if (status != i2cTransferDone)
{
/* read config fail */
return -1;
}
return 0;
}
/*
* pca9557.h
*
* Created on: 2021-07-15
* Author: shynan
*/
#ifndef EXPAND_IO_PCA9557_H_
#define EXPAND_IO_PCA9557_H_
#include <stdlib.h>
#include <stdint.h>
typedef unsigned char uint8_t;
enum {
EXTAND_IO_OUTPUT = 0,
EXTAND_IO_INPUT = 1,
};
#define PCA9557_IO0 0x01
#define PCA9557_IO1 0x02
#define PCA9557_IO2 0x04
#define PCA9557_IO3 0x08
#define PCA9557_IO4 0x10
#define PCA9557_IO5 0x20
#define PCA9557_IO6 0x40
#define PCA9557_IO7 0x80
extern int pca9557_init(void);
extern int pca9557_set_mode(uint8_t pin, const uint8_t mode);
extern int pca9557_setOutputValue(const uint8_t pin, const uint8_t val);
extern int pca9557_getInputValue(uint8_t* val);
#endif /* EXPAND_IO_PCA9557_H_ */
IO0无法输出高电平问题,看了下芯片手册发现这个引脚比较特殊,是开漏输出,需要外部上拉。