这是迷你系列的 第 4 部分 。在第 3 部分中,我描述了软件概念(请参阅“ 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 - 第 3 部分:概念 ”)。在这篇文章中,我描述了如何设置定时器来触发以后的 DMA 操作。目标是使用 Freescale FRDM-K64F 板驱动 Adafruit 的 NeoPixel (WS2812B):
带有 FRDM-K64F 的 NeoPixel
迷你系列教程列表
- 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 – 第 1 部分: 硬件
- 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板——第 2 部分: 软件工具
- 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板——第 3 部分: 概念
- 教程:Adafruit WS2812B NeoPixels 与 Freescale FRDM-K64F 板 – 第 4 部分: 定时器
- 教程: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 项目结构中。我需要将以下主要文件/文件夹添加到我的项目中:
- EDMA : SDK\平台\src\edma
- FTM : SDK\平台\驱动程序\ftm
- 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 请求。敬请期待……
快乐的时机 :-)
链接
- NeoPixels 上的 Adafruit 指南: https ://learn.adafruit.com/adafruit-neopixel-uberguide/overview
- Freescale Freedom FRDM-K64F 开发板: http://www.freescale.com/webapp/sps/site/prod_summary.jsp ?code=FRDM-K64F
- 飞思卡尔 Kinetis 设计工作室: http://www.freescale.com/kds
- 飞思卡尔 Kinetis SDK: http://www.freescale.com/kds
- K64 子系列参考手册 (K64P144M120SF5RM): http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K64P144M120SF5RM.pdf
- GitHub 上的项目: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_NeoPixel_SDK