diff --git a/testjig/production/arm_debug.cpp b/testjig/production/arm_debug.cpp
index 99a324bab7aaddb3acf871c03c5a125745262bc0..f50919b0181804522cffd3cfc906da9f75ec46cb 100644
--- a/testjig/production/arm_debug.cpp
+++ b/testjig/production/arm_debug.cpp
@@ -42,15 +42,54 @@ int ARMDebug::begin(unsigned clockPin, unsigned dataPin, libswd_loglevel_t logLe
 	libswdctx->config.autofixerrors = false;
 	libswd_log_level_set(libswdctx, logLevel);
 
+	// Identify the attached chip
  	ret = libswd_dap_detect(libswdctx, LIBSWD_OPERATION_EXECUTE, &idcode);
-	if (ret >= 0) {
-		libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL,
-			"Found ARM processor. IDCODE: 0x%X (%s)\n",
-			*idcode, libswd_bin32_string(idcode));
+ 	if (ret < 0) return ret;
+	libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL,
+		"Found ARM processor. IDCODE: 0x%X (%s)\n", *idcode, libswd_bin32_string(idcode));
+
+ 	// Initialize CTRL/STAT, request system and debugger power-up
+	int ctrlstat = LIBSWD_DP_CTRLSTAT_CDBGPWRUPREQ | LIBSWD_DP_CTRLSTAT_CSYSPWRUPREQ;
+	ret = libswd_dp_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat);
+	if (ret < 0) return ret;
+
+	// Wait for power-up acknowledgment
+	uint32_t powerAck = LIBSWD_DP_CTRLSTAT_CDBGPWRUPACK | LIBSWD_DP_CTRLSTAT_CSYSPWRUPACK;
+	unsigned retries = 4;
+	while (retries-- && (ctrlstat & powerAck) != powerAck) {
+		int *ptr;
+		ret = libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ptr);
+	 	if (ret < 0) return ret;
+	 	ctrlstat = *ptr;
+	}
+	if ((ctrlstat & powerAck) != powerAck) {
+		libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR,
+			"ARMDebug: Debug port failed to power on (CTRLSTAT: %08x)\n", ctrlstat);
+		return LIBSWD_ERROR_MAXRETRY;
 	}
 
-	libswd_cmdq_free_head(libswdctx->cmdq);
-	return ret;
+	// Select the default debug access port
+	ret = libswd_ap_select(libswdctx, LIBSWD_OPERATION_EXECUTE, 0);
+	if (ret < 0) return ret;
+
+	// We expect this to be an AHB (memory bus) access port. Make sure this is right.
+	int *idr;
+	ret = libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_IDR, &idr);
+	if (ret < 0) return ret;
+	if ((*idr & 0xF) != 1) {
+		libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR,
+			"ARMDebug: Default access port is not an AHB-AP as expected! (IDR: %08x)\n", *idr);
+		return LIBSWD_ERROR_GENERAL;	
+	}
+
+	// Set up default CSW values for the AHB-AP. Use 32-bit accesses with auto-increment.
+	int csw = (1 << 6) |  // Device enable
+	          (1 << 4) |  // Increment by a single word
+	          (2 << 0) ;  // 32-bit data size
+	ret = libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_CONTROLSTATUS, &csw);
+	if (ret < 0) return ret;
+
+	return 0;
 }
 
 void ARMDebug::end()
@@ -63,28 +102,46 @@ void ARMDebug::end()
 	}
 }
 
-int ARMDebug::memStore(uint32_t addr, uint32_t data, uint8_t accessPort)
+int ARMDebug::memStore(uint32_t addr, uint32_t data)
 {
-	return 0;
+	return memStore(addr, &data, 1);
 }
 
-int ARMDebug::memLoad(uint32_t addr, uint32_t &data, uint8_t accessPort)
+int ARMDebug::memLoad(uint32_t addr, uint32_t &data)
 {
-	int ret = 0;
+	return memLoad(addr, &data, 1);
+}
 
-	ret = libswd_ap_select(libswdctx, LIBSWD_OPERATION_EXECUTE, accessPort);
-	if (ret >= 0) {
+int ARMDebug::memStore(uint32_t addr, uint32_t *data, unsigned count)
+{
+	int ret = libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_TAR, (int*) &addr);
+	if (ret < 0) return ret;
 
-		int *result = 0;
-		ret = libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, 0xFC, &result);
-		if (ret >= 0) {
-			libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL,
-				"FC -> %p %08x\n", result, *result);
-		}
+	while (count) {
+		ret = libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_DRW, (int*) data);
+		if (ret < 0) return ret;
+		data++;
+		count--;
 	}
 
-	libswd_cmdq_free_head(libswdctx->cmdq);
-	return ret;
+	return 0;
+}
+
+int ARMDebug::memLoad(uint32_t addr, uint32_t *data, unsigned count)
+{
+	int ret = libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_TAR, (int*) &addr);
+	if (ret < 0) return ret;
+
+	while (count) {
+		int *ptr;
+		ret = libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, AHB_AP_DRW, &ptr);
+		if (ret < 0) return ret;
+		*data = *ptr;
+		data++;
+		count--;
+	}
+
+	return 0;
 }
 
 void ARMDebug::mosi_transfer(uint32_t data, unsigned nBits)
@@ -114,6 +171,7 @@ uint32_t ARMDebug::miso_transfer(unsigned nBits)
 
 void ARMDebug::mosi_trn(unsigned nClocks)
 {
+	digitalWrite(dataPin, HIGH);
 	pinMode(dataPin, INPUT_PULLUP);
 	while (nClocks--) {
 		digitalWrite(clockPin, LOW);
diff --git a/testjig/production/arm_debug.h b/testjig/production/arm_debug.h
index e7294aaab25ce819521ce7056d08336312a42f3b..e72af9b4cb7ef60addac1cd3abefed3f023bfcca 100644
--- a/testjig/production/arm_debug.h
+++ b/testjig/production/arm_debug.h
@@ -47,14 +47,13 @@ public:
 	/// Deinitialize the debug interface, if it's been initialized.
 	void end();
 
-	/// Memory store, using a memory access port
-	int memStore(uint32_t addr, uint32_t data, uint8_t accessPort = CortexM_AHB_AP);
+	/// Memory store
+	int memStore(uint32_t addr, uint32_t data);
+	int memStore(uint32_t addr, uint32_t *data, unsigned count);
 
-	/// Memory load, using a memory access port
-	int memLoad(uint32_t addr, uint32_t &data, uint8_t accessPort = CortexM_AHB_AP);
-
-	// Memory access port (MEM-AP) types.
-	static const uint8_t CortexM_AHB_AP = 0x11;		// AHB-AP on ARM Cortex-M parts
+	/// Memory load
+	int memLoad(uint32_t addr, uint32_t &data);
+	int memLoad(uint32_t addr, uint32_t *data, unsigned count);
 
 	// Low-level interface (LSB-first)
 	void mosi_transfer(uint32_t data, unsigned nBits);
@@ -62,6 +61,9 @@ public:
 	void mosi_trn(unsigned nClocks);
 	void miso_trn(unsigned nClocks);
 
+	// Low-level access to libswd
+	libswd_ctx_t *getContext() { return libswdctx; }
+
 private:
 	uint8_t clockPin, dataPin;
 	libswd_ctx_t *libswdctx;
diff --git a/testjig/production/production.ino b/testjig/production/production.ino
index 05a2204595b6e12eda77212d202c7e5f3acddb9c..33280393e6041683f08b76bfa7325f8588ff1aef 100644
--- a/testjig/production/production.ino
+++ b/testjig/production/production.ino
@@ -30,6 +30,7 @@ void loop()
 	Serial.println("");
 
 	while (digitalRead(buttonPin) == LOW);
+	delay(20);   // Debounce delay
 	while (digitalRead(buttonPin) == HIGH) {
 		// While we're waiting, blink the LED to indicate we're alive
 		digitalWrite(ledPin, (millis() % 1000) < 150);
@@ -40,5 +41,14 @@ void loop()
 		return;
 
 	uint32_t data;
-	target.memLoad(0x000000, data);
+	if (target.memLoad(0x20000000, data) < 0)
+		return;
+	libswd_log(target.getContext(), LIBSWD_LOGLEVEL_NORMAL, "data = 0x%08x\n", data);
+	data ^= 0xFFFFFFFF;
+	libswd_log(target.getContext(), LIBSWD_LOGLEVEL_NORMAL, "data = 0x%08x\n", data);
+	if (target.memStore(0x20000000, data) < 0)
+		return;
+	if (target.memLoad(0x20000000, data) < 0)
+		return;
+	libswd_log(target.getContext(), LIBSWD_LOGLEVEL_NORMAL, "data = 0x%08x\n", data);
 }