/**
* @file HW_PWM_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2025 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
* @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)
{
if(level)
PWM_Start(1000, level * 1000, channelS);
else
PWM_Start(1000, 0, channelS);
}
/**
* @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(dutyS < 0)
dutyS = 0;
P_SW2 |= 0x80;
if(channelS == PWM_CHANNEL_1P || channelS == PWM_CHANNEL_1N){
PWMA_PS = (PWMA_PS & 0xFC) | (PWM_PIN_POS_1 << 0); //
PWMA_CCER1 &= 0xF0;
PWMA_CCMR1 = 0x60;
PWMA_CCER1 |= 0x05;
PWMA_CCR1 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_2P || channelS == PWM_CHANNEL_2N){
PWMA_PS = (PWMA_PS & 0xF3) | (PWM_PIN_POS_1 << 2); //
PWMA_CCER1 &= 0x0F;
PWMA_CCMR2 = 0x60;
PWMA_CCER1 |= 0x50;
PWMA_CCR2 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_3P || channelS == PWM_CHANNEL_3N){
PWMA_PS = (PWMA_PS & 0xCF) | (PWM_PIN_POS_1 << 4); // PWM3N_2 Heat
PWMA_CCER2 &= 0xF0;
PWMA_CCMR3 = 0x60;
PWMA_CCER2 |= 0x05;
PWMA_CCR3 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_4P || channelS == PWM_CHANNEL_4N){
PWMA_PS = (PWMA_PS & 0x3F) | (PWM_PIN_POS_1 << 6); //
PWMA_CCER2 &= 0x0F;
PWMA_CCMR4 = 0x60;
PWMA_CCER2 |= 0x50;
PWMA_CCR4 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_5P){
PWMB_PS = (PWMB_PS & 0xFC) | (PWM_PIN_POS_1 << 0); //
PWMB_CCER1 &= 0xF0;
PWMB_CCMR1 = 0x60;
PWMB_CCER1 |= 0x01;
PWMB_CCR5 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_6P){
PWMB_PS = (PWMB_PS & 0xF3) | (PWM_PIN_POS_1 << 2); // PWM6_2 DAC_PWM P54
PWMB_CCER1 &= 0x0F; // 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
}
else if(channelS == PWM_CHANNEL_7P){
PWMB_PS = (PWMB_PS & 0xCF) | (PWM_PIN_POS_0 << 4); //
PWMB_CCER2 &= 0xF0;
PWMB_CCMR3 = 0x60;
PWMB_CCER2 |= 0x01;
PWMB_CCR7 = dutyS / 100.0 * periodS;
}
else if(channelS == PWM_CHANNEL_8P){
PWMB_PS = (PWMB_PS & 0x3F) | (PWM_PIN_POS_0 << 6); // PWM8 23 TMC_STEP
PWMB_CCER2 &= 0x0F;
PWMB_CCMR4 = 0x60;
PWMB_CCER2 |= 0x10;
PWMB_CCR8 = dutyS / 100.0 * periodS;
}
if((channelS & 0xF0) == 0xF0){ // channel 5-8
PWMB_ARR = periodS; // Set period time
PWMB_ENO |= ((uint8_t)1 << ((channelS & 0x0F) * 2)); // Enable channel output
PWMB_BKR = 0x80; // Enable main output
PWMB_CR1 = 0x01; // Start counter
}
else{ // channel 1-4
PWMA_ARR = periodS;
PWMA_ENO |= channelS;
PWMA_BKR = 0x80;
PWMA_CR1 = 0x01;
}
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, float dutyS, uint8_t channelS)
{
#if defined (PWM_T01C1)
if(channelS == PWM_T01C1){
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
// TIM1->CNT = 0;
// TIM1->ARR = periodS;
// TIM1->CCR2 = (uint32_t)(periodS * dutyS);
// TIM1->EGR = TIM_EGR_UG;
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
__HAL_TIM_SET_AUTORELOAD(&htim1, periodS);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint32_t)(periodS / 100 * dutyS));
}
#endif
#if defined (PWM_T02C2)
if(channelS == PWM_T02C2){
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_AUTORELOAD(&htim2, periodS);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (uint32_t)(periodS / 100 * dutyS));
}
#endif
#if defined (PWM_T03C2)
if(channelS == PWM_T03C2){
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
__HAL_TIM_SET_AUTORELOAD(&htim3, periodS);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, (uint32_t)(periodS / 100 * dutyS));
}
#endif
}
/**
* @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)
{
#if defined (PWM_T01C1)
if(channelS == PWM_T01C1){
if(level)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, __HAL_TIM_GET_AUTORELOAD(&htim1));
else
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
#endif
#if defined (PWM_T02C2)
if(level)
{
TIM2->ARR = 0;
TIM2->CCR4 = 0;
TIM2->EGR = TIM_EGR_UG;
}
else
{
TIM2->ARR = 0;
TIM2->CCR4 = 1;
TIM2->EGR = TIM_EGR_UG;
}
if(channelS == PWM_T02C2)
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
#endif
#if defined (PWM_T03C2)
if(level)
{
TIM3->ARR = 0;
TIM3->CCR4 = 0;
TIM3->EGR = TIM_EGR_UG;
}
else
{
TIM3->ARR = 0;
TIM3->CCR4 = 1;
TIM3->EGR = TIM_EGR_UG;
}
if(channelS == PWM_T03C2)
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
#endif
}
// for generate spefied pulse
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
}
#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 *********************************/