Estoy usando SPI para escribir y leer los datos de la placa esclava. Tengo dos preguntas con respecto a este proceso:
Pregunta 1. ¿Por qué cuando estoy tratando de leer 1.000.000 bytes a través de SPI usando 1 mensaje, funciona más lento que si los divido en K mensajes?
Traté de jugar con la diferencia entre un mensaje enorme por transacción y varios mensajes más pequeños (lo que en total nos da exactamente el mismo tamaño de búfer) y observé que a menor tamaño del mensaje, mayor velocidad de transacción SPI.
Pregunta 2. ¿Hay alguna forma de aumentar la velocidad de transacción de SPI?
Según mis pruebas, la transacción SPI pura de 1.000.000 de bytes divididos en 500 paquetes requiere 380 ms de tiempo de trabajo.
Lo que significa que tengo 8.000.000 bits por 0,38 segundos => 20,55 Mbits/seg, que es menos de 48 Mbits/seg que se supone que es.
Además, aquí hay algunos fragmentos de código que usé para comparar y probar:
device = "/dev/spidev1.0";
mode = SPI_MODE_0;
bits = 8;
speed = 48000000;
fd = open(device, O_RDWR);
memset(read_buffer, 0, sizeof(read_buffer));
mass_xfer[0].tx_buf = (unsigned long)tx1;
mass_xfer[0].len = 2;
mass_xfer[0].speed_hz = speed;
// sz - amount of bytes within one SPI message
// n - amount of messages in one SPI transaction
unsigned long sz = 2000, i, n = (nbytes + sz - 1) / sz;
for (i = 0; i < n; i++) {
mass_xfer[i + 1].rx_buf = (unsigned long)read_buffer + i * sz;
mass_xfer[i + 1].len = min(sz, nbytes - i * sz);
mass_xfer[i + 1].speed_hz = speed;
}
timestamp_t t0 = get_timestamp();
ret = ioctl(fd, SPI_IOC_MESSAGE(n + 1), mass_xfer);
// ret = ioctl(fd, SPI_IOC_MESSAGE(1), &read_xfer); // When I tried to read using one message, time was more than 600ms
timestamp_t t1 = get_timestamp();
printf(" SPI READ: %.2f (%d) %d\n", (t1 - t0)/1000.0L, n + 1, SPI_MSGSIZE(n + 1)); // After this output, for 1.000.000 bytes I am receiving 380.xx ms
if (ret < 1)
pabort("can't send spi message");
¿Algunas ideas?
ACTUALIZACIÓN 1:
SO: Linux 3.15.10-bone8 #1 viernes 26 de septiembre 14:20:19 PDT 2014 armv7l GNU/Linux
CPU: Sitara AM3358 1GHz. De acuerdo con esta CPU, la velocidad máxima del reloj SPI es de 48 MHz.
El código está escrito en C++ y usa la biblioteca spidev.h.
Básicamente la tabla es BeagleBone Black .
ACTUALIZACIÓN 2: Hice muchas pruebas y descubrí qué está pasando y qué causa el problema.
La razón son las brechas entre las lecturas de bytes. Para ser más específicos, revisemos las líneas de código: read_xfer.rx_buf = read_buffer; read_xfer.len = ; read_xfer.speed_hz = 48000000; ioctl(fd, SPI_IOC_MESSAGE(1), &read_xfer);
Si colocamos 100 (que se lee 100 bytes) en lugar de, veremos la siguiente imagen en el osciloscopio: como puede notar, lee 8 bits, luego hace una pausa y luego lee otros 8 bits. Entonces, el problema son esos espacios entre la lectura de los bytes. Aquí hay algunos resultados de prueba usando un osciloscopio:
Según los resultados, no puedo leer mensajes de más de 100 000 bytes en un paquete, ya que las brechas crearán una sobrecarga enorme.
OTRA PREGUNTA ¿Qué provoca esas brechas y cómo reducirlas?
Como regla general, este tipo de esto no se hace mejor de esta manera. ¿Realmente está usando este código para hacer algo o simplemente está tratando de instrumentar las capacidades de SPI? Qué más se está ejecutando en la placa y cómo está configurado su kernel. ¿Cuál es la velocidad del procesador configurada realmente y qué prioridad tiene su pequeña aplicación?
Si tiene algún tipo de requisito casi en tiempo real, le sugiero que mire
a) DMA (transmisión de descarga de los búferes de la zona de usuario)
b) Xenomai
c) (para los locos entusiastas) la PRU
¡Espero que esta no sea una pregunta de tarea! Aquí hay 2 enlaces para que comiences con A.
https://stackoverflow.com/questions/3333959/mapping-dma-buffers-to-userspace https://groups.google.com/forum/#!topic/beagleboard/UPbU2WoVzVI
Su búfer SPI está configurado para enviar solo una cierta cantidad de bits a la vez. Dividirá su mensaje en segmentos del tamaño del búfer como está viendo en el alcance.
Wouter van Ooijen
alias
pericintion
alias
Wouter van Ooijen
alias