#define NOP __asm__ __volatile__ ("nop\n\t")
#define F_CPU 16000000UL
#define _delayNanoseconds(__ns) __builtin_avr_delay_cycles( (double)(F_CPU)*((double)__ns)/1.0e9 + 0.5 )
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TIMER 1 variables, for the Frequency and pulse width.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 1/16Mhz = 0.0625us, prescaler = 64
// Pulse time = period * 64 * 0.0625us
volatile int period = 2500; // Pulse time = 25 * 64 * 0.0625 = 100us
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------------------------------
volatile int PULSE_OUTPUT_ON = 0;
//------------------------------------------------------------------------------------------------------------------------
volatile int PULSE_FREQUENCY = 100;
volatile int PULSE_WIDTH_US = 1;
//------------------------------------------------------------------------------------------------------------------------
volatile int bootingup = 1; // After powering up the Device, initialization of timer should be done once.
// if wanting that the device will startup with let's say,
// 100Hz and 5 us pulse generation.
// after that, new commands are accepted via Ethernet UDP comms.
// Removed the Ethernet UDP from this code, because hard to simulate, on WOKWI.
//
// delayMicroseconds() function does not allow decimals, trying to do some
// finer adjustment for the pulse OUT signal, by adding some NOP; operations
//
//
volatile int PULSE_WIDTH_FINE_TUNE = 1; // 0.Xus delay.. about..
//Trying.. 1 NOP command is 62,5ns. on Mega, 16MHz clock cycles.
// Value 1 -> 2 NOP commands, 125ns.
// 2 -> 3 NOP commands, 187,5ns.
// 3 -> 5 NOP commands, 312,5ns.
// 4 -> 7 NOP commands, 437,5ns.
// 5 -> 8 NOP commands, 500ns.
// 6 -> 10 NOP commands, 625ns.
// 7 -> 12 NOP commands, 750ns.
// 8 -> 13 NOP commands, 813ns.
// 9 -> 15 NOP commands, 936ns.
volatile bool Nanoseconds_100=false;
volatile bool Nanoseconds_200=false;
volatile bool Nanoseconds_300=false;
volatile bool Nanoseconds_400=false;
volatile bool Nanoseconds_500=false;
volatile bool Nanoseconds_600=false;
volatile bool Nanoseconds_700=false;
volatile bool Nanoseconds_800=false;
volatile bool Nanoseconds_900=false;
//------------------------------------------------------------------------------------------------------------------------
void setup() {
// PIN D0, to Output, Generating the frequency pulse out here.
pinMode(0, OUTPUT);
///////////////////////////////////////////////////////////////////////////
// TIMER 1, configuration.
///////////////////////////////////////////////////////////////////////////
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0; //initialize counter value to 0
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS11) | (1 << CS10); // 64 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
OCR1A = period - 1;
interrupts();
////////////////////////////////////////////////////////////////////////
} // END OF SETUP Function.
///////////////////////////////////////////////////////////////////////////
// Timer 1, parameters.
///////////////////////////////////////////////////////////////////////////
ISR(TIMER1_COMPA_vect) {
if(PULSE_OUTPUT_ON == 1){
/////////////////////////////////////////////////////////////////////////
PORTE = B1111111; // TURN ON THE Digital outputs, D0..
}
/////////////////////////////////////////////////////////////////////////
// delayMicroseconds(PULSE_WIDTH_US); // the Coarse adjustment
// after that, trying to add
// "finetune" smaller delay,
// 0.1us, or 0.2.. to 0.9us
// PROBLEM IS, that the IF conditions takes also CPU cycles,
// how to avoid that?
//
// --- Just for measuring CPU cycles
// TCCR1B = bit(CS10);
// TCNT1 = 0;
// --- Just for measuring CPU cycles
// NOP; // one nop, should be one CPU cycle, 62,5ns, at 16MHz Mega.
// AND problem here was, that _delayNanoseconds() function, expects to have static integer, at compile time.
// was trying to do like this, with many if statements,
// because it looked like that for loop is no go, too many cycles.
// and switch case also takes many CPU cycles..
// so does these if statements.. but I duno how to avoid these?
// if(Nanoseconds_100 == true){
// _delayNanoseconds(100);
// }
// if(Nanoseconds_200 == true){
// _delayNanoseconds(200);
// }
// if(Nanoseconds_300 == true){
// _delayNanoseconds(300);
// }
// if(Nanoseconds_400 == true){
// _delayNanoseconds(400);
// }
// if(Nanoseconds_500 == true){
// _delayNanoseconds(500);
// }
// if(Nanoseconds_600 == true){
// _delayNanoseconds(600);
// }
// if(Nanoseconds_700 == true){
// _delayNanoseconds(700);
// }
// if(Nanoseconds_800 == true){
// _delayNanoseconds(800);
// }
// if(Nanoseconds_900 == true){
// _delayNanoseconds(900);
// }
// Was testing the for loop, that makes way too mutch overhead,
// loop itself takes longer than the actual NOP instructions.
// for (int i = 0; i <= 5; i++){
// NOP; // ASM NO OPERATION
// }
PORTE = B0000000; // TURN OFF THE Digital outputs, D0..
/////////////////////////////////////////////////////////////////////////
OCR1A = period - 1;
// --- Just for measuring CPU cycles
// unsigned int cycles = TCNT1;
// Serial.println(cycles -1);
// --- Just for measuring CPU cycles
}
///////////////////////////////////////////////////////////////////////////
void adjust_timer_values()
{
if(PULSE_FREQUENCY > 49 && PULSE_FREQUENCY < 1001)
{
noInterrupts();
period = 250000 / PULSE_FREQUENCY; // 1000000us / fps / 4us (4us= 1 timer1 tick with 64 prescaler)
interrupts();
}
}
///////////////////////////////////////////////////////////////////////////
// MAIN LOOP
///////////////////////////////////////////////////////////////////////////
// Before going into the loop:
// When booting up, some default values for timer first.
//-------------------------------------------------------------------------
void bootupinitialization()
{
//-----------------------------------------------------------------------
delay(100); // delay, after power up.
//-----------------------------------------------------------------------
PULSE_OUTPUT_ON = 1;
PULSE_FREQUENCY = 500;
PULSE_WIDTH_US = 5; // Couarse adjustment for the pulse, 1us, 2us, 3us,... up to 100us.
PULSE_WIDTH_FINE_TUNE = 5; // Fine tuning adjust for the pulse, 0.1us, 0.2us... up to 0.9us.
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
adjust_timer_values();
//-----------------------------------------------------------------------
PULSE_OUTPUT_ON = 1;
//-----------------------------------------------------------------------
bootingup = 0; // Flag down, init only once.
}
// ----------------------- MAIN LOOP ----------------------------------------------------------------------------------------------
void loop()
{
if (bootingup == 1){ // FLAG, SO THAT THIS IS DONE ONLY ONCE, when booting up.
bootupinitialization(); // delay, so that LED-light power supply, can charge the capasitors voltage.
// the use case for this code is to trigger some other devices,
// not just the Beeper here, at the simulation....
}
PULSE_OUTPUT_ON = 1;
PULSE_FREQUENCY = 500;
PULSE_WIDTH_US = 5; // Couarse adjustment for the pulse, 1us, 2us, 3us,... up to 100us.
PULSE_WIDTH_FINE_TUNE = 5; // Fine tuning adjust for the pulse, 0.1us, 0.2us... up to 0.9us.
switch (PULSE_WIDTH_FINE_TUNE) {
case 1:
Nanoseconds_100=true;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 2:
Nanoseconds_100=false;
Nanoseconds_200=true;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 3:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=true;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 4:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=true;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 5:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=true;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 6:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=true;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 7:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=true;
Nanoseconds_800=false;
Nanoseconds_900=false;
break;
case 8:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=true;
Nanoseconds_900=false;
break;
case 9:
Nanoseconds_100=false;
Nanoseconds_200=false;
Nanoseconds_300=false;
Nanoseconds_400=false;
Nanoseconds_500=false;
Nanoseconds_600=false;
Nanoseconds_700=false;
Nanoseconds_800=false;
Nanoseconds_900=true;
break;
default:
// if nothing else matches, do the default
// default is optional
break;
}
adjust_timer_values();
}
//--------------------------------------------------------------------------------------------------------------------------------------------------
//MORE INFO: PURPOSE IS TO GENERATE A FREQUENCY,
// let' say from 50Hz... to 1000Hz, adjustable, also pulse width adjustable, by 0.1us...
// or 567Hz, 27,7us long pulse, Out from the Digital 0 pin.
//--------------------------------------------------------------------------------------------------------------------------------------------------
// Idea for using the timer1 is from;
// https://github.com/indrekluuk/code_examples/blob/master/InterruptPulseExample/InterruptPulseExample.ino
// https://youtu.be/m4EpTYaBBJ4
//---------------------------------------------------------
// Trying to figure out Some way, how to add cpu cycles measurement to the Arduino Code;
// these youtube videos, which might help;
// https://youtu.be/tnfeMCyLZSo
// https://youtu.be/2ESXfD8X-FQ