//ch32x035 #include "ch32fun_pwm.h" #include "ch32fun_gpio.h" #if defined( CH32X03x ) static volatile uint8_t pin_timer[]={ // timer, map, ch 0201, 0202, 0203, 0204, 0332, 0, 0301, 0302, 0, 0, 0, 0, 0215, 0216, 0217, 0, 0, 0, 0, 0, 0, 0205, 0206, 0207, 0116, 0117, 0, 0223, 0224, 0312, 0125, 0126, 0127, 0121, 0122, 0123, 0124, 0, 0, 0212, 0241, 0242, 0243, 0244, 0, 0211, 0, 0, 0131, 0132, 0133, 0134, 0, 0135, 0136, 0137, 0, 0, 0, 0, 0, 0, 0262, 0263, 0114, 0, 0322, 0321, 0, 0, 0, 0, }; static volatile uint32_t base[]={TIM1_BASE,TIM2_BASE,TIM3_BASE}; #elif defined( CH32V20x ) static volatile uint8_t pin_timer[]={ // timer-1, map, ch 0101, 0102, 0103, 0104, 0, 0, 0201, 0202, 0001, 0002, 0003, 0004, 0, 0, 0, 0131, 0223, 0224, 0, 0132, 0221, 0222, 0301, 0302, 0303, 0304, 0133, 0134, 0, 0005, 0006, 0007, 0, 0, 0, 0, 0, 0, 0231, 0232, 0233, 0234, 0, 0, 0, 0, 0, 0, }; static volatile uint32_t base[]={TIM1_BASE,TIM2_BASE,TIM3_BASE,TIM4_BASE}; #endif void general_pwm(uint8_t pin, uint16_t limit, uint16_t val, uint16_t prescaler) { #if defined( CH32X03x ) if(pin>=72) return; //48->72 #else if(pin>=32) return; #endif uint8_t tmr=pin_timer[pin]; if(tmr == 0) return; uint8_t ch=tmr%8; uint8_t alt=(tmr/8)%8; // alternate setting tmr>>=6; #if defined( CH32V20x ) tmr++; #endif TIM_TypeDef *tim = ((TIM_TypeDef *) base[tmr-1]); volatile uint32_t *enadrs=&(RCC->APB2PCENR); #if defined( CH32X03x ) *(enadrs+tmr/2) |= 1<<((tmr+10)%12); //RCC_APB2Periph_TIMx 0x800,1,2 AFIO->PCFR1 &= ~( (7-tmr/3*4)<<(tmr*3+12) ); // AFIO_PCFR1_TIM1_REMAP 7,7,3 AFIO->PCFR1 |= alt<<(tmr*3+12); // AFIO_PCFR1_TIMx_REMAP_0 15,18,21 #else *(enadrs+(tmr>1)) |= 1<<( (tmr==1)*12+tmr-2 ); //RCC_APB2Periph_TIMx 11,0-2 AFIO->PCFR1 &= ~( (3-tmr/4*2)<<(tmr*2+4) ); // AFIO_PCFR1_TIM1_REMAP 3,3,3,1 AFIO->PCFR1 |= alt<<(tmr*2+4); // AFIO_PCFR1_TIMx_REMAP_0 6,8,10,12 #endif tim->PSC = prescaler; tim->CTLR1 |= TIM_ARPE; tim->ATRLR = limit; tim->CCER |= (TIM_CC1E | TIM_CC1P)<<(4*(ch-1)-ch/5*14); // 1,1N,2,2N,3,3N,4 volatile uint16_t *chadrs=&(tim->CHCTLR1); *(chadrs+((ch-1)&2)) |= (TIM_OC1M_2 | TIM_OC1M_1 | TIM_OC1PE)<<((ch-1)%2*8); #if defined( CH32X03x ) volatile uint32_t *vladrs=&(tim->CH1CVR); #else volatile uint16_t *vladrs=&(tim->CH1CVR); #endif *(vladrs+(ch-1)%4) = val; tim->BDTR |= TIM_MOE; tim->SWEVGR |= TIM_UG; tim->CTLR1 |= TIM_CEN; funPinMode2(pin, GPIO_CFGLR_OUT_50Mhz_AF_PP); } void c_pwm_sub(mrb_vm *vm, mrb_value *v){ PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; if(handle->freq_num==0){ funDigitalWrite(handle->pin_num,0); funPinMode2(handle->pin_num, GPIO_CFGLR_OUT_50Mhz_PP); }else{ uint32_t limit=FUNCONF_SYSTEM_CORE_CLOCK/(handle->freq_num); uint32_t prescaler=limit>>16; limit/=(prescaler+1); uint16_t val=limit*(handle->duty_num)/10000; general_pwm(handle->pin_num, limit, val, prescaler); } } void c_pwm_new(mrb_vm *vm, mrb_value *v, int argc){ v[0] = mrbc_instance_new(vm, v[0].cls, sizeof(PWM_HANDLE)); PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; handle->pin_num = GET_INT_ARG(1); MRBC_KW_ARG(frequency, freq, duty); if( MRBC_ISNUMERIC(duty) ){ handle->duty_num = MRBC_TO_INT(duty)*100; }else{ handle->duty_num = 5000; } if( MRBC_ISNUMERIC(frequency) ){ handle->freq_num = MRBC_TO_INT(frequency); }else if( MRBC_ISNUMERIC(freq) ){ handle->freq_num = MRBC_TO_INT(freq); }else{ handle->freq_num = 1000; } MRBC_KW_DELETE(frequency, freq, duty); c_pwm_sub(vm,v); } static void c_pwm_duty(mrbc_vm *vm, mrbc_value *v, int argc){ PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; handle->duty_num = MRBC_ARG_I(1)*100; c_pwm_sub(vm,v); } static void c_pwm_frequency(mrbc_vm *vm, mrbc_value *v, int argc){ PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; handle->freq_num = MRBC_ARG_I(1); c_pwm_sub(vm,v); } static void c_pwm_period_us(mrbc_vm *vm, mrbc_value *v, int argc){ PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; uint16_t us = MRBC_ARG_I(1); uint32_t freq = ( us==0 ? 0 : 1000000 / us ); handle->freq_num = freq; c_pwm_sub(vm,v); } static void c_pwm_pulse_width_us(mrbc_vm *vm, mrbc_value *v, int argc){ PWM_HANDLE *handle = (PWM_HANDLE *)v[0].instance->data; handle->duty_num = MRBC_ARG_I(1)*(handle->freq_num)/100; //1e6/1e4 c_pwm_sub(vm,v); } void mrbc_init_class_pwm(void){ mrbc_class *pwm = mrbc_define_class(0, "PWM", mrbc_class_object); mrbc_define_method(0, pwm, "new", c_pwm_new); mrbc_define_method(0, pwm, "duty", c_pwm_duty); mrbc_define_method(0, pwm, "frequency", c_pwm_frequency); mrbc_define_method(0, pwm, "period_us", c_pwm_period_us); mrbc_define_method(0, pwm, "pulse_width_us", c_pwm_pulse_width_us); }