How to regulate the phase on pin PA9

Hi, this is generator code

#define F_TIMER   72000000
#define FREQ    9000  

#define SAMPLES ((int)sqrt(F_TIMER / FREQ))
#define T_CNT   ((F_TIMER/FREQ)/SAMPLES)

#define sin_zero     (T_CNT/2)
#define max_amp      (sin_zero-1)

#define DEBOUNCE_DELAY 100

#define DEBOUNCE_IDLE 0
#define DEBOUNCE_ACTIVE 1

#include <libmaple/dma.h>
#include <EEPROM.h>

dma_tube_config dma_cfg;

float shift = 0.0;
float current_amp_step = 0.0;

int botonState = 0;
int flag2 = 0;
int out2 = PA8;
int out3 = PA9;
int * val2 = new int[SAMPLES];
int amp = 0;
int amp_mv = 0;
int max_mv = 3300;
int cnt = 0;
int time_track = 0;
float stp = 6.2831 / SAMPLES;
int ret = 17;

timer_dev *dev2 = PIN_MAP[out2].timer_device;
uint8 cc_channel2 = PIN_MAP[out2].timer_channel;

void fun2()
{
  static uint8_t ff = 0;
  flag2++;
  digitalWrite(out3, ff = (1 - ff));
}

void timer_conf()
{
  timer_dma_set_base_addr(dev2, TIMER_DMA_BASE_CCR1);
  timer_dma_set_burst_len(dev2, 1);
  timer_dma_enable_req(dev2, cc_channel2);
  timer_set_reload(dev2, T_CNT);
  timer_set_prescaler(dev2, 0);
}

void dma_conf()
{
  dma_init(DMA1);

  /* T1C1 DMA C2 */
  dma_cfg.tube_dst = &(dev2->regs.gen->DMAR);
  dma_cfg.tube_dst_size = DMA_SIZE_32BITS;
  dma_cfg.tube_src = val2;
  dma_cfg.tube_src_size = DMA_SIZE_32BITS;

  dma_cfg.tube_nr_xfers = SAMPLES;
  dma_cfg.tube_flags = DMA_CFG_SRC_INC | DMA_CFG_CIRC | DMA_CFG_HALF_CMPLT_IE | DMA_CFG_CMPLT_IE;

  dma_cfg.tube_req_src = DMA_REQ_SRC_TIM1_CH1;
  dma_cfg.target_data = 0;

  ret = dma_tube_cfg(DMA1, DMA_CH2, &dma_cfg);
}

void dma_start()
{
  dma_attach_interrupt(DMA1, DMA_CH2, fun2);
  dma_enable(DMA1, DMA_CH2);
  timer_resume(dev2);
}

void init_wave()
{
  int i;
  for (i = 0; i < SAMPLES; i++)
  {
    val2[i] = sin_zero + amp * sin(stp * i);
  }
}

void get_wave(float current_shift)
{
  int i;
  float phase_rad = current_shift * (6.2831853 / 360.0);
  for (i = 0; i < SAMPLES; i++)
  {
    val2[i] = sin_zero + amp * sin(stp * i + phase_rad);
  }
}

void save_settings()
{
  int addr = 0;
  EEPROM.write(addr, (int16)shift);
  addr += sizeof(int16);
  EEPROM.write(addr, (int16)current_amp_step);
}

void load_settings()
{
  int addr = 0;
  int16 loaded_shift = 0;
  int16 loaded_amp_step = 500;

  EEPROM.read(addr, (uint16*)&loaded_shift);
  addr += sizeof(int16);
  EEPROM.read(addr, (uint16*)&loaded_amp_step);

  if (loaded_shift >= 0 && loaded_shift <= 360) {
    shift = (float)loaded_shift;
  } else {
    shift = 0.0;
  }

  if (loaded_amp_step >= 0 && loaded_amp_step <= 1000) {
    current_amp_step = (float)loaded_amp_step;
  } else {
    current_amp_step = 500.0;
  }
}

void setup() {
  pinMode(out2, PWM);
  pinMode(out3, OUTPUT);

  // Custom external/internal alignment pin configurations
  pinMode(PB15, INPUT_PULLUP); // Button to INCREASE AMP STEP
  pinMode(PB13, INPUT_PULLUP); // Button to DECREASE AMP STEP
  pinMode(PA15, INPUT_PULLUP); // Button to cycle Menu Cases (0, 1, 2, 3, 4)
  pinMode(PB12, INPUT_PULLUP); // LEFT (DECREASE PHASE)
  pinMode(PB14, INPUT_PULLUP); // RIGHT (INCREASE PHASE)

  Serial.begin(115200);

  timer_conf();
  dma_conf();
  dma_start();

  load_settings();

  amp = (int)((current_amp_step / 1000.0) * max_amp);
  amp_mv = (int)((current_amp_step / 1000.0) * max_mv);

  init_wave();
  get_wave(shift);
}

void loop() {
  // 1. Menu Navigation
  if (digitalRead(PA15) == 0) {
    botonState = (botonState + 1) % 5;
    delay(250); // Button click guard
  }

  // 2. State-Dependent Logic
  switch (botonState) {
    case 0: // Idle
      Serial.println("  C0  ");
      delay(100);
      break;

    case 1: // Sine Regulation
      {
        bool update_required = false;

        // Amplitude steps handling (0 to 1000 steps)
        if (digitalRead(PB15) == LOW)
        {
          if (current_amp_step < 1000.0) {
            current_amp_step++;
            update_required = true;
          }
        }
        if (digitalRead(PB13) == LOW)
        {
          if (current_amp_step > 0.0) {
            current_amp_step--;
            update_required = true;
          }
        }

        // Phase handling (0.5 degree steps with strict rollover)
        if (digitalRead(PB14) == LOW)
        {
          shift += 0.5;
          if (shift > 360.0) {
            shift = 0.0;
          }
          update_required = true;
        }
        if (digitalRead(PB12) == LOW)
        {
          shift -= 0.5;
          if (shift < 0.0) {
            shift = 360.0;
          }
          update_required = true;
        }

        // Apply changes dynamically if a button was pressed
        if (update_required) {
          amp = (int)((current_amp_step / 1000.0) * max_amp);
          amp_mv = (int)((current_amp_step / 1000.0) * max_mv);
          get_wave(shift);
        }
      }
      
      // Your requested serial monitor layout
      Serial.print("  C1 ");
      Serial.print(" | A = ");    Serial.print(amp_mv);
      Serial.print("  P = ");     Serial.print(shift, 1); 
      Serial.println("°");
      delay(80); // Controls step speed when holding down buttons
      break;

    case 2:
      Serial.println("  C2 ");
      delay(100);
      break;

    case 3:
      Serial.println("  C3 " );
      delay(100);
      break;

    case 4:
      Serial.println("  C4 spare 2");
      delay(100);
      break;
  }
}

I'd first define the reference.

Phase is always relative to another signal. Which signal should PA9 be phase-shifted against?

look at this line

The entire term \((\omega t)\) represents the angle of the wave in radians. As time t advances, the angle continuously increases, causing the sine output to oscillate smoothly between -1 and

it is this one

I understand that phase_rad is the phase angle inside the sine function. My question is different: relative to which other waveform do you want PA9 to have that phase shift? PA8? Another timer output? An external signal?

Ok, and what is your issue?

to make simple, currently sine wave has phase regulation compared to square wave, PA8 > PA9, now I want to regulate phase of square wave compared to sine wave PA9 > PA8,

what microcontroller are you using?
what frequency range do you require?

sec ond line in code, stm32f

Isn't it the same thing?
The phase is relative.

If the phase PA8 > PA9 difference is x degrees, so PA9 > PA8 difference will be 360-x

what is the purpose of sin_zero? it just adds an constant offset to the amplitude. it's name implies having something to do with the value being computed or the angle?

would be better written as

val2 [i] = amp0 + amp * sin(k * i + ph0)

where k = 2 π / nSamp

  • cyan - no phase or amplitude offset
  • yellow - 70 deg phase offset
  • red - -2 amplitude offset

ph0 = k *deg0

another thing to consider is to maintain a continuous waveform. since you generate samples in a buffer, changing the initial phase (i.e. ph0) results in a discontinuity, an abrup phase shift.

one approach for maintaining continuity while changing phase is to change the k value, the frequency by just a little over some # of samples and keeping track of the ending phase value to be used to generate the next buffer.

once at the desired phase shift, the original k value is used, or possibly some different one.

if a change in frequency is desired, the k value is changed a little with each sample until the desired frequency is reached.

your get_wave() could have arguments for how much to change k with each sample, dK and values for both k and ph0 should be maintained between calls to get_wave()

it may be easier to have a getSample() maintaining and using the values of k and ph0 which can be called any # of times to fill buffer.

here are 3 100 sample buffers. k is incremented by 0.001 for each sample in the middle (fuchsia) group and then maintained in the last (yellow) group

yes, it's an awk program

awk '
function getSamp (dK)  {
    k    += dK
    samp  = sin(k +ph0)
    ph0  += k
    return samp
}

# ------------------------------------------------
function getNsamp (N, dK)  {
    while (N--)
        printf " %6d %8.4f\n", n++, getSamp(dK)
}

# ------------------------------------------------
BEGIN {
    Pi = atan2(0, -1)

    M     = 10^6
    Ftmr  = 72 *M
    Freq  = 9000
    Nsamp = sqrt(Ftmr /Freq)

    printf "# %8d Ftmr\n", Ftmr
    printf "# %8d Freq\n", Freq
    printf "# %8d Nsamp\n", Nsamp

    printf "thickness=1.5\n"

        ph0 = 2*Pi /9
        k   = 2*Pi / 100
        printf "color = %s\n", "cyan"
        getNsamp(100, 0)
        printf "color = %s\n", "fuchsia"
        getNsamp(100, 0.001)
        printf "color = %s\n", "yellow"
        getNsamp(100, 0)

    printf "title_x k %6.2f\n", k
}' | tee tom.xgr