mirror of
https://github.com/EEVengers/ThunderScope.git
synced 2025-04-22 17:43:44 +00:00
start calibration program
This commit is contained in:
parent
dd17422182
commit
454052c050
Software/libthunderscopehw
@ -6,6 +6,7 @@ project(thunderscopehwlib VERSION ${PROJECT_VERSION})
|
||||
|
||||
add_subdirectory(library)
|
||||
add_subdirectory(examples/thunderscopehwdump)
|
||||
add_subdirectory(examples/thunderscopehwcalibrate)
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
|
@ -0,0 +1,4 @@
|
||||
add_executable(thunderscopehwcalibrate
|
||||
thunderscopehwcalibrate.c)
|
||||
target_link_libraries(thunderscopehwcalibrate
|
||||
thunderscopehwlib)
|
@ -0,0 +1,150 @@
|
||||
#include "thunderscopehw.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
struct Option {
|
||||
const char* name;
|
||||
bool needs_argument;
|
||||
int return_value;
|
||||
};
|
||||
|
||||
struct Option options[] = {
|
||||
{"device", true, 1 },
|
||||
};
|
||||
|
||||
#define TS_RUN(X) do { \
|
||||
enum ThunderScopeHWStatus ret = thunderscopehw_##X; \
|
||||
if (ret != THUNDERSCOPEHW_STATUS_OK) { \
|
||||
fprintf(stderr, "thunderscope_%s failed @ line %d, error = %s\n", #X, __LINE__, thunderscopehw_describe_error(ret)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
char* optarg;
|
||||
int optind = 1;
|
||||
int mygetopt(int argc, char** argv) {
|
||||
if (optind >= argc) return -1;
|
||||
if (!argv[optind][0] == '-' || argv[optind][1] != '-') return -1;
|
||||
char *arg = strchr(argv[optind], '=');
|
||||
for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
|
||||
size_t len = strlen(options[i].name);
|
||||
if (strncmp(options[i].name, argv[optind] + 2, len)) continue;
|
||||
if (options[i].needs_argument) {
|
||||
if (!arg) continue;
|
||||
if (argv[optind] + 2 + len != arg) continue;
|
||||
optarg = arg + 1;
|
||||
} else {
|
||||
if (arg) continue;
|
||||
if (argv[optind][2 + len]) continue;
|
||||
optarg = NULL;
|
||||
}
|
||||
optind++;
|
||||
return options[i].return_value;
|
||||
}
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[optind]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
uint64_t scope_id = 0;
|
||||
uint64_t samples = 0;
|
||||
int samplerate = 0;
|
||||
while (1) {
|
||||
switch (mygetopt(argc, argv)) {
|
||||
case 1:
|
||||
if (!sscanf(optarg, "%" PRIx64, &scope_id)) {
|
||||
fprintf(stderr, "Scope ID must be hexadecimal.\n");
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
case -1:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (scope_id == 0) {
|
||||
uint64_t scope_ids[32];
|
||||
int scopes = thunderscopehw_scan(scope_ids, 32);
|
||||
if (scopes == 0) {
|
||||
fprintf(stderr, "No thunderscopehw hardware found.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (scopes > 1) {
|
||||
fprintf(stderr, "Multiple scopes found, please select one with --device.\n");
|
||||
for (int i = 0; i < scopes; i++) {
|
||||
fprintf(stderr, " %0" PRIx64 "\n", scope_ids[i]);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
scope_id = scope_ids[0];
|
||||
}
|
||||
|
||||
#define BUFFER_SIZE (1<<20)
|
||||
uint8_t* buffer;
|
||||
#ifdef _WIN32
|
||||
buffer = _aligned_malloc(BUFFER_SIZE, 4096);
|
||||
#else
|
||||
posix_memalign((void**)&buffer, 4096, BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
struct ThunderScopeHW *ts = thunderscopehw_create();
|
||||
enum ThunderScopeHWStatus ret;
|
||||
TS_RUN(connect(ts, scope_id));
|
||||
|
||||
for (int channel = 0; channel < 4; channel++) {
|
||||
TS_RUN(enable_channel(ts, channel));
|
||||
// 1mV / div
|
||||
TS_RUN(voltage_division_set(ts, channel, 1));
|
||||
#ifdef WIN32
|
||||
Sleep(500);
|
||||
#else
|
||||
usleep(500000);
|
||||
#endif
|
||||
|
||||
double minoffset = -0.5;
|
||||
double maxoffset = 0.5;
|
||||
|
||||
for (int i =0; i < 1000; i++) {
|
||||
for (int j = 0; j < 20; j++) {
|
||||
double midoffset = (minoffset + maxoffset) / 2;
|
||||
TS_RUN(voltage_offset_set(ts, channel, midoffset));
|
||||
TS_RUN(start(ts));
|
||||
TS_RUN(read(ts, buffer, BUFFER_SIZE));
|
||||
// Convert signed output to unsigned output
|
||||
for (size_t i = 0; i < BUFFER_SIZE; i++) {
|
||||
buffer[i] += 0x80;
|
||||
}
|
||||
TS_RUN(stop(ts));
|
||||
int high = 0;
|
||||
int low = 0;
|
||||
uint64_t sum = 0;
|
||||
for (size_t i = 0; i < BUFFER_SIZE; i++) {
|
||||
if (buffer[i] > 0x80) high++;
|
||||
if (buffer[i] < 0x80) low++;
|
||||
sum += buffer[i];
|
||||
}
|
||||
// fprintf(stderr," min = %8.4f max = %8.4f mid = %8.4f high=%d low=%d avg=%f\n",
|
||||
// minoffset, maxoffset, midoffset,
|
||||
// high, low,
|
||||
// sum / (double)BUFFER_SIZE);
|
||||
if (high > low) {
|
||||
minoffset = midoffset;
|
||||
} else {
|
||||
maxoffset = midoffset;
|
||||
}
|
||||
}
|
||||
printf("Channel %d calibration = %f\n", channel + 1, (minoffset + maxoffset) / 2);
|
||||
}
|
||||
TS_RUN(disable_channel(ts, channel));
|
||||
}
|
||||
}
|
@ -21,44 +21,45 @@ struct Option {
|
||||
};
|
||||
|
||||
struct Option options[] = {
|
||||
{"device", true, 1 },
|
||||
{"samples", true, 2 },
|
||||
{"device", true, 1 },
|
||||
{"samples", true, 2 },
|
||||
{"output-samplerate", true, 3 },
|
||||
|
||||
{"bw-all", true, 0x10 },
|
||||
{"bw1", true, 0x11 },
|
||||
{"bw2", true, 0x12 },
|
||||
{"bw3", true, 0x13 },
|
||||
{"bw4", true, 0x14 },
|
||||
{"bw-all", true, 0x10 },
|
||||
{"bw1", true, 0x11 },
|
||||
{"bw2", true, 0x12 },
|
||||
{"bw3", true, 0x13 },
|
||||
{"bw4", true, 0x14 },
|
||||
|
||||
{"vdiv-all", true, 0x20 },
|
||||
{"vdiv1", true, 0x21 },
|
||||
{"vdiv2", true, 0x22 },
|
||||
{"vdiv3", true, 0x23 },
|
||||
{"vdiv4", true, 0x24 },
|
||||
{"vdiv-all", true, 0x20 },
|
||||
{"vdiv1", true, 0x21 },
|
||||
{"vdiv2", true, 0x22 },
|
||||
{"vdiv3", true, 0x23 },
|
||||
{"vdiv4", true, 0x24 },
|
||||
|
||||
{"voffset-all", true, 0x30 },
|
||||
{"voffset1", true, 0x31 },
|
||||
{"voffset2", true, 0x32 },
|
||||
{"voffset3", true, 0x33 },
|
||||
{"voffset4", true, 0x34 },
|
||||
{"voffset-all", true, 0x30 },
|
||||
{"voffset1", true, 0x31 },
|
||||
{"voffset2", true, 0x32 },
|
||||
{"voffset3", true, 0x33 },
|
||||
{"voffset4", true, 0x34 },
|
||||
|
||||
{"ac-all", false, 0x40 },
|
||||
{"ac1", false, 0x41 },
|
||||
{"ac2", false, 0x42 },
|
||||
{"ac3", false, 0x43 },
|
||||
{"ac4", false, 0x44 },
|
||||
{"ac-all", false, 0x40 },
|
||||
{"ac1", false, 0x41 },
|
||||
{"ac2", false, 0x42 },
|
||||
{"ac3", false, 0x43 },
|
||||
{"ac4", false, 0x44 },
|
||||
|
||||
{"dc-all", false, 0x50 },
|
||||
{"ac1", false, 0x51 },
|
||||
{"ac2", false, 0x52 },
|
||||
{"ac3", false, 0x53 },
|
||||
{"ac4", false, 0x54 },
|
||||
{"dc-all", false, 0x50 },
|
||||
{"ac1", false, 0x51 },
|
||||
{"ac2", false, 0x52 },
|
||||
{"ac3", false, 0x53 },
|
||||
{"ac4", false, 0x54 },
|
||||
|
||||
{"enable-all", false, 0x60 },
|
||||
{"enable1", false, 0x61 },
|
||||
{"enable2", false, 0x62 },
|
||||
{"enable3", false, 0x63 },
|
||||
{"enable4", false, 0x64 },
|
||||
{"enable-all", false, 0x60 },
|
||||
{"enable1", false, 0x61 },
|
||||
{"enable2", false, 0x62 },
|
||||
{"enable3", false, 0x63 },
|
||||
{"enable4", false, 0x64 },
|
||||
};
|
||||
|
||||
char* optarg;
|
||||
@ -89,6 +90,7 @@ int mygetopt(int argc, char** argv) {
|
||||
int main(int argc, char** argv) {
|
||||
uint64_t scope_id = 0;
|
||||
uint64_t samples = 0;
|
||||
int samplerate = 0;
|
||||
while (1) {
|
||||
switch (mygetopt(argc, argv)) {
|
||||
case 1:
|
||||
@ -102,6 +104,11 @@ int main(int argc, char** argv) {
|
||||
fprintf(stderr, "Number of samples must be a number.\n");
|
||||
exit(1);
|
||||
}
|
||||
case 3:
|
||||
if (!sscanf(optarg, "%d", &samplerate)) {
|
||||
fprintf(stderr, "Output samplerate must be a number.\n");
|
||||
exit(1);
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
case -1:
|
||||
@ -232,7 +239,11 @@ int main(int argc, char** argv) {
|
||||
struct Fmt fmt;
|
||||
fmt.pcm = 1;
|
||||
fmt.channels = num_channels;
|
||||
fmt.rate = 1000000000 / fmt.channels;
|
||||
if (samplerate) {
|
||||
fmt.rate = samplerate;
|
||||
} else {
|
||||
fmt.rate = 1000000000 / fmt.channels;
|
||||
}
|
||||
fmt.byterate = 1000000000;
|
||||
fmt.block_align = 0;
|
||||
fmt.bits_per_sample = 8;
|
||||
|
@ -25,6 +25,8 @@ enum ThunderScopeHWStatus {
|
||||
THUNDERSCOPEHW_STATUS_ALREADY_STARTED,
|
||||
THUNDERSCOPEHW_STATUS_NOT_STARTED,
|
||||
THUNDERSCOPEHW_STATUS_ALREADY_STOPPED,
|
||||
THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW,
|
||||
THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH,
|
||||
};
|
||||
|
||||
// Return's number of scopes.
|
||||
|
@ -93,6 +93,8 @@ enum ThunderScopeHWStatus thunderscopehw_start(struct ThunderScopeHW* ts) {
|
||||
return THUNDERSCOPEHW_STATUS_ALREADY_STARTED;
|
||||
ts->datamover_en = true;
|
||||
ts->fpga_adc_en = true;
|
||||
ts->buffer_head = 0;
|
||||
ts->buffer_tail = 0;
|
||||
return thunderscopehw_set_datamover_reg(ts);
|
||||
}
|
||||
|
||||
@ -220,6 +222,10 @@ const char* thunderscopehw_describe_error(enum ThunderScopeHWStatus err) {
|
||||
return "not started";
|
||||
case THUNDERSCOPEHW_STATUS_ALREADY_STOPPED:
|
||||
return "already stopped";
|
||||
case THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW:
|
||||
return "voffset too low";
|
||||
case THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH:
|
||||
return "voffset too high";
|
||||
}
|
||||
return "unkonwn error";
|
||||
}
|
||||
|
@ -126,7 +126,12 @@ enum ThunderScopeHWStatus thunderscopehw_set_dac(struct ThunderScopeHW* ts, int
|
||||
{
|
||||
// value is 12-bit
|
||||
// Is this right?? Or is it rounding wrong?
|
||||
unsigned int dac_value = (unsigned int)round((ts->channels[channel].voffset + 0.5) * 4095);
|
||||
int dac_value = (unsigned int)round((ts->channels[channel].voffset + 0.5) * 4095);
|
||||
if (dac_value < 0)
|
||||
return THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW;
|
||||
if (dac_value > 0xFFF)
|
||||
return THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH;
|
||||
|
||||
uint8_t fifo[5];
|
||||
fifo[0] = 0xFF; // I2C
|
||||
fifo[1] = 0xC2; // DAC?
|
||||
@ -151,7 +156,7 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH
|
||||
|
||||
switch (num_channels_on) {
|
||||
case 0:
|
||||
return false;
|
||||
return THUNDERSCOPEHW_STATUS_NO_CHANNELS;
|
||||
|
||||
case 1:
|
||||
on_channels[1] = on_channels[2] = on_channels[3] = on_channels[0];
|
||||
|
Loading…
Reference in New Issue
Block a user