Skip to main content

ESP32 Arduino perikelen PA-controller

   Must say I have not yet done the real test in my 4m PA  but I do not yet see why  this should not work

My 144PA 500W also uses an Arduino controller with a Nano and an OLED monochrome display. I initially programmed it myself, but later replaced the software with AI-generated code that runs in graphic mode, making it more efficient and compact.

PA controller: Power, bar, drive power, sequencer, drive level protection, supply V/A, temperature NTC, fan PWM control. The peak/hold feature took me some time to figure out—it seemed not to work, but eventually I realized the wrong variable was being displayed. No matter what I tried, it didn’t help. Then the AI pointed out, “You displayed the wrong variable.” Turns out the AI did that, but blamed me!! took me a lot of time...
 scary human behavior!


AI generated  a new PA controller software  very quick in a few hours I had a working system but it needed tuning character size and more.

During testing, a lot of strange things happened. I shorted the 3V2, and the display went out, and I couldn’t get it to work again. The ESP Mini’s very small onboard regulator, the LD3985 to the right of the USB connector, was damaged. The USB 5V goes through a low-drop diode to the low-drop LD3985, rated for max 6V and 180mA. I tested with external 3V3, and the ESP was still okay. To test WiFi, the 3V2 needs to supply 180mA and higher pulses, though normally it takes about 40–50mA. I’ll replace the LD3985 so it can be repaired. Another  thing I learned there is a 2nd 3V2 regulator onboard that lets the programm run like blink led  once it is loaded and connected with USB power. But to program it power the CH9102 USB /serial and external devices the LD3985 3V2 output is needed
 For some reason, the ST7789 wouldn’t display anymore; it seemed like the display was damaged, but a newly received ST7789 also didn’t work. That turned out to be bad soldering. I struggled quite a bit to get it to display again. The driver was suspected but turned out to be fine.  sketch code is below

 
Backside the 6206 in the Vcc regulator 6206   the top = middle pin is connected with Vcc   the regulator accept 3V3 but also 5V so Vcc can be 5V or even  higher  without damaging the display that is what I learned now by taking a deeper dive in the hardware since the hardware break  down.. After all the damage is only the the super smaal cheap lowdrop regulator , off coarse it needs to come from China since our electronic parts  make industrie i.e. Philips was closed down 25 years ago.. Sure it better to let it transport over the planet ...


//24-5-2026
//in één avond gemaakt met AI copilot  en ook nog even tot hier gekeken!
//board: ESP32 Dev Espressif Systems 2.0.18 ! NIET UPDATEN! moest DOWNGRADEN NAAR ESP32 CORE 2.0.14\
//ESP‑X32 toolchain. heeft een fout Omdat de ESP‑X32 toolchain nog geen LEDC‑PWM ondersteunt.
//genereerd 2 com ports de enhanced kiezen voor download
// testopstelling vergeten de 3V2V te isoleren LD3983 3V2 regulator SOT23-5 super klein defect ESPwerkte nog wel met externe 3V2
// Chip ESP32 mini ID test:
//ESP32 Chip model = ESP32-D0WDQ6 Rev 1
//This chip has 2 cores
//Chip ID: 3897936


#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>

// -------------------- TFT PINS --------------------
#define TFT_CS   5   // was 5  display werkt maar steeds niet
#define TFT_DC   2
#define TFT_RST  4

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// -------------------- IO PINS --------------------
#define PIN_NTC     13  //ADC   36 pin mist op deze ESP
#define PTT_IN      14
#define RELAY_TX    26
#define PA_ENABLE   27

#define PIN_FWD     32  //ADC
#define PIN_REF     33  //ADC
#define PIN_I_SENSE 34  //ADC input only
#define PIN_V_SENSE 35  //ADC input only

// FAN PWM
#define PIN_FAN_PWM 25  //PWM output
#define FAN_CHANNEL 0
#define FAN_FREQ    25000
#define FAN_RES     8

// -------------------- KALIBRATIE --------------------
float K_FWD = 200.0;
float K_REF = 20.0;
float K_I   = 5.0;
float K_V   = 20.0;

float SWR_LIMIT   = 3.0;
float TEMP_LIMIT  = 70.0;
float I_LIMIT     = 30.0;

float P_MAX = 500.0;
//float Pf = 0;   //globaal gemaakt ivm fout in peak maar de fout was in de display update de verkeerde power  waarde
float peakPower = 0;
unsigned long peakHoldTime = 0;
unsigned long peakHoldDuration = 1000;  // 500 ms hangtijd helaas werkt het niet
unsigned long lastDecayTime = 0;

bool fault = false;
String faultMsg = "";

// -------------------- HULPFUNCTIES --------------------

float readADCVoltage(int pin) {
  int raw = analogRead(pin);
  return (raw / 4095.0) * 3.3;
}

float readForwardPowerW() {
  return readADCVoltage(PIN_FWD) * K_FWD;
}

float readReflectedPowerW() {
  return readADCVoltage(PIN_REF) * K_REF;
}

float calcSWR(float Pf, float Pr) {
  if (Pf <= 0.1) return 1.0;
  float rho = sqrt(Pr / Pf);
  if (rho >= 1.0) rho = 0.999;
  return (1 + rho) / (1 - rho);
}

float readCurrentA() {
  return readADCVoltage(PIN_I_SENSE) * K_I;
}

float readVoltageV() {
  return readADCVoltage(PIN_V_SENSE) * K_V;
}

// ⭐ NTC 50k/50k Beta-formule
float readTempC() {
  float V = readADCVoltage(PIN_NTC);
  float Rntc = (V * 50000.0) / (3.3 - V);

  const float R0 = 50000.0;
  const float T0 = 298.15;
  const float B  = 3950.0;

  float invT = (1.0 / T0) + (1.0 / B) * log(Rntc / R0);
  float T = 1.0 / invT;

 // return T - 273.15;
  return 20,12;   //voor test zonder NTC

}

void setFanByTemp(float temp) {
  int duty = 0;
  if (temp < 35) duty = 0;
  else if (temp < 45) duty = 80;
  else if (temp < 55) duty = 150;
  else duty = 255;
  ledcWrite(FAN_CHANNEL, duty);
}

void setFanFull() {
  ledcWrite(FAN_CHANNEL, 255);
}

// -------------------- DISPLAY --------------------



void drawStaticLayout() {
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.println("PA CONTROLL  v1.0");

  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(1);
 
}

void drawBigPower(float P) {
  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
  tft.setTextSize(4);        // GROTE LETTERS
  tft.setCursor(20, 55);     // MOOIE POSITIE BOVEN DE BAR
  tft.printf("%4.0f W", P);
  tft.setTextSize(1);        // TERUG NAAR NORMAAL
}

void drawPowerBar(float P) {
 // oud int x = 80, y = 100, w = 140, h = 10;
int x = 20;     // meer naar links
int y = 90;    // lager op het scherm
int w = 200;    // veel breder
int h = 20;     // hogere bar

  tft.drawRect(x, y, w, h, ST77XX_WHITE);

  float ratio = P / P_MAX;
  if (ratio > 1) ratio = 1;
  if (ratio < 0) ratio = 0;

  int fill = w * ratio;

 uint16_t color = ST77XX_GREEN;

if (P >= 400 && P <= 500)
  color = ST77XX_YELLOW;

if (P > 500)
  color = ST77XX_RED;


  tft.fillRect(x + 1, y + 1, w - 2, h - 2, ST77XX_BLACK);
  if (fill > 0) tft.fillRect(x + 1, y + 1, fill - 2, h - 2, color);
}

void updateDisplay(float Pf, float Pr, float swr,
                   float V, float I, float temp,
                   bool tx, bool fault, String faultMsg) {

  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
 

  drawBigPower(Pf);

// Peak power rechtsboven naast de grote readout
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
tft.setCursor(150, 75);
//tft.printf("%4.0fW", peakPower);
tft.setTextSize(1);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);


  drawPowerBar(Pf);

 
tft.setTextSize(2);   // GROTER FONT

tft.setCursor(0, 130);
tft.printf("%4.1fW   %4.2f", Pr, swr);
tft.setCursor(0, 150);
tft.printf("%4.1fA  %4.0fV  %3.0fC", I, V, temp);


  tft.setCursor(10, 185);
  if (fault) tft.print("FULL");
  else if (temp < 35) tft.print("OFF ");
  else if (temp < 45) tft.print("LOW ");
  else if (temp < 55) tft.print("MID ");
  else tft.print("HIGH");

  tft.setCursor(10, 205);
  if (fault) {
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.print(faultMsg);
    tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
  } else tft.print("OK");

  tft.setCursor(60, 205);
  if (tx) {
    tft.setTextColor(ST77XX_YELLOW, ST77XX_RED);
    tft.print("TX");
  } else {
    tft.setTextColor(ST77XX_CYAN, ST77XX_BLACK);
    tft.print("RX");
  }
  tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
}

// -------------------- SEQUENCER --------------------

void goTX() {
  digitalWrite(RELAY_TX, HIGH);
  delay(20);
  digitalWrite(PA_ENABLE, HIGH);
}

void goRX() {
  digitalWrite(PA_ENABLE, LOW);
  delay(20);
  digitalWrite(RELAY_TX, LOW);
 

}

// -------------------- SETUP --------------------

void setup() {
  Serial.begin(115200);
 
  tft.init(240, 240);
  tft.setRotation(0);
  drawStaticLayout();

  pinMode(PTT_IN, INPUT_PULLUP);
  pinMode(RELAY_TX, OUTPUT);
  pinMode(PA_ENABLE, OUTPUT);

  digitalWrite(RELAY_TX, LOW);
  digitalWrite(PA_ENABLE, LOW);

  ledcSetup(FAN_CHANNEL, FAN_FREQ, FAN_RES);
  ledcAttachPin(PIN_FAN_PWM, FAN_CHANNEL);
  ledcWrite(FAN_CHANNEL, 0);

 

}

// -------------------- LOOP --------------------

void loop() {
  bool txState = (digitalRead(PTT_IN) == LOW);   // LOW = zenden
  static bool inTX = false;

  // --- EERST TX-STATUS UPDATEN ---
  if (txState && !fault) {
    if (!inTX) { goTX(); inTX = true; }
  } else {
    if (inTX) { goRX(); inTX = false; }
  }

  if (fault && inTX) {
    goRX();
    inTX = false;
  }

  // --- DAN PAS METEN --
  float Pf = readForwardPowerW();
 
  // --- PEAK HOLD LOGICA ---
  // Nieuwe hogere piek?
if (Pf > peakPower) {
// debug
 //Serial.print("Pf = ");
//Serial.print(Pf);
//Serial.print("   peakPower = ");
//Serial.println(peakPower);
// eind debug

    peakPower   = Pf;
    peakHoldTime = millis();   // hangtijd opnieuw starten

}
 else {
    // Geen nieuwe piek → alleen dan naar hangtijd/decay kijken
    if (millis() - peakHoldTime > peakHoldDuration) {
        if (millis() - lastDecayTime > 50) {   // elke 50 ms één stap
            peakPower *= 0.98;                 // decay
            if (peakPower < 0) peakPower = 0;
            lastDecayTime = millis();
        }

    }
}

  // --- REST VAN DE METINGEN ---
  float Pr   = readReflectedPowerW();
  float swr  = calcSWR(Pf, Pr);
  float I    = readCurrentA();
  float V    = readVoltageV();
  float temp = readTempC();

  fault = false;
  faultMsg = "";

  if (swr > SWR_LIMIT) { fault = true; faultMsg = "HIGH SWR"; }
  if (temp > TEMP_LIMIT) { fault = true; faultMsg = "OVERTEMP"; }
  if (I > I_LIMIT) { fault = true; faultMsg = "OVER CUR"; }

  if (fault) setFanFull();
  else setFanByTemp(temp);
/// peakPower ipv Pf lang gezocht naar fout in piekhold logica
  updateDisplay(peakPower, Pr, swr, V, I, temp, txState, fault, faultMsg);
}


Comments

Archive

Show more

Popular posts from this blog

IARU R1 70 MHz Contest Report. 19 20 Juli

 26 QSO in CW USB. Op zaterdag wat zwakke signalen uit Engeland, in de avond haast geen signalen meer. Dit was geen FT8 dat was duidelijk...  Op 70MHz is men in Engeland heel actief , voor een grote contest zoals deze IARU R1 24uur zoekt men daar goede locaties op zoals hier M0ICK/P IO84SA ik had QSO nr 4 Michael al 41! . Maar ook op de activity avonden op de Dinsdag avonden van de de maand zijn veel Engelse stations actief . Zo kon ik op de 2e dinsdag  van juni op 1 avond in een paar uur tijd 100QSO's op 70cm 432 MHz in CW USB hoofdzakelijk G's maar ook SM7 6 OZ SP OK DL   zoek  voor de agenda op : https://vhf-uhf.veron.nl/contesten/contestrobot/   On 70 MHz activity in England is very strong. For a major contest like the IARU R1 24‑hour , operators look for good locations, such as M0ICK/P IO84SA . I had QSO number 4, while Michael already had 41! But also during the activity evenings on Tuesday nights each month , many English stations are active. O...

2011-01-22 DIAMOND 2m 70cm 1m30 Colinear inside

Having relative poor signals on the local 70cm / 2m channels using this X50 Diamond collinear 70/2  1m antenna at a height of 25m. I needed to investigate what could be wrong. Measuring the cable only 3W is left for the antenna of the 10W 435MHz output from a IC451E The cable is 30m type H100 Z50 10mm outside diameter it is semi air-spaced but has an impossible 4mm² solid CU inner conductor not much air left. I preferred the H43 Z75 cable having lower loss and mechanical better ratio in conductor size. My antenna uses SO239 connector UHF type semi air spaced isolator.  3W should be enough for a comfortable noise free FM signal. But only 27km away at PA0A the signal is weak too weak something must be wrong? I made a simple reference dipole of 2x17cm CU wire. With this dipole the signals where totally worse. So the Diamond does work? I got curious to look inside. Maybe moisture penetration degraded the antenna. This  antenna is rainwater close in its n...

SPF5189z Low noise preamp 23cm

 14-4-2018 updated Above the low noise  preamp 50 - 4GHz    ebay  6€ Tested  2 small porto antennas 1 Baofeng UV antenna left   2nd best signal on PI2NOS 2 eBay DIAMONDSRH805S  wide band 144/432/1200  it works for its size as expected 3 piece of wire :   best signal in the setup... Unit under test at workbench. It was stable  50mA  at 5V   few days,  but sudden the current went up to 100mA And i could  no longer adjust it with the negative bias Voltage. The - Voltage went to zero and the SPF input port became low Z. This SPF5189z was broken  no oscillations, no input overload just it broke while i was receiving the PI2NOS 430.125 using a small antenna at the workbench. The specs of  SPF5189z  say it has an internal circuit  regulating the bias current. Replaced . again   with an other of the 5 spare SPF i have. The new one again could be adjuste...