lpt-signal-generator: calibration
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 11 Jun 2017 03:05:27 +0200
changeset 49e1e5db678ce8
parent 48 254d5d1bc659
child 50 75edae164ebc
lpt-signal-generator: calibration
c++/lpt-signal-generator/lpt.cpp
     1.1 --- a/c++/lpt-signal-generator/lpt.cpp	Sun Jun 11 01:25:56 2017 +0200
     1.2 +++ b/c++/lpt-signal-generator/lpt.cpp	Sun Jun 11 03:05:27 2017 +0200
     1.3 @@ -54,10 +54,14 @@
     1.4     */
     1.5    setlocale(LC_ALL,"");
     1.6  
     1.7 +
     1.8 +  // configuration ----
     1.9    int addr = 0xe400; // parallel port address; first number of given port in: cat /proc/ioports | grep parport
    1.10    int baseFreq = 10000; // base frequency in Hz, should be between 5 000 between 10 000 Hz; lower frequency leads to dashed/dotted lines instead of greyscale
    1.11    int outputPower = 20; // duty cycle; 100 = 100 %
    1.12    int duration = 1; // in seconds; total sleep time, see note above
    1.13 +  // ------------------
    1.14 +
    1.15  
    1.16    int valueWidth =  10; // just for padding of printed values
    1.17    int labelWidth = -15; // just for padding of printed labels
    1.18 @@ -74,9 +78,6 @@
    1.19    int timeOn =  oneSecond *        outputPower  / 100 / baseFreq;
    1.20    int timeOff = oneSecond * (100 - outputPower) / 100 / baseFreq;
    1.21  
    1.22 -  timeOn  -= 13;
    1.23 -  timeOff -= 13;
    1.24 -
    1.25    int cycleCount = duration * baseFreq;
    1.26    wprintf(L"%*ls %'*d ×\n", labelWidth, L"Cycle count:", valueWidth, cycleCount);
    1.27    wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Time on:",  valueWidth, timeOn);
    1.28 @@ -84,12 +85,67 @@
    1.29  
    1.30    //wprintf(L"%*ls %*ls\n", labelWidth, L"unicode test:", valueWidth, L"čeština → …");
    1.31  
    1.32 +  wprintf(L"\n");
    1.33  
    1.34    if (ioperm(addr,1,1)) { fwprintf(stderr, L"Access denied to port %#x\n", addr), exit(1); }
    1.35  
    1.36 -  outb(0b00000000, addr);
    1.37  
    1.38 +  // calibration
    1.39    auto startTimestamp = chrono::high_resolution_clock::now();
    1.40 +  auto calibrationCycles = 10000;
    1.41 +  auto calibrationSleepTime = 10;
    1.42 +
    1.43 +  for (int i = 0; i < calibrationCycles; i++) {
    1.44 +    outb(0b00000000, addr);
    1.45 +    usleep(calibrationSleepTime);
    1.46 +    outb(0b00000000, addr);
    1.47 +    usleep(calibrationSleepTime);
    1.48 +  }
    1.49 +
    1.50 +  auto finishTimestamp = chrono::high_resolution_clock::now();
    1.51 +  auto measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
    1.52 +
    1.53 +  auto singleOutbCostNano = (measuredDuration - calibrationCycles*2*calibrationSleepTime*1000)/calibrationCycles/2;
    1.54 +  auto singleOutbCostMicro = singleOutbCostNano/1000;
    1.55 +
    1.56 +  wprintf(L"%*ls %'*d μs 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostMicro);
    1.57 +  wprintf(L"%*ls %'*d ns 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostNano);
    1.58 +
    1.59 +  auto minPower = 100*singleOutbCostNano/(1000*1000*1000/baseFreq);
    1.60 +  auto maxPower = 100-minPower;
    1.61 +  wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Minimum power:", valueWidth, minPower);
    1.62 +  wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Maximum power:", valueWidth, maxPower);
    1.63 +
    1.64 +  if (singleOutbCostMicro < timeOn && singleOutbCostMicro < timeOff) {
    1.65 +    wprintf(L"%*ls %*ls both frequency and duty cycle should be correct\n",  labelWidth, L"Calibration:", valueWidth, L"OK");
    1.66 +    timeOn  -= singleOutbCostMicro;
    1.67 +    timeOff -= singleOutbCostMicro;
    1.68 +  } else if (2*singleOutbCostMicro < (timeOn + timeOff)) {
    1.69 +    wprintf(L"%*ls %*ls frequency should be OK, but duty cycle is not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"WARNING");
    1.70 +    timeOn  -= singleOutbCostMicro;
    1.71 +    timeOff -= singleOutbCostMicro;
    1.72 +
    1.73 +    if (timeOn < 0) {
    1.74 +      timeOff -= timeOn;
    1.75 +      timeOn = 0;
    1.76 +    } else {
    1.77 +      timeOn -= timeOff;
    1.78 +      timeOff = 0;
    1.79 +    }
    1.80 +  } else {
    1.81 +    wprintf(L"%*ls %*ls both frequency and duty cycle are not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"ERROR");
    1.82 +    timeOn  = 0;
    1.83 +    timeOff = 0;
    1.84 +  }
    1.85 +
    1.86 +  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep on:",  valueWidth, timeOn);
    1.87 +  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep off:", valueWidth, timeOff);
    1.88 +
    1.89 +  wprintf(L"\n");
    1.90 +
    1.91 +
    1.92 +  // actual signal generation
    1.93 +  startTimestamp = chrono::high_resolution_clock::now();
    1.94  
    1.95    for (int i = 0; i < cycleCount; i++) {
    1.96      outb(0b00000001, addr); // first data out pin = data out 0 = pin 2 on DB-25 connector
    1.97 @@ -98,10 +154,10 @@
    1.98      usleep(timeOff);
    1.99    }
   1.100  
   1.101 -  auto finishTimestamp = chrono::high_resolution_clock::now();
   1.102 -  auto measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.103 +  finishTimestamp = chrono::high_resolution_clock::now();
   1.104 +  measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.105  
   1.106 -  wprintf(L"%*ls %'*d μs 2× in each cycle\n", labelWidth, L"single outb():", valueWidth, (measuredDuration-duration*oneSecond*1000)/cycleCount/2/1000);
   1.107 -  wprintf(L"%*ls %'*d ns 2× in each cycle\n", labelWidth, L"single outb():", valueWidth, (measuredDuration-duration*oneSecond*1000)/cycleCount/2);
   1.108 +  wprintf(L"%*ls %'*d μs in total\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/1000);
   1.109 +  wprintf(L"%*ls %'*d ns in each cycle\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/cycleCount);
   1.110  
   1.111  }