bug correction: retry reading values if i2c read was unsuccessfull, do not loose interuption added files for AXP209 interrupt started mapping axp209 interrupt

This commit is contained in:
Vincent-FK 2019-09-13 03:13:58 +08:00
parent 65fd83e6d5
commit 1aaecc7c3e
12 changed files with 233 additions and 86 deletions

View File

@ -4,7 +4,7 @@ TOOLS_CFLAGS := -Wall -std=c99 -D _DEFAULT_SOURCE
# #
all: funkey_gpio_management all: funkey_gpio_management
funkey_gpio_management: funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o smbus.o funkey_gpio_management: funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o driver_axp209.o smbus.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^

71
driver_axp209.c Normal file
View File

@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <linux/input.h>
#include "read_conf_file.h"
#include <assert.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "smbus.h"
#include "driver_axp209.h"
/****************************************************************
* Defines
****************************************************************/
#define DEBUG_AXP209_PRINTF (1)
#if (DEBUG_AXP209_PRINTF)
#define DEBUG_PRINTF(...) printf(__VA_ARGS__);
#else
#define DEBUG_PRINTF(...)
#endif
/****************************************************************
* Static variables
****************************************************************/
static int fd_axp209;
static char i2c0_sysfs_filename[] = "/dev/i2c-0";
/****************************************************************
* Static functions
****************************************************************/
/****************************************************************
* Public functions
****************************************************************/
bool axp209_init(void) {
if ((fd_axp209 = open(i2c0_sysfs_filename,O_RDWR)) < 0) {
printf("In axp209_init - Failed to open the I2C bus %s", i2c0_sysfs_filename);
// ERROR HANDLING; you can check errno to see what went wrong
return false;
}
if (ioctl(fd_axp209, I2C_SLAVE, AXP209_I2C_ADDR) < 0) {
printf("In axp209_init - Failed to acquire bus access and/or talk to slave.\n");
// ERROR HANDLING; you can check errno to see what went wrong
return false;
}
return true;
}
bool axp209_deinit(void) {
// Close I2C open interface
close(fd_axp209);
return true;
}
int axp209_read_interrupt_bank_3(void){
int val = i2c_smbus_read_byte_data ( fd_axp209 , AXP209_INTERRUPT_BANK_3_STATUS );
if(val < 0){
return val;
}
DEBUG_PRINTF("READ AXP209_INTERRUPT_BANK_3_STATUS: 0x%02X\n",val);
return 0xFF & val;
}

31
driver_axp209.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _DRIVER_AXP209_H_
#define _DRIVER_AXP209_H_
/****************************************************************
* Includes
****************************************************************/
#include <stdbool.h>
/****************************************************************
* Defines
****************************************************************/
// Chip physical address
#define AXP209_I2C_ADDR 0x34
// Chip registers adresses
#define AXP209_INTERRUPT_BANK_3_STATUS 0x4A
// Masks
#define AXP209_INTERRUPT_PEK_SHORT_PRESS 0x02
#define AXP209_INTERRUPT_PEK_LONG_PRESS 0x01
/****************************************************************
* Public functions
****************************************************************/
bool axp209_init(void);
bool axp209_deinit(void);
int axp209_read_interrupt_bank_3(void);
#endif //_DRIVER_AXP209_H_

BIN
driver_axp209.o Normal file

Binary file not shown.

View File

@ -29,8 +29,8 @@
/**************************************************************** /****************************************************************
* Static variables * Static variables
****************************************************************/ ****************************************************************/
int fd_i2c_expander; static int fd_i2c_expander;
char i2c0_sysfs_filename[] = "/dev/i2c-0"; static char i2c0_sysfs_filename[] = "/dev/i2c-0";
/**************************************************************** /****************************************************************
* Static functions * Static functions
@ -67,15 +67,23 @@ bool pcal6416a_deinit(void) {
return true; return true;
} }
uint16_t pcal6416a_read_mask_interrupts(void){ int pcal6416a_read_mask_interrupts(void){
uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS ); int val_int = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS );
if(val_int < 0){
return val_int;
}
uint16_t val = val_int & 0xFFFF;
DEBUG_PRINTF("READ PCAL6416A_INT_STATUS : 0x%04X\n",val); DEBUG_PRINTF("READ PCAL6416A_INT_STATUS : 0x%04X\n",val);
return val; return (int) val;
} }
uint16_t pcal6416a_read_mask_active_GPIOs(void){ int pcal6416a_read_mask_active_GPIOs(void){
uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT ); int val_int = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT );
if(val_int < 0){
return val_int;
}
uint16_t val = val_int & 0xFFFF;
val = 0xFFFF-val; val = 0xFFFF-val;
DEBUG_PRINTF("READ PCAL6416A_INPUT (active GPIOs) : 0x%04X\n",val); DEBUG_PRINTF("READ PCAL6416A_INPUT (active GPIOs) : 0x%04X\n",val);
return val; return (int) val;
} }

View File

@ -14,16 +14,16 @@
#define PCAL6416A_I2C_ADDR 0x20 #define PCAL6416A_I2C_ADDR 0x20
// Chip registers adresses // Chip registers adresses
#define PCAL6416A_INPUT 0x00 /* Input port [RO] */ #define PCAL6416A_INPUT 0x00 /* Input port [RO] */
#define PCAL6416A_DAT_OUT 0x02 /* GPIO DATA OUT [R/W] */ #define PCAL6416A_DAT_OUT 0x02 /* GPIO DATA OUT [R/W] */
#define PCAL6416A_POLARITY 0x04 /* Polarity Inversion port [R/W] */ #define PCAL6416A_POLARITY 0x04 /* Polarity Inversion port [R/W] */
#define PCAL6416A_CONFIG 0x06 /* Configuration port [R/W] */ #define PCAL6416A_CONFIG 0x06 /* Configuration port [R/W] */
#define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */ #define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */
#define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */ #define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */
#define PCAL6416A_INPUT_LATCH 0x44 /* Port0 Input latch [R/W] */ #define PCAL6416A_INPUT_LATCH 0x44 /* Port0 Input latch [R/W] */
#define PCAL6416A_EN_PULLUPDOWN 0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */ #define PCAL6416A_EN_PULLUPDOWN 0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */
#define PCAL6416A_SEL_PULLUPDOWN 0x48 /* Port0 Pull-up/Pull-down slct [R/W] */ #define PCAL6416A_SEL_PULLUPDOWN 0x48 /* Port0 Pull-up/Pull-down slct [R/W] */
#define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */ #define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */
#define PCAL6416A_INT_STATUS 0x4C /* Interrupt status [RO] */ #define PCAL6416A_INT_STATUS 0x4C /* Interrupt status [RO] */
#define PCAL6416A_OUTPUT_CONFIG 0x4F /* Output port config [R/W] */ #define PCAL6416A_OUTPUT_CONFIG 0x4F /* Output port config [R/W] */
@ -32,8 +32,8 @@
****************************************************************/ ****************************************************************/
bool pcal6416a_init(void); bool pcal6416a_init(void);
bool pcal6416a_deinit(void); bool pcal6416a_deinit(void);
uint16_t pcal6416a_read_mask_interrupts(void); int pcal6416a_read_mask_interrupts(void);
uint16_t pcal6416a_read_mask_active_GPIOs(void); int pcal6416a_read_mask_active_GPIOs(void);
#endif //_DRIVER_PCAL6416A_H_ #endif //_DRIVER_PCAL6416A_H_

Binary file not shown.

Binary file not shown.

View File

@ -1,33 +1,6 @@
/* Copyright (c) 2011, RidgeRun /* Copyright (c) 2019 FunKey
* All rights reserved. * All rights reserved.
* *
From https://www.ridgerun.com/developer/wiki/index.php/Gpio-int-test.c
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the RidgeRun.
* 4. Neither the name of the RidgeRun nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "gpio-utils.h" #include "gpio-utils.h"

View File

@ -12,6 +12,7 @@
#include <linux/input.h> #include <linux/input.h>
#include "gpio_mapping.h" #include "gpio_mapping.h"
#include "driver_pcal6416a.h" #include "driver_pcal6416a.h"
#include "driver_axp209.h"
/**************************************************************** /****************************************************************
* Defines * Defines
@ -21,7 +22,7 @@
return(EXIT_FAILURE); \ return(EXIT_FAILURE); \
} while(0) } while(0)
#define DEBUG_GPIO_PRINTF (0) #define DEBUG_GPIO_PRINTF (1)
#define ERROR_GPIO_PRINTF (1) #define ERROR_GPIO_PRINTF (1)
#if (DEBUG_GPIO_PRINTF) #if (DEBUG_GPIO_PRINTF)
@ -40,6 +41,9 @@
// If not declared, there will be no timeout and no periodical sanity check of GPIO expander values // If not declared, there will be no timeout and no periodical sanity check of GPIO expander values
#define TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP 2 #define TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP 2
// This is for debug purposes on cards or eval boards that do not have the AXP209
//#define ENABLE_AXP209_INTERRUPTS
/**************************************************************** /****************************************************************
* Static variables * Static variables
@ -48,9 +52,12 @@ static int nb_mapped_gpios;
static int * gpio_pins; static int * gpio_pins;
STRUCT_MAPPED_GPIO * chained_list_mapping; STRUCT_MAPPED_GPIO * chained_list_mapping;
static int max_fd = 0; static int max_fd = 0;
static int gpio_fd_interrupt_i2c; static int gpio_fd_interrupt_expander_gpio;
static int gpio_fd_interrupt_axp209;
static fd_set fds; static fd_set fds;
static bool * mask_gpio_value; static bool * mask_gpio_value;
static bool interrupt_i2c_expander_found = false;
static bool interrupt_axp209_found = false;
/**************************************************************** /****************************************************************
@ -178,37 +185,37 @@ static void find_and_call_mapping_function(int idx_gpio_interrupted,
} }
/***** Init GPIO Interrupt i2c expander fd *****/ /***** Init GPIO Interrupt i2c expander fd *****/
static int init_gpio_interrupt(void) static int init_gpio_interrupt(int pin_nb, int *fd_saved)
{ {
// Variables // Variables
int cur_pin_nb = GPIO_PIN_I2C_EXPANDER_INTERRUPT; GPIO_PRINTF("Initializing Interrupt on GPIO pin: %d\n", pin_nb);
GPIO_PRINTF("Initializing Interrupt i2c expander GPIO pin fd: %d\n", cur_pin_nb);
// Init fds fd_set // Init fds fd_set
FD_ZERO(&fds); FD_ZERO(&fds);
//Initializing I2C interrupt GPIO //Initializing I2C interrupt GPIO
gpio_export(cur_pin_nb); gpio_export(pin_nb);
//gpio_set_edge(cur_pin_nb, "both"); // Can be rising, falling or both //gpio_set_edge(cur_pin_nb, "both"); // Can be rising, falling or both
gpio_set_edge(cur_pin_nb, "falling"); // Can be rising, falling or both gpio_set_edge(pin_nb, "falling"); // Can be rising, falling or both
gpio_fd_interrupt_i2c = gpio_fd_open(cur_pin_nb, O_RDONLY); *fd_saved = gpio_fd_open(pin_nb, O_RDONLY);
GPIO_PRINTF("fd is: %d\n", *fd_saved);
// add stdin and the sock fd to fds fd_set // add stdin and the sock fd to fds fd_set
safe_fd_set(gpio_fd_interrupt_i2c, &fds, &max_fd); safe_fd_set(*fd_saved, &fds, &max_fd);
return 0; return 0;
} }
/***** DeInit GPIO Interrupt i2c expander fd *****/ /***** DeInit GPIO Interrupt i2c expander fd *****/
static int deinit_gpio_interrupt(void) static int deinit_gpio_interrupt(int fd_saved)
{ {
GPIO_PRINTF("DeInitializing Interrupt i2c expander GPIO pin fd\n"); GPIO_PRINTF("DeInitializing Interrupt on GPIO pin fd: %d\n", fd_saved);
// Remove stdin and sock fd from fds fd_set // Remove stdin and sock fd from fds fd_set
safe_fd_clr(gpio_fd_interrupt_i2c, &fds, &max_fd); safe_fd_clr(fd_saved, &fds, &max_fd);
// Unexport GPIO // Unexport GPIO
gpio_fd_close(gpio_fd_interrupt_i2c); gpio_fd_close(fd_saved);
return 0; return 0;
} }
@ -242,12 +249,22 @@ int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
current = current->next_mapped_gpio; current = current->next_mapped_gpio;
} while(current != NULL); } while(current != NULL);
// Init GPIO interrupt from I2C expander // Init GPIO interrupt from I2C GPIO expander
init_gpio_interrupt(); GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n");
init_gpio_interrupt(GPIO_PIN_I2C_EXPANDER_INTERRUPT, &gpio_fd_interrupt_expander_gpio);
// Init I2C expander // Init I2C expander
pcal6416a_init(); pcal6416a_init();
#ifdef ENABLE_AXP209_INTERRUPTS
// Init GPIO interrupt from AXP209
GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n");
init_gpio_interrupt(GPIO_PIN_AXP209_INTERRUPT, &gpio_fd_interrupt_axp209);
// Init AXP209
axp209_init();
#endif //ENABLE_AXP209_INTERRUPTS
return 0; return 0;
} }
@ -255,10 +272,21 @@ int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
int deinit_mapping_gpios(void) int deinit_mapping_gpios(void)
{ {
// DeInit GPIO interrupt from I2C expander // DeInit GPIO interrupt from I2C expander
deinit_gpio_interrupt(); GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n");
deinit_gpio_interrupt(gpio_fd_interrupt_expander_gpio);
// DeInit I2C expander // DeInit I2C expander
pcal6416a_deinit(); pcal6416a_deinit();
#ifdef ENABLE_AXP209_INTERRUPTS
// DeInit GPIO interrupt from AXP209
GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n");
deinit_gpio_interrupt(gpio_fd_interrupt_axp209);
// DeInit AXP209
axp209_deinit();
#endif //ENABLE_AXP209_INTERRUPTS
return 0; return 0;
} }
@ -267,12 +295,11 @@ int deinit_mapping_gpios(void)
int listen_gpios_interrupts(void) int listen_gpios_interrupts(void)
{ {
// Variables // Variables
char buffer[2]; //char buffer[2];
int idx_gpio, value; //int value;
int idx_gpio;
bool previous_mask_gpio_value[nb_mapped_gpios]; bool previous_mask_gpio_value[nb_mapped_gpios];
bool mask_gpio_current_interrupts[nb_mapped_gpios]; bool mask_gpio_current_interrupts[nb_mapped_gpios];
uint16_t val_i2c_mask_interrupted, val_i2c_mask_active;
bool interrupt_found = false;
// Back up master // Back up master
fd_set dup = fds; fd_set dup = fds;
@ -282,29 +309,31 @@ int listen_gpios_interrupts(void)
memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool)); memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool)); memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool));
// Waiting for interrupt or timeout, Note the max_fd+1 // If interrupt not already found, waiting for interrupt or timeout, Note the max_fd+1
if(!interrupt_i2c_expander_found && !interrupt_axp209_found){
#ifdef TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP #ifdef TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP
struct timeval timeout = {TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP, 0}; struct timeval timeout = {TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP, 0};
int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout); int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout);
#else #else
int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, NULL); int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, NULL);
#endif //TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP #endif //TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP
if(!nb_interrupts){ if(!nb_interrupts){
// Timeout case // Timeout case
GPIO_PRINTF(" Timeout, forcing sanity check\n"); GPIO_PRINTF(" Timeout, forcing sanity check\n");
// Timeout forcing a "Found interrupt" event for sanity check // Timeout forcing a "Found interrupt" event for sanity check
interrupt_found = true; interrupt_i2c_expander_found = true;
} }
else if ( nb_interrupts < 0) { else if ( nb_interrupts < 0) {
perror("select"); perror("select");
return -1; return -1;
}
} }
// Check if interrupt from I2C expander // Check if interrupt from I2C expander or AXP209
// Check which cur_fd is available for read // Check which cur_fd is available for read
for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) { for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) {
if (FD_ISSET(cur_fd, &dup)) { if (FD_ISSET(cur_fd, &dup)) {
// Revenir au debut du fichier (lectures successives). /*// Rewind file
lseek(cur_fd, 0, SEEK_SET); lseek(cur_fd, 0, SEEK_SET);
// Read current gpio value // Read current gpio value
@ -313,19 +342,54 @@ int listen_gpios_interrupts(void)
break; break;
} }
// Effacer le retour-chariot. // remove end of line char
buffer[1] = '\0'; buffer[1] = '\0';
value = 1-atoi(buffer); value = 1-atoi(buffer);*/
// Found interrupt // Found interrupt
interrupt_found = true; if(cur_fd == gpio_fd_interrupt_expander_gpio){
interrupt_i2c_expander_found = true;
}
else if(cur_fd == gpio_fd_interrupt_axp209){
interrupt_axp209_found = true;
}
} }
} }
if(interrupt_found){
#ifdef ENABLE_AXP209_INTERRUPTS
if(interrupt_axp209_found){
GPIO_PRINTF(" Found interrupt AXP209\n");
int val_int_bank_3 = axp209_read_interrupt_bank_3();
if(val_int_bank_3 < 0){
GPIO_PRINTF(" Could not read AXP209 with I2C\n");
return 0;
}
interrupt_axp209_found = false;
if(val_int_bank_3 & AXP209_INTERRUPT_PEK_SHORT_PRESS){
GPIO_PRINTF(" AXP209 short PEK key press detected\n");
}
if(val_int_bank_3 & AXP209_INTERRUPT_PEK_LONG_PRESS){
GPIO_PRINTF(" AXP209 long PEK key press detected\n");
}
}
#endif //ENABLE_AXP209_INTERRUPTS
if(interrupt_i2c_expander_found){
// Read I2C GPIO masks: // Read I2C GPIO masks:
val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts(); int val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts();
val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs(); if(val_i2c_mask_interrupted < 0){
GPIO_PRINTF(" Could not read pcal6416a_read_mask_interrupts\n");
return 0;
}
int val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs();
if(val_i2c_mask_active < 0){
GPIO_PRINTF(" Could not read pcal6416a_read_mask_active_GPIOs\n");
return 0;
}
interrupt_i2c_expander_found = false;
// Find GPIO idx correspondance // Find GPIO idx correspondance
for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){ for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){

View File

@ -11,8 +11,8 @@
/**************************************************************** /****************************************************************
* Defines * Defines
****************************************************************/ ****************************************************************/
#define GPIO_PIN_I2C_EXPANDER_INTERRUPT 35 //PB3 #define GPIO_PIN_I2C_EXPANDER_INTERRUPT 35 //PB3
//#define GPIO_PIN_I2C_EXPANDER_INTERRUPT 38 //PB6 #define GPIO_PIN_AXP209_INTERRUPT 37 //PB5
/**************************************************************** /****************************************************************
* Public functions * Public functions

Binary file not shown.