2.4. PWM
2.4.1. Introduction
PWM is a technology that implements analog voltage control in a digital way. It modulates the width of a series of pulses, equivalent to the required waveform (including shape and amplitude), and digitally encodes the analog signal level. That is to say, by adjusting the change of the duty cycle to adjust the change of the signal, energy, etc. The duty cycle refers to the percentage of the entire signal period when the signal is at a high level. For example, the duty cycle of a square wave is 50%. The DMA device in BL series MCU has the following characteristics:
Support 5-channel PWM
Three clock sources can be selected (bus clock <bclk>, crystal oscillator clock <xtal_ck>, slow clock <32k>), with 16-bit clock divider
Double threshold domain setting, increase pulse flexibility
2.4.2. PWM Device Structure Definition
typedef struct pwm_device {
struct device parent;
uint8_t ch;
uint8_t polarity_invert_mode;
uint16_t period;
uint16_t threshold_low;
uint16_t threshold_high;
uint16_t it_pulse_count;
} pwm_device_t;
parent inherit the properties of the parent class
ch channel number, ch is 0 if PWM channel 0 is enabled, ch is 1 if PWM channel 1 is enabled, and so on
polarity_invert_mode polarity invert enable
period PWM period value
threshold_low PWM low threshold
threshold_high PWM high threshold
it_pulse_count The cycle count value that triggered the interrupt condition
备注
PWM actual frequency = pwm_clock_source/frequency_division/period, period is not the actual PWM period,it just has the same name.
备注
PWM Duty cycle = (threshold_high-threshold_low)/period * 100%
2.4.3. PWM Device Parameter Configuration Table
Each PWM device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_pwm.c
, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_PWM_CH2
, and PWM_CH2_CONFIG
will take effect, and at the same time, channel 2 of the PWM
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_PWM_CH2)
#ifndef PWM_CH2_CONFIG
#define PWM_CH2_CONFIG \
{ \
.ch = 2, \
.polarity_invert_mode = DISABLE, \
.period = 0, \
.threshold_low = 0, \
.threshold_high = 0, \
.it_pulse_count = 0, \
}
#endif
#endif
/*Variable definitions*/
static pwm_device_t pwmx_device[PWM_MAX_INDEX] = {
#ifdef BSP_USING_PWM_CH0
PWM_CH0_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH1
PWM_CH1_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH2
PWM_CH2_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH3
PWM_CH3_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH4
PWM_CH4_CONFIG,
#endif
};
备注
The above configuration can be modified through PWM_DEV(dev)->xxx
, and can only be used before calling device_open
.
2.4.4. PWM device interface
The PWM device interfaces all follow the interfaces provided by the standard device driver management layer. And in order to facilitate the user to call, some standard interfaces are redefined using macros.
2.4.4.1. pwm_register
pwm_register
is used to register a channel of the PWM device standard driver interface. Before registering, you need to open the macro definition of a certain channel of the corresponding PWM device. For example, define BSP_USING_PWM_CH0
before you can use the PWM
channel 0 device. After the registration is completed, other interfaces can be used. If no macro is defined, the PWM device cannot be used.
int pwm_register(enum pwm_index_type index, const char *name);
index the index of the device to be registered
name name the registered device
index
is used to select the configuration of a certain channel of the PWM device. An index corresponds to a channel configuration of a PWM device. For example, PWM_CH0_INDEX
corresponds to the configuration of PWM channel 0, and index
has the following optional types:
enum pwm_index_type
{
#ifdef BSP_USING_PWM_CH0
PWM_CH0_INDEX,
#endif
#ifdef BSP_USING_PWM_CH1
PWM_CH1_INDEX,
#endif
#ifdef BSP_USING_PWM_CH2
PWM_CH2_INDEX,
#endif
#ifdef BSP_USING_PWM_CH3
PWM_CH3_INDEX,
#endif
#ifdef BSP_USING_PWM_CH4
PWM_CH4_INDEX,
#endif
PWM_MAX_INDEX
};
2.4.4.2. device_open
device_open
is used to open a channel of a pwm device,this funtion calls pwm_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return error code, 0 means opening is successful, others mean errors
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
2.4.4.3. device_close
device_close
is used to close a channel of a pwm device.this funtion calls pwm_close
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others mean error
2.4.4.4. device_control
device_control
is used to control and modify the parameters of the PWM device according to commands.This funtion calls pwm_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return different control commands return different meanings
In addition to standard control commands, PWM devices also have their own special control commands.
#define DEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG 0x10
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_RESUME |
NULL |
Enable the current PWM channel |
DEVICE_CTRL_SUSPEND |
NULL |
Disable the current PWM channel |
DEVICE_CTRL_PWM_FREQUENCE_CONFIG |
uint32_t |
Configure the current PWM channel period |
DEVICE_CTRL_PWM_DUTYCYCLE_CONFIG |
pwm_dutycycle_config_t |
Configure the current PWM channel duty cycle |
DEVICE_CTRL_PWM_IT_PULSE_COUNT_CONFIG |
uint32_t |
Configure the trigger PWM interrupt period value |
2.4.4.5. device_set_callback
device_set_callback
is used to register a PWM channel interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev device handle
callback the interrupt callback function to be registered
dev device handle
args unused
size unused
event interrupt event type
event
type definition is as follows:
enum pwm_event_type
{
PWM_EVENT_COMPLETE,
};
2.4.4.6. pwm_channel_start
pwm_channel_start
is used to start the PWM channel. It actually calls device_control
, where cmd
is DEVICE_CTRL_RESUME
.
pwm_channel_start(dev)
dev pwm channel handle that needs to be opened
2.4.4.7. pwm_channel_stop
pwm_channel_stop
is used to close the PWM channel. It actually calls device_control
, where cmd
is DEVICE_CTRL_SUSPEND
.
pwm_channel_stop(dev)
dev pwm channel handle that needs to be closed
2.4.4.8. pwm_channel_update
pwm_channel_update
is used to update the frequency and duty cycle of the PWM channel. The actual call is device_control
, where cmd
is DEVICE_CTRL_CONFIG
.
pwm_channel_update(dev,cfg)
dev pwm channel handle that needs to be updated
cfg pwm_config_t handle
2.4.4.9. pwm_it_pulse_count_update
pwm_it_pulse_count_update
is used to update the count value of the PWM channel. The PWM interrupt needs to be enabled before it takes effect. When the PWM count reaches the set period count value, an interrupt will be generated. The actual call is device_control
, where cmd
is DEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG
.
pwm_it_pulse_count_update(dev,count)
dev pwm channel handle that needs to update the cycle count value
count cycle count value