Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

这是迷你系列的 第 4 部分 。在第 3 部分中,我描述了软件概念(请参阅“ 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 - 第 3 部分:概念 ”)。在这篇文章中,我描述了如何设置定时器来触发以后的 DMA 操作。目标是使用 Freescale FRDM-K64F 板驱动 Adafruit 的 NeoPixel (WS2812B):

带有 FRDM-K64F 的 NeoPixel

迷你系列教程列表

  1. 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 – 第 1 部分: 硬件
  2. 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板——第 2 部分: 软件工具
  3. 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板——第 3 部分: 概念
  4. 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 – 第 4 部分: 定时器
  5. 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 – 第 5 部分: DMA

大纲

在这篇文章中,我解释了如何使用 Kinetis 的 FTM (Flex Timer Module)生成 3 个波形,在之前的文章中解释过(参见“ 教程:Adafruit WS2812B NeoPixels with the Freescale FRDM-K64F Board – Part 3: Concepts ”) .为了能够验证波形,我将定时器配置为在 PWM 模式下切换外部引脚,以便我可以检查信号。我正在使用 Kinetis Design Studio V3.0.0 和 Kinetis SDK V1.2。

添加 Kinetis SDK 文件

虽然 DMA 将在下一篇文章中介绍,但我现在将所有必要的文件添加到项目中。我更喜欢将文件复制到我的项目中:将文件和文件夹从 SDK 安装复制到 Eclipse 项目结构中。我需要将以下主要文件/文件夹添加到我的项目中:

  1. EDMA : SDK\平台\src\edma
  2. FTM : SDK\平台\驱动程序\ftm
  3. GPIO : SDK\platform\drivers\gpio

:idea: GitHub 上有项目源/文件的链接。

SDK 主文件


事实上,由于 SDK 和所有 HAL(硬件抽象层)文件的复杂目录结构,还需要大量其他文件 :-( .

下图显示了所有必要的文件:

Kinetis SDK 文件


由于目录太多,我还需要将文件夹添加到编译器中,包括路径设置:-(:

:idea: 我希望将来SDK 只是一个源文件夹和一个头文件文件夹。

所以在项目设置中,我需要配置包含路径:

:idea: GitHub 上有项目源/文件的链接。

编译器包含路径


:idea: 另一个选择是使用 Processor Expert:Processor Expert 会知道需要哪些文件,并自动将它们添加到项目中并更新项目设置。但由于 Manya 不想使用 Processor Expert,事情现在变得更加困难。都是你的错,曼雅! ;-)

作为参考(您可以将这些行复制粘贴到项目设置中),这是我的包含路径:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"

:想法: 我正在使用项目相对(“../SDK/”路径,因为我想让我的项目独立于 Kinetis SDK 安装。

时钟和定时器配置

接下来是我需要添加到编译器预处理器设置中的两个定义:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"

预处理器定义


第一个在启动期间启用 60 MHz 外设/系统时钟,第二个告诉我不想也不需要操作系统意识层的计时器。

添加 DMAPixel 文件

是时候开始编码了 :-) 。我想将我所有的低级定时器和 DMA 内容存储到模块“ DMAPixel ”中。因此,我创建(使用文件夹上的上下文菜单,然后 新建 > 头文件 新建 > 源文件 DMAPixel.c DMAPixel.h 文件:

添加了 DMA 像素


现在的界面非常简单,只是一个初始化例程:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


现在的初始化例程如下所示:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


硬件初始化

我将使用 PTC1、PTC2 和 PTC3 作为定时器的切换/输出引脚。我必须使用 SIM_HAL_EnableClock() 为端口 C 的外围域计时。使用 InitFlexTimer() 可以初始化计时器(稍后会介绍)。最后,三个引脚需要复用:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


FTM 框图

下图为 K64F 的 FTM(Flex Timer Module):

FTM 框图


有一个选择时钟源的时钟选择(CLKS)。我将使用 60 MHz 系统时钟作为输入时钟,预分频器为 1。

为了获得 1.25 µs 的周期,我使用了定时器匹配值 0x4B:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"

通道的相应值是:

  • 通道 0:0x10
  • 通道 1:0x2A
  • 通道 2:0x40

我将在接下来的计时器初始化中使用这些值。

FTM 计时器初始化

以下函数初始化定时器。它使用 Kinetis SDK API 来初始化外设并对其进行配置。


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


:idea: 您可能会注意到我使用了 Kinetis SDK 的许多低级 HAL(硬件抽象层)API 调用,并且*没有*使用很多 SDK API。原因是 V1.2 中现有的 API 不允许在不启动它们的情况下配置三个通道,除此之外我还需要让它们与 DMA 一起工作的其他细节。

检查 FTM 寄存器

查看 FTM 寄存器值的一个好方法当然是阅读参考手册 :-) 。但另一个好方法是在 Eclipse 中使用寄存器查看器(请参阅“ 使用额外的 Freescale SVD 文件更新 Eclipse EmbSysReg 查看器 ”):

FTM 寄存器设置


:idea: 小心使用寄存器视图显示的内容,因为读取某些位和外围设备可能会产生副作用。我曾经读过太多的寄存器,导致 FTM 无法工作。关闭视图并重新打开它可以解决问题,如果您不记得正在阅读的寄存器。

运行 FTM 定时器

上面的代码只初始化了定时器。开始完成


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


实现如下:


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


所以它所做的只是为 FTM 计时或禁用它的计时。

从 main() 调用

为了测试我的计时器,我必须从 main() 中调用 DMA_Init():


 "../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"


测试定时器信号

因此,使用逻辑分析仪,我可以验证定时器通道是否正常运行:

使用逻辑分析仪探测信号


事实上,他们看起来不错 :-)

波形和时序


概括

在本文中,我使用 Kinetis SDK 和 Kinetis Design Studio 生成 3 个波形,使用 Kinetis FTM(灵活定时器模块)的 3 个通道。 Kinetis SDK 提供了很多驱动程序,但同时需要一个学习曲线。不幸的是,SDK 没有提供我所期望的功能,例如,FTM 无法正确初始化多个通道并运行它。这很容易通过 Manya 不想使用的 Processor Expert 实现,因此我最终不得不改用 HAL 宏和方法。这种 HAL 方法的好处是我可以轻松绕过 SDK 并更接近裸机。我仍然可以使用 SDK 功能作为灵感,但改用 HAL。至少对于这个对我有用的项目。不过,将 SDK 与 Processor Expert 一起使用要容易得多,因为它处理项目设置并将所有文件添加到项目中。

项目源码可以在 GitHub 上找到:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_NeoPixel_SDK

在下一篇文章中,我将解释如何从中触发 DMA 请求。敬请期待……

快乐的时机 :-)

链接

相关文章