1.1 Einstieg in Arduino für STM32

Forum der STM32 Boardleute: https://www.stm32duino.com

Anleitung für MacOS

Arduino Software laden und installieren.
Unter Voreinstellungen zusätzliche Boardverwalter-URL eingeben damit die Erweiterung gefunden wird:
https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json

Boardverwalter
Boardverwalter-URL hinzufügen

Arduino-IDE NEU Starten => Dann wird Eintrag unter Voreinstellungen erst aktiv!​
DANN In den Boardverwalter gehen und STM32 MCU based borads installieren
Werkzeuge => Board => Boardverwalter => STM32 => Installieren

Boardinstallation
Boardinstallation

Das richtige Board auswählen:
Werkzeuge =>​ Board =>​ STM32 boards =>​ Nucleo-64​

Nucleo-64 auswählen
Nucleo-64 auswählen

Den richtigen Chip auswählen
Werkzeuge =>​ Board part number =>​ Nucleo 152RE​

Einstecken des Nucleo​ zum Programmieren
Wie bei Arduino gewohnt:
Werkzeuge =>​ Port =>​ COM ???​ –Nein!
Unter MacOS wird das Board als Volume eingebunden.
Die Software wird auf das erscheinende externe Laufwerk NODE_L152RE kopiert.

Bord wird als Volume (ext. Datenspeicher) angezeigt
Bord wird als Volume (ext. Datenspeicher) angezeigt

Upload method: “Mass Storage” auswählen.
Nicht 😭 wenn der Mac beim Upload über nicht richtig ausgeworfene Volumes 🤬.

Nicht korrekt ausgeworfen
Nicht korrekt ausgeworfen
Nucleo L152RE
Nucleo L152RE
Upload method: "Mass Storage"
Upload method: “Mass Storage”

Testprogramm

#define Board_LED D13 // grüne LED auf dem Board

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
}

void loop(){
    digitalWrite(Board_LED, HIGH); //Output Bitwise High
    delay(200);                //Wait...
    digitalWrite(Board_LED, LOW); //Output Bitwise High
    delay(200);                //Wait...
}

Anleitung für Windows

Ausgeben und Einlesen von Werten über den seriellen Monitor

Arduino-Doku zur seriellen Schnittstelle Serial. Zur besseren Lesbarkeit der Ausgaben wird printf verwendet:

#define Board_LED D13
char empfangByte = 0; // für empfangenes Byte

void setup(){   // Einmalige Ausführung => Initialisierungen...
    pinMode(Board_LED, OUTPUT);  // Pin als Ausgang
    Serial.begin(115200); // Serielle Schnittstelle starten und Baudrate festlegen
}

void loop(){
    digitalWrite(Board_LED, HIGH); //Output Bitwise High
    Serial.println("an"); // Ausgabe auf Seriellen Monitor
    delay(1000);                //Wait...
    digitalWrite(Board_LED, LOW); //Output Bitwise LOW
    Serial.println("aus");
    delay(1000);                //Wait...
    Serial.printf("Analogwert: %4d\n",analogRead(A0)); // AD-Wert ausgeben von A0
    if(Serial.available()>0){ // wurde was empfangen?
      empfangByte = Serial.read();  // lies ein Byte
      Serial.printf("Ich empfing: %3d 0x%2x %c\n",empfangByte,empfangByte,empfangByte);
    }
}
Port auswählen
Port auswählen
Seriellen Monitor starten
Seriellen Monitor starten
Baudrate entsprechend einstellen
Baudrate entsprechend einstellen

Pin-Namen des Chips verwenden statt Arduino-Bezeichnungen

Kann ich auch die Bezeichnungen des Chips benutzen ohne die Ummodelung durch Arduino?
Ja, das geht, die Bezeichnungen des Chips sind verfügbar.

void setup(){   // Einmalige Ausführung => Initialisierungen...  
    pinMode(PC0, OUTPUT);  // PC0 als Ausgang
    pinMode(PC1, OUTPUT);
    pinMode(PC2, OUTPUT);
    pinMode(PC3, OUTPUT); 
    pinMode(PA1, INPUT_PULLDOWN); // PA1 als Eingang mit Pulldown einschalten
}

void loop(){
    digitalWrite(PC2,digitalRead(PA1)); // PA1 auf PC2 ausgeben
    digitalWrite(PC0, HIGH); //Output Bitwise High
    delay(300);                //Wait...
    digitalWrite(PC0, LOW); //Output Bitwise High
    digitalWrite(PC1, HIGH); //Output Bitwise High
    delay(300);                //Wait...
    digitalWrite(PC1, LOW); //Output Bitwise High
}

Bonus: Ports direkt adressieren

Wäre es nicht schön, in einer Schleife viele Pins bequem initialisieren zu können? Leider geht das nicht so einfach, da hinter den Bezeichnern eine wirre Zuordnung zu Werten steckt, zur besseren Lesbarkeit wird printf verwendet:

void setup(){   // Einmalige Ausführung => Initialisierungen...
    Serial.begin(115200);
    Serial.printf("PC0: %d\n",PC0);
    Serial.printf("PC1: %d\n",PC1);
    Serial.printf("PC2: %d\n",PC2);
    Serial.printf("PC3: %d\n",PC3);
    Serial.printf("PC4: %d\n",PC4);
    Serial.printf("PC5: %d\n",PC5);
    Serial.printf("PC6: %d\n",PC6);
    Serial.printf("PC7: %d\n",PC7);
}

void loop(){
}

Ok, könnte man es auch über die I/O-Register direkt hin kriegen?
Ja, Anleitungen gibt es z.B.: STM32 GPIO OUTPUT Config using REGISTERS und STM32 GPIO INPUT Configuration
Mit diesen Erkenntnissen ein wenig HardCore-Code:

void setup(){   // Einmalige Ausführung => Initialisierungen...
    Serial.begin(115200);
    pinMode(PC0, OUTPUT);  // ohne diese Zeile klappts nicht
    GPIOC->MODER = 0x5555; // PC0..PC7 als Ausgang
    GPIOC->ODR = 0xff;     // PC0..PC7 einschalten
    Serial.printf("GPIOC->MODER: %4x\n",GPIOC->MODER);
    pinMode(PA1, INPUT_PULLDOWN); // PA1 als Eingang mit Pulldown
    Serial.printf("GPIOA->MODER: %4x\n",GPIOA->MODER); // PinMode
    Serial.printf("GPIOA->PUPDR: %4x\n",GPIOA->PUPDR); // PullUpMode
}

void loop(){
    digitalWrite(PC0, HIGH); // PC0 <-1
    digitalWrite(PC1, LOW);  // PC1 <-0
    delay(200);
  // ohne Arduino Watte
    GPIOC->ODR &=~1;         // PC0 <-0
    GPIOC->ODR |=2;          // PC1 <-1
    delay(200);
    if(GPIOA->IDR & 0b10){   // wenn PA1
      GPIOC->ODR |= (1<<2);  // setzte PC2
    }
    else{                    // sonst
      GPIOC->ODR &= ~(1<<2); // lösche PC2
    }
  // mit Arduino Watte
    digitalWrite(PC3,digitalRead(PA1)); // PC3 <- PA1
}

Ohne Umverpackung direkt auf der Hardware des Chips agieren geht auch mit Arduino in diesem Beispiel.
Einmal muss pinMode() aufgerufen werden sonst funktioniert GPIOC->MODER nicht.
Ergänzender Link: Introduction to GPIO