7
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:
profezzorn 2022-02-13 01:04:00 -08:00
parent dd17422182
commit 454052c050
7 changed files with 214 additions and 35 deletions
Software/libthunderscopehw

View File

@ -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)

View File

@ -0,0 +1,4 @@
add_executable(thunderscopehwcalibrate
thunderscopehwcalibrate.c)
target_link_libraries(thunderscopehwcalibrate
thunderscopehwlib)

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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.

View File

@ -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";
}

View File

@ -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];