# CH32V003 (SOP-8) Arduino Pin Remapping & Serial Guide

## Overview
The **CH32V003J4M6** comes in a tiny SOP-8 package. Due to the limited pin count (only 6 usable I/O pins), standard Arduino pin mappings often conflict with required peripherals like I2C or the SWIO programming interface.

![WCH LinkE Connection](images/WCH-LinkE-connection.jpg)

This guide details how to:
1.  **Remap Hardware Serial** to different pins by modifying the Arduino Core.
2.  **Manage Conflicts** (e.g., losing I2C to gain Serial RX).
3.  **Share Pin 8 (SWIO)** for both programming and Serial TX.
4.  **Unbrick/Erase the chip** using `minichlink` if configuration errors lock you out.

---

## The Pinout Constraints
On the SOP-8 package, several peripherals share the same physical pins. You cannot use all functions simultaneously.

![CH32V003J4M6 Pinout](images/CH32V003J4M6.webp)

| Pin # | Pin Name | Default Function | Conflict / Alt Function |
| :--- | :--- | :--- | :--- |
| **1** | **PD6** | UART1 RX (Default) | **Can be remapped to UART1 TX** |
| **5** | **PC1** | **I2C SDA** | Can be remapped to UART1 RX |
| **6** | **PC2** | **I2C SCL** | - |
| **8** | **PD1** | **SWIO (Programming)** | Can be remapped to UART1 TX |

---

## Method 1: Permanent Remap (Editing Core Files)
To use Hardware Serial on **Pin 1 (PD6)** as TX, you must modify the board definition files. This allows `Serial.print` to work natively on the new pins.

### 1. Locate the Core Files
Navigate to the directory where the WCH Arduino core is installed:
*   **Windows:** `%LOCALAPPDATA%\Arduino15\packages\WCH\hardware\ch32v\1.0.4\variants\CH32V003F4`
*   **Linux:** `~/.arduino15/packages/WCH/hardware/ch32v/1.0.4/variants/CH32V003F4`
*   **Mac:** `~/Library/Arduino15/packages/WCH/hardware/ch32v/1.0.4/variants/CH32V003F4`

### 2. Modify `PeripheralPins.c`
Open `PeripheralPins.c`. You need to change the pin definitions in the `PinMap_UART_TX` and `PinMap_UART_RX` arrays.

**To set TX to Pin 1 (PD6) and RX to Pin 5 (PC1):**
*Note: This configuration sacrifices hardware I2C SDA on Pin 5.*

```c
//*** UART ***
#ifdef UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_TX[] = {
  {PD_6, USART1, CH_PIN_DATA(CH_MODE_OUTPUT_50MHz, CH_CNF_OUTPUT_AFPP, 0, AFIO_NONE)}, // from PD_5
  {NC,   NP,     0}
};
#endif

#ifdef UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_RX[] = {
  {PC_1, USART1, CH_PIN_DATA(CH_MODE_INPUT, CH_CNF_INPUT_PUPD, PULLUP, AFIO_NONE)}, // from PD_6
  {NC,    NP,     0}
};
#endif
```

### 3. Modify `variant_CH32V003F4.h`
Open `variant_CH32V003F4.h` and update the definitions to match your changes in `PeripheralPins.c`.

```c
// UART Definitions
#ifndef SERIAL_UART_INSTANCE
  #define SERIAL_UART_INSTANCE  1
#endif
// Default pin used for generic 'Serial' instance
// Mandatory for Firmata
#ifndef PIN_SERIAL_RX
  #define PIN_SERIAL_RX         PC1 // from PD6
#endif
#ifndef PIN_SERIAL_TX
  #define PIN_SERIAL_TX         PD6 // from PD5
#endif
```

> **Warning:** These changes affect **all** sketches compiled for the CH32V003F4 board. If you switch projects, you may need to revert these files.

### 4. Modify your sketch
Add the following lines to your setup() code in your Arduino IDE sketch:
```c
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap2_USART1, ENABLE);
Serial.begin(115200);
```

### 5. Full code
```c
#define ledpin PC4
int counter = 0;

void setup() {
  pinMode(ledpin, OUTPUT);
  // Must enable clock for AFIO
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
  GPIO_PinRemapConfig(GPIO_PartialRemap2_USART1, ENABLE);
  Serial.begin(115200);
}

void loop() {
  digitalWrite(ledpin, HIGH);
  delay(80);
  counter++;
  digitalWrite(ledpin, LOW);
  delay(300);
  Serial.print("blink ");
  Serial.println(counter);
}
```

### 6. Switch the new RX/TX connections
Do not forget to switch to the new RX/TX pins. Then you can reprogram and use serial communication as well.

![Breadboard remap](images/Breadboard-remap.jpg)

---

## Method 2: Shared Serial on Pin 8 (SWIO)
If you need Pin 1 and Pin 5 for other uses (like sensors), you can use **Pin 8 (PD1)** for Serial TX. However, **PD1 is the SWIO programming pin**.

To use this safely, you must dynamically initialize and de-initialize the Serial port in your code. This ensures the pin is only driving data when you specifically print, leaving it free for the programmer (WCH-Link) the rest of the time.

### Code Implementation
Do **not** put `Serial.begin()` in `setup()`. Instead, wrap your print statements like this:

```cpp
void setup() {
  // Do not initialize Serial here!
}

void loop() {
  // 1. Initialize Serial (Claims Pin 8)
  Serial.begin(115200); 
  
  // 2. Send Data
  Serial.println("Battery Status: OK");
  
  // 3. Wait for transmission to complete
  Serial.flush(); 
  
  // 4. End Serial (Releases Pin 8 back to High-Z/Input)
  Serial.end(); 
  
  // Pin 8 is now free for SWIO programming
  delay(1000); 
}
```

**Pros:** Keeps Pins 1, 5, and 6 free for sensors.  
**Cons:** You cannot debug continuously; using the Serial Monitor constantly will make it difficult to upload new code.

---

## Unbricking / Full Erasure
If you configure the pins incorrectly (e.g., setting SWIO to output low permanently) or disable the debug interface, the WCH-Link might fail to detect the chip.

To recover the chip, you need to perform a full erasure using `minichlink`.

### Prerequisites
1.  Clone the [cnlohr/ch32fun](https://github.com/cnlohr/ch32fun) or [openwch/ch32v003](https://github.com/openwch/ch32v003) repository.
```bash
cd ~
git clone --depth 1 https://github.com/cnlohr/ch32fun.git
```

3.  Go to the directory
```bash
cd ch32fun/minichlink
```

4.  Run compile
```bash
make
```

In case of an error
```bash
/usr/bin/ld: cannot find -lusb-1.0: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [Makefile:47: minichlink] Error 1
```

Install dependencies
```bash
sudo apt update
sudo apt install libusb-1.0-0-dev libudev-dev
```

5.  Install the binary
```bash
sudo cp minichlink /usr/local/bin/
```

Check if succesfull
```bash
which minichlink
```
Should output
```bash
/usr/local/bin/minichlink
```

6.  Connect the WCH-LinkE to the chip using a single wire interface (SWD).

### The Unbrick Command
Run the following command in your terminal:

```bash
minichlink -u
```

*   **`-u`**: This flag commands the programmer to perform a chip erase and re-enable the SWIO interface.
*   If this fails, try holding the chip in "Reset" (connect NRST to GND if available, or power cycle rapidly) while issuing the command.

---

## References & Credits
This guide describes advanced configuration techniques derived from the following resources:
*   **YouTube:** [Re-mapping the pins on a CH32v003](https://www.youtube.com/watch?v=jhtcRypzWq4) – Visual guide on locating and editing the Arduino Core files for pin redefinition.
*   **Blog:** [CH32v003 Serial and SWIO Communication Clash](https://onecircuit.blogspot.com/2024/10/0000-0000-1111-0100.html) – Detailed analysis of pin conflicts on the SOP-8 package and methods for resolving SWIO/Serial overlaps.