Teensy 4.0 & 4.1

Discussion and questions about boards that can run MicroPython but don't have a dedicated forum.
Target audience: Everyone interested in running MicroPython on other hardware.
KurtE
Posts: 11
Joined: Mon Mar 28, 2022 1:52 pm

Re: Teensy 4.0 & 4.1

Post by KurtE » Thu Apr 21, 2022 8:14 pm

That appeared to work, I now have the new Branch in my Fork:
https://github.com/KurtE/circuitPython/ ... python_dev

One interesting side effect, is Adafruit's code checks run on this branch as well, even though this branch will not be PR'd into CircuitPython...

In this branch I have a version of the Micromod that appears to build and run. For example this blinks the LED

Code: Select all

>>> import machine
>>> from machine import Pin
>>> led = Pin('LED', Pin.OUT)
>>> led.on()
>>> led.off()
>>> import time
>>> for i in range(10):
...     time.sleep_ms(250)
...     led.on()
...     time.sleep_ms(250)
...     led.off()
...
>>>
Note: I also made some small tweaks to the T4 and T4.1 stuff, like T4.1 has a few more Analog pins than T4 does.

Also the command line for teensy_loader_cli was wrong for T4.1. Also experimenting with adding the TX1-7(8) RX1-7(8) pin names like @mjs513 and myself added to the CircuitPython code.

One of the next things I may try to figure out, is. Is there a dictionary or the like, that I can enumerate to know which pins may be defined for a particular board? Is there a way to deduce if multiple logical names map to the same physical name.

For example: I have check_pins sketch for CircuitPython, that loops through the logical names and comes up with list of unique pins, and then allows me to Pull up all of the pins high and then check to see if any of the pins register low (jumper from GND to pin), and if so then print out which pins have changed state...

Code: Select all

import board, busio, digitalio, time, supervisor
from microcontroller import Pin
from digitalio import DigitalInOut, Direction, Pull

#led = digitalio.DigitalInOut(board.LED)
#led.direction = digitalio.Direction.OUTPUT

# lets first get a list of the boards pins
# temporary exclude led
exclude = ['USB_HOST_DM', 'USB_HOST_DP', 'USB_HOST_POWER', 'LED']
all_pins = {}
print_progress_dots = False

pull_up_or_down = Pull.UP  #default first pass to do Pullup


class pinNamesRecord(object):
    def __init__(self, pin, pin_name):
        self.pin = pin
        self.pin_names = pin_name
        self.last_check = True

def print_pin_table():
    print("\nEnum pin list")
    print("Physical Pins\tLogical Names")
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        print(pin_entry, "\t", pny.pin_names)

def UpdatePullUpDown():
    print()
    if pull_up_or_down == Pull.UP:
        print("Setting all pins to PULL up - so test by jumpering pins to GND")
        last_check = True
    else:
        print("Setting all pins to PULL down - so test by jumpering pins to +3.3v")
        last_check = False
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        pny.pin.pull = pull_up_or_down
        pny.last_check = last_check
    time.sleep(0.25)

for board_item in dir(board):
    if board_item not in exclude:
        item_attr = getattr(board, board_item)
        if isinstance(item_attr, Pin):
            #print("Check pin: ", board_item, "(",item_attr, ")")
            pin_str = str(item_attr)
            #has names like: board.D33
            pin_str = pin_str[6:] #remove board.
            if pin_str in all_pins:
                if pin_str != board_item:
                    pnr = all_pins[pin_str]
                    pnr.pin_names = pnr.pin_names + ' ' + board_item
                    all_pins[pin_str] = pnr
                    #print("\tDup: ", pnr.pin_names)
            else:
                # new one
                iopin = DigitalInOut(item_attr)
                iopin.direction = Direction.INPUT
                iopin.pull = Pull.UP
                if board_item == pin_str:
                    add_str = board_item
                else:
                    add_str = pin_str + ' ' + board_item
                pnr = pinNamesRecord(iopin, add_str)
                all_pins[pin_str] = pnr
                #print("\tnew: ", pnr.pin_names)
UpdatePullUpDown()
#print_pin_table()
print("A Python version of the Pin High/Low test")
print("Simple keyboard interface")
print("\tEmpty line, will toggle between IO pins Pulled UP and Pulled Down")
print("\tp - print pin table out showing all pin names for pin")
print("\t. - will toggle printing progress dots on or off")

loop_count_no_changes = 0
while True:
    #check for User Input
    if supervisor.runtime.serial_bytes_available:
        text = input()
        print("*** Serial input ***", text)
        if text == 'p' or text == 'P':
            print_pin_table()
        elif text == '.':
            if print_progress_dots:
                print_progress_dots = False
                print("** Turned off progress dots ***")
            else:
                print_progress_dots = True
                print("** Turned off progress dots ***")
        else:
            if pull_up_or_down == Pull.UP:
                pull_up_or_down = Pull.DOWN
            else:
                pull_up_or_down = Pull.UP

            UpdatePullUpDown()
    # scan the pins
    pin_changed = False
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        new_pin_value = pny.pin.value
        if new_pin_value != pny.last_check:
            if loop_count_no_changes:
                loop_count_no_changes = 0
                if print_progress_dots:
                    print()
            pny.last_check = new_pin_value
            if pny.last_check:
                print("HIGH: ", end='')
            else:
                print("LOW: ", end='')
            print(pny.pin_names)
            pin_changed = True
    if pin_changed == False:
        loop_count_no_changes += 1
        if loop_count_no_changes < 320:
            if (loop_count_no_changes & 7) == 0:
                if print_progress_dots:
                    print('.', end='')
        else:
            if print_progress_dots:
                print('.')
            loop_count_no_changes = 0

    time.sleep(0.25)
Sorry I know this is probably not great code as Python is not my native language. But using this as example on how to do things in both platforms.

Thanks again.

Edit: progress in my understanding

Code: Select all

>>> import machine
>>> for bi in dir(machine.Pin.board):
...     print(bi, "->", getattr(machine.Pin.board, bi))
...
Partial output:

Code: Select all

A0 -> Pin(GPIO_AD_B1_02)
A1 -> Pin(GPIO_AD_B1_03)
A10 -> Pin(GPIO_AD_B0_12)
A11 -> Pin(GPIO_AD_B0_13)
A12 -> Pin(GPIO_AD_B1_14)
A13 -> Pin(GPIO_AD_B1_15)
A2 -> Pin(GPIO_AD_B1_07)
A3 -> Pin(GPIO_AD_B1_06)
A4 -> Pin(GPIO_AD_B1_01)
A5 -> Pin(GPIO_AD_B1_00)
A6 -> Pin(GPIO_AD_B1_10)
A7 -> Pin(GPIO_AD_B1_11)
A8 -> Pin(GPIO_AD_B1_08)
A9 -> Pin(GPIO_AD_B1_09)
CLK -> Pin(GPIO_SD_B0_01)
CMD -> Pin(GPIO_SD_B0_00)
D0 -> Pin(GPIO_AD_B0_03)
D1 -> Pin(GPIO_AD_B0_02)

KurtE
Posts: 11
Joined: Mon Mar 28, 2022 1:52 pm

Re: Teensy 4.0 & 4.1

Post by KurtE » Fri Apr 22, 2022 1:38 am

Not sure if this is interesting, but making progress with the check pins...

Current version:

Code: Select all

import machine
import time
import select
import sys
from machine import Pin
board = Pin.board

exclude = ['__class__ ', '__name__', '__bases__', '__dict__']
all_pins = {}
print_progress_dots = False

pull_up_or_down = Pin.PULL_UP  #default first pass to do Pullup


class pinNamesRecord(object):
    def __init__(self, pin, pin_name):
        self.pin = pin
        self.pin_names = pin_name
        self.last_check = True

def print_pin_table():
    print("\nEnum pin list")
    print("Physical Pins\tLogical Names")
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        print(pin_entry, "\t", pny.pin_names)

def UpdatePullUpDown():
    print()
    if pull_up_or_down == Pin.PULL_UP:
        print("Setting all pins to PULL up - so test by jumpering pins to GND")
        last_check = True
    else:
        print("Setting all pins to PULL down - so test by jumpering pins to +3.3v")
        last_check = False
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        pin = pny.pin
        pin.init( mode=Pin.IN, pull=pull_up_or_down)
        pny.last_check = last_check
    time.sleep(0.25)

for board_item in dir(board):
    if board_item not in exclude:
        item_attr = getattr(board, board_item)
        pin_str = str(item_attr)
        if pin_str.startswith("Pin("):
            #print("Check pin: ", board_item, "(",item_attr, ")")
            #has names like: board.D33
            pin_str = pin_str[4:-1] #remove PIN( and trailing)
            if pin_str in all_pins:
                pnr = all_pins[pin_str]
                pnr.pin_names = pnr.pin_names + ' ' + board_item
                all_pins[pin_str] = pnr
            else:
                # new one
                #iopin = Pin(board_item, Pin.IN Pin.PULL_UP)
                iopin = item_attr
                iopin.init( mode=Pin.IN, pull=Pin.PULL_UP)
                add_str = board_item
                pnr = pinNamesRecord(iopin, add_str)
                all_pins[pin_str] = pnr

print_pin_table()

UpdatePullUpDown()
#print_pin_table()
print("A Python version of the Pin High/Low test")
print("Simple keyboard interface")
print("\tEmpty line, will toggle between IO pins Pulled UP and Pulled Down")
print("\tp - print pin table out showing all pin names for pin")
print("\t. - will toggle printing progress dots on or off")

loop_count_no_changes = 0
while True:
    #check for User Input
    avail = select.select([sys.stdin], [], [], 0)
    if avail != ([], [], []): #supervisor.runtime.serial_bytes_available:
        text = input()
        print("*** Serial input ***", text)
        if text == 'p' or text == 'P':
            print_pin_table()
        elif text == '.':
            if print_progress_dots:
                print_progress_dots = False
                print("** Turned off progress dots ***")
            else:
                print_progress_dots = True
                print("** Turned off progress dots ***")
        else:
            if pull_up_or_down == Pin.PULL_UP:
                pull_up_or_down = Pin.PULL_DOWN
            else:
                pull_up_or_down = Pin.PULL_UP

            UpdatePullUpDown()
    # scan the pins
    pin_changed = False
    for pin_entry in all_pins:
        pny = all_pins[pin_entry]
        new_pin_value = pny.pin.value()
        if new_pin_value != pny.last_check:
            if loop_count_no_changes:
                loop_count_no_changes = 0
                if print_progress_dots:
                    print()
            pny.last_check = new_pin_value
            if pny.last_check:
                print("HIGH: ", end='')
            else:
                print("LOW: ", end='')
            print(pny.pin_names)
            pin_changed = True
    if pin_changed == False:
        loop_count_no_changes += 1
        if loop_count_no_changes < 320:
            if (loop_count_no_changes & 7) == 0:
                if print_progress_dots:
                    print('.', end='')
        else:
            if print_progress_dots:
                print('.')
            loop_count_no_changes = 0

    time.sleep(0.25)

Test run on MicroMod:

Code: Select all


Enum pin list
Physical Pins   Logical Names
GPIO_AD_B0_13    A11 D25 MM_SDA1 RX6
GPIO_AD_B0_12    A10 D24 MM_SCL1 TX6
GPIO_EMC_29      QSPI_IO3
GPIO_EMC_28      QSPI_IO2
GPIO_AD_B1_09    A9 D23 MCK MM_MCLK
GPIO_AD_B1_08    A8 D22 MM_BATT_VIN3
GPIO_SD_B0_04    D39 DAT2 MM_DAT2
GPIO_SD_B0_05    D38 DAT3 MM_CS1 MM_DAT3
GPIO_SD_B0_02    D35 DAT0 MM_CIPO1 MM_DAT0
GPIO_EMC_08      D5 MM_D1
GPIO_AD_B1_07    A2 D16 MM_RX2 RX2
GPIO_AD_B1_06    A3 D17 MM_TX2 TX2
GPIO_EMC_05      D3 MM_PWM0 WS_TX
GPIO_EMC_04      D2 MM_PWM1 SD_TX
GPIO_EMC_22      FLASH_CS
GPIO_AD_B1_02    A0 D14 MM_A0 TX3
GPIO_AD_B1_01    A4 D18 MM_SDA
GPIO_EMC_07      D33 MM_G10
GPIO_EMC_06      D4 MM_D0 SCK_TX
GPIO_B0_11       D9 MM_G7
GPIO_B0_10       D6 MM_G6
GPIO_SD_B0_03    D34 DAT1 MM_DAT1
GPIO_B1_01       D7 MM_I2S_SDO RX4
GPIO_B1_00       D8 MM_I2S_SDI SD_RX TX4
GPIO_SD_B0_01    CLK D36 MM_SCK1
GPIO_B0_12       D32 MM_G9
GPIO_SD_B0_00    CMD D37 MM_COPI1
GPIO_AD_B1_00    A5 D19 MM_SCL
GPIO_AD_B1_03    A1 D15 MM_A1 RX3
GPIO_EMC_24      PSRAM_CS
GPIO_EMC_25      QSPI_CLK
GPIO_AD_B0_02    D1 MM_TX TX1
GPIO_AD_B0_03    D0 MM_RX RX1
GPIO_EMC_26      QSPI_IO0
GPIO_EMC_27      QSPI_IO1
GPIO_B0_06       D42 MM_G2
GPIO_B0_07       D43 MM_G3
GPIO_B0_04       D40 MM_G0
GPIO_B0_05       D41 MM_G1
GPIO_B0_02       D11 MM_COPI
GPIO_EMC_36      D31 MM_CAN_TX
GPIO_AD_B1_14    A12 D26 MM_G8
GPIO_AD_B1_15    A13 D27 MM_G11
GPIO_EMC_31      D29 MM_I2C_INT TX7
GPIO_EMC_32      D28 MM_33V_EN RX7
GPIO_AD_B1_10    A6 D20 MM_I2S_FS TX5 WS_RX
GPIO_AD_B1_11    A7 D21 MM_I2S_CLK RX5 SCK_RX
GPIO_EMC_37      D30 MM_CAN_RX
GPIO_B0_03       D13 LED MM_SCK
GPIO_B0_08       D44 MM_G4
GPIO_B0_09       D45 MM_G5
GPIO_B0_00       D10 MM_CS
GPIO_B0_01       D12 MM_CIPO

Setting all pins to PULL up - so test by jumpering pins to GND
A Python version of the Pin High/Low test
Simple keyboard interface
        Empty line, will toggle between IO pins Pulled UP and Pulled Down
        p - print pin table out showing all pin names for pin
        . - will toggle printing progress dots on or off
LOW: D3 MM_PWM0 WS_TX
HIGH: D3 MM_PWM0 WS_TX
LOW: D45 MM_G5
HIGH: D45 MM_G5
LOW: A13 D27 MM_G11
HIGH: A13 D27 MM_G11
LOW: D1 MM_TX TX1
HIGH: D1 MM_TX TX1
LOW: A9 D23 MCK MM_MCLK
HIGH: A9 D23 MCK MM_MCLK

Testing on a ATP board.

Next thing to figure out, On CircuitPython I could detect if there was Serial input available:
if supervisor.runtime.serial_bytes_available:
Now to figure out how to do on MicroPython... I know for some ports have pyb...
Edit - I knew I asked this before... Answer:
sys.stdin is a stream, so you can stream methods like select to check, whether something available:

Code: Select all

import select
import sys
avail = select.select([sys.stdin], [], [], 0)
Checks for data in sys.stdin. It will return ([], [], []) if no data is waiting and ([<io.FileIO 0>], [], []) if there is data.
EDIT2 - updated sketch with it

Online
User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Teensy 4.0 & 4.1

Post by Roberthh » Sat Apr 23, 2022 7:21 pm

One of the next things I may try to figure out, is. Is there a dictionary or the like, that I can enumerate to know which pins may be defined for a particular board? Is there a way to deduce if multiple logical names map to the same physical name.
There are the classes machine.Pin.board and machine.Pin.cpu with contain the pin objects at board or cpu level.

KurtE
Posts: 11
Joined: Mon Mar 28, 2022 1:52 pm

Re: Teensy 4.0 & 4.1

Post by KurtE » Sat Apr 23, 2022 8:34 pm

Roberthh wrote:
Sat Apr 23, 2022 7:21 pm
There are the classes machine.Pin.board and machine.Pin.cpu with contain the pin objects at board or cpu level.
Thanks!

I figured that out after posting it... And I Should have updated the post. The sketch in previous post uses that to build list of pins.

Thanks again

v923z
Posts: 168
Joined: Mon Dec 28, 2015 6:19 pm

Re: Teensy 4.0 & 4.1

Post by v923z » Mon May 16, 2022 6:56 pm

ryanGT wrote:
Sat Mar 12, 2022 8:48 pm
I was able to build micropython with ulab for teensy 4.1 without too much trouble.
I know that this is a somewhat old post, but I was wondering, whether you would care to add your build instructions here https://github.com/v923z/micropython-builder, so that other would profit from it.

toani
Posts: 1
Joined: Sat Jul 30, 2022 12:14 pm

Re: Teensy 4.0 & 4.1

Post by toani » Sat Jul 30, 2022 12:19 pm

Hi everyone.

Question. How do I transfer audio files from my computer to the SPI flash on the Audio Shield? I'm using the Teensy4.0 and I intend to use LFS. I used EraseEverything and CopyFromSD utilities but then ListFiles doesn't show any files. I'm assuming CopyFromSD is not creating a LFS system properly. What tool should I use?

Thanks!

Online
User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Teensy 4.0 & 4.1

Post by Roberthh » Sat Jul 30, 2022 12:55 pm

Assuming you have soldered a flash chip to the audio board, you can create a LFS file system using @pythoncoder's driver for flash at https://github.com/peterhinch/micropython_eeprom.git. I tried that and it worked. I made most of the tests with I2S with a SD card.

Online
User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Teensy 4.0 & 4.1

Post by Roberthh » Sat Jul 30, 2022 3:16 pm

I have to correct myseld. I tried the flash drive again, and it does not work. What works is the SD card, using the sdcard.py driver from the MicroPyhton repository. Then, you can mount the SD card with the little script below, giving you access to the files on the SD card at the directory /flash. The speed is high enough to play Stereo WAV files at a 44100 Hz sample rate.

Code: Select all

import os, sdcard, machine

spi = machine.SPI(0) # SPI0 with cs1 used for SDCARD
cs = machine.Pin(10, machine.Pin.OUT, value=1)
sd = sdcard.SDCard(spi, cs, baudrate=20_000_000)
vfs = os.VfsFat(sd)
os.mount(vfs, "/sdcard")

Online
User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Teensy 4.0 & 4.1

Post by Roberthh » Sat Jul 30, 2022 8:16 pm

Ok. I found the problem. It was with the flash chip I used, which requires a different option. To use the flash with a LFS file system, You need the files bdevice.py and flash_spi.py from @pythoncoder's repository. Then, you can use for instance the script below to mount the file system:

Code: Select all

import os
from machine import SPI, Pin
from flash_spi import FLASH
cspins=(Pin(6, Pin.OUT, value=1), )
spi=SPI(0, baudrate=10_000_000)
pp=Pin(10, Pin.OUT, value=1)
drive=FLASH(spi, cspins, cmd5=False)
try:
    os.mount(drive, "/audio")
except:
    print("Mount failed, format drive")
    os.VfsLfs2.mkfs(drive)
    os.mount(drive, "/audio")
When the flash is not yet formatted, the script will do so. The new filesystem is mounter at /audio. You can use any other name, except /flash. The 16MByte Flash I use requires the option cmd5=False in the line

drive=FLASH(spi, cspins, cmd5=False)

Other flash chips might not require that option, or the need it to be set as: cmd5=True.
Pin 10 is defined in the script as output, avoiding to being driven automatically by SPI. Then, you can use both flash and SDCard.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Teensy 4.0 & 4.1

Post by pythoncoder » Sun Jul 31, 2022 9:46 am

Roberthh wrote:
Sat Jul 30, 2022 8:16 pm
...
Other flash chips might not require that option, or the need it to be set as: cmd5=True...
As you may know, some chip designs use 4 byte commands and others use 5 bytes. Aside from studying the datasheet, trial and error with the cmd5 arg is required. Unless there is a way to query the chip to discover which command set it uses? Does anyone happen to know?
Peter Hinch
Index to my micropython libraries.

Post Reply