Forum: Mikrocontroller und Digitale Elektronik Raspberry Pi ADC Interrupt


von ADC19191 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin momentan dabei mit einem Raspberry Pi sowie einem ADC MCP3208 
und mit Hilfe der wiringPi-Bib Signale einzulesen. Ziel ist es 
irgendwann einen FIR-Filter zu implementieren. Da ist aber noch 
Zukunftsmusik :D
Momentan gebe ich über einen Signalgenerator einen Takt vor, welcher 
wiederum den Interrupt auslöst. In der ISR wird der ADC getartet, 
welcher über SPI die Daten an den Raspberry Pi sendet.
Das Problem: Am Signalgenerator stelle ich 40 kHz ein. Somit müsste ja 
der Interrupt alle 25 µs ausgelöst werden. Um das ganze zu überprüfen 
habe ich in der ISR einen Testpin so konfiguriert, dass er bei jedem 
Aufruf des ISR den Zustand wechselt. Sprich von LOW auf HIGH und von 
HIGH auf LOW wechselt. Diesen Pin messe ich mit dem Oszi. Auf dem Oszi 
sind lese ich jedoch eine Frequenz von 17 kHz ab. Weiß eventuell jemand 
wie das zustande kommt?
1
#include <stdio.h>
2
#include <string.h>
3
#include <errno.h>
4
#include <stdlib.h>
5
6
#include <wiringPi.h>
7
#include <wiringPiSPI.h>
8
9
#define CS_MCP3208  8       // BCM_GPIO8
10
11
#define BUTTON_PIN 3
12
#define DG_OUT 7
13
#define CHANNEL_BIT_MASK 0x07
14
#define BYTE_I_MASK 0x06
15
#define BYTE_II_MASK 0x00
16
#define BYTE_II_RCV_MASK 0x0F
17
#define SPI_CHANNEL 0
18
#define SPI_SPEED   2000000 // !! Start low here and if all works try to increase if needed on a breadboard I could go upto about 750000 
19
20
int toggle = 1;
21
int start, end;
22
  
23
int read_mcp3208_adc(unsigned char adcChannel);
24
25
26
void myInterrupt(void) {
27
  int adc1Channel = 0;
28
  int adc1Value   = 0;
29
  
30
  start = micros();
31
  toggle ^= 1;
32
  digitalWrite(DG_OUT, toggle); 
33
  adc1Value = read_mcp3208_adc(adc1Channel);
34
  adc1Value = (3.3/4096) * adc1Value;
35
  end = micros();
36
37
  //printf("\n int: 0 %d \n", end - start);
38
}
39
40
41
int main (void)
42
{
43
  //int adc1Channel = 0;
44
  //int adc1Value   = 0;
45
46
   
47
  if(wiringPiSetup() == -1)
48
  {
49
    fprintf (stdout, "Unable to start wiringPi: %s\n", strerror(errno));
50
    return 1 ;
51
  }
52
53
  wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED);
54
  
55
    if ( wiringPiISR (BUTTON_PIN, INT_EDGE_RISING, &myInterrupt) < 0 ) {
56
      fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno));
57
      return 1;
58
  }
59
60
  pinMode(CS_MCP3208, OUTPUT);
61
  pinMode(DG_OUT, OUTPUT);
62
63
  while(1)
64
  {
65
    //system("clear");
66
    //printf("\n\nMCP3208 channel output.\n\n");
67
    //adc1Value = read_mcp3208_adc(adc1Channel);
68
    //printf("adc0 Value = %04u", adc1Value);
69
    //printf("\tVoltage = %.6f\n", ((3.3/4096) * adc1Value));
70
71
    usleep(1000000);
72
    //printf("\n int: 0 %d \n", end - start);
73
    //waitForInterrupt(BUTTON_PIN,1);
74
75
  
76
  }
77
  return 0;
78
}
79
80
81
82
int read_mcp3208_adc(unsigned char adcChannel)
83
{
84
  unsigned char buff[3];
85
  int adcValue = 0;
86
  
87
88
89
  buff[0] = BYTE_I_MASK | ((adcChannel & CHANNEL_BIT_MASK) >> 2);
90
  buff[1] = ((adcChannel & CHANNEL_BIT_MASK) << 6);
91
  buff[2] = BYTE_II_MASK;
92
93
  digitalWrite(CS_MCP3208, 0);  // Low : CS Active
94
95
  wiringPiSPIDataRW(SPI_CHANNEL, buff, 3);
96
97
  buff[1] = BYTE_II_RCV_MASK & buff[1];
98
  adcValue = ( buff[1] << 8) | buff[2];
99
100
  digitalWrite(CS_MCP3208, 1);  // High : CS Inactive
101
  
102
103
104
  return adcValue;
105
}

von Alex G. (dragongamer)


Lesenswert?

Hmm, entweder ist einfach zu viel Code im ISR - diese sollten ja 
normalerweise sehr kurz sein - oder das digitalWrite ist zu langsam da 
es immer noch durch eine Treiberschicht durch muss, auf dem Raspi.

Versuch dahingehend zu debuggen.
Erstmal in die ISR nur einen double incrementieren und nach Separat nach 
z.B. 5s anhalten und den Wert ausgeben.
Damit kannst du prüfen ob die ISR erfolgreich mit 40khz feuert.

Dann bau das Auslesen des ADC hinzu und prüfe erneut.

Zuletzt lass das ADC Zeug raus und mach nur den Toggle und miss die 
Frequenz.

von Wolfgang (Gast)


Lesenswert?

ADC19191 schrieb:
> Momentan gebe ich über einen Signalgenerator einen Takt vor, welcher
> wiederum den Interrupt auslöst. In der ISR wird der ADC getartet,
> welcher über SPI die Daten an den Raspberry Pi sendet.

Damit taucht der Jitter der Interrupt Latenz als Abtastjitter auf und du 
versaust dir bei höheren Abtastraten deine Zeitserie vom ADC.

von PittyJ (Gast)


Lesenswert?

Ist der Raspi der richtige Rechner für dein Vorhaben?
Wenn ich exaktes Timing brauche, dann nehme ich einen Rechner ohne OS, 
welches mir meine Seiten auslagern könnte.

Nichts gegen Raspi, ich selbst habe mehrere, doch für Echtzeit ist der 
nicht der richtige.

von Alex G. (dragongamer)


Lesenswert?

Das stimmt auch wieder..
Die Möglichkeit ISRs einzusetzen hat zwar einiges an interesanten 
Einsatzgebieten eröffnet (z.B. den Takt von Hallsensoren an üblichen 
Motoren auszuwerten), aber z.B. ein sinnvolles Oszilloskop kann man 
damit trotzdem nicht bauen.

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

PittyJ schrieb:
> Nichts gegen Raspi, ich selbst habe mehrere, doch für Echtzeit ist der
> nicht der richtige.

Das kommt drauf an, wie "Echtzeit" spezifiziert ist. Für einen 
Datenlogger, der im deutlichen Sub-Hz-Bereich abtastet und dessen 
Eingangssignal frequenzmäßig vernünftig begrenzt ist, wird es vermutlich 
reichen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.