CH592 UART

2025-08-21

Here's a program to send data over the UART:

// TXD3: PA5


#include "CH59x_common.h"
#include <string.h>


int main()
{
  char *s = "Hello world\r\n";
  SetSysClock(CLK_SOURCE_PLL_60MHz);
  
  GPIOA_ModeCfg(bTXD3, GPIO_ModeOut_PP_5mA);
  UART3_DefInit();  
  
  while (1) {
    UART3_SendString((uint8_t *)s, strlen(s));
    mDelaymS(1000);
  }
  
}

Note bTXD3 is equivalent to PA5. Make sure to include CH59x_uart3.c in the compilation Makefile:

C_SOURCES = \
src/main.c \
../../vendor/StdPeriphDriver/CH59x_clk.c \
../../vendor/StdPeriphDriver/CH59x_gpio.c \
../../vendor/StdPeriphDriver/CH59x_pwr.c \
../../vendor/StdPeriphDriver/CH59x_sys.c \
../../vendor/StdPeriphDriver/CH59x_uart3.c \				# <== add this
../../vendor/RVMSIS/core_riscv.c \

Using the DEBUG flag

There is a convenience offered in the SDK; the DEBUG flag. As per CH59x_common.h it can take one of these values:

#define Debug_UART0        0
#define Debug_UART1        1
#define Debug_UART2        2
#define Debug_UART3        3

Which is followed by the line:

#ifdef DEBUG
#include <stdio.h>
#endif

And in CH59x_sys.h:

#ifdef DEBUG
int _write(int fd, char *buf, int size)
{
    int i;
    for(i = 0; i < size; i++)
    {
#if DEBUG == Debug_UART0
        while(R8_UART0_TFC == UART_FIFO_SIZE);
        R8_UART0_THR = *buf++;
#elif DEBUG == Debug_UART1
        while(R8_UART1_TFC == UART_FIFO_SIZE);
        R8_UART1_THR = *buf++;
#elif DEBUG == Debug_UART2
        while(R8_UART2_TFC == UART_FIFO_SIZE);
        R8_UART2_THR = *buf++;
#elif DEBUG == Debug_UART3       
        while(R8_UART3_TFC == UART_FIFO_SIZE);
        R8_UART3_THR = *buf++;
#endif
    }
    return size;
}

#endif

These constructs enable us to use printf(). But there's more... In CH592SFR.h:

#ifdef  DEBUG
#define PRINT(X...) printf(X)
#else
#define PRINT(X...)
#endif

Which means if we use PRINT(X) instead, depending on the DEBUG flag, this expression will be evaluated and still not cause an compiling error if we are not in DEBUG condition.

We will see an example.

// TXD3: PA5


#define DEBUG	Debug_UART3
#include "CH59x_common.h"


int main()
{
  char *s = "Hello world\r\n";
  SetSysClock(CLK_SOURCE_PLL_60MHz);
  
#ifdef DEBUG
  GPIOA_ModeCfg(bTXD3, GPIO_ModeOut_PP_5mA);
  UART3_DefInit();
#endif
  
  while (1) {
    PRINT(s);
    mDelaymS(1000);
  }
  
}

Or to switch up the convenience, we could move the #define DEBUG Debug_UART3 flag to the makefile.

Insert this line at the top:

DEFINES = -DDEBUG=Debug_UART3

And change:

CFLAGS = $(MCU) $(C_INCLUDES) $(OPT) $(DEFINES) -Wall -fdata-sections -ffunction-sections