Hi there, i could not find the same topic in this forum. I am using the 2560 to monitor data and address lines of a 6502 mpu. The share a common clock and this is monitored on pin 2 of the 2560. As i can change the clock speed i want to see the frequency on the
monitor without having to rig up an oscilloscope. At low speeds (50 Hz) this works. At 1Mhz i get 65kHz. The code is below.
const char ADDR[] = {22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52};
const char DATA[] = {53, 51, 49, 47, 45, 43, 41, 39};
#define CLOCKIN 2
#define READ_WRITE 3
int pinState = LOW;
unsigned long freq = 0;
unsigned long counter = 1;
unsigned long time = 0;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
void setup()
{
for (int n = 0; n < 16; n += 1)
{
pinMode(ADDR[n], INPUT);
}
for (int n = 0; n < 8; n += 1)
{
pinMode(DATA[n], INPUT);
}
pinMode(CLOCKIN, INPUT);
pinMode(READ_WRITE, INPUT);
attachInterrupt(digitalPinToInterrupt(CLOCKIN), onClock, RISING);
Serial.begin(2000000);
}
void loop()
{
}
void onClock()
{
char output[20];
// Measure frequency
currentMillis = millis();
counter = counter + 1;
if (counter >= 1000)
{
time = currentMillis - previousMillis;
freq = counter*1000/time;
previousMillis = currentMillis;
counter = 1;
}
unsigned int address = 0; // Determining and printing bus address in binary
for (int n = 0; n < 16; n += 1)
{
int bit = digitalRead(ADDR[n]) ? 1 : 0;
//Serial.print(bit);
address = (address << 1) + bit; // Store address
}
// Serial.print(" "); // Determining and printing bus data in binary
unsigned int data = 0;
for (int n = 0; n < 8; n += 1)
{
int bit = digitalRead(DATA[n]) ? 1 : 0;
//Serial.print(bit);
data = (data << 1) + bit; // Store data
}
sprintf(output, " %04x %c %02x %u Hz", address, digitalRead(READ_WRITE) ? 'r' : 'W', data, freq);
Serial.println(output);
}
Can anyone explain why this is not working?
Many thanks
Besides shortening your ISR, never put print() statements inside your ISR. They use interrupts to work and interrupts are turned off. The core takes special care to make it work, but print()'ing takes a long time.
If you want to go up to 1MHz, I would suggest moving to a more powerful processor, like the Teensy or an ESP32 with a much higher clock speed.
You do know that digitalRead() returns 0/1 directly, yes? (HIGH==1, LOW==0)
Thanks for the reply. I am following a project to build a 6502 computer so the code comes from someone who understands this stuff. I am a beginner in this respect. Any suggestions on how to modify the code to achieve the objective of providing the address on the bus, the data on the bus, and the clock speed. Operating at 16MHz you would think the 2560 could deal with monitoring a 1MHz processing speed without missing output. How do i calculate how many clock cycles it takes to move through the ISR?
Many thanks
You are missing the point! Any interrupt code MUST be as short as you can possibly make it! You can set a Boolean to True in the interrupt code and then test for it being True in your main code and then do something and set the Boolean to False.
I would not think that at all. With 1MHz 6502 clock, you have only 16 2560 clock cycles to do ALL of your processing. Simply responding to the interrupt takes more than that, even if the ISR does NO processing.
One possible way to create a frequency meter on the Arduino Mega, is to configure timer 5 to count the number of input pulses on its T5 input, (digital pin D47).
As this timer is only 16-bits, it's only possible to count from 0 to 65535. This means it's not possible to count 1 million pulses over 1 second, neither is it possible to use interrupts at this frequency to implement a software counter.
It is however possible to count the number of input pulses over 1/16th of a second, which at 1MHz = 62500 pulses, then subsequently multiply this value by 16. This obviously reduces your resolution to a minimum of 16Hz. There's also the additional delay for your sketch to check that 1/16th of a second has elapsed using the micros() function, copy timer 5's count register (TCNT5) then reset it to 0. As a consequency the frequency meter isn't super accurate, but does measure values in the right ballpark at 1MHz.
Here's the code with T5 on the Mega's digital pin D47:
// Set-up timer 5 to count pulses on digital pin D47
uint32_t currentMicros, previousMicros;
void setup() {
Serial.begin(115200); // Initialise the serial port
TCCR5A = 0; // Clear the TCCR5A register
TCCR5B = _BV(CS52) | _BV(CS51) | _BV(CS50); // Set T5 (D47) as the timer 5 clock source triggered on the rising edge
previousMicros = micros(); // Update the previous micros
}
void loop() {
currentMicros = micros(); // Update the current micros
if (currentMicros - previousMicros >= 62500) // After a 1/16th second delay
{
uint32_t count = TCNT5; // Copy the count register
TCNT5 = 0; // Reset timer 5 count register to 0
count *= 16; // Multiply up the count value over 1/16th second to give frequency (Hz)
Serial.println(count); // Output the number of pulses counted in Hz
previousMicros = currentMicros; // Update the previous micros
}
}