Teensy 4.0 First Beta Test

Status
Not open for further replies.
now we have steps of 10 micros - so +- 1 is better :)
disabling interrupts works - but... it disables interrupts. not good. we already have that in yield and in systick ( later in the function call) ..and many more places. we should minimize that as much as possible...
taking this into account, the +-1 is not that important, I think.
 
AFAIK: the result would be +/- 1 millisecond < 1 ms not 1 us :( > - a tick would double count - or not count the systick_isr's update depending on the order of the change not detected.

It would be nice to make it safe and not touch interrupts - current micros() when called with "no interrupts" returns with them enabled as a side effect.

There is an LDREXD - for double words - but not supported on M7.

I found PJRC code that disables 'timer' interrupts - but that does all - and then selectively restores them?
T:\arduino-1.8.8T4_146\hardware\teensy\avr\cores\teensy4\EventResponder.h:
Code:
	static bool disableTimerInterrupt() {
		uint32_t primask;
		__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::);
		__disable_irq();
		return (primask == 0) ? true : false;
	}
	static void enableTimerInterrupt(bool doit) {
		if (doit) __enable_irq();

// where
//#define __disable_irq() __asm__ volatile("CPSID i":::"memory");
//#define __enable_irq()  __asm__ volatile("CPSIE i":::"memory");
	}
 
Hi @Frank (and others)...

Been playing around with the DMA code with my ILI9341_t3n library code and making some progress.

Currently I can get it started, with hopefully correct stuff... Took some playing around with some SPI registers and the like...

The Init dma buffer code for this processor now looks like:
Code:
	// Now lets setup DMA access to this memory... 
	// Try to do like T3.6 except not kludge for first word...
	Serial4.println("DMA initDMASettings - before settings");
	Serial4.printf("  CWW: %d %d %d\n", CBALLOC, SCREEN_DMA_NUM_SETTINGS, COUNT_WORDS_WRITE);
	_dmasettings[0].sourceBuffer(&_pfbtft[0], COUNT_WORDS_WRITE*2);
	_dmasettings[0].destination(_pimxrt_spi->TDR);
	_dmasettings[0].TCD->ATTR_DST = 1;
	_dmasettings[0].replaceSettingsOnCompletion(_dmasettings[1]);

	_dmasettings[1].sourceBuffer(&_pfbtft[COUNT_WORDS_WRITE], COUNT_WORDS_WRITE*2);
	_dmasettings[1].destination(_pimxrt_spi->TDR);
	_dmasettings[1].TCD->ATTR_DST = 1;
	_dmasettings[1].replaceSettingsOnCompletion(_dmasettings[2]);

	_dmasettings[2].sourceBuffer(&_pfbtft[COUNT_WORDS_WRITE], COUNT_WORDS_WRITE*2);
	_dmasettings[2].destination(_pimxrt_spi->TDR);
	_dmasettings[2].TCD->ATTR_DST = 1;
	_dmasettings[2].replaceSettingsOnCompletion(_dmasettings[3]);

	_dmasettings[3].sourceBuffer(&_pfbtft[COUNT_WORDS_WRITE*3], COUNT_WORDS_WRITE*2);
	_dmasettings[3].destination(_pimxrt_spi->TDR);
	_dmasettings[3].TCD->ATTR_DST = 1;
	_dmasettings[3].replaceSettingsOnCompletion(_dmasettings[0]);
	_dmasettings[3].interruptAtCompletion();

	// Setup DMA main object
	//Serial.println("Setup _dmatx");
	Serial4.println("DMA initDMASettings - before dmatx");
	_dmatx.begin(true);
	_dmatx.triggerAtHardwareEvent(dmaTXevent);
	_dmatx = _dmasettings[0];
	_dmatx.attachInterrupt(dmaInterrupt);

The code to start it up looks like:
Code:
bool ILI9341_t3n::updateScreenAsync(bool update_cont)					// call to say update the screen now.
{
	// Not sure if better here to check flag or check existence of buffer.
	// Will go by buffer as maybe can do interesting things?
	// BUGBUG:: only handles full screen so bail on the rest of it...
	#ifdef ENABLE_ILI9341_FRAMEBUFFER
	if (!_use_fbtft) return false;

#ifdef DEBUG_ASYNC_LEDS
	digitalWriteFast(DEBUG_PIN_1, HIGH);
#endif
	// Init DMA settings. 
	initDMASettings();

	// Don't start one if already active.
	if (_dma_state & ILI9341_DMA_ACTIVE) {
	#ifdef DEBUG_ASYNC_LEDS
		digitalWriteFast(DEBUG_PIN_1, LOW);
	#endif
		return false;
	}


	if (update_cont) {
		// Try to link in #3 into the chain
	} else {
		// In this case we will only run through once...
		_dmasettings[3].disableOnCompletion();
		_dma_state &= ~ILI9341_DMA_CONT;
	}
#ifdef DEBUG_ASYNC_UPDATE
	dumpDMASettings();
#endif

	beginSPITransaction();
	// Doing full window. 
	setAddr(0, 0, _width-1, _height-1);
	writecommand_last(ILI9341_RAMWR);

	// Update TCR to 16 bit mode. and output the first entry.
	_spi_fcr_save = _pimxrt_spi->FCR;	// remember the FCR
	_pimxrt_spi->FCR = 0;	// clear water marks... 	
	maybeUpdateTCR(LPSPI_TCR_PCS(1) | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_RXMSK | LPSPI_TCR_CONT);
 	_pimxrt_spi->DER = LPSPI_DER_TDDE;

  	_dmatx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_TX );

 	_dmatx = _dmasettings[0];

  	_dmatx.begin(false);
  	_dmatx.enable();

	_dma_frame_count = 0;  // Set frame count back to zero. 
	_dmaActiveDisplay = this;
	if (update_cont) {
		_dma_state |= ILI9341_DMA_CONT;
	} else {
		_dma_state &= ~ILI9341_DMA_CONT;

	}

	_dma_state |= ILI9341_DMA_ACTIVE;
}

And it looks like it is starting up OK... Starting of LA
screenshot.jpg

And then the Interrupt at the end is signaled (I am doing a one shot, code looks like:
Code:
void ILI9341_t3n::process_dma_interrupt(void) {
#ifdef DEBUG_ASYNC_LEDS
	digitalWriteFast(DEBUG_PIN_2, HIGH);
#endif
	// T4

	_dma_frame_count++;
	_dmatx.clearInterrupt();

	if ((_dma_state & ILI9341_DMA_CONT) == 0) {
#ifdef DEBUG_ASYNC_LEDS
		digitalWriteFast(DEBUG_PIN_3, HIGH);
#endif
		_dmatx.clearComplete();
		// We are in single refresh mode or the user has called cancel so
		// Lets try to release the CS pin
		// Lets wait until FIFO is not empty
		_pimxrt_spi->CR = LPSPI_CR_RRF | LPSPI_CR_MEN;	// clear out FIFO
		_pimxrt_spi->SR = 0x3f00;	// clear out all of the other status...
		Serial4.printf("Before FSR wait: %x\n", _pimxrt_spi->FSR);
		while (_pimxrt_spi->FSR)  ;	// wait until this one is complete
		uint32_t sr = _pimxrt_spi->SR;
		Serial4.printf("Before SR wait: %x\n", sr);
		while (_pimxrt_spi->SR == sr) ; // Wait until something changes 
		_pimxrt_spi->FCR = _spi_fcr_save;	// restore the FSR status... 
		Serial4.printf("Output NOP (SR %d)\n", _pimxrt_spi->SR);
		writecommand_last(ILI9341_NOP);
		Serial4.println("Do End transaction");
		endSPITransaction();
		_dma_state &= ~ILI9341_DMA_ACTIVE;
		_dmaActiveDisplay = 0;	// We don't have a display active any more... 

#ifdef DEBUG_ASYNC_LEDS
		digitalWriteFast(DEBUG_PIN_3, LOW);
#endif
	}
#ifdef DEBUG_ASYNC_LEDS
	digitalWriteFast(DEBUG_PIN_2, LOW);
#endif
}
Note: Edited out T3.5 and 3.6 code here to not confuse things. Also some of the debug prints and some wait loops were added to see if I could resolve the issue.

The main issue is knowing when the transfer has completed, so we can properly shut down the SPI transaction and restore things. The TX DMA Interrupt is called before things are actually done. If you look at the output LA...
screenshot.jpg The bottom trace line goes high when the ISR is called currently the looking at SR loop is hanging... i.e. SR does not change again...

With T3.5 I ended up resolving something like this by having another RXDMA from the LPSPI_TDR register to a dummy word in memory (not increment) and set the ISR on that one, which you then know is at the right time. I probably could do that here as well but sort of a waste.

With T3.6, solved it by pushing an NOP instruction with the EOQ flag which we could test for.

Still investigating but suggestions desired!
 
XBARA1 pin reassign to pins 2 and 3.

Ok back at this, got tired of not being able to get something else working so took a break and came back to this. Not sure if I am using the port assignment macros correctly so just want to get a sanity check if this looks about right:
Code:
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);   //turn clock on for xbara1

*(portConfigRegister(2)) = 0x03;  //Select mux mode: ALT3 mux port, ((digital_pin_to_info_PGM[(pin)].mux))
*(portModeRegister(2)) = 0x01;    //Input Path is determined by functionality
                                  //((digital_pin_to_info_PGM[(pin)].reg + 1))

*(portConfigRegister(3)) = 0x03;
*(portModeRegister(3)) = 0x01;

*(portInputRegister(2)) = 0x0; //SELECT_INPUT DAISY Register
*(portInputRegister(3)) = 0x0; //((digital_pin_to_info_PGM[(pin)].reg + 2))

*(portControlRegister(2)) = 0x10B0;  //pin pad configuration
*(portControlRegister(3)) = 0x10B0;  //((digital_pin_to_info_PGM[(pin)].pad))

//set as input
*(portInputRegister(2)) = 0x01;  //set both pins as input
*(portInputRegister(3)) = 0x01;  //((digital_pin_to_info_PGM[(pin)].pad))
If I did this right, a lot of reconfiguring to use alternate pins?
 
Mike, can you bring out ghost pins without a connection and trade off connected pins?

Hey Tim,
Yeah - I did that test to (liquid cooling :) ) when I was playing with the standalone sketch - couldn't resist - I should have put the heat sink on it to see what would happen :)

Heat sink just showed up - was running 49.85 to 50.51 in turns between 21 second updates. Room temp is up ...

Plopped it on fin side down and a reading popped up at 45 then 42. It is getting heat soaked now - 3 hits in 42 then two in 43 3 passing 44 then 2 @ 45.3, and 3 @ 45.93 then 4 @ 46.58 then 47.24 and 2 @ 46.58 - so that may be stable range with fins wrong way around - down 3 degrees. Pulled it off and it hit 48.55. Put it tape covered side down and fins up and 5 hits @ 47.24 . Removed and 48.55 and 6 @ 49.2 , 49.85 and back 4 @ 49.20 - seems stable there until the boards reheats - mostly 49.85 again ... back to a 50.51 once after a few minutes away.
 
Mike, can you bring out ghost pins without a connection and trade off connected pins?
….
Heat sink just showed up - was running 49.85 to 50.51 in turns between 21 second updates. Room temp is up ...

Plopped it on fin side down and a reading popped up at 45 then 42. It is getting heat soaked now - 3 hits in 42 then two in 43 3 passing 44 then 2 @ 45.3, and 3 @ 45.93 then 4 @ 46.58 then 47.24 and 2 @ 46.58 - so that may be stable range with fins wrong way around - down 3 degrees. Pulled it off and it hit 48.55. Put it tape covered side down and fins up and 5 hits @ 47.24 . Removed and 48.55 and 6 @ 49.2 , 49.85 and back 4 @ 49.20 - seems stable there until the boards reheats - mostly 49.85 again ... back to a 50.51 once after a few minutes away.
Hi Tim, not sure what you mean by ghost pins? If you mean redefine existing pins with alternate pins, supposedly you can, if you look at say the IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_04 register you will see that you have alt configures for EMC_04 pin. Alt3 is used to reassign it to XBAR_INOUT06 pin, and the associated SCION bit tells it to "Force the selected mux mode Input path no matter of MUX_MODE functionality" just not sure if its 1 or 0, ENABLED — Force input path of pad GPIO_EMC_04 or 0 - input path determined by functionality - probably 0. If there is a 50/50 chance of me getting it right bet on me getting it wrong :)

As for temp, what you see is about what I have seen - if you blow on it, it will decrease. On the SDK board its lower but the RT1052 is on a much much bigger board which probably acts like a huge heat sink for the chip, so it didn't really surprise me when I saw it running hotter.
 
Nothing uses GPTn as far as I know ... which goes to Paul's need to have a "timers consumers list" to know what is using which timers (PIT, GPT, QTMR, flexPWM) ... IntervalTimer, Tone, PWM, IRremote ...

One possible use of GPT1 is for FreqCount (pin 25 is the external trigger). Here is a proof-of-concept (32-bit counter)
https://github.com/manitou48/teensy4/blob/master/gpt_count.ino
Jumper PWM pin 11 to 25 for testing.

UPDATE: pin 25 works on T4B2 (1062), and on 1062 GPT2 CLOCK pin is available on pin 14 ALT8 with low bit set in IOMUXC_GPT2_IPP_IND_CLKIN_SELECT_INPUT (ref pg 1000)

quad timer might also be used for FreqCount, see sketch

GPTn can also do PWM, but NONE of the GPTn output pins are available on T4 (1050).

update: see https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=211156&viewfull=1#post211156
use QTMR pin 9, FreqCount lib updated 1.47-beta5
also see https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=211416&viewfull=1#post211416
 
Last edited:
Hi Tim, not sure what you mean by ghost pins? ...
Any of the MCU Pins not brought out with a connection to a pin/pad to connect.

I'll get a ref for manitou's GPT timer as micros() to compare - I'm still using the digit short version old_micros() - it would show a messed up tick of +/- 1000 us - and in the hours I've left it to run I have not caught that. The micros() is about 30 cycles [avg] - _isr would have to hit in the right spot to break the while(A||B) test - and it may be the code is ordered such that it can't change without triggering - reading the last changed first and read&test it last?
 
Any of the MCU Pins not brought out with a connection to a pin/pad to connect.

I'll get a ref for manitou's GPT timer as micros() to compare - I'm still using the digit short version old_micros() - it would show a messed up tick of +/- 1000 us - and in the hours I've left it to run I have not caught that. The micros() is about 30 cycles [avg] - _isr would have to hit in the right spot to break the while(A||B) test - and it may be the code is ordered such that it can't change without triggering - reading the last changed first and read&test it last?

manitou poste a link a while ago to his GITHUB: https://github.com/manitou48/teensy4. Pretty sure it would be there.

Ok now I know what you mean by ghost pin, I think. oops forgot he rest. The answer I believe is no. The alternate function assignments are for that one pin to MCU connection. You can reassign its function based on whats allowed by the pin config but no others than that.
 
manitou poste a link a while ago to his GITHUB: https://github.com/manitou48/teensy4. Pretty sure it would be there.

Ok now I know what you mean by ghost pin, I think. oops forgot he rest. The answer I believe is no. The alternate function assignments are for that one pin to MCU connection. You can reassign its function based on whats allowed by the pin config but no others than that.

Have the manitou 1MHz GPT code in my sketch from when he posted - I just didn't integrate it yet for current code. I noted it is a good way to fault the MCU by writing to the timer read location :) I'll need to get the offset to the running micros and then do a func to normalize it.

I didn't figure pins that were ghosted could be brought around - that would be something for nothing :)
 
Last edited:
I've sent you a Mail.. could have posted it here too, it was less than expected :)
Yes, you need DMAMEM - or just use malloc. The heap is in OCRAM now - like DMAMEM.

Good night.

Hi @Frank (and others) Still playing with the ili9341_t3n DMA Asynch updates. As I mentioned yesterday, having issues stopping the updates.

But I was also noticing the screen update was not looking right... I tried turning on the continuous updates, with my test which first test simply fills screen with green... And when I looked at Logic Analyzer output of the data, there were gaps in the data which were zeros...
Which you can sort of see in this LA capture:
screenshot.jpg

Currently I simply have the Frame buffer defined: DMAMEM uint16_t tft_frame_buffer[ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT];

First thought was maybe my fillScreen code was failing... So quick and dirty test:
Code:
void testDMAContUpdate(bool fCont) {
  // Force frame buffer on

  DBGSerial.printf("continuous DMA udpate test - Frame mode on\n"); DBGSerial.flush();
  if (!fCont) {
    DBGSerial.println("Step Mode");
    DBGSerial.flush();
  }
  use_fb = 1; //

  tft.useFrameBuffer(use_fb);
  tft.fillScreen(ILI9341_GREEN);

  // check to see if screen memory actually turned green.
  if (use_fb) {
    int error_count = 0;
    for (int i=0; i < (sizeof(tft_frame_buffer)/sizeof(tft_frame_buffer[0])); i++) 
    {
      if (tft_frame_buffer[i] != ILI9341_GREEN) {
        DBGSerial.printf("tft.fillScreen(ILI9341_GREEN) not green? %d != %x\n", i, tft_frame_buffer[i]);
        error_count++;
      }
    }
    DBGSerial.printf("tft.fillScreen(ILI9341_GREEN(%x)) error count = %d\n", ILI9341_GREEN, error_count);
  }

  if (fCont)
    tft.updateScreenAsync(fCont);

  // Start the update
  WaitForFrame(fCont, 10);
And it does not print out any Errors. Also when it ran with this code in place: The output in the LA for the startup of the DMA output of green looks more correct:
screenshot.jpg


So I am guessing like maybe the writes are not being registered by the DMA system... Need some other attribute?
Also in your email you showed that you allocated an extra 32 bytes of data and aligned your buffer to a 32 byte aligned address? Is this needed? If so, probably does not make sense to add general DMA access into the SPI code (i.e. the SPI.transfer(buf, retbuf, cnt, event); ...


Thanks
Kurt
 
Hi Kurt,
can you upload your current code to gihub (as a new test-branch) or send it to me via mail? I want to look at it (had my experimental code working).
32-bit align: for sure not needed if you do 16 bit-transfers. 32 Bit: I don't know if DMA can work unaligned, have not tried it. I added it for faster access. OCRAM has waitstates anyway...

Unrelated question: does anyone know how many waitstates the different memory areas have in a case of a cache miss?
 
Tim:
played a few minutes with ldrex/strex:
Code:
#include "arm_math.h"
#include "core_cmInstr.h"

void setup() { delay(1000); }

void loop() {
static uint32_t a = 0;
static uint32_t b = 0;
uint32_t c,d, dummy;
 do {
  __LDREXW(&dummy);
  c = a;
  d = b;
  if (c==10) {delay(2);a++;}//<- interrupt happens most likely here   
 } while ( __STREXW(0, &dummy));
 Serial.printf("c: %d, c:%d\n",c,d);
 delay(500);
 a++;b++;
}
It just detects interrupts :) so.. if an interrupt is detected, it repeats the loop.
simple.
 
Last edited:
Hi Frank,

Current stuff pushed up on github in my WIP branch: https://github.com/KurtE/ILI9341_t3n/tree/T4_WIP

I have included here a test app, that is sort of a piece of ... But I have used to test different pieces of the library code, like using frame buffers, offsets, clipping, ...

Currently it is hacked up to do testing using Serial4 as the terminal as I use inputs for commands...

The commands are pretty simple/stupid...

If you just hit enter, it draws test screen, alternating each time between using frame buffer and not using frame buffer..

If you use the input of just: d
it Turns on or off using DMA (Async support).

Now if you alternate with just <CR>
When it's turn for frame buffer it will use the DMA function, which will hang at the end...

There is a command: t
For drawing text screen

But the continuous updates, for something like 35 frames is the command: r
(Don't remember what r stood for ;) ) - This is where I saw issue with green... Again hangs when I try to end DMA mode...

The 'a' command does the same Async code like 'r' but it only does one test at a time with single frame asynch output, Which will hang at the end like above.
 

Attachments

  • Kurts_ILI9341_t3n_FB_and_clip_tests-190118a.zip
    3.9 KB · Views: 82
32-bit align: for sure not needed if you do 16 bit-transfers. 32 Bit: I don't know if DMA can work unaligned, have not tried it. I added it for faster access. OCRAM has waitstates anyway...
Forgot to comment here. In the code I updated on github... When I do the malloc (if user does not set their own buffer).

I followed sort of the code you emailed:
Code:
 const int bufalign = 32; //alignment of buffer
   mem = (uint16_t* )malloc(BUFSIZE + bufalign);
   buffer = (uint16_t*) (((uintptr_t)mem + bufalign) & ~ ((uintptr_t) (bufalign - 1 )));
Which aligned to 32 byte boundary, which I was why I was asking. I understand 32 bit boundary. Or in my case 16 bit boundary.
My assumption (which is often wrong) is that unless I do something special to force alignments (like #pragma pack)
If I define a variable like:
uint16_t My_Array[100];
It will align the array with proper 16 bit alignment. and Likewise if I have an array:
uint32_t My_Array[100];

The array will have proper 32 bit alignment...
 
uint16_t My_Array[100];
uint32_t My_Array[100];
The array will have proper 32 bit alignment...
I think both arrays will have 32-bit alignment.
but... not with malloc!

I'll take a longer break now, and then try to get that display working with dma :)
 
Tim:
played a few minutes with ldrex/strex:
Code:
#include "arm_math.h"
#include "core_cmInstr.h"

void setup() { delay(1000); }

void loop() {
static uint32_t a = 0;
static uint32_t b = 0;
uint32_t c,d, dummy;
 do {
  __LDREXW(&dummy);
  c = a;
  d = b;
  if (c==10) {delay(2);a++;}//<- interrupt happens most likely here   
 } while ( __STREXW(0, &dummy));
 Serial.printf("c: %d, c:%d\n",c,d);
 delay(500);
 a++;b++;
}
It just detects interrupts :) so.. if an interrupt is detected, it repeats the loop.
simple.

Thanks Frank. I thought about setting a global flag '1' in micros and then checking just that before computing with the other numbers. If at any point the interrupt happens that is set '0' in systick_isr.

To see what happens I took out the while( no change) test doing a loop watching for 100 Million successive increments to micros(). Sometime two sets works and once I see 4 successive times where the returned value of micros() is 999 too high suggesting the interrupt occurred between reads and stopped that test run.

But it seems I have a test that can see it happen.

So doing this for the _isr:
Code:
extern "C" void systick_isr(void)
{
	systick_safe_read = 0;
	systick_cycle_count = ARM_DWT_CYCCNT;
	systick_millis_count++;
	MillisTimer::runFromTimer();
}

and this in micros() is currently showing 25 completed sets of 100,000,000 micros() updates:
Code:
	do {
		systick_safe_read = 1;
		smc = systick_millis_count;
		scc = systick_cycle_count;
	} while ( 1 != systick_safe_read ); // repeat if systick_isr

I'm not positive this is complete - but having micros() put a known value there to test for helps versus the other two values I can only trust to read the same way not knowing the value?

I'll rewrite that with __LDREXW...__STREXW on that systick_safe_read in place of your dummy and in the while loop and see how timing compares.

Currently adding the new code looks like it added maybe 7 cycles to the execution of micros() up from 31. Funny cycle timing on that 100K timing test runs in different times - sometime 10 cycles faster in the low 20's on prior versions.
 
Hi Frank,

Current stuff pushed up on github in my WIP branch: https://github.com/KurtE/ILI9341_t3n/tree/T4_WIP

I have included here a test app, that is sort of a piece of ... But I have used to test different pieces of the library code, like using frame buffers, offsets, clipping, ...

oh... took me quite some time to figure out that _pimxrt_spi is = 0... why?? Kurt? pls help :) looks like i'm doing something wrong :)
nothing works..


Edit: so much defines...#idefs... that code is complicated. how about splitting it into different files?
Edit: one more warning:
Code:
C:\Users\Frank\Documents\Arduino\libraries\ILI9341_t3n-T4_WIP\ILI9341_t3n.cpp: In member function 'uint16_t ILI9341_t3n::readPixel(int16_t, int16_t)':
C:\Users\Frank\Documents\Arduino\libraries\ILI9341_t3n-T4_WIP\ILI9341_t3n.cpp:1347:9: warning: 'colors' is used uninitialized in this function [-Wuninitialized]
  return colors;
         ^~~~~~
Edit: one important hint:
Avoid register reading problems: Reading the Transmit Command Register will return
the current state of the command register. Reading the Transmit Command Register at the
same time that the Transmit Command Register is loaded from the transmit FIFO, can
return an incorrect Transmit Command Register value. It is recommended:
• to either read the Transmit Command Register when the transmit FIFO is empty,
• or to read the Transmit Command Register more than once and then compare the

returned values.
so... i'd not read that register. instead use a shadow-copy in a variable(?)
 
Last edited:
T4 QUADRATURE ENCODER MODULE

As a fast test I copied over enough of the encoder driver from the SDK to test both the encoder functionality and the method I am using for assigning alternate pins. I got it working after rereading the chapters on xbar and encorder a couple times :). Verified it using a rotary encoder attached to pins 2 and 3 (stayed away from the uart6 pins for now). It does show the counts going increasing and decreasing depending on the way I am turning knob.

Just for reference I am listing the method:
Code:
void setup()
{
  while(!Serial && millis() < 4000);
  delay(2000);

  CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);   //turn clock on for xbara1

  CORE_PIN2_CONFIG = 0x03;  //Select mux mode: ALT3 mux port
  CORE_PIN3_CONFIG = 0x03;  //0x03=Input Path is determined by functionality, 
                            //0x13 for 1 enabled
  
  CORE_PIN2_PADCONFIG = 0x10B0;  //pin pad configuration
  CORE_PIN2_PADCONFIG = 0x10B0;
  
  //set as input
  IOMUXC_XBAR1_IN04_SELECT_INPUT = 0x01;  //set both pins as input
  IOMUXC_XBAR1_IN05_SELECT_INPUT = 0x01;

  //==========================================================================
  /* XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputIomuxXbarIn21, kXBARA1_OutputEnc1PhaseAInput);
   * XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputIomuxXbarIn22, kXBARA1_OutputEnc1PhaseBInput);
   * XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputIomuxXbarIn23, kXBARA1_OutputEnc1Index);
   * These are the SDK settings
   * kXBARA1_OutputEnc1PhaseAInput   = 66|0x100U,   // XBARA1_OUT66 output assigned to ENC1_PHASE_A_INPUT
   * kXBARA1_OutputEnc1PhaseBInput   = 67|0x100U,   // XBARA1_OUT67 output assigned to ENC1_PHASE_B_INPUT
   * kXBARA1_OutputEnc1Index         = 68|0x100U,   // XBARA1_OUT68 output assigned to ENC1_INDEX 
   * kXBARA1_OutputEnc1Home          = 69|0x100U,   // XBARA1_OUT69 output assigned to ENC1_HOME
   * kXBARA1_OutputEnc1Trigger       = 70|0x100U,   // XBARA1_OUT70 output assigned to ENC1_TRIGGER 
   *
   * kXBARA1_InputIomuxXbarInout06   = 6|0x100U,    // IOMUX_XBAR_INOUT06 output assigned to XBARA1_IN6 input.
   * kXBARA1_InputIomuxXbarInout07   = 7|0x100U,    // IOMUX_XBAR_INOUT07 output assigned to XBARA1_IN7 input.
   * kXBARA1_InputIomuxXbarInout08   = 8|0x100U,    // IOMUX_XBAR_INOUT08 output assigned to XBARA1_IN8 input.
   */
  
  xbar_connect(6, 66);
  xbar_connect(7, 67);
  //========================================================================
  //Phase A => pin2
  //Phase B => pin3
    /* Initialize the ENC module. */
    ENC_GetDefaultConfig(&mEncConfigStruct);
    ENC_Init(&mEncConfigStruct);
    ENC_DoSoftwareLoadInitialPositionValue(); /* Update the position counter with initial value. */
}

EDIT: A couple of notes that I just thought of that might be of interest.
1. if CORE_PIN2_CONFIG =0x03 it counts x1, if 0x13 it counts by 4.
2. xbar_connect(input, output); => input/output values were pulled from the SDK, I couldn't find them defined any place out, although input seems to correspond to the IOn value.
3. Not going to pursue a library at this point as encoder library works just as well for basic encoder function. There are a lot of bells and whistles that can be used with the RT1052 encoder module and with other tests needed...
 
Last edited:
AltsoftSerial needs porting:
Code:
Detecting libraries used...
"C:\\Arduino\\hardware\\teensy/../tools/arm8/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "c:\\temp\\arduino_build_330333\\sketch\\ShowConfiguration.ino.cpp" -o nul
"C:\\Arduino\\hardware\\teensy/../tools/arm8/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\AltSoftSerial" "c:\\temp\\arduino_build_330333\\sketch\\ShowConfiguration.ino.cpp" -o nul
Error while detecting libraries included by c:\temp\arduino_build_330333\sketch\ShowConfiguration.ino.cpp
"C:\\Arduino\\hardware\\teensy/../tools/arm8/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\AltSoftSerial" "C:\\Arduino\\hardware\\teensy\\avr\\libraries\\AltSoftSerial\\AltSoftSerial.cpp" -o nul
Error while detecting libraries included by C:\Arduino\hardware\teensy\avr\libraries\AltSoftSerial\AltSoftSerial.cpp
Generating function prototypes...
"C:\\Arduino\\hardware\\teensy/../tools/arm8/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\AltSoftSerial" "c:\\temp\\arduino_build_330333\\sketch\\ShowConfiguration.ino.cpp" -o "c:\\temp\\arduino_build_330333\\preproc\\ctags_target_for_gcc_minus_e.cpp"
In file included from C:\Arduino\hardware\teensy\avr\libraries\AltSoftSerial\examples\ShowConfiguration\ShowConfiguration.ino:15:
C:\Arduino\hardware\teensy\avr\libraries\AltSoftSerial/config/AltSoftSerial_Boards.h:146:2: error: #error "Please define your board timer and pins"
 #error "Please define your board timer and pins"
  ^~~~~
Bibliothek AltSoftSerial in Version 1.4 im Ordner: C:\Arduino\hardware\teensy\avr\libraries\AltSoftSerial  wird verwendet
Fehler beim Kompilieren für das Board Teensy 4-Beta1.
 
A simple wire and touching the pin should work. Bounce2 does not work, too. I tried the example.
Interesting, I just tested the rotary encoder I have (http://henrysbench.capnfatz.com/hen...es-ky-040-arduino-rotary-encoder-user-manual/), it has a push button capability as well. That seemed to work well for me - example worked and when I attached one of encoder pins when I turned the knob it work with out a problem.

Will give your wire method a try and see what happens.

UPDATE: One thing I noticed right away the LED is always on unless you go to ground - it will work the other way as well just have to modify the if. Anyway I didn't touch the pin I used a breadboard jumper and then just touched the jumpers. Used 1 ms and 5 ms for test but didn't notice anything not working. One touch it goes out - if I leave it connected it stays out.
 
Last edited:
Status
Not open for further replies.
Back
Top