GPIO: Getting ISR on both edges though edge is set to ''rising" - linux-kernel

Specific GPIO pin is connected to switch, upon pressing the switch the ISR needs to triggered. So I have the user space application to read the ISR, but I am getting the ISR on both the edges.
Receiving the interrupt when switch is pressed and also when released. How to configure to receive the ISR only on rising edge
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
int main(int argc, char *argv[]) {
int fd;
char value;
struct pollfd poll_gpio;
poll_gpio.events = POLLPRI;
// export GPIO
fd = open ("/sys/class/gpio/export", O_WRONLY);
write (fd, "44", 4);
close (fd);
// configure as input
fd = open ("/sys/class/gpio/gpio44/direction", O_WRONLY);
write (fd, "in", 3);
close (fd);
// configure interrupt
fd = open ("/sys/class/gpio/gpio44/edge", O_WRONLY);
write (fd, "rising", 7); // configure as rising edge
close (fd);
// open value file
fd = open("/sys/class/gpio/gpio44/value", O_RDONLY );
poll_gpio.fd = fd;
poll (&poll_gpio, 1, -1); // discard first IRQ
read (fd, &value, 1);
// wait for interrupt
while (1) {
poll (&poll_gpio, 1, -1);
if ((poll_gpio.revents & POLLPRI) == POLLPRI) {
lseek(fd, 0, SEEK_SET);
read (fd, &value, 1);
usleep (50);
printf("Interrupt GPIO val: %c\n", value);
}
}
close(fd); //close value file
return EXIT_SUCCESS;
}

I used gpio test driver also to test the ISR, but even in driver code I am getting ISR on both edges when the switch is pressed
Here is the gpio test driver code
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("A Button driver for the GPIO Switch");
MODULE_VERSION("0.1");
#define GPIO_NUM 44
#define GPIO_KEY_NAME "GPIO_INT_KEY"
static int irq;
/* interrupt handler*/
static irqreturn_t gpio_int_key_isr(int irq, void *dev_id)
{
printk(KERN_INFO "GPIO:Interrupt received. key: %s\n", GPIO_KEY_NAME);
return IRQ_HANDLED;
}
static int __init gpio_test_probe(struct platform_device *pdev)
{
int ret_val;
struct device *dev = &pdev->dev;
printk(KERN_INFO "GPIO Platform_probe enter\n");
gpio_request(GPIO_NUM, "sysfs");
gpio_direction_input(GPIO_NUM);
gpio_set_debounce(GPIO_NUM, 200);
gpio_export(GPIO_NUM, false);
irq = gpio_to_irq(GPIO_NUM);
if (irq < 0)
{
pr_err("IRQ is not available\n");
return -EINVAL;//1;
}
printk(KERN_INFO "IRQ using gpio_to_irq: %d\n", irq);
/*Register the interrupt handler*/
ret_val = devm_request_irq(dev, irq, gpio_int_key_isr, IRQF_TRIGGER_RISING, GPIO_KEY_NAME, pdev->dev.of_node);
if(ret_val)
{
pr_err("Failed to request GPIO interrupt %d, error %d\n",irq, ret_val);
return ret_val;
}
return 0;
}
static int __exit gpio_test_remove(struct platform_device *pdev)
{
pr_info("%s function is called. \n",__func__);
return 0;
}
/*Declare list of devices supported by the driver*/
static const struct of_device_id my_of_ids[] = {
{ .compatible = "gpio-intr-key"},
{},
};
MODULE_DEVICE_TABLE(of, my_of_ids);
/*Define platform driver structure*/
static struct platform_driver my_platform_driver = {
.probe = gpio_test_probe,
.remove = gpio_test_remove,
.driver = {
.name = "gpioIntrKey",
.of_match_table = of_match_ptr(my_of_ids),
.owner = THIS_MODULE,
}
};
module_platform_driver(my_platform_driver);
Below is the dts entry
gpio_test {
compatible = "gpio-intr-key";
gpio = <&gpio2a 44>;
interrupt-controller;
interrupt-parent = <&gpio2a>;
interrupts = <44 IRQ_TYPE_EDGE_RISING>;
status = "okay";
};

Related

Data loss SPI communication (Master Slave) (ESP32)

I am trying to make a simple SPI Master/slave comunication between two ESP32, using this code as reference https://github.com/hideakitai/ESP32DMASPI
My code is (master) :
#include <stdio.h>
#include <stdint.h>
#include <Arduino.h>
#include "maspn18_e3_a_r2_c_can_cr09338.h"
#include <ESP32DMASPIMaster.h>
//#include <ESP32DMASPISlave.h>
#include <ESP32CAN.h>
#include <CAN_config.h>
#include <iostream>
#include <stdlib.h>
//#include <SPI.h>
/*
#include <string.h>
#include <math.h>
*/
// === [ START ] Master Configuration ===
ESP32DMASPI::Master master;
static const uint32_t BUFFER_SIZE = 8; // deve essere un multiplo di 4 ==> 8192
uint8_t* spi_master_tx_buf;
//uint8_t* spi_master_rx_buf;
uint8_t num_msg = 0;
uint8_t msg_src[]= {num_msg, 0x80, 0x4A, 0x0F, 0x00, 0x00, 0x00, 0x00};
//uint8_t msg_src[]= {0x00, 0x80, 0x4A, 0x0F, 0x00, 0x00, 0x00, 0x00};
void set_buffer() {
for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
spi_master_tx_buf[i] = msg_src[i];
//spi_master_tx_buf[i] = i & 0xFF;
}
//memset(spi_master_rx_buf, 0, BUFFER_SIZE);
}
// === [ STOP ] Master Configuration ===
using namespace std;
CAN_device_t CAN_cfg; // CAN Config
const int rx_queue_size = 10; // Receive Queue size
void setup() {
Serial.begin(115200);
Serial.println("CAN reader on primary CAN bus - MASTER SPI");
//CAN_cfg.speed = CAN_SPEED_500KBPS;
//CAN_cfg.tx_pin_id = GPIO_NUM_22;
//CAN_cfg.rx_pin_id = GPIO_NUM_21;
//CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
//////////// Init CAN Module
//ESP32Can.CANInit();
// === [ START ] Master setup ===
// to use DMA buffer, use these methods to allocate buffer
spi_master_tx_buf = master.allocDMABuffer(BUFFER_SIZE);
//spi_master_rx_buf = master.allocDMABuffer(BUFFER_SIZE);
set_buffer();
delay(5000);
master.setDataMode(SPI_MODE0); // default: SPI_MODE0
master.setFrequency(4000000); // default: 8MHz (too fast for bread board...) // 4000000
master.setMaxTransferSize(BUFFER_SIZE); // default: 4092 bytes
// begin() after setting
Serial.println("master.begin() - default: VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)");
master.begin(VSPI); // default: HSPI (CS: 15, CLK: 14, MOSI: 13, MISO: 12)
// === [ STOP ] Master setup ===
}
void loop() {
master.transfer(spi_master_tx_buf, BUFFER_SIZE);
printf("[%d] Send data ==>\n", msg_src[0]);
msg_src[0]++;
for (uint32_t i = 0; i < BUFFER_SIZE; i++) {
spi_master_tx_buf[i] = msg_src[i];
//spi_master_tx_buf[i] = i & 0xFF;
}
delay(2000);
// === [ STOP ] Master loop ===
}
And for the slave :
#include <stdio.h>
#include <stdint.h>
#include <Arduino.h>
#include "maspn18_e3_a_r2_c_can_cr09338.h"
#include <ESP32DMASPISlave.h>
#include <ESP32CAN.h>
#include <CAN_config.h>
#include <iostream>
#include <stdlib.h>
#include <SPI.h>
/*
#include <string.h>
#include <math.h>
*/
// MASTER SPI ==> https://github.com/hideakitai/ESP32DMASPI/blob/master/examples/master_simple/master_simple.ino
ESP32DMASPI::Slave slave;
static const uint32_t BUFFER_SIZE = 8; // 8192
//uint8_t* spi_slave_tx_buf;
uint8_t* spi_slave_rx_buf;
using namespace std;
CAN_device_t CAN_cfg; // CAN Config
const int rx_queue_size = 10; // Receive Queue size
void setup() {
Serial.begin(115200);
Serial.println("CAN writer on second CAN bus - SLAVE SPI");
spi_slave_rx_buf = slave.allocDMABuffer(BUFFER_SIZE);
//set_buffer();
delay(5000);
// slave device configuration
slave.setDataMode(SPI_MODE0);
slave.setMaxTransferSize(BUFFER_SIZE);
// begin() after setting
//slave.begin(); // HSPI = CS: 15, CLK: 14, MOSI: 13, MISO: 12 -> default
// VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)
Serial.println("slave.begin(VSPI); - VSPI (CS: 5, CLK: 18, MOSI: 23, MISO: 19)");
slave.begin(VSPI);
}
void loop() {
// if there is no transaction in queue, add transaction
if (slave.remained() == 0) {
//slave.queue(spi_slave_rx_buf, spi_slave_tx_buf, BUFFER_SIZE);
slave.queue(spi_slave_rx_buf, BUFFER_SIZE);
}
// if transaction has completed from master,
// available() returns size of results of transaction,
// and buffer is automatically updated
while (slave.available()) {
printf("Received data ==> ");
// show received data
for (size_t i = 0; i < BUFFER_SIZE; ++i) {
printf("%d ", spi_slave_rx_buf[i]);
}
printf("\n");
slave.pop();
}
}
Basically it just sends a simple array over and over again with an incremental number in the first place. However, apparently at random, the comunication will "skip" a number or it will print the same a couple of time and then skip it. Image for reference :
Print of the received message on the slave:
What could be the cause of this problem?
I tried altering the frequence of the communication and i tried varying the buffer size to the smallest possible, but it does not seem to have any effect
Thanks a lot in advance

Shared Memory between Kernel and User

I am currently working on a kernel module for a RaspberryPi 3 and am new to this area. This should generate an interrupt on a rising or falling edge. In the corresponding ISR, a time stamp is set and a signal is generated to notify a user application.
I have taken the signaling for the sake of the code.
My goal is now to write the value of the time stamp into a shared memory and the user application can read it out after an incoming signal in order to measure the latency between the interrupt and the signal received in the user application. I have already researched but found no solution. How do I map the virtual kernel address of the allocated memory into the user application and what steps are necessary?
Thanks in advance.
Kernel Code:
/****************************************************************************/
/* Kernelmodul Shared Memory */
/****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
// kmalloc
#include <linux/slab.h>
// ioremap
#include <asm/io.h>
/****************************************************************************/
/* Define block */
/****************************************************************************/
#define DriverAuthor ""
#define DriverDescription "Shared Memory"
#define InterruptPin 26
#define GPIO_PIN_DEV_STR "PIN"
#define GPIO_PIN_STR "Timestamp"
unsigned int * timerAddr;
unsigned int time = 0;
unsigned int * SHMvirtual = 0;
/****************************************************************************/
/* Module params declaration block */
/****************************************************************************/
static short int gpio_pin = InterruptPin;
/****************************************************************************/
/* Interrupts variables block */
/****************************************************************************/
short int irq_gpio_pin = InterruptPin;
short int irq_enabled = 0; // this is only a flag
/****************************************************************************/
/* IRQ handler */
/****************************************************************************/
static irqreturn_t ISR(int irq, void *dev_id, struct pt_regs *regs) {
unsigned long flags;
// disable hard interrupts (remember them in flag 'flags')
local_irq_save(flags);
time = timerAddr[1];
*SHMvirtual = time;
// restore hard interrupts
local_irq_restore(flags);
return IRQ_HANDLED;
}
/****************************************************************************/
/* This function configures interrupts. */
/****************************************************************************/
void configInterrupts(void) {
if (gpio_request(gpio_pin, GPIO_PIN_STR))
{
printk(KERN_INFO "GPIO request faiure %d\n", gpio_pin);
return;
}
if ( (irq_gpio_pin = gpio_to_irq(gpio_pin)) < 0 )
{
printk(KERN_INFO "GPIO to IRQ mapping faiure %d\n", gpio_pin);
return;
}
printk(KERN_INFO "Mapped int %d\n", irq_gpio_pin);
if (request_irq(irq_gpio_pin, (irq_handler_t ) ISR, (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), GPIO_PIN_STR,
GPIO_PIN_DEV_STR))
{
printk("Interrupt Request failure\n");
return;
}
return;
}
/****************************************************************************/
/* This function releases interrupts. */
/****************************************************************************/
void releaseInterrupt(void) {
free_irq(irq_gpio_pin, GPIO_PIN_DEV_STR);
gpio_free(gpio_pin);
return;
}
/****************************************************************************/
/* Module init / cleanup block. */
/****************************************************************************/
int initModule(void) {
printk(KERN_INFO "Hello\n");
configInterrupts();
timerAddr = ioremap(0x3F003000, 0x20);
SHMvirtual = (unsigned int *)kmalloc(sizeof(time),GFP_USER);
return 0;
}
void cleanupModule(void) {
printk(KERN_INFO "Goodbye\n");
releaseInterrupt();
kfree(SHMvirtual);
return;
}
module_init(initModule);
module_exit(cleanupModule);
/****************************************************************************/
/* Module licensing/description block. */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DriverAuthor);
MODULE_DESCRIPTION(DriverDescription);

sys v shared memory from kernel module to user space process

i am new in linux kernel module developpement and i am searching for sharing a memory segment from kernel module to user space process to escape latency of copying data.
i am using the sys v shared memory api, when i share memory between two process it's work fine, but i am not able to share memory between process and kernel module.
bellow is my code of the kernel module and the user space app
server side : module
#include <linux/module.h> // init_module, cleanup_module //
#include <linux/kernel.h> // KERN_INFO //
#include <linux/types.h> // uint64_t //
#include <linux/kthread.h> // kthread_run, kthread_stop //
#include <linux/delay.h> // msleep_interruptible //
#include <linux/syscalls.h> // sys_shmget //
#define BUFSIZE 100
#define SHMSZ BUFSIZE*sizeof(char)
key_t KEY = 5678;
static struct task_struct *shm_task = NULL;
static char *shm = NULL;
static int shmid;
static int run_thread( void *data )
{
char strAux[BUFSIZE];
shmid = sys_shmget(KEY, SHMSZ, IPC_CREAT | 0666);
if( shmid < 0 )
{
printk( KERN_INFO "SERVER : Unable to obtain shmid\n" );
return -1;
}
shm = sys_shmat(shmid, NULL, 0);
if( !shm )
{
printk( KERN_INFO "SERVER : Unable to attach to memory\n" );
return -1;
}
strncpy( strAux, "hello world from kernel module", BUFSIZE );
memcpy(shm, strAux, BUFSIZE);
return 0;
}
int init_module()
{
printk( KERN_INFO "SERVER : Initializing shm_server\n" );
shm_task = kthread_run( run_thread, NULL, "shm_server" );
return 0;
}
void cleanup_module()
{
int result;
printk( KERN_INFO "SERVER : Cleaning up shm_server\n" );
result = kthread_stop( shm_task );
if( result < 0 )
{
printk( KERN_INFO "SERVER : Unable to stop shm_task\n" );
}
result = sys_shmctl( shmid, IPC_RMID, NULL );
if( result < 0 )
{
printk( KERN_INFO
"SERVER : Unable to remove shared memory from system\n" );
}
}
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( " MBA" );
MODULE_DESCRIPTION( "Shared memory server" );
client side : process
#include <sys/ipc.h> // IPC_CREAT, ftok //
#include <sys/shm.h> // shmget, ... //
#include <sys/sem.h> // semget, semop //
#include <stdio.h> // printf //
#include <string.h> // strcpy //
#include <stdint.h> // uint64_t //
#define BUFSIZE 4096
key_t KEY = 5678;
int main(int argc, char *argv[]) {
int shmid, result;
char *shm = NULL;
shmid = shmget(KEY, BUFSIZE, 0666);
if (shmid == -1) {
perror("shmget");
exit(-1);
}
shm = shmat(shmid, NULL, 0);
if (!shm) {
perror("shmat");
exit(-1);
}
printf("%s\n", shm);
result = shmdt(shm);
if (result < 0) {
perror("shmdt");
exit(-1);
}
}
any suggestion or document can help.
System calls are not intended for being use by the kernel: they are for user programs only. Also, it is unlikely that is sys v memory sharing works for kernel threads.
Kernel and kernel modules have their own mechanism for interract with user
space. For sharing memory, your kernel module may implement character device and mmap method for it, which maps kernel's allocated memory to user. See example of such mmap implementation in Linux Device Drivers(3d edition), Chapter 15.

register_kretprobe fails with a return value of -2

I have written a kretprobe to hook on to the randomize_stack_top() function mentioned in fs/binfmt_elf.c file. On loading the LKM with insmod the register_kretprobe() call fails with a return value of -2. How do I go about debugging/rectifying that in order to get my module started ?
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/current.h>
#include <asm/param.h>
/* Global variables */
int randomize_stack_retval;
// randomize_stack_top() kretprobe specific declarations
static char stack_name[NAME_MAX] = "randomize_stack_top";
static int randomize_stack_top_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
return 0;
}
static int randomize_stack_top_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
randomize_stack_retval = regs_return_value(regs); //store in global variable
printk(KERN_INFO "%d\n",randomize_stack_retval);
return 0;
}
//randomize_stack_top return probe
static struct kretprobe randomize_kretprobe = {
.handler = randomize_stack_top_ret_handler,
.entry_handler = randomize_stack_top_entry_handler,
.maxactive = NR_CPUS,
};
/* Register kretprobe */
static int __init kretprobe_init(void)
{
int ret;
randomize_kretprobe.kp.symbol_name = stack_name;
ret = register_kretprobe(&randomize_kretprobe);
if (ret < 0) {
printk(KERN_INFO "register_kretprobe failed, returned %d\n",
ret);
return -1;
}
printk(KERN_INFO "Planted return probe at %s: %p\n",
randomize_kretprobe.kp.symbol_name, randomize_kretprobe.kp.addr);
return 0;
}
/* Unregister kretprobe */
static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&randomize_kretprobe);
printk(KERN_INFO "kretprobe at %p unregistered\n",
randomize_kretprobe.kp.addr);
// nmissed > 0 suggests that maxactive was set too low.
printk(KERN_INFO "Missed probing %d instances of %s\n",
randomize_kretprobe.nmissed, randomize_kretprobe.kp.symbol_name);
}
module_init(kretprobe_init);
module_exit(kretprobe_exit);
MODULE_LICENSE("GPL");
-2 corresponds to -ENOENT (you can check that in include/uapi/asm-generic/errno-base.h). Probably, it means that kprobe cannot find symbol with given name.
Note, that randomize_stack_top is static function with a short implementation and it is used only once. So it can be inlined by the gcc.

Linux kernel copy_to_user to user space display different result

There some bugs reading from the user space with this application. Is my copy_to_user dont correctly?
The following is the readout from terminal:
Press r to read from device or w to write the device r
0x-1075024108 0x15123440 0xe70401 0xe6f8dc 0xe73524
0x0 0x15037588 0xbfec6f14 0xe57612 0xbfec6f34
0x15037140 0x2 0xe57334 0xc6d690 0xd696910
0x-1075024080 0x15071734 0xc737c9 0x804835a 0x2
The following is the code from apps layer:
read(fd, read_buf, sizeof(read_buf));
for(i=0;i<=(BUFF_SIZE / sizeof(int));i+=5)
printf(" 0x%x 0x%x 0x%x 0x%x 0x%x \n",
read_buf[i],read_buf[i+1],read_buf[i+2],
read_buf[i+3],read_buf[i+4]);
break;
and the following is my driver code:
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
# include <linux/modversions.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h> // required for copy_from and copy_to user
/* character device structures */
static dev_t mmap_dev;
static struct cdev mmap_cdev;
/* methods of the character device */
static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file *filp);
/* the file operations, i.e. all character device methods */
static struct file_operations mmap_fops = {
.open = mmap_open,
.release= mmap_release,
.owner = THIS_MODULE,
};
static int *vmalloc_area;
#define NPAGES 1//16
#define BUFF_SIZE 64 // bytes
/* character device open method */
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
/* character device last close method */
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t read(struct file *filp, int *buff, size_t count, loff_t *offp)
{
unsigned long bytes_left;
printk("Inside read \n");
bytes_left = copy_to_user(buff, vmalloc_area , count);
if(bytes_left<0)
bytes_left = -EFAULT;
return bytes_left;
}
/* module initialization - called at module load time */
static int __init membuff_init(void)
{
int ret = 0, i =0;
printk(KERN_ERR "#membuff_init\n");
/* allocate a memory area with vmalloc. */
if ((vmalloc_area = vmalloc(BUFF_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_vfree;
}
/* get the major number of the character device */
if( (ret = alloc_chrdev_region(&mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "#membuff_init could not allocate major number for mmap\n");
goto out_vfree;
}
printk(KERN_ERR "#membuff_init Major number for mmap: %d\n",MAJOR(mmap_dev));
/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_cdev, mmap_dev, 1)) < 0) {
printk(KERN_ERR "#membuff_init could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
for (i = 0; i < (BUFF_SIZE / sizeof(int)); i +=1) {
vmalloc_area[i] = i;
printk(KERN_ERR "#membuff_init: %d\n",vmalloc_area[i]);
}
return ret;
out_unalloc_region:
unregister_chrdev_region(mmap_dev, 1);
out_vfree:
if(vmalloc_area)
vfree(vmalloc_area);
return ret;
}
/* module unload */
static void __exit mmap_exit(void)
{
if(vmalloc_area)
vfree(vmalloc_area);
/* remove the character deivce */
cdev_del(&mmap_cdev);
unregister_chrdev_region(mmap_dev, 1);
printk(KERN_ERR "#mmap_exit\n");
}
module_init(membuff_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("trying out copy_to_user");
MODULE_LICENSE("Dual BSD/GPL");

Resources