Forums

How to access gpio from userspace and kernelspace continuously and sequentially

Started by Saniya 5 months ago4 replieslatest reply 5 months ago77 views

Hello Everyone,

I need your help to write a clean code to toggle gpio in userspace and kernel space simultaneously

I am working on a project, which involves cryptography and led toggling. So the idea is as follows:

  1. A userspace application will read data input through Serial port.
  2. once it reads the data it will turn the LED ON and send the data to the kernel through af_alg crypto library.
  3. The kernel will receive and process the data. When it recieves the data it will turn OFF the LED and perform the encryption process. once the encryption is done it will turn the LED ON again and send data back to Userspace.
  4. Once the userspace application receives the encrypted data it will turn the LED OFF.

So the LED is modified twice in userspace and twice in kernel space. I tried implementation with the following 2 methods. 1st method crashes after sometime in random module and second gives GPIO access error after few mins The process has to run continuously for 5-6 hours.

1st Method: I am using gpiod library in userspace, here is the code snippet.

<code>Initialisation:

#define GPIO4_IOPORT        3 //0 base
#define GPIO_TRIGGER_LED    17
/*Initialise gpio for trigger */
static int trigger_initialise(void)
{

int ret ;

  output_line  = get_gpio_line( GPIO4_IOPORT, GPIO_TRIGGER_LED );
  ret = gpiod_line_request_output(output_line, "trigger-led", GPIOD_LINE_ACTIVE_STATE_HIGH);
  if(ret == -1)
  {
    printf("Cannot get gpio line for trigger\n");
    return -1;
  }
  ret = gpiod_line_set_value( output_line, GPIOD_LINE_ACTIVE_STATE_LOW );
  if(ret == -1)
  {
    printf("Cannot set ouput value on gpio line for trigger\n");
    return -1;
  }
  return 0;
}

And at the place where I want to set/clear gpio, I call the following function with high/low

void set_trigger_value( int value)
{
  gpiod_line_set_value( output_line, value );
}
</code>

In Kernel space I am using ioremap: Initialisation is as follows: In crypto driver

<code>unsigned long gpio_addr = 0x30230000; //GPIO4 register address
void __iomem *virtual_gpio_addr;
size_t page_size = 512;

sca_initialise(void)
{

    virtual_gpio_addr = ioremap(gpio_addr, page_size);
    if(virtual_gpio_addr == NULL)
    {
        pr_warn("Could not map I/O Address\n");
    }
}
    
once initialisation is done in driver and whenever data is recived for encrytpion process,
I toggle LED high/low, I use following function IO Memory access function
writel(0x00020000, virtual_gpio_addr) //write high to gpio 17
</code>

2nd Method: In 2nd method, I am again using gpiod library in userspace, but once I write value to gpio LED, I release it, so that kernel can have access. This is how I do

<code>#define GPIO4_IOPORT        3 //0 base
#define GPIO_TRIGGER_LED    17

static int set_trigger(uint8_t value)
{
  int ret ;

  chip = gpiod_chip_open_by_number( GPIO4_IOPORT );
  if ( chip == NULL )
  {
    goto error;
  }

  output_line = gpiod_chip_get_line( chip, GPIO_TRIGGER_LED );
  if ( output_line == NULL )
  {
    printf( "Error getting gpiod_chip_get_line\n" );
    goto error;
  }

  ret = gpiod_line_request_output(output_line, "trigger-led", GPIOD_LINE_ACTIVE_STATE_HIGH);
  if(ret == -1)
  {
    printf("Error requesting gpio line for trigger\n");
    return -1;
  }
  ret = gpiod_line_set_value( output_line, value );
  if(ret == -1)
  {
    printf("Cannot set ouput value on gpio line for trigger\n");
    return -1;
  }
  gpiod_line_release(output_line);

  chip = NULL;
  output_line = NULL;

  return 0;
error:
  return -1;
}


for kernel space, I am doing like this:
I have defined gpio in device tree as follows:

sca-trigger
{
        compatible = "trigger-led-driver";
        trigger-gpios = <&gpio4 17 GPIO_ACTIVE_HIGH>;
        status = "okay";

};
whenever I want to read or write to LED I call this:

gpiod_trigger = devm_gpiod_get(dev,"trigger", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod_trigger))
    {
        /* Sometimes we get a request to try again later, so we pass this up */
        if (PTR_ERR(gpiod_trigger) == -EPROBE_DEFER)
        {
            return -EPROBE_DEFER;
        }
        dev_err(dev, "error getting GPIO descriptor\n");
            return PTR_ERR(gpiod_trigger);
    }
devm_gpiod_put(dev,gpiod_trigger);
gpiod_trigger = NULL;
</code>

I have tried different ideas, but nothing works. Can somebody please help me? Any help is really appreciated.

Thanks,

Asma

[ - ]
Reply by Bob11August 27, 2020

I'd be surprised you even see the LED light. How long does it take your userspace--kernelspace interface to transmit data?

[ - ]
Reply by waydanAugust 27, 2020

Do you have any link to the gpiod library documentation or source code?

[ - ]
Reply by Dineshmuthu97August 28, 2020

Hi,


could you tell us about the hardware used ?

[ - ]
Reply by abernasconiAugust 31, 2020

Hi,

just a question: why are you trying to drive the same gpio line both from user and kernel space? In my opinion, it would be better to chose one of them ...

As Bob11 said, I think you cannot see the transition of LED if you turn it on in userspace and then you switch it off in kernel space unless you add a delay somewhere ... 

Am I missing something?

Andrea