Initial commit

This commit is contained in:
2026-03-29 14:47:13 +02:00
commit b49984b9c0
32 changed files with 2394 additions and 0 deletions
@@ -0,0 +1,100 @@
/* Linker script for ATSAMD21G17D with 8KB bootloader (flash starts at 0x2000) */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
MEMORY
{
rom (rx) : ORIGIN = 0x00002000, LENGTH = 0x0001E000 /* 120K (128K - 8K bootloader) */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00004000 /* 16K */
}
__StackTop = ORIGIN(ram) + LENGTH(ram);
__StackLimit = __StackTop - 0x1000;
SECTIONS
{
.text :
{
__text_start__ = .;
. = ALIGN(4);
KEEP(*(.isr_vector))
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
KEEP(*(.init))
__preinit_array_start = .;
KEEP(*(.preinit_array))
__preinit_array_end = .;
__init_array_start = .;
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
__init_array_end = .;
KEEP(*crtbegin.o(.ctors))
KEEP(*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP(*(SORT(.ctors.*)))
KEEP(*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
__fini_array_start = .;
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP(*crtbegin.o(.dtors))
KEEP(*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP(*(SORT(.dtors.*)))
KEEP(*crtend.o(.dtors))
. = ALIGN(4);
} > rom
PROVIDE_HIDDEN(__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN(__exidx_end = .);
. = ALIGN(4);
__etext = .;
_etext = .;
.data : AT(__etext)
{
. = ALIGN(4);
__data_start__ = .;
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
__data_end__ = .;
_erelocate = .;
} > ram
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
_sbss = .;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
_ebss = .;
_ezero = .;
} > ram
. = ALIGN(4);
end = .;
_end = .;
}
@@ -0,0 +1,108 @@
/* Linker script for ATSAMD21G17D no bootloader (flash starts at 0x00000000)
*
* Symbol names match Arduino SAMD core 1.8.14 (cortex_handlers.c / Reset.cpp):
* __StackTop, __data_start__, __data_end__, __etext,
* __bss_start__, __bss_end__, __text_start__, end
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x0001FE00 /* 127.5K Firmware */
config (rx) : ORIGIN = 0x0001FE00, LENGTH = 0x00000200 /* 512B NVM Config (2 Rows) */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00004000 /* 16K */
}
/* Initial stack pointer = top of RAM */
__StackTop = ORIGIN(ram) + LENGTH(ram); /* 0x20004000 */
__StackLimit = __StackTop - 0x1000; /* 4 KB minimum stack */
SECTIONS
{
.text :
{
__text_start__ = .;
. = ALIGN(4);
KEEP(*(.isr_vector))
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
KEEP(*(.init))
__preinit_array_start = .;
KEEP(*(.preinit_array))
__preinit_array_end = .;
__init_array_start = .;
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
__init_array_end = .;
KEEP(*crtbegin.o(.ctors))
KEEP(*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP(*(SORT(.ctors.*)))
KEEP(*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
__fini_array_start = .;
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP(*crtbegin.o(.dtors))
KEEP(*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP(*(SORT(.dtors.*)))
KEEP(*crtend.o(.dtors))
. = ALIGN(4);
} > rom
PROVIDE_HIDDEN(__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN(__exidx_end = .);
. = ALIGN(4);
__etext = .; /* LMA of .data where initialized data lives in flash */
_etext = .; /* legacy alias */
.data : AT(__etext)
{
. = ALIGN(4);
__data_start__ = .;
_srelocate = .; /* legacy alias */
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
__data_end__ = .;
_erelocate = .; /* legacy alias */
} > ram
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
_sbss = .; /* legacy alias */
_szero = .; /* legacy alias */
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
_ebss = .; /* legacy alias */
_ezero = .; /* legacy alias */
} > ram
/* Heap starts here (used by sbrk / malloc) */
. = ALIGN(4);
end = .;
_end = .;
}
+100
View File
@@ -0,0 +1,100 @@
// VersaPad v2 SAMD21G18A Custom Variant
// Pin descriptions and peripheral object definitions
#include "variant.h"
#include "Arduino.h"
// ─── g_APinDescription ────────────────────────────────────────────────────────
// Maps Arduino pin D0D25 to SAMD21 port/pin pairs.
//
// Format:
// { PORT, PIN, PinType, PinAttr, ADC_Channel, PWM_Channel, TC_Channel, ExtInt }
//
// ─────────────────────────────────────────────────────────────────────────────
const PinDescription g_APinDescription[] = {
// ── Button Matrix: Columns (D0D4) ────────────────────────────────────────
// Driven LOW one at a time during scanning; idle = INPUT_PULLUP or OUTPUT HIGH
// D0 PA08 COL_4
{ PORTA, 8, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI },
// D1 PA09 COL_3
{ PORTA, 9, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9 },
// D2 PA10 COL_2
{ PORTA, 10, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 },
// D3 PA11 COL_1
{ PORTA, 11, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 },
// D4 PB10 COL_0 (also: encoder SW column)
{ PORTB, 10, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 },
// ── Button Matrix: Rows (D5D9) ───────────────────────────────────────────
// Read as INPUT_PULLUP; go LOW when a button in the active column is pressed
// D5 PB11 ROW_0
{ PORTB, 11, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 },
// D6 PA12 ROW_1
{ PORTA, 12, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 },
// D7 PA13 ROW_2
{ PORTA, 13, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_13 },
// D8 PA14 ROW_3
{ PORTA, 14, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14 },
// D9 PA15 ROW_4
{ PORTA, 15, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 },
// ── Rotary Encoders (D10D17) ─────────────────────────────────────────────
// All wired to EIC (External Interrupt Controller) via PMUX A.
// Quadrature decoding done in ISRs.
// D10 PA16 ENC3_A EIC EXTINT[0]
{ PORTA, 16, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0 },
// D11 PA17 ENC3_B EIC EXTINT[1]
{ PORTA, 17, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1 },
// D12 PA18 ENC2_A EIC EXTINT[2]
{ PORTA, 18, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 },
// D13 PA19 ENC2_B EIC EXTINT[3]
{ PORTA, 19, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3 },
// D14 PA20 ENC1_A EIC EXTINT[4]
{ PORTA, 20, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4 },
// D15 PA21 ENC1_B EIC EXTINT[5]
{ PORTA, 21, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 },
// D16 PA22 ENC0_A EIC EXTINT[6]
{ PORTA, 22, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6 },
// D17 PA23 ENC0_B EIC EXTINT[7]
{ PORTA, 23, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_7 },
// ── WS2812 SPI SERCOM5 (D18D20) ───────────────────────────────────────
// PB22/PB23 use peripheral function D → PIO_SERCOM_ALT
// PB03 uses peripheral function D → PIO_SERCOM_ALT
// D18 PB22 SPI MOSI / WS2812 data (SERCOM5 PAD[2])
{ PORTB, 22, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// D19 PB23 SPI SCK (SERCOM5 PAD[3])
{ PORTB, 23, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// D20 PB03 SPI MISO (unused) (SERCOM5 PAD[1])
{ PORTB, 3, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// ── USB D / D+ (D21–D22) ────────────────────────────────────────────────
// D21 PA24 USB D
{ PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// D22 PA25 USB D+
{ PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// ── Faders / ADC (D23D25 = A0–A2) ──────────────────────────────────────
// D23/A0 PA02 FADER_0 ADC AIN[0]
{ PORTA, 2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// D24/A1 PA03 FADER_1 ADC AIN[1] (also VREFA do not use as digital)
{ PORTA, 3, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel1, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
// D25/A2 PB08 FADER_2 ADC AIN[2]
{ PORTB, 8, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI },
};
extern "C" {
unsigned int PINCOUNT_fn() { return PINS_COUNT; }
}
// ─── USB ──────────────────────────────────────────────────────────────────────
void initVariant() {
// Nothing board-specific needed at startup.
// USB is handled by the Arduino SAMD core.
}
+98
View File
@@ -0,0 +1,98 @@
#pragma once
// VersaPad v2 SAMD21G18A Custom Variant
// Arduino pin assignments for the custom PCB
#define ARDUINO_SAMD_VARIANT_COMPLIANCE 10610
#include <WVariant.h>
// ─── Pin count ────────────────────────────────────────────────────────────────
// D0D9 : Button matrix (COL_04, ROW_04)
// D10D17 : Rotary encoders A/B (ENC0ENC3), all on EIC
// D18D20 : SPI for WS2812 (SERCOM5: MOSI, SCK, MISO)
// D21D22 : USB D/D+ (internal, not exposed)
// D23D25 : Fader ADC inputs (A0A2)
// ─────────────────────────────────────────────────────────────────────────────
#define PINS_COUNT (26u)
#define NUM_DIGITAL_PINS (23u) // D0D22 usable as digital
#define NUM_ANALOG_INPUTS (3u) // A0A2 = D23D25
#define NUM_ANALOG_OUTPUTS (0u)
#define analogInputToDigitalPin(p) ((p < NUM_ANALOG_INPUTS) ? (p) + 23u : -1)
// digitalPinToInterrupt is defined by Arduino.h as (P).
// attachInterrupt() then internally looks up ulExtInt via g_APinDescription.
// ─── Button Matrix ────────────────────────────────────────────────────────────
// Columns (driven LOW one at a time)
#define PIN_COL0 (4u) // PB10 also encoder SW column
#define PIN_COL1 (3u) // PA11
#define PIN_COL2 (2u) // PA10
#define PIN_COL3 (1u) // PA09
#define PIN_COL4 (0u) // PA08
// Rows (read with internal pull-up)
#define PIN_ROW0 (5u) // PB11
#define PIN_ROW1 (6u) // PA12
#define PIN_ROW2 (7u) // PA13
#define PIN_ROW3 (8u) // PA14
#define PIN_ROW4 (9u) // PA15
// ─── Rotary Encoders ──────────────────────────────────────────────────────────
// All on EIC (External Interrupt Controller) for hardware quadrature
#define PIN_ENC0_A (16u) // PA22 EIC EXTINT6
#define PIN_ENC0_B (17u) // PA23 EIC EXTINT7
#define PIN_ENC1_A (14u) // PA20 EIC EXTINT4
#define PIN_ENC1_B (15u) // PA21 EIC EXTINT5
#define PIN_ENC2_A (12u) // PA18 EIC EXTINT2
#define PIN_ENC2_B (13u) // PA19 EIC EXTINT3
#define PIN_ENC3_A (10u) // PA16 EIC EXTINT0
#define PIN_ENC3_B (11u) // PA17 EIC EXTINT1
// ─── WS2812 SPI (SERCOM5) ─────────────────────────────────────────────────────
#define PIN_SPI_MOSI (18u) // PB22 SERCOM5 PAD2 ← LED data line
#define PIN_SPI_SCK (19u) // PB23 SERCOM5 PAD3
#define PIN_SPI_MISO (20u) // PB03 SERCOM5 PAD1 (unused for WS2812)
#define PERIPH_SPI sercom5
#define PAD_SPI_TX SPI_PAD_2_SCK_3 // MOSI=PAD2, SCK=PAD3
#define PAD_SPI_RX SERCOM_RX_PAD_1 // MISO=PAD1
// ─── Faders (ADC) ─────────────────────────────────────────────────────────────
#define PIN_A0 (23u) // PA02 ADC AIN[0]
#define PIN_A1 (24u) // PA03 ADC AIN[1] (also VREFA)
#define PIN_A2 (25u) // PB08 ADC AIN[2]
#define PIN_FADER0 PIN_A0
#define PIN_FADER1 PIN_A1
#define PIN_FADER2 PIN_A2
static const uint8_t A0 = PIN_A0;
static const uint8_t A1 = PIN_A1;
static const uint8_t A2 = PIN_A2;
// ─── USB (internal) ───────────────────────────────────────────────────────────
#define PIN_USB_DM (21u) // PA24
#define PIN_USB_DP (22u) // PA25
#define PIN_USB_HOST_ENABLE (21u) // unused, required by core
// ─── SPI ──────────────────────────────────────────────────────────────────────
#define SPI_INTERFACES_COUNT 0 // SPI-Objekt wird in src/hal/spi.cpp definiert
// ─── Serial / UART ────────────────────────────────────────────────────────────
// No hardware UART exposed; USB CDC is used as Serial
#define SERIAL_INTERFACES_COUNT 0
// ─── I2C ──────────────────────────────────────────────────────────────────────
// Not used on this board, stubs required by core
#define WIRE_INTERFACES_COUNT 0
#define PIN_WIRE_SDA (16u) // PA22 (reused, I2C not enabled)
#define PIN_WIRE_SCL (17u) // PA23
// ─── ADC reference ────────────────────────────────────────────────────────────
#define ADC_RESOLUTION 12
// ─── Clock ────────────────────────────────────────────────────────────────────
// Required by cores/arduino/delay.c (micros / delayMicroseconds)
#define VARIANT_MCK (48000000ul)
#define VARIANT_MAINOSC (32768ul)