diff --git a/minichlink/Makefile b/minichlink/Makefile
index dc6c8cc949c0dbbe024a5b31ccadd512d70b9455..a60c9f9b4f4ff6706cbab48dfec14641a1495561 100644
--- a/minichlink/Makefile
+++ b/minichlink/Makefile
@@ -23,6 +23,9 @@ else
 		LIBINCLUDES:=$(shell pkg-config --libs-only-L libusb-1.0)
 		INCS:=$(INCLUDES) $(LIBINCLUDES)
 	endif
+
+    # Until it's supported on Windows, add the Ardulink file here.
+    C_S:=$(C_S) ardulink.c
 endif
 
 all : $(TOOLS)
diff --git a/minichlink/ardulink.c b/minichlink/ardulink.c
new file mode 100644
index 0000000000000000000000000000000000000000..5da4d10640b31c44aaa2c8651182aa14aedb8a08
--- /dev/null
+++ b/minichlink/ardulink.c
@@ -0,0 +1,186 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+
+#include "minichlink.h"
+
+void * TryInit_Ardulink(void);
+
+static int ArdulinkWriteReg32(void * dev, uint8_t reg_7_bit, uint32_t command);
+static int ArdulinkReadReg32(void * dev, uint8_t reg_7_bit, uint32_t * commandresp);
+static int ArdulinkFlushLLCommands(void * dev);
+static int ArdulinkExit(void * dev);
+static int ArdulinkTargetReset(void * dev, int reset);
+
+
+typedef struct {
+    struct ProgrammerStructBase psb;
+    int fd;
+} ardulink_ctx_t;
+
+int ArdulinkWriteReg32(void * dev, uint8_t reg_7_bit, uint32_t command)
+{
+    uint8_t buf[6];
+    buf[0] = 'w';
+    buf[1] = reg_7_bit;
+
+    //fprintf(stderr, "WriteReg32: 0x%02x = 0x%08x\n", reg_7_bit, command);
+
+    buf[2] = command & 0xff;
+    buf[3] = (command >> 8) & 0xff;
+    buf[4] = (command >> 16) & 0xff;
+    buf[5] = (command >> 24) & 0xff;
+
+    if (write(((ardulink_ctx_t*)dev)->fd, buf, 6) == -1)
+        return -errno;
+
+    if (read(((ardulink_ctx_t*)dev)->fd, buf, 1) == -1)
+        return -errno;
+
+    return buf[0] == '+' ? 0 : -EPROTO;
+}
+
+int ArdulinkReadReg32(void * dev, uint8_t reg_7_bit, uint32_t * commandresp)
+{
+    uint8_t buf[4];
+    buf[0] = 'r';
+    buf[1] = reg_7_bit;
+
+    if (write(((ardulink_ctx_t*)dev)->fd, buf, 2) == -1)
+        return -errno;
+
+    if (read(((ardulink_ctx_t*)dev)->fd, buf, 4) == -1)
+        return -errno;
+
+    *commandresp = (uint32_t)buf[0] | (uint32_t)buf[1] << 8 | \
+        (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24;
+
+    //fprintf(stderr, "ReadReg32: 0x%02x = 0x%08x\n", reg_7_bit, *commandresp);
+
+    return 0;
+}
+
+int ArdulinkFlushLLCommands(void * dev)
+{
+    return 0;
+}
+
+int ArdulinkExit(void * dev)
+{
+    close(((ardulink_ctx_t*)dev)->fd);
+    free(dev);
+    return 0;
+}
+
+int ArdulinkTargetReset(void * dev, int reset) {
+    char c;
+
+    fprintf(stderr, "Ardulink: target reset %d\n", reset);
+
+    // Assert reset.
+    c = reset ? 'a' : 'A';
+    if (write(((ardulink_ctx_t*)dev)->fd, &c, 1) == -1)
+        return -errno;
+
+    if (read(((ardulink_ctx_t*)dev)->fd, &c, 1) == -1)
+        return -errno;
+
+    if (c != '+')
+        return -EPROTO;
+
+    usleep(20000);
+    return 0;
+}
+
+void * TryInit_Ardulink(void)
+{
+    ardulink_ctx_t *ctx;
+    struct termios attr;
+    char first;
+    int argp = TIOCM_DTR;
+
+    if (!(ctx = calloc(sizeof(ardulink_ctx_t), 1))) {
+        perror("calloc");
+        return NULL;
+    }
+
+    if ((ctx->fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY)) == -1) {
+        perror("open");
+        return NULL;
+    }
+
+    if (tcgetattr(ctx->fd, &attr) == -1) {
+        perror("tcgetattr");
+        return NULL;
+    }
+
+    cfmakeraw(&attr);
+    cfsetspeed(&attr, 115200);
+
+    if (tcsetattr(ctx->fd, TCSANOW, &attr) == -1) {
+        perror("tcsetattr");
+        return NULL;
+    }
+
+    // Arduino DTR reset.
+    if (ioctl(ctx->fd, TIOCMBIC, &argp) == -1) {
+        perror("ioctl");
+        return NULL;
+    }
+
+    if (tcdrain(ctx->fd) == -1) {
+        perror("tcdrain");
+        return NULL;
+    }
+
+    if (ioctl(ctx->fd, TIOCMBIS, &argp) == -1) {
+        perror("ioctl");
+        return NULL;
+    }
+
+    if (tcdrain(ctx->fd) == -1) {
+        perror("tcdrain");
+        return NULL;
+    }
+
+    // Flush anything that might be in the RX buffer, we need the sync char.
+    if (tcflush(ctx->fd, TCIFLUSH) == -1) {
+        perror("tcflush");
+        return NULL;
+    }
+
+    // Let the bootloader do its thing.
+    sleep(3);
+
+    if (read(ctx->fd, &first, 1) == -1) {
+        perror("read");
+        return NULL;
+    }
+
+    if (first != '!') {
+        fprintf(stderr, "Ardulink: not the sync character.\n");
+        return NULL;
+    }
+
+    if (ArdulinkTargetReset(ctx, 1) != 0) {
+        fprintf(stderr, "Ardulink: target reset failed.\n");
+        return NULL;
+    }
+
+    fprintf(stderr, "Ardulink: synced.\n");
+
+    MCF.WriteReg32 = ArdulinkWriteReg32;
+	MCF.ReadReg32 = ArdulinkReadReg32;
+    MCF.FlushLLCommands = ArdulinkFlushLLCommands;
+	MCF.Exit = ArdulinkExit;
+    MCF.TargetReset = ArdulinkTargetReset;
+
+	return ctx;
+}
diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index 8c3e5ecd3b7c5353a9713945985c4be9931cff0e..980cf9329794c50f03fd179f08fe414308277473 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -12,6 +12,7 @@
 #include "../ch32v003fun/ch32v003fun.h"
 
 #if defined(WINDOWS) || defined(WIN32) || defined(_WIN32)
+#define DISABLE_ARDULINK
 void Sleep(uint32_t dwMilliseconds);
 #else
 #include <unistd.h>
@@ -41,6 +42,15 @@ void * MiniCHLinkInitAsDLL( struct MiniChlinkFunctions ** MCFO )
 	{
 		fprintf( stderr, "Found NHC-Link042 Programmer\n" );
 	}
+
+#ifndef DISABLE_ARDULINK
+	else if ((dev = TryInit_Ardulink()))
+	{
+		fprintf( stderr, "Found Ardulink Programmer\n" );
+	}
+#else
+    #warning Ardulink not yet supported on Windows.
+#endif
 	else
 	{
 		fprintf( stderr, "Error: Could not initialize any supported programmers\n" );
@@ -1656,6 +1666,8 @@ static int DefaultHaltMode( void * dev, int mode )
 	}
 #endif
 
+    MCF.TargetReset(dev, 0);
+
 	iss->processor_in_mode = mode;
 	return 0;
 }
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
index 131a433c4183202c4ac8787c30ae89f13b79ea20..6a974ff230635fa24a2a769512d61c356dc3013c 100644
--- a/minichlink/minichlink.h
+++ b/minichlink/minichlink.h
@@ -78,6 +78,8 @@ struct MiniChlinkFunctions
 
 	int (*WriteByte)( void * dev, uint32_t address_to_write, uint8_t data );
 	int (*ReadByte)( void * dev, uint32_t address_to_read, uint8_t * data );
+
+	int (*TargetReset)( void * dev, int reset );
 };
 
 /** If you are writing a driver, the minimal number of functions you can implement are:
@@ -151,6 +153,7 @@ extern struct MiniChlinkFunctions MCF;
 void * TryInit_WCHLinkE();
 void * TryInit_ESP32S2CHFUN();
 void * TryInit_NHCLink042(void);
+void * TryInit_Ardulink();
 
 // Returns 0 if ok, populated, 1 if not populated.
 int SetupAutomaticHighLevelFunctions( void * dev );