PWM

Last Updated on : 2024-11-20 02:14:53download

File description

API files

The PWM API is located in ty_pwm.h. The driver code for different chip platforms is located in ty_pwm_xxxx.c.

tuya_ble_sdk_demo
└── board
     ├── include
     |    └── ty_pwm.h
     ├── xxxx                      /* xxxx represents the chip platform, such as TLSR825x */
     |    └── ty_board_xxxx        /* xxxx represents the chip platform, such as ty_board_tlsr825x */
     |         └── ty_pwm_xxxx.c   /* xxxx represents the chip platform, such as ty_pin_tlsr825x.c */
     └── board.h

Demo files

File structure of tuya_board_api_demo:

tuya_ble_sdk_demo
├── app  /* API example */
|    ├── include
|    |    └── ty_board_demo
|    |    |    ├── demo_config.h        /* Demo configuration file */
|    |    |    └── ty_pwm_demo.h        /* PWM sample code */
|    |    ├── tuya_ble_board_api_demo.h /* Entry point to Board API example */
|    |    └── tuya_ble_sdk_demo.h       /* Entry point to tuya_ble_sdk application */
|    └── src
|         ├── ty_board_demo
|         |    └── ty_pwm_demo.c        /* PWM sample code */
|         ├── tuya_ble_board_api_demo.c /* Entry point to Board API example */
|         └── tuya_ble_sdk_demo.c       /* Entry point to tuya_ble_sdk application */
└── board /* Example of modifying API code */

Modify demo_config.h to toggle to the PWM example.

#define BOARD_API_DEMO          BOARD_API_PWM

API list

Function name Description
ty_pwm_init Initialize the PWM.
ty_pwm_start Start the PWM output.
ty_pwm_stop Stop the PWM output.
ty_pwm_control Control the PWM.
ty_pwm_uninit Disable the PWM.

API description

ty_pwm_init

Function name ty_pwm_init
Function prototype uint32_t ty_pwm_init(ty_pwm_t* p_pwm);
Description Initialize the PWM.
Parameter p_pwm [in]: The PWM parameter, defined by ty_pwm_t.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_pwm_start

Function name ty_pwm_start
Function prototype uint32_t ty_pwm_start(ty_pwm_t* p_pwm);
Description Start the PWM output.
Parameter p_pwm [in]: The PWM parameter, defined by ty_pwm_t.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_pwm_stop

Function name ty_pwm_stop
Function prototype uint32_t ty_pwm_stop(ty_pwm_t* p_pwm);
Description Stop the PWM output.
Parameter p_pwm [in]: The PWM parameter, defined by ty_pwm_t.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_pwm_control

Function name ty_pwm_control
Function prototype uint32_t ty_pwm_control(ty_pwm_t* p_pwm, uint8_t cmd, void* arg);
Description Control the PWM.
Parameter p_pwm [inout]: The PWM parameter, defined by ty_pwm_t.
cmd [in]: The control command, defined by ty_pwm_cmd_t.
arg [in]: The parameter of the command.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

ty_pwm_uninit

Function name ty_pwm_uninit
Function prototype uint32_t ty_pwm_uninit(ty_pwm_t* p_pwm);
Description Disable the PWM.
Parameter p_pwm [in]: The PWM parameter, defined by ty_pwm_t.
Return value 0: Success.
Others: Failure.
Notes You can add or modify functions, parameters, and return values as needed.

Data type

ty_pwm_t

typedef struct {
    GPIO_PinTypeDef pin;            /* Pin number */
    pwm_id id;                      /* PWM ID */
    uint8_t polarity;               /* Polarity */
    uint32_t freq;                  /* Frequency */
    uint8_t duty;                   /* Duty cycle */
} ty_pwm_t;

ty_pwm_cmd_t

typedef enum {
    TY_PWM_CMD_SET_POLARITY = 0,    /* Polarity */
    TY_PWM_CMD_SET_FREQ,            /* Frequency */
    TY_PWM_CMD_SET_DUTY,            /* Duty cycle */
} ty_pwm_cmd_t;

ty_pwm_set_polarity_t

typedef struct {
    uint8_t  polarity;              /* Polarity (0-H, 1-L) */
} ty_pwm_set_polarity_t;

ty_pwm_set_freq_t

typedef struct {
    uint32_t freq;                  /* Frequency (µs) */
} ty_pwm_set_freq_t;

ty_pwm_set_duty_t

typedef struct {
    uint8_t  duty;                  /* Duty cycle (%) */
} ty_pwm_set_duty_t;

API example

Use TLSR825x as an example. You can add PWM API functions or call APIs provided by the chip vendor in the application code.

ty_pwm.h

/* Change the parameter id to func based on the mappings between the PWM channels and pins of TLSR825x */
typedef struct {
    GPIO_PinTypeDef pin;            /* Pin number */
    GPIO_FuncTypeDef func;          /* Pin function */
    uint8_t polarity;               /* Polarity */
    uint32_t freq;                  /* Frequency */
    uint8_t duty;                   /* Duty cycle */
} ty_pwm_t;

ty_pwm_tlsr825x.c

/****************************************************
    PWM0   :  PA2.  PC1.  PC2.  PD5.
    PWM1   :  PA3.  PC3.
    PWM2   :  PA4.  PC4.
    PWM3   :  PB0.  PD2.
    PWM4   :  PB1.  PB4.
    PWM5   :  PB2.  PB5.
    PWM0_N :  PA0.  PB3.  PC4.	PD5.
    PWM1_N :  PC1.  PD3.
    PWM2_N :  PD4.
    PWM3_N :  PC5.
    PWM4_N :  PC0.  PC6.
    PWM5_N :  PC7.
 ****************************************************/

uint32_t ty_pwm_init(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->duty < 0 || p_pwm->duty > 100) {
        return 2;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);
    gpio_set_func(p_pwm->pin, p_pwm->func);
    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_set_mode(id, PWM_NORMAL_MODE);
    pwm_polo_enable(id, p_pwm->polarity);
    pwm_set_cycle_and_duty(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US),
                               (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));

    return 0;
}

uint32_t ty_pwm_start(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->duty < 0 || p_pwm->duty > 100) {
        return 2;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_start(id);
    return 0;
}

uint32_t ty_pwm_stop(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_stop(id);
    return 0;
}

uint32_t ty_pwm_control(ty_pwm_t* p_pwm, uint8_t cmd, void* arg)
{
    if ((p_pwm == NULL) || (arg == NULL)) {
        return 1;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }
    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);

    switch(cmd) {
    case TY_PWM_CMD_SET_POLARITY: {
            ty_pwm_set_polarity_t* param = arg;
            p_pwm->polarity = param->polarity;
            pwm_polo_enable(id, p_pwm->polarity);
        }
        break;
    case TY_PWM_CMD_SET_FREQ: {
            ty_pwm_set_freq_t* param = arg;
            p_pwm->freq = param->freq;
            pwm_set_cycle_and_duty(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US),
                                       (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));
        }
        break;
    case TY_PWM_CMD_SET_DUTY: {
            ty_pwm_set_duty_t* param = arg;
            if (p_pwm->duty < 0 || p_pwm->duty > 100) {
                return 2;
            }
            p_pwm->duty = param->duty;
            pwm_set_cmp(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));
        }
        break;
    default:
        break;
    }

    return 0;
}

uint32_t ty_pwm_uninit(ty_pwm_t* p_pwm)
{
    uint32_t res = ty_pwm_stop(p_pwm);
    if (res) {
        return res;
    }
    gpio_set_func(p_pwm->pin, AS_GPIO);
    return 0;
}

Sample application

Description

Generate a positive polarity PWM signal with 500 µs frequency and 50% duty cycle. After two seconds, adjust the duty cycle to 80%. Two seconds later, modify the frequency to 800 µs. Another two seconds later, switch the polarity to negative. Finally, after another two seconds, stop PWM output and disable PWM.

Sample code

The sample code uses the TLSR825x platform:

#include "ty_pwm_demo.h"
#include "ty_pwm.h"
#include "tuya_ble_log.h"
#include "tuya_ble_port.h"

/***********************************************************
************************micro define************************
***********************************************************/
#define PWM_PIN             GPIO_PB5
#define PWM_FUNC            AS_PWM5

#define PWM_POL             0
#define PWM_POL_UPDATE      1
#define PWM_FREQ            500
#define PWM_FREQ_UPDATE     800
#define PWM_DUTY            50
#define PWM_DUTY_UPDATE     80

#define PWM_UPDATE_TIME_MS  2000

/***********************************************************
***********************variable define**********************
***********************************************************/
static ty_pwm_t sg_pwm = {
    .pin = PWM_PIN,
    .func = PWM_FUNC,
    .polarity = PWM_POL,
    .freq = PWM_FREQ,
    .duty = PWM_DUTY
};

static tuya_ble_timer_t sg_pwm_timer;

/***********************************************************
***********************function define**********************
***********************************************************/
/**
 * @brief pwm timer callback
 * @param[in] none
 * @return none
 */
void __pwm_timer_cb(void)
{
    static uint8_t s_step = 0;

    switch (s_step) {
    case 0: {
            ty_pwm_set_duty_t new_duty = {
                .duty = PWM_DUTY_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_DUTY, &new_duty);
        }
        break;
    case 1: {
            ty_pwm_set_freq_t new_freq = {
                .freq = PWM_FREQ_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_FREQ, &new_freq);
        }
        break;
    case 2: {
            ty_pwm_set_polarity_t new_pol = {
                .polarity = PWM_POL_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_POLARITY, &new_pol);
        }
        break;
    case 3: {
            ty_pwm_stop(&sg_pwm);
            ty_pwm_uninit(&sg_pwm);
        }
        break;
    default:
        break;
    }
    if (s_step <= 3) {
        s_step++;
    }
}

/**
 * @brief ty_pwm api demo init
 * @param none
 * @return none
 */
void ty_pwm_demo_init(void)
{
    uint32_t res;
    res = ty_pwm_init(&sg_pwm);
    if (res) {
        TUYA_APP_LOG_ERROR("ty_pwm_init failed, error code: %d", res);
        return;
    }
    res = ty_pwm_start(&sg_pwm);
    if (res) {
        TUYA_APP_LOG_ERROR("ty_pwm_start failed, error code: %d", res);
        return;
    }
    tuya_ble_timer_create(&sg_pwm_timer, PWM_UPDATE_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__pwm_timer_cb);
    tuya_ble_timer_start(sg_pwm_timer);
}