Monday, October 7, 2024

0000 0000 1111 0100

CH32v003 Serial and SWIO Communication Clash

The SOP8 version of the CH32v003 is pretty amazing, and one "feature" is the ability to remap many functions/protocols to the same pins.

This is fine up to the point where there might be a clash. For instance, just look how busy pin 8 is - overloaded including the function that allows it to be programmed and reprogrammed (the one-wire SWIO "single wire" protocol) that for some reason is on the same pin as serial TX.

So...what if you have engaged serial communication AND want to reprogram the chip?

Disaster! But, there are a few ways I have found to get around the problem.

1. Use the minichlink program as we saw in a previous blog and video.
2. Only open up Serial when you need it, and then the chances of interrupting the program to "reprogram" are increased (dodgy I know)
3. Use a mysterious function on a mysterious piece of software to somehow use the one-wire protocol to "printf" from pin 8.

4. Re-map the pins! (see below)
5. Buy the version with more pins you cheapskate!

Now the deep deep deep dive into pin re-allocation took me through many websites, forums and configurations files, but here is what you need to do:

a) find the files PeripheralPins.c and variant_CH32V003F4.h in the core directory as follows:

b) Make the following config file edits to re-map the pins:

1. in the file PeripheralPins.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

2. in the file variant_CH32V003F4.h

// 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

c) add the following lines to your setup() code in your Arduino IDE sketch:

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);
  GPIO_PinRemapConfig(GPIO_PartialRemap2_USART1, ENABLE);
  Serial.begin(115200);

Full code:

#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);
}

After that the only "gotcha" is to remember to switch the connections as follows:

Then you can reprogram at your leisure and enjoy serial communication as well. Speaking of enjoyment, please see the video below and let me know if any of these workarounds did the trick for you as well.



No comments:

Post a Comment