|
@@ -9,151 +9,216 @@ |
|
|
#include <time.h> |
|
|
#include <time.h> |
|
|
#include <stdint.h> |
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
int PWM0[2] = {18, 12}; |
|
|
|
|
|
int PWM0_IN[2] = {17, 13}; |
|
|
|
|
|
int PWM1[2] = {13, 19}; |
|
|
|
|
|
int PWM1_IN[2] = {12, 16}; |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
int PWM0 = 12; |
|
|
|
|
|
int FREQIN = 6; |
|
|
|
|
|
|
|
|
int PWM_OUT[4] = { 18, 12, 13, 19 }; |
|
|
|
|
|
int PWM_IN[4] = { 17, 13, 12, 16 }; |
|
|
|
|
|
|
|
|
volatile int gCounter = 0; |
|
|
volatile int gCounter = 0; |
|
|
|
|
|
|
|
|
//Interrupt Service Routine for FREQIN |
|
|
//Interrupt Service Routine for FREQIN |
|
|
void ISR_FREQIN(void) { |
|
|
void ISR_FREQIN(void) { |
|
|
gCounter++; |
|
|
|
|
|
|
|
|
gCounter++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
double MeasureAndCheckFreq(const char* msg, double expect_freq) { |
|
|
double MeasureAndCheckFreq(const char* msg, double expect_freq) { |
|
|
double fFrequency; |
|
|
|
|
|
clock_t CPUClockBegin, CPUClockEnd; |
|
|
|
|
|
int CountBegin, CountEnd; |
|
|
|
|
|
double CPUClockInterval, CountInterval; |
|
|
|
|
|
double elapsed_time, CPULoad; |
|
|
|
|
|
|
|
|
double fFrequency; |
|
|
|
|
|
clock_t CPUClockBegin, CPUClockEnd; |
|
|
|
|
|
int CountBegin, CountEnd; |
|
|
|
|
|
double CPUClockInterval, CountInterval; |
|
|
|
|
|
double elapsed_time, CPULoad; |
|
|
uint64_t tbegin, tend; |
|
|
uint64_t tbegin, tend; |
|
|
int SleepMs = 1200; |
|
|
int SleepMs = 1200; |
|
|
|
|
|
|
|
|
CPUClockBegin = clock(); |
|
|
CPUClockBegin = clock(); |
|
|
tbegin = piMicros64(); |
|
|
|
|
|
|
|
|
tbegin = piMicros64(); |
|
|
CountBegin = gCounter; |
|
|
CountBegin = gCounter; |
|
|
delay(SleepMs); |
|
|
delay(SleepMs); |
|
|
CountEnd = gCounter; |
|
|
CountEnd = gCounter; |
|
|
CPUClockEnd = clock(); |
|
|
CPUClockEnd = clock(); |
|
|
tend = piMicros64(); |
|
|
|
|
|
|
|
|
tend = piMicros64(); |
|
|
|
|
|
|
|
|
elapsed_time = (double)(tend-tbegin)/1.0e6; |
|
|
elapsed_time = (double)(tend-tbegin)/1.0e6; |
|
|
CountInterval = CountEnd - CountBegin; |
|
|
CountInterval = CountEnd - CountBegin; |
|
|
CPUClockInterval = CPUClockEnd - CPUClockBegin; |
|
|
|
|
|
|
|
|
CPUClockInterval = CPUClockEnd - CPUClockBegin; |
|
|
CPULoad = CPUClockInterval*100.0 / CLOCKS_PER_SEC / elapsed_time; |
|
|
CPULoad = CPUClockInterval*100.0 / CLOCKS_PER_SEC / elapsed_time; |
|
|
fFrequency = CountInterval / elapsed_time / 1000; |
|
|
fFrequency = CountInterval / elapsed_time / 1000; |
|
|
|
|
|
|
|
|
printf("Interval: time: %.6f sec (CPU: %3.1f %%), count: %g -> frequency: %.3f kHz\n", |
|
|
|
|
|
|
|
|
printf("\nInterval: time: %.6f sec (CPU: %3.1f %%), count: %g -> frequency: %.3f kHz\n", |
|
|
elapsed_time, CPULoad, CountInterval, fFrequency); |
|
|
elapsed_time, CPULoad, CountInterval, fFrequency); |
|
|
|
|
|
|
|
|
CheckSameDouble("Wait for freq. meas.", elapsed_time, SleepMs/1000.0, 0.1); //100ms tolerance. maybe problematic on high freq/cpu load |
|
|
|
|
|
CheckSameDouble(msg, fFrequency, expect_freq, expect_freq*2/100); //2% tolerance |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CheckSameDouble("Wait for freq. meas.", elapsed_time, SleepMs/1000.0, 0.1); //100ms tolerance. maybe problematic on high freq/cpu load |
|
|
|
|
|
CheckSameDouble(msg, fFrequency, expect_freq, expect_freq*2/100); //2% toleranc |
|
|
return fFrequency; |
|
|
return fFrequency; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int tests_pwmc[7] = {1456, 1000, 512, 100, 2000, 3000, 4000}; |
|
|
int tests_pwmc[7] = {1456, 1000, 512, 100, 2000, 3000, 4000}; |
|
|
int tests_duty[7] = { 512, 768, 682, 922, 256, 341, 102}; |
|
|
int tests_duty[7] = { 512, 768, 682, 922, 256, 341, 102}; |
|
|
int tests_pwmr[10]= { 100, 512, 1024, 1456, 2000, 3000, 5000, 10000, 15000, 20000}; |
|
|
|
|
|
|
|
|
int tests_pwmr[12]= { 50, 100, 200, 512, 1024, 1456, 2000, 3000, 5000, 10000, 15000, 20000}; |
|
|
|
|
|
int tests_pwm[3] = { 50, 25, 75}; |
|
|
|
|
|
|
|
|
int main (void) { |
|
|
int main (void) { |
|
|
|
|
|
|
|
|
int major, minor; |
|
|
|
|
|
char msg[255]; |
|
|
|
|
|
|
|
|
|
|
|
wiringPiVersion(&major, &minor); |
|
|
|
|
|
|
|
|
|
|
|
printf("WiringPi GPIO test program 9 (using PWM@GPIO%d (output) and GPIO%d (input))\n", PWM0, FREQIN); |
|
|
|
|
|
printf(" pwm0 irq time\n"); |
|
|
|
|
|
|
|
|
|
|
|
printf("\nPWM/ISR test (WiringPi %d.%d)\n", major, minor); |
|
|
|
|
|
|
|
|
|
|
|
wiringPiSetupGpio() ; |
|
|
|
|
|
|
|
|
|
|
|
int rev, mem, maker, overVolted, RaspberryPiModel; |
|
|
|
|
|
piBoardId(&RaspberryPiModel, &rev, &mem, &maker, &overVolted); |
|
|
|
|
|
CheckNotSame("Model: ", RaspberryPiModel, -1); |
|
|
|
|
|
|
|
|
int major, minor; |
|
|
|
|
|
char msg[255]; |
|
|
|
|
|
int testruns = 4; |
|
|
|
|
|
int PWM, FREQIN; |
|
|
|
|
|
|
|
|
|
|
|
wiringPiVersion(&major, &minor); |
|
|
|
|
|
|
|
|
|
|
|
printf("WiringPi GPIO test program 9\n"); |
|
|
|
|
|
printf("PWM/ISR test (WiringPi %d.%d)\n", major, minor); |
|
|
|
|
|
|
|
|
|
|
|
wiringPiSetupGpio() ; |
|
|
|
|
|
|
|
|
|
|
|
int rev, mem, maker, overVolted, RaspberryPiModel; |
|
|
|
|
|
piBoardId(&RaspberryPiModel, &rev, &mem, &maker, &overVolted); |
|
|
|
|
|
CheckNotSame("Model: ", RaspberryPiModel, -1); |
|
|
|
|
|
int Pi4 = 0; |
|
|
|
|
|
double MaxFreq = 100.0; |
|
|
|
|
|
switch(RaspberryPiModel) { |
|
|
|
|
|
case PI_MODEL_A: |
|
|
|
|
|
case PI_MODEL_B: |
|
|
|
|
|
case PI_MODEL_BP: |
|
|
|
|
|
case PI_MODEL_AP: |
|
|
|
|
|
case PI_MODEL_ZERO: |
|
|
|
|
|
case PI_MODEL_ZERO_W: |
|
|
|
|
|
case PI_MODEL_CM: |
|
|
|
|
|
MaxFreq = 13.0; // 12.5 kHz -> ~40% CPU@800 MHz |
|
|
|
|
|
printf(" - Pi1/BCM2835 detected, will skip tests with frequency above %g kHz\n", MaxFreq); |
|
|
|
|
|
break; |
|
|
|
|
|
case PI_MODEL_2: |
|
|
|
|
|
MaxFreq = 20.0; |
|
|
|
|
|
printf(" - Pi2/BCM2836 detected, will skip tests with frequency above %g kHz\n", MaxFreq); |
|
|
|
|
|
break; |
|
|
|
|
|
case PI_MODEL_3B: |
|
|
|
|
|
case PI_MODEL_CM3: |
|
|
|
|
|
case PI_MODEL_3BP: |
|
|
|
|
|
case PI_MODEL_3AP: |
|
|
|
|
|
case PI_MODEL_CM3P: |
|
|
|
|
|
case PI_MODEL_ZERO_2W: |
|
|
|
|
|
MaxFreq = 50.0; |
|
|
|
|
|
printf(" - Pi3/BCM2837 detected, will skip tests with frequency above %g kHz\n", MaxFreq); |
|
|
|
|
|
break; |
|
|
|
|
|
case PI_MODEL_4B: |
|
|
|
|
|
case PI_MODEL_400: |
|
|
|
|
|
case PI_MODEL_CM4: |
|
|
|
|
|
case PI_MODEL_CM4S: |
|
|
|
|
|
Pi4 = 1; |
|
|
|
|
|
break; |
|
|
|
|
|
case PI_MODEL_5: |
|
|
|
|
|
return UnitTestState(); //not supported so far |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (!piBoard40Pin()) { |
|
|
|
|
|
PWM0 = 18; |
|
|
|
|
|
FREQIN = 17; |
|
|
|
|
|
} |
|
|
|
|
|
// INT_EDGE_BOTH, INT_EDGE_FALLING, INT_EDGE_RISING only one ISR per input |
|
|
|
|
|
int result = wiringPiISR(FREQIN, INT_EDGE_RISING, &ISR_FREQIN); |
|
|
|
|
|
CheckSame("Register ISR", result, 0); |
|
|
|
|
|
if (result < 0) { |
|
|
|
|
|
printf("Unable to setup ISR for GPIO %d (%s)\n\n", |
|
|
|
|
|
FREQIN, strerror(errno)); |
|
|
|
|
|
return UnitTestState(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int Pi4 = 0; |
|
|
|
|
|
switch(RaspberryPiModel) { |
|
|
|
|
|
case PI_MODEL_4B: |
|
|
|
|
|
case PI_MODEL_400: |
|
|
|
|
|
case PI_MODEL_CM4: |
|
|
|
|
|
case PI_MODEL_CM4S: |
|
|
|
|
|
Pi4 = 1; |
|
|
|
|
|
break; |
|
|
|
|
|
case PI_MODEL_5: |
|
|
|
|
|
return UnitTestState(); //not supported so far |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("\nPWM0 BAL mode:\n"); |
|
|
|
|
|
printf("==============\n"); |
|
|
|
|
|
|
|
|
|
|
|
pinMode(PWM0, PWM_OUTPUT); //pwmr=1024, pwmc=32 |
|
|
|
|
|
const int pmw = 512; |
|
|
|
|
|
int pmwr = 1024; |
|
|
|
|
|
pwmWrite(PWM0, pmw); //50% Duty |
|
|
|
|
|
//MeasureAndCheckFreq("50\% Duty (default)", 300.000); //FAIL , freq (pwmc=32) to high for irq count |
|
|
|
|
|
|
|
|
|
|
|
for (int c_duty=0, c_duty_end = sizeof(tests_duty)/sizeof(tests_duty[0]); c_duty<c_duty_end; c_duty++) { |
|
|
|
|
|
|
|
|
|
|
|
double tests_duty_corr; |
|
|
|
|
|
if (tests_duty[c_duty]>(pmwr/2)) { |
|
|
|
|
|
tests_duty_corr = pmwr-tests_duty[c_duty]; |
|
|
|
|
|
} else { |
|
|
|
|
|
tests_duty_corr = tests_duty[c_duty]; |
|
|
|
|
|
|
|
|
if (!piBoard40Pin()) { |
|
|
|
|
|
testruns = 1; // only fist PWM0, supported |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
double duty_fact = tests_duty_corr/(double)pmwr; |
|
|
|
|
|
printf("\n%d/%d set duty %d/%d\n",c_duty+1, c_duty_end, tests_duty[c_duty], pmwr); |
|
|
|
|
|
pwmWrite(PWM0, tests_duty[c_duty]); |
|
|
|
|
|
|
|
|
|
|
|
for (int c_pwmc=0, end = sizeof(tests_pwmc)/sizeof(tests_pwmc[0]); c_pwmc<end; c_pwmc++) { |
|
|
|
|
|
if (Pi4 && tests_pwmc[c_pwmc]>1456) { |
|
|
|
|
|
printf("* Set Clock (pwmc) %d not possible on BCM2711 system (OSC 54 MHz), ignore\n", tests_pwmc[c_pwmc]); |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
for (int testrun=0; testrun<testruns; testrun++) { |
|
|
|
|
|
PWM = PWM_OUT[testrun]; |
|
|
|
|
|
FREQIN = PWM_IN[testrun]; |
|
|
|
|
|
|
|
|
|
|
|
printf("using PWM@GPIO%d (output) and GPIO%d (input))\n", PWM, FREQIN); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// INT_EDGE_BOTH, INT_EDGE_FALLING, INT_EDGE_RISING only one ISR per input |
|
|
|
|
|
int result = wiringPiISR(FREQIN, INT_EDGE_RISING, &ISR_FREQIN); |
|
|
|
|
|
CheckSame("Register ISR", result, 0); |
|
|
|
|
|
if (result < 0) { |
|
|
|
|
|
printf("Unable to setup ISR for GPIO %d (%s)\n\n", |
|
|
|
|
|
FREQIN, strerror(errno)); |
|
|
|
|
|
return UnitTestState(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
printf("*********************************\n"); |
|
|
|
|
|
printf("* PWM BAL mode *\n"); |
|
|
|
|
|
printf("*********************************\n"); |
|
|
|
|
|
pinMode(PWM, PWM_OUTPUT); //pwmr=1024, pwmc=32 |
|
|
|
|
|
const int pmw = 512; |
|
|
|
|
|
int pmwr = 1024; |
|
|
|
|
|
pwmWrite(PWM, pmw); //50% Duty |
|
|
|
|
|
//MeasureAndCheckFreq("50\% Duty (default)", 300.000); //FAIL , freq (pwmc=32) to high for irq count |
|
|
|
|
|
|
|
|
|
|
|
for (int c_duty=0, c_duty_end = sizeof(tests_duty)/sizeof(tests_duty[0]); c_duty<c_duty_end; c_duty++) { |
|
|
|
|
|
double tests_duty_corr; |
|
|
|
|
|
if (tests_duty[c_duty]>(pmwr/2)) { |
|
|
|
|
|
tests_duty_corr = pmwr-tests_duty[c_duty]; |
|
|
|
|
|
} else { |
|
|
|
|
|
tests_duty_corr = tests_duty[c_duty]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double duty_fact = tests_duty_corr/(double)pmwr; |
|
|
|
|
|
printf("\n%d/%d set duty %d/%d\n",c_duty+1, c_duty_end, tests_duty[c_duty], pmwr); |
|
|
|
|
|
pwmWrite(PWM, tests_duty[c_duty]); |
|
|
|
|
|
|
|
|
|
|
|
for (int c_pwmc=0, end = sizeof(tests_pwmc)/sizeof(tests_pwmc[0]); c_pwmc<end; c_pwmc++) { |
|
|
|
|
|
int pwmc = tests_pwmc[c_pwmc]; |
|
|
|
|
|
if (Pi4 && pwmc>1456) { |
|
|
|
|
|
printf("* Set clock (pwmc) %d not possible on BCM2711 system (OSC 54 MHz), ignore\n", pwmc); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
double freq = 19200.0/pwmc*duty_fact; |
|
|
|
|
|
if (freq>MaxFreq) { |
|
|
|
|
|
printf("* Set clock (pwmc) %d not possible on system (to slow to measure %g kHz with ISR), ignore\n", pwmc, freq); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
pwmSetClock(pwmc); |
|
|
|
|
|
delay(250); |
|
|
|
|
|
sprintf(msg, "Set Clock (pwmc) %d, %d%% duty", pwmc, tests_duty[c_duty]*100/pmwr); |
|
|
|
|
|
MeasureAndCheckFreq(msg, freq); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
pwmSetClock(tests_pwmc[c_pwmc]); |
|
|
|
|
|
|
|
|
|
|
|
delay(250); |
|
|
delay(250); |
|
|
double freq = 19200.0/tests_pwmc[c_pwmc]*duty_fact; |
|
|
|
|
|
sprintf(msg, "Set Clock (pwmc) %d, %d%% duty", tests_pwmc[c_pwmc], tests_duty[c_duty]*100/pmwr); |
|
|
|
|
|
MeasureAndCheckFreq(msg, freq); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
printf("*********************************\n"); |
|
|
|
|
|
printf("* PWM MS mode *\n"); |
|
|
|
|
|
printf("*********************************\n"); |
|
|
|
|
|
pwmSetMode(PWM_MODE_MS) ; |
|
|
|
|
|
|
|
|
|
|
|
int pwmc = 10; |
|
|
|
|
|
pwmSetClock(pwmc); |
|
|
|
|
|
delay(2500); |
|
|
|
|
|
|
|
|
|
|
|
for (int c_pmwr=0, c_pmwr_end = sizeof(tests_pwmr)/sizeof(tests_pwmr[0]); c_pmwr<c_pmwr_end; c_pmwr++) { |
|
|
|
|
|
int pwmr = tests_pwmr[c_pmwr]; |
|
|
|
|
|
double freq = 19200.0/(double)pwmc/(double)pwmr; |
|
|
|
|
|
if (freq>MaxFreq) { |
|
|
|
|
|
printf("* Set Clock (pwmc, pwmr) %d, %d not possible on system (to slow to measure %g kHz with ISR), ignore\n", pwmc, pwmr, freq); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
sprintf(msg, "Set range (pwmr) %d", pwmr); |
|
|
|
|
|
pwmSetRange(pwmr); |
|
|
|
|
|
|
|
|
|
|
|
for (int c_pmw=0, c_pmw_end = sizeof(tests_pwm)/sizeof(tests_pwm[0]); c_pmw<c_pmw_end; c_pmw++) { |
|
|
|
|
|
int pwm = pwmr*tests_pwm[c_pmw]/100; |
|
|
|
|
|
sprintf(msg, "Set pwm %d/%d (%d %%)", pwm, pwmr, tests_pwm[c_pmw]); |
|
|
|
|
|
pwmWrite(PWM, pwm); |
|
|
|
|
|
delay(250); |
|
|
|
|
|
MeasureAndCheckFreq(msg, freq); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
delay(250); |
|
|
|
|
|
pwmSetMode(PWM_MODE_MS) ; |
|
|
|
|
|
printf("\nPWM0 MS mode:\n"); |
|
|
|
|
|
printf("==============\n"); |
|
|
|
|
|
|
|
|
result = wiringPiISRStop(FREQIN); |
|
|
|
|
|
CheckSame("\n\nRelease ISR", result, 0); |
|
|
|
|
|
if (result < 0) { |
|
|
|
|
|
printf("Unable to release ISR for GPIO %d (%s)\n\n", |
|
|
|
|
|
FREQIN, strerror(errno)); |
|
|
|
|
|
return UnitTestState(); |
|
|
|
|
|
} |
|
|
|
|
|
pinMode(PWM, INPUT); |
|
|
|
|
|
|
|
|
int pwmc = 10; |
|
|
|
|
|
pwmSetClock(pwmc); |
|
|
|
|
|
delay(2500); |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (int c_pmwr=0, c_pmwr_end = sizeof(tests_pwmr)/sizeof(tests_pwmr[0]); c_pmwr<c_pmwr_end; c_pmwr++) { |
|
|
|
|
|
pwmWrite(PWM0, tests_pwmr[c_pmwr]/2); |
|
|
|
|
|
pwmSetRange(tests_pwmr[c_pmwr]) ; |
|
|
|
|
|
delay(250); |
|
|
|
|
|
double freq = 19200.0/(double)pwmc/(double)tests_pwmr[c_pmwr]; |
|
|
|
|
|
sprintf(msg, "Set range (pwmr) %d", tests_pwmr[c_pmwr]); |
|
|
|
|
|
MeasureAndCheckFreq(msg, freq); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return UnitTestState(); |
|
|
|
|
|
|
|
|
return UnitTestState(); |
|
|
} |
|
|
} |