arduino
#include <SPI.h>
#include <TimerOne.h>

#define CS_PIN   8
#define CS_PORT  PORTB
#define CS_BIT   _BV(PB0)

const unsigned int STEPS   = 128;     // Number of points per ramp cycle
const float        FREQ_HZ = 800;   // Desired ramp frequency (Hz)
const float        DUTY    = 0.9;     // Duty cycle (fraction of rising edge)
const float        AMPL    = 1.0;     // Output amplitude scale (0.0–1.0)

unsigned int ramp_vals[STEPS];        // Precomputed DAC output values
unsigned int idx = 0;                 // Current sample index
unsigned int upSteps, dnSteps;        // Steps for rising/falling edges
unsigned long count = 0;              // Counter for signal cycles

// Build the lookup table for ramp waveform (scaled by DUTY and AMPL)
void buildTable() {
  upSteps = max(2u, min(STEPS - 2, (unsigned int)(DUTY * STEPS)));
  dnSteps = STEPS - upSteps;
  for (unsigned int i = 0; i < STEPS; i++) {
    unsigned int v = (i < upSteps)
      ? (4095UL * i) / (upSteps - 1)
      : (4095UL * (STEPS - 1 - i)) / (dnSteps - 1);
    ramp_vals[i] = (unsigned int)(v * AMPL);
  }
}

// Send a 16-bit command to the DAC using direct port manipulation
inline void writeDAC(uint16_t val) {
  uint16_t frame = 0x3000 | (val & 0x0FFF);
  CS_PORT &= ~CS_BIT;           // Assert CS low
  SPI.transfer16(frame);        // Fast SPI transfer
  CS_PORT |= CS_BIT;            // Deassert CS high
}

// Timer1 interrupt handler: output next ramp sample
void outputStep() {
  writeDAC(ramp_vals[idx]);
  idx = (++idx == STEPS) ? 0 : idx;  // Wrap index around
  count++; // Increment the counter on each step
}

void setup() {
  SPI.begin();
  SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); // Set 20 MHz SPI

  pinMode(CS_PIN, OUTPUT);
  CS_PORT |= CS_BIT;            // Ensure CS remains inactive until used

  buildTable();                 // Populate ramp_vals[]

  unsigned long period_us = (unsigned long)(1e6 / (FREQ_HZ * STEPS));
  Timer1.initialize(period_us);         // Trigger ISR at each sample time
  Timer1.attachInterrupt(outputStep);   // Link ISR to ramp output
}

void loop() {
  // You can now access the 'count' variable in the loop
  // to track the number of signal cycles.
  // For example, you could print it to the serial monitor:
  Serial.print("Signal Cycles: ");
  Serial.println(count);

  // You can add other code here that runs periodically
  // without interfering with the ramp generation.
}


*Explanation of Changes:*

1. **unsigned long count = 0;**: A new variable count of type unsigned long is declared to store the number of signal cycles. unsigned long is used because the count can potentially become large.

2. **count++;**: Inside the outputStep() interrupt handler, after writing the DAC value and wrapping the index, the count variable is incremented by 1. This happens on every step of the ramp.

3. **Serial.print("Signal Cycles: "); and Serial.println(count);**: In the loop() function, after the ramp generation is complete, we now print the current value of count to the serial monitor. This allows you to observe the number of signal cycles that have occurred.

*How to Use:*

1. Upload this code to your Arduino Uno.
2. Open the Serial Monitor in the Arduino IDE (Tools > Serial Monitor).
3. You will see the "Signal Cycles:" value continuously increasing as the ramp signal is generated.

*Important Note:*

The count variable represents the number of steps taken in the ramp cycle. Since the ramp cycle repeats every STEPS steps, the count will effectively track the number of complete cycles. If you want to count something else (e.g., the number of milliseconds since the start of the ramp), you would need to modify the outputStep() function accordingly..How will i know it is counting?