I am trying to trigger an interrupt on an ATMega328P chip which is running on a breadboard on an external clock. I can oscillate a pin via code and play around with it, so I know that my circuit is running ok.
I am trying to get an interrupt going, but it is not responding to the input transition (low to high, high to low, etc...).
volatile int sync = 0; // Global
void interruptSync() // The ISR
{
sync = 1;
}
attachInterrupt(digitalPinToInterrupt(1),interruptSync,FALLING); // Attaching the interrupt via setup
while(sync == 0) // Endless loop inside the main loop until the interrupt is triggered
{
}
Ideally I want to be triggering the interrupt from pin 15 on the IC (PB1), but I am possibly querying the wrong pin (as far as the Arduino SDK goes) due to the confusion on the Arduino diagrams, in the link below (I'm not sure how to insert the picture itself on these forums yet).
Any advice on how to setup an interrupt on PB1 (or any pin really) would be greatly appreciated. I have tried a bunch of different pin values attempting to decipher the layout, but so far no luck.
If I remember well only pin 2 and 3 have individual interrupts ISR's all other pins are grouped per port meaning the ISR is activated if one of the pins on a port is triggered. In the ISR your need to look for which pin it was that activated the ISR.
look for PCINT0, PCINT1, PCINT2 they describe the interrupt per port mechanism
// The C file
extern "C"
{
void init();
void loop();
}
volatile int sync = 0; // Global
void interruptSync() // The ISR
{
sync = 1;
}
void setup()
{
init();
//attachInterrupt(digitalPinToInterrupt(1),interruptSync,FALLING); // Attaching the interrupt via setup
while(sync == 0) // Endless loop inside the main loop until the interrupt is triggered
{
}
detachInterrupt(digitalPinToInterrupt(1));
noInterrupts();
}
// The ASM file
#define OUTPUT 0
#define INPUT 1
.global init
.global loop
init:
SBI DDRB, OUTPUT ; PB0 is an output
CBI DDRB, INPUT ; PB1 is an input
SBI PORTB, OUTPUT ; Set OUTPUT pin to high
RET
loop:
here:
SBIS PINB, 1 ; Skip next instruction if Port B pin 1 is high
RJMP here;
SBI PORTB, OUTPUT ; Clear output pin
CBI PORTB, OUTPUT ; Set OUTPUT pin
RJMP loop
So, essentially I have an 1 MHz waveform going in to PB1 and am just toggling PB0 high and low in response to that.
Clock 8 MHz crystal
1 MHz to PB1 (1 MHz is divided from the 8 MHz ATMega clock - so is 100% in sync)
PB0 driving high or low depending on what it sees on PB1
^^ This part is ok (if you remove the interrupt code), but the wave position varies on power up depending on that startup conditions. When it is running it is stable but the initial offset varies when power is applied.
Blue is the 1 MHz input on PB1 and Yellow is the output on PB0.
The reason for the interrupt was to hopefully set the initial starting position of the yellow waveform in stone rather than the three or so clock cycle drift in initial starting point.
I think I may even need to dig a little deeper. The IC I am using is a completely new chip. I had to set the fuse bits a few days back to get it to recognise the external clock. It seems that I might need to do additional work to it to recognise interrupts perhaps.
The reason behind my thinking is that I am getting no jitter when firing the output at maximum speed. Normally I have to add NoInterrupts() to my C code to get rid of the jitter. But it is completely stable without that function.
Edit - Actually, I only want to interrupt if for the first clock cycle to get it in sync. At the moment my brute force method of testing a pin, gives an error of a few clock cycles either side.
The 'theory' is for the ATMega to sample the 1MHz input at start up (via interrupt) by the clock edge. Once it goes to the ISR and returns immediately back and then disable interrupts, I should be at a known point on the clock cycle. From there I can add a couple of NOP's to get me exactly where I want to be.
From there I'll have 8 clock cycles to do the main loop (which includes the relative jump back I know).
That's the theory anyway...
Pretty much what I am after is to ensure that my main loop (of only a few clock cycles) starts here-
Or on the tailing edge - doesn't really matter.
At this point at initial power on, the loop may execute at slightly different points. The point is rock solid when running, but just varies slightly on every power up, because of this;
here:
SBIS PINB, 1
RJMP here
Because that's three clock cycles, the variance can be up to three clock cycles on power up and anywhere on the high edge of the input clock.
You need to study the data sheet, the ATmega328 chip pinout and the Arduino pin mapping.
This line will not work, as it attempts to assign Arduino digital pin 1 (TX, PD1) to the interrupt routine.
attachInterrupt(digitalPinToInterrupt(1),interruptSync,FALLING); // Attaching the interrupt via setup
External interrupts 0 and 1 are the most flexible, and they are assigned to Arduino Uno digital pins 2 and 3, which correspond to ATmega328 port pins PD2 and PD3.
I did have the input hooked to pin 4 (INT0) earlier today in my testing, but it became confusing as to what to reference that pin as via code as the pins in the Arduino SDK are labeled differently.