/*
* ESP32 3-Phase SPWM - WOKWI PERFECT (NO WATCHDOG)
*/
#include <Arduino.h>
// ========== PIN ==========
const int pinU = 12, pinV = 14, pinW = 27;
const int pinButton = 13, pinPot = 34;
// ========== PWM ==========
const int pwmFreq = 5000, pwmRes = 8;
const float sinusFreq = 50.0;
const int LUT_SIZE = 256;
uint8_t sinLUT[LUT_SIZE];
volatile bool isRunning = false;
volatile float amplitude = 0.0, phase = 0.0;
// ========== SINUS LUT ==========
void initSinLUT() {
for (int i = 0; i < LUT_SIZE; i++) {
sinLUT[i] = (uint8_t)((sin(2 * PI * i / LUT_SIZE) + 1.0) * 127.5);
}
Serial.println("SinLUT OK");
}
inline uint8_t getSin(uint16_t idx) {
return sinLUT[idx & (LUT_SIZE - 1)];
}
// ========== PWM ==========
void setupPWM() {
ledcAttach(pinU, pwmFreq, pwmRes);
ledcAttach(pinV, pwmFreq, pwmRes);
ledcAttach(pinW, pwmFreq, pwmRes);
Serial.println("PWM OK");
}
// ========== TIMER ==========
hw_timer_t *timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
if (isRunning) {
phase += 2 * PI * sinusFreq / pwmFreq;
if (phase >= 2 * PI) phase -= 2 * PI;
uint16_t idx = (uint16_t)(phase / (2 * PI) * LUT_SIZE);
uint8_t sinU = getSin(idx);
uint8_t sinV = getSin(idx + LUT_SIZE / 3);
uint8_t sinW = getSin(idx + 2 * LUT_SIZE / 3);
ledcWrite(pinU, (uint8_t)(sinU * amplitude));
ledcWrite(pinV, (uint8_t)(sinV * amplitude));
ledcWrite(pinW, (uint8_t)(sinW * amplitude));
} else {
ledcWrite(pinU, 0); ledcWrite(pinV, 0); ledcWrite(pinW, 0);
}
portEXIT_CRITICAL_ISR(&timerMux);
}
void setupTimer() {
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 200, true, 0); // 5kHz
Serial.println("Timer 5kHz OK");
}
// ========== TASKS ==========
void readPotTask(void *pv) {
int last = 0;
while (1) {
int raw = analogRead(pinPot);
last = (last * 7 + raw) >> 3;
amplitude = last / 4095.0;
vTaskDelay(pdMS_TO_TICKS(20));
}
}
void buttonTask(void *pv) {
bool lastState = HIGH;
while (1) {
bool state = digitalRead(pinButton);
if (lastState == HIGH && state == LOW) {
isRunning = !isRunning;
Serial.printf(">>> %s >>>\n", isRunning ? "START" : "STOP");
}
lastState = state;
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// ========== SETUP ==========
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== 3-PHASE SPWM WOKWI PERFECT ===");
initSinLUT();
setupPWM();
setupTimer();
pinMode(pinButton, INPUT_PULLUP);
// TASKS
xTaskCreatePinnedToCore(readPotTask, "Pot", 2048, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(buttonTask, "Btn", 2048, NULL, 1, NULL, 0);
Serial.println("🚀 READY! Pin13=BTN Pin34=POT");
}
// ========== LOOP ==========
void loop() {
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 2000) {
lastPrint = millis();
Serial.printf("STATUS: %s | AMP: %.1f%% | PHASE: %.2f\n",
isRunning?"RUN":"STOP", amplitude*100, phase);
}
delay(10);
}