Ich behalte einige Userspace-Code, der über SPI mit einem FPGA spricht. Im Augenblick wird abgefragt, ob es Daten zum Handeln gibt, über die ich nicht begeistert bin. Die (stark vereinfacht) Struktur des comm Thread sieht wie folgt aus:Kann ich() auf einem Dateideskriptor/dev/spidev auswählen?
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
}
}
}
Ich würde wirklich lieber eine ereignisbasierte Lösung über Umfrage-und-Schlaf. Das erste, was in den Sinn kam war dabei ein select() auf der spidev Dateideskriptors statt einige Register alle X Sekunden überprüft, so etwas wie
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);
}
Sache ist, kann ich keine Beispiele von Menschen, wie Umgang mit SPI finden und ich frage mich, ob es vielleicht einen guten Grund dafür gibt. Kann/dev/spidev auf diese Weise verwendet werden? Wird es etwas tun, doof wie immer/nie "Read Read"? Kann es sein gemacht so zu verhalten, wie ich will? Ist es Hardware abhängig? Ich bin nicht abgeneigt, wenn ein kleiner Kernel-Treiber hackt, wenn es notwendig ist, aber ich bin mir nicht sicher, ob/wohin ich schauen muss.
'select()' sollte funktionieren. Die Daten können gelesen werden, sobald ein einzelnes Byte im Puffer des Kernels bereitsteht. Ich kann jedoch nicht garantieren, dass der Autor des Gerätetreibers keine Ecken und Kanten abgeschnitten hat. – fuz
Wenn der Treiber Sound ist, sollte 'select()' funktionieren. Während Sie sich dieser Probleme bewusst sind, sollten Sie einen geeigneten Test schreiben. Selbst wenn alles auf dem Gerät funktioniert, auf das Sie jetzt zielen, werden Sie für den Test dankbar sein, wenn Sie später versuchen, ein Gerät oder einen Treiber zu erstellen woran es scheitert. –
* "Ich würde wirklich eine ereignisbasierte Lösung bevorzugen" * - Wenn der SPI-Treiber Sie zum Abfragen zwingt, weil er keine Interrupts verwendet, dann gibt es keine magische Routine, die die Situation verändern wird.Die Verwendung von ** select() ** (was möglicherweise nicht mit dem *** user-space *** SPI-Treiber funktioniert) würde nur die Abfrage Ihres Codes verschieben und sich hinter einem libc-Aufruf verbergen. Wenn Sie ereignisgesteuerte E/A verwenden möchten, müssen Sie einen Treiber verwenden/schreiben, der Interrupts für Dienste generiert. – sawdust