用MSPM0L1306实现简易PWM发生器
用MSPM0L1306实现简易PWM发生器,上位机程序实时显示PWM输出参数。移植了RT-Thread和MSH组件,实现了pwm自定义指令
标签
嵌入式系统
rt-thread
MSPM0L1306
bigzhu
更新2024-07-18
苏州大学
301

项目介绍

使用MSPM0L1306的定时器,生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节。

其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。

PWM重复频率越高,占空比分辨率降低

设计思路

移植RT-Thread,在RTOS环境下更方便的编写可移植代码,为后续功能打框架基础

使用两路独立的定时器TIMG2生成PWM0,输出引脚PA3;TIMG1生成PWM1,输出引脚PA14

通过串口实时汇报数据


硬件框图和软件流程图

系统启动流程图

主任务流程图


简单的硬件介绍

准备一条USB转串口线,一条USB TYPEC,一台示波器(我使用的是正点原子便携示波器)

UART1

开发板底板自带调试器和UART,UART接到了MSPM0L1306的PA10和PA11(UART1)。我们可以直接和调试器的UART来和单片机的UART1进行通信。

UART0

连接PA8 PA9,此串口和上位机进行通信。

PWM

两路PWM输出,使用两个独立的定时器:TIMG2生成PWM0,输出引脚PA3;TIMG1生成PWM1,输出引脚PA14

实现的功能及图片展示

指令操作

示波器截图

主要代码片段及说明

为了实现PWM重复频率在1Hz~10KHz内连续可调,写了一个函数,这个函数对于32MHz的CortexM0内核计算量有点大,在有些频率下需要计算的时间有点长。简单的优化了一下,使其更适合计算1-10000Hz的PWM参数计算。

/* 生成特定PWM频率的CPS和LOAD值 */
static int mspm0l1306_pwm_gen(uint32_t freq, uint8_t *cps, uint16_t *period) {
  if (!cps || !period)
    return -1;

  /* CPS:8bit, LOAD:16bit */
  for (uint8_t i = 0; i < 0xFF; i++) {
    for (uint32_t j = 0xFFFF; j > 1000; j--) {
      uint32_t f = CPUCLK_FREQ / ((i + 1) * j);
      if (f == freq || f - freq < freq * 0.01) {
        *cps = i;
        *period = j;
        return 0;
      }
    }
  }
  return -1;
}

PWM控制原理

为了更灵活的调节pwm,使用 rtthread msh 组件实现了一个pwm指令

MSH_CMD_EXPORT(pwm, pwm ctrl: pwm <chan> <freq|duty> [value]);

测试示例

pwm <chan> <freq|duty> [value]
# 例如调节PWM通道1输出频率为2000Hz
pwm 1 freq 2000

# 调节pwm通道1占空比为60%
pwm 1 duty 60

PWM调节原理

我们来看下本次任务的要点

  • 使用MSPM0L1306的定时器,生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节。
  • 其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。
  • PWM重复频率越高,占空比分辨率降低(主时钟32MHz为例)

通过MSPM0L1306参考手册,我们知道PWM输出需要配置定时器的Compare Mode

为了生成两路独立的PWM波,需要使用两个独立的普通定时器TIMG



从下图可以看出LOAD寄存器和PWM频率相关,一个PWM周期=LOAD CNT*定时器周期。占空比和CC寄存器有关系。CC寄存器配置的数值不能超过LOAD寄存器

LOAD CNT越大,周期越长(频率越低),调节精度(CC)也相应增加。反之,LOAD CNT越小,PWM波周期越小(频率越高),调节精度越小。

上位机通信

上位机主要用来实时显示运行参数,包括当前的ADC值,每个pwm通道的频率和占空比。


UART通信协议:每包固定15个字节。UART通信参数:115200, 8N1。

123-67-1011-1415
帧头1字节无符号整型无符号整型无符号整型帧尾
0x3E通道ADC实时采样PWM频率PWM占空比0xAA

无符号整型是使用小端传输。

下位机在状态发生改变时主动汇报数据,上位机可以实时显示当前的ADC值,PWM通道,PWM频率和PWM占空比。

实际的例子

3c012f0d00008813000043000000aa

遇到的主要难题及解决方法

本次主要的难点是移植RT-Thread nano版本,因为MSPM0L1306的SRAM比较小(4KB),需要进行适当的裁剪。

1. 添加rtthread

为了更好的了解OS移植细节,这里使用手动方式添加rtthread

  1. rtthread官网下载 3.1.5 nano 版本。
  2. rt-thread 文件夹整体拷贝到工程中,删除 libcpu 文件夹下其他架构代码,只保留 arm 目录下的 commoncortex-m0 文件夹。
  3. 添加文件到MDK工程中。为了方便管理这里新建了 rtthread-bsp rtthread-components rtthread-src rtthread-libcpu 4个组,按照对应关系将源码加到MDK工程中。需要我们修改的代码都在 rtthread-bsp 中。borad.c 为初始化入口,在 rt_hw_board_init 中初始化硬件,打开调试串口。

2. 调整stack

启动文件 startup_mspm0l1306_uvision.s 中默认定义的 0x100(256)太小,需要改成 0x200(512)。否则rtt初始化时会出现栈溢出,导致系统崩溃。

Stack_Size      EQU     0x00000200

3. 添加rtthread组件

为了方便调试,添加了 RT_USING_CONSOLERT_USING_FINSH

MSPM0L1306共有两个串口,UART0作为和上位机通信接口,UART1作为调试串口。

rtconfig.h 配置项如下

#define RT_THREAD_PRIORITY_MAX  8
#define RT_TICK_PER_SECOND 1000
#define RT_ALIGN_SIZE   4
#define RT_NAME_MAX   8
#define RT_USING_COMPONENTS_INIT

#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE     512

#define RT_DEBUG_INIT 0
#define RT_USING_HOOK
#define RT_USING_IDLE_HOOK

#define RT_USING_TIMER_SOFT         1
#define RT_TIMER_THREAD_PRIO       4
#define RT_TIMER_THREAD_STACK_SIZE 200

#define RT_USING_SEMAPHORE
#define RT_USING_MAILBOX

#define RT_USING_HEAP
#define RT_USING_SMALL_MEM
#define RT_USING_TINY_SIZE
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE         128

/* FINSH */
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_USING_MSH_ONLY
#define FINSH_THREAD_PRIORITY       6
#define FINSH_THREAD_STACK_SIZE     512
#define FINSH_HISTORY_LINES         1
#define FINSH_USING_SYMTAB

4. UART1数据接收处理流程

使用UART1 作为 rtthread 调试串口,在 rtthread nano 中,我们只需要实现两个函数 char rt_hw_console_getchar(void)void rt_hw_console_output(const char *str),剩下的事情框架已经帮我们处理好。

这里采用中断接收数据,使用 ringbuffer 和信号量 shell_rx_sem,提高数据处理效率。如果没有接收到串口数据,接收线程会一直被信号量阻塞rt_sem_take,这样可以释放CPU处理其他事情。

char rt_hw_console_getchar(void)
{
   char ch = 0;

   while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1) {
       rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
  }
   return ch;
}

接收到数据存放到 uart_rxcb ringbuffer中,然后释放 shell_rx_sem 信号量,通知接收线程开始处理数据。

void UART1_IRQHandler()
{
   rt_interrupt_enter();

   switch (DL_UART_Main_getPendingInterrupt(UART1)) {
       case DL_UART_MAIN_IIDX_RX:
      {
           uint8_t data = DL_UART_Main_receiveData(UART1);
           rt_ringbuffer_putchar(&uart_rxcb, data);
           rt_sem_release(&shell_rx_sem);
      }
       break;
       default:
           break;
  }

   rt_interrupt_leave();
}

5. OS资源占用

rtthread nano 资源占用低,MSPMOL1306这么小的资源(64KB Flash,4KB SRAM)上面都能正常运行,不得不说rtthread nano优化的还不错。

对比了一下移植前面的资源占用

# 裸机
Program Size: Code=3352 RO-data=1800 RW-data=0 ZI-data=352
# 使用上面 rtconfig.h 定义的配置项资源占用情况
Program Size: Code=19166 RO-data=2610 RW-data=64 ZI-data=1800

运行状态中的 rtthread nano

msh >ps
thread   pri status     sp     stack size max used left tick error
-------- ---  ------- ---------- ----------  ------  ---------- ---
tshell     6 ready   0x00000094 0x00000200    82%   0x00000005 000
tidle      7 ready   0x00000040 0x00000100    31%   0x0000000b 000
timer      4 suspend 0x00000050 0x000000c8    40%   0x0000000a 000
main       2 suspend 0x00000080 0x00000200    31%   0x0000000f 000
msh >free
total memory: 2208
used memory : 1444
maximum allocated memory: 1444


未来的计划或建议

经过这个项目的实践,对MSPM0L1306有了更深入的了解。这款芯片主打低功耗,芯片虽小,但是功能强大,能应用到相对复杂的项目中。

希望后面有项目机会可以用起来~

附件下载
mspm0l1306-rtt.zip
MSPM0L1306源代码
mspm0-ctrl.zip
上位机QT源代码
project.hex
设备hex固件
mspm0-ctrl.zip
上位机QT打包好的程序
团队介绍
苏州大学电子信息
评论
0 / 100
查看更多
猜你喜欢
基于MSPM0L1306实现简易PWM波发生器该项目使用了MSPM0L1306,实现了生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节的设计,它的主要功能为:其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。 PWM重复频率越高,占空比分辨率降低(主时钟32MHz为例)。
sty
231
基于MSPM0L1306的简易PWM发生器该项目使用了EVM_MSPM0L1306,实现了简易PWM的设计,它的主要功能为:使用MSPM0L1306的定时器,生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节。 其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。 PWM重复频率越高,占空比分辨率降低(主时钟32MHz为例) 重复频率 占空比调节精度 1MHz 1/10 100KHz 1/100 10KHz 1/1,000 1KHz 1/10,000 100Hz 1/10,000 1Hz 1/10,000 PWM重复频率在1Hz~10KHz时,占空比的精度不低于1/1000,100Khz和1Mhz的占空比精度按照表格即可。 使用按键或拨码开关组合调节输出频率、占空比,并由按键控制每一路PWM信号的输出。 能在OLED屏幕上显示基础信息,当前使用引脚示意、引脚相应的PWM参数。 将PWM参数(包括两个通道的频率占空比、及通道工作与否)按照1s左右的周期,通过串口发送到上位机。。
冲向天空的猪
217
基于MSPM0L1306实现简易PWM发生器该项目使用了MSPM0L1306,实现了简易PWM发生器的设计,它的主要功能为:生成两路独立且可调节的PWM信号,每路信号的重复频率范围从1Hz到1MHz,其中在1Hz到10kHz范围内,用户可以实现连续的频率调节;在1Hz至10kHz的频率范围内,PWM信号的占空比精度不低于1/10000。而在100kHz和1MHz的高频模式下,占空比精度会自动调整;OLED屏幕实时显示当前PWM信号的状态,包括所使用的通道、频率和占空比等参数。每隔大约1秒,该系统会通过串口通信将所有PWM参数(包括两路信号的频率、占空比以及是否正在工作)发送至上位机,以便于监控和记录。。
Samaritan
101
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号