圧電スピーカーで音を鳴らしたり、RCサーボを動かそうと思うと、PWMライブラリが欲しいですよね。STM32のMicroPythonには、他のMCU用の実装とは異なり、PWMライブラリがなく、ちょっと困ってしまいます。
STM32は、各端子によって対応付けられるタイマーやPWMでデューティー比を制御するチャネルの組み合わせが複雑で、PWMの汎用的なライブラリを作成しようとすると少し気合がいりますが、ないととても不便なので作成しました。
PWMライブラリ
"""
STM32PWM: PWM driver for STM32
for MicroPython
Version 1.1
Copyright 2023 K.Kakizaki
"""
from machine import Pin
from pyb import Timer
import sys
class PWM:
tim446 = {'PA0':2, 'PA1':2, 'PA2':9, 'PA3':9, 'PA4':None, 'PA5':2, 'PA6':3, 'PA7':3, 'PA8':1, 'PA9':1, 'PA10':1, 'PA11':1, 'PA12':None, 'PA13':None, 'PA14':None, 'PA15':2,
'PB0':3, 'PB1':3, 'PB2':2, 'PB3':2, 'PB4':3, 'PB5':3, 'PB6':4, 'PB7':4, 'PB8':10, 'PB9':11, 'PB10':2, 'PB11':2, 'PB12':None, 'PB13':1, 'PB14':1, 'PB15':1,
'PC0':None, 'PC1':None, 'PC2':None, 'PC3':None, 'PC4':None, 'PC5':None, 'PC6':8, 'PC7':8, 'PC8':8, 'PC9':8}
ch446 = {'PA0':1, 'PA1':2, 'PA2':1, 'PA3':2, 'PA4':None, 'PA5': 1, 'PA6':1, 'PA7':2, 'PA8':1, 'PA9':2, 'PA10':3, 'PA11':4, 'PA12':None, 'PA13':None, 'PA14':None, 'PA15':1,
'PB0':3, 'PB1':4, 'PB2':4, 'PB3':2, 'PB4':1, 'PB5':2, 'PB6':1, 'PB7':2, 'PB8':1, 'PB9':1, 'PB10':3, 'PB11':4, 'PB12':None, 'PB13':-1, 'PB14':-2, 'PB15':-3,
'PC0':None, 'PC1':None, 'PC2':None, 'PC3':None, 'PC4':None, 'PC5':None, 'PC6':1, 'PC7':2, 'PC8':3, 'PC9':4}
# tim412 = {'PA0':2, 'PA1':2, 'PA2':9, 'PA3':9, 'PA4':None, 'PA5':2, 'PA6':3, 'PA7':3, 'PA8':1, 'PA9':1, 'PA10':1, 'PA11':1, 'PA12':None, 'PA13':None, 'PA14':None, 'PA15':2,
# 'PB0':3, 'PB1':3, 'PB2':None, 'PB3':2, 'PB4':3, 'PB5':3, 'PB6':4, 'PB7':4, 'PB8':10, 'PB9':11, 'PB10':2, 'PB11':2, 'PB12':None, 'PB13':1, 'PB14':1, 'PB15':1,
# 'PC0':None, 'PC1':None, 'PC2':None, 'PC3':None, 'PC4':None, 'PC5':None, 'PC6':8, 'PC7':8, 'PC8':8, 'PC9':8}
# ch412 = {'PA0':1, 'PA1':2, 'PA2':1, 'PA3':2, 'PA4':None, 'PA5': 1, 'PA6':1, 'PA7':2, 'PA8':1, 'PA9':2, 'PA10':3, 'PA11':4, 'PA12':None, 'PA13':None, 'PA14':None, 'PA15':1,
# 'PB0':3, 'PB1':4, 'PB2':None, 'PB3':2, 'PB4':1, 'PB5':2, 'PB6':1, 'PB7':2, 'PB8':1, 'PB9':1, 'PB10':3, 'PB11':4, 'PB12':None, 'PB13':-1, 'PB14':-2, 'PB15':-3,
# 'PC0':None, 'PC1':None, 'PC2':None, 'PC3':None, 'PC4':None, 'PC5':None, 'PC6':1, 'PC7':2, 'PC8':3, 'PC9':4}
if sys.implementation[2].find('UNO') > 0:
fpin = {'LED1':'PB13', 'LED_BLUE':'PB13', 'D13':'PB13', 'SND':'PC8', 'SRV1':'PA0', 'SRV2':'PA1', 'SRV3':'PA2', 'SRV4':'PA3'}
else:
fpin = {'LED1':'PA10', 'LED_BLUE':'PA10', 'SND':'PB9', 'SRV1':'PA0', 'SRV2':'PA1', 'SRV3':'PA2', 'SRV4':'PA3'}
def __init__(self, pin, freq=1000, duty_percent=50):
if pin in PWM.fpin:
pin = PWM.fpin[pin]
self._pin = pin
self._freq = freq
self._duty_percent = duty_percent
self._tim = Timer(PWM.tim446[self._pin],freq=freq)
self._mode = Timer.PWM
if PWM.ch446[self._pin] < 0:
self._mode = Timer.PWM_INVERTED
self._ch = self._tim.channel(abs(PWM.ch446[self._pin]), self._mode, pin=Pin(self._pin))
self._ch.pulse_width_percent(duty_percent)
def freq(self, hz=-1):
if hz == -1:
return self._freq
else:
self._freq = hz
self._tim = Timer(PWM.tim446[self._pin],freq=hz)
def duty_percent(self, v=-1):
if v == -1:
return self._ch.pulse_width_percent()
else:
self._ch.pulse_width_percent(v)
def duty_u16(self, v=-1):
if v == -1:
return int(self._ch.pulse_width_percent() / 100 * 65535)
else:
self._ch.pulse_width_percent(v / 65535 * 100)
def pulse_width(self, v=-1):
if v == -1:
return self._ch.pulse_width()
else:
self._ch.pulse_width(v)
def period(self):
return self._tim.period()
def stop(self): # Stop PWM of the channel
self._ch.pulse_width_percent(0)
def deinit(self): # Deinitialises the timer
self._tim.deinit()