Skip to content

Instantly share code, notes, and snippets.

@hexeguitar
Last active July 15, 2023 21:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hexeguitar/b08104484706dde16b6aae7195496967 to your computer and use it in GitHub Desktop.
Save hexeguitar/b08104484706dde16b6aae7195496967 to your computer and use it in GitHub Desktop.
ch32v003 project for testing various clock configurations
/**
* @file sysclk_test.c
* @author Piotr Zapart
* @brief Testing various sysclock configurations for the ch32v003
* LED Pin definition for the NanoCH32V003 board
* Try different conbinations in the funconfig.h file, ie:
*
* #define FUNCONF_USE_HSI 1
* #define FUNCONF_USE_PLL 1
* #define CH32V003 1
*
* #define FUNCONF_USE_HSE 1
* #define FUNCONF_USE_PLL 0
* #define CH32V003 1
*
* @version 0.1
* @date 2023-07-14
*/
#define PIN_LED 6
#include "ch32v003fun.h"
#include <stdio.h>
#include "ch32v003_GPIO_branchless.h"
// --------------------------------------------------------
const char msg_sep[] = "====================================\n";
const char msg_en[] = "Enabled";
const char msg_dis[] = "Disabled";
const char *msg_clkSrc[] = {"HSI", "HSE", "PLL"};
const char *msg_mco[] = {"Disabled", "SYSCLK", "HSI 24MHz", "HSE", "PLL"};
typedef enum
{
MCO_DISABLED = 0,
MCO_OUT_SYSCLK = (4<<24),
MCO_OUT_HSI = (5<<24),
MCO_OUT_HSE = (6<<24),
MCO_OUT_PLL = (7<<24)
}mco_cfg_e;
uint8_t getMCOidx(uint32_t mco);
void print_sysclk();
void MCO_cfg(mco_cfg_e cfg);
void SetupUART( int uartBRR );
// --------------------------------------------------------
/**
* @brief alternative SystemInit function, fixes few issues:
* - correct source for the PLL
* - safe HSE clock switching
* - enabled clock security bit
*/
void SystemInit2()
{
#if FUNCONF_HSE_BYPASS
#define HSEBYP (1<<18)
#else
#define HSEBYP 0
#endif
// set the correct clock source for the PLL
#if defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
#define PLL_SRC RCC_PLLSRC_HSE_Mul2
#endif
#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
#define PLL_SRC RCC_PLLSRC_HSI_Mul2
#endif
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
#define BASE_CFGR0 (RCC_HPRE_DIV1 | PLL_SRC) // HCLK = SYSCLK = APB1 And, enable PLL
#else
#define BASE_CFGR0 (RCC_HPRE_DIV1) // HCLK = SYSCLK = APB1 And, no PLL
#endif
// version with HSI turned off if using HSE
//#define BASE_CTLR (((FUNCONF_HSITRIM) << 3) | RCC_CSSON | HSEBYP)
// version with HSI always ON
#define BASE_CTLR (((FUNCONF_HSITRIM) << 3) | RCC_HSION | RCC_CSSON | HSEBYP)
#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
RCC->CFGR0 = BASE_CFGR0;
RCC->CTLR = BASE_CTLR | RCC_HSION | RCC_PLLON; // Use HSI, enable PLL.
#else
RCC->CFGR0 = BASE_CFGR0; // PLLCLK = HCLK = SYSCLK = APB1
RCC->CTLR = BASE_CTLR | RCC_HSION; // Use HSI, Only.
#endif
#endif
#if defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
RCC->CFGR0 = RCC_HPRE_DIV1;
RCC->CTLR = BASE_CTLR | RCC_HSION; // start with HSI first, no PLL
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; // enable AFIO
AFIO->PCFR1 |= GPIO_Remap_PA1_2; // remap PA1 PA2 to XTAL
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
RCC->CTLR = BASE_CTLR | RCC_HSION | RCC_HSEON; // Keep HSI and PLL on just in case, while turning on HSE
while(!(RCC->CTLR&RCC_HSERDY)); // wait untill the HSE is ready
RCC->CFGR0 = BASE_CFGR0 | RCC_SW_HSE; // switch the clock to HSE
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04); // Wait till HSE is used as system clock source
RCC->CTLR = BASE_CTLR | RCC_HSEON | RCC_PLLON ; // Turn off HSI, enable PLL
#else
RCC->CTLR = BASE_CTLR | RCC_HSION | RCC_HSEON ; // Keep HSI on while turning on HSE
while(!(RCC->CTLR&RCC_HSERDY)); // Wait till HSE is ready
RCC->CFGR0 = BASE_CFGR0 | RCC_SW_HSE;
RCC->CTLR = BASE_CTLR | RCC_HSEON; // Turn off PLL and HSI.
#endif
#endif
#if FUNCONF_SYSTEM_CORE_CLOCK > 25000000
FLASH->ACTLR = FLASH_ACTLR_LATENCY_1; //+1 Cycle Latency
#else
FLASH->ACTLR = FLASH_ACTLR_LATENCY_0; // +0 Cycle Latency
#endif
RCC->INTR = 0x009F0000; // Clear PLL, CSSC, HSE, HSI and LSI ready flags.
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
// From SetSysClockTo_48MHZ_HSI
while((RCC->CTLR & RCC_PLLRDY) == 0); // Wait till PLL is ready
RCC->CFGR0 = BASE_CFGR0 | RCC_SW_PLL; // Select PLL as system clock source
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08); // Wait till PLL is used as system clock source
#endif
#if defined( FUNCONF_USE_UARTPRINTF ) && FUNCONF_USE_UARTPRINTF
SetupUART( UART_BRR );
#endif
#if defined( FUNCONF_USE_DEBUGPRINTF ) && FUNCONF_USE_DEBUGPRINTF
// Clear out the sending flag.
*DMDATA1 = 0x0;
*DMDATA0 = 0x80;
#endif
}
// --------------------------------------------------------
void MCO_cfg(mco_cfg_e cfg)
{
RCC->CFGR0 &= ~RCC_CFGR0_MCO;
RCC->CFGR0 |= cfg & RCC_CFGR0_MCO;
}
// --------------------------------------------------------
uint8_t getMCOidx(uint32_t mco)
{
mco >>= 24;
return (mco ? mco-3 : mco);
}
// --------------------------------------------------------
void print_sysclk()
{
uint32_t ctlr = RCC->CTLR;
uint32_t cfgr0 = RCC->CFGR0;
printf("%s", msg_sep);
printf("HSI %s\n", ctlr & RCC_HSION ? msg_en : msg_dis);
printf("HSI trim = %ld\n",(ctlr & RCC_HSITRIM)>>3);
printf("HSI cal = %ld\n",(ctlr & RCC_HSICAL)>>8);
printf("HSE %s\n", ctlr & RCC_HSEON ? msg_en : msg_dis);
printf("PLL %s\n", ctlr & RCC_PLLON ? msg_en : msg_dis);
printf("PLL Source = %s\n", msg_clkSrc[(cfgr0 & (1<<16))>>16]);
printf("Clk Security %s\n", ctlr & RCC_CSSON ? msg_en : msg_dis);
printf("HSE bypass %s\n", ctlr & RCC_HSEBYP ? msg_en : msg_dis);
printf("Sysclk source = %s\n", msg_clkSrc[(cfgr0 & 0x0C)>>2]);
printf("MCO output: %s\n", msg_mco[getMCOidx(cfgr0 & RCC_CFGR0_MCO)]);
}
// --------------------------------------------------------
int main()
{
Delay_Ms(50); // adding a bit of delay here partially fixes the problem with WCHLinkE bricking the MCU
SystemInit2();
GPIO_port_enable(GPIO_port_D);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_D, PIN_LED), GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_D, PIN_LED), high);
// needed for MCO output
GPIO_port_enable(GPIO_port_C);
GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_C, 4), GPIO_pinMode_O_pushPullMux, GPIO_Speed_50MHz);
Delay_Ms(200);
printf("%s", msg_sep);
printf("System Clock test\n");
//MCO_cfg(MCO_OUT_SYSCLK);
print_sysclk();
while(1)
{
// blink onboard led to show the mcu is running
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_D, PIN_LED), high);
Delay_Ms(100);
GPIO_digitalWrite(GPIOv_from_PORT_PIN(GPIO_port_D, PIN_LED), low);
Delay_Ms(100);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment