雷竞技注册
项目

DMA数字到模拟转换与SAM4S微控制器:计时器/计数器

2016年4月28日经过罗伯特·凯

本三篇文章系列中的一部分专注于使用SAM4S定时器/计数器外围设备精确控制DAC的采样率。

本三篇文章系列中的一部分专注于使用SAM4S定时器/计数器外围设备精确控制DAC的采样率。

支持信息

必需的硬件/软件

一个真正的DAC.

如果你读了我最近的一篇文章其中我分析了基于脉冲宽度调制的数模转换器的性能,您知道PWM DAC远非令人印象深刻。但是,PWM DAC部分地存在(如上所述)另一篇文章在同一主题上)许多微控制器不包含专用的DAC硬件。这种相对普遍的“缺乏DAC” - along,我一般不愿意使设计与外部组件复杂化,如果IC制造商能够如此善良,那么制定微控制器的方式是我想要的方式 - 解释我的良好时发现自己使用的微控制器确实有一个真正的DAC。此满意度与SAM4S系列设备达到了新的高度,其提供不是一个而不是两个数字控制的模拟输出。

本项目的目标是使用SAM4S DAC模块生成正弦波。由于SAM4S数据表、Atmel软件框架(ASF)、ASF文档和微控制器的实际硬件之间有些复杂的关系,单是这个任务就足够重要了。尽管如此,我们将进一步通过直接内存访问(DMA)而不是CPU指令向DAC提供数据。我们将在第3部分中更多地讨论DMA。

虽然我喜欢在我的示波器上看着正弦波,但这个项目并不是真的一直在结束。相反,它是一个用于探索重要的SAM4S能力的车辆,即精确定时/计数,DMA和集成的数字到模拟转换;2)对于需要同步,CPU高效的数字到模拟转换的其他项目的基础,例如合成音频信号或为软件定义的无线电产生基带波形。

自由运行与触发

只需将值写入DAC的转换数据寄存器即可使用DAC即可使用DAC。这被称为自由运行模式。在编写数据时立即更新模拟输出电压(实际上,25个DAC时钟滴答声您可以在第2部分中的DAC硬件详细信息上写入数据。对于某些应用,这很好,但是为了精确合成周期性信号(例如正弦曲线),我们需要确保所有输出电压更新都通过相同的间隔分开。为此,我们将使用触发模式,其中写入转换数据寄存器实际上没有修改输出电压,直到DAC硬件被单独的定时信号触发。这SAM4S数据表(第1124页)将这个触发器称为“外部”,这有点误导——在我的经验中“外部”通常意味着“芯片外部”,而在这种情况下,它意味着“DAC模块外部”。以下是触发信号选项:

我们将使用来自定时器/计数器通道1的TIO信号,因为我们可以通过标记为“PIED接口”的贯通通孔中的端子1方便地探测该信号:

如图所示,这个端子1连接到引脚A15, SAM4S datasheet (page 52)告诉我们,我们可以通过连接这个引脚到外设B来驱动信号TIOA1在PA15上:

TIO后的“A”表示这是每个计时器/计数器通道可以产生的两个输出信号(TIOA和TIOB)中的第一个;“TIOA”后的“1”指的是定时器/计数器模块的通道1,它包括三个相同的,独立的通道。

波形和捕捉

可以为波形模式或捕获模式配置定时器/计数器通道。在捕获模式下,TiOA和TiOB是输入;连接到TiOA或TIOB的信号可用于告诉定时器/计数器硬件将当前计数器值存储在单独的寄存器中。该功能对于测量脉冲宽度或两个脉冲之间的延迟非常有用。但是,我们想要产生定时信号,不测量一个,所以我们需要波形模式。此名称反映了定时器/计数器通过三个比较寄存器和不同的计数模式生成各种数字波形的能力。我们的任务非常简单,但我们只需要一个平方波,频率等于我们所需的DAC采样率。因此,我们可以使用Up-Counting的模式,并且我们只需要一个比较寄存器。

首先要做的是选择将驱动计数器寄存器的时钟。以下是一些选项:

我们将配置单片机为96 MHz的主时钟(MCK)频率;原因将在第2部分中解释。所需的DAC采样率是1 MHz,而MCK/8(即12 MHz)是生成1 MHz DAC触发器的良好选择,因为所需的分频值是一个整数。

既然我们知道计数器时钟源的频率,我们需要选择“寄存器C”的适当值缩写RC。如下:如下:,这将用于在达到RC中保持的值时重置计数器,如下所示:

因此,如果我们设置“TC通道模式”寄存器的WAVESEL位为二进制10,然后加载适当的比较值到RC,我们将有一个计数器,当计数器的值等于RC时,它会重置并开始从0开始计数。剩下的唯一事情是告诉计时器/计数器通道在每次匹配发生时修改TIOA的逻辑级别。我们通过通道模式寄存器中的ACPC字段来做到这一点:

我们将使用toggle选项。下图传达了RC比较值和TIOA上产生的波形之间的关系。

固件

现在是时候将所有这些定时器/计数器业务翻译成代码,并且为此,我们将(像往常一样)转向ASF。首先,让我们添加所有项目所需的所有ASF模块:

绿色下划线的模块是您需要添加的模块(其他)由Atmel Studio自动包含)。

接下来我们有两个预处理器定义:

//端口I / O #define TC0_TIOA_CH1 Ioport_create_pin(PIOA,15)//定时器配置#define TC0_CHANNEL1 1

第一种方法将一个名称附加到pin A15,第二种方法允许我们使用TC0_CHANNEL1来引用计时器/计数器通道1,而不是包含较少信息的数字1。

接下来,我们需要为定时器/计数器启用外围时钟。这里有一个细节我认为很困惑,所以请注意以下讨论 - 它可能有助于您有一天避免挫败一点。这些混淆涉及与PMC_Enable_PeriPH_CLK()函数一起使用的外围ID的问题。在我看来,显而易见的答案是id_tc0,因为我们正在使用频道1定时器/计数器模块0。此现实反映在定时器/计数器频道 - 初始化函数中,TC_INIT() - 第一参数是TC0或TC1(参考定时器/计数器模块0或模块1),第二参数是频道号。似乎只是自然的外围ID应该对应于外围模块本身,而不是到某个通道模块。但你可能已经猜到了,事实并非如此。事实证明,外围时钟为单个计时器通道启用或禁用。雪上加霜,SAM4S datasheet (page 50)指明这些通道如下:

因此,对于外围标识符,我们具有定时器/计数器通道0到5,而我们有定时器/计数器模块0.通道0到2和定时器/计数器模块1通道0到2。无论如何,请注意您必须为您正在使用的每个计时器/计数器通道启用外围时钟,外围ID通道0 - 2对应模块0通道0 - 2,外围ID通道3-5对应模块1通道0 - 2。

通过pmc_enable_peri_clk (ID_TC1)启用外围时钟后,我们配置计时器/计数器通道:

tc_init(TC0, TC0_CHANNEL1, TC_CMR_TCCLKS_TIMER_CLOCK2 //MCK/8 | TC_CMR_WAVE //波形模式| TC_CMR_WAVSEL_UP_RC //count up, reset on RC match | TC_CMR_ACPC_TOGGLE //toggle TIOA on RC match);

使用TC_INIT()函数,首先指定模块中的定时器/计数器模块和频道,然后使用逻辑或运算符以及ASF预处理器定义(在TC.H“中找到)以指定适当的值需要在频道模式寄存器中修改字段。如上面代码摘录中的评论所示,我们正在配置频道

  1. MCK / 8个时钟源,
  2. 波形模式,
  3. 当计数器值等于RC时,唯一只有自动复位的模式,并且
  4. 当计数器值等于RC时,Tioo切换。

从上图来看,我们知道RC中的值应该是6产生1 MHz时钟:

\ [f_ {tioa} = \ frac {12 \ mhz} {2 \ times rc} \ \ \ lightarrow \ \ rc = \ frac {12 \ mhz} {2 \ time1 \ mhz} = 6 \]

tc_write_rc (TC0 TC0_CHANNEL1 6);

现在我们需要做的就是将定时器/计数器通道启用到TC_START()的调用:

tc_start(tc0,tc0_channel1);

结果与结论

您可以使用以下链接下载项目阶段的源和项目文件:

dma_dac_sinewave_part1.zip.

这是一个结果波形的范围捕获:

现在我们有了我们想要的采样速率信号,我们准备好启动DAC了。在下一篇文章中,我们将探讨SAM4S DAC控制器(DAC)外设、DAC本身的电气特性,以及ASF的DAC模块。

下一篇文章:

为自己提供这个项目!得到bom。

2评论
  • Ben Nguyen 1. 2018年1月31日

    是TIOA计数器重新加载的映射,
    pmc_enable_periph_clk(id_tc1);
    pio_configure_pin(tc0_tioa_ch1,pio_type_pio_periph_b);

    只作为调试测试点?即,dac需要这个pio映射,以便在dma传输之间暂停?

    喜欢的。 回复
    • RK37. 2018年1月31日
      自从我写这篇文章已经有一段时间了,我不记得固件细节很好。但是,我认为你是正确的:定时器重新加载仅被路由到端口引脚,因为我希望能够探测采样率信号。
      喜欢的。 回复