Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 9 of 9

Thread: teensy 4.0 XBAR questions

  1. #1
    Junior Member
    Join Date
    Feb 2020
    Location
    New Hampshire, USA
    Posts
    5

    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
    Attached Files Attached Files

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,331
    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

  3. #3
    Junior Member
    Join Date
    Feb 2020
    Location
    New Hampshire, USA
    Posts
    5
    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().

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,331
    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.

  5. #5
    Junior Member
    Join Date
    Feb 2020
    Location
    New Hampshire, USA
    Posts
    5
    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!

  6. #6
    Junior Member
    Join Date
    Feb 2020
    Location
    New Hampshire, USA
    Posts
    5
    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.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,473
    Yup, looks like these defines have been wrong since the beginning. Committed a fix on github.

    https://github.com/PaulStoffregen/co...626d772eed6ed5

    FWIW, I looked at the old reference manuals. Looks like I got this wrong info from the very first pre-release RT1050 manual (under NDA) dated 06/2017.

  8. #8
    Junior Member
    Join Date
    Feb 2020
    Location
    New Hampshire, USA
    Posts
    5
    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!

  9. #9

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •