Other Parts Discussed in Thread: Z-STACK, PCA9534A, PCA9534,
Tool/software: TI-RTOS
Hi,
I'm using a custom board which contains CC2650MODA module running Z-Stack 1.2.2a (bios_6_41_02_41 , driverlib cc26xxware_2_20_06_14829, xdctools_3_30_06_67). I'm trying to communicate to TI PCA9534A 8-bit I2C IO-expander. My custom PCA9534 device driver uses bsp_i2c module located in \tirtos_simplelink_2_11_01_09\packages\ti\boards\SensorTag\Interfaces respectively the sensor sw-module implementation which comes with CC2650 z-stack demo code. sensor.h/.c is just a wrapper for bsp_i2c.h/.c.
The communication runs perfectly as long as I call communication functions in task context, as soon as I'll try to read a registers in Hwi/Swi context readIOs() returns false. The Hwi is configured dynamically during PCA9534 initialization. Register read in Hwi context is triggered by PCA8534 interrupt pin which is connected to CC2650MODA module. As soon as PCA9534 drives a falling edge GPIO_InterruptISR(...) is called, but sensorReadReg(...) (which is just a wrapper for bspI2cWriteRead() always returns false.
I already checked if I2C frames are sent/received as it should be, and physical communication shows the right request/respons frame on I2C for Hwi/Swi based calls and for frequently calls in task context. So the issue has to be located somewhere in TI-RTOS context
BTW.: IAR Embedded Workbench IDE ARM v7.70.2 is used.
#include "bsp_i2c.h"
#include "sensor.h"
#include "expander_pca9534a.h"
#include "Board.h"
#include <stddef.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>
#include <xdc/cfg/global.h>
#include <ti/drivers/pin/PINCC26xx.h>
#include <ti/sysbios/knl/Swi.h>
/* ------------------------------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------------------------------
*/
/* Slave address */
#define DEVICE_I2C_ADDRESS 0x38
/* Register addresses */
#define REG_INPUT 0x00
#define REG_OUTPUT 0x01
#define REG_POL_INVERSION 0x02
#define REG_CONFIGURATION 0x03
#define REG_LENGTH 0x01 // register length
#define DEVICE_SELECT() bspI2cSelect(BSP_I2C_INTERFACE_0,DEVICE_I2C_ADDRESS)
#define DEVICE_DESELECT() bspI2cDeselect()
static uint8_t gIoConfig = 0;
static uint8_t gInputRegVal = 0x00;
static bool gInit = false;
/* interrupt pin */
PIN_Handle interruptPinHandle;
static PIN_State interruptPinState;
static PIN_Config interruptPinTable[] =
{
Board_INTERRUPT_IN | PIN_INPUT_EN | PIN_NOPULL | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS, // expander interrupt pin
PIN_TERMINATE /* Terminate list */
};
/* ------------------------------------------------------------------------------------------------
* Local Functions
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* Public Functions
* ------------------------------------------------------------------------------------------------
*/
// Hwi
void GPIO_InterruptISR(PIN_Handle interruptPinHandle, PIN_Id interruptPinId){
Swi_post(swiExpanderInterrupt);
}
// Swi
void interruptStatusSwi(){
uint8_t readVal = 0;
if(!readIOs(&readVal)){
// here we return :/
return;
}
// some stuff to do
}
// initialization
bool setIOCfg(eBoardID const config){
bool success = false;
uint8_t cfg;
uint8_t buf;
//
... some initialization
//
// Hwi config
interruptPinHandle = PIN_open(&interruptPinState, interruptPinTable);
if(interruptPinHandle == NULL){
return false;
}
if (PIN_registerIntCb(interruptPinHandle, GPIO_InterruptISR) != PIN_SUCCESS){
PIN_close(interruptPinHandle);
return false;
}
}
gInit = success;
return success;
}
bool getIOCfg(uint8_t * const data){
if(data == NULL){
return false;
}
bool success;
DEVICE_SELECT();
success = sensorReadReg(REG_INPUT, data, REG_LENGTH);
DEVICE_DESELECT();
*data = ~(*data); // return 1 for input, 0 for output -> inverted is more intuitive.
return success;
}
#pragma optimize=none
bool readIOs(uint8_t * data){
if(data == NULL){
return false;
}
bool success;
if(!DEVICE_SELECT()){
return false;
}
success = sensorReadReg(REG_INPUT, data, REG_LENGTH);// wrapper for bspI2cWriteRead(...);
DEVICE_DESELECT();
*data = *data & gIoConfig; // mask out output pins.
return success;
}
bool writeIOs(uint8_t const data, uint8_t const mask){
// read current values
bool success;
uint8_t readReg;
uint8_t writeReg = data;
// read current output register
DEVICE_SELECT();
success = sensorReadReg(REG_OUTPUT, &readReg, REG_LENGTH);
maskOutValues(readReg, mask, &writeReg);
writeReg &= ~gIoConfig; // mask out all inputs
success &= sensorWriteReg(REG_OUTPUT, &writeReg, REG_LENGTH);
DEVICE_DESELECT();
return success;
}
static swi initialization in config file
/* ================= SWI configuration ================ */
var expanderInterruptParams = new Swi.Params();
expanderInterruptParams.arg0 = 1;
expanderInterruptParams.arg1 = 0;
expanderInterruptParams.priority = 1;
expanderInterruptParams.trigger = 0;
Program.global.swiExpanderInterrupt = Swi.create("&interruptStatusSwi", expanderInterruptParams);
It doesn't matter if I call register read in Hwi or Swi context, both return false.
My question is, is there any configuration of Hwi/Swi I missed? Are there any preconditions I have to take into account, so I can use I2C communication in interrupt context?