[gelöst] SPI Beenden - oder: Wie bekomme ich LED D13 zum Blinken? --> SPI.end();

Hi

In meinem CAN Bus benutze ich auf Uno/Nano/Mega(-Clon) CAN-Module per SPI.
Die verwendete Library "CAN_BUS_Shield-master in Version 1.0.0"
aus der library.properties :

name=CAN-BUS Shield
version=1.0.0
author=Seeed Studio
maintainer=Seeed Studio <techsupport@seeed.cc>
sentence=Arduino library to control CAN-BUS Shield.
paragraph=Arduino library to control CAN-BUS Shield.
category=Device Control
url=https://github.com/Seeed-Studio/CAN_BUS_Shield
architectures=*

Mein Bestreben war es, mir einen Fehler-Code ausgeben zu lassen, wenn der Arduino Probleme bekommt.
Z.B. wollte ich die LED 'L' (D13) zwei Mal aufblitzen lassen, wenn bereits im setup() die Initialisierung des CAN-Modul fehlschlägt.
Soweit - so wenig Funktion zeigte sich :slight_smile:
D13 ist SPI-Clock, sollte also bereits ein OUTPUT sein - egal, pinMode eingefügt, ohne Änderung.
In der Lib gesucht, ob's eine Methode gibt, womit ich das Modul 'beenden' kann - ist nicht vorgesehen.
In der Referenz gesucht, ob ich SPI beenden kann - zumindest hat spi dafür die Methode .end() - nur will ich nicht verstehen, wie ich Das anwenden kann - ob's mir hilft ist Da noch nicht ganz raus.

Momentan habe ich das Problem, daß digitalWrite auf D13 rein gar Nichts an der LED auslöst.

Meine Intuition geht in die Richtung, daß, wenn ich SPI deaktiviere, ich wieder Herr über D13 werden - lasse mich Da gerne belehren - geiler fände ich, wenn D13 mir was vorblinkt.

SPI muß danach nicht wieder aktiviert werden - das Blinken ist bis zu einem WatchDog-Reset (8 Sekunden) - der Versuch, beim nächsten Starten Alles besser hinzubekommen.

Resets werden ausgelöst:

  • CAN-Init fail in setup() (2x Blitzen)
  • keine CAN-Nachricht empfangen über 72 Sekunden (willkürliche Zeit) (5x Blitzen)
  • Reset-Befehl via CAN (8x Blitzen)
    Das Blitzen passiert per State-Maschine in einer Endlos-Schleife bis zum Reset.

Wer einen Weg für mich hat, möge bitte in Erscheinung treten :slight_smile:

MfG

Edit
Thread als Gelöst markiert
Lösung: SPI.end(); beendet den Zugriff der SPI-Hardware auf die SPI-Pins, somit kann wieder 'normal' mit den Pins gearbeitet werden.
Normal müsste ein SPI.begin(); danach SPI wieder aktivieren - hier unnötig, da per Reset der Sketch eh neu gestartet wird.

Hast Du keinen Pin mehr frei, an den Du eine Status-Led hängen kannst?

Gruß Tommy

nach etwas nachdenken: Andere Statusled verwenden.

Kann dein Problem nicht reproduzieren.

//  UNO


#include <SPI.h>

void setup() 
{

  digitalWrite(SS,1);
  pinMode(SS,OUTPUT);
 // pinMode(13,OUTPUT);
  
}

void loop() 
{
  SPI.begin();
  digitalWrite(SS,0);
  for(int i = 0; i < 1335; i++)
  {
    SPI.transfer16(i);
    delay(1);
  }
  digitalWrite(SS,1);
  SPI.end();

  
  for(int i = 0; i < 13; i++)
  {
    digitalWrite(13,i&1);
    delay(100);
  }
  
  delay(500);
}

Hi

Pins sind wirklich keine mehr frei kopfkratz - egal, es sind keine LEDs verbaut, weshalb ich die Interne (also auf dem Arduino eh Befindliche) benutzen wollte.

Mein Problem besteht momentan darin, daß ein digitalWrite(13,x) keine Auswirkung zeigt, wenn ich den CAN-Kram starte.

Also includen und eine Instanz erzeugen - kein Problem, meine Error-Meldung geht raus.
Sobald ich aber in setup()

if (can.begin(can_speed) != CAN_OK) {
  Serial.print(F("Can init fail!!\r\n"));
#ifdef noKI
  let_wdt_bite(2); //Reset auslösen   NICHT beim Mega mit enthaltenen Logiken - da Dieser wohl (vorerst) am PC hängt
#endif    
}

Also can.begin() aufrufe, kommen meine digitalWrite nicht mehr an der LED an.

@combie
Dein Beispiel lässt die LED 5x aufblinken (denke, während des Transfer blitzt Die auch rum, dafür bin ich aber zu langsam).

MfG

Hi

/*********************************************************************************************************
** Function name:           begin
** Descriptions:            init can and set speed
*********************************************************************************************************/
byte MCP_CAN::begin(byte speedset, const byte clockset)
{
    pSPI->begin();
    byte res = mcp2515_init(speedset, clockset);
    return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT);
}

Das ist die .begin()-Methode der CAN-Lib.
Dort ist auch ein SPI_ENDE definiert:

#define SPI_END()          pSPI->endTransaction()

Wenn ich Das aufzurufen versuche, gibt's ein " 'SPI_END' was not declared in this scope".

Wird mir aber wohl nicht helfen - SPI_BEGIN(); und SPI_END(); wird recht häufig in der Lib benutzt.
... to be continue ...

MfG²

postmaster-ino:
Pins sind wirklich keine mehr frei kopfkratz - egal, es sind keine LEDs verbaut, weshalb ich die Interne (also auf dem Arduino eh Befindliche) benutzen wollte.

wennst im Fehlerfall die CS vom CAN-Bus Modul als Signalisierung verwendest? Ist ja dann "eh" tot, dann kannst auch noch was rausblinken. Und im laufenden Betrieb hast bei Aktivität etwas geflackere. Ist auch nicht schlecht...

Hi

Ist ja das Problem: Es flackert Nichts.
Ohne can.begin() lässt sich D13 ganz normal befehligen, nach dem can.begin() kommt Da Nichts mehr von an.

Theoretisch könnte ich den Port auch direkt beschreiben - hatte zwas wieder gehofft, daß digitalWrite Das unterm Strich auch irgendwie hin bekommt ... :wink:

Mal Lesen, woran D13 hängt ...

MfG

ich rede jetzt von deiner definierten Chip Select Leitung - nicht vom Clock!

Hi

An D13 hängt Clock, denke, Das ist auch mein Problem, daß Da ein Timer Da die Finger drauf hat.
Ein anderer Pin würde bedeuten, daß ich eine zusätzliche LED hinzufügen müsste - blöd, da ja schon Eine vorhanden ist, Die ja sogar 'tut' - nur eben nicht nach dem can.begin();

  DDRB = B00100000;
  PORTB = B00100000;
  PORTB = B00000000;
  delay(1000);  
  PORTB = B00100000;
  delay(1000);
  PORTB = B00000000;
  delay(1000);

Schaltet die LED übrigens auch nur an - nicht wieder aus - zumindest nach dem can.begin();
Ohne (bzw. als Eigensketch) blinkt 'L' so, wie Es der Sketch vorsieht.

Mir geht Es nicht darum, mit aller Gewalt um das Verlöten dieser einen LED herum zu kommen - nur 'L' kann ja leuchten oder eben nicht, sogar dann, wenn ich Das will - nur halt nicht mehr hinter can.begin();

MfG

Die Ursache für das Verhalten geht aus dem Datenblatt hervor.

Die meisten Portpins haben neben der Standard-Funktion ( schreiben über die Portregister ) ja noch eine Alternativ-Funktion. Wenn SPI aktiviert wird, bekommen 4 Portpins eine alternative Funktion ( MISO,MOSI,SCK,SS ). Wenn das eine OUTPUT-Funktion ist, so wie bei SCK, wird der Portpin von dem Standard-Portregister komplett getrennt und in diesem Fall mit der internen SPI-HW verbunden.
Da kannst Du dann in das Portregister reinschreiben was Du magst, der Portpin bekommt das gar nicht mit.
Edit: bei Eingängen ( z.B. MISO ) ist es ähnlich, die kann man dann gar nicht mehr auf 'Ausgang' schalten.

Erst wenn die SPI-HW komplett deaktiviert wird, werden die Ausgänge auch wieder mit dem Standard-Portregister verbunden, und reagieren dann wieder 'normal'.

OT: welch kleine Welt built-in LED and SPI - LEDs and Multiplexing - Arduino Forum :wink:

Hi

SPI-Hardware klingt doch schon Mal vielversprechend - irgendwie muß Das ja aktiviert werden - die Gegenrichtung könnte zumindest mir helfen.
Bei mir muß SPI 'danach' ja nicht mehr funktionieren - erst nach dem Reset brauche ich Das ja wieder.
Ob Das auch beim englischen Post der Fall ist, ist eher fraglich.

Morgen Mal schauen, ob ich in Sache SPI-Hardware weiter komme - sollte sich ja in den Tiefen des DaBla was zu finden lassen, welches Controll-Register Da eine 1 oder 0 braucht.

MfG

PS: Der Englische bin ich zufällig nicht :wink:

Hallo,

in dem Moment wo du die Hardware SPI Einheit initialisierst, hast du keinen Zugriff mehr über die normalen Portregister auf den Pin. Denn die Hardware Einheit SPI hat jetzt die totale Kontrolle über sich selbst. Wer ja noch schöner wenn dennoch jeder andere wild dazwischen funken könnte. Betrifft auch die USART u.a.

Habe das auch nochmal getestet. Bei mir auf meinem Mega klappt das so.

Mit SPI.begin und ohne SPI.end blinkt es wie erwartet nicht.
Mit SPI.end blinkt es.

Du wirst wohl erst den CAN-Bus mit dessen .end() Funktion beenden müssen und dann zusätzlich SPI.end() aufrufen wenn das die CAN Lib nicht ordentlich macht. Man möchte eigentlich immer klare Zustände haben für eine spätere erneute Nutzung. Dann sollte das klappen.

#include <SPI.h>

const byte pin_CLK = 52;
const byte pin_CS = 53;

void setup(void) {
  SPI.begin();
  pinMode(pin_CLK, OUTPUT);
  digitalWrite(pin_CS, HIGH);
  pinMode(pin_CS, OUTPUT);
  SPI.end();                  // ohne .end() blinkt es nicht
}

void loop(void) {
  
  heartbeat(500, pin_CLK);

}


void heartbeat (const unsigned int interval, const byte pin)       
{
  static unsigned long last_ms = 0;
  static bool state = LOW;
  
  unsigned long ms = millis();
  
  if (ms - last_ms >= interval) {
    last_ms = ms;
    state = !state;
    digitalWrite(pin, state);
  }
}

Hi

Danke @Doc - genau Das ist der Weg.
Das SPI_END(), Welches dutzende Male in der Lib selber benutzt wird, ist nicht in meinem Zugriff, Das hatte ich Gestern schon Mal in #5 probiert - das SPI.end(); hingegen funktioniert ohne Probleme - meine LED blinkt mir meinen Fehler-Code vor.

//Am Sketchanfang
#include <avr/wdt.h>    //für WTD-Reset

void setup(void){
...
}

void loop(void){
...
   if (...){
      let_wdt_bite(3);       //Reset mit Error-Code 3 (3x Blinken)
   }
...
}

void let_wdt_bite(byte errorcode) {
  SPI.end();    //SPI-Zugriff auf Pin13 beenden, damit Blink-Code ausgegeben werden kann.
  wdt_enable(WDTO_8S);
  uint32_t lasttime = millis();    //letzte Zeit eines Stern?
  uint32_t lasterror = millis();   //letzte Zeit beim Blinken?
  byte checkwert = 0;              //Zählwert Blink-Code
  byte blinkstatus = 0;            //State-Maschine

  DDRB = B00100000;                       // B5 (=D13) auf OUTPUT
  while (1) {
    switch (blinkstatus) {
      case 0:
        PORTB = B00100000;                //LED 'L' (D13 an Uno/Nano) an
        lasterror = millis();
        blinkstatus = 1;
        break;
      case 1: if (millis() - lasterror >= 200) { //warte auf Ende von HIGH
          lasterror = millis();
          blinkstatus = 2;
          PORTB = B00000000;              //LED aus
          checkwert++;
        }
        break;
      case 2: if (millis() - lasterror >= 100) { //warte auf Ende von LOW
          lasterror = millis();
          if (checkwert == errorcode) {
            blinkstatus = 3;              //wenn wir fertig geblinkt haben, längere/zusätzliche Pause
          } else {
            blinkstatus = 0;              //sonst weiter mit nächstem Blink-Impuls
          }
        }
        break;
      case 3: if (millis() - lasterror >= 400) {
          blinkstatus = 0;                //nach der Zwischenpause wieder erneut mit Error-Code anfangen
          checkwert = 0;
        }
        break;
    }
    if (millis() - lasttime >= 1000) {
      Serial.print("*");
      lasttime += 1000;
    }
  }     //der WatchDog beendet Das per Reset nach 8 Sekunden
}

Danke für's Mitgrübeln!!

MfG