PS: for software engineers who use English as the main coding tool, it is convenient to use English punctuation even when writing documents in a Chinese editing environment
Requirements
The API reference design specification for PWM module is provided in the development manual of micropython. See:
https://docs.micropython.org/en/latest/library/machine.PWM.html
I looked at the code warehouse of micro Python again. Only rp2/esp32/esp8266 have machines_ The implementation of PWM. C in the official development manual is consistent with rp2, and the ESP series is another similar implementation
When designing PWM module, it is necessary to consider the problem that multiple PWM share the same timer, and sometimes there are not many timer pins, which can not support many PWM. If more PWM output channels are to be supported, the problem of grouping multiple timers may also be considered
The implementation of rp2 is a bit flashy. From the code point of view, the 1 timer of rp2 may have 8 channels (powerful timer IP) or 8 timers (powerful SOC). Each timer only leads to one channel (A and B count as one)
STATIC machine_pwm_obj_t machine_pwm_obj[] = { {{&machine_pwm_type}, 0, PWM_CHAN_A}, {{&machine_pwm_type}, 0, PWM_CHAN_B}, {{&machine_pwm_type}, 1, PWM_CHAN_A}, {{&machine_pwm_type}, 1, PWM_CHAN_B}, {{&machine_pwm_type}, 2, PWM_CHAN_A}, {{&machine_pwm_type}, 2, PWM_CHAN_B}, {{&machine_pwm_type}, 3, PWM_CHAN_A}, {{&machine_pwm_type}, 3, PWM_CHAN_B}, {{&machine_pwm_type}, 4, PWM_CHAN_A}, {{&machine_pwm_type}, 4, PWM_CHAN_B}, {{&machine_pwm_type}, 5, PWM_CHAN_A}, {{&machine_pwm_type}, 5, PWM_CHAN_B}, {{&machine_pwm_type}, 6, PWM_CHAN_A}, {{&machine_pwm_type}, 6, PWM_CHAN_B}, {{&machine_pwm_type}, 7, PWM_CHAN_A}, {{&machine_pwm_type}, 7, PWM_CHAN_B}, };
In this way, it certainly solves the problem of PWM multiplexing, either fully multiplexed or fully independent
By the way, read the introduction of raspberry pico. Good guy, this chip is almost defined for this exclusive board, and this board is defined to serve micro python
rp2 machine_ The PWM implementation extends the adjustable range of duty to 65536. Even it does not hesitate to spend computational effort to do multiplication and division on the core of CM0 + for conversion ns and so on
// Set the frequency, making "top" as large as possible for maximum resolution. // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535. #define TOP_MAX 65534 mp_int_t freq = mp_obj_get_int(args[1]); uint32_t div16_top = 16 * source_hz / freq;
The overall code implementation is not very good-looking. But it doesn't matter. As long as the final function of the board comes out, the software may not be for secondary development for users. Atmosphere! But I can't do this for general MCU, so I finally consider referring to the implementation model of esp series
esp32 and esp8266 use the same set of interfaces:
STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) }, };
In terms of naming style, the PWM module also belongs to the pyb module, rather than the machine expressly agreed later, indicating that this is still an early implementation. The problem is not big. I use its implementation model and hang it under the machine module
While implementing the basic API, I will agree in advance:
- The valid input range of duty is 0-1000, indicating the thousandth ratio. In this way, the counting cycle of the timer can be fixed to 1000, but the frequency is adjustable
- Through TIM3, TIM3 and TIM4, a total of 6 channels are led out, and a multi timer combination architecture is tried to be designed. At the same time, the coupling between multiple PWM channels sharing a timer should be considered
// start the PWM subsystem if it's not already running if (!pwm_inited) { pwm_init(); pwm_inited = true; }
Hehe, I think so too. Avoid repeated initialization of shared time base
- As for instantiation and parameter passing, it still follows the popular practice in Python. It is acceptable: pin name / global channel number / similar objects
To be continued