15.【NXP 号令者RT1052】开发——实战-XBAR

15.【NXP 号令者RT1052】开发------实战-XBAR

上一章,我们介绍了如何使用 RT1052 的四定时器 QTMR4 的通道 3 来产生 PWM 输出,不过由于该 PWM 的输出脚,不在 LED 脚上,所以需要一根杜邦线来飞线。本章,我们介绍RT1052 的内部外设交错开关(XBAR),并通过其来将 QTMR4 通道 3 的 PWM 输出和 DS0 所在的 IO 口在芯片内部连接起来,这样我们就不需要使用杜邦线了。

15.1 XBAR 简介

XBAR 是 RT1052 芯片自带的内部外设交错开关矩阵,它可以将 RT1052 内部外设的输出(或 IO 口的输入)映射到另外一部分内部外设的输入(或 IO 口的输出)上,从而实现各种外设和 IO 之间的交错互联。

RT1052 内部总共有 3 个外设交错开关矩阵:XBAR1、XBAR2 和 XBAR3。其中,XBAR1(也称 XBARA1)有 88 路输入,132 路输出;XBAR2(也称 XBARB2)有 64 路输入(只有 58路有效),16 路输出;XBAR3(也称 XBARB3)同样有 64 路输入(只有 58 路有效),16 路输出。

从图中可以看出,XBAR 分为:XBAR1、XBAR2 和 XBAR3,其中 XBAR2 和 XBAR3 的输出经过 AOI1 和 AOI2 后,进入 XBAR1,最终才输出到各个外设/GPIO。因此,XBAR2 和XBAR3 必须搭配 AOI1 和 AOI2 以及 XBAR1 才可以正常使用。这里 AOI1 和 AOI2 是 RT1052内部的两个与或非模块,可以对 XBAR2 和 XBAR3 的输出做与或非处理后,输入到 XBAR1 的输入,再输出到各个外设和 GPIO。

图中,左侧信号是 XBAR 的输入信号,右侧是 XBAR 的输出信号。在图中列出来的这些外设就可以使用 XBAR 来做交错连接,比如:QTIM4 我们就可以使用 XBAR 来交错连接,从而改变 QTIM4 通道 3 的 PWM 输出 IO 口

图中 XBAR_Inn(n=0~N-1)代表 XBAR 的 N 路输入信号,XBAR_OUTm(m=0~M-1)代表 XBAR 的 M 路输出信号;MUX 是复用选择器,用于在 N 路输入里面选 1 路,由 SELm 寄存器控制;CTRLm 则控制 XBAR_OUTm 的触发边沿以及中断/DMA 设置。注意,中断/DMA触发仅 XBAROUT0~ XBAROUT3 支持,其他输出通道不支持!

该表描述了 XBAR1_Inn(n=0~87)的 88 个输入通道所对应的输入信号源(指定输入),不过上表我们只列出了一部分内容,完整的映射关系,见《RT1050 参考手册》第 239 页 3.4 节,Table 3-3。如表所示:QTMR4 通道 3 的输出,就被指定在 XBAR1_IN39 上,如果我们设置 SELx选择 XBAR1 输入通道 39(XBAR1_IN39)其实就是选择 QTMR4 通道 3 的输出作为 XBAR1 的输入。

该表描述了 XBAR1_OUTm(m=0~131)的 132 个输出通道所对应的目标信号(指定输出),不过上表我们也只列出了一部分内容,完整的映射关系,见《RT1050 参考手册》第 246 页 3.3节,Table 3-6。如表所示:XBAR1_OUT17 就被指定到 IOMUX_XBAR_INOUT17 上。这里的 IOMUX_XBAR_INOUT17 是指 XBAR 的输入/输出通道 17(二选一),它可以通过IOMUX 的设置,映射到 XBAR1_INOUT17 复用功能上,最终使用:GPIO1_IO03、GPIO1_IO05、GPIO2_IO19 和 GPIO4_IO08 等(由 IOMUX 设置)作为 XBAR 的输入/输出使用。经过以上了解,我们可以得出 XBAR1 的特点如下:

  1. 支持 88 路输入和 132 路输出;
  2. 任意一路输出都可以独立选择 88 路输入里面的任意一路;
  3. 支持边沿检测,并可以触发中断/DMA(仅前 4 个输出通道支持);
  4. 具有独立的选择设置寄存器(SELx/CTRLy,x=0~651,y=0/1);
    注 1:这里的 SELx 寄存器每个控制 2 路输入,所以总共只要 66 个寄存器,就可以设置 132 路
    输入。
    本章,我们将使用 XBAR1 来实现把 QTMR4 通道 3 的输出,映射到 DS0(GPIO1_IO03)上,从而 QTMR4 通道 3 的 PWM 输出可以直接驱动板载的 DS0,而不需要通过杜邦线连接。经过前面的学习,我们知道 QTMR4 通道 3 是连接在 XBAR1_IN39 上面的,而 GPIO1_IO03则可以复用成 XBAR1_INOUT17,因此,我们只需要将 XBAR1 输出通道 17 的输入选择设置为XBAR1_IN39 即可实现这个功能。
    本章,我们需要用到 2 个寄存器:XBARAx_SEL8 和 IOMUXC_GPR_GPR6,接下来我们分别介绍这两个寄存器。

实验目标

QTMR4 通道 3 的输出通过 XBARA1 路由到 XBAR1_INOUT17 ,再映射到 GPIO1_IO03 (DS0),实现 PWM 信号直接驱动 DS0,而无需杜邦线飞线。

配置步骤

1. 设置 GPIO1_IO03 复用功能

c

复制代码
//GPIO_AD_B0_03 配置为 ALT1,即 XBAR1_INOUT17
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_03_XBAR1_INOUT17,0);
2. 使能 XBARA1 时钟

c

复制代码
CLOCK_EnableClock(kCLOCK_Xbar1);

实际上 XBARA_Init() 内部已调用,无需重复。

3. 初始化 XBARA1

c

复制代码
XBARA_Init(XBARA1); //初始化 XBARA1
4. 设置 IOMUXC_GPR_GPR6
  • 配置寄存器 IOMUXC_GPR_GPR6,将 IOMUXC_XBAR_DIR_SEL_17 位置 1。
  • 设置 XBAR_INOUT17 为输出模式。

5. 设置 XBARA1 信号连接

使用 XBARA_SetSignalsConnectionQTMR4 通道 3 输出 连接到 XBAR1_INOUT17

c

复制代码
XBARA_SetSignalsConnection(XBARA1, 
                           kXBARA1_InputQtimer4Tmr3Output,
                           kXBARA1_OutputIomuxXbarInout17);

参数说明

  • 输入信号枚举 (xbar_input_signal_t)
    • 包含 XBAR1、XBAR2、XBAR3 的输入通道定义,共 204 个通道。
    • 本例选择 kXBARA1_InputQtimer4Tmr3Output,即 QTMR4 通道 3 的输出。
  • 输出信号枚举 (xbar_output_signal_t)
    • 包含 XBAR1、XBAR2、XBAR3 的输出通道定义,共 163 个通道。
    • 本例选择 kXBARA1_OutputIomuxXbarInout17,即输出到 XBAR1_INOUT17。
      本例程我们要操作的是XBARA1。第二个参数看名字就知道是设置要连接的输入信号,参数类型为 xbar_input_signal_t,
      这是一个枚举类型,在文件 MIMXRT1052.h 中有如下定义:

输入信号枚举 (xbar_input_signal_t)

c 复制代码
typedef enum _xbar_input_signal
{
    kXBARA1_InputLogicLow = 0|0x100U,   // LOGIC_LOW → XBARA1_IN0
    kXBARA1_InputLogicHigh = 1|0x100U,  // LOGIC_HIGH → XBARA1_IN1
    kXBARA1_InputIomuxXbarIn02 = 2|0x100U, // IOMUX_XBAR_IN02 → XBARA1_IN2
    ...
    kXBARA1_InputAdcEtcXbar1Coco2 = 86|0x100U, // ADC_ETC_XBAR1_COCO2 → XBARA1_IN86
    kXBARA1_InputAdcEtcXbar1Coco3 = 87|0x100U, // ADC_ETC_XBAR1_COCO3 → XBARA1_IN87

    kXBARB2_InputLogicLow = 0|0x200U,   // LOGIC_LOW → XBARB2_IN0
    kXBARB2_InputLogicHigh = 1|0x200U,  // LOGIC_HIGH → XBARB2_IN1
    kXBARB2_InputRESERVED2 = 2|0x200U,  // 保留
    ...
    kXBARB2_InputDmaDone6 = 56|0x200U,  // DMA_DONE6 → XBARB2_IN56
    kXBARB2_InputDmaDone7 = 57|0x200U,  // DMA_DONE7 → XBARB2_IN57

    kXBARB3_InputLogicLow = 0|0x300U,   // LOGIC_LOW → XBARB3_IN0
    kXBARB3_InputLogicHigh = 1|0x300U,  // LOGIC_HIGH → XBARB3_IN1
    kXBARB3_InputRESERVED2 = 2|0x300U,  // 保留
    ...
    kXBARB3_InputDmaDone6 = 56|0x300U,  // DMA_DONE6 → XBARB3_IN56
    kXBARB3_InputDmaDone7 = 57|0x300U   // DMA_DONE7 → XBARB3_IN57
} xbar_input_signal_t;
  • 通道数量
    • XBARA1:0 ~ 87,共 88 个输入通道
    • XBARA2:0 ~ 57,共 58 个输入通道
    • XBARA3:0 ~ 57,共 58 个输入通道
    • 总计 204 个输入通道
  • 示例
c 复制代码
kXBARA1_InputLogicHigh = 1|0x100U; // LOGIC_HIGH → XBARA1_IN1

表示 XBARA1 的输入通道 1(XBARA1_IN1),信号源为逻辑高电平。

  • 本例程选择
c 复制代码
kXBARA1_InputQtimer4Tmr3Output

QTMR4 通道 3 的输出作为 XBARA1 的输入信号。


输出信号枚举 (xbar_output_signal_t)

c 复制代码
typedef enum _xbar_output_signal
{
    //XBARA1_OUT0 → DMA_CH_MUX_REQ30
    kXBARA1_OutputDmaChMuxReq30 = 0|0x100U,
    //XBARA1_OUT1 → DMA_CH_MUX_REQ31
    kXBARA1_OutputDmaChMuxReq31 = 1|0x100U,
    //XBARA1_OUT2 → DMA_CH_MUX_REQ94
    kXBARA1_OutputDmaChMuxReq94 = 2|0x100U,
    ... //省略部分定义

    //XBARA1_OUT129 → FLEXIO2_TRIGGER_IN0
    kXBARA1_OutputFlexio2TriggerIn0 = 129|0x100U,
    //XBARA1_OUT130 → FLEXIO2_TRIGGER_IN1
    kXBARA1_OutputFlexio2TriggerIn1 = 130|0x100U,

    kXBARB2_OutputAoi1In00 = 0|0x200U, //XBARB2_OUT0 AOI1_IN00
    kXBARB2_OutputAoi1In01 = 1|0x200U, //XBARB2_OUT1 AOI1_IN01
    ... //省略部分定义
    kXBARB2_OutputAoi1In14 = 14|0x200U, //XBARB2_OUT14 AOI1_IN14
    kXBARB2_OutputAoi1In15 = 15|0x200U, //XBARB2_OUT15 AOI1_IN15

    kXBARB3_OutputAoi2In00 = 0|0x300U, //XBARB3_OUT0 AOI2_IN00
    kXBARB3_OutputAoi2In01 = 1|0x300U, //XBARB3_OUT1 AOI2_IN01
    ... //省略部分定义
    kXBARB3_OutputAoi2In14 = 14|0x300U, //XBARB3_OUT14 AOI2_IN14
    kXBARB3_OutputAoi2In15 = 15|0x300U  //XBARB3_OUT15 AOI2_IN15
} xbar_output_signal_t;
  • 通道数量
    • XBARA1:0 ~ 130,共 131 个输出通道
    • XBARA2:0 ~ 15,共 16 个输出通道
    • XBARA3:0 ~ 15,共 16 个输出通道
    • 总计 163 个输出通道
  • 示例
c 复制代码
kXBARA1_OutputFlexio2TriggerIn0 = 129|0x100U;

表示 XBARA1 的输出通道 129(XBARA1_OUT129),将输出到 FLEXIO2_TRIGGER_IN0。

  • 本例程选择
c 复制代码
kXBARA1_OutputIomuxXbarInout17

即输出到 XBAR1_INOUT17


信号连接代码

c 复制代码
XBARA_SetSignalsConnection(XBARA1, 
                           kXBARA1_InputQtimer4Tmr3Output,
                           kXBARA1_OutputIomuxXbarInout17);

15.2 硬件设计

本实验用到的硬件资源有:

  1. 指示灯 DS0
  2. QTMR4 通道 3 定时器
    本章将通过 QTMR4 的通道 3 来控制 DS0 的亮灭,DS0 是连接到 GPIO1_IO03(P103)上的,这个前面已经有介绍了。而 QTMR4 通道 3 的输出默认是连接在 GPIO2_IO27(P227)上的。本来是需要一根杜邦线连接 GPIO2_IO27 和 GPIO1_IO03 的,但是经过我们 XBARA1 的配置,就可以把 QTMR4 通道 3 的输出直接映射到 GPIO1_IO03 上面了,不需要经过 GPIO2_IO27也无需使用杜邦线条线。

15.3 软件设计

本章,我们依旧是在前一章的基础上修改代码,先打开之前的工程,然后在 HARDWARE文件夹下新建 XBAR 文件夹。然后打开 USER 文件夹下的工程,新建一个 xbar.c 的文件和 xbar.h的头文件,保存在 XBAR 文件夹下,并将 XBAR 文件夹加入头文件包含路径
xbar.c

c 复制代码
#include "xbar.h"
#include "lpuart.h"

//设置XBARA1的信号连接关系
//input: XBARA_INn选择,低8位有效,范围:0~87,参见xbar_input_signal_t的枚举值.
//output: XBARA_OUTx编号,低8位有效,范围:0~130, 参见xbar_output_signal_t的枚举值.
//详细的对应表,见:<<RT1052英文参考手册>>Table 3-5 和 Table 3-6
void XBARA1_Signal_Set(xbar_input_signal_t input, xbar_output_signal_t output)
{
	u8 outx;
  
	outx=output&0XFF;									//得到真正的XBARA_OUT编号. 
	if(outx>3&&outx<20)IOMUXC_GPR->GPR6|=1<<(12+outx);	//GPIO做输出,则设置对应的I0为输出模式

    XBARA_Init(XBARA1);                                 //初始化XBARA1
    XBARA_SetSignalsConnection(XBARA1,input,output);    //设置输入和输出连接
}

XBARA1_Signal_Set 函数,用于设置 XBAR1 的信号连接关系(映射关系),实际上就是设置 IOMUXC_GPR->GPR6 和 XBARA1->SELx 寄存器,该函数支持任意 XBARA1 通道的配置。
xbar.h

c 复制代码
#ifndef _XBAR_H
#define _XBAR_H
#include "sys.h"

void XBARA1_Signal_Set(xbar_input_signal_t input, xbar_output_signal_t output);
#endif

main.c

c 复制代码
#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdog.h"
#include "rtwdog.h"
#include "gptimer.h"
#include "pitimer.h"
#include "qtimer.h"
#include "pwm.h"
#include "xbar.h"

int main(void)
{
    u8 key=0;
	MPU_Memory_Protection();    //初始化MPU
	RT1052_Clock_Init();	    //配置系统时钟
	DELAY_Init(600);		    //延时函数初始化
	LPUART1_Init(115200);       //初始化串口1
    RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4
#ifdef LED_DEBUG
	u8 led0sta=1,led1sta=1;     //LED0,LED1的当前状态
	LED_Init();				    //初始化LED
#endif
#ifdef KEY_DEBUG
	KEY_Init();                 //初始化KEY
#endif
#ifdef LPUART_DEBUG
    u8 len;					//接收数据长度
    u16 times=0;            //延时计数器
    LED0(0);					//先点亮红灯 
#endif
#ifdef EXTIX_DEBUG
    EXTIX_Init();			    //初始化外部中断
#endif
#ifdef WDOG_DEBUG
    WDOG1_Init(3,2);		    //初始化看门狗1,2秒溢出,提前1秒进入中断,方便喂狗
	LED0(0);               	    //先点亮LED灯
    delay_ms(300);				//延时300ms再初始化看门狗,LED0的变化"可见"
#endif
#ifdef RTWDOG_DEBUG
    LED_Init();				    //初始化LED 
    KEY_Init();                 //初始化KEY
    delay_ms(100);         	    //延时100ms再初始化看门狗,LED0的变化"可见"
	MYRTWDOG_Init(1,0,32768,0);	//初始化RT看门狗,1秒溢出,非窗口模式
	LED0(0);               	    //先点亮LED灯
#endif
#ifdef GPT1_DEBUG
    LED_Init();				    //初始化LED  
    KEY_Init();                 //初始化按键
	GPT1_Int_Init(3750-1,10000); //设置GPT1 0.5秒钟产生一次中断
#endif
#ifdef PIT_DEBUG
    LED_Init();				    //初始化LED  
	PIT_CH0_Int_Init(75000000/2);	//设置PIT 0.5秒钟产生一次中断
#endif
#ifdef QTMR_DEBUG
    KEY_Init();                 //初始化按键
	LED_Init();				            //初始化LED
	QTMR1_CH0_Int_Init(15,46875);	//设置QTMR1 0.04秒钟产生一次中断
#endif
#ifdef QTMR_PWM_DEBUG
    u8 dir=1; 
	u16 led1pwmval=0;    
    gpio_pin_config_t led_config;

    LED_Init();				    //初始化LED  
    KEY_Init();                 //初始化按键
    
    //初始化PWM,定时器时钟为:150/64=2.34375Mhz,设置频率为5Khz,50%占空比
	QTMR4_CH3_PWM_Init(14,5000,0);

    //设置P103为输入模式,防止干扰PWM
    led_config.direction=kGPIO_DigitalInput;	//输出
	led_config.interruptMode=kGPIO_NoIntmode;	//不使用中断功能
	led_config.outputLogic=0;					//默认高电平,LED灯关闭
	GPIO_PinInit(GPIO1,3,&led_config); 	        //初始化GPIO1_3
#endif
    u8 dir=1; 
	u16 led1pwmval=0;  
    
    //初始化PWM,定时器时钟为:150/64=2.34375Mhz,设置频率为5Khz,50%占空比
	QTMR4_CH3_PWM_Init(14,5000,50); 
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_03_XBAR1_INOUT17,0);	//GPIO_AD_B0_03配置为ALT1,即XBAR1_INOUT17
    XBARA1_Signal_Set(kXBARA1_InputQtimer4Tmr3Output,kXBARA1_OutputIomuxXbarInout17);   //QTMR4_CH3输出到XBARA1_INOUT17上面.
                                                                                        //即:通过GPIO_AD_B0_03(GPIO1_IO03)输出QMR4_CH3的波形.
    while(1)
    {
        delay_ms(10);	 
		if(dir)led1pwmval++;
		else led1pwmval--;	 
        if(led1pwmval>=100)dir=0;
		if(led1pwmval==0)dir=1;	 
        QTMER4CH3_PWM_DutySet(14,5000,led1pwmval);
#ifdef QTMR_PWM_DEBUG
        delay_ms(10);	 
		if(dir)led1pwmval++;
		else led1pwmval--;	 
        if(led1pwmval>=100)dir=0;
		if(led1pwmval==0)dir=1;	 
        QTMER4CH3_PWM_DutySet(14,5000,led1pwmval);
#endif
#ifdef QTMR_DEBUG
        LED0_Toggle;
		delay_ms(1000);
#endif
#ifdef PIT_DEBUG
        LED0_Toggle;
		delay_ms(1000);
#endif
#ifdef GPT1_DEBUG
        LED0_Toggle;
		delay_ms(1000);
#endif
#ifdef RTWDOG_DEBUG
        key=KEY_Scan(0);
		if(key==WKUP_PRES)		//如果按键按下,则喂狗.
		{
			RTWDOG_Feed();
		} 
		delay_ms(10);
#endif
#ifdef WDOG_DEBUG
        LED0(1);				//关闭DS0,如不复位,DS0将一直处于关闭状态.
		delay_ms(100);
#endif
#ifdef EXTIX_DEBUG
        printf("Int example driver!\r\n");
		delay_ms(1000);
#endif
#ifdef KEY_DEBUG
        key=KEY_Scan(0); 		    //得到键值
        if(key)
        {	
            switch(key)
            {				 
                case WKUP_PRES:	//控制LED0,LED1互斥点亮
                    led1sta=!led1sta;
                    led0sta=!led1sta;
                    break;
                case KEY2_PRES:	//控制LED0翻转
                    led0sta=!led0sta;
                    break;
                case KEY1_PRES:	//控制LED1翻转	 
                    led1sta=!led1sta;
                    break;
                case KEY0_PRES:	//同时控制LED0,LED1翻转 
                    led0sta=!led0sta;
                    led1sta=!led1sta;
                    break;
            }
            LED0(led0sta);		//控制LED0状态
            LED1(led1sta);		//控制LED1状态
        }else delay_ms(10);
#endif // KEY_DEBUG
#ifdef LPUART_DEBUG
        if(LPUART_RX_STA&0x8000)
		{					   
			len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n发送的消息为:\r\n");
			LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据
			printf("\r\n\r\n");//插入换行
			LPUART_RX_STA=0;
		}else
		{
			times++;
			if(times%5000==0)
			{
				printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
			if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		}
#endif // LPUART_DEBUG
	}
}

编译,下载,结果与上一章结果相同。

总结

XBAR 的实现与传统杜邦线连接相比,最大的区别在于信号的传输方式:使用杜邦线时,QTMR4 通道 3 的 PWM 输出需要通过外部飞线物理连接到 DS0 所在的 GPIO 引脚,容易造成布线复杂、可靠性下降;而通过 XBAR 配置,可以在芯片内部直接将 QTMR4 通道 3 的输出映射到 GPIO1_IO03,实现 PWM 信号的内部路由,无需额外硬件连接,既简化了电路,又提升了稳定性和可维护性。因此,XBAR 的优势在于 内部互联、灵活映射、减少外部连线 ,而杜邦线方式则是 物理跳线、依赖外部连接

OK!谢谢大家!

相关推荐
xiaohai@Linux2 小时前
STM32上使用HAL库完美实现驱动MAX98357声卡模块(I2S+DMA+音频环形缓冲区)
stm32·单片机·嵌入式硬件·音视频
思茂信息2 小时前
CST License(Flexnet)设置与问题处理方法
服务器·网络·单片机·3d·php·1024程序员节·cst
C.咖.3 小时前
STM32—— 嵌入式微控制器入门
stm32·单片机·嵌入式硬件
兆龙电子单片机设计3 小时前
【STM32项目开源】STM32单片机物联网门禁控制系统
stm32·单片机·物联网·开源·自动化
云雾J视界4 小时前
C语言位运算深度应用:嵌入式硬件寄存器控制与低功耗优化实践
c语言·stm32·嵌入式硬件·低功耗·数据压缩·寄存器
芋头莎莎4 小时前
MCU单片机驱动WS2812,点亮RGB灯带各种效果
单片机·嵌入式硬件
无垠的广袤6 小时前
【CPKCOR-RA8D1】Home Assistant 物联网 ADC 电压温度计
嵌入式硬件·物联网·智能家居·瑞萨
诸葛务农6 小时前
光电对抗分类及外场静爆试验操作规程
人工智能·嵌入式硬件·分类·数据挖掘
点灯小铭10 小时前
基于单片机的多波形信号发生器设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业