diff --git a/.cmake/avr-gcc.cmake b/.cmake/avr-gcc.cmake new file mode 100644 index 0000000..aacfd9e --- /dev/null +++ b/.cmake/avr-gcc.cmake @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3471dc0 --- /dev/null +++ b/CMakeLists.txt @@ -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 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 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..." +) diff --git a/README-DE.md b/README-DE.md new file mode 100644 index 0000000..572dffb --- /dev/null +++ b/README-DE.md @@ -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 ``) auf den Chip. + +*Hinweis: Da wir das moderne ELF-Format nutzen, entfällt das manuelle Generieren von alten `.hex`-Dateien vollständig.* diff --git a/README.md b/README.md index 426ab6a..3a12435 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,56 @@ -# AVRDxBlink +# Emacs AVR IDE Template -Template to start devloping for avr8 with emacs \ No newline at end of file +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 ``) to the chip. + +*Note: Since we use the modern ELF format, manually generating old `.hex` files is completely obsolete.* diff --git a/init-example.el b/init-example.el new file mode 100644 index 0000000..73b9b91 --- /dev/null +++ b/init-example.el @@ -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 "") 'my-avr-clean-build) +(global-set-key (kbd "") 'my-avr-flash-code) +(global-set-key (kbd "") 'my-avr-flash-eeprom) +(global-set-key (kbd "") 'my-avr-read-fuses) +(global-set-key (kbd "") 'my-avr-flash-fuses) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e29a237 --- /dev/null +++ b/src/main.c @@ -0,0 +1,35 @@ +#ifndef F_CPU +#define F_CPU 16000000UL // Set to 16 MHz +#endif + +#include +#include +#include +#include + +/* + * 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); + } +}