Ch32v003 sop8 version, pin mapping issue? - Page 1
Forum section: electronics / general

author: Nout1
author_rank: Newbie
timestamp: January 27, 2025, 10:17:21 pm
content: I'm struggling to get a correct behaviour from PA1 and PA2. Likely it has to do with my code but can't recognize the problem.Through debugging i notice that PA2 always reads a zero, while it should be a pull-up input. PA1 on the other hand works correctly. So delay and other functions do work correctly.PC1 does show a PWM and work correctlyPC2 does drive a led and works correctlyPC4 does drive a led and after the debounce time goes active, which is expected when PA2 reads always zero.I actively disable PA1 and PA2 to be mapped as oscillator pins, but maybe i'm doing it wrong? PA2 seem to be stuck to zero.I'm not using any board, just a bare chip, directly programmed by link-e. I'm also 100% sure there is no short between PA2 and GND.I've tried on 2 samples and both show the same behaviour. So very likely my code is the reason and in some way PA2 always reads a zero.Any help in solving this is appreciated.Here is my code:/**************************************************************** File Name : main.c* for ch32v003j4g6, soic8 package* Description : create 50Hz pwm on pc1, with 2 buttons on pa1 and pa2, increment or decrement the pulse time of the pwm* also control 2 leds, connected to pc2 and pc4** programming pin connections* pin 2 = gnd* pin 4 = 3v3* pin 8 = swdio**************************************************************/#include "ch32v00x.h"#include "delay.h"#include <stdint.h>#define PWM_TIMER TIM2#define PWM_FREQ 50 // 50Hz for servo#define ZERO_ANGLE_PULSE 1500 // 1.5ms pulse width for 0 degrees#define FULL_ANGLE_PULSE 2500 // 2.5ms pulse width for 180 degrees#define MOVE_DURATION_MS 5000 // 5 seconds for full 90-degree motion// Button pins#define UP_PIN GPIO_Pin_1 // PA1#define DOWN_PIN GPIO_Pin_2 // PA2//PWM pin PC1 (mapping TIM2 CH4)#define PWM_PIN GPIO_Pin_1 // PC1// LED pins#define GREEN_LED_PIN GPIO_Pin_2 // PC2#define RED_LED_PIN GPIO_Pin_4 // PC4/* Global Variable */volatile uint8_t button1_state = 0xff; //0xff is the "not pushed" statevolatile uint8_t button2_state = 0xff; //0xff is the "not pushed" state/*// Initialize PWM on PA1 (default mapping is Timer 1 Channel 2 to PA1)void pwm_init(void) {// Enable clocks for TIM1 and GPIOARCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE);// Enable AF clock to get to tim1 + undo any possible pin mapping for PA1 and PA2 back to default mappingRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_PA1_2, DISABLE);// Configure PA1 as alternate function push-pullGPIO_InitTypeDef GPIO_InitStructure = {0};GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // PA1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// Configure TIM1 for PWMTIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / (PWM_FREQ * 20000) - 1;TIM_TimeBaseStructure.TIM_Period = 20000;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //no divisionTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);TIM_OCInitTypeDef TIM_OCInitStructure = {0};TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = ZERO_ANGLE_PULSE;TIM_OC2Init(TIM1, &TIM_OCInitStructure); // Use Channel 2// Enable TIM1 outputs and start the timerTIM_CtrlPWMOutputs(TIM1, ENABLE);TIM_Cmd(TIM1, ENABLE);}// Initialize GPIO for buttons and LEDsvoid gpio_init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);GPIO_InitTypeDef GPIO_InitStructure = {0};// Buttons: PC1 (UP) and PA2 (DOWN) as inputs with pull-upGPIO_InitStructure.GPIO_Pin = GPIO_PIN_UP;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_PIN_DOWN;GPIO_Init(GPIOA, &GPIO_InitStructure);// LEDs: PC2 (Green) and PC4 (Red) as outputsGPIO_InitStructure.GPIO_Pin = GREEN_LED_PIN | RED_LED_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_ResetBits(GPIOC, GREEN_LED_PIN | RED_LED_PIN); // Turn off LEDs initially}*/// Function to configure GPIOvoid gpio_init(void){GPIO_InitTypeDef GPIO_InitStructure = {0};// activate GPIO clocks + Alternate Function clockRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);// make sure PA1 and PA2 are not remapped to OSCGPIO_PinRemapConfig(GPIO_Remap_PA1_2, DISABLE);//LEDS on PA1 and PA2GPIO_InitStructure.GPIO_Pin = UP_PIN | DOWN_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIO_InitStructure);//LEDS on PC2 and PC4GPIO_InitStructure.GPIO_Pin = RED_LED_PIN | GREEN_LED_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOC, &GPIO_InitStructure);// Turn off LEDs initiallyGPIO_ResetBits(GPIOC, GREEN_LED_PIN | RED_LED_PIN);}// Function to configure PWMvoid pwm_init(void){GPIO_InitTypeDef GPIO_InitStructure = {0};TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};TIM_OCInitTypeDef TIM_OCInitStructure = {0};// Enable Timer2 clock and gpioc clockRCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE );// set PC1 as AF to TIM2 CH4 => Pin as Alternate Function Push-PullGPIO_InitStructure.GPIO_Pin = PWM_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOC, &GPIO_InitStructure);// Timer2 base configuration for PWMTIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / (PWM_FREQ * 20000) - 1;TIM_TimeBaseStructure.TIM_Period = 20000;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //no divisionTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseStructure);// PWM Channel 1 configurationTIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = ZERO_ANGLE_PULSE + 500; // Initial duty cycleTIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(PWM_TIMER, &TIM_OCInitStructure); // Channel 1 for PWMTIM_CtrlPWMOutputs(PWM_TIMER, ENABLE );TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable); // Channel 1 for PWM// Enable TIM2 Preload register on ARRTIM_ARRPreloadConfig(PWM_TIMER, ENABLE);// Enable PWM_TIMERTIM_Cmd(PWM_TIMER, ENABLE);//remap PC1 as TIM2 CH1GPIO_PinRemapConfig(GPIO_PartialRemap2_TIM2, ENABLE);}int main(void){SystemCoreClockUpdate(); // Initialize system clocks and peripherals at 48MHzdelay_init();gpio_init();pwm_init();uint32_t lastmills_button = getmills();uint32_t lastmills_servo = getmills();uint16_t pulse_width = 500;while(1) {//debounce the buttonsif ((getmills() - lastmills_button) > 1){button1_state = (button1_state<<1) | GPIO_ReadInputDataBit(GPIOA, UP_PIN);button2_state = (button2_state<<1) | GPIO_ReadInputDataBit(GPIOA, DOWN_PIN);lastmills_button = getmills();}if ((getmills() - lastmills_servo) > 50) {//act on button state. 0x00 means the button is pressed. 0xff means the button is released. any other value is debouncing noiseif (button1_state == 0x00) { //button is pressedGPIO_SetBits(GPIOC, GREEN_LED_PIN);pulse_width++;} else if (button1_state == 0xff) {GPIO_ResetBits(GPIOC, GREEN_LED_PIN);}if (button2_state == 0x00) { //button is pressedGPIO_SetBits(GPIOC, RED_LED_PIN);pulse_width--;} else if (button2_state == 0xff) {GPIO_ResetBits(GPIOC, RED_LED_PIN);}if (pulse_width > 999) { pulse_width = 0; }// TIM_SetCompare1(PWM_TIMER, ZERO_ANGLE_PULSE + pulse_width); // Channel 1lastmills_servo = getmills();}}}

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 28, 2025, 12:45:00 am
content: Maybe this?https://www.eevblog.com/forum/microcontrollers/ch32v003-info/

author: corgon
author_rank: Contributor
timestamp: January 28, 2025, 08:39:32 pm
content: No problem with your config. It works fine.I’ve tested it. Here’s an example:Code:#include "ch32v00x.h"void gpio_init(void){GPIO_InitTypeDef GPIO_InitStructure = {0};// activate GPIO clocks + Alternate Function clockRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// make sure PA1 and PA2 are not remapped to OSCGPIO_PinRemapConfig(GPIO_Remap_PA1_2, DISABLE);//LEDS on PA1 and PA2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIO_InitStructure);// GPIOC SetupRCC->APB2PCENR |= (1 << 4);GPIOC->CFGLR = 0x22222222;}int main(void) {gpio_init();GPIOC->BCR = 0x0FF;while (1) {(GPIOA->INDR & (1 << 1)) ? (GPIOC->BSHR |= (1 << 18)) : (GPIOC->BSHR |= (1 << 2)); // GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1), LED on C2(GPIOA->INDR & (1 << 2)) ? (GPIOC->BSHR |= (1 << 20)) : (GPIOC->BSHR |= (1 << 4)); // GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2), LED on C4}}Do you have in "ch32v00x.h" set to the internal oscillator?Code:#define SYSCLK_FREQ_48MHZ_HSI 48000000

author: corgon
author_rank: Contributor
timestamp: January 29, 2025, 04:06:56 pm
content: So, I tested it, and I'm 100% sure that your problem is in the settings where you have an external crystal selected.The code does work, but it behaves exactly as in your case.Set HSI as I mentioned in my previous message, and it will work.

author: Nout1
author_rank: Newbie
timestamp: January 29, 2025, 04:08:31 pm
content: Hi Corgon ,You made my day!Your code did show exactly the same problem, but after adding the sysclk definition to ch32v00x.h, all works fineAnd also my code works now fine.I've limited experience with this framework and would never have found this by myself.Thanks a lot!

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 29, 2025, 05:20:14 pm
content: Something to be be aware of on the 8 pin is that some pins are bonded to multiple pads on the chip, so you need to be careful to set them to compatible modes