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)