Last active
July 15, 2023 21:32
-
-
Save hexeguitar/b08104484706dde16b6aae7195496967 to your computer and use it in GitHub Desktop.
ch32v003 project for testing various clock configurations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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