diff --git a/Software/libthunderscopehw/CMakeLists.txt b/Software/libthunderscopehw/CMakeLists.txt index 546ecaa4..5b83eed1 100644 --- a/Software/libthunderscopehw/CMakeLists.txt +++ b/Software/libthunderscopehw/CMakeLists.txt @@ -6,6 +6,8 @@ project(thunderscopehwlib VERSION ${PROJECT_VERSION}) add_subdirectory(library) add_subdirectory(examples/thunderscopehwdump) +add_subdirectory(examples/thunderscopehwcalibrate) +add_subdirectory(examples/thunderscopehwbench) enable_testing() add_subdirectory(test) diff --git a/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt b/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt new file mode 100644 index 00000000..22305733 --- /dev/null +++ b/Software/libthunderscopehw/examples/thunderscopehwbench/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(thunderscopehwbench + thunderscopehwbench.c) +target_link_libraries(thunderscopehwbench + thunderscopehwlib) diff --git a/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c b/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c new file mode 100644 index 00000000..0001b297 --- /dev/null +++ b/Software/libthunderscopehw/examples/thunderscopehwbench/thunderscopehwbench.c @@ -0,0 +1,150 @@ +#include "thunderscopehw.h" + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> + +#ifndef WIN32 +#include <unistd.h> +#include <sys/time.h> +#endif + + +static uint64_t time_ns(void) +{ +#ifdef WIN32 + struct timespec tv; + if (timespec_get(&ts, TIME_UTC) != TIME_UTC) + { + fprintf(stderr, "timespec_get failed!"); + exit(1); + } + return 1000000000 * ts.tv_sec + ts.tv_nsec; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return 1000000000 * tv.tv_sec + tv.tv_usec * 1000; +#endif +} + +struct Option { + const char* name; + bool needs_argument; + int return_value; +}; + +struct Option options[] = { + {"device", true, 1 }, + {"verbose", false, 2 }, + {"repeat", true, 3 }, +}; + +#define TS_RUN(X) do { \ + enum ThunderScopeHWStatus ret = thunderscopehw_##X; \ + if (ret != THUNDERSCOPEHW_STATUS_OK) { \ + fprintf(stderr, "thunderscopehw_%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) { + int verbose = 0; + int repeat = 1; + 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; + case 2: + verbose++; + continue; + case 3: + if (!sscanf(optarg, "%d", &repeat)) { + fprintf(stderr, "--repeat needs a number.\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]; + } + + // 32Mb +#define BUFFER_SIZE (32<<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)); + + + TS_RUN(enable_channel(ts, 0)); + TS_RUN(start(ts)); + for (int i = 0; i < repeat; i++) { + uint64_t start = time_ns(); + uint64_t bytes = 0; + for (int j = 0; j < (1<<30) / BUFFER_SIZE; j++) { + TS_RUN(read(ts, buffer, BUFFER_SIZE)); + bytes += BUFFER_SIZE; + } + uint64_t end = time_ns(); + printf("Rate = %f Mib/s\n", bytes / 1000.0 / 1000.0 * 1000000000.0 / (end - start)); + } +} diff --git a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt new file mode 100644 index 00000000..f168201c --- /dev/null +++ b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(thunderscopehwcalibrate + thunderscopehwcalibrate.c) +target_link_libraries(thunderscopehwcalibrate + thunderscopehwlib) diff --git a/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c new file mode 100644 index 00000000..bf1e27f8 --- /dev/null +++ b/Software/libthunderscopehw/examples/thunderscopehwcalibrate/thunderscopehwcalibrate.c @@ -0,0 +1,170 @@ +#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 }, + {"verbose", false, 2 }, + {"retries", true, 3 }, +}; + +#define TS_RUN(X) do { \ + enum ThunderScopeHWStatus ret = thunderscopehw_##X; \ + if (ret != THUNDERSCOPEHW_STATUS_OK) { \ + fprintf(stderr, "thunderscopehw_%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) { + int verbose = 0; + int retries = 1; + 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; + case 2: + verbose++; + continue; + case 3: + if (!sscanf(optarg, "%d", &retries)) { + fprintf(stderr, "--retries needs a number.\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 + + for (int i = 0; i < retries; i++) { + double minoffset = -0.5; + double maxoffset = 0.5; + for (int j = 0; j < 20; j++) { + double midoffset = (minoffset + maxoffset) / 2; + TS_RUN(voltage_offset_set(ts, channel, midoffset)); + TS_RUN(start(ts)); + enum ThunderScopeHWStatus status = thunderscopehw_read(ts, buffer, BUFFER_SIZE); + if (status != THUNDERSCOPEHW_STATUS_OK) { + fprintf(stderr, "thunderscopehw_read failed, error = %s\n", thunderscopehw_describe_error(status)); + j--; + TS_RUN(stop(ts)); + continue; + } + // 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]; + } + if (verbose) { + 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)); + } +} diff --git a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c index 8f172e13..e29331cd 100644 --- a/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c +++ b/Software/libthunderscopehw/examples/thunderscopehwdump/thunderscopehwdump.c @@ -5,9 +5,8 @@ #include <inttypes.h> #include <string.h> -#ifdef _WIN32 -#include <fcntl.h> -#include <io.h> +#ifndef WIN32 +#include <unistd.h> #endif void write32(uint64_t x, FILE* f) { @@ -26,44 +25,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 }, + {"dc1", false, 0x51 }, + {"dc2", false, 0x52 }, + {"dc3", false, 0x53 }, + {"dc4", 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; @@ -87,12 +87,14 @@ int mygetopt(int argc, char** argv) { optind++; return options[i].return_value; } - return -1; + 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: @@ -106,6 +108,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: @@ -165,7 +172,7 @@ int main(int argc, char** argv) { } break; case 3: // voffset - ret = thunderscopehw_voltage_offset_set(ts, channel, atoi(optarg)); + ret = thunderscopehw_voltage_offset_set(ts, channel, atof(optarg)); if (ret != THUNDERSCOPEHW_STATUS_OK) { fprintf(stderr, "Failed to set voffset. error =%s\n", thunderscopehw_describe_error(ret)); exit(1); @@ -222,11 +229,6 @@ int main(int argc, char** argv) { perror("open output file"); exit(1); } - } else { -#ifdef _WIN32 - // Attempt to set stdout to binary mode. - _setmode( _fileno( stdout ), _O_BINARY ); -#endif } struct Fmt { @@ -237,11 +239,20 @@ int main(int argc, char** argv) { uint16_t block_align; uint16_t bits_per_sample; }; +#ifdef WIN32 + Sleep(500); +#else + usleep(500000); +#endif 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; @@ -262,22 +273,27 @@ int main(int argc, char** argv) { exit(1); } +#define BUFFER_SIZE samples uint8_t* buffer; #ifdef _WIN32 - buffer = _aligned_malloc(1 << 20, 4096); -#else - posix_memalign((void**)&buffer, 4096, 1 << 20); + buffer = _aligned_malloc(BUFFER_SIZE, 4096); +#else + posix_memalign((void**)&buffer, 4096, BUFFER_SIZE); #endif while (samples) { int64_t to_copy = samples; - if (to_copy > sizeof(buffer)) to_copy = sizeof(buffer); - ret = thunderscopehw_read(ts, buffer, sizeof(buffer)); + if (to_copy > BUFFER_SIZE) to_copy = BUFFER_SIZE; + ret = thunderscopehw_read(ts, buffer, to_copy); if (ret != THUNDERSCOPEHW_STATUS_OK) { fprintf(stderr, "Thunderscope read error, error = %s\n", thunderscopehw_describe_error(ret)); exit(1); } - if (fwrite(buffer, 1, sizeof(buffer), outfile) != sizeof(buffer)) { + // Convert signed output to unsigned output + for (size_t i = 0; i < BUFFER_SIZE; i++) { + buffer[i] += 0x80; + } + if (fwrite(buffer, 1, to_copy, outfile) != to_copy) { perror("fwrite"); exit(1); } diff --git a/Software/libthunderscopehw/include/thunderscopehw.h b/Software/libthunderscopehw/include/thunderscopehw.h index e214666c..9f6225f8 100644 --- a/Software/libthunderscopehw/include/thunderscopehw.h +++ b/Software/libthunderscopehw/include/thunderscopehw.h @@ -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. diff --git a/Software/libthunderscopehw/library/thunderscopehw.c b/Software/libthunderscopehw/library/thunderscopehw.c index 2764d026..1b8f2495 100644 --- a/Software/libthunderscopehw/library/thunderscopehw.c +++ b/Software/libthunderscopehw/library/thunderscopehw.c @@ -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); } @@ -112,16 +114,15 @@ static enum ThunderScopeHWStatus thunderscopehw_update_buffer_head(struct Thunde // 1 page = 4k uint32_t transfer_counter = thunderscopehw_read32(ts, DATAMOVER_TRANSFER_COUNTER); uint32_t error_code = transfer_counter >> 30; - if (error_code & 1) - return THUNDERSCOPEHW_STATUS_DATAMOVER_ERROR; if (error_code & 2) + return THUNDERSCOPEHW_STATUS_DATAMOVER_ERROR; + + if (error_code & 1) return THUNDERSCOPEHW_STATUS_FIFO_OVERFLOW; uint32_t overflow_cycles = (transfer_counter >> 16) & 0x3FFF; - if (overflow_cycles) { - fprintf(stderr, "TRANSFER COUNTER = %llx\n", (long long)transfer_counter); + if (overflow_cycles) return THUNDERSCOPEHW_STATUS_PIPELINE_OVERFLOW; - } uint32_t pages_moved = transfer_counter & 0xFFFF; uint64_t buffer_head = (ts->buffer_head & ~0xFFFFULL) | pages_moved; @@ -168,7 +169,7 @@ enum ThunderScopeHWStatus thunderscopehw_read(struct ThunderScopeHW* ts, uint8_t if (pages_to_read > ts->ram_size_pages - buffer_read_pos) pages_to_read = ts->ram_size_pages - buffer_read_pos; if (pages_to_read > ts->ram_size_pages / 4) pages_to_read = ts->ram_size_pages / 4; - thunderscopehw_read_handle(ts, ts->user_handle, data, buffer_read_pos << 12, pages_to_read << 12); + THUNDERSCOPEHW_RUN(read_handle(ts, ts->c2h0_handle, data, buffer_read_pos << 12, pages_to_read << 12)); data += pages_to_read << 12; length -= pages_to_read << 12; @@ -221,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"; } diff --git a/Software/libthunderscopehw/library/thunderscopehw_adc.c b/Software/libthunderscopehw/library/thunderscopehw_adc.c index 89ea7803..308f36d2 100644 --- a/Software/libthunderscopehw/library/thunderscopehw_adc.c +++ b/Software/libthunderscopehw/library/thunderscopehw_adc.c @@ -14,7 +14,7 @@ enum ThunderScopeHWStatus thunderscopehw_adc_power(struct ThunderScopeHW* ts, bo { return thunderscopehw_adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_POWER, - on ? 0x0200 : 0x0000); + on ? 0x0000 : 0x0200); } enum ThunderScopeHWStatus thunderscopehw_configure_adc(struct ThunderScopeHW* ts) @@ -25,7 +25,7 @@ enum ThunderScopeHWStatus thunderscopehw_configure_adc(struct ThunderScopeHW* ts THUNDERSCOPEHW_RUN(adc_power(ts, false)); // invert channels - THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_INVERT, 0x0074)); + THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_INVERT, 0x007F)); // Adjust full scale value THUNDERSCOPEHW_RUN(adc_set_reg(ts, THUNDERSCOPEHW_ADC_REG_FS_CNTRL, 0x0010)); diff --git a/Software/libthunderscopehw/library/thunderscopehw_internals.c b/Software/libthunderscopehw/library/thunderscopehw_internals.c index 2a0ed246..e3b491e2 100644 --- a/Software/libthunderscopehw/library/thunderscopehw_internals.c +++ b/Software/libthunderscopehw/library/thunderscopehw_internals.c @@ -1,6 +1,8 @@ #include "thunderscopehw_private.h" #include <math.h> +#include <stdio.h> +#include <stdlib.h> #ifdef WIN32 #else @@ -37,7 +39,7 @@ enum ThunderScopeHWStatus thunderscopehw_fifo_write(struct ThunderScopeHW* ts, u // write to TLR (the size of the packet) THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_TLR_ADDRESS, (uint32_t)(bytes * 4))); // read ISR for a done value - while ((thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS) & 0xff) != 8) { + while ((thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS) >> 24) != 8) { #ifdef WIN32 Sleep(1); #else @@ -63,19 +65,17 @@ enum ThunderScopeHWStatus thunderscopehw_set_datamover_reg(struct ThunderScopeHW if (ts->datamover_en) datamover_reg |= 0x1; if (ts->fpga_adc_en) datamover_reg |= 0x2; -#if 1 for (int channel = 0; channel < 4; channel++) { if (ts->channels[channel].on == true) { num_channels_on++; } - if (ts->channels[channel].vdiv > 100) { + if (ts->channels[channel].vdiv <= 100) { datamover_reg |= 1 << (16 + channel); } if (ts->channels[channel].coupling == THUNDERSCOPEHW_COUPLING_DC) { datamover_reg |= 1 << (20 + channel); } } -#endif switch (num_channels_on) { case 0: case 1: break; // do nothing @@ -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,8 +156,6 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH switch (num_channels_on) { case 0: - return false; - case 1: on_channels[1] = on_channels[2] = on_channels[3] = on_channels[0]; clkdiv = 0; @@ -195,6 +198,8 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeH #else usleep(5000); #endif + /* No channels, leave data mover off. */ + if (num_channels_on == 0) return THUNDERSCOPEHW_STATUS_OK; return thunderscopehw_set_datamover_reg(ts); } @@ -209,8 +214,11 @@ enum ThunderScopeHWStatus thunderscopehw_configure_channel(struct ThunderScopeHW uint32_t thunderscopehw_read32(struct ThunderScopeHW* ts, size_t addr) { uint8_t bytes[4]; - thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4); - return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + if (thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4) != THUNDERSCOPEHW_STATUS_OK) { + fprintf(stderr, "Error in thunderscopehw_read32\n"); + exit(1); + } + return (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]; } enum ThunderScopeHWStatus thunderscopehw_write32(struct ThunderScopeHW* ts, size_t addr, uint32_t value) diff --git a/Software/libthunderscopehw/library/thunderscopehw_private.h b/Software/libthunderscopehw/library/thunderscopehw_private.h index 4820a0df..612aae7c 100644 --- a/Software/libthunderscopehw/library/thunderscopehw_private.h +++ b/Software/libthunderscopehw/library/thunderscopehw_private.h @@ -33,7 +33,7 @@ #define SPI_FRONT_END_CHANNEL_3 0xFA #define SPI_FRONT_END_CHANNEL_4 0xFB -#define SPI_BYTE_ADC 0xFC +#define SPI_BYTE_ADC 0xFD #define I2C_BYTE_PLL 0xFF @@ -102,7 +102,7 @@ enum ThunderScopeHWAdcRegister { THUNDERSCOPEHW_ADC_REG_CHNUM_CLKDIV = 0x31, THUNDERSCOPEHW_ADC_REG_GAIN_CFG = 0x33, THUNDERSCOPEHW_ADC_REG_INSEL12 = 0x3A, - THUNDERSCOPEHW_ADC_REG_INSEL34 = 0x3A, + THUNDERSCOPEHW_ADC_REG_INSEL34 = 0x3B, THUNDERSCOPEHW_ADC_REG_FS_CNTRL = 0x55, }; enum ThunderScopeHWStatus thunderscopehw_adc_set_reg(struct ThunderScopeHW* ts, enum ThunderScopeHWAdcRegister reg, uint16_t value); diff --git a/Software/libthunderscopehw/library/thunderscopehw_win.c b/Software/libthunderscopehw/library/thunderscopehw_win.c index e8a9ff68..187887cb 100644 --- a/Software/libthunderscopehw/library/thunderscopehw_win.c +++ b/Software/libthunderscopehw/library/thunderscopehw_win.c @@ -153,7 +153,7 @@ enum ThunderScopeHWStatus thunderscopehw_read_handle(struct ThunderScopeHW* ts, fprintf(stderr, "read handle failed, win32 error code: %d\n", GetLastError()); return THUNDERSCOPEHW_STATUS_READ_ERROR; } - return true; + return THUNDERSCOPEHW_STATUS_OK; } enum ThunderScopeHWStatus thunderscopehw_write_handle(struct ThunderScopeHW* ts, HANDLE h, uint8_t* data, uint64_t addr, int64_t bytes)