Custom PCB (Based on Teensy 4.0) - Accessing Wire3

amertz03

Member
We have developed a custom pcb, based on the Teensy 4.0 schematic, but we brought out 2 additional lines (I2C) from the processor that we intended to use with "Wire3", but the Wire library does not seem to support "Wire3" on Teensy 4.0. The additional lines we brought out are Port LPI2C2_SDA and LPI2C2_SCL. I did some digging on the this forum and found the modifications needed to the file "WireKenitis.h" to enable access to Wire3 on Teensy 3.X and below, but I can't seem to find anything related to Teensy 4.0. Any idea which files to modify and how to modify them to allow me to utilize "Wire3" for communications to sensors on this line?
 
Look at WireIMXRT.h/.cpp

You will find an area in it like:
Code:
#if defined(ARDUINO_TEENSY_MICROMOD)
PROGMEM
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = {
	CCM_CCGR2, CCM_CCGR2_LPI2C2(CCM_CCGR_ON),
		{{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
		{{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
	IRQ_LPI2C2, &lpi2c2_isr
};
TwoWire Wire3(IMXRT_LPI2C2_ADDRESS, TwoWire::i2c2_hardware);
#endif
You will need to add one like it or modify it to include yours...

Earlier in the file there is also:
Code:
#if defined(ARDUINO_TEENSY_MICROMOD)
void lpi2c1_isr(void) { Wire.isr(); }
void lpi2c3_isr(void) { Wire2.isr(); }
void lpi2c4_isr(void) { Wire1.isr(); }
void lpi2c2_isr(void) { Wire3.isr(); }
#else
void lpi2c1_isr(void) { Wire.isr(); }
void lpi2c3_isr(void) { Wire1.isr(); }
void lpi2c4_isr(void) { Wire2.isr(); }
#endif
That you will also need to add/modify as well.

You probably need to edit the header file as well.
That has:
Code:
#if defined(ARDUINO_TEENSY_MICROMOD)
extern TwoWire Wire3;
#endif
 
I wasn't able to find those lines of code in the WireIMXRT.h/.cpp files so I updated to a newer version of Teensyduino (Old version 1.55, New version 1.58), and now I see these lines of code. They are just how you suggested above, however, I get the following error when I try to add Wire3.begin() to my Setup routine, 'Wire3' was not declared in this scope; did you mean 'Wire2'?. I am thinking this is because this I2C port is only brought out for "ARDUINO_TEENSY_MICROMOD". What is this? I have Teensy 4.0. I am able to get it to compile successfully if I choose Teensy MicroMod as my board, but obviously I can't upload this way since I have Teensy 4.0? Am I missing something?
 
Only updating to 1.58 isn't enough. You need to actually edit WireIMXRT.h and WireIMXRT.cpp.

ARDUINO_TEENSY_MICROMOD is defined when you select Teensy MicroMod in the Tools > Board menu. It supports MicroMod Teensy from Sparkfun.

Probably the simplest thing would be the delete those #if defined(ARDUINO_TEENSY_MICROMOD) lines for the 2 places Kurt mentioned where it's a simple matter of only compiling it for MicroMod.

The one with #if #else is a bit more complicated, because the hardware ports map onto the Arduino names differently. Probably best to just copy of the last line from the ARDUINO_TEENSY_MICROMOD case to the lines for other boards.
 
Paul,

It looks like your suggestions now allow the firmware to compile and upload, but the sketch fails/freezes on Wire3.begin(). If I remove this, I can call some other things like Wire.BeignTransmission(), and Wire.RequestFrom without the sketch failing, but I don't get any communications back
 
Sounds like you're really close.

At this point, probably best to share your modified WireIMXRT.h and WireIMXRT.cpp so I can others like Kurt can take a look.

If using forum's Quick Reply, click Go Advanced to get to the full editor which lets you attach files to your message.
 
I have attached the WireIMXRT.h and WireIMXRT.cpp files. The suggested edited portions are listed below...


From WireIMXRT.h
Code:
//#if defined(ARDUINO_TEENSY_MICROMOD)
extern TwoWire Wire3;
//#endif

From WireIMXRT.cpp
Code:
#if defined(ARDUINO_TEENSY_MICROMOD)
void lpi2c1_isr(void) { Wire.isr(); }
void lpi2c3_isr(void) { Wire2.isr(); }
void lpi2c4_isr(void) { Wire1.isr(); }
void lpi2c2_isr(void) { Wire3.isr(); }
#else
void lpi2c1_isr(void) { Wire.isr(); }
void lpi2c3_isr(void) { Wire1.isr(); }
void lpi2c4_isr(void) { Wire2.isr(); }
void lpi2c2_isr(void) { Wire3.isr(); }
#endif

From WireIMXRT.cpp
Code:
//#if defined(ARDUINO_TEENSY_MICROMOD)
PROGMEM
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = {
	CCM_CCGR2, CCM_CCGR2_LPI2C2(CCM_CCGR_ON),
		{{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
		{{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
	IRQ_LPI2C2, &lpi2c2_isr
};
TwoWire Wire3(&IMXRT_LPI2C2, TwoWire::i2c2_hardware);
//#endif
 

Attachments

  • WireIMXRT.h
    10.2 KB · Views: 47
  • WireIMXRT.cpp
    14.8 KB · Views: 33
Your changes:
Code:
PROGMEM
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = {
	CCM_CCGR2, CCM_CCGR2_LPI2C2(CCM_CCGR_ON),
		{{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
		{{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
	IRQ_LPI2C2, &lpi2c2_isr
};
TwoWire Wire3(&IMXRT_LPI2C2, TwoWire::i2c2_hardware);

Assumes that the SDA pin is pin 41 and the SCL pin is Pin 40.

But Teensy 4 only has pins 0-39.

You would need to go into the Teensy core file: *cores\teensy4\core_pins.h

And update the section (assuming that you are just modifying the T4 object), else you need to add your own complete section...

Code:
#if defined(__IMXRT1062__) && defined(ARDUINO_TEENSY40)

#define CORE_NUM_TOTAL_PINS	40
#define CORE_NUM_DIGITAL	40
#define CORE_NUM_INTERRUPT	40
#define CORE_NUM_ANALOG		14
#define CORE_NUM_PWM		27
You need to update the 40s to the correct number...
And then add in:
All of the defines for Pin40 and 41.

Now assuming you brought out the same pins for this as the Micromod used, you can copy those values from the Micromod section of this file:
Code:
#define CORE_PIN40_BIT		4
#define CORE_PIN41_BIT		5

#define CORE_PIN40_BITMASK	(1<<(CORE_PIN40_BIT))
#define CORE_PIN41_BITMASK	(1<<(CORE_PIN41_BIT))

#define CORE_PIN40_PORTREG	GPIO7_DR
#define CORE_PIN41_PORTREG	GPIO7_DR
...

You may need to edit digital.c, where the table is defined.
Code:
const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[] = {

Where:
Code:
#if CORE_NUM_DIGITAL > 40
	{&CORE_PIN40_PORTREG, &CORE_PIN40_CONFIG, &CORE_PIN40_PADCONFIG, CORE_PIN40_BITMASK},
	{&CORE_PIN41_PORTREG, &CORE_PIN41_CONFIG, &CORE_PIN41_PADCONFIG, CORE_PIN41_BITMASK},
	{&CORE_PIN42_PORTREG, &CORE_PIN42_CONFIG, &CORE_PIN42_PADCONFIG, CORE_PIN42_BITMASK},
	{&CORE_PIN43_PORTREG, &CORE_PIN43_CONFIG, &CORE_PIN43_PADCONFIG, CORE_PIN43_BITMASK},
	{&CORE_PIN44_PORTREG, &CORE_PIN44_CONFIG, &CORE_PIN44_PADCONFIG, CORE_PIN44_BITMASK},
	{&CORE_PIN45_PORTREG, &CORE_PIN45_CONFIG, &CORE_PIN45_PADCONFIG, CORE_PIN45_BITMASK},
#endif
#if CORE_NUM_DIGITAL > 46
	{&CORE_PIN46_PORTREG, &CORE_PIN46_CONFIG, &CORE_PIN46_PADCONFIG, CORE_PIN46_BITMASK},
	{&CORE_PIN47_PORTREG, &CORE_PIN47_CONFIG, &CORE_PIN47_PADCONFIG, CORE_PIN47_BITMASK},
	{&CORE_PIN48_PORTREG, &CORE_PIN48_CONFIG, &CORE_PIN48_PADCONFIG, CORE_PIN48_BITMASK},
Where you might need to ad another #if/#endif for NUM_DIGITAL > 42 or the like, depending on if these were the only pins you brought out.

There might be other places, but that is where I would start
 
Thanks @KurtE and @PaulStoffregen, this compiles and runs and an initial test looks like comms are performing as expected. I will do a little deeper testing in the next day or two, but so far all looks good.
 
So upon further testing and investigation, we actually designed our board according to Teensy 4.1, not 4.0. We have developed many boards in this similar way, but have yet to have to use the Wire3 bus. For some reason, this board is showing up as Teensy 4.0. I tried many of our other recent boards with the exact same circuits and components, and they all show up as Teensy 4.1. Any idea why this might be? It is my understanding that the bootloader chips are just Teensy 4.X. I am now trying to gain access to Teensy pins 40 and 38 to use as analog inputs, but since Teensy 4.0 doesn't bring these out, they are not in the existing libraries. I am looking into making similar changes in the core_pins.h, analog.c, digital.c, and pins_arduino.h files, but I am having difficulty understanding if I should copy the Teensy 4.0 portions, or the Teensy MicroMOD portions. Any guidance would be greatly appreciated.
 
This is for sure more of a Paul question, but my one guess is what flash memory did you build with? Does it match the one used in T4 or T4.1?
 
For some reason, this board is showing up as Teensy 4.0. I tried many of our other recent boards with the exact same circuits and components, and they all show up as Teensy 4.1. Any idea why this might be?

The bootloader is supposed to detect which flash chip you have connected. The 2MB (16Mb) chip means Teensy 4.0 and the 8MB (64Mb) chip means Teensy 4.1.
 
Ok, this has been confirmed. We used the 2MB chip on this board because we had some trouble securing the 8MB versions for some time and accidentally used the 2MB chip during population, this is where some of my confusion has been coming from. So now I believe I am left with 2 options and I am looking for some direction here from you guys.

Option 1 (Preferred)
Switch the flash memory to the 8MB version since we have way more of these on hand now and use the system as Teensy 4.1. I have my Wire3 pins wired to processor balls GPIO_B0_04 for SCL and GPIO_B0_05 for SDA, and I have 2 sensors wired to pins GPIO_AD_B1_12, and GPIO_AD_B1_04 that will be used as analogInputs, so I believe I will need to modify some files to make this work, but now sure how much modifications are needed with this route.

Option 2
Keep the 2MB flash version that is currently on the board, so utilize it as Teensy 4.0, and make modifications needed to be able to see those 2 additional analog inputs. I already am successfully using the Wire3 line this way, but I can't see those additional analog inputs.

If option 1 is still doable but requires more modifications, I think I would go down that road because like I mentioned, we have many more 8MB flash chips than we do the 2MB versions so we would either have to get more of these or eventually I would have to port it over to the 4.1 version anyways.
 
Is it possible to tell me which processor pins the Teensy 4.1 uses for I2C comms on Wire3, and where in the libraries this is located? I am thinking it should be easier to modify this (if needed) rather than modify the Teensy 4.0 stuff to utilize the additional IO pins.
 
The Teensy 4.1 only has 3 I2C ports accessed as Wire, Wire1 and Wire2.
The third port (Wire2) is on pins 24 and 25.
 
I believe the processor has a 4th bus, just not brought out on the Teensy breakout boards. I am connected to pins GPIO_B0_04 for SCL and GPIO_B0_05 for SDA on the processor and trying to figure out how I can modify the library to accept Wire3 on these pins.
 
I believe the processor has a 4th bus, just not brought out on the Teensy breakout boards. I am connected to pins GPIO_B0_04 for SCL and GPIO_B0_05 for SDA on the processor and trying to figure out how I can modify the library to accept Wire3 on these pins.

The same way I mentioned in post #2.

WireIMXRT.cpp, only Micromod brings it out:
Code:
#if defined(ARDUINO_TEENSY_MICROMOD)
PROGMEM
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c2_hardware = {
	CCM_CCGR2, CCM_CCGR2_LPI2C2(CCM_CCGR_ON),
		{{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
		{{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
	IRQ_LPI2C2, &lpi2c2_isr
};
TwoWire Wire3(IMXRT_LPI2C2_ADDRESS, TwoWire::i2c2_hardware);
#endif
You would need to add in #if for which board type you are adding or modifying. I

The two lines that may be different are:
Code:
		{{41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
		{{40, 2 | 0x10, &IOMUXC_LPI2C2_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
Where the first line is for SDA and 2nd line for SCL. We defined in header file, that we have a max of 2 pins per signal, but in the case of MMOD only one is used...
The: {41, 2 | 0x10, &IOMUXC_LPI2C2_SDA_SELECT_INPUT, 1}

41 - is Teensy pin number

2 | 0x10 - is the mode that pin changes to for I2C/Wire...

&IOMUXC_LPI2C2_SDA_SELECT_INPUT - Is pointer to the IOMUXC register that controls, in cases of the input signal can be routed to different pins, which pin is the signal to be routed to.

1 - is the setting for that register.

You may also want to edit the header file (WireIMXRT.h) to add the extern in for it as well...

Code:
extern TwoWire Wire;
extern TwoWire Wire1;
extern TwoWire Wire2;
#if defined(ARDUINO_TEENSY_MICROMOD)
extern TwoWire Wire3;
#endif
 
Last edited:
Back
Top