tca959 作为一款纯IIC控制的mcu,上电后即可通过主控IC的I2C 来控制mcu 的管脚,设置这些pin的input / output 模式,以及获取output的高低,另外也可以获取input的状态。通常主控IC 的IO 口不够用时用来扩展IO 口。
TCA9539 I2C地址的确定
查看TCA9539 的datasheet 文档,地址部分,总共有7位,其中Slave address 的bit 位固定,另外最后两个bits 位根据原理图中地址pin 的高低来判断
查看原理图发现,tca9539 的I2C地址脚IIC_SEL0,IIC_SEL1 接的是下拉电阻,两个PIN都是低电平,故地址应该取0x74.
结合原理图和datasheet 得到一个7bit 的I2C地址后,需要左移(x2), 末尾补零生成一个8bit 的地址给软件使用。计算后改地址为 0xE8.
IIC地址的配置
找到对应板型的board.h 文件,配置tca9539 IIC 信息。包含在那一组IIC及设备的IIC 地址。其中TCA9539_I2C_ID 只是一个枚举值方便应用调用。
管脚功能配置
功能配置主要是配置对应pin的输入,输出模式及输出模式的高低状态
根据datasheet 的说明,寄存器0x06 , 0x07 分别配置port 0~ 7 ,
port 10~17对应bit位为1 则为输入 为0 则为输出。 而寄存器0x04, 0x05 分别是设置port 0 ~ 7,port 10 ~ 17 极性的。
例如:设置P3,P4,P5,P7,P10,P11 需要设置为output,其它为input模式
#define TCA9539_MASK_P0 (1 << 0)
#define TCA9539_MASK_P1 (1 << 1)
#define TCA9539_MASK_P2 (1 << 2)
#define TCA9539_MASK_P3 (1 << 3)
#define TCA9539_MASK_P4 (1 << 4)
#define TCA9539_MASK_P5 (1 << 5)
#define TCA9539_MASK_P6 (1 << 6)
#define TCA9539_MASK_P7 (1 << 7)
// P3,P4,P5,P7 set to output 0x47
static MAPI_U8 uTca9539_Ports_L_Mode = 0xFF & \
(~(TCA9539_MASK_P3)) & \
(~(TCA9539_MASK_P4)) & \
(~(TCA9539_MASK_P5)) & \
(~(TCA9539_MASK_P7));
// P10,P11 set to output 0xFC
static MAPI_U8 uTca9539_Ports_H_Mode = (0xFF & (~(TCA9539_MASK_P0)) & (~(TCA9539_MASK_P1)));
定义寄存器0x06 需要初始化的值0x47 (0100 0111), 二进制从右到左 bit0~bit7 对应port0 ~ port7;寄存器 0x07,需要初始化的值0xFC (1111 1100) ,二进制从右到左bit0 ~ bit7 对应port10 ~ port17.
MAPI_U8 uCfgLowPorts = 0x06;
MAPI_U8 uCfgHighPorts = 0x07;
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// config the port mode <input or output>
if(MAPI_FALSE == iptr->WriteBytes(1,&uCfgLowPorts,1,&uTca9539_Ports_L_Mode))
{
printf("[%s][%d] wirte the port 0~7 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
if(MAPI_FALSE == iptr->WriteBytes(1,&uCfgHighPorts,1,&uTca9539_Ports_H_Mode))
{
printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
这样就完成input , output 模式的配置。
读取输出管脚状态
通过datasheet得到,寄存器0x00,0x01 是用来获取port 的状态。
MAPI_U8 uLowRegAddr = 0x00;
MAPI_U8 uHighRegAddr = 0x01;
MAPI_U8 uOldData = 0x00;
MAPI_U8 uData = 0x00;
MAPI_U8 uMask = 0x00;
MAPI_U8 uRRegAddr = (port > TCA9539_P7) ? uHighRegAddr : uLowRegAddr;
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// 获取port 口该组的所有状态
if(MAPI_FALSE == iptr->ReadBytes(1, &uRRegAddr, 1, &uOldData))
{
printf("[%s][%d] get the port status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// 计算返回对应port 口的状态
return (uData >> (port % 10) | 0x01);
设置输出管脚状态
通过datasheet可知,输出管脚的状态,通过寄存器0x2,0x03 来设置。
MAPI_BOOL device_mcu_tca9539::Set_port_Output(MAPI_U8 port, MAPI_BOOL bOutState)
{
mapi_i2c *iptr = NULL;
// for output status
MAPI_U8 uLowRegAddr = 0x00;
MAPI_U8 uHighRegAddr = 0x01;
MAPI_U8 uLowWReg = 0x02;
MAPI_U8 uHighWReg = 0x03;
MAPI_U8 uOldData = 0x00;
MAPI_U8 uData = 0x00;
MAPI_U8 uMask = 0x00;
MAPI_U8 uRRegAddr = (port > TCA9539_P7) ? uHighRegAddr : uLowRegAddr;
MAPI_U8 uWRegAddr = (port > TCA9539_P7) ? uHighWReg : uLowWReg;
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// 通过寄存器0x00(port0 ~ port7)/0x01(port10 ~ port17)读取当前port口的状态
if(MAPI_FALSE == iptr->ReadBytes(1, &uRRegAddr, 1, &uOldData))
{
printf("[%s][%d] get the port status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// 计算,并设置port 的新状态,其它port 状态不变
uMask = 1 << (port % 10);
// set the new status
if(bOutState){
uData = (uMask | uOldData); // set H
} else {
uData = (~uMask) & uOldData; // set L
}
// 对寄存器0x02(port0 ~ port7)/0x03(port10 ~ port17)写输出的高低状态
if(MAPI_FALSE == iptr->WriteBytes(1, &uWRegAddr, 1, &uData))
{
printf("[%s][%d] set the new status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
printf("[%s][%d] set the P%02d to %d.\n",__FUNCTION__,__LINE__,port,bOutState);
return MAPI_TRUE;
}
头文件源码
#ifndef __DEVIDE_MCU_TCA9539_H__
#define __DEVIDE_MCU_TCA9539_H__
/*@ <Include> @*/
#include "mapi_mcu.h"
#include "MsTypes.h"
#include "MTypes.h"
/*@ </Include> @*/
#define PORT_INPUT (1)
#define PORT_OUTPUT (0)
#define OUTPUT_H (1)
#define OUTPUT_L (0)
#define TCA9539_P0 (0)
#define TCA9539_P1 (1)
#define TCA9539_P2 (2)
#define TCA9539_P3 (3)
#define TCA9539_P4 (4)
#define TCA9539_P5 (5)
#define TCA9539_P6 (6)
#define TCA9539_P7 (7)
#define TCA9539_P10 (10)
#define TCA9539_P11 (11)
#define TCA9539_P12 (12)
#define TCA9539_P13 (13)
#define TCA9539_P14 (14)
#define TCA9539_P15 (16)
#define TCA9539_P16 (15)
#define TCA9539_P17 (17)
#define TCA9539_MASK_P0 (1 << 0)
#define TCA9539_MASK_P1 (1 << 1)
#define TCA9539_MASK_P2 (1 << 2)
#define TCA9539_MASK_P3 (1 << 3)
#define TCA9539_MASK_P4 (1 << 4)
#define TCA9539_MASK_P5 (1 << 5)
#define TCA9539_MASK_P6 (1 << 6)
#define TCA9539_MASK_P7 (1 << 7)
class device_mcu_tca9539 : public mapi_mcu
{
public:
DLL_PUBLIC device_mcu_tca9539(void);
DLL_PUBLIC ~device_mcu_tca9539(void);
DLL_PUBLIC MAPI_BOOL Init(void);
DLL_PUBLIC MAPI_BOOL Finalize(void);
DLL_PUBLIC MAPI_BOOL Reset(void);
DLL_PUBLIC MAPI_BOOL Set_port_mode(MAPI_U8 port, MAPI_BOOL bInput);
DLL_PUBLIC MAPI_BOOL Get_port_mode(MAPI_U8 port, MAPI_U8 *uMode);
DLL_PUBLIC MAPI_BOOL Set_port_Output(MAPI_U8 port, MAPI_BOOL bOutState);
DLL_PUBLIC MAPI_BOOL Get_port_State(MAPI_U8 port, MAPI_BOOL *bMode, MAPI_BOOL *bState);
DLL_PUBLIC MAPI_BOOL Tca9539Setup(void);
};
#endif // __DEVIDE_LED_DEFAULT_H__
源文件
// Alex.Ke
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include "MsCommon.h"
#include "MsOS.h"
#include <dirent.h>
// #include "mapi_gpio.h"
#include "mapi_i2c.h"
#include "mapi_i2c_devTable.h"
#include "mapi_gpio_devTable.h"
#include "device_mcu_tca9539.h"
#include "MSrv_Control_common.h"
// P3,P4,P5,P7 set to output 0x47
static MAPI_U8 uTca9539_Ports_L_Mode = 0xFF & \
(~(TCA9539_MASK_P3)) & \
(~(TCA9539_MASK_P4)) & \
(~(TCA9539_MASK_P5)) & \
(~(TCA9539_MASK_P7));
// P10,P11 set to output 0xFC
static MAPI_U8 uTca9539_Ports_H_Mode = (0xFF & (~(TCA9539_MASK_P0)) & (~(TCA9539_MASK_P1)));
device_mcu_tca9539::device_mcu_tca9539(void)
{
}
device_mcu_tca9539::~device_mcu_tca9539(void)
{
}
MAPI_BOOL device_mcu_tca9539::Init(void)
{
return Reset();
}
MAPI_BOOL device_mcu_tca9539::Finalize(void)
{
BOOL bRet = FALSE;
printf("Finalize TCA9539\n");
bRet = MSrv_Control_common::SetGpioDeviceStatus(MCU_RESET,FALSE);
return (bRet) ? MAPI_TRUE : MAPI_FALSE;
}
MAPI_BOOL device_mcu_tca9539::Reset(void)
{
BOOL bRet1 = FALSE;
BOOL bRet2 = FALSE;
printf("Reset TCA9539\n");
bRet1 = MSrv_Control_common::SetGpioDeviceStatus(MCU_RESET,FALSE);
usleep(100*1000); // 100ms
bRet2 = MSrv_Control_common::SetGpioDeviceStatus(MCU_RESET,TRUE);
Tca9539Setup();
return (bRet1 && bRet2) ? MAPI_TRUE : MAPI_FALSE;
}
MAPI_BOOL device_mcu_tca9539::doHandleOps(void)
{
MAPI_BOOL bMode = FALSE;
MAPI_BOOL bPlugState = TRUE; // plug out: ops H ; plug in : ops L
MAPI_BOOL bState = TRUE; // ops status. H: off; L: on
// OPS Det
Get_port_State(TCA9539_P6, &bMode, &bPlugState);
// OPS power
Get_port_State(TCA9539_P17, &bMode, &bState);
if((!bPlugState)&&(bState)){
// // set ops on
// uData = 0x7F; // P3 = H ,P7 = L
// if(MAPI_FALSE == iptr->WriteBytes(1,&uLowRegAddr,1,&uData))
// {
// printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
// return MAPI_FALSE;
// }
// usleep(100*1000);
// uData = 0xFF; // P3 = H ,P7 = H
// if(MAPI_FALSE == iptr->WriteBytes(1,&uLowRegAddr,1,&uData))
// {
// printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
// return MAPI_FALSE;
// }
Set_port_Output(TCA9539_P7,MAPI_FALSE); // to L
usleep(100*1000);
Set_port_Output(TCA9539_P7,MAPI_TRUE); // to H
printf("[%s][%d] start the ops .\n",__FUNCTION__,__LINE__);
return TRUE;
}
return FALSE;
}
MAPI_BOOL device_mcu_tca9539::Tca9539Setup(void)
{
mapi_i2c *iptr = NULL;
MAPI_U8 uCfgLowPorts = 0x06;
MAPI_U8 uCfgHighPorts = 0x07;
// for output status
MAPI_U8 uLowRegAddr = 0x02;
MAPI_U8 uHighRegAddr = 0x03;
MAPI_U8 uData = 0x00;
printf("[%s][%d] Enter .\n",__FUNCTION__,__LINE__);
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// config the port mode <input or output>
if(MAPI_FALSE == iptr->WriteBytes(1,&uCfgLowPorts,1,&uTca9539_Ports_L_Mode))
{
printf("[%s][%d] wirte the port 0~7 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
if(MAPI_FALSE == iptr->WriteBytes(1,&uCfgHighPorts,1,&uTca9539_Ports_H_Mode))
{
printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// config: set port(output) status
uData = 0xF7; // P3 = L , other bit was seted to H
if(MAPI_FALSE == iptr->WriteBytes(1,&uLowRegAddr,1,&uData))
{
printf("[%s][%d] wirte the port 0~7 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// set touch power
uData = 0xFC; // P10, P11 = L , other bit was seted to H
if(MAPI_FALSE == iptr->WriteBytes(1,&uHighRegAddr,1,&uData))
{
printf("[%s][%d] wirte the port 0~7 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
doHandleOps();
#if 0
// set ops on
uData = 0x7F; // P3 = H ,P7 = L
if(MAPI_FALSE == iptr->WriteBytes(1,&uLowRegAddr,1,&uData))
{
printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
usleep(100*1000);
uData = 0xFF; // P3 = H ,P7 = H
if(MAPI_FALSE == iptr->WriteBytes(1,&uLowRegAddr,1,&uData))
{
printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
#endif
#if 0
// config the S_USB_SEL
// uData = 0xFE; // P10 = L android source
uData = 0xFF; // P10 = H OPS source
if(MAPI_FALSE == iptr->WriteBytes(1,&uHighRegAddr,1,&uData))
{
printf("[%s][%d] wirte the port 10~17 failed.\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
#endif
printf("[%s][%d] setup success.\n",__FUNCTION__,__LINE__);
return MAPI_TRUE;
}
// bInput: TRUE --> input , FALSE --> output
MAPI_BOOL device_mcu_tca9539::Set_port_mode(MAPI_U8 port, MAPI_BOOL bInput)
{
printf("[%s][%d] Enter .\n",__FUNCTION__,__LINE__);
return MAPI_TRUE;
}
// uMode: 1 --> input, 0 --> output
MAPI_BOOL device_mcu_tca9539::Get_port_mode(MAPI_U8 port, MAPI_U8 *uMode)
{
printf("[%s][%d] Enter .\n",__FUNCTION__,__LINE__);
return MAPI_TRUE;
}
MAPI_BOOL device_mcu_tca9539::Set_port_Output(MAPI_U8 port, MAPI_BOOL bOutState)
{
mapi_i2c *iptr = NULL;
// for output status
MAPI_U8 uLowRegAddr = 0x00;
MAPI_U8 uHighRegAddr = 0x01;
MAPI_U8 uLowWReg = 0x02;
MAPI_U8 uHighWReg = 0x03;
MAPI_U8 uOldData = 0x00;
MAPI_U8 uData = 0x00;
MAPI_U8 uMask = 0x00;
MAPI_U8 uRRegAddr = (port > TCA9539_P7) ? uHighRegAddr : uLowRegAddr;
MAPI_U8 uWRegAddr = (port > TCA9539_P7) ? uHighWReg : uLowWReg;
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// get the old status
if(MAPI_FALSE == iptr->ReadBytes(1, &uRRegAddr, 1, &uOldData))
{
printf("[%s][%d] get the port status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
uMask = 1 << (port % 10);
// set the new status
if(bOutState){
uData = (uMask | uOldData); // set H
} else {
uData = (~uMask) & uOldData; // set L
}
if(MAPI_FALSE == iptr->WriteBytes(1, &uWRegAddr, 1, &uData))
{
printf("[%s][%d] set the new status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
printf("[%s][%d] set the P%02d to %d.\n",__FUNCTION__,__LINE__,port,bOutState);
return MAPI_TRUE;
}
MAPI_BOOL device_mcu_tca9539::Get_port_State(MAPI_U8 port, MAPI_BOOL *bMode, MAPI_BOOL *bState)
{
mapi_i2c *iptr = NULL;
// used for port status
MAPI_U8 uInLowRegAddr = 0x00;
MAPI_U8 uInHighRegAddr = 0x01;
MAPI_U8 uRegAddr = (port > TCA9539_P7) ? uInHighRegAddr : uInLowRegAddr;
// for port mode
MAPI_U8 uLowPorts = 0x06;
MAPI_U8 uHighPorts = 0x07;
MAPI_U8 uModeRegAddr = (port > TCA9539_P7) ? uHighPorts : uLowPorts;
MAPI_U8 uData = 0x00;
MAPI_U8 uMode = 0x00;
if(NULL == bMode || NULL == bState || (port > TCA9539_P17 || port < TCA9539_P0))
{
printf("[%s][%d] param error .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
iptr = mapi_i2c::GetI2C_Dev(TCA9539_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] Invalid I2c mcu addr .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
// get the port mode <input/outputO>
if(MAPI_FALSE == iptr->ReadBytes(1, &uModeRegAddr, 1, &uData))
{
printf("[%s][%d] get the old status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
uMode = (uData >> (port % 10)) & 0x01;
*bMode = uMode;
uData = 0x00;
if(MAPI_FALSE == iptr->ReadBytes(1, &uRegAddr, 1, &uData))
{
printf("[%s][%d] get the port status failed .\n",__FUNCTION__,__LINE__);
return MAPI_FALSE;
}
printf("[%s][%d] uRegAddr [0x%02x] , uData [0x%02x] \n", __FUNCTION__,__LINE__, uRegAddr, uData);
*bState = (uData >> (port % 10) & 0x01);
printf("[%s][%d] P%02d mode <%s> , state [%d] \n", __FUNCTION__,__LINE__, port, (bMode ? "Input":"Output"), *bState);
return MAPI_TRUE;
}