2016-04-14 52 views
6

Utrzymuję kod obszaru użytkownika, który komunikuje się z FPGA przez SPI. W tej chwili jest sondowanie, aby sprawdzić, czy istnieją dane, na które należy zareagować, a których nie jestem zachwycony. The (mocno uproszczony) struktura nici łączności wygląda następująco:Czy mogę wybrać() na deskryptorze pliku/dev/spidev?

int spi_fd; 

void do_transfer(char *buf, int len) 
{ 
    struct spi_ioc_transfer xfer; 
    memset(xfer, 0, sizeof(xfer)); 

    ioctl_tell_some_fpga_register_heads_up(); 

    xfer[0].len = len; 
    xfer[0].tx_buf = NULL; 
    xfer[0].rx_buf = buf; 
    ioctl(spi_fd, SPI_IOC_MESSAGE(1), xfer); 

    ioctl_tell_some_fpga_register_were_done(); 
} 

void *comm_thread(void arg) 
{ 
    uint8_t config = SPI_MODE_3; 
    __u32 speed = 4000000; 
    char buffer[5120]; 

    spi_fd = open("/dev/spidev1.0", O_RDWR); 
    ioctl(spi_fd, SPI_IOC_WR_MODE, &config); 
    ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 

    while(1) { 
     sleep(2); //ugh 
     if(ioctl_read_some_fpga_register_that_says_if_theres_data()) 
     { 
      do_transfer(buffer, some_small_number_of_bytes()); 
      do_stuff(buffer); //you get the picture 
     } 
    } 
} 

ja bym naprawdę preferują rozwiązania opartego na zdarzeniu nad poll-and-sen. Pierwszą rzeczą, która przyszła mi do głowy robi select() na deskryptor pliku spidev zamiast sprawdzania jakiś rejestr co X sekund, coś

fd_set myset; 

while(1) { 
    FD_ZERO(&myset); 
    FD_SET(spi_fd, &myset); 
    select(spi_fd + 1, &myset, NULL, NULL, NULL); 
    do_transfer(buffer, some_small_number_of_bytes()); 
    do_stuff(buffer); 
} 

rzeczą jest nie mogę znaleźć żadnych przykładów osób obsługujących jak SPI to i zastanawiam się, czy może istnieje ku temu dobry powód. Czy Can/dev/spidev może być używany w ten sposób? Czy zrobi to coś głupiego jak zawsze/nigdy nie będąc "gotowymi do czytania"? Czy może być wykonane, aby zachowywać się tak, jak chcę? Czy jest zależny od sprzętu? Nie mam nic przeciwko małym hakerom, jeśli jest to konieczne, ale nie jestem pewien, czy/gdzie powinienem szukać.

+1

'select()' powinno działać. Dane są gotowe do czytania, gdy tylko gotowy jest jeden bajt w buforze jądra. Nie mogę jednak zagwarantować, że autor sterownika urządzenia nie ciął żadnych narożników. – fuz

+0

Jeśli sterownik jest dźwiękowy, powinno działać 'select()'. Pamiętaj o tych kwestiach, ale dobrze jest napisać odpowiedni test - nawet jeśli wszystko działa na urządzeniu, na które teraz celujesz, będziesz wdzięczny za test, jeśli później spróbujesz zbudować urządzenie lub sterownik na którym zawodzi. –

+1

* "Naprawdę wolałbym rozwiązanie oparte na zdarzeniach" * - Jeśli sterownik SPI zmusza do odpytywania, ponieważ nie używa przerwania, to nie ma magicznej procedury, która zmieni sytuację.Używanie ** select() ** (które może nie działać z *** *** przestrzenią użytkownika *** SPI) spowoduje jedynie przesunięcie odpytywania kodu i ukryje się za wywołaniem libc. Jeśli chcesz sterować zdarzeniami we/wy, musisz użyć/napisać sterownik, który generuje przerwań i usług. – sawdust

Odpowiedz

2

Czy mogę wybrać() na deskryptorze pliku/dev/spidev?

nr
W spidev documentation stany

At this time there is no async I/O support; everything is purely synchronous. 

Co ważniejsze spidev driver nie obsługuje operację plików poll. Skill systemowy select() wymaga sterownika urządzenia do obsługi odpytywania sond.

670 static const struct file_operations spidev_fops = { 
671   .owner =  THIS_MODULE, 
672   /* REVISIT switch to aio primitives, so that userspace 
673   * gets more complete API coverage. It'll simplify things 
674   * too, except for the locking. 
675   */ 
676   .write =  spidev_write, 
677   .read =   spidev_read, 
678   .unlocked_ioctl = spidev_ioctl, 
679   .compat_ioctl = spidev_compat_ioctl, 
680   .open =   spidev_open, 
681   .release =  spidev_release, 
682   .llseek =  no_llseek, 
683 }; 
+1

Jeśli nie ma asynchronicznego wsparcia we/wy ani żadnego sposobu blokowania, dopóki urządzenie nie będzie gotowe do dostarczenia danych, jest to dość smutne. :( –

+0

@DavidSchwartz - Sterownik spidev nie był przeznaczony do sterownika o jakości produkcyjnej, jest to pamięć użytkownika umożliwiająca szybkie tworzenie i testowanie sterownika protokołu w modelu sterownika SPI .Jeśli urządzenie slave SPI wymaga uwagi , zazwyczaj występuje szum HW, taki jak przerwanie GPIO. – sawdust

1

Jeszcze przed tym może być pytanie sterownika Linux SPI, trzeba spojrzeć na sposób, w jaki można uzyskać informacje o statusie z FPGA.

Jeśli FPGA nie robi czegoś w rodzaju prowadzenia linii przerwań lub uwagi, mistrz SPI (przypuszczalnie podłączony do procesora) będzie musiał wykonać operację SPI, aby odpytać FPGA. Więc dopóki nie masz kodu w przestrzeni jądra, który okresowo wykonuje to pobieranie, nie ma informacji dostępnych w sterowniku dla przestrzeni użytkownika do sensownego wybrania().

Jeśli otrzymasz sygnał uwagi z FPGA z powrotem do procesora (który w zależności od tego, czy cokolwiek innego się nim dzieli, może być tak prosty jak wyłączenie MISO poza zakrętem), możesz prawdopodobnie monitorować to jako przerwanie albo w sterowniku SPI jądra, albo osobno przy użyciu interfejsu przerwania przestrzeni użytkownika, w którym można wybrać().

Jeśli nie, będziesz musiał ocenić kompromisy związane z przeniesieniem sondowania statusu przez SPI do niestandardowego sterownika jądra, zamiast pozostawić go w przestrzeni użytkownika.