Source file: /~heha/hsn/bl/blink4.zip/main.cpp

// Lässt eine LED an PC13 blitzen.
// Nicht für BluePill (2× 20 Pins) sondern für ein kleineres Board mit 2× 17-poligen Pfosten
// 210916 heha

// CMSIS-„Bibliothek“: Registerdefinitionen.
// Wie alle Bibliotheken für 16- und 32-Bit-Mikrocontroller ist diese
// unglücklich gestrickt, was den Zugriff auf gleichartige Peripherie angeht:
// Statt GPIOA->reg, GPIOB->reg usw. wäre besser:
//	GPIOA.reg, GPIOB.reg … sowie GPIO[x].reg mit x von 0 ab.
// Sowie enum statt #define. Außerdem mehr C++.
// Bissel kleiner und mit hierarchischer Abhängigkeit statt aus einem Kodegenerator
// wäre ebenfalls nett.
#include <stm32f401xc.h>
// Siehe: http://www.tu-chemnitz.de/~heha/hs/bl/cmsis4.zip

// Berechnet zur Compilezeit die Bitadresse für das Register und das Bit
// Funktioniert dank Adresszerlegung sowohl für RAM als auch für Register
// (Eine constexpr-Funktion wird vom Compiler leider nicht immer inline
// platziert und ergibt dann größeren Kode.)
// WICHTIG: Die Adresse muss zur Compilezeit bekannt sein,
// sonst entsteht aufgeblähter Kode!
#define BB_BIT(a,b) (*(uint32_t*)(((uint32_t)&(a)&0xFF00'0000)+0x0200'0000+((uint32_t)&(a)&0x00FFF'FFFF)*32+(b)*4))

namespace bb{	// Bit-Banding = atomarer Bitzugriff, für RAM und Register

inline void set(volatile uint32_t&a, unsigned b, bool v=true) {
  BB_BIT(a,b) = v;
}
inline void clr(volatile uint32_t&a, unsigned b) {
  set(a,b,false);
}
inline bool test(const volatile uint32_t&a, unsigned b) {
  return (bool)BB_BIT(a,b);
}
}

// Eine einfache Warteschleife, die hier „geinlined“ wird
static void delay(uint32_t timeout) {
 do __NOP(); while(--timeout);
}

// Hier geht's los.
// Achtung! Statische Variablen sind weder initialisiert (.data) noch nullgesetzt (.bss)!!
// Statische Konstruktoren wurden nicht aufgerufen.
// Das macht normalerweise der Startupkode vor main().
void onReset() {
// Damit die Leuchtdiode an PC13 überhaupt angesprochen werden kann,
// muss der Takt für die Port-Peripherie aktiviert werden.
 bb::set(RCC->APB1ENR,RCC_AHB1ENR_GPIOCEN_Pos);	// PortC takten
// Dann erst lässt sich der Port als Ausgang festlegen.
 bb::set(GPIOC->MODER,GPIO_MODER_MODE13_Pos);	// Output-Modus PC13
 for(;;) {
  bb::clr(GPIOC->ODR,13);	// Löschen = LED ein
  delay(0x0001'0000);
  bb::set(GPIOC->ODR,13);	// Setzen = LED aus
  delay(0x0007'0000);
 }
}

typedef void(*handler_t)();

// Um ohne Laufzeitbibliothek auszukommen
// wird die Interrupttabelle hier definiert (2 Einträge sind nötig)
// und vom Linker an die Anfangsadresse (hinter dem Urlader) platziert.
handler_t vectors[] __attribute__((section(".vectors"))) = {
 (handler_t) (SRAM1_BASE + 1024),	// Startwert des Stapelzeigers
 onReset,	// Einsprungadresse bei RESET, hier: vom Urlader ausgewertet
};
Detected encoding: UTF-80