OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5086|回复: 2

stm32mp157之点亮led_操作寄存器

[复制链接]

4

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
199
金钱
199
注册时间
2016-1-27
在线时间
18 小时
发表于 2021-1-4 15:58:21 | 显示全部楼层 |阅读模式
    1.硬件上连接,LED0 <--> PI0    LED1 <--> PF3
    2.修改设备树,由于板子出厂自带的程序是有点亮 led 的,所以一般来说设备树有相关节点,
根据板子开机 Log 可以知道板子使用的设备树是 stm32mp157d-atk.dts

    假设当前在 kernel 源码
vi arch/arm/boot/dts/stm32mp157d-atk.dts
    因为 LED0 接的是 PI0 ,所以直接搜索 gpioi 0,或者搜索 led

    结果是没有在 stm32mp157d-atk.dts 找到,在文件开头可以看到 include 其他 dts 文件,可以一个一个打开,继续搜索

    经过一番搜索,在 stm32mp157.dtsi 找到以下节点

    leds {
         compatible = "gpio-leds";

         led1 {
             label = "sys-led";
             gpios = <&gpioi 0 GPIO_ACTIVE_LOW>;
             linux,default-trigger = "heartbeat";
             default-state = "on";
             status = "okay";
         };

         led2 {
             label = "user-led";
             gpios = <&gpiof 3 GPIO_ACTIVE_LOW>;
             linux,default-trigger = "none";
             default-state = "on";
             status = "okay";
         };

         beep {
             label = "beep";
             gpios = <&gpioc 7 GPIO_ACTIVE_LOW>;
             default-state = "off";
         };
     };


其中 led1 led2 这两个节点就是我们关注的,可以直接注释掉,或者将 status 属性的值从 okay 改为 disabled

改完设备树之后 可以通过  make dtbs 重新编译,然后下载到板子中

    3.打开 stm32mp157 的参考手册,主要关注以下寄存器

    RCC_PLL4CR(RCC PLL4 Control Register)  物理地址 0x50000000 + 0x894
    设置该寄存器打开 PLL4,PLL4 是 gpio 等相关外设的时钟源
    这里主要最低两位
    [1] Bit 1 PLL4RDY: PLL4 clock ready flag
         Set by hardware to indicate that the PLL4 is locked.
         0: PLL4 unlocked (default after reset)
         1: PLL4 locked
    [0] Bit 0 PLLON: PLL4 enable
         Set and cleared by software to enable the PLL4.
         0: PLL4 OFF (default after reset)
         1: PLL4 ON, and ref4_ck is provided to the PLL4

    RCC_MP_AHB4ENSETR(RCC AHB4 Periph. Enable For MPU Set Register)  物理地址 0x50000000 + 0xA28
    设置该寄存器可以打开 gpio 的时钟,比如设置 GPIOI 和 GPIOF 的位如下
    [8] Bit 8 GPIOIEN: GPIOI peripheral clocks enable
         Set by software.
         0: Writing '0' has no effect, reading '0' means that the peripheral clocks are disabled
         1: Writing '1' enables the peripheral clocks, reading '1' means that the peripheral clocks are enabled
    [5] Bit 5 GPIOFEN: GPIOF peripheral clocks enable
         Set by software.
         0: Writing '0' has no effect, reading '0' means that the peripheral clocks are disabled
         1: Writing '1' enables the peripheral clocks, reading '1' means that the peripheral clocks are enabled

    GPIOx_MODER(GPIO port mode register)
    (x = A to K, Z)
    这些寄存器(GPIOA_MODER to GPIOK_MODER,GPIOZ_MODER)用于设置 GPIO 输出输入模式,同时也表明了
相应的引脚为 GPIO 功能。

    GPIOI_MODER  物理地址 0x5000A000 + 0x00
    设置 GPIOI 相关引脚的模式,位定义如下,对于 PI0 关注 [1:0]
    Bits 31:0 MODER[15:0][1:0]: Port x configuration I/O pin y (y = 15 to 0)
    These bits are written by software to configure the I/O mode.
    00: Input mode
    01: General purpose output mode
    10: Alternate function mode
    11: Analog mode

    GPIOF_MODER  物理地址 0x50007000 + 0x00
    设置 GPIOF 相关引脚的模式,未定义同上,对于 PF3 ,关注 [7:6]

    GPIOx_BSRR(GPIO port bit set/reset register)
    (x = A to K, Z)
    这些寄存器(GPIOA_MODER to GPIOK_MODER,GPIOZ_MODER)可以快速的设置 GPIO 输出 1 或者 0

    GPIOI_BSRR  物理地址  0x5000A000 + 0x18
    设置 GPIOI 相关引脚输出 1 或者 0 ,位定义如下,对于 PI0 关注 [16] 和 [0]
    Bits 31:16 BR[15:0]: Port x reset I/O pin y (y = 15 to 0)
    These bits are write-only. A read to these bits returns the value 0x0000.
    0: No action on the corresponding ODRx bit
    1: Resets the corresponding ODRx bit
    Bits 15:0 BS[15:0]: Port x set I/O pin y (y = 15 to 0)
    These bits are write-only. A read to these bits returns the value 0x0000.
    0: No action on the corresponding ODRx bit
    1: Sets the corresponding ODRx bit

    GPIOF_BSRR  物理地址  0x50007000 + 0x18
    设置 GPIOI 相关引脚输出 1 或者 0 ,位定义同上,对于 PF3 关注 [19] 和 [3]

    4.编写驱动和 Makefile
    程序的一个重点是对相关寄存器重映射,然后就是根据参考手册设置寄存器,具体程序,即 Makefile 如下
led.c
  1. #include <linux/module.h>

  2. #include <linux/fs.h>
  3. #include <linux/errno.h>
  4. #include <linux/miscdevice.h>
  5. #include <linux/kernel.h>
  6. #include <linux/major.h>
  7. #include <linux/mutex.h>
  8. #include <linux/proc_fs.h>
  9. #include <linux/seq_file.h>
  10. #include <linux/stat.h>
  11. #include <linux/init.h>
  12. #include <linux/device.h>
  13. #include <linux/tty.h>
  14. #include <linux/kmod.h>
  15. #include <linux/gfp.h>
  16. #include <linux/delay.h>
  17. #include <asm/io.h>

  18. #define RCC_BASE    0x50000000
  19. #define RCC_PLL4CR         (RCC_BASE + 0x894)
  20. #define RCC_MP_AHB4ENSETR  (RCC_BASE + 0xA28)

  21. #define GPIOF_BASE  0x50007000
  22. #define GPIOF_MODER        (GPIOF_BASE + 0x00)
  23. #define GPIOF_BSRR         (GPIOF_BASE + 0x18)

  24. #define GPIOI_BASE  0x5000A000
  25. #define GPIOI_MODER        (GPIOI_BASE + 0x00)
  26. #define GPIOI_BSRR         (GPIOI_BASE + 0x18)

  27. static volatile unsigned int *rcc_pll4cr;
  28. static volatile unsigned int *rcc_mp_ahb4ensetr;
  29. static volatile unsigned int *gpiof_moder;
  30. static volatile unsigned int *gpiof_bsrr;
  31. static volatile unsigned int *gpioi_moder;
  32. static volatile unsigned int *gpioi_bsrr;

  33. static void gpio_init(void)
  34. {
  35.         rcc_pll4cr = ioremap(RCC_PLL4CR, 4);
  36.         rcc_mp_ahb4ensetr = ioremap(RCC_MP_AHB4ENSETR, 4);
  37.         gpiof_moder = ioremap(GPIOF_MODER, 4);
  38.         gpiof_bsrr  = ioremap(GPIOF_BSRR, 4);
  39.         gpioi_moder = ioremap(GPIOI_MODER, 4);
  40.         gpioi_bsrr  = ioremap(GPIOI_BSRR, 4);

  41.         //使能 pll4 时钟
  42.         *rcc_pll4cr |= (1 << 0);
  43.         while((*rcc_pll4cr & (1 << 1)) == 0);

  44.         printk("%s PLL4 clock ready!!\n", __func__);

  45.         //使能 gpioI gpioF 时钟
  46.         *rcc_mp_ahb4ensetr |= (1 << 8);
  47.         *rcc_mp_ahb4ensetr |= (1 << 5);

  48.         //设置为 gpio 引脚输出模式,这一步包含了引脚复用的设置
  49.         //GPIOI_0   GPIOF_3
  50.         *gpioi_moder &= ~(3 << 0);
  51.         *gpioi_moder |= (1 << 0);
  52.         *gpiof_moder &= ~(3 << 6);
  53.         *gpiof_moder |= (1 << 6);

  54. }

  55. static void led0_on(void)
  56. {
  57.         *gpioi_bsrr |= (1 << 16);
  58. }

  59. static void led0_off(void)
  60. {
  61.         *gpioi_bsrr |= (1 << 0);
  62. }

  63. static void led0_twinkle(void)
  64. {
  65.         while(1) {
  66.                 led0_on();
  67.                 msleep(1000);
  68.                 led0_off();
  69.                 msleep(1000);
  70.         }
  71. }

  72. static void gpio_uninit(void)
  73. {
  74.         return ;
  75. }

  76. static int __init led_init(void)
  77. {
  78.         gpio_init();
  79.         led0_twinkle();
  80.         return 0;
  81. }

  82. static void __exit led_exit(void)
  83. {
  84.         return ;
  85. }

  86. module_init(led_init);
  87. module_exit(led_exit);

  88. MODULE_LICENSE("GPL");
复制代码
Makefile
  1. KERN_DIR = /home/liu/work/projects/atk_stm32MP157/kernel

  2. CROSS_COMPILE = /home/liu/bin/arm/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-

  3. my_led-y := led.o
  4. obj-m += my_led.o

  5. all:
  6.         make -C $(KERN_DIR) M=`pwd` modules

  7. clean:
  8.         make -C $(KERN_DIR) M=`pwd` modules clean
  9.         rm -rf modules.order
复制代码


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

91

帖子

0

精华

高级会员

Rank: 4

积分
790
金钱
790
注册时间
2020-7-30
在线时间
117 小时
发表于 2021-1-5 11:51:40 | 显示全部楼层
stm32mp157.dtsi  打错了是 stm32mp157d-atk.dtsi
神一样的少年
回复 支持 反对

使用道具 举报

4

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
199
金钱
199
注册时间
2016-1-27
在线时间
18 小时
 楼主| 发表于 2021-1-5 22:02:51 | 显示全部楼层
lclinux 发表于 2021-1-5 11:51
stm32mp157.dtsi  打错了是 stm32mp157d-atk.dtsi

感谢指出,确实是 stm32mp157d-atk.dtsi
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-10 20:28

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表