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 schalten
}

void loop(){
    digitalWrite(BOARD_LED, HIGH);// High ausgeben
    delay(200);                   // warte 200ms
    digitalWrite(BOARD_LED, LOW); // Low ausgeben
    delay(200);                   // warte 200ms
}

Erläuterungen
Die grüne LED auf dem Board ist an D13 angeschlossen, damit im Quelltext statt D13 das aussagekräftigere Board_LED verwendet werden kann lässt man mit #define Board_LED D13 den Präprozessor (Textverarbeitung vor dem Compiler) alle Vorkommen des Textes Board_LED durch den Text D13 ersetzen.
Im setup() werden alle Initialisierungen beim Programmstart oder nach einem Reset durchgeführt.
Bevor ein Pin als Ausgang verwendet werden kann muss er als Ausgang definiert werden: pinMode(Board_LED, OUTPUT) stellt die Hardware so ein, dass D13 als Ausgang funktioniert.
Die loop()-Funktion wird endlos ständig wiederholt.

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

Der µC hat viel mehr Pins als bei den Arduino-Anschlüssen verwendet werden, dazu müssen die Bezeichnungen des Chips verwendet werden.

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

void loop(){
    digitalWrite(PC2,digitalRead(PA1)); // PA1 einlesen und auf PC2 ausgeben
    digitalWrite(PC0, HIGH);  // PC0 <- 1
    delay(300);               // warte 300ms
    digitalWrite(PC0, LOW);   // PC0 <- 0
    digitalWrite(PC1, HIGH);  // PC1 <- 1
    delay(300);               // warte 300ms
    digitalWrite(PC1, LOW);   // PC1 <- 0
}

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);
    RCC->AHBENR |= (1<<2);  // Enable the GPIOC clock
    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