Untitled

Anonymous
c_cpp
02/01/2026 4:09 PM
8.6 KB
16
Indexable
/**
 * @file      pico-spwm-headless.ino
 * @brief     Autonomous Grid-Tie SPWM (No Serial / Headless)
 * @details   Runs on 3.3V/5V power without USB.
 * 5 Second Delay -> ZVS Start.
 */

#include <Arduino.h>
#include "hardware/pwm.h"
#include "hardware/irq.h"


#define AUTO_START_DELAY_MS 10000  // 5 Seconds Wait

#define PUSHPULL_DRIVE_1    2     // GP2
#define PUSHPULL_DRIVE_2    3     // GP3
#define SHUTDOWN_PIN        14    // GP14 (Master Switch)
#define ZC_INPUT_PIN        15    // GP15
#define STATUS_LED          25    // Onboard LED

#define MODULATING_FREQ     50000 
#define PWM_RES             255   
#define FULL_BRIDGE         1
#define MAX_STEPS           360.0
#define TRANSISTOR_SWITCH_STEP 179

// ==========================================
// GLOBALS
// ==========================================
volatile float sync_phase_shift = 6.2; 
volatile int32_t amplitude = 240; 

// System State
volatile bool systemEnabled = false; 
volatile bool requestEnable = false; 
bool autoStartTriggered = false;     

// PLL Variables
volatile float phasor = 0.0;
const float BASE_INC = 0.36; 
volatile float currentInc = 0.36; 

// Debugging
volatile float lastPhaseError = 0.0;
volatile unsigned long last_sync_time = 0; 
unsigned long lastLedToggle = 0;
bool ledState = false;

uint slice_num; 

// Sine Lookup Table (0-255)
const int32_t sinetable[] = {
  0, 4, 8, 13, 17, 22, 26, 31, 35, 39, 44, 48, 53, 57, 61, 65, 70, 74, 78, 83, 87, 91, 95, 99, 
  103, 107, 111, 115, 119, 123, 127, 131, 135, 138, 142, 146, 149, 153, 156, 160, 163, 167, 170, 
  173, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 208, 211, 213, 216, 218, 220, 223, 
  225, 227, 229, 231, 232, 234, 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 
  251, 252, 253, 253, 254, 254, 254, 254, 254, 255, 254, 254, 254, 254, 254, 253, 253, 252, 251, 
  251, 250, 249, 248, 247, 246, 245, 243, 242, 241, 239, 238, 236, 234, 232, 231, 229, 227, 225, 
  223, 220, 218, 216, 213, 211, 208, 206, 203, 200, 198, 195, 192, 189, 186, 183, 180, 177, 173, 
  170, 167, 163, 160, 156, 153, 149, 146, 142, 138, 135, 131, 127, 123, 119, 115, 111, 107, 103, 
  99, 95, 91, 87, 83, 78, 74, 70, 65, 61, 57, 53, 48, 44, 39, 35, 31, 26, 22, 17, 13, 8, 4, 0, 
  5, 9, 14, 18, 23, 27, 32, 36, 40, 45, 49, 54, 58, 62, 66, 71, 75, 79, 84, 88, 92, 96, 100, 104, 
  108, 112, 116, 120, 124, 128, 132, 136, 139, 143, 147, 150, 154, 157, 161, 164, 168, 171, 174, 
  178, 181, 184, 187, 190, 193, 196, 199, 201, 204, 207, 209, 212, 214, 217, 219, 221, 224, 226, 
  228, 230, 232, 233, 235, 237, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252, 
  253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 252, 252, 
  251, 250, 249, 248, 247, 246, 244, 243, 242, 240, 239, 237, 235, 233, 232, 230, 228, 226, 224, 
  221, 219, 217, 214, 212, 209, 207, 204, 201, 199, 196, 193, 190, 187, 184, 181, 178, 174, 171, 
  168, 164, 161, 157, 154, 150, 147, 143, 139, 136, 132, 128, 124, 120, 116, 112, 108, 104, 100, 
  96, 92, 88, 84, 79, 75, 71, 66, 62, 58, 54, 49, 45, 40, 36, 32, 27, 23, 18, 14, 9, 5, 1
};

// ==========================================
// INTERRUPT 1: SPWM GENERATOR (50kHz)
// ==========================================
void isr_pwm() {
  pwm_clear_irq(slice_num);

  // Safety: If system disabled, force 0
  if (!systemEnabled) {
    analogWrite(PUSHPULL_DRIVE_1, 0);
    analogWrite(PUSHPULL_DRIVE_2, 0);
    // Keep phasor running for PLL
    phasor += currentInc;
    if (phasor >= MAX_STEPS) phasor -= MAX_STEPS;
    return;
  }

  int current_step = (int)phasor;
  int32_t val = (sinetable[current_step] * amplitude) >> 8; 

  if (current_step > TRANSISTOR_SWITCH_STEP) {
    analogWrite(PUSHPULL_DRIVE_1, val);
    analogWrite(PUSHPULL_DRIVE_2, 0);
  } else {
    analogWrite(PUSHPULL_DRIVE_1, 0);
    analogWrite(PUSHPULL_DRIVE_2, val);
  }

  phasor += currentInc;
  if (phasor >= MAX_STEPS) phasor -= MAX_STEPS;
}

// ==========================================
// INTERRUPT 2: GRID SYNC
// ==========================================
void isr_grid_sync() {
  unsigned long now = millis();
  if ((now - last_sync_time) < 15) return;
  last_sync_time = now;

  // --- ZVS STARTUP LOGIC ---
  if (requestEnable) {
    digitalWrite(SHUTDOWN_PIN, HIGH); // Enable Drivers
    systemEnabled = true;             // Update State
    requestEnable = false;            // Clear Request
  }
  // -------------------------

  // PLL Logic
  float targetPhase = (sync_phase_shift / 360.0) * MAX_STEPS;
  float diff = targetPhase - phasor;

  if (diff > (MAX_STEPS / 2)) diff -= MAX_STEPS;
  else if (diff < -(MAX_STEPS / 2)) diff += MAX_STEPS;

  float Kp = 0.0003; 
  float targetInc = BASE_INC + (diff * Kp);
  
  currentInc = (currentInc * 0.90) + (targetInc * 0.10);
  lastPhaseError = diff;

  if (currentInc < 0.34) currentInc = 0.34;
  if (currentInc > 0.38) currentInc = 0.38;
}

// ==========================================
// SETUP & LOOP
// ==========================================
void setup() {
  // NO Serial.begin() here to prevent blocking!

  // LED Setup
  pinMode(STATUS_LED, OUTPUT);
  
  // PWM Setup
  analogWriteFreq(MODULATING_FREQ); 
  analogWriteRange(PWM_RES);        

  pinMode(PUSHPULL_DRIVE_1, OUTPUT);
  pinMode(PUSHPULL_DRIVE_2, OUTPUT);
  analogWrite(PUSHPULL_DRIVE_1, 0);
  analogWrite(PUSHPULL_DRIVE_2, 0);

  // Shutdown Pin (Start OFF)
  pinMode(SHUTDOWN_PIN, OUTPUT);
  digitalWrite(SHUTDOWN_PIN, LOW); 

  // Interrupts
  slice_num = pwm_gpio_to_slice_num(PUSHPULL_DRIVE_1);
  pwm_clear_irq(slice_num);
  pwm_set_irq_enabled(slice_num, true);
  irq_set_exclusive_handler(PWM_IRQ_WRAP, isr_pwm);
  irq_set_enabled(PWM_IRQ_WRAP, true);

  pinMode(ZC_INPUT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ZC_INPUT_PIN), isr_grid_sync, FALLING);
}

void loop() {
  unsigned long now = millis();

  // --- AUTO START LOGIC ---
  if (!autoStartTriggered && !systemEnabled) {
    if (now > AUTO_START_DELAY_MS) {
      requestEnable = true;   // Ask ISR to turn ON at next ZC
      autoStartTriggered = true; // Don't ask again
    }
  }

  // --- LED STATUS INDICATOR ---
  if (systemEnabled) {
    // SOLID ON = RUNNING
    digitalWrite(STATUS_LED, HIGH);
  } else {
    // BLINK = WAITING / LOCKING
    if (now - lastLedToggle > 500) {
      lastLedToggle = now;
      ledState = !ledState;
      digitalWrite(STATUS_LED, ledState);
    }
  }
}
Editor is loading...
Leave a Comment