Help with interrupt definition using MegaCoreX

Hi, I am gradually making progress with my avr4809 baremetal encoder project. (which I previously coded in the Arduino IDE on a mega2560 board.

In the MegaCoreX github readme it says I can do the following to call an Interrupt
Simply call attachInterrupt like this:

attachInterrupt(myPin, myInterruptFunction, RISING);


so in my barebones project, my version of the above is as follows:

attachInterrupt(encoder_Pin,encoderInterrupt, RISING);

where encoder_Pin is defined in my .h file as at the bottom of this extract :

#include <avr/io.h>
#include <stdio.h>
#include <string.h>
#include <util/delay.h>
#include <stdlib.h>

#define F_CPU 3333333
#define USART1_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)
#define MAX_COMMAND_LEN		16
#define INIT_DELAY			10	// Delay to invalidate the after-reset noise on the PC0 pin (TX) 

#define ASCOMSerial   USART1      // give the USARTS meaningful names
#define MONITORSerial USART0      //this will be a ftdi
#define STEPPERSerial USART2      //this is serial to serial hardwired connectors

#define encoder_Pin PC2            // pin used for encoder interrupts

and an interrupt routine handling the encoder devices inputs, called ‘encoderInterrupt’ exists in my encoder.cpp file

I was a bit perplexed by the ’ ; ’ following the attachinterrupt statement as that obviously implies a function call.
So I’m guessing I’ve missed something, but don’t know what that is, so any help much appreciated. The errors from compilation are posted below:

 Executing task: C:\Users\Paul\.platformio\penv\Scripts\platformio.exe run <

Processing ATmega4809_pyupdi_upload (platform: atmelmegaavr; board: ATmega4809; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
PLATFORM: Atmel megaAVR (1.4.0) > ATmega4809
 - framework-arduino-megaavr-megacorex 1.0.7
 - toolchain-atmelavr 2.70300.201015 (7.3.0)
LDF: Library Dependency Finder ->
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 10 compatible libraries
Scanning dependencies...     
Dependency Graph
|-- <src>
Building in release mode
Compiling .pio\build\ATmega4809_pyupdi_upload\src\main.cpp.o
Archiving .pio\build\ATmega4809_pyupdi_upload\lib50d\libsrc.a
In file included from src\main.cpp:7:0:
src\main.cpp: In function 'int main()':
lib\src/encoder.h:23:21: error: 'PC2' was not declared in this scope
 #define encoder_Pin PC2            // pin used for encoder interrupts
src\main.cpp:26:17: note: in expansion of macro 'encoder_Pin'
 attachInterrupt(encoder_Pin,encoderInterrupt, RISING);
src\main.cpp:26:47: error: 'RISING' was not declared in this scope
 attachInterrupt(encoder_Pin,encoderInterrupt, RISING);
src\main.cpp:26:1: error: 'attachInterrupt' was not declared in this scope
 attachInterrupt(encoder_Pin,encoderInterrupt, RISING);
src\main.cpp:26:1: note: suggested alternative: 'encoderInterrupt'
 attachInterrupt(encoder_Pin,encoderInterrupt, RISING);
*** [.pio\build\ATmega4809_pyupdi_upload\src\main.cpp.o] Error 1
================================================================================================== [FAILED] Took 0.79 seconds ==================================================================================================
The terminal process "C:\Users\Paul\.platformio\penv\Scripts\platformio.exe 'run'" terminated with exit code: 1.

The compiler doesn’t like my encoder pin definition as PC2, but again from the MegaCoreX documentation, I understand I can do this and if I control click on PC2, I see the definition as chip pin 2, which is what I’d expect (it’s a 4809 40 pin DIP).

I could model the intterrupt as per Microchip’s TB3229 example - wake up on button press, and happy to do so if needs be, but the MegaCoreX readme’s explanation looks easy to use, so I thought I’d try that 1st and see what the code volume looks like.


PC2 doesn’t exist as a pin definition. The Arduino function attachInterrupt for the MegaCoreX (and all Arduino cores, really) expect an Arduino pin number definition, usually made in the variant. Other functions like digitalWrite(), digitalRead() also expect such a “Arduino” pin number.

For that, the core has

thus you need to use PIN_PC2.

You’re attempting to call Arduino API functions but haven’t done the #include <Arduino.h>.

If I write src\main.cpp as

#include <Arduino.h>
#define encoder_Pin PIN_PC2            // pin used for encoder interrupts

volatile bool encoder_isr_fired = false;

void encoderInterrupt() {
    /* called in ISR context */
    encoder_isr_fired = true;

void setup() {
    pinMode(encoder_Pin, INPUT); // can also be INPUT_PULLUP if wished
    attachInterrupt(encoder_Pin, encoderInterrupt, RISING);

void loop(){
    if(encoder_isr_fired) {
        encoder_isr_fired = false;
        Serial.println("ISR was executed");

with the standard platformio.ini

platform = atmelmegaavr
board = ATmega4809
framework = arduino

it compiles.

Building .pio\build\ATmega4809\firmware.hex
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   4.2% (used 256 bytes from 6144 bytes)
Flash: [=         ]   6.6% (used 3224 bytes from 49152 bytes)
========================= [SUCCESS] Took 1.68 seconds =========================

thanks very much for explanation and time. Still getting my head around stuff and hadn’t realised MegaCoreX needed arduino.h.

If I ctrl click PC2 (in my #define encoder_Pin PC2) I get this (excerpt):

#define PORTC   _SFR_IO8(0x08)
#define PC7     7
#define PC6     6
#define PC5     5
#define PC4     4
#define PC2     2
#define PC1     1
#define PC0     0

which I assume is a pin macro, anyway no worries if it’s not…I’ll have to think about it.

More worrysome for me is that if I instead use

#define encoder_Pin PIN_PC2 

as you’ve suggested, If I ctrl Click PIN_PC2, I get the following excerpt:

// Pin macros
#define PIN_PA0 0
#define PIN_PA1 1
#define PIN_PA2 2
#define PIN_PA3 3
#define PIN_PA4 4
#define PIN_PA5 5
#define PIN_PA6 6
#define PIN_PA7 7
#define PIN_PC0 8
#define PIN_PC1 9
#define PIN_PC2 10
#define PIN_PC3 11

which defines PIN_PC2 as arduino pin 10

but in the pinout diagram for the 40 pin variant here:

at the bottom of the diagram it states that digital pins 8 through 13 are not available on the dip 40.

In terms of PHYSICAL pin numbers on the chip, having used pins 1 and 2 for USART1 comms, I would like to use pin3 (PC2) as my interrupt trigger pin. So what #define would I write for that?

thanks again,

it would be #define encoder_Pin PIN_PD2

I think this is going to drive me barmy :slight_smile:

These are macro from the I/O headers of the AVR toolchains – used in functions accessing registers (like PORTC, but the Arduino core APIs as said uses different definitions.

This is indeed weird. The image shows a DIP 40 packages but has the pin numbers from the 48-pin variant.

Maybe this graphic was created when the 40-pin package variant didn’t yet exist and so people had to use the 48-pin arduino variant for their 40-pin chip, then, that is correct.

But, I’ve made an error indeed in my references above. The Platform-AtmelMegaAVR defines the board to be of the variant


If you are working with the Arduino variant for the 40 pin package you can write

board_build.variant = 40pin-standard

in the platformio.ini.

However, this should actually not make a difference – when you reference the pin via it’s macro value, like PIN_PC2, it will be mapped correctly according to the variant. The macro may have a different value depending on which variant is used, but they will access the same physical pin in the end. So if the pin is exposed on your package, it should work.

Yeah this seems to be an old picture. There, PC2 is digital pin number 16. But when you go to GitHub - MCUdude/MegaCoreX at 85021fe18c3f924752e9f4612ec764955ee839ec and click on the 40-pin variant, it’s number 10.