Pergunta

I'm porting and existing system that used level triggered interrupts to an embedded Linux device. I'm having a bit of trouble and hopefully someone can help. My plan was to use the poll() function (in user space, no plan for a low level driver) to detect when the gpio line is high. That's the indication to do something.

Unfortunately I haven't figured out how to enable that condition. Right now I'm doing the following:

  • Write the gpio number to /sys/class/gpio/export
  • Set the direction to "in"
  • Set the edge to ?

Can I setup the GPIO such that poll will return whenever the gpio line is high, even if poll() is called multiple times without clearing the condition, but it will wait if the line is low? Should I be using something else instead of trying to use poll()? Thanks!

Update

I thought I had a solution, but apparently not. I set the edge on the GPIO line to "rising". On the hardware side, the line is tied to the "FIFO used" count of a data buffer. If there is data in the FIFO, the line is high. Otherwise it's low. I then setup the following system:

GetByte() {
    Is there data in the FIFO? {
        Read a byte.
        Return
    }
    Call poll() to wait for the data {
        Is there data in the FIFO? {
            Read a byte.
            Return
        }
    }
}

The first "If" statement is there because I only read a byte at a time and poll() won't return before the time out if the condition doesn't change (and it won't in my system if multiple bytes are in the FIFO). The problem I'm seeing now is that poll() will sometimes return but there isn't any data in the FIFO. In fact, poll() returns '1', but the FIFO reports that it's empty.

I expect poll() will only detect changes when the gpioXX/value file changes from 0 to 1 due to the "rising" edge setting with the GPIO line. Is that correct? Is this a reasonable way to use poll() or should I be looking at a different design.

Foi útil?

Solução

I finally figured out the answer. I need to read the GPIO's value file before emptying the FIFO to ensure things are in a good state the next time poll() is called. Here's the change to the pseudo code:

GetByte() {
    Is there data in the FIFO? {
        Read the GPIO value file
        Read a byte.
        Return
    }
    Call poll() to wait for the data {
        Is there data in the FIFO? {
            Read a byte.
            Return
        }
    }
}

I always try to read a byte if one is available. If it's the last byte in the FIFO, I read the GPIO value file first. I know the level triggered interrupt line is high when I do this, so I can safely clear any pending file events that poll() might see. Now I read the byte.

Now when I call poll(), I know it won't return unless it sees the rising edge from the interrupt. Simple fix, but it wasn't until I read a comment in kernel/fs/sysfs/file.c until I fully understood what I needed to do.

Outras dicas

I have this feeling that without writing a driver, you will need to access the hardware registers yourself. This involves 1. Understand the hardware, so you know the hardware addresses of the registers you need to access, 2. Use open & mmap to get a pointer to the register(s), 3. Dereference the pointers.

Here is some code I snipped from a project of mine:

fd = open("/dev/mem", O_RDWR|O_SYNC);
if (fd == -1)
{
perror("open /dev/mem");
exit(1);
}
unsigned char *start;
start = (unsigned char*)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED,
fd, 0x80810000);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top