ZYNQ-PS端TTC多路PWM_EMIO输出
1.简介
主要根据赛灵思官方手册
每个 Cortex-A9 处理器都有自己的私有 32 位定时器和 32 位看门狗定时器。 两个处理器共享一个全局 64 位定时器。 这些定时器的时钟频率始终为 CPU 频率的 1/2(CPU_3x2x)。
在系统层面,有一个 24 位看门狗定时器和两个 16 位三重定时器/计数器。 系统看门狗定时器的时钟频率为 CPU 频率 (CPU_1x) 的 1/4 或 1/6,或者可以由来自 MIO 引脚或 PL 的外部信号。 两个三重定时器/计数器始终计时CPU 频率 (CPU_1x) 的 1/4 或 1/6,用于计算来自一个 MIO 引脚或来自 PL。
可以看出能够有外部管脚输出的只有TTC和SWDT,输出PWM的话只能使用TTC来输出了。TTC 包含三个独立的定时器/计数器。 PS中有两个TTC模块,一共有六个定时器。
每个三重计时器计数器具有:
- 三个独立的 16 位预分频器和 16 位加/减计数器
- 可选择的时钟输入来自:
° 内部 PS 总线时钟 (CPU_1x)
° 内部时钟(来自 PL)
° 外部时钟(来自 MIO)- 三个中断,每个计数器一个
- 溢出中断、定期中断或计数器匹配可编程值
- 通过 MIO 和 PL 生成波形输出(例如,PWM)
每个预分频器模块可以独立编程以使用 PS 内部总线时钟 (CPU_1x),或来自 MIO 或 PL 的外部时钟。 对于外部时钟,SLCR 寄存器通过 MIO 或 PL 确定准确的引脚分配。 然后将所选时钟从 /2 分频到 /65536,然后再应用于计数器。
计数器模块可以向上计数或向下计数,并且可以配置为在给定的时间间隔内计数。 它还将三个匹配寄存器与计数器值进行比较,如果一个匹配,则产生中断。
中断模块结合了各种类型的中断:计数器间隔、计数器匹配、计数器溢出、事件定时器溢出。 每种类型都可以单独启用。
每个计数器模块都可以独立编程以在以下两种中的任何一种中运行模式:
间隔模式:计数器在 0 和间隔寄存器的值之间连续递增或递减,计数方向由计数器控制寄存器的 DEC 位决定。 当计数器过零时产生一个间隔中断。 当计数器值等于匹配寄存器之一时,会产生相应的匹配中断。
溢出模式:计数器在 0 到 0xFFFF 之间连续递增或递减,计数方向由计数器控制寄存器的 DEC 位决定。 当计数器过零时产生溢出中断。 当计数器值等于匹配寄存器之一时,会产生相应的匹配中断。
2.代码
vivado配置
可以看到定时器的输入时钟
vitis中新建一个helloworld工程。
/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include <stdlib.h>
#include "xparameters.h"
#include "xstatus.h"
#include "xil_exception.h"
#include "xttcps.h"
#include "xscugic.h"
#include "xil_printf.h"
#define TTC_PWM0_DEVICE_ID XPAR_XTTCPS_0_DEVICE_ID
#define TTC_PWM1_DEVICE_ID XPAR_XTTCPS_1_DEVICE_ID
#define TTC_PWM2_DEVICE_ID XPAR_XTTCPS_2_DEVICE_ID
#define TTC_PWM3_DEVICE_ID XPAR_XTTCPS_3_DEVICE_ID
#define TTC_PWM4_DEVICE_ID XPAR_XTTCPS_4_DEVICE_ID
#define TTC_PWM5_DEVICE_ID XPAR_XTTCPS_5_DEVICE_ID
#define PWM_DELTA_DUTY 20
typedef struct {
u32 OutputHz; /* Output frequency */
XInterval Interval; /* Interval value */
u8 Prescaler; /* Prescaler value */
u16 Options; /* Option settings */
} TmrCntrSetup;
//----------------------------------------------------------------
TmrCntrSetup timer0_SettingsTable = {100, 0, 0, 0};
XTtcPs timer[6];
void setup_pwm_timer(XTtcPs *timer,int DeviceID,TmrCntrSetup *timerSetupMes);//setup_pwm_timer
int main()
{
init_platform();
print("Hello World\n\r");
setup_pwm_timer(&timer[0],TTC_PWM0_DEVICE_ID,&timer0_SettingsTable);
setup_pwm_timer(&timer[1],TTC_PWM1_DEVICE_ID,&timer0_SettingsTable);
setup_pwm_timer(&timer[2],TTC_PWM2_DEVICE_ID,&timer0_SettingsTable);
setup_pwm_timer(&timer[3],TTC_PWM3_DEVICE_ID,&timer0_SettingsTable);
setup_pwm_timer(&timer[4],TTC_PWM4_DEVICE_ID,&timer0_SettingsTable);
setup_pwm_timer(&timer[5],TTC_PWM5_DEVICE_ID,&timer0_SettingsTable);
for (int i = 0; i < 6; i++)
{
/* code */
XTtcPs_Start(&timer[i]);
}
cleanup_platform();
return 0;
}
void setup_pwm_timer(XTtcPs *timer,int DeviceID,TmrCntrSetup *timerSetupMes)
{
XTtcPs_Config *TTC_Config;
uint8_t DutyCycle = PWM_DELTA_DUTY;
uint32_t MatchValue = 0;
//look for config
TTC_Config = XTtcPs_LookupConfig(DeviceID);
//init
XTtcPs_CfgInitialize(timer, TTC_Config, TTC_Config->BaseAddress);
//set work mode
timerSetupMes->Options |= (XTTCPS_OPTION_INTERVAL_MODE |
XTTCPS_OPTION_MATCH_MODE | XTTCPS_OPTION_DECREMENT);
XTtcPs_SetOptions(timer,timerSetupMes->Options);
//calculate the value of Interval
XTtcPs_CalcIntervalFromFreq(timer, timerSetupMes->OutputHz,
&(timerSetupMes->Interval), &(timerSetupMes->Prescaler));
/*
* Set the interval and prescale
*/
XTtcPs_SetInterval(timer, timerSetupMes->Interval);
XTtcPs_SetPrescaler(timer, timerSetupMes->Prescaler);
//set the match value
MatchValue = (timerSetupMes->Interval * DutyCycle) / 100;
XTtcPs_SetMatchValue(timer, 0, MatchValue);
//XTtcPs_Start(timer);
}
编程的关键点在于定时器工作模式的选择,这里启用的是间隔模式,匹配模式,计数值递减模式。
定时器初始时钟输入之后经过预分频之后作用于计数器的递增或者递减,至少也要对时钟进行2分频(分频寄存器为0)。
间隔寄存器相当于是自动重装载的值,计数器在递减或者递增的时候不会到全为1,最高只能到间隔寄存器设置的值。
匹配寄存器相当于用来设置占空比,当计数器的值到达匹配寄存器的值,输出就会翻转,匹配寄存器最多可以配置3个。
注意配置计数器是递增递减和输出波形的极性。
3.结果
6路输出全部使能。使用逻辑分析仪观察结果。
设置的频率是100hz,实际测试的结果也是100hz。
工程已经上传