通过mem32函数来提高MM32 MicroPython 输出PWM 频率的精度
2022/2/5 22:27:24
本文主要是介绍通过mem32函数来提高MM32 MicroPython 输出PWM 频率的精度,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
简 介: 利用mem32功能,对于MM32的MicroPython中的PWM频率精度低的问题,通过重新调整ARR来提高PWM频率精度。
关键词
: PWM,MM32,MicroPython,mem32
§01 MM32 PWM输出
1.1 版本的优缺点
在MindMotion MM32 单片机上的MicroPython移植-PWM中给出了灵动公司SuYong移植在MM32F3277上的MicroPython版本中具有了PWM。相比于MicroPython官网给出的版本,这个版本的PWM优点:
- 它是基于两个Timer(TIM3、TIM4)给出了八个通道的PWM输出,所以它允许存在两组不同基频的PWM波形输出。从而可以分别控制舵机、直流电机控制等。
但在实现过程中,它的缺点也很明显。SuYong在实现过程中,对于ARR固定位999,对应PWM的CNT范围是从0 ~ 999。可以实现1/1000的输出PWM精度。但这带来对应的输出PWM频率精度受限。
这一点在 使用MM32 MicroPython产生双音频信号的局限性 进行了测量。下图给出从500到2000Hz之内, MM32 PWM频率出现的绝对误差。
▲ 图1.1.1 输出频率在500 ~ 2000 Hz之间对应的实际PWM频率误差
1.2 误差分析
1.2.1 PWM频率确定
假设MM32F3277的Time工作频率来自于MCU的主频,对应 f o s c = 120 M H z f_{osc} = 120MHz fosc=120MHz 。对于 A R R = 999 ARR = 999 ARR=999 ,确定PWM频率是由TIM3/TIM4的预分配器 PSC 来决定。
f P W M = f o s c ( 1 + P S C ) ⋅ ( A R R + 1 ) f_{PWM} = {{f_{osc} } \over {\left( {1 + PSC} \right) \cdot \left( {ARR + 1} \right)}} fPWM=(1+PSC)⋅(ARR+1)fosc
由于PSC必须采用整数,所以对应输出的 f P W M f_{PWM} fPWM 会存在一定的误差。
1.2.2 误差
下面是从500 到1000 范围内设定的频率与实际频率之间的误差。
from headm import * fset = range(500, 2000, 5) def deltaf(f): fosc = 120e6 psc = int(fosc/f/1000)-1 freal = fosc/(1+psc)/1000 return f-freal fdel = [deltaf(f) for f in fset] plt.plot(fset, fdel) plt.xlabel("Set Frequency(Hz)") plt.ylabel("Delta Frequency(Hz)") plt.grid(True) plt.tight_layout() plt.show()
▲ 从500 - 1000 内对应的频率误差
下面是每隔5Hz计算出来的PWM 频率误差,这与在使用MM32 MicroPython产生双音频信号的局限性中实际测量的结果基本上很接近了。
▲ 图1.2.2 500 ~ 2000Hz 之间每隔5Hz计算出的理论频率误差
1.3 如何改进PWM频率误差?
这个问题主要来自于在SuYong的PWM功能实现过程中,固定ARR为999,这就使得实际输出的PWM频率无法进行小的调整。下面给出一个计算方式,使得ARR在999范围前后,能够根据误差进行调整,使得输出的频率满足设定的频率。
1.3.1 修改方式
具体修改方式分为两步,有下面的 函数给出:
def deltaf(f): fosc = 120e6 psc = int(fosc/f/1000)-1 arr = int(fosc/(1+psc)/f) - 1 freal = fosc/(1+psc)/(1+arr) return f-freal,arr
1.3.2 修改结果
利用这种方式修改之后,对应的ARR在1000左右进行浮动,可以看到对应的频率误差都小于1/1000
▲ 对应的频率误差与ARR取值
1.4 在MicroPython实现
根据MM32F3277 MicroPython的 mem 函数对于MCU内存访问描述,可以利用mem32技术直接访问MM32F3277的寄存器,所以可以将上面修正后的频率所需要对应的PSC, ARR利用Mem32进行调整。从而实现提高PWM 输出频率的精度。
1.4.1 实现代码
#------------------------------------------------------------ from micropython import const APB1PERIPH_BASE = const(0x40000000) TIM3_BASE = const(APB1PERIPH_BASE + 0x0400) TIM4_BASE = const(APB1PERIPH_BASE + 0x0800) TIM_TYPE_CR1 = const(0*4) TIM_TYPE_CR2 = const(1*4) TIM_TYPE_SR = const(4*4) TIM_TYPE_CNT = const(9*4) TIM_TYPE_PSC = const(10*4) TIM_TYPE_ARR = const(11*4) TIM_TYPE_CCR1 = const(13*4) TIM_TYPE_CCR2 = const(14*4) TIM_TYPE_CCR3 = const(15*4) TIM_TYPE_CCR4 = const(16*4) def pwmFreq(f, pwm): fosc = 96e6 psc = int(fosc/f/1000) - 1 arr = int(fosc/(1+psc)/f) - 1 if pwm < 4: base = TIM3_BASE else: base = TIM4_BASE mem32[base+TIM_TYPE_PSC] = psc mem32[base+TIM_TYPE_ARR] = arr return arr #------------------------------------------------------------ pwmFreq(697, 0) pwmFreq(697, 4)
1.4.2 测试结果
实际测量对应的输出频率结果为 697.32Hz。
测试设定PWM频率与实际输出频率之间的误差。为什么是这样,现在无法解释。
▲ 图1.4.1 500 到 2000Hz 之间的设置与输出频率之间的误差
下面对于arr的取值进行调整,进行四舍五入。 另外对于ARR设置为10000左右,可以看到误差频率在10000分之一左右。
▲ 图1.4.2 频率在500-2000Hz之间的设置误差
▲ 图1.4.3 在频率 500 - 1600Hz之内的频率误差
※ 总 结 ※
利用mem32功能,对于MM32的MicroPython中的PWM频率精度低的问题,通过重新调整ARR来提高PWM频率精度。
2.1 软件代码
2.1.1 MicroPython程序
from machine import Pin,mem32,PWM import utime led = Pin('PB2', Pin.OUT_PUSHPULL) f = 697 pwm0 = PWM(0, freq=f, duty=500) pwm1 = PWM(4, freq=f, duty=500) from micropython import const APB2PERIPH_BASE = const(0x40010000) UART1_BASE = const(APB2PERIPH_BASE + 0x3800) UART1_RDR = const(UART1_BASE + 1*4) UART1_CSR = const(UART1_BASE + 2*4) REPLBUF_LENGTH = const(64) replbuf = [0]*REPLBUF_LENGTH replpoint = 0 def procREPL(f): global replbuf,replpoint if mem32[UART1_CSR] & 0x2: bc = mem32[UART1_RDR] if replpoint < REPLBUF_LENGTH-1: replbuf[replpoint] = bc replpoint += 1 if bc == 13: f(bytes(replbuf[0:replpoint-1])) replpoint = 0 from micropython import const APB1PERIPH_BASE = const(0x40000000) TIM3_BASE = const(APB1PERIPH_BASE + 0x0400) TIM4_BASE = const(APB1PERIPH_BASE + 0x0800) TIM_TYPE_CR1 = const(0*4) TIM_TYPE_CR2 = const(1*4) TIM_TYPE_SR = const(4*4) TIM_TYPE_CNT = const(9*4) TIM_TYPE_PSC = const(10*4) TIM_TYPE_ARR = const(11*4) TIM_TYPE_CCR1 = const(13*4) TIM_TYPE_CCR2 = const(14*4) TIM_TYPE_CCR3 = const(15*4) TIM_TYPE_CCR4 = const(16*4) def pwmFreq(f, pwm, duty): fosc = 96e6 psc = int(fosc/f/10000) - 1 arr = int(fosc/(1+psc)/f+0.5) if pwm < 4: base = TIM3_BASE else: base = TIM4_BASE pwm -= 4 mem32[base+TIM_TYPE_PSC] = psc mem32[base+TIM_TYPE_ARR] = arr ccr = int(arr*duty) mem32[base+TIM_TYPE_CCR1+pwm*4] return arr def f(s): global pwm0,pwm1 frq= int(s) print(frq) pwmFreq(frq, 0, 0.5) pwmFreq(frq, 4, 0.5) while True: procREPL(f)
2.1.2 测试代码
#!/usr/local/bin/python # -*- coding: gbk -*- #============================================================ # TEST3.PY -- by Dr. ZhuoQing 2022-02-05 # # Note: #============================================================ from headm import * # = from tsmodule.tsstm32 import * setf = range(500, 2000, 10) outf = [] stm32cmd('SNDCD%d\r'%setf[0]) time.sleep(2) for f in setf: stm32cmd('SNDCD%d\r'%f) time.sleep(2) meter = meterval() outf.append(meter[0]) printff(f, meter[0]) tspsave('measure', setf=setf, outf=outf) delf = [f1-f2 for f1,f2 in zip(setf, outf)] plt.plot(setf, delf) plt.xlabel("SetFrequency") plt.ylabel("Delta Frequency") plt.grid(True) plt.tight_layout() plt.show() printf('\a') #------------------------------------------------------------ # END OF FILE : TEST3.PY #============================================================
2.1.3 mm32代码
from headm import * # = caretpos = list(tspgetcaretpos()) headspaceself = '\r\n' + ' '*caretpos[0] + 'self.' headspace = '\r\n' + ' '*caretpos[0] headspaceonly = ' '*caretpos[0] returnpos = 0 insertstr = '' if len(sys.argv) > 1: if sys.argv[1] == 'repl': codestr = ( "from micropython import const,mem32", "APB2PERIPH_BASE = const(0x40010000)", "UART1_BASE = const(APB2PERIPH_BASE + 0x3800)", "UART1_RDR = const(UART1_BASE + 1*4)", "UART1_CSR = const(UART1_BASE + 2*4)", "REPLBUF_LENGTH = const(64)", "replbuf = [0]*REPLBUF_LENGTH", "replpoint = 0", "def procREPL(f):", " global replbuf,replpoint", " if mem32[UART1_CSR] & 0x2:", " bc = mem32[UART1_RDR]", " if replpoint < REPLBUF_LENGTH-1:", " replbuf[replpoint] = bc", " replpoint += 1", " if bc == 13:", " f(bytes(replbuf[0:replpoint-1]))", " replpoint = 0", "def f(s):", " print(int(s))\r\n", ) insertstr = headspace.join(codestr).rstrip(' ') elif sys.argv[1] == 'pwmf': codestr = ( "from micropython import const", "APB1PERIPH_BASE = const(0x40000000)", "TIM3_BASE = const(APB1PERIPH_BASE + 0x0400)", "TIM4_BASE = const(APB1PERIPH_BASE + 0x0800)", "TIM_TYPE_CR1 = const(0*4)", "TIM_TYPE_CR2 = const(1*4)", "TIM_TYPE_SR = const(4*4)", "TIM_TYPE_CNT = const(9*4)", "TIM_TYPE_PSC = const(10*4)", "TIM_TYPE_ARR = const(11*4)", "TIM_TYPE_CCR1 = const(13*4)", "TIM_TYPE_CCR2 = const(14*4)", "TIM_TYPE_CCR3 = const(15*4)", "TIM_TYPE_CCR4 = const(16*4)", "def pwmFreq(f, pwm, duty):", " fosc = 96e6", " psc = int(fosc/f/10000) - 1", " arr = int(fosc/(1+psc)/f+0.5)", " if pwm < 4: base = TIM3_BASE", " else:", " base = TIM4_BASE", " pwm -= 4", " mem32[base+TIM_TYPE_PSC] = psc", " mem32[base+TIM_TYPE_ARR] = arr", " ccr = int(arr*duty)", " mem32[base+TIM_TYPE_CCR1+pwm*4]", " return arr\r\n", ) insertstr = headspace.join(codestr).rstrip(' ') elif sys.argv[1] == 'xxxx': codestr = ( ) insertstr = headspace.join(codestr).rstrip(' ') else: printf("Unrecoginized argument.\a") exit() if len(insertstr) > 0: clipboard.copy(insertstr) tsppasteclipboard() if returnpos > 0: tspsetcaretpos(caretpos[0], caretpos[1]) printf('\a')
■ 相关文献链接:
- MindMotion MM32 单片机上的MicroPython移植-PWM
- 使用MM32 MicroPython产生双音频信号的局限性
- MM32F3277 MicroPython的 mem 函数对于MCU内存访问
● 相关图表链接:
- 图1.1.1 输出频率在500 ~ 2000 Hz之间对应的实际PWM频率误差
- 从500 - 1000 内对应的频率误差
- 图1.2.2 500 ~ 2000Hz 之间每隔5Hz计算出的理论频率误差
- 对应的频率误差与ARR取值
- 图1.4.1 500 到 2000Hz 之间的设置与输出频率之间的误差
- 图1.4.2 频率在500-2000Hz之间的设置误差
- 图1.4.3 在频率 500 - 1600Hz之内的频率误差
这篇关于通过mem32函数来提高MM32 MicroPython 输出PWM 频率的精度的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-27使用python 将ETH账户的资产打散
- 2024-09-26Python编程基础
- 2024-09-2610 种方法写出更好的 Python 代码
- 2024-09-25Python编程基础详解
- 2024-09-25Python编程入门教程
- 2024-09-25从零开始使用Python构建LLaMA 3
- 2024-09-23Python中理解和使用树形结构的简单教程
- 2024-09-23Python 编程基础入门
- 2024-09-18初探Python股票自动化交易:入门指南
- 2024-09-18Python量化入门:轻松掌握量化分析基础与实战