teensy 4.0 XBAR questions

I was attempting to setup an XBAR (A1) "mapping" on my teensy 4.0 (input 40 to output 6) and discovered I cannot write to the XBARA1_SEL3 register.

i.e.: it remains 0 after writing a new value to it - and appears to not take effect either (but I can't be sure of that yet). I'm aware that other things need to be done to bring the signal out to a pin and I have code to do that, but I've not been able to test it since this step doesn't work. I've looked into whether the MPU setup might be causing this, and I don't think so.

Any clue?

I'm also curious why the imxrt.h file has entries for XBARA1_SEL0 through XBARA1_SEL29 followed by XBARA1_CTRL0. Per the reference manual for the 1062 there are 132 outputs from XBAR1 and thus 66 select registers (0 to 65) and thus the CTRL0 and CTRL1 registers are at the wrong offset. This is not relevant to the problem above right now since I do not need to use the CTRL registers to setup edge detection, DMA or interrupts.

I am using teensyduino 1.49 via make and the teensy tools on a host running ubuntu. I am not using the Arduino IDE, although I did start out using it until I learned that make "just works" (which is terrific BTW). Yes I know that 1.49 is not the latest.

I created the following simple code fragment to demonstrate the problem. It is inserted into the main.cpp file. Nothing more is needed to demonstrate the problem (I think I also attached the file to this post).

Code:
extern "C" int main(void)
{
#ifdef USING_MAKEFILE

	// To use Teensy 4.0 without Arduino, simply put your code here.
	// For example:

	pinMode(13, OUTPUT);
        int count = 0;
	while (1) {
                ++count;
		digitalWriteFast(13, HIGH);
		delay(100);
		digitalWriteFast(13, LOW);
                delay(100);

                // MY ADDITION
                Serial.print("count=");Serial.println(count);
                uint32_t addr = (uint32_t)&XBARA1_SEL3;
                uint16_t val = XBARA1_SEL3;
                Serial.print("&XBARA1_SEL3=0x"); Serial.println(addr, HEX);
                Serial.print("XBARA1_SEL3=0x"); Serial.println(val, HEX);
                if(count == 5) {
                  // map XBAR1 input 40 (FLEXPWM1_PWM1_OUT_TRIG0 | FLEXPWM1_PWM1_OUT_TRIG1)
                  // to XBAR1 output 6 (XBAR1_OUT06 = IOMUX_XBAR_INOUT06) by writing 40 to
                  // XBARA1_SEL3 (@ 0x403BC006)
                  XBARA1_SEL3 = 40;
                  Serial.println("executed: XBARA1_SEL3 = 40;");
                }
		delay(1000);
	}
#endif
}

Here is the output I get from this code:

Disconnect /dev/bus/usb/002/020
Opened /dev/ttyACM0 Serial
count=2
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
count=3
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
count=4
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
count=5
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
executed: XBARA1_SEL3 = 40;
count=6
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
count=7
&XBARA1_SEL3=0x403BC006
XBARA1_SEL3=0x0
Disconnect /dev/bus/usb/002/022
 

Attachments

  • main.cpp
    2.7 KB · Views: 82
For what it is worth. The few times I have played with the XBAR, I either copied or made external reference to the helper function that is currently in pwm.c


Code:
 void xbar_connect(unsigned int input, unsigned int output)
{
	if (input >= 88) return;
	if (output >= 132) return;
#if 1
	volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2);
	uint16_t val = *xbar;
	if (!(output & 1)) {
		val = (val & 0xFF00) | input;
	} else {
		val = (val & 0x00FF) | (input << 8);
	}
	*xbar = val;
#else
	// does not work, seems 8 bit access is not allowed
	volatile uint8_t *xbar = (volatile uint8_t *)XBARA1_SEL0;
	xbar[output] = input;
#endif
}
Note: there are symbolic names in the IMXRT header file for these different inputs and outputs
 
Thanks.

I'm using that in my actual code. I just simplified it for this posting. In fact I first discovered the problem using xbar_connect().
 
Yes - It appears that you can not do: xbar_connect(40, 6);
Or better with symbols: xbar_connect(XBARA1_IN_FLEXPWM1_PWM1_OUT_TRIG0, XBARA1_OUT_IOMUX_XBAR_INOUT06);

Again I have not used XBAR enough to know if that mapping makes sense or not.

BUT I think the main issue is you have not enable XBAR1_IO through the clocking, so it failed it.
When I added: CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);

The assignment appears to take

Also as you mentioned not all of the XBar Selects were defined here. So as you mentioned the ctrl0 and ctrl1 will be wrong addresses.

Some one should probably do a PR to update this.
 
Aha! I'll try that. I figured something was missing. Guess its time to read chapters 12 to 16! Thank You Steely Eyed Missle Man!
 
KurtE, I added your clock enable line and could then read back what I wrote to XBARA1_SEL3. xbar_connect(40, 6) also works to that same degree.

This is not my actual code, I do use the header macros or my own functions to determine the input number (40) from other parameters, so I am simplifying a bit. Most of what I am doing now is experimenting and trying to learn what works so I've not tried to write polished code that I want to share.

The medium term goal here was to synchronize 2 (or more) flexPWM modules (not submodules) by routing a trigger from one module to the EXT_SYNC input of (multiple) submodules. I already have working code to synchronize the submodules within a module by using the Local_Sync input via the INIT_SEL field of the submodule's CTRL2 register. That was fairly easy. Problem is that the teensy does not have 2 pairs of channel A & B pins from the same flexPWM module on its outside pin rows (to drive a full H-Bridge). Synchronizing two modules was one of several approaches I've thought of to solve that. Probably the best approach would be to solder to one or more of the backside pads. I've not done soldering at that tiny a scale before so I'm not really looking forward to that approach myself. However having learned about SMT BergStiks recently, so I may try it. With this synchronization approach I was first trying to route a flexPWM trigger to a pin so I could look at it. XBARA1 output 6 is XBAR_INOUT40 which is ALT3 of pin EMC_04 which is Teensy 4.0 pin 2. XBARA1 input 40 is the trigger output from the 1st submodule of the 1st flexPWM module. So I needed to do 2 other things for which I have code: Enable the trigger output via the flexPWM's submodule TCTRL register, and select the XBAR_INOUT40 signal to the EMC_04 pin (it is ALT3). I never got a signal on this pin, so something is still not working. Of course once I got past this then I would have used a different XBARA1 output to route the trigger to the EXT_SYNC input of a flexPWM submodule whose INIT_SEL would need to be programmed for EXT_SYNC. BTW: I am thinking of using the dead time insertion capability of the flexPWM. Otherwise maybe this could be accomplished with a Quad Timer but I have not looked into that at all (yet).

Meanwhile I have other ideas so I am putting this on the back burner. Sometimes you learn about solutions to old problems later as you get more familiar with a chip - and obviously this is one hell of a complex chip. Diving into programming the "raw hardware" is not a trivial undertaking. I did hesitate on seeing that the chip manual is more than 3600 pages long! How many little details are missing or wrong or require a nuanced understanding of multiple aspects of the chip to get anything to work? There is no way I could absorb the whole manual without getting started & motivated. I could try working on top of an SDK/RTOS from NXP (eg: mcuXPRESSO) but that is sometimes trading one complexity for another. The teensy was cheap enough that I could start here and reconsider that decision if I hit too many roadblocks. I suspect I am going to need the XBAR to work eventually and will have to return to this.

In any event, thanks for your help on this issue.
 
Paul,

I also noticed that the macro in imxrt.h:

Code:
#define FLEXPWM_SMTCTRL_OUT_TRIG_EN(n)		((uint16_t)(((n) & 0x1F) << 0))

is probably wrong. It is a 6 bit field so the mask should be 0x3F.

I am thrilled that I could easily bypass the Arduino IDE and use make to compile, build and load code (on Ubuntu). I feel like I have all the code I need right there in one folder so I could get started without a huge learning curve on an IDE, RTOS, etc. Your stuff just works!
 
The medium term goal here was to synchronize 2 (or more) flexPWM modules (not submodules) by routing a trigger from one module to the EXT_SYNC input of (multiple) submodules.
I happen to recently having been attempting the same thing, synchronizing different FlexPWM modules. It took me quite some hours figuring this out
and I think I can explain what you saw back in 2020 (!)

With this synchronization approach I was first trying to route a flexPWM trigger to a pin so I could look at it. XBARA1 output 6 is XBAR_INOUT40 which is ALT3 of pin EMC_04 which is Teensy 4.0 pin 2. XBARA1 input 40 is the trigger output from the 1st submodule of the 1st flexPWM module. So I needed to do 2 other things for which I have code: Enable the trigger output via the flexPWM's submodule TCTRL register, and select the XBAR_INOUT40 signal to the EMC_04 pin (it is ALT3). I never got a signal on this pin, so something is still not working.
Turns out the trigger outputs are one clock in duration (not the FlexPWM clock either - slowing this down doesn't help, I suspect
its the XBAR clocking that sets this) - you can only really see any pulses on an IO pin if you set max slewrate, full drive strength,
and even then they are runt pulses.

Another gotcha I discovered was the inconsistent numbering of FlexPWM submodules - in most of the documentation each FlexPWM
unit has submodules 0..3, whereas the trigger output lines to the XBAR switch are named
FLEXPWM4_PWM1_OUT_TRIG0
FLEXPWM4_PWM2_OUT_TRIG0
FLEXPWM4_PWM3_OUT_TRIG0
FLEXPWM4_PWM4_OUT_TRIG0
so for many hours I was bashing my head against this by assuming FLEXPWM4_PWM2_OUT_TRIG0 was for submodule 2 :(

Of course once I got past this then I would have used a different XBARA1 output to route the trigger to the EXT_SYNC input of a flexPWM submodule whose INIT_SEL would need to be programmed for EXT_SYNC. BTW: I am thinking of using the dead time insertion capability of the flexPWM. Otherwise maybe this could be accomplished with a Quad Timer but I have not looked into that at all (yet).
I've then routed the correct signal to EXT_SYNC on the other units and get them to sync up with only 20ns delay at 600MHz
(this is not dependent on the FlexPWM prescaler). I used the VAL1 trigger (0b000010 in the TCTRL register's
FLEXPWM_SMTCTRL_OUT_TRIG_EN field)
Meanwhile I have other ideas so I am putting this on the back burner. Sometimes you learn about solutions to old problems later as you get more familiar with a chip -
Indeed!
 
Back
Top