你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

OpenHarmony HDF PWM开发 基于STM32MP1

[复制链接]
STMCU小助手 发布时间:2022-10-24 21:59
本文介绍如何在HDF PWM框架中开发stm32mp1的pwm外设。
. r) s3 a4 _9 q2 W
& e( A# e' w: e* g3 X3 B+ A1 ?0 Lstm32mp1的大部分外设可以使用st提供的HAL库来开发。hal库是st官网为所有st芯片提供的sdk包,使开发者可以免去操作寄存器的操作,直接使用库函数完成芯片外设的配置。" o4 c$ q: O2 Y6 Q) t; Z: B

: [1 ^& i, t8 t, g/ @$ N综上所述,可以将整个开发步骤分三步走:
0 |1 o3 h- S) D, t. o% f4 g" T4 W, j8 \3 W; o9 q0 U$ g  O
1、导入STM32HAL库
9 {! \7 A0 ?/ X- d' o* [0 h. U* Y: Q
2、使能HDF PWM驱动
, S; c4 K* w# q
! W6 v$ j5 e; A3、编写PWM驱动- C( ^5 E$ T% O
! o% Y. i+ m) g! J$ p- |
1、导入stm32mp1 HAL库文件
5 h! v8 O/ S: L# d/ v: O下载HAL库完成后,将HAL库中的以下文件添加到bearpi-micro\device\st\drivers\stm32mp1xx_hal\STM32MP1xx_HAL_Driver的Inc目录中。( G& Q) x0 ~! p* j, D+ d" k' {
stm32mp1xx_hal_tim.h
$ C+ n: \6 m) z, V/ J& Lstm32mp1xx_hal_tim_ex.h
) i, B, O( J7 W  w. x) [7 F: I# S/ n( Astm32mp1xx_hal_dma.h
4 K; _' j9 k6 Kstm32mp1xx_hal_dma_ex.h
: o! U# m2 R- F" S, v) E将 以下文件添加到bearpi-micro\device\st\drivers\stm32mp1xx_hal\STM32MP1xx_HAL_Driver的Src目录中:7 c  z( q! f0 @8 p
stm32mp1xx_hal_tim.c
# F- D, }6 H5 q% ~+ [% Y" fstm32mp1xx_hal_tim_ex.c
1 L; E  G! A4 H6 |: ostm32mp1xx_hal_dma.c. t* f( I5 @! k
stm32mp1xx_hal_dma_ex.c4 D4 ^( ?! x! v; }3 m3 v9 L

7 g6 I2 A$ A) e. p+ l4 V% G- z1 z, l然后将四个源文件加入编译构建体系:编辑bearpi-micro\device\st\drivers\stm32mp1xx_hal\STM32MP1xx_HAL_Driver\BUILD.gn  ?  ?9 D$ k2 `
' v8 y7 I8 S) |( N$ m
在sources添加如下两项:
2 |5 e& L9 @$ u* z5 ~0 R3 W+ R3 |7 P# H8 a1 p# V; @7 t" O! b: t
  1.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_tim_ex.c",
    / W/ j9 ?. ~% y9 C0 X) G
  2.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_tim.c",
    * r3 m8 |' M: `3 V# Y
  3.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_dma_ex.c",
    " S  V- K7 j. P! O5 a, _
  4.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_dma.c",
复制代码
7 |% f- y, H$ f
添加后如下所示,这样编译系统就会编译这两个文件:
$ O1 ?6 a$ P  A8 t/ `7 M' T$ t. F: G9 E& w
  1. import("//drivers/adapter/khdf/liteos/hdf.gni")8 v" j9 U3 P2 M. ~5 L# g; W2 ^
  2. module_name = "hdf_stm32mp1xx_hal", T$ k& C; b9 W1 e2 p
  3. hdf_driver(module_name) {8 x2 ^( B) q: X) A/ `; s
  4.   sources = [+ g( f& V4 c6 `, l
  5.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_tim_ex.c",
    0 h/ |* X$ i7 v2 N
  6.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_tim.c",+ i% V5 u1 }# Z% x- P* j
  7.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_dma_ex.c",9 f3 t  [# S7 b5 }
  8.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_dma.c",
    % V& J4 P! N$ S: q+ v7 h) t
  9.     "STM32MP1xx_HAL_Driver/Src/system_stm32mp1xx.c",- i6 a2 ~7 _7 u7 |
  10.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal.c",/ A, m' W& ?' F" N  g
  11.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_gpio.c",1 k0 ]9 D0 `# v7 ]  d- c
  12.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_i2c.c",6 b9 |+ a' J6 K( v+ c
  13.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_exti.c",
    # }' O6 o; f9 i  I! J7 r
  14.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_ltdc.c",: v/ {4 c9 U7 u
  15.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_rcc.c",, C: i1 w7 u4 a. x( ^/ M6 N) U
  16.     "STM32MP1xx_HAL_Driver/Src/stm32mp1xx_hal_rcc_ex.c",
    . j% c! Q+ K/ k! y$ s9 c7 |) S) r

  17. + ~8 E  f% f7 _+ Z
  18.   ]
    7 F3 x5 R1 v8 `* \/ x
  19.   include_dirs = [. v, O4 n: g) u0 K/ w2 |
  20.     ".",1 {% y8 Q* @' k7 i
  21.     "//device/st/drivers/stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc",: a5 p! S& ^/ o+ l  y
  22. 0 \) B" P& o# h! C
  23.   ]( D$ a$ O/ J, ^# j
  24. }' m. Q+ }  T. n+ d
复制代码

, m- O2 f' P8 x+ [( ~最后,还需要配置一个宏定义,来使能TIM,编辑 STM32MP1xx_HAL_Driver\Inc\stm32mp1xx_hal_conf.h,将 HAL_TIM_MODULE_ENABLED 和HAL_DMA_MODULE_ENABLED使能 ,如下所示:& Q- k' ]  t9 I8 U$ q- i# k* c
, ]3 Q2 A7 F1 G
  1. #define HAL_TIM_MODULE_ENABLED   
    4 ~3 V4 `, R# P0 D( t1 G: W- u
  2. #define HAL_DMA_MODULE_ENABLED   
复制代码
6 S  @, j# D# M
到此,我们就能使用stm32mp1xx_hal_tim.h 提供的函数来开发PWM驱动。
) D8 ^' H( ?6 y; ]0 |9 g
( [" r  e% j5 W; ?8 R2、使能HDF PWM框架, E' H" b( u# _2 O% H2 b
由于HDF 框架是在内核中的,需要在内核中使能PWM驱动。3 m3 x7 _3 J2 W4 h: c1 k1 _

2 Z( I: ^. H8 _6 U+ {) c. E- h! X编辑 vendor/bearpi/bearpi_hm_micro/kernel_configs/debug_tee.config,将 LOSCFG_DRIVERS_HDF_PLATFORM_PWM设置为y,如下所示:
) q5 \% ^' |' s; B: p/ f" n; F' {2 b3 M# w/ I
  1. LOSCFG_DRIVERS_HDF_PLATFORM_PWM = y
复制代码
4 C/ Q  b: i4 H
开启该宏之后,就会编译HDF 的PWM框架,就能在驱动中使用PWM框架的pwm_core.h和pwm_if.h。
8 ?) D9 o; F* x$ i3 @" _9 L) K9 L+ N1 W
3、编写驱动代码4 M" y- X( a; U  L: P6 R
按照官网文档的指示进行编写:PWM框架开发) _5 [7 {' h) ~* |' x" L

- S3 \+ x4 J8 _3 I同样分为三步走。6 M2 @4 n. G; Y
+ d6 o5 C7 `$ W7 s! @( |6 j" U( p
1、配置文件
9 s* m) k1 _, m5 b; {$ n3 L7 R一共需要修改两个hcs文件,分别是:device_info.hcs和pwm_config.hcs
, B7 d1 `+ M2 V6 P# I* S8 q7 s( C$ A  ~6 Y+ n9 E2 e
首先 编辑st\bearpi_hm_micro\liteos_a\hdf_config\device_info\device_info.hcs增加pwm节点,如下所示:# B5 T7 q- \* G% Y0 M5 H( g  H7 U

4 _9 V. F  V- L9 a% i5 C, x+ \该节点应该是在 platform :: host节点下创建。其中policy=1表示只对内核发布驱动服务,moduleName必须为HDF_PLATFORM_PWM,serviceName必须以HDF_PLATFORM_PWM_开头,后面的数字用来区别不同的pwm外设。( V$ V3 R( j) L& y; K
; j6 T2 v+ _6 W3 O
这里我设置为2是因为我使用TIM2作为PWM的源。
  1.             device_pwm :: device{
    4 X* m9 Q& U8 v
  2.                 device0 :: deviceNode{
    + ?6 n, m, b  I& y
  3.                     policy = 1;
    3 N) M: K* o4 n$ T0 i
  4.                     priority = 12;' s. v! n# G0 U# ^! ?1 R
  5.                     permission = 0777;
    6 s" \0 }& V/ U, m7 ?9 F
  6.                     moduleName = "HDF_PLATFORM_PWM";% F1 x+ z+ \$ c$ h) F
  7.                     serviceName = "HDF_PLATFORM_PWM_2";& ^8 ^4 Z* f" N' H, s3 d3 z  Z
  8.                     deviceMatchAttr = "st_stm32mp157_pwm_2";
    : b; G4 \$ c, Y) V! A7 p
  9.                 }% R" Q$ R4 E. s7 R# z# \- n2 C4 k
  10.             }
复制代码

, _7 _' c( [9 C第二个配置文件就是自己创建的,在\bearpi_hm_micro\liteos_a\hdf_config\录下创建pwm目录,在目录中创建 pwm_config.hcs,并在其中添加以下内容:9 W( O# u2 t6 J7 B( s8 C# R
& I5 F. l. g& ~" `7 t
其中PWM的计数频率是1MHZ,在代码中写死,可以修改;physics_register表示TIM的寄存器基地址,根据STM32MP1参考手册可知TIM2的寄存器地址是x40000000寄存器地址范围是0x70。
" l' d3 i+ D3 w0 |* U( T) i$ i% X6 ~9 _
下面的配置表示:使用TIM2 Channel 1作为PWM输出,周期是1ms,占空比是50%" O& p# Q$ j; v5 u- O
/ v( P5 J% w, ~( x* d
  1. root {
    6 m1 F* T8 H# b% B
  2.     platform {
    1 Z, T/ x7 V( i% I, v# T
  3.         pwm_config {7 e: V  ]- T! u* e/ \$ Q
  4.             //1mhz
    / D: `) \* Z* V  o4 j
  5.             template pwm_device {! e5 ?6 F+ C; S- e7 Q- z4 h
  6.                 Period = 1000;        //1000*0.1us=100us=10khz) Q0 k% W( ^0 P  Y1 w. r: V. r, P
  7.                 Pulse = 500;         //5009 @, H* S) s) p+ x% `; h
  8.                 Polarity = 0;   //high& ]1 `- A+ u  ?$ u. v
  9.                 IdleState = 0;  //reset
    7 p! L4 F# Y. T, i
  10.                 channel = 0;    //channel_1 PA5
    * v( Y3 k; w. n
  11.                 match_attr = "";
    5 h" N- ?% X; |  v; \9 g
  12.                 num = 0;
    : l1 U9 r9 u, F1 t! p
  13.                 physics_register = 0X40000000;
    0 t2 V) `* s- @; l( i" N
  14.                 register_size = 0X70;
      B2 i, t! H8 R9 w2 `# I/ ?
  15.             }
    / B8 w6 d8 s- S. w* O* p

  16. 5 K0 f& t2 {$ G
  17.             device_0X40000000 :: pwm_device {" \5 m' @0 a! X; t3 s
  18.                 match_attr = "st_stm32mp157_pwm_2";, a8 p7 K' {9 v/ \2 c
  19.                 num = 2;
    % `7 o% f/ ~& e
  20.                 physics_register = 0X40000000;+ j' M; Q1 |- s$ S  T8 f0 J# i; |
  21.             }& V* W  _: B& i" h0 H; Q# g& N
  22.         }& M: O/ Q% L+ m+ A  W
  23.     }# ?/ r: i- X  A3 r0 ?5 b
  24. }
复制代码
# E0 h9 \' K- k6 s1 {0 U& c5 D6 B
将上诉两个文件编辑完成后,在t\bearpi_hm_micro\liteos_a\hdf_config\hdf.hcs添加一行:0 G$ }1 E6 S+ \. m6 o

  Y+ [+ N6 b! @3 f7 s
  1. #include "pwm/pwm_config.hcs"
复制代码
; V1 f; e* |" j, n9 B/ A7 h
2、编写驱动% l5 _; X1 r1 i! \, r1 E3 J7 R0 D1 D
在earpi-micro\device\st\drivers录下新建pwm目录,并创建驱动源文件stm32mp1_pwm.c,以及BUILD.gn
1 F, V& W- w4 i
; {; m  U: {8 ~- [" E首先定义驱动入口对象:
* X: B  L. T6 C! S# n( I( X; o/ s& d& r1 n- Z
  1. // 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
    0 p( c6 J1 I1 W9 v+ U& m
  2. struct HdfDriverEntry g_pwmDriverEntry = {
    / c* j# v9 S# G
  3.     .moduleVersion = 1,* b2 M9 ]# Z2 _1 x% l: X6 q# E
  4.     .moduleName = "HDF_PLATFORM_PWM",        //必须与device_info.hcs中的字段一样,用于与驱动设备资源匹配
    1 V% a3 G& Z- e  B& i  \
  5.     .Bind = HdfPwmDriverBind,
    2 l# |* @1 _' W  }+ n' M
  6.     .Init = HdfPwmDriverInit,! R. v/ h8 ]( ?& O, w& N  ~1 i
  7.     .Release = HdfPwnDriverRelease,
    7 a; |: z' O: Q3 v1 o
  8. };
      P" J+ M5 v2 v( f
  9. + n6 Q) M" D2 i0 u6 p
  10. // 调用HDF_INIT将驱动入口注册到HDF框架中! [/ o, C3 a  v4 C" U( q
  11. HDF_INIT(g_pwmDriverEntry);
复制代码
( J7 a$ i/ g5 k/ ^7 C
以及自定义一个PWM对象:% H& a4 X+ M2 N# j
2 ]$ p7 k. O  \, }
  1. //私有pwm结构体! i$ t" p8 @4 Z5 L( F& T/ ^
  2. struct StmPwm {3 @" ^; u' i; |7 `
  3.     TIM_HandleTypeDef htim;                //HAL TIM必须
    / a3 I& T5 i% M6 x5 u
  4.     struct PwmDev dev;                        //HDF PWM核心层必须
    4 X9 |5 Y, V/ l* ~) B$ ^
  5.     TIM_OC_InitTypeDef sConfig; //HAL PWM必须 & E" U0 R, C2 v9 Y4 X: q+ d3 x' T& O
  6.     uint32_t physics_register;  //TIM基地址
    1 D+ ~1 ]4 W: i9 f
  7.     uint32_t register_size;                //地址范围
    ' L* H8 c. @  X& z
  8.     uint32_t channel;                        //pwm channel6 O# e$ z" ^8 j$ n
  9. };
复制代码

( I- i/ m$ U. d+ g( J9 U初始化函数逻辑很简单,就是使用 struct StmPwm 对象中的成员去调用各个库的初始化函数。
+ a3 G" C4 e5 |( [& C0 l5 h" O! \0 ]2 u5 \. i) V3 X0 J: j* u
首先引入PWM所需的头文件:0 ~" m/ J3 i5 ~/ f
, W+ j; p; ^' ~/ `4 D! S3 f. V
  1. //stm hal库
    . Y2 B9 l( I( D0 Y: [
  2. #include "stm32mp1xx_hal.h". X2 B/ z3 Q7 g1 |% q
  3. #include "stm32mp1xx_hal_tim.h"" _3 ]5 y$ X: R5 E* L6 F) s
  4. //hdf pwm1 G0 p+ s9 a0 X, `5 q& Q
  5. #include "pwm_core.h"
    & X% y* c6 i3 ^( Y! k) a
  6. #include "pwm_if.h"
复制代码
3 z& H$ d# u3 O, B5 o
驱动初始化函数:首先读取上文所配置的信息到StmPwm对象中,然后将PwmDev添加到HDF PWM框架中,这样就能使用HDF PWM框架的功能;最后调用STM32MP1 HAL库函数,初始化TIM2的PWM模式,设置对应的GPIO复用功能,开始输出PWM。
5 U: n6 }/ F( s# h3 Y: x' ^0 T1 a& _7 t; G6 D% h/ }: c, e. ?/ R
  1. // 驱动自身业务初始的接口(设置IO口为输出) HDF框架在加载驱动的时候,会将私有配置信息保存在HdfDeviceObject 中的property里面9 U( P+ ^7 }5 f4 Y
  2. int32_t HdfPwmDriverInit(struct HdfDeviceObject *device)2 s6 ~4 F: h0 K+ H1 t% f4 ^
  3. {1 q  c+ U. p$ v2 V* ?
  4.     dprintf("%s enter\r\n",__func__);
    * w% c) @) y6 J$ d
  5. + M: s2 O3 R* F# n; ~6 o
  6.     RCC_ClkInitTypeDef    clkconfig;! ^; u5 T$ g4 ~2 _
  7.     uint32_t              pFLatency;
    6 b2 |% x+ Z5 U* ]" e( n
  8.     uint32_t              uwTimclock;
    1 n9 C1 O: N4 W9 o( s
  9. ! Q0 c0 O$ p! K/ |2 x2 y
  10.     sp = (struct StmPwm *)OsalMemCalloc(sizeof(*sp));
    " [. x& H- p- ]" \" q5 r! Z
  11. . v/ U+ D, A# D3 Q% F" K/ ^) [
  12.     //读取配置文件
    ! c8 d# I* }* W7 i
  13.     readHcs(device);
    5 Q" }: X$ H5 E) r- S/ H
  14. " {  U+ J: w) U) F0 b
  15.     //获取时钟频率
    $ k6 h2 h, p7 }1 J1 t, T
  16.     HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);   # h1 v9 t3 W4 T
  17.     __HAL_RCC_TIM2_CLK_ENABLE();
    ; W' j* }- C8 l" e7 |0 t( r: e" Q
  18.     uwTimclock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_TIMG1);
    # O1 y( k7 `4 K7 @/ B4 j: _
  19.     //dprintf(" uwTimclock = %d\r\n",uwTimclock);
    ( h( H# B0 x7 V8 P
  20.         //配置TIM的计数频率为10MHZ
    # \1 N9 A, C$ a. o) G5 c1 Y. P
  21.     sp->htim.Init.Prescaler = (uint32_t) ((uwTimclock / 10000000U) - 1U);    6 r. x3 g# p9 d; H; E
  22.     sp->htim.Init.CounterMode = TIM_COUNTERMODE_UP;
    + s& Z0 N; ^8 r5 Q- J
  23.     sp->htim.Init.ClockDivision = 0U;, M  V7 {* Y( v4 Y- G- h+ {
  24.     sp->htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;% i2 q5 W; z( ?6 i
  25.     sp->sConfig.OCMode = TIM_OCMODE_PWM1;
    % d; j3 f6 E+ i% M' T
  26.     sp->sConfig.OCFastMode = TIM_OCFAST_DISABLE;
    2 q3 }& h. s- r4 R+ R
  27. 3 B. }: _. M" p& Y% g! w% \1 ~7 Y
  28.     sp->dev.method = &g_pwmOps;
    * I& t/ F& W+ e$ o6 E/ P% @
  29.     sp->dev.cfg.duty = sp->sConfig.Pulse;  
    6 Y& N5 }$ E9 k5 Q1 A+ Q; L6 ?
  30.     sp->dev.cfg.period = sp->htim.Init.Period;    6 f* V( q5 |2 S0 _& {
  31.     sp->dev.cfg.polarity = sp->sConfig.OCPolarity;    ( e  C/ a5 b9 C2 U! O( |
  32.     sp->dev.cfg.status = PWM_ENABLE_STATUS;
    , q9 }0 l3 y- _+ ?7 E0 {
  33.     sp->dev.cfg.number = 10000; 2 t3 _' N7 D& F+ x

  34. * i1 y: g- j7 A" y4 ~
  35.     sp->dev.busy = false;
    1 d, `# ~9 e; C
  36. ! P! t; z) P+ ~6 p/ d
  37.     //添加到核心层
    7 E7 I0 U4 Y" I
  38.     if (PwmDeviceAdd(device, &(sp->dev)) != HDF_SUCCESS) {
    - e4 n" J+ e" s: Y- Z# X

  39. : g: ^- o% c" q3 G, M
  40.         return HDF_FAILURE;
    # s2 Z! M! o' k
  41.     }
    7 D  Z* I- ]* \# S6 E9 b
  42.         //对TIM2寄存器基地址进行映射
    , ?. O' I  `+ r1 ]5 L
  43.     sp->htim.Instance = (TIM_TypeDef *)OsalIoRemap(sp->physics_register, sp->register_size);6 ]+ t7 W4 R- r
  44.     if (sp->htim.Instance == NULL) {- w) D" ^" m3 K' A0 C& h, {- C
  45.         dprintf("error OsalIoRemap for htim \r\n");
    8 C7 Y3 \6 H- _, o, U" Z* C$ A
  46.         return -1;
    1 n& M% E7 K  u# g* `* u
  47.     }8 Q; A7 `3 `3 c( }4 C9 ?. }, ^
  48.     //初始化PWM寄存器) n" ?* D: i( L- `
  49.     if (HAL_TIM_PWM_Init(&sp->htim) == HAL_OK)5 `5 o( P8 b) f- L5 l8 k% W
  50.     {6 b  L# X6 V$ ^& ^0 U4 ~/ V  {8 f
  51.         dprintf("pwm init ok config channel \r\n");$ U% P- W' p5 B& _: L6 v

  52. * Q7 L) ~( ?& ]1 C- p2 x- Z/ l
  53.         HAL_TIM_PWM_ConfigChannel(&sp->htim, &sp->sConfig, sp->channel);& E7 k, P& r0 W: m8 t" M, M* m
  54.                 //初始化gpio
    4 o' _& J& u6 ]; c* M" ]/ F+ C. u
  55.         HAL_TIM_MspPostInit(&sp->htim);
      H7 Q. y: ?/ |6 F! ], Y+ e- B# g
  56.         //开始输出PWM7 v' l  i& ]) U; N$ T1 o) S3 b
  57.         HAL_TIM_PWM_Start(&sp->htim,sp->channel);! W+ K* x$ c, C# F& v& R7 c
  58.     }else{
    * p: M) X& k( e
  59.         return -1;  V' P3 o8 O$ t- S! K7 F1 K
  60.     }
    ! _8 U. o) @. {7 B

  61. # I4 o' X0 A/ F- S
  62. 1 S  y) H; J7 l$ D
  63.     return HDF_SUCCESS;( W+ d5 F( I+ S+ f; f, }/ ]
  64. }
复制代码
- V& G0 h7 F' Q* V- K- G& @
读取上诉配置文件到StmPwm对象:
2 u! u. z1 g0 V- H0 T: O+ h5 V( v, b: C& z
  1. //读取配置文件   pa5 tim2 channel 1
      j! B% l( A) E* C) N) t
  2. int readHcs(struct HdfDeviceObject *obj)
    # K, E2 Q/ Y" X5 S( S: ?7 W* G
  3. {; f$ b; F: i- J; |9 e, B
  4.     dprintf("%s enter\r\n",__func__);2 r' P& b, d+ k  O
  5. % ~2 @) G) x" _. H

  6. ! s4 l, D/ D, j, n' Z$ X0 r
  7.     struct DeviceResourceIface *iface = NULL;. V5 n0 X4 T" e$ }7 m
  8. 6 d' p/ |4 G3 z  N
  9.     iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);6 F. E; P5 s2 m3 \6 O7 o
  10.     if (iface == NULL || iface->GetUint32 == NULL) {& [, J* b# Z* M( d* A0 h5 u
  11.         HDF_LOGE("%s: face is invalid", __func__);
    ) Q3 [1 P( h# x/ \) ~3 y3 [
  12.         return HDF_FAILURE;# p+ j* }6 f' N5 ^
  13.     }5 W- p& T+ H+ B) h
  14.     if (iface->GetUint32(obj->property, "Period", &sp->htim.Init.Period, 0) != HDF_SUCCESS) {
    ( g" d& `8 ]9 Q, Q( |7 P1 c
  15.         HDF_LOGE("%s: read num fail", __func__);  r# Y0 ?& y, }' E8 g! }
  16.         return HDF_FAILURE;% k1 m! W/ f' F5 _: U! }
  17.     }/ @  y, p" f2 K9 A" f( G+ J
  18.     if (iface->GetUint32(obj->property, "Pulse", &sp->sConfig.Pulse, 0) != HDF_SUCCESS) {; I6 G8 B  K7 F- `( ]
  19.         HDF_LOGE("%s: read num fail", __func__);
    & k5 c4 x4 F0 O# C9 z9 M
  20.         return HDF_FAILURE;
    9 i/ j' w  o6 x3 l; v" v2 p
  21.     }8 b; I, F1 f3 |& v* t6 g
  22.     if (iface->GetUint32(obj->property, "physics_register", &sp->physics_register, 0) != HDF_SUCCESS) {! C2 k+ j; J- r
  23.         HDF_LOGE("%s: read num fail", __func__);
    , `% ?% Q/ ?0 Y2 \
  24.         return HDF_FAILURE;3 M1 _1 m4 a7 ^& t/ m/ m' C
  25.     }
    6 k+ {; ^" G( I+ I" V$ G
  26.     if (iface->GetUint32(obj->property, "register_size", &sp->register_size, 0) != HDF_SUCCESS) {1 ^/ y. W0 h/ A5 D- y5 a7 f
  27.         HDF_LOGE("%s: read num fail", __func__);# F0 {/ `/ x; \* Q3 K4 N& G; x
  28.         return HDF_FAILURE;
    / K5 M5 r; a; l0 x& T; x7 G' I2 O
  29.     }* |  n$ m' Q/ V$ v$ ^: g
  30.     if (iface->GetUint32(obj->property, "channel", &sp->channel, 0) != HDF_SUCCESS) {. I* O/ H- h! G7 r& |0 G2 [' c
  31.         HDF_LOGE("%s: read num fail", __func__);
    , M; g2 o5 r0 C
  32.         return HDF_FAILURE;
    " \3 y/ B: ?8 r0 b' r0 c6 `
  33.     }" k7 w( d# V' p, w0 T" _. C( l4 D
  34.     if (iface->GetUint32(obj->property, "Polarity", &sp->sConfig.OCPolarity , 0) != HDF_SUCCESS) {
    % Y" O7 A: u* W; X
  35.         HDF_LOGE("%s: read num fail", __func__);/ Z' C6 _# I& _/ U. V% D
  36.         return HDF_FAILURE;$ x# b# D# f" n3 l5 G7 F
  37.     }( h2 J: R) \2 c% M. [
  38.     if (iface->GetUint32(obj->property, "IdleState", &sp->sConfig.OCIdleState , 0) != HDF_SUCCESS) {6 {1 e( T4 a  W/ D1 X7 X& q
  39.         HDF_LOGE("%s: read num fail", __func__);2 W6 b+ d* V$ z8 }8 D, J. a6 C
  40.         return HDF_FAILURE;( ^0 {' a" _" A1 y* b% b
  41.     }
    5 o, L# z* ^) {# u3 y
  42.     if (iface->GetUint32(obj->property, "IdleState", &sp->dev.num , 0) != HDF_SUCCESS) {9 `1 K# O! i/ g
  43.         HDF_LOGE("%s: read num fail", __func__);
    & o8 U) H( o+ p' [& H! B
  44.         return HDF_FAILURE;
    ! c: A# w* s" I9 F5 y
  45.     }9 ]- N+ t/ Y& _! u! ^( O
  46. , Y3 K& O9 |7 L# I
  47.     return 0;( y/ g! `9 P, C6 f
  48. }
    " @! D5 b% J4 Y! O
复制代码

* [- S- g: l1 F/ OGPIOA_5 复用为PWM模式
, n6 s: B4 a: y& N3 b+ V& d$ ?# L6 T, N$ H& h
  1. //初始化gpio口
    ( r: l: {' G4 @2 ~
  2. void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
    ! f; M; o6 b/ ?# |6 j7 h
  3. {- s1 s" U0 j4 l! S
  4.     __HAL_RCC_GPIOA_CLK_ENABLE();0 a$ n' s" W5 f9 ^, l. F2 W
  5.     dprintf("%s enter\r\n",__func__);  e7 E7 c7 H- I# a- o+ b- S5 @
  6.     GPIO_InitTypeDef GPIO_InitStruct;) S- t: C( y) u9 j. y

  7. 0 P0 F! p* h; L
  8.     //gpioa addr
    ) K2 h( S/ \6 q8 h  j" S
  9.     unsigned char *gpioa= (unsigned char *)OsalIoRemap(GPIOA_PHYADDR, GPIOA_SIZE);
    2 D/ ^/ I1 \$ _4 d5 E
  10.     /**TIM2 GPIO Configuration   
    2 L6 j% @+ q/ c" j1 H$ j7 h
  11.     PA5     ------> TIM2_CH1 7 z" Z4 }7 J) h& k) L+ t$ B8 E- U( g
  12.     */
    , V1 j1 u9 v7 }4 X
  13.     GPIO_InitStruct.Pin = GPIO_PIN_5;8 }8 t0 Q9 Z1 V7 R5 f4 u7 ?
  14.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;! ~$ Q! ~4 s! l& c# L  d
  15.     GPIO_InitStruct.Pull = GPIO_NOPULL;  f* |$ l5 n+ z) Q% y" F/ d
  16.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    % x8 Y) O5 {+ m* G- U0 X8 f% w9 O. N# ~
  17.     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    , {; y  Y& E' B  J* |+ N
  18.     HAL_GPIO_Init((GPIO_TypeDef *)gpioa, &GPIO_InitStruct);
    ; ?, U" b, v% z) o0 N
  19. % c' Y1 {7 r7 P# P
  20. }
复制代码
- ?& Q6 O  ?: u& `! h+ E
到此初始化任务就基本完成,那么HDF PWM框架如何来使用我们的PWM驱动呢?这就要提到 PwmMethod,通过设置PwmMethod的函数,提供接口给PWM框架,主要是提供StmPwmSetConfig。6 [, J5 b) B# d1 b/ U
7 `2 r* d) G: I  {( ?0 O  L1 G4 l' D! i, |
  1. struct PwmMethod g_pwmOps = {6 y* o0 [5 {& [5 ]: I4 K" V2 G% L/ y
  2.     .setConfig = StmPwmSetConfig,
    - o# N3 W; d+ Q) @1 _3 y
  3. };
复制代码
5 Q: a4 F" ]" i. \# N
HDF_PWM框架是通过pwm_if.h文件给内核提供PWM功能的,我们来看pwm_if.h给内核提供了什么。$ ]5 J& J0 F( w% F: D) X, r

+ @6 M5 Q/ c+ O1 h* q- B, x
  1. //获取pwm句柄
    + I; n( }7 m, i( m4 _5 o  p
  2. DevHandle PwmOpen(uint32_t num);! T* R9 O2 [' g/ i  J7 Y+ j
  3. void PwmClose(DevHandle handle);( ^8 s2 i0 x1 c! B- p# \* O
  4. //设置pwm周期6 J& g& H3 S% W! p7 Q! P; I- A
  5. int32_t PwmSetPeriod(DevHandle handle, uint32_t period);) \. r& [, l' o5 t5 c4 b! F2 C
  6. //设置占空比& M0 }- [* g! K3 z" v8 e0 f# V7 F. C
  7. int32_t PwmSetDuty(DevHandle handle, uint32_t duty);) A4 x* d" j8 n1 ?" H$ {7 G
  8. //设置极性
    6 ~# i+ z7 K; ~* e( Q/ ^
  9. int32_t PwmSetPolarity(DevHandle handle, uint8_t polarity);. _0 i9 a$ v+ A  a4 v# r
  10. //使能pwm
    8 E0 V$ t- [! p" f
  11. int32_t PwmEnable(DevHandle handle);
    " w( [- L- F9 |- z% z
  12. int32_t PwmDisable(DevHandle handle);
    3 n6 A3 r0 y& L' o' O
  13. //设置pwm8 S- o) M( O, w8 L! g- @$ e# I
  14. int32_t PwmSetConfig(DevHandle handle, struct PwmConfig *config);
    9 j" D5 k5 t+ l% u% @5 |
  15. int32_t PwmGetConfig(DevHandle handle, struct PwmConfig *config);
复制代码

7 e( S# }% L9 {! M! H/ `% }, f可以看到PWM框架提供给内核设置PWM参数的接口,这些接口最终会调用我们编写的驱动,那么我们的驱动应该如何实现上述的功能?答案就在:StmPwmSetConfig,所有的接口最终都会调用PwmSetConfig()而间接调用我们编写的StmPwmSetConfig()。9 N) W6 g8 a% p% [: P9 G  U
7 Q/ r& }* s* _- C& S7 S: V
在StmPwmSetConfig()中会对config参数进行检查,然后根据config参数去操作PWM外设,具体而言就是调用HAL库的PWM函数去实现:
! U0 f- t8 o/ c$ u6 V0 J" s
6 P# q$ `, F$ F' L, F
  1. //给pwm框架注册的函数! }  W& J/ Q' K. ?
  2. struct PwmMethod g_pwmOps = {6 Q/ u5 c; C3 O, r
  3.     .setConfig = StmPwmSetConfig,
      @$ k' e2 X) j3 R1 }8 l
  4. };" ?5 w0 _% R$ Q: O7 ?# J
  5. //设置pwm
    + }! V5 ]4 Q, s% p" b+ k8 Z5 G
  6. static int32_t StmPwmSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
    6 c; C: X3 U  D7 T4 E5 m
  7. {! x& w- V' X) `+ [0 X

  8. 5 G# K/ \, O0 Y# y
  9.     if (pwm->cfg.polarity != config->polarity ) {/ Z0 Q/ ~3 m) U. u7 U1 E
  10.         HDF_LOGE("%s: not support set pwm polarity", __func__);
    3 l/ ?+ q% u' {& I$ r( L. `
  11.         return HDF_ERR_NOT_SUPPORT;! i; k* l% {' t: j9 t/ q" }5 w
  12.     }- a8 R' P; v- P1 h$ `4 d. v

  13. 7 V5 E) g# ?7 j' A
  14.     if (config->status == PWM_DISABLE_STATUS) {
    ) X8 M3 P+ t! Q* y+ M" ?& Y
  15. # [4 K! [! X& J  Y% I
  16.         StmPwmDisable();- ]9 {7 t% ^" O4 T% ]& g
  17.         return HDF_SUCCESS;" }/ T) P; u/ r- [$ r7 e, d+ e
  18.     }
    , \3 e9 e( b8 Q  t( _  [3 q$ f

  19. % Q2 b% G% Y* X3 n+ ]* z: F- y
  20.     if (config->polarity != PWM_NORMAL_POLARITY && config->polarity != PWM_INVERTED_POLARITY) {
      F( Z" x& `0 t# t
  21.         HDF_LOGE("%s: polarity %u is invalid", __func__, config->polarity);
    : H+ z' s) w/ d5 V$ R+ b7 V
  22.         return HDF_ERR_INVALID_PARAM;+ m) z5 N$ ^2 z9 E4 k& s. T
  23.     }
    , ?. Z: ~; U0 G1 I: X

  24. 8 Z5 z* M. n3 D1 n4 c* V0 r; {
  25.     if (config->period < 0) {
    ) u9 M" T8 b/ ]  ]. Y2 M% Y
  26.         HDF_LOGE("%s: period %u is not support, min period %u", __func__, config->period, 0);( F# m; L. q" W- f6 }+ A
  27.         return HDF_ERR_INVALID_PARAM;- S. `4 q3 E7 i  \  ?# R' l
  28.     }% o6 K$ I  N& C! ^5 L5 a* e& X
  29.     if (config->duty < 1 || config->duty > config->period) {
    . E$ \6 T- `- b
  30.         HDF_LOGE("%s: duty %u is not support, min dutyCycle 1 max dutyCycle %u",- N* g# R1 y: `+ H  H+ p* y4 s# C
  31.             __func__, config->duty, config->period);
    / W" D; Z) G9 C
  32.         return HDF_ERR_INVALID_PARAM;) l4 y) P( s" u. W" _! v
  33.     }
    3 L0 R3 x4 `' q
  34.     //暂停pwm,更新配置6 L4 B  n$ F  L9 x9 [; n" F; x
  35.     StmPwmDisable();
    * S8 z" r+ M: Z# @. w

  36. 0 ]! ~  M& f3 \* O
  37.     if (pwm->cfg.polarity != config->polarity) {
    % `5 _$ ?* \% G/ H
  38.         StmPwmSetPolarity( config->polarity);
    # z2 B1 ?! x  a4 ]6 j
  39.     }4 }% q2 ?; N& i! y0 E; \4 W
  40.     StmPwmSetPeriod( config->period);
    2 T4 |. r2 S. x/ L
  41.     StmPwmSetDuty( config->duty);
    ' P5 T% D# r$ {3 A, f* r
  42.     //继续输出+ @0 q; q9 ~9 `, Y& D6 a( L
  43. - h/ h& n! M2 W% s$ O8 j
  44.     if (config->number == 0) {" p1 z* @4 T+ b3 M9 e
  45.         StmPwmAlwaysOutput();
      S5 z( m" r* g
  46.     } else {$ V' P  Q. K* B
  47.         StmPwmOutputNumberSquareWaves( config->number);
    4 G2 n, j/ E) {+ J; E. T0 X" ]
  48.     }
    # g! V7 b% U$ L# p% C2 Z# G+ f2 V
  49.     return HDF_SUCCESS;& T3 o8 c- D6 S2 v) L
  50. }) G% y* k0 S/ {& ~: j
复制代码
( c- P$ S( L. p$ J
HAL库实现配置PWM的方法:! R. g: w- o5 J. C, v
8 G& {- u) |$ _* |
  1. static inline void StmPwmDisable()
    , L. e' T1 ^5 J& x8 w! a% j7 j
  2. {5 v+ v, ^6 @9 N! r* F" P
  3.     HAL_TIM_PWM_Stop(&sp->htim, sp->channel);
    - i* S" j0 T! c4 M1 _) w: R+ R
  4. }
    ) x! P$ I9 F0 C. M
  5. 4 ^& P3 [. _+ Y* M
  6. static inline void StmPwmSetPeriod(uint32_t us)
    0 ?% R# F3 L% _
  7. {
    * z+ t2 h4 e1 y' N6 ]& M
  8.     sp->htim.Init.Period = us;
    8 m  n# H' e! V* Q* N% c( R/ K5 ?
  9.     TIM_Base_SetConfig(sp->htim.Instance, &sp->htim.Init);: F$ \. A& H  e/ I6 M
  10. }; G1 X# u8 I2 k
  11. static inline void StmPwmSetDuty(uint32_t us)
    1 q5 X* _2 F% s) ^# Q8 f( ]' n
  12. {
    * `/ i) f% y) O0 q
  13.     sp->sConfig.Pulse = us;
    . x' O: R2 ]& M5 w5 C2 P( m# w
  14.     HAL_TIM_PWM_ConfigChannel(&sp->htim, &sp->sConfig, sp->channel);
    / o2 W* P- ^  D; P3 \
  15. }
    % F. ~) E+ Q9 Z* \* k* s/ a
  16. static inline void StmPwmSetPolarity(uint32_t polarity)) H* r3 }; ~! |0 w" c
  17. {
    , i0 I  p% L' G2 h# W
  18.     sp->sConfig.OCPolarity = polarity;8 l9 p% G4 x/ T4 }; B5 P
  19.     HAL_TIM_PWM_ConfigChannel(&sp->htim, &sp->sConfig, sp->channel);    8 B; }( Z  [8 u: l: J7 p
  20. }. ^1 A" b9 C7 }" L4 ?' }' t
  21. static inline void StmPwmAlwaysOutput()0 f& [5 B+ D# C/ T9 o% P
  22. {
    9 V9 T  T9 c1 p9 R
  23.     HAL_TIM_PWM_Start(&sp->htim, sp->channel);
    ! k! i  ]( {: V6 D% d4 n
  24. }% o8 G- L! l: p. e- ?7 m
  25. 6 D2 |$ B9 R- H" v4 {7 ?" N
  26. static inline void StmPwmOutputNumberSquareWaves(uint32_t num)
    $ G- a; L' U* `3 f, C7 u. S4 G
  27. {! c! D- @- t" T( s

  28. 7 X* p; }0 _0 A% A+ }
  29.     HAL_TIM_PWM_Start(&sp->htim, sp->channel);
    . C/ d% A! Q% p: L
  30. }
复制代码
1 _/ z4 Y- I% v4 l8 V6 [  `) Z9 o- I
3、编写构建脚本$ U0 i8 O' ^  B# U6 M  |
最后要将我们编写好的驱动文件加入到编译构建系统中:
9 p7 H+ G" D  D& K. Z& X
( E* ]- j( e4 V编辑BUILD.gn:
5 T! H5 q+ b$ B% T% _0 L7 ]  l6 H( ~9 i+ i
  1. import("//drivers/adapter/khdf/liteos/hdf.gni")8 n3 ~1 ^) m4 U
  2. module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_PWM)
    , H( }: x2 X9 b9 R
  3. hdf_driver("hdf_pwm") {
    + l+ U& Q2 ^9 w7 L+ G- V
  4.     sources = [" R8 W$ y& M9 |2 E3 B
  5.     "stm32mp1_pwm.c",5 T; A  G0 z% E- n! ~/ D$ I1 G
  6.     ]4 ?3 f; s& \5 ~2 [+ F  o. ^
  7.     include_dirs = [' H' B5 v( h3 P! T
  8.      "." ,
    0 o) J. ~8 e9 N7 a# N) M
  9.      "//device/st/drivers/stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc",
    . k, B( e+ k1 ]
  10.   ]' _# W) r2 z; M4 e9 L6 d
  11. }
复制代码

+ `$ x3 C% x2 q并修改device/st/drivers/BUILD.gn,在dep添加pwm:: A$ G$ ]3 F; e

# F* @/ @  o5 D7 _( V  }1 g+ |
  1. group("drivers") {* r9 t8 C. z# A" {+ n2 t$ c
  2.   deps = [
    1 J$ f" v3 A0 o+ Y. ~7 f" |; \
  3.     "pwm",( f3 {# A8 @7 W5 _" X
  4.     "uart",2 I6 n7 d- [- W3 m* T2 Q4 t- Y1 _
  5.     "iwdg",
    - B' X0 D6 \3 {$ o, b; \8 }! h
  6.     "i2c",
    : d1 z6 b% H7 K" ?6 }% S
  7.     "gpio",
    - f- ^- T. r/ V' G
  8.     "led",
    : l& \- z% L; G- o6 M8 m5 ]. V
  9.     "button",
    0 U( Y9 C  P6 a2 h! ^+ n
  10.     "sample",
    7 E0 b% m* A- @2 j  s1 I5 `
  11.     "mem",! X: B# J  g2 z4 j; q
  12.     "stm32mp1xx_hal",5 s9 y9 D/ |6 P. t
  13.     "wifi/driver/hi3881",  h# h7 K; G1 u! F& T$ |
  14.     "wifi/driver:hdf_vendor_wifi",
    5 k" t- x3 F0 E; }0 r  _
  15.   ]
    7 [6 N' f! _; }3 x
  16. }
复制代码

& c$ l: ]$ q; M. @7 e4、效果& }* C3 A9 U% f- F
完成PWM驱动的编写后,就可以使用bearpi-micro\drivers\framework\include\platform\pwm_if.h里的函数来控制PWM波。如图是使用逻辑分析测量到的GPIOA_5引脚上的PWM信号:$ C: @3 \- A8 A$ u' @6 D$ \6 h1 T

0 Y8 b+ @9 O/ l/ k计数频率10MHZ,计数值1000,那么PWM的频率就是10MHZ/1000=10KHZ:
, o: A* o! a- v" M. l; |6 [+ o1 f+ b% a, r( Q" ]0 U
e3f95bd192b049f4b1570353680f7e13.png + c" i; U# O/ o5 _8 t' F* m9 h$ V
/ k( d* U9 ]; f$ f( w8 d6 r
————————————————, z4 F" j3 g, K: t
版权声明:killer-p( U8 ^# S  u" F
% y- Q0 L! S2 y5 l" f6 e( A! m' F7 z

  x4 _0 m2 ~# P+ r6 S% _, R. f
收藏 评论0 发布时间:2022-10-24 21:59

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版