Inital code commit

This commit is contained in:
2026-06-16 20:13:26 +02:00
parent ca3890507d
commit 04b627768d
6 changed files with 433 additions and 2 deletions
+17
View File
@@ -0,0 +1,17 @@
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR avr)
find_program(AVR_CC avr-gcc)
find_program(AVR_CXX avr-g++)
find_program(AVR_OBJCOPY avr-objcopy)
find_program(AVR_SIZE_TOOL avr-size)
find_program(AVR_OBJDUMP avr-objdump)
find_program(AVR_STRIP avr-strip)
set(CMAKE_C_COMPILER ${AVR_CC})
set(CMAKE_CXX_COMPILER ${AVR_CXX})
# Umgehen der Standard-Compiler-Checks von CMake, die bei Cross-Compilation oft fehlschlagen
set(CMAKE_C_COMPILER_WORKS 1)
set(CMAKE_CXX_COMPILER_WORKS 1)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+90
View File
@@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.10)
# Set the toolchain file BEFORE the project() call
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/.cmake/avr-gcc.cmake)
project(AVRDxBlink C)
# Configurable variables
set(MCU "avr128db28" CACHE STRING "Target Microcontroller")
set(F_CPU "20000000" CACHE STRING "Clock frequency in Hz")
set(DEVICE_PACK_DIR "/opt/toolchains/microchip/device-packs/AVRDx" CACHE STRING "Path to Device Packs")
set(PROGRAMMER "pickit4_updi" CACHE STRING "Programmer for avrdude") # often pickit4_updi is the right name for UPDI
# Include Device Pack
# -B instructs gcc to look for device-specific binaries/specs in this folder
# -I adds the device-specific headers
set(AVR_PACK_FLAGS "-B${DEVICE_PACK_DIR}/gcc/dev/${MCU} -I${DEVICE_PACK_DIR}/include")
# Clangd (and therefore eglot/lsp) often does not know about the AVR Device Pack.
# We define the corresponding macro manually so <avr/io.h> works.
string(TOUPPER "${MCU}" MCU_UPPER)
set(AVR_MACRO "-D__AVR_${MCU_UPPER}__ -D__AVR_DEVICE_NAME__=${MCU}")
# If the MCU is a modern AVR (Dx/Ex) or XMEGA, avr-gcc defines __AVR_XMEGA__ internally.
# Clangd needs this so <avr/fuse.h> uses NVM_FUSES_t instead of the old __fuse_t.
if(MCU MATCHES "^avr[0-9]+" OR MCU MATCHES "^atxmega")
set(AVR_MACRO "${AVR_MACRO} -D__AVR_XMEGA__")
endif()
# Set Build Type (Default: Release)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type: Debug or Release" FORCE)
endif()
# General Compiler Flags (for all build types)
# -ffunction-sections and -fdata-sections allow the linker to remove unused code
set(COMMON_FLAGS "-mmcu=${MCU} ${AVR_MACRO} -DF_CPU=${F_CPU}UL -Wall -Wstrict-prototypes -std=gnu99 ${AVR_PACK_FLAGS} -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS "${COMMON_FLAGS}")
# Specific flags for Debug and Release
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3 -DDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG")
# Linker Flags: -Wl,--gc-sections removes everything that is not needed
set(CMAKE_EXE_LINKER_FLAGS "-mmcu=${MCU} ${AVR_PACK_FLAGS} -Wl,--gc-sections")
# Generate compile_commands.json for Emacs/clangd (code completion)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Source and Header files
file(GLOB_RECURSE SRC_FILES src/*.c)
list(FILTER SRC_FILES EXCLUDE REGEX "/[.]#") # Ignore Emacs lock files like .#main.c
include_directories(inc)
# Generate Executable (.elf)
add_executable(${PROJECT_NAME}.elf ${SRC_FILES})
# Display size after build (Hex file is obsolete thanks to ELF support)
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
COMMAND avr-size --format=avr --mcu=${MCU} ${PROJECT_NAME}.elf
)
# --- Avrdude Programming Targets ---
# F6: Program Flash only
add_custom_target(flash
COMMAND avrdude -c ${PROGRAMMER} -p ${MCU} -U flash:w:${PROJECT_NAME}.elf:e
DEPENDS ${PROJECT_NAME}.elf
COMMENT "Flashing program code (Flash)..."
)
# C-F6: Program Flash and EEPROM
add_custom_target(flash_eeprom
COMMAND avrdude -c ${PROGRAMMER} -p ${MCU} -U flash:w:${PROJECT_NAME}.elf:e -U eeprom:w:${PROJECT_NAME}.elf:e
DEPENDS ${PROJECT_NAME}.elf
COMMENT "Flashing program code and EEPROM..."
)
# F7: Read Fuses
add_custom_target(read_fuses
COMMAND avrdude -c ${PROGRAMMER} -p ${MCU} -U fuses:r:-:h
COMMENT "Reading fuses..."
)
# C-F7: Program Fuses only
add_custom_target(flash_fuses
COMMAND avrdude -c ${PROGRAMMER} -p ${MCU} -U fuses:w:${PROJECT_NAME}.elf:e
DEPENDS ${PROJECT_NAME}.elf
COMMENT "Programming fuses from ELF file..."
)
+56
View File
@@ -0,0 +1,56 @@
# Emacs AVR IDE Template
Dieses Repository ist ein vollständiges Template, um **Emacs** als leichtgewichtige, aber extrem mächtige IDE für die Entwicklung von **AVR Mikrocontrollern** (speziell moderne AVR Dx/Ex Serien, aber auch voll abwärtskompatibel zu älteren Serien) zu nutzen.
Es verwendet **CMake** als Build-System und verlässt sich auf die Kombination von `avr-gcc`, `avrdude` (ELF-Support) und `clangd` (Language Server), um Code-Vervollständigung, schnelles Kompilieren und direktes Flashen aus dem Editor heraus zu ermöglichen.
## Voraussetzungen auf Betriebssystemebene
* `avr-gcc` (AVR Toolchain Compiler)
* `avrdude` (Version 7.0 oder höher zwingend empfohlen für nativen ELF-Support)
* `clangd` (Für Code-Vervollständigung, Warnungen und Fehleranzeige in Emacs)
* `cmake` (Build-System)
* `ripgrep` (Wird für die extrem schnelle Suche in Emacs verwendet)
* Device Packs für moderne AVRs: [Microchip Packs Repository](http://packs.download.microchip.com/)
## Emacs Packages
Damit das IDE-Feeling perfekt wird, greift dieses Template auf einige spezifische Emacs-Packages zurück, die sich bewährt haben:
* **Projectile**: Zur Projektverwaltung (findet den Root-Ordner automatisch anhand der `CMakeLists.txt`).
* **Eglot**: Als integrierter C/C++ Language Server Client (kommuniziert im Hintergrund mit `clangd`).
* **Corfu**: Für das moderne Autovervollständigungs-Popup direkt am Cursor.
* **Vertico, Orderless & Consult**: Für eine smarte, fehlertolerante Suche über das gesamte Projekt (inklusive Ripgrep-Anbindung).
* **Doom Themes**: Für einen augenschonenden, modernen Dark Mode.
## Installation der Emacs-Konfiguration
Wenn du Emacs von Grund auf neu einrichtest, kannst du die beiliegende Beispieldatei verwenden:
1. Kopiere die Datei `init-example.el` in dein Emacs-Konfigurationsverzeichnis (meist `~/.emacs.d/` oder `~/.config/emacs/`).
2. Benenne sie in `init.el` um.
```bash
cp init-example.el ~/.emacs.d/init.el
```
3. Starte Emacs neu. Beim ersten Start werden alle fehlenden Pakete automatisch von MELPA heruntergeladen und installiert.
## Mikrocontroller (MCU) wechseln
Dieses Projekt ist standardmäßig für den **AVR128DB28** konfiguriert. Wenn du einen anderen Chip verwenden möchtest:
1. Öffne die Datei `CMakeLists.txt`.
2. Ändere den Wert der Variable `MCU` (z.B. auf `atmega328p` oder `avr128da28`).
3. Ändere bei Bedarf das `DEVICE_PACK_DIR`. (Für moderne AVR Dx/EA Serien wird das Device Pack von Microchip benötigt. Für ältere Modelle wie den ATmega kannst du diesen Pfad oft leer lassen).
4. Drücke **F5** in Emacs, um das Projekt frisch zu konfigurieren und zu bauen.
*(CMake erzeugt die Datei `compile_commands.json` dabei neu, wodurch `clangd` sofort die Register und Pins des neuen Chips in der Autovervollständigung kennt!)*
## Entwicklungsworkflow & Shortcuts
Sobald du eine `.c` oder `.h` Datei im Projekt öffnest, erkennt Projectile das Projekt automatisch und Eglot startet im Hintergrund den Language Server.
Die wichtigsten Tastenkürzel für die **Projektverwaltung** (via Projectile & Consult):
* `C-c p f`: Datei im Projekt finden (Fuzzy Search).
* `C-r`: Projektweit nach Text suchen (Consult Ripgrep - extrem schnell!).
* `C-c p p`: Zwischen verschiedenen, lokal gespeicherten Projekten wechseln.
Die Tastenkürzel zum **Bauen und Flashen** (eingestellt über F-Tasten in der `init.el`):
* **`F5`**: **Clean Build**. Löscht den Cache radikal und baut das Projekt komplett neu (Kompiliert inkl. Linker Garbage Collection für minimale Größe).
* **`F6`**: **Flash Code**. Flasht nur den Programmcode (Flash-Speicher) via Avrdude. *(Standardbefehl während der Entwicklung)*
* **`Strg + F6`**: **Flash Code & EEPROM**. Flasht den Code und die EEPROM-Daten.
* **`F7`**: **Read Fuses**. Liest die Fuses vom Mikrocontroller und zeigt sie im Emacs Compile-Fenster an.
* **`Strg + F7`**: **Flash Fuses**. Schreibt die direkt in der C-Software definierten Fuses (via `<avr/fuse.h>`) auf den Chip.
*Hinweis: Da wir das moderne ELF-Format nutzen, entfällt das manuelle Generieren von alten `.hex`-Dateien vollständig.*
+55 -2
View File
@@ -1,3 +1,56 @@
# AVRDxBlink
# Emacs AVR IDE Template
Template to start devloping for avr8 with emacs
This repository is a complete template to use **Emacs** as a lightweight, yet extremely powerful IDE for developing **AVR microcontrollers** (specifically modern AVR Dx/Ex series, but also fully backwards compatible with older series).
It uses **CMake** as the build system and relies on the combination of `avr-gcc`, `avrdude` (with ELF support), and `clangd` (Language Server) to enable code completion, fast compilation, and direct flashing from within the editor.
## System Prerequisites
* `avr-gcc` (AVR Toolchain Compiler)
* `avrdude` (Version 7.0 or higher highly recommended for native ELF support)
* `clangd` (For code completion, warnings, and error display in Emacs)
* `cmake` (Build System)
* `ripgrep` (Used for extremely fast searching in Emacs)
* Device Packs for modern AVRs: [Microchip Packs Repository](http://packs.download.microchip.com/)
## Emacs Packages
To achieve the perfect IDE feel, this template relies on several proven Emacs packages:
* **Projectile**: For project management (automatically finds the root folder based on `CMakeLists.txt`).
* **Eglot**: As an integrated C/C++ Language Server Client (communicates with `clangd` in the background).
* **Corfu**: For the modern auto-completion popup directly at the cursor.
* **Vertico, Orderless & Consult**: For smart, fault-tolerant searching across the entire project (including Ripgrep integration).
* **Doom Themes**: For an eye-friendly, modern dark mode.
## Emacs Configuration Installation
If you are setting up Emacs from scratch, you can use the provided example file:
1. Copy the file `init-example.el` to your Emacs configuration directory (usually `~/.emacs.d/` or `~/.config/emacs/`).
2. Rename it to `init.el`.
```bash
cp init-example.el ~/.emacs.d/init.el
```
3. Restart Emacs. On the first launch, all missing packages will automatically be downloaded and installed from MELPA.
## Changing the Microcontroller (MCU)
This project is configured for the **AVR128DB28** by default. If you want to use a different chip:
1. Open the file `CMakeLists.txt`.
2. Change the value of the `MCU` variable (e.g., to `atmega328p` or `avr128da28`).
3. If necessary, change the `DEVICE_PACK_DIR`. (For modern AVR Dx/EA series, the Device Pack from Microchip is required. For older models like the ATmega, you can often leave this path empty).
4. Press **F5** in Emacs to do a fresh configure and build.
*(CMake will regenerate the `compile_commands.json` file, allowing `clangd` to immediately know the registers and pins of the new chip for auto-completion!)*
## Development Workflow & Shortcuts
As soon as you open a `.c` or `.h` file in the project, Projectile will automatically detect the project, and Eglot will start the Language Server in the background.
The most important shortcuts for **project management** (via Projectile & Consult):
* `C-c p f`: Find file in project (Fuzzy Search).
* `C-r`: Search for text across the project (Consult Ripgrep - extremely fast!).
* `C-c p p`: Switch between different, locally stored projects.
The shortcuts for **building and flashing** (configured via F-keys in `init.el`):
* **`F5`**: **Clean Build**. Radically deletes the cache and completely rebuilds the project (Compiles including linker garbage collection for minimal size).
* **`F6`**: **Flash Code**. Flashes only the program code (Flash memory) via Avrdude. *(Standard command during development)*
* **`Strg + F6`**: **Flash Code & EEPROM**. Flashes the code and the EEPROM data.
* **`F7`**: **Read Fuses**. Reads the fuses from the microcontroller and displays them in the Emacs Compile window.
* **`Strg + F7`**: **Flash Fuses**. Writes the fuses directly defined in the C software (via `<avr/fuse.h>`) to the chip.
*Note: Since we use the modern ELF format, manually generating old `.hex` files is completely obsolete.*
+180
View File
@@ -0,0 +1,180 @@
;; ==================================================
;; AVR Emacs IDE - Minimal Example init.el
;; ==================================================
;; --- 1. Basic Setup & Package Manager ---
(setq inhibit-startup-message t)
(require 'package)
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;; Install use-package if not present
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)
;; Mache die Menüleiste, Werkzeugleiste und alte Scroll-Leiste unsichtbar
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
;; Erhöhe die Standard-Fensterbreite auf 120 Spalten, damit durch die Minimap (20 Spalten)
;; immer noch genug Platz (100 Spalten) für den Code bleibt und dieser nicht umbricht.
(add-to-list 'default-frame-alist '(width . 100))
(add-to-list 'initial-frame-alist '(width . 100))
;; Unterdrücke nervige Warnungen (z.B. beim Kompilieren von heruntergeladenen Paketen)
(setq warning-minimum-level :error)
(setq native-comp-async-report-warnings-errors 'silent)
;; Aktiviere Zeilennummern links
(global-display-line-numbers-mode 1)
;; Sublime Text ähnliche Minimap (Vorschaubild) auf der rechten Seite
(use-package minimap
:init
(setq minimap-window-location 'right)
(setq minimap-update-delay 0.2)
(setq minimap-width-fraction 0.01) ; 1% (wird durch Minimum überschrieben)
(setq minimap-minimum-width 20) ; Erzwingt exakt feste 20 Spalten!
:config
;; Verhindert, dass das Minimap-Fenster beim Maximieren (Vollbild) des Emacs-Fensters mitwächst
(advice-add 'minimap-new-minimap :after
(lambda (&rest _)
(when-let ((win (minimap-get-window)))
(window-preserve-size win t t))))
(minimap-mode 1))
;; Deaktiviere die Erstellung von temporären #Dateien#, .#Lockfiles und Datei~ Backups
(setq make-backup-files nil)
(setq auto-save-default nil) ; Deaktiviert die lästigen #Dateien#
(setq create-lockfiles nil)
;; AKTIVIERE stattdessen modernes "Auto-Save" (speichert direkt in die Originaldatei)
(auto-save-visited-mode 1)
(setq auto-save-visited-interval 2) ; Speichert automatisch nach 2 Sekunden Inaktivität
;; --- 2. Theme (Doom Dark Theme) ---
(use-package doom-themes
:config
(load-theme 'doom-one t))
;; --- 3. Projectile (Projektverwaltung) ---
(use-package projectile
:demand t
:config (projectile-mode +1)
:bind-keymap ("C-c p" . projectile-command-map))
;; --- 4. Autocompletion (Corfu & Eglot für clangd) ---
(use-package corfu
:custom
(corfu-cycle t)
(corfu-auto t)
:init
(global-corfu-mode))
(use-package eglot
:hook ((c-mode . eglot-ensure)
(c++-mode . eglot-ensure)
(c-ts-mode . eglot-ensure)
(c++-ts-mode . eglot-ensure))
:config
;; Clangd-spezifische Parameter für C/C++
(add-to-list 'eglot-server-programs
'(c-mode . ("clangd" "-j=8" "--background-index" "--clang-tidy")))
(add-to-list 'eglot-server-programs
'(c-ts-mode . ("clangd" "-j=8" "--background-index" "--clang-tidy"))))
;; Modernes Hover-Popup (wie in Eclipse/VS Code) für Dokumentation und Signaturen
(use-package eldoc-box
:hook (eglot-managed-mode . eldoc-box-hover-at-point-mode))
;; --- 5. CMake Syntax Highlighting ---
(use-package cmake-mode
:mode ("CMakeLists\\.txt\\'" "\\.cmake\\'"))
;; --- 5. Suche & Ripgrep (Vertico, Orderless & Consult) ---
(use-package vertico
:init (vertico-mode))
(use-package orderless
:custom
(completion-styles '(orderless basic)))
(use-package consult
:bind (("C-s" . consult-line)
("C-r" . consult-ripgrep)))
;; --- 6. Compilation Window Tweaks ---
;; Öffne das Compile-Fenster immer unten (nicht rechts) und mache es 30% hoch
(add-to-list 'display-buffer-alist
'("\\*compilation\\*"
(display-buffer-reuse-window display-buffer-at-bottom)
(window-height . 0.3)))
;; Aktiviere ANSI-Farben im Compile-Fenster (für CMake-Farben)
(require 'ansi-color)
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
;; Automatisch nach unten scrollen, um Fehler oder die finale Dateigröße sofort zu sehen
(setq compilation-scroll-output t)
;; --- 7. Modernes Syntax-Highlighting (Tree-Sitter) ---
(use-package treesit-auto
:custom
(treesit-auto-install t) ; Lade fehlende Grammatiken vollautomatisch herunter
:config
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode)
;; Workaround für c-ts-mode: Benötigt intern ZWINGEND auch die cpp-Grammatik!
;; Wir prüfen beim Start, ob C, C++ oder CMake fehlen und installieren sie stumm nach.
(setq treesit-language-source-alist
'((c "https://github.com/tree-sitter/tree-sitter-c")
(cpp "https://github.com/tree-sitter/tree-sitter-cpp")
(cmake "https://github.com/uyha/tree-sitter-cmake")))
(dolist (lang '(c cpp cmake))
(unless (treesit-language-available-p lang)
(treesit-install-language-grammar lang))))
;; --- 8. AVR Build & Flash Shortcuts ---
(defun my-avr-clean-build ()
"Baut das aktuelle CMake-Projekt komplett neu ohne Rückfrage."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "cmake --fresh -B build && cmake --build build")))
(defun my-avr-flash-code ()
"Flasht nur den Programmcode (Flash)."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "cmake --build build --target flash")))
(defun my-avr-flash-eeprom ()
"Flasht Programmcode und EEPROM."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "cmake --build build --target flash_eeprom")))
(defun my-avr-read-fuses ()
"Liest die Fuses via Avrdude aus."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "cmake --build build --target read_fuses")))
(defun my-avr-flash-fuses ()
"Programmiert die Fuses aus der ELF-Datei."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "cmake --build build --target flash_fuses")))
;; Tastenbelegungen (F-Tasten)
(global-set-key (kbd "<f5>") 'my-avr-clean-build)
(global-set-key (kbd "<f6>") 'my-avr-flash-code)
(global-set-key (kbd "<C-f6>") 'my-avr-flash-eeprom)
(global-set-key (kbd "<f7>") 'my-avr-read-fuses)
(global-set-key (kbd "<C-f7>") 'my-avr-flash-fuses)
+35
View File
@@ -0,0 +1,35 @@
#ifndef F_CPU
#define F_CPU 16000000UL // Set to 16 MHz
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/fuse.h>
#include <stdbool.h>
/*
* Fuses Configuration
*/
FUSES = {
.WDTCFG = 0x00, // Watchdog Timer: deactivated
.BODCFG = 0x10, // Brown-out Detector: factory default
.OSCCFG = 0x78, // Oscillator: Internal OSCHF (starting with 4 MHz)
.SYSCFG0 = 0xF6, // System Config 0: UPDI activated
.SYSCFG1 = 0xE8 // System Config 1: Standard Start-up Time
};
#define LED_PIN 7
int main(void) {
// 1. System clock to 20MHz
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_16M_gc);
// LED Pin as output
PORTA.DIRSET = (1 << LED_PIN);
// main loop
while (true) {
PORTA.OUTTGL = (1 << LED_PIN);
_delay_ms(750);
}
}