/** * @file HW_PWM_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2023 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief Familiar definition of PWM for users * * @version * - 1_01_220602 > ATY * -# Preliminary version, first Release * - Undone ******************************************************************************** */ #ifndef __HW_PWM_ATY_C #define __HW_PWM_ATY_C #include "HW_PWM_ATY.h" /******************************* For user *************************************/ #if defined(__STC8G_ATY) /** * @brief set pulse period with specified duty with PCA * @param periodS pulse period, us * @param dutyS pulse duty, 0-100.0 @ % * @param channelS channel to start or to change param * @todo any freq with ITM1 */ void PWM_Start(uint32_t periodS, uint8_t dutyS, uint8_t channelS) { // P_SW1 |= 0x10; // PCA1 P36 // P3M0 = 0x40; // P36 PP out CCON = 0x00; // PWM freq = SYS freq / n / 256 if(periodS <= 10) CMOD = 0x08; // PCA clk = sys clk, 32/3us 93.75KHz @ 24MHz else if(periodS <= 21 && periodS > 10) CMOD = 0x02; // PCA clk = sys clk / 2, else if(periodS <= 42 && periodS > 21) CMOD = 0x0A; // PCA clk = sys clk / 4 else if(periodS <= 64 && periodS > 42) CMOD = 0x0C; // PCA clk = sys clk / 6 else if(periodS <= 85 && periodS > 64) CMOD = 0x0E; // PCA clk = sys clk / 8 else if(periodS > 85)//periodS <= 128 && periodS > 85) CMOD = 0x00; // PCA clk = sys clk / 12 else CMOD = 0x04; // PCA clk = TIM1 IT CL = 0x00; // init counter value CH = 0x00; if(channelS == 1) { CCAPM1 = 0x42; // PCA at PWM mode // PCA_PWM1 = 0x80; // 6bit PWM // PCA_PWM1 = 0x40; // 7bit PWM PCA_PWM1 = 0x00; // 8bit PWM // PCA_PWM1 = 0xC0; // 10bit PWM CCAP1L = (uint16_t)(0xFFFF * (float)((100 - dutyS) / 100.0)); CCAP1H = (uint16_t)(0xFFFF * (float)((100 - dutyS) / 100.0)) >> 8; } CR = 1; // start PCA } /** * @brief stop PWM output with specified level with PCA * @param level IO level after stop PWM * @note voltage lower than write pin */ void PWM_Stop(uint8_t level) { if(level) { PCA_PWM1 &= 0xC0; CCAP1H = 0x00; } else { PCA_PWM1 |= 0x3F; CCAP1H = 0xFF; } CR = 0; } /** * @brief set pulse period with specified duty with PCA * @param periodS pulse period, us * @param dutyS pulse duty, 0-100.0 @ % * @param channelS channel to start or to change param * @todo any freq with ITM1 */ void PWM_StartPulse(uint32_t periodS, uint8_t channelS) { CCON = 0x00; CMOD = 0x08; // PCA clk = sys clk, 32/3us 93.75KHz @ 24MHz CL = 0x00; // init counter value CH = 0x00; if(channelS == 1) { CCAPM1 = 0x4D; // PCA at fast pulse mode, enbale IT CCAP1L = periodS; CCAP1H = periodS >> 8; } CR = 1; // start PCA EA = 1; } void PCA_Isr() interrupt 7 { CCF1 = 0; CL = 0x00; CH = 0x00; } #elif defined(__STC51_ATY) /** * @brief set pulse period with specified duty * @param periodS pulse period, us * @param dutyS pulse duty, 0-100.0 @ % * @param channelS channel to start or to change param * @note Undone */ void PWM_Start(uint32_t periodS, float dutyS, uint8_t channelS) { if(channelS == 2) { P_SW2 |= 0x80; PWMA_CCER1 = 0x00; PWMA_CCMR2 = 0x60; PWMA_CCER1 = 0x50; PWMA_CCR2 = dutyS / 100.0 * periodS; PWMA_ARR = periodS; PWMA_ENO = 0x08; PWMA_PS = (PWMA_PS & 0xF3) | 0x04; // PWM2N_2 TMC_STEP PWMA_BKR = 0x80; PWMA_CR1 = 0x01; P_SW2 &= 0x7F; } else if(channelS == 3) { P_SW2 |= 0x80; PWMA_CCER2 = 0x00; PWMA_CCMR3 = 0x60; PWMA_CCER2 = 0x05; PWMA_CCR3 = dutyS / 100.0 * periodS; PWMA_ARR = periodS; PWMA_ENO = 0x20; PWMA_PS = (PWMA_PS & 0xCF) | 0x10; // PWM3N_2 Heat PWMA_BKR = 0x80; PWMA_CR1 = 0x01; P_SW2 &= 0x7F; } else if(channelS == 6) { P_SW2 |= 0x80; PWMB_CCER1 = 0x00; // Set 0 of CCERx before write CCMRx PWMB_CCMR2 = 0x60; // Set CC6 PWMB output mode PWMB_CCER1 = 0x10; // Enable CC6 channel PWMB_CCR6 = dutyS / 100.0 * periodS; // Set dutys time PWMB_ARR = periodS; // Set period time PWMB_ENO = 0x04; // Enable PWM6P output PWMB_PS = (PWMB_PS & 0xF3) | 0x04; // PWM6_2 DAC_PWM P54 PWMB_BKR = 0x80; // Enable main output PWMB_CR1 = 0x01; // Start counter P_SW2 &= 0x7F; } } /** * @brief stop PWM output with specified level * @param level IO level after stop PWM * @param channelS channel to start or to change param * @note Undone, not real stop */ void PWM_Stop(uint8_t level, uint8_t channelS) { PWM_Start(1000, level * 1000, channelS); } #elif defined(__STM32_HAL_ATY) #include "tim.h" /** * @brief set pulse period with specified duty * @param periodS pulse period, us * @param dutyS pulse duty, 0-100.0 @ % * @param channelS channel to start or to change param * @note Undone */ void PWM_Start(uint32_t periodS, uint8_t dutyS, uint8_t channelS) { HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); TIM1->CNT = 0; HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); TIM1->ARR = periodS; TIM1->CCR4 = dutyS; TIM1->EGR = TIM_EGR_UG; } /** * @brief stop PWM output with specified level * @param level IO level after stop PWM * @note Undone */ void PWM_Stop(uint8_t level) { if(level) { TIM1->ARR = 0; TIM1->CCR4 = 0; TIM1->EGR = TIM_EGR_UG; } else { TIM1->ARR = 0; TIM1->CCR4 = 1; TIM1->EGR = TIM_EGR_UG; } HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); } #elif defined(__ESP8266_RTOS_ATY) #include "driver/pwm.h" #define PWM_CHANNEL_FAN 0 #define PWM_CHANNEL_COLD 1 #define PWM_CHANNEL_WARM 2 const uint32_t* channelPin = {4, 2, 15}; uint8_t* dutiesPercent = {50, 50, 50}; /** * @see https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/api-reference/peripherals/pwm.html * */ void PWM_Init(void) { uint32_t period = 1000; uint32_t duties[3]; duties[0] = dutiesPercent[0] / 100.0 * period; duties[1] = dutiesPercent[1] / 100.0 * period; duties[2] = dutiesPercent[2] / 100.0 * period; pwm_init(period, duties, 3, channelPin); } /** * @brief set pulse period with specified duty * @param periodS pulse period, us * @param dutyS pulse duty, 0-100.0 @ % * @param channelS channel to start or to change param * @todo not tested */ void PWM_Start(uint32_t periodS, uint8_t dutyS, uint8_t channelS) { extern pwm_obj_t* pwm_obj; if(periodS = !pwm_obj->period) pwm_set_period(periodS); pwm_set_duty(channelS, (uint32_t)((float)(dutyS / 100.0) * periodS)); // pwm_set_period_duties(period, allDuties); pwm_start(); } /** * @brief stop PWM output with specified level * @param level IO level after stop PWM * @todo not tested */ void PWM_Stop(uint8_t level) { if(level) pwm_stop(0x00); else pwm_stop(0xFF); pwm_deinit(); } #endif /* PLATFORM */ #ifdef __DEBUG_HW_PWM_ATY void PWM_Test(uint8_t testType) { if(testType == 11) { static dutyCount = 0; dutyCount++; UartSendStr("\r\n"); UartSendByte(dutyCount / 100 + '0'); UartSendByte(((uint8_t)dutyCount % 100) / 10 + '0'); UartSendByte((uint8_t)dutyCount % 10 + '0'); UartSendStr("\r\n"); if(dutyCount <= 100) PWM_Start(10, dutyCount, 1); else if(dutyCount > 100 && dutyCount < 200) PWM_Start(10, 200 - dutyCount, 1); else dutyCount = 0; } else if(testType == 21) { static uint8_t tempa = 10; PWM_Start(tempa, 50, 1); if(tempa == 10) tempa = 21; else if(tempa == 21) tempa = 42; else if(tempa == 42) tempa = 64; else if(tempa == 64) tempa = 85; else if(tempa == 85) tempa = 128; else tempa = 10; } else if(testType == 31) { static uint8_t stopLevel = 0; PWM_Start(10, 50, 1); stopLevel = !stopLevel; UartSendByte(stopLevel + '0'); PWM_Stop(stopLevel); // P36 = stopLevel; } else if(testType == 22) { static uint32_t freqCount = 0xFFFF; P37 = 0; P35 = 0; if(freqCount > 100) freqCount -= 100; else if(freqCount > 0 && freqCount <= 100) freqCount -= 1; else if(freqCount == 0) freqCount = 0xFFFF; PWM_StartPulse(freqCount, 1); UartSendStr("\r\n"); UartSendByte(freqCount / 10000 + '0'); UartSendByte(((uint16_t)freqCount % 10000) / 1000 + '0'); UartSendByte(((uint16_t)freqCount % 1000) / 100 + '0'); UartSendByte(((uint16_t)freqCount % 100) / 10 + '0'); UartSendByte((uint16_t)freqCount % 10 + '0'); } } #endif /* __DEBUG_HW_PWM_ATY */ /******************************************************************************/ /** * @brief set pulse frequence with half dutycycle * @param periodS pulse frequence */ void PwmFreqSet(uint32_t periodS, uint8_t channelS) { PWM_Start(periodS, 50, channelS); } // /** // * @brief set pulse frequence with half period // * @param periodS pulse frequence // */ // void PwmFreqSet(uint32_t periodS, uint8_t channelS) // { // PWM_Start(periodS, periodS / 2, channelS); // } #endif /* __HW_PWM_ATY_C */ /******************************** End Of File *********************************/