Auf Raspberry Pi, das unter Linux verwendet werden soll, läuft das Benutzerprogramm natürlich unter dem OS-Scheduler. Daher ist es sehr schwierig, ein zeitstriktes Programm zu schreiben. Einfach gesagt, ich bin nicht gut darin, etwas in regelmäßigen Abständen genau zu verarbeiten. In einem solchen Fall handelt es sich um einen Timer-Interrupt oder eine Taktabfrage, aber ich denke, dass es viele Fälle gibt, in denen Sie Letzteres verwenden möchten, wenn Sie den geringen Overhead und die Einfachheit des Kontexts berücksichtigen. Zu diesem Zeitpunkt stören verschiedene Unterbrechungen. Ich dachte, es wäre schön, wenn ich einige einfache vorübergehende Unterbrechungen verbieten könnte, und ich habe verschiedene Dinge ausprobiert, also habe ich einen Artikel geschrieben. Es ist der DI / EI von Z80, der dem alten Mann vertraut ist.
Ich habe ein Programm geschrieben (später beschrieben), das gettimeofday () abfragt und in einem Zyklus von 100 us arbeitet. Hier sind die Ergebnisse (gemessener Zyklus) für den Standardfall und wenn Interrupts deaktiviert sind.
Wie ist das? Es ist auf einen Blick offensichtlich. Wenn Sie Interrupts deaktivieren, können Sie verschiedene Timings steuern. Zum Beispiel Infrarot-Fernbedienung. (Hinweis: Das Deaktivieren von Interrupts hat natürlich viele Nebenwirkungen. Minimieren Sie die Deaktivierungszeit.)
Laut dem Handbuch von SoC BCM2835 / 2837 von Raspberry Pi scheint es "Interrupt Disable Register" und "Interrupt Enable Register" zu geben, also schlagen Sie sie direkt. Das ist das bekannte "/ dev / mem" in GPIO zu "mmap ()".
mmap ()
, damit Sie die physikalische Adresse direkt treffen können.Und das ist alles. In Bezug auf Z80 ist 2-3 "DI" und 5 ist "EI".
Dies ist der Code, mit dem die Daten für das obige Diagramm erstellt werden. Bitte ändern Sie den Teil von #define PERI_BASE PI? _PERI_BASE
entsprechend Ihrem Raspberry Pi.
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#define BLOCK_SIZE (4 * 1024)
#define PI2_PERI_BASE 0x3f000000
#define PI1_PERI_BASE 0x20000000
#define PERI_BASE PI1_PERI_BASE // Raspberry 0/1 or 2/3
//Angegebene Zeit(us)Warten Sie durch Abfragen
inline static void waitUs(struct timeval tv_zero, int until_us) {
struct timeval tv;
int us;
while (1) {
gettimeofday(&tv, NULL);
us = (tv.tv_sec - tv_zero.tv_sec) * 1000000 + (tv.tv_usec - tv_zero.tv_usec);
if (us >= until_us) break;
}
}
int main() {
int mem_fd;
char *map;
int i;
int us_next;
struct timeval tv0, tv1;
int dt[10000];
int irq1, irq2, irq3; //Speichern wir die Interrupt-Informationen(Zum Schluss schreibe zurück an irqen)
volatile unsigned int *irqen1;
volatile unsigned int *irqen2;
volatile unsigned int *irqen3;
volatile unsigned int *irqdi1;
volatile unsigned int *irqdi2;
volatile unsigned int *irqdi3;
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) return -1;
map = (char*) mmap(NULL,
BLOCK_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
mem_fd,
PERI_BASE + 0xb000
);
if (map == MAP_FAILED) return -1;
irqen1 = (volatile unsigned int *) (map + 0x210);
irqen2 = (volatile unsigned int *) (map + 0x214);
irqen3 = (volatile unsigned int *) (map + 0x218);
irqdi1 = (volatile unsigned int *) (map + 0x21c);
irqdi2 = (volatile unsigned int *) (map + 0x220);
irqdi3 = (volatile unsigned int *) (map + 0x224);
gettimeofday(&tv0, NULL);
irq1 = *irqen1;
irq2 = *irqen2;
irq3 = *irqen3;
//Deaktivieren Sie alle Interrupts in den folgenden 3 Zeilen
*irqdi1 = 0xffffffff;
*irqdi2 = 0xffffffff;
*irqdi3 = 0xffffffff;
for (i = 0, us_next = 100; i < 10000; i++, us_next += 100) {
waitUs(tv0, us_next);
gettimeofday(&tv1, NULL);
dt[i] = (tv1.tv_usec - tv0.tv_usec) + (tv1.tv_sec - tv0.tv_sec) * 1000000;
}
//Stellen Sie das Interrupt-Berechtigungsflag in den folgenden drei Zeilen wieder her.
*irqen1 = irq1;
*irqen2 = irq2;
*irqen3 = irq3;
//Ergebnisanzeige
for (i = 1; i < 10000; i++) {
printf("%d\n", dt[i] - dt[i - 1]);
}
return 0;
}
Recommended Posts