ftdi_ft4222: Added GPIO interrupt support for language bindings.
- FT4222 GPIO ISR implementation was specific to C/C++ and ignored language binding support. This is now fixed via adv_func updates. - GPIO ISR code has been refactored to reduce i2c traffic when using I/O expanders - Added support for built-in FT4222 GPIO interrupts Signed-off-by: Henry Bruce <henry.bruce@intel.com>
This commit is contained in:
committed by
Brendan Le Foll
parent
d2fcb88c4b
commit
1fd4ed5736
@@ -41,7 +41,7 @@ typedef struct {
|
||||
mraa_result_t (*gpio_mode_replace) (mraa_gpio_context dev, mraa_gpio_mode_t mode);
|
||||
mraa_result_t (*gpio_mode_pre) (mraa_gpio_context dev, mraa_gpio_mode_t mode);
|
||||
mraa_result_t (*gpio_mode_post) (mraa_gpio_context dev, mraa_gpio_mode_t mode);
|
||||
|
||||
|
||||
mraa_result_t (*gpio_edge_mode_replace) (mraa_gpio_context dev, mraa_gpio_edge_t mode);
|
||||
|
||||
mraa_result_t (*gpio_dir_replace) (mraa_gpio_context dev, mraa_gpio_dir_t dir);
|
||||
@@ -53,7 +53,8 @@ typedef struct {
|
||||
mraa_result_t (*gpio_write_pre) (mraa_gpio_context dev, int value);
|
||||
mraa_result_t (*gpio_write_post) (mraa_gpio_context dev, int value);
|
||||
mraa_result_t (*gpio_mmap_setup) (mraa_gpio_context dev, mraa_boolean_t en);
|
||||
void* (*gpio_interrupt_handler_replace) (mraa_gpio_context dev);
|
||||
mraa_result_t (*gpio_interrupt_handler_init_replace) (mraa_gpio_context dev);
|
||||
mraa_result_t (*gpio_wait_interrupt_replace) (mraa_gpio_context dev);
|
||||
|
||||
mraa_result_t (*i2c_init_pre) (unsigned int bus);
|
||||
mraa_result_t (*i2c_init_bus_replace) (mraa_i2c_context dev);
|
||||
|
||||
@@ -268,18 +268,21 @@ static void*
|
||||
mraa_gpio_interrupt_handler(void* arg)
|
||||
{
|
||||
mraa_gpio_context dev = (mraa_gpio_context) arg;
|
||||
if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_replace))
|
||||
return dev->advance_func->gpio_interrupt_handler_replace(dev);
|
||||
|
||||
int fp = -1;
|
||||
mraa_result_t ret;
|
||||
|
||||
// open gpio value with open(3)
|
||||
char bu[MAX_SIZE];
|
||||
sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
|
||||
int fp = open(bu, O_RDONLY);
|
||||
if (fp < 0) {
|
||||
syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin);
|
||||
return NULL;
|
||||
if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_init_replace)) {
|
||||
if (dev->advance_func->gpio_interrupt_handler_init_replace(dev) != MRAA_SUCCESS)
|
||||
return NULL;
|
||||
} else {
|
||||
// open gpio value with open(3)
|
||||
char bu[MAX_SIZE];
|
||||
sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
|
||||
fp = open(bu, O_RDONLY);
|
||||
if (fp < 0) {
|
||||
syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_PTHREAD_CANCEL
|
||||
@@ -309,11 +312,15 @@ mraa_gpio_interrupt_handler(void* arg)
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
ret = mraa_gpio_wait_interrupt(dev->isr_value_fp
|
||||
if (IS_FUNC_DEFINED(dev, gpio_wait_interrupt_replace)) {
|
||||
ret = dev->advance_func->gpio_wait_interrupt_replace(dev);
|
||||
} else {
|
||||
ret = mraa_gpio_wait_interrupt(dev->isr_value_fp
|
||||
#ifndef HAVE_PTHREAD_CANCEL
|
||||
, dev->isr_control_pipe[0]
|
||||
#endif
|
||||
);
|
||||
}
|
||||
if (ret == MRAA_SUCCESS && !dev->isr_thread_terminating) {
|
||||
#ifdef HAVE_PTHREAD_CANCEL
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
@@ -391,8 +398,10 @@ mraa_gpio_interrupt_handler(void* arg)
|
||||
#ifdef HAVE_PTHREAD_CANCEL
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
#endif
|
||||
close(dev->isr_value_fp);
|
||||
dev->isr_value_fp = -1;
|
||||
if (fp != -1) {
|
||||
close(dev->isr_value_fp);
|
||||
dev->isr_value_fp = -1;
|
||||
}
|
||||
#if defined(SWIGJAVA) || defined(JAVACALLBACK)
|
||||
|
||||
if(dev->isr == mraa_java_isr_callback) {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#define PCA9672_PINS 8
|
||||
#define PCA9545_BUSSES 4
|
||||
#define GPIO_PORT_IO_RESET GPIO_PORT2
|
||||
#define GPIO_PORT_IO_STATUS GPIO_PORT3
|
||||
#define GPIO_PORT_IO_INT GPIO_PORT3
|
||||
|
||||
static FT_HANDLE ftHandleGpio = (FT_HANDLE) NULL; //GPIO Handle
|
||||
static FT_HANDLE ftHandleI2c = (FT_HANDLE) NULL; //I2C/SPI Handle
|
||||
@@ -52,6 +52,36 @@ static int numI2cGpioExpanderPins = 8;
|
||||
static int numI2cSwitchBusses = 4;
|
||||
static int currentI2cBus = 0;
|
||||
|
||||
|
||||
static void
|
||||
mraa_ftdi_ft4222_sleep_ms(unsigned long mseconds)
|
||||
{
|
||||
struct timespec sleepTime;
|
||||
|
||||
sleepTime.tv_sec = mseconds / 1000; // Number of seconds
|
||||
sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds
|
||||
|
||||
// Iterate nanosleep in a loop until the total sleep time is the original
|
||||
// value of the seconds parameter
|
||||
while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR))
|
||||
;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
mraa_ftdi_ft4222_get_tick_count_ms()
|
||||
{
|
||||
static unsigned int startTick = 0;
|
||||
unsigned int ticks;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
ticks = now.tv_sec * 1000;
|
||||
ticks += now.tv_usec / 1000;
|
||||
if (startTick == 0)
|
||||
startTick = ticks;
|
||||
return ticks - startTick;
|
||||
}
|
||||
|
||||
|
||||
mraa_result_t
|
||||
mraa_ftdi_ft4222_init()
|
||||
{
|
||||
@@ -181,7 +211,8 @@ mraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data
|
||||
{
|
||||
uint16 bytesRead = 0;
|
||||
uint8 controllerStatus;
|
||||
// syslog(LOG_NOTICE, "FT4222_I2CMaster_Read(%#02X, %#02X)", addr, length);
|
||||
syslog(LOG_NOTICE, "FT4222_I2CMaster_Read(%#02X, %#02X)", addr, length);
|
||||
mraa_ftdi_ft4222_sleep_ms(1);
|
||||
FT4222_STATUS ft4222Status = FT4222_I2CMaster_Read(handle, addr, data, length, &bytesRead);
|
||||
ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus);
|
||||
if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) {
|
||||
@@ -189,6 +220,7 @@ mraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data
|
||||
FT4222_I2CMaster_Reset(handle);
|
||||
return 0;
|
||||
}
|
||||
syslog(LOG_NOTICE, "FT4222_I2CMaster_Read completed");
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
@@ -197,7 +229,7 @@ mraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_
|
||||
{
|
||||
uint16 bytesWritten = 0;
|
||||
uint8 controllerStatus;
|
||||
// syslog(LOG_NOTICE, "FT4222_I2CMaster_Write(%#02X, %#02X, %d)", addr, *data, bytesToWrite);
|
||||
syslog(LOG_NOTICE, "FT4222_I2CMaster_Write(%#02X, %#02X, %d)", addr, *data, bytesToWrite);
|
||||
FT4222_STATUS ft4222Status = FT4222_I2CMaster_Write(handle, addr, (uint8_t*) data, bytesToWrite, &bytesWritten);
|
||||
ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus);
|
||||
if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) {
|
||||
@@ -209,6 +241,7 @@ mraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_
|
||||
if (bytesWritten != bytesToWrite)
|
||||
syslog(LOG_ERR, "FT4222_I2CMaster_Write wrote %u of %u bytes.\n", bytesWritten, bytesToWrite);
|
||||
|
||||
syslog(LOG_NOTICE, "FT4222_I2CMaster_Write completed");
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
@@ -242,6 +275,17 @@ ftdi_ft4222_set_internal_gpio_dir(int pin, GPIO_Dir direction)
|
||||
return MRAA_SUCCESS;
|
||||
}
|
||||
|
||||
static mraa_result_t
|
||||
ftdi_ft4222_set_internal_gpio_trigger(int pin, GPIO_Trigger trigger)
|
||||
{
|
||||
FT4222_STATUS ft4222Status = FT4222_GPIO_SetInputTrigger(ftHandleGpio, pin, trigger);
|
||||
if (ft4222Status == FT4222_OK)
|
||||
return MRAA_SUCCESS;
|
||||
else
|
||||
return MRAA_ERROR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
||||
// Function detects known I2C switches and returns the number of busses.
|
||||
// On startup switch is disabled so default bus will be integrated i2c bus.
|
||||
static int
|
||||
@@ -260,6 +304,7 @@ static mraa_result_t
|
||||
mraa_ftdi_ft4222_i2c_select_bus(int bus)
|
||||
{
|
||||
if (bus != currentI2cBus) {
|
||||
syslog(LOG_NOTICE, "mraa_ftdi_ft4222_i2c_select_bus switching to bus %d", bus);
|
||||
uint8_t data;
|
||||
if (bus == 0)
|
||||
data = 0;
|
||||
@@ -292,34 +337,6 @@ mraa_ftdi_ft4222_i2c_context_write(mraa_i2c_context dev, uint8_t* data, int leng
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mraa_ftdi_ft4222_sleep_ms(unsigned long mseconds)
|
||||
{
|
||||
struct timespec sleepTime;
|
||||
|
||||
sleepTime.tv_sec = mseconds / 1000; // Number of seconds
|
||||
sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds
|
||||
|
||||
// Iterate nanosleep in a loop until the total sleep time is the original
|
||||
// value of the seconds parameter
|
||||
while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR))
|
||||
;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
mraa_ftdi_ft4222_get_tick_count_ms()
|
||||
{
|
||||
static unsigned int startTick = 0;
|
||||
unsigned int ticks;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
ticks = now.tv_sec * 1000;
|
||||
ticks += now.tv_usec / 1000;
|
||||
if (startTick == 0)
|
||||
startTick = ticks;
|
||||
return ticks - startTick;
|
||||
}
|
||||
|
||||
|
||||
/******************* I2C functions *******************/
|
||||
|
||||
@@ -488,13 +505,27 @@ mraa_ftdi_ft4222_gpio_init_internal_replace(mraa_gpio_context dev, int pin)
|
||||
static mraa_result_t
|
||||
mraa_ftdi_ft4222_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode)
|
||||
{
|
||||
return MRAA_SUCCESS;
|
||||
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static mraa_result_t
|
||||
mraa_ftdi_ft4222_gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode)
|
||||
{
|
||||
return MRAA_SUCCESS;
|
||||
if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) {
|
||||
switch (mode) {
|
||||
case MRAA_GPIO_EDGE_NONE:
|
||||
return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, 0);
|
||||
case MRAA_GPIO_EDGE_BOTH:
|
||||
return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING | GPIO_TRIGGER_FALLING);
|
||||
case MRAA_GPIO_EDGE_RISING:
|
||||
return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING);
|
||||
case MRAA_GPIO_EDGE_FALLING:
|
||||
return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_FALLING);
|
||||
default:
|
||||
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
|
||||
}
|
||||
} else
|
||||
return MRAA_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -581,49 +612,61 @@ mraa_ftdi_ft4222_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void*
|
||||
mraa_ftdi_ft4222_gpio_interrupt_handler_replace(mraa_gpio_context dev)
|
||||
static mraa_boolean_t
|
||||
mraa_ftdi_ft4222_has_internal_gpio_triggered(int pin)
|
||||
{
|
||||
#ifdef USE_FT4222_GPIO_TRIGGER
|
||||
// FIXME: Use big buffer; shouldn't be more than this many events to read
|
||||
GPIO_Trigger event_buf[256];
|
||||
int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
while (1) {
|
||||
uint16 num_events = 0;
|
||||
FT4222_STATUS status = FT4222_GPIO_GetTriggerStatus(ftHandleGpio, GPIO_PORT_IO_STATUS, &num_events);
|
||||
if (status != FT4222_OK)
|
||||
printf("FT4222_GPIO_GetTriggerStatus failed with code %d\n", status);
|
||||
printf("%u: FT4222_GPIO_GetTriggerStatus Events = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events);
|
||||
if (num_events > 0) {
|
||||
int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
uint16 num_events_read;
|
||||
FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, GPIO_PORT_IO_STATUS, event_buf, num_events, &num_events_read);
|
||||
// printf("%u: FT4222_GPIO_ReadTriggerQueue Events= %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events_read);
|
||||
printf("%u: level = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), level);
|
||||
if (level != prev_level) {
|
||||
dev->isr(dev->isr_args);
|
||||
prev_level = level;
|
||||
}
|
||||
uint16 num_events = 0;
|
||||
FT4222_STATUS ft4222Status = FT4222_GPIO_GetTriggerStatus(ftHandleGpio, pin, &num_events);
|
||||
if (num_events > 0) {
|
||||
int i;
|
||||
uint16 num_events_read;
|
||||
GPIO_Trigger event;
|
||||
for (i = 0; i < num_events; ++i)
|
||||
FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, pin, &event, 1, &num_events_read);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
mraa_ftdi_ft4222_sleep_ms(20);
|
||||
// int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
// printf("level = %d\n", level);
|
||||
static mraa_result_t
|
||||
mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace(mraa_gpio_context dev)
|
||||
{
|
||||
if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) {
|
||||
mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin);
|
||||
} else {
|
||||
ftdi_ft4222_set_internal_gpio_dir(GPIO_PORT_IO_INT, GPIO_INPUT);
|
||||
ftdi_ft4222_set_internal_gpio_trigger(GPIO_PORT_IO_INT, GPIO_TRIGGER_FALLING);
|
||||
mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT);
|
||||
}
|
||||
#else
|
||||
return MRAA_SUCCESS;
|
||||
}
|
||||
|
||||
static mraa_result_t
|
||||
mraa_ftdi_ft4222_gpio_wait_interrupt_replace(mraa_gpio_context dev)
|
||||
{
|
||||
int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
while (1) {
|
||||
int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
// MRAA_GPIO_EDGE_BOTH
|
||||
if (level != prev_level) {
|
||||
dev->isr(dev->isr_args);
|
||||
prev_level = level;
|
||||
mraa_boolean_t is_internal_pin = mraa_ftdi_ft4222_is_internal_gpio(dev->pin);
|
||||
mraa_boolean_t interrupt_detected = FALSE;
|
||||
|
||||
// INT pin of i2c PCA9672 GPIO expander is connected to FT4222 GPIO #3
|
||||
// We use INT to detect any expander GPIO level change
|
||||
while (!dev->isr_thread_terminating && !interrupt_detected) {
|
||||
if (is_internal_pin) {
|
||||
interrupt_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin);
|
||||
}
|
||||
mraa_ftdi_ft4222_sleep_ms(100);
|
||||
else {
|
||||
mraa_boolean_t gpio_activity_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT);
|
||||
if (gpio_activity_detected) {
|
||||
int level = mraa_ftdi_ft4222_gpio_read_replace(dev);
|
||||
if (level != prev_level) {
|
||||
interrupt_detected = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!interrupt_detected)
|
||||
mraa_ftdi_ft4222_sleep_ms(20);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
return MRAA_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -653,7 +696,8 @@ mraa_ftdi_ft4222_populate_gpio_func_table(mraa_adv_func_t* func_table)
|
||||
func_table->gpio_dir_replace = &mraa_ftdi_ft4222_gpio_dir_replace;
|
||||
func_table->gpio_read_replace = &mraa_ftdi_ft4222_gpio_read_replace;
|
||||
func_table->gpio_write_replace = &mraa_ftdi_ft4222_gpio_write_replace;
|
||||
func_table->gpio_interrupt_handler_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_replace;
|
||||
func_table->gpio_interrupt_handler_init_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace;
|
||||
func_table->gpio_wait_interrupt_replace = &mraa_ftdi_ft4222_gpio_wait_interrupt_replace;
|
||||
}
|
||||
|
||||
|
||||
@@ -752,3 +796,4 @@ mraa_ftdi_ft4222()
|
||||
sub_plat->adv_func = func_table;
|
||||
return sub_plat;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user