Browse Source

Fix PWM offset comptutation

Kevin Lee 2 years ago
parent
commit
d99e0b6588
2 changed files with 48 additions and 90 deletions
  1. 46 90
      Nixie_Firmware_Mbed/main.cpp
  2. 2 0
      Nixie_Firmware_Mbed/pca9685.cpp

+ 46 - 90
Nixie_Firmware_Mbed/main.cpp

@@ -85,105 +85,61 @@ TUBE_CALLBACK(2)
 Timeout Tube3UpdateTimeout;
 TUBE_CALLBACK(3)
 
-// In the event that there are multiple PWM outputs at less than 100% duty cycle,
-// stagger the start time of each PWM to reduce the switch on surge current.
-void ComputePwmOffsets() {
-    int validOutputs = 0;
-    int totalOnTime = 0;
-    int lastPwmEnd = 0;
-
-    // Determine the number of active outputs as well as the total on-time across all outputs.
-    // Ignore outputs that are off (min) or fully on (max) as they have no surge impact.
+void UpdatePwm(Digit *digit, int *lastPwm, bool *increment) {
     for (int i = 0; i < NUM_TUBES; i++) {
         for (int j = 0; j < NUM_DIGITS; j++) {
-            if (Tubes[i].Digits[j].Value != PCA9685_Min_Brightness && 
-                Tubes[i].Digits[j].Value != PCA9685_Max_Brightness) {
-
-                validOutputs++;
-                totalOnTime += Tubes[i].Digits[j].Value;
+            if (digit->Value == PCA9685_Min_Brightness) {
+                digit->PwmStart = 0;
+                digit->PwmEnd = 0;
             }
-        }
-    }
-    if (Dot.Value != PCA9685_Min_Brightness && Dot.Value != PCA9685_Max_Brightness) {
-        validOutputs++;
-        totalOnTime += Dot.Value;
-    }
-
-    // If the total on-time across all outputs is less than one PWM period, stagger each
-    // output such that the rise of one pulse begins at the end of the previous pulse.
-    if (totalOnTime <= PCA9685_Max_Brightness) {
-
-        for (int i = 0; i < NUM_TUBES; i++) {
-            for (int j = 0; j < NUM_DIGITS; j++) {
-                if (Tubes[i].Digits[j].Value == PCA9685_Min_Brightness) {
-                    Tubes[i].Digits[j].PwmStart = 0;
-                    Tubes[i].Digits[j].PwmEnd = 0;
-                }
-                else if (Tubes[i].Digits[j].Value == PCA9685_Max_Brightness) {
-                    Tubes[i].Digits[j].PwmStart = 0;
-                    Tubes[i].Digits[j].PwmEnd = PCA9685_Max_Brightness;
-                }
-                else {
-                    Tubes[i].Digits[j].PwmStart = lastPwmEnd;
-                    Tubes[i].Digits[j].PwmEnd = lastPwmEnd + Tubes[i].Digits[j].Value;
-                    lastPwmEnd = Tubes[i].Digits[j].PwmEnd;
-                    Tubes[i].Digits[j].Updated = true;
-                }
+            else if (digit->Value == PCA9685_Max_Brightness) {
+                digit->PwmStart = 0;
+                digit->PwmEnd = PCA9685_Max_Brightness;
             }
-        }
-        if (Dot.Value == PCA9685_Min_Brightness) {
-            Dot.PwmStart = 0;
-            Dot.PwmEnd = 0;
-        }
-        else if (Dot.Value == PCA9685_Max_Brightness) {
-            Dot.PwmStart = 0;
-            Dot.PwmEnd = PCA9685_Max_Brightness;
-        }
-        else {
-            Dot.PwmStart = lastPwmEnd;
-            Dot.PwmEnd = lastPwmEnd + Dot.Value;
-            lastPwmEnd = Dot.PwmEnd;
-            Dot.Updated = true;
-        }
-    }
-    else {
-        // Compute the amount of overlap between all outputs
-        int overlap = (totalOnTime - PCA9685_Max_Brightness) / (validOutputs - 1);
-
-        // Compute the staggered output period for each output
-        for (int i = 0; i < NUM_TUBES; i++) {
-            for (int j = 0; j < NUM_DIGITS; j++) {
-                if (Tubes[i].Digits[j].Value == PCA9685_Min_Brightness) {
-                    Tubes[i].Digits[j].PwmStart = 0;
-                    Tubes[i].Digits[j].PwmEnd = 0;
-                }
-                else if (Tubes[i].Digits[j].Value == PCA9685_Max_Brightness) {
-                    Tubes[i].Digits[j].PwmStart = 0;
-                    Tubes[i].Digits[j].PwmEnd = PCA9685_Max_Brightness;
-                }
-                else {
-                    Tubes[i].Digits[j].PwmStart = (lastPwmEnd - overlap < 0) ? 0 : lastPwmEnd - overlap;
-                    Tubes[i].Digits[j].PwmEnd = Tubes[i].Digits[j].PwmStart + Tubes[i].Digits[j].Value;
-                    lastPwmEnd = Tubes[i].Digits[j].PwmEnd;
-                    Tubes[i].Digits[j].Updated = true;
+            else {
+                if (*increment) {
+                    if (*lastPwm + digit->Value > PCA9685_Max_Brightness) {
+                        digit->PwmStart = PCA9685_Max_Brightness - digit->Value;
+                        digit->PwmEnd = PCA9685_Max_Brightness;
+                        *lastPwm = digit->PwmStart;
+                        *increment = false;
+                    } else {
+                        digit->PwmStart = *lastPwm;
+                        digit->PwmEnd = digit->PwmStart + digit->Value;
+                        *lastPwm = digit->PwmEnd;
+                    }
+                } else {
+                    if (*lastPwm - PCA9685_Min_Brightness < digit->Value) {
+                        digit->PwmStart = PCA9685_Min_Brightness;
+                        digit->PwmEnd = digit->PwmStart + digit->Value;
+                        *lastPwm = digit->PwmEnd;
+                        *increment = true;
+                    } else {
+                        digit->PwmEnd = *lastPwm;
+                        digit->PwmStart = digit->PwmEnd - digit->Value;
+                        *lastPwm = digit->PwmStart;
+                    }
                 }
+                digit->Updated = true;
             }
         }
-        if (Dot.Value == PCA9685_Min_Brightness) {
-            Dot.PwmStart = 0;
-            Dot.PwmEnd = 0;
-        }
-        else if (Dot.Value == PCA9685_Max_Brightness) {
-            Dot.PwmStart = 0;
-            Dot.PwmEnd = PCA9685_Max_Brightness;
-        }
-        else {
-            Dot.PwmStart = (lastPwmEnd - overlap < 0) ? 0 : lastPwmEnd - overlap;
-            Dot.PwmEnd = Dot.PwmStart + Dot.Value;
-            lastPwmEnd = Dot.PwmEnd;
-            Dot.Updated = true;
+    }
+}
+
+// In the event that there are multiple PWM outputs at less than 100% duty cycle,
+// stagger the start time of each PWM to reduce the switch on surge current. If the
+// duty cycle is greater than 100%, distribute the PWM outputs as much as possible
+// to keep the current consumption at a minimum.
+void ComputePwmOffsets() {
+    int lastPwm = 0;
+    bool increment = true;
+
+    for (int i = 0; i < NUM_TUBES; i++) {
+        for (int j = 0; j < NUM_DIGITS; j++) {
+            UpdatePwm(&Tubes[i].Digits[j], &lastPwm, &increment);
         }
     }
+    UpdatePwm(&Dot, &lastPwm, &increment);
 }
 
 void FadeInOutDigit(int T, int D, int Duration, bool RngUpdate = false) {

+ 2 - 0
Nixie_Firmware_Mbed/pca9685.cpp

@@ -107,6 +107,8 @@ void PCA9685_SetDotPwm(int StartPwm, int EndPwm) {
         reg.ON_FULL = 1;
     } else if (EndPwm == 0) {
         reg.OFF_FULL = 1;
+    } else if (EndPwm >= PCA9685_Max_Brightness) {
+        reg.OFF = 0xFFF;
     }
 
     I2C_Write(TUBE_DOT_ADDR, FIELD_OFFSET(PCA9685_REGS, TUBE_DOT_PIN), reg.AS_BYTE, sizeof(LED_CTRL));