Forum: Digitale Signalverarbeitung / DSP / Machine Learning Blackfin GPIO rising edge


von pumpkin (Gast)


Lesenswert?

Hallo Forum,

mein BF537 stellt mich gerade vor ein Kuriosum. Es geht dabei um den 
Port F (PF2 bis PF5) GPIO über den ich die Taster von meinem EZ-Kit auf 
steigende Flanke prüfen möchte. Im ersten Schritt konfigurierte ich die 
betreffenden Pins des GPIO's:
1
void Init_Flags(void)
2
{
3
  // ...
4
  *pPORTF_FER = 0x0000;
5
  *pPORTF_FER = 0x0000;
6
7
  // set PORTF direction register
8
  *pPORTFIO_DIR = 0x1FC0;
9
     //EZ-Kit switches as Input (PF5..2), LEDs (PF6..11) as Output
10
11
  // set PORTF input enable register
12
  *pPORTFIO_INEN = 0x003C;
13
     //EZ-Kit switches enable Input (PF5..2), LEDs as Output (PF6..11)
14
15
  //set PORTF polarization register
16
  *pPORTFIO_POLAR = 0x0020;
17
     //EZ-Kit switch SW10 is active low (bypass switch)
18
19
  //set PORTF edge register
20
  *pPORTFIO_EDGE = 0x001C;
21
     //EZ-Kit switches SW11-13 are rising edge sensitive
22
23
  // set PORTF clear register
24
  *pPORTFIO_CLEAR = 0x0FC0 & 0x0FC0;
25
     //EZ-Kit LEDs off
26
}

Hier geht es erstmal um den Switch SW11 und SW12 (PF4 und PF3) zum 
testen. Anschließend strickte ich mir eine einfache Abfrage in der die 
LED1 mit SW11 an und mit SW12 wieder ausgeschaltet werden sollte:
1
//...
2
#define FUNCTION 4
3
#define DOWN     3
4
// ...
5
6
void main(void)
7
{
8
  Init_Flags();
9
  // ...
10
11
  while(1)
12
  {
13
    if( *pPORTFIO & (1 << FUNCTION) )      // rising edge?
14
    {
15
      *pPORTFIO_SET = (1 << 6) & 0x0FC0;   // LED6 on
16
      *pPORTFIO_CLEAR = (1 << FUNCTION);   // (1)
17
    }
18
    else if( *pPORTFIO & (1 << DOWN) )
19
    {
20
      *pPORTFIO_CLEAR = (1 << 6) & 0x0FC0; // LED6 off
21
      *pPORTFIO_CLEAR = (1 << DOWN);       // (1)
22
    }
23
  }
24
}

(1) "For GPIOs configured as edge-sensitive, a readback of 1 from one
    of these registers is sticky. That is, once it is set it remains set
    until cleared by user code. [...]" (Hardware Reference page 14-12)

Das funktionierte leider nicht. Die LED geht weder an (und 
logischerweise auch nicht wieder aus  ;^) ). Also versuchte ich es 
hiermit:
1
//...
2
#define FUNCTION 4
3
#define DOWN     3
4
// ...
5
6
void main(void)
7
{
8
  Init_Flags();
9
  // ...
10
11
  while(1)
12
  {
13
    if( *pPORTFIO & (1 << FUNCTION) )      // rising edge?
14
    {
15
      *pPORTFIO_SET = (1 << 6) & 0x0FC0;   // LED6 on
16
    }
17
    else if( *pPORTFIO & (1 << DOWN) )
18
    {
19
      *pPORTFIO_CLEAR = (1 << 6) & 0x0FC0; // LED6 off
20
    }
21
22
    *pPORTFIO_CLEAR = (1 << FUNCTION);
23
    *pPORTFIO_CLEAR = (1 << DOWN);
24
  }
25
}

Und siehe da, es klappt; Aber nicht perfekt, d.h. manchmal mit etwas 
Verzögerung - eher marginal, aber für einen 600MHz Prozessor doch 
deutlich zu langsam. Lösche ich die pPORTFIO_CLEAR Register nicht so 
bleibt die LED (wie zu erwarten) an, nehme ich die "else"-Anweisung weg 
dann flackert sie - das macht alles Sinn. Ich sollte noch erwähnen, dass 
ein Interrupt mit 48kHz ausgelöst wird in dem bisher ein paar einstufige 
IIR's und ein mächtiger 1300er FIR durchgezogen werden (alles fractional 
1.15). Wo liegt der Fehler? Habe ich etwas übersehen/vergessen zu 
setzen?

  pumpkin



Edit:
Was mich stutzig macht ist der folgende Abschnitt in der Hardware 
Reference (page 1-11):

"GPIO interrupt sensitivity registers – The two GPIO interrupt 
sensitivity
registers specify whether individual pins are level- or edge-sensitive 
and specify—if edge-sensitive—whether just the rising edge or both the 
rising and falling edges of the signal are significant. One register 
selects the type of sensitivity, and one register selects which edges 
are significant for edge-sensitivity."

Plötzlich ist von Interrupt-Registern die Rede (sicher kann man damit 
welche auslösen, aber ist das nicht etwas inkonsistent formuliert?).

von pumpkin (Gast)


Lesenswert?

Meine Lösungen, vllt bringt es ja irgendwann jemanden weiter:

ASM Stil:
1
//...
2
#define FUNCTION 4
3
#define DOWN     3
4
// ...
5
6
void main(void)
7
{
8
  // ...
9
10
  while(1)
11
  {
12
    if( *pPORTFIO & (1 << FUNCTION) )
13
    {
14
      asm("P0.L = 0x0708; ");      //#
15
      asm("P0.H = 0xFFC0; ");      //# PORTFIO_SET
16
      asm("R0.L = 0x0040; ");
17
      asm("W[P0] = R0;    ");
18
19
      asm("P0.L = 0x0704; ");      // PORTFIO_CLEAR
20
      asm("R0.L = 0x0010; ");
21
      asm("W[P0] = R0;    ");
22
    }
23
    else if( *pPORTFIO & (1 << DOWN) )
24
    {
25
      asm("P0.L = 0x0704; ");      //#
26
      asm("P0.H = 0xFFC0; ");      //# PORTFIO_CLEAR
27
      asm("R0.L = 0x0048; ");
28
      asm("W[P0] = R0;    ");
29
    }
30
  }
31
}


C Stil:
1
//...
2
#define FUNCTION 4
3
#define DOWN     3
4
// ...
5
6
void main(void)
7
{
8
  // ...
9
10
  while(1)
11
  {
12
    if( *pPORTFIO & (1 << FUNCTION) )
13
    {
14
      *pPORTFIO_SET = (1 << 6);
15
      *pPORTFIO_CLEAR = (1 << FUNCTION);
16
    }
17
    else if( *pPORTFIO & (1 << DOWN) )
18
    {
19
      *pPORTFIO_CLEAR = (1 << 6);
20
      *pPORTFIO_CLEAR = (1 << DOWN);
21
      asm("NOP; ");                  // !!!
22
    }
23
  }
24
}

Mit dem kleinen NOP in C steht und fällt die Sache. Ich habe bisher 
nicht begriffen warum, im disassembly konnte ich bisher keine 
Unterschiede feststellen.  %^/

VisualDSP++ 4.5, May 2006


pumpkin

von Xion (Gast)


Lesenswert?

Warum nicht mit Interrupt routinen?

von pumpkin (Gast)


Lesenswert?

Da muss ich nur wieder gucken wie der mir in meinen Audio-Interrupt 
reinknallt uswusf. - ist mir (bei diesem Wetter ; ) ) zu anstrengend, 
vllt in der nächsten Version.

Viel interessanter ist imho der Umstand mit NOP. ssync() oder 
asm("SSYNC;") haben nichts gebracht. Die Errata/IC Anomaly bringt 
diesbezüglich auch nichts gescheites für den 537 hervor. 
http://www.blackfin.org hilft leider auch nicht. Die Compiler Errata hab 
ich noch nicht gewälzt - aber ich denke es liegt an ihm.


pumpkin

von Xion (Gast)


Lesenswert?

Auf gar keinen Fall ich arbeite jetz seit 2 Jahre mit Blackfin 
Prozessoren ich hab leider nicht viel zeit deine Programm zu 
nachvollziehen aber ich kann dir mit 99.99% Sicherheit sagen das es dein 
Fehler ist. Hast du überhaupt die PLL richtig intialisiert? Ich denke 
auch eines seits es ist ein Denkfehler eine Edge detecting per Polling 
zu entdeken um diese auszuschließen solltest du vielleicht eine Level 
detecting versuchen.

von pumpkin (Gast)


Lesenswert?

Ich denke nicht, dass ich einen Denkfehler habe - in ASM funktioniert 
mein Ansatz einwandfrei. Wieso sollte es ein Fehler sein einen 
Trigger-Latch (Hardware!) per polling zu dedektieren? Ich habe mir die 
Geschichte mit dem Interrupt durchdacht und bin zu dem Schluss gekommen, 
dass es für meine Anwendung vorerst nicht in Frage kommt.

Ich habe ein Beispiel von VisualDSP verwendet, insofern stellt sich die 
Frage nach der PLL für mich nicht - aber guter Tip, ich werde dem mal 
nachgehen. Vielmehr stellt sich für mich die Frage ob du in C/C++ oder 
ASM programmierst und ob du dich schonmal mit solch einer Konfiguration 
beschäftigt hast.

Ich habe auch mit keiner Silbe erwähnt, dass der Blackfin einen Fehler 
macht - Die Errata beäugen war nur ein logischer Schritt bei der 
Fehlersuche.

pumpkin

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.