Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for adding board variants for Teensy 4.x boards. #750

Open
wants to merge 37 commits into
base: master
Choose a base branch
from

Conversation

KurtE
Copy link
Contributor

@KurtE KurtE commented Jul 19, 2024

As discussed on the forum thread:
https://forum.pjrc.com/index.php?threads/teensy-4-x-maybe-support-for-custom-boards-using-variants.75372/

I believe it would benefit the Teensy 4.x community if it was easier for PJRC and other builders who wish to generate
custom teensy boards, if there was at least some minimal support for adding variant boards. I personally do not want to
necessarily have to hack up a teensy install, to for example support the Devboard 4 4.5 or 5 boards, where the changes could
directly impact in this case the setup for Micromod boards.

So I have this branch of my fork setup to allow me to create the different variants for these above boards. Note: I have not done anything specific for the 4.5 as it is simply the 4 plus SDIO and USB Host changes.

So far the changes have included:

  1. change core_pins.h that checks for a variant.h file like:
#if __has_include("variant.h")
#  include "variant.h"
//#pragma message "core_pins.h" - included variant.h
// Default no override file
#elif defined(__IMXRT1062__) && defined(ARDUINO_TEENSY40)
  1. digital.c - have the pin table digital_pin_bitband_and_config_table_struct defined with weak attribute.

  2. XBAR - define the table as attribute weak likewise the count variable.

  3. PWM table - weak

  4. Analog table - weak

  5. Serial objects - this was a little more complex - Simply put, I defined the Serial objects, using
    a set of defines: Which allow the variant to define them first. Example Serial1

#ifndef SERIAL1_RX_PINS 
#define SERIAL1_UART_ADDR IMXRT_LPUART6_ADDRESS
#define SERIAL1_LPUART IRQ_LPUART6, CCM_CCGR3, CCM_CCGR3_LPUART6(CCM_CCGR_ON),	XBARA1_OUT_LPUART6_TRG_INPUT
#define SERIAL1_CTS_PIN 0xff, 0 
#if defined(ARDUINO_TEENSY41)
#define SERIAL1_RX_PINS {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {52, 2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 0}}
#define SERIAL1_TX_PINS {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {53, 2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 0}}
#else
#define SERIAL1_RX_PINS {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}
#define SERIAL1_TX_PINS {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}
#endif
#endif
...
const HardwareSerialIMXRT::hardware_t Serial1_Hardware = {
	0, 
	&IRQHandler_Serial1, 
	&serialEvent1,
	IRQ_PRIORITY, 38, 24, // IRQ, rts_low_watermark, rts_high_watermark
	// Stuff that can be overwritten easily by variant
	SERIAL1_LPUART, SERIAL1_RX_PINS, SERIAL1_TX_PINS, SERIAL1_CTS_PIN
};
HardwareSerialIMXRT Serial1(SERIAL1_UART_ADDR, &Serial1_Hardware, tx_buffer1,
	SERIAL1_TX_BUFFER_SIZE, rx_buffer1, SERIAL1_RX_BUFFER_SIZE);

Pin Names - I checked this in to play with but obviously optional.
There are times when I wish to set the state of a pin that is not in the pin table. I have found it useful on some of the Arduino boards that support something like that as well. Often times they include names that match their MicroPython or CircuitPython pin names.

So I created an enum with all of the pin names like: AD_B0_00 and their values is actually the offset in address for this
pins from the start of a main section. The actual addresses for registers and the like can be computed.
With this I have stuff in the header file that allows me to do something like: pinMode(AD_B0_00, OUTPUT);
digitalWrite(AD_B0_00, HIGH);

I have variants defined using all of this up in the github project:
https://github.com/KurtE/teensy4_variant_experiment

Where I defined variants for DB4 and DB5, which appear to be working reasonably well.
One issue we have is with the Teensly loader. The arduino 2.x setup does not want to reboot and program the boards if we have the Teensy Serial port selected, however if we have the Arduino Serial port selected it does work.

There are a few of us like @mjs513 and myself who have been using this for awhile now, and a few others are now trying
it with the DB5 board.

Thought it would be great if we could get some or all of this into an early beta build for the next Teensyduino release.

EDIT: Note - I have also updated the Flexio_t4 library to not include pin tables per different teensy boards, instead it has a
table of all of the possible Flexio pins, and when you pass in a pin number, I map that to one of the registers associated with
that IO pin and look it up in the flexio table.

Likewise in our teensy_camera library (https://github.com/mjs513/Teensy_Camera) I have similar table, that maps
IO pins to CSI pins.

Kurt

@mjs513
Copy link
Contributor

mjs513 commented Aug 2, 2024

@PaulStoffregen
Just to confirm I have been using @KurtE variant core since he put it together for all the testing I have been doing with Teensy Camera and the SDRAM Variant board testing and haven't run into an issue with it yet.

PaulStoffregen and others added 4 commits August 12, 2024 14:57
Before there were two different begin Methods that were wrappers
to the c begin and format functions.  The code that checked for SerialEvent being defined
in a sketch was only in the begin method where format was not passed in.

Changed these to have only one begin method, with an optional format descriptor
If format is not specified I pass in: (uint32_t)-1 which the begin method checks
for if it is -1 format is not called otherwise it is.

Note: with T4.x the default was always 0 and the format code was always done, but did not want to this here on the off chance there are T3.x sketches out there where
maybe the first call SerialX.begin(baud, some-not-default-format)... and later call
SerialX.begin(baud), and expected the format not to change.
Copy link
Contributor

@sndsgd sndsgd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to hear some feedback from @PaulStoffregen before devoting too much effort into this, as I'm not sure how likely he is to allow changes of this nature.

That said, I'm currently down a rabbit hole of mapping pins to peripherals from the reference manual so a variant can be generated from a list of RT1062 pads. I think adopting such a strategy could also be used to migrate the existing teensy4 versions to variant-esque code to streamline things a bit, but I'm not really that far down the hole yet.

@@ -47,8 +47,11 @@
#define FALLING 2
#define RISING 3


#if defined(__IMXRT1062__) && defined(ARDUINO_TEENSY40)
#if __has_include("variant.h")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this pattern is reasonable, and I'd go so far as to say it should probably be adopted everywhere you see these if defined(__IMXRT1062__) && defined(ARDUINO_TEENSY...) blocks, and recommended for external libraries (example in flasherx).

That said, it seems like variant.h could use a little more precision. How do you feel about something like teensy4_custom_variant.h?

#define SERIAL1_RX_PINS {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {52, 2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 0}}
#define SERIAL1_TX_PINS {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {53, 2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 0}}
#else
#define SERIAL1_RX_PINS {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT the serial instances are just handed out in the order the pins are defined. So if I routed LPUART4 to pins 1 and 0, those should be associated with Serial1.

It might make sense to create some more defines so custom boards can do the same?

#define SERIAL1_UART                LPUART6
#define SERIAL1_UART_ADDR           IMXRT_LPUART6_ADDRESS
#define SERIAL1_UART_OPTIONS        IRQ_LPUART6, CCM_CCGR3, CCM_CCGR3_LPUART6(CCM_CCGR_ON), XBARA1_OUT_LPUART6_TRG_INPUT
#define SERIAL1_TX_PIN              1
#define SERIAL1_RX_PIN              0
#define SERIAL1_CTS_PIN             0xff
#define SERIAL1_RTS_PIN             0xff
#define SERIAL1_TX_SELECT_INPUT     &IOMUXC_LPUART6_TX_SELECT_INPUT
#define SERIAL1_RX_SELECT_INPUT     &IOMUXC_LPUART6_RX_SELECT_INPUT
#define SERIAL1_ALT_TX_PIN          0xff
#define SERIAL1_ALT_RX_PIN          0xff
#define SERIAL1_ALT_CTS_PIN         0xff
#define SERIAL1_ALT_RTS_PIN         0xff
#define SERIAL1_ALT_TX_SELECT_INPUT nullptr
#define SERIAL1_ALT_RX_SELECT_INPUT nullptr

KurtE and others added 10 commits September 10, 2024 13:12
Note this is probably only temporarily hosted here.
Before there were two different begin Methods that were wrappers
to the c begin and format functions.  The code that checked for SerialEvent being defined
in a sketch was only in the begin method where format was not passed in.

Changed these to have only one begin method, with an optional format descriptor
If format is not specified I pass in: (uint32_t)-1 which the begin method checks
for if it is -1 format is not called otherwise it is.

Note: with T4.x the default was always 0 and the format code was always done, but did not want to this here on the off chance there are T3.x sketches out there where
maybe the first call SerialX.begin(baud, some-not-default-format)... and later call
SerialX.begin(baud), and expected the format not to change.
Added  parameter to attachRts that if set will invert the signals:
```
bool attachRts(uint8_t pin, bool invert_signal=false);
```

This should allow more flexability in connecting two teensy 4.x boards to each other and using the CTS/RTS between the two boards for flow control.

This is in response to the thread:
https://forum.pjrc.com/index.php?threads/teensy-4-0-4-1-serial1-attachcts.75899/#post-350107

Where I felt somewhat strange to require somone to have to use hardware inverters to do this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants