npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@typecad/framework-avr

v1.0.0-alpha.7

Published

TypeCAD framework package for native AVR register-level code generation

Readme

@typecad/framework-avr

Native AVR register-level code generation for TypeCAD.

Overview

@typecad/framework-avr is a TypeCAD framework strategy that emits direct AVR register access instead of Arduino Wiring calls. Where @typecad/framework-arduino lowers D13.high() to digitalWrite(13, HIGH), this package lowers it to PORTB |= 0x20 — the bare-metal instruction the compiler would eventually produce anyway, without the function-call overhead or the Arduino core dependency.

This is the right choice when you want tighter control over AVR hardware behavior, faster firmware, smaller binaries, or fewer runtime dependencies than the Arduino framework provides.

What it lowers natively

Every hardware peripheral is lowered to direct register access — no HAL op falls through to the Arduino Wiring API:

| Peripheral | Operation | Arduino framework | framework-avr | |---|---|---|---| | GPIO | pin high | digitalWrite(13, HIGH) | PORTB \|= 0x20 | | GPIO | pin read | digitalRead(13) | ((PINB & 0x20) ? 1 : 0) | | GPIO | pin toggle | digitalWrite(n, !digitalRead(n)) | PINB \|= 0x20 | | GPIO | pin mode | pinMode(13, OUTPUT) | DDRB \|= 0x20 | | PWM | duty cycle | analogWrite(11, 128) | OCR2A = 128 | | ADC | read | analogRead(A0) | ({ ADMUX=(1<<REFS0)\|0; ...; ADC; }) | | ADC | set reference | analogReference(INTERNAL) | ADMUX = ... \| (1<<REFS1) \| (1<<REFS0) | | Timing | delay | delay(500) | _native_delay_ms(500) | | Timing | millis | millis() | native Timer0 ISR millis() | | Interrupts | attach | attachInterrupt(digitalPinToInterrupt(2), fn, FALLING) | EICRA \| ISC bits; EIMSK \| (1<<INT0) | | Tone | play | tone(11, 440) | _tc_tone_play(11, 440, 0) (Timer2 CTC) | | Pulse | measure | pulseIn(7, HIGH) | native micros() + GPIO poll loop | | Shift | out | shiftOut(D10, D11, LSBFIRST, val) | inline PORT/clock bit-bang loop | | SPI | transfer | SPI.transfer(0xFF) | _spi_transfer(0xFF) (SPDR + SPIF) | | UART | print | Serial.print(val) | _uart_print_expr(val) (USART0) | | I2C | write | Wire.write(data) | _twi_write_byte(data) (TWDR + TWCR) | | EEPROM | read | EEPROM.read(addr) | eeprom_read_byte((uint8_t*)addr) |

Native timing (setInterval/setTimeout/millis)

The framework provides its own millis()/micros() via a Timer0 overflow ISR, driven by the chip descriptor's millisTimer config. The ISR uses the Arduino wiring.c fractional-accumulator pattern (incremental millisecond accumulation, not multiply-at-read) for accurate long-running timing. setInterval and setTimeout are backed by a cooperative timer runtime (__tc_TimerRuntime) pumped from loop().

Bare-metal main() — no Arduino core linked

The strategy emits a bare-metal int main(void) that calls setup() once, then runs the cooperative while(1) { loop(); } super-loop. Defining main() overrides the Arduino core's entry point, causing the linker to dead-code-eliminate the entire core (wiring.c, HardwareSerial, Wire, SPI, EEPROM, Tone). Result: 72% Flash reduction (198 bytes vs 712 bytes for a pin toggle, 724 bytes vs 2.5 KB for a multi-peripheral demo).

Testing

The @typecad/expect test framework supports a pluggable OutputShim (avrUartShim) that routes test protocol output through the framework's native _uart_* helpers instead of Arduino Serial. This means test builds are fully bare-metal too — no Arduino core is linked even when running on-device tests. The shim is selected automatically based on the config's framework field.

Supported chips

Pin/register mapping is driven by chip descriptors — pure-data tables under src/chips/. Adding a chip is editing a data file, not strategy code.

| Chip | Board | Descriptor | |---|---|---| | ATmega328P | Arduino Uno, Nano | ATMEGA328P | | ATmega2560 | Arduino Mega 2560 | ATMEGA2560 |

The active chip is selected automatically from your config's buildTarget (FQBN): arduino:avr:uno → ATmega328P, arduino:avr:mega → ATmega2560.

Quick start

Use the package in your cuttlefish.config.ts:

import type { CuttlefishConfig } from '@typecad/cuttlefish/api';

const config: CuttlefishConfig = {
  entry: './src/main.ts',
  target: 'avr',
  mcu: '@typecad/mcu-atmega328p',
  board: '@typecad/board-arduino-uno',
  framework: '@typecad/framework-avr',
  frameworkData: {
    buildTarget: 'arduino:avr:uno',
  },
  output: { optimize: 'size' },
};

export default config;

Transpile, compile, and upload:

npx @typecad/cuttlefish src/main.ts --compile --upload --port COM4

Pin references

Pins should be referenced by their AVR datasheet port names (PB5, PD7, PC0), not Arduino Dx/Ax aliases. Port names are the canonical, chip-portable identity for a bare-metal framework:

import { PB5, PD7, PC0 } from '@typecad/board';

PB5.asOutput().high();   // → PORTB |= 0x20
const a = PC0.asInput(); // → ADMUX channel 0
a.readAnalog();          // → ADC register read

Exports

Strategy

  • NativeAVRStrategy / FrameworkStrategy — the platform strategy class. Pass a chip descriptor to the constructor to override the FQBN-derived default: new NativeAVRStrategy(ATMEGA2560).
  • PlatformStrategy — re-exported type.

Toolchain

Compile/upload/monitor via arduino-cli (re-exported from @typecad/framework-arduino — the build path has no framework-strategy coupling):

  • Toolchain — the loader-contract object (prepare/compile/upload/monitor).
  • flattenGeneratedModulesIntoSketch, compileArduinoSketch, uploadArduinoSketch, monitorArduinoSketch.

Library resolution

  • isFrameworkLibraryImport, getFrameworkLibraryHeaderName — Arduino library import detection.
  • buildClassNameMap — library class-name mapping.
  • tryGenerateLibDecl.d.ts generation for discovered libraries.

Chip descriptors

  • ATMEGA328P, ATMEGA2560 — descriptor instances.
  • setActiveChip — select the active chip at runtime.
  • Types: AVRChipDescriptor, AVRPinMap, AVRTimer, AVRPwmPin, AVRInterruptPin, AVRAdcConfig, AVRUartConfig.

Profile resolution

  • resolveAvrProfile — resolve the chip + diagnostics from a build target.
  • chipForBuildTarget — map a FQBN to its chip descriptor.
  • ResolvedAvrProfile — resolved profile type.

Register helpers

Chip-agnostic reads over the active descriptor:

  • getPinInfo, getPinBitMask, getPortReg, getDDRReg
  • getADCChannel, getPWMInfo, isPWMPin, getPWMPins
  • getInterruptInfo, isInterruptPin
  • inferReceiverKind, parsePinFromReceiver

Diagnostics

Invalid pins and unsupported peripherals surface as structured diagnostics instead of silent /* invalid pin */ comments. For example, using a pin that doesn't exist on the selected chip produces:

error [avr-invalid-pin]: D40 is used as an output but has no PORT/DDR mapping on the atmega328p.
  → Pin D40 is not valid on the atmega328p. See the chip's pin map in src/chips/atmega328p.ts.

Diagnostic codes: avr-invalid-pin, avr-pwm-unsupported.

Testing

Unit tests (vitest)

npx vitest run tests/packages/framework-avr

Covers HAL resolution (register string output), chip-descriptor portability (328P vs 2560), and profile resolution (FQBN selection, diagnostics).

On-device hardware tests

npm run test:hw          # run the full suite
npm run test:hw:basics   # run one file

Each .test.ts transpiles to a sketch, flashes to a real ATmega328P, and the firmware reports pass/fail over UART. Requires a board connected via serial (see cuttlefish.config.ts test.port). Tests are wiring-free — they rely on internal pullups and in-range checks, no breadboard jumpers.

License

MIT