Teensy 4.0 and 4.1 pin 16 input using assembler

clivets

Member
Hello,

I am using a Teensy 4.0 to read a 10bit ADC. I am using pins AD_B1_00 to AD_B1_11(AD_B1_04 and AD_B1_05 are not available on Teensy 4.0) as data inputs.

I am reading the ADC in assembler for maximum speed.

I am having trouble setting up pin 16 as an input. I can set up all the other pins but pin 16 seems to stay as an output.

The code below is a test. I have used it to test the pins individually. I have also used a new Teensy 4.1 with the same result.

GPIO6_DR = 0x42000000
GPIO6_GDIR = 4

GPIO7_DR = 0x42004000
GPIO7_GDIR = 4

IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x401F813C

IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_00 = 0x401F832C

IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_00 = 0x401F80FC

IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00 = 0x401F82EC
B0_00 = 0
B0_01 = 4
B0_02 = 8
AD_B1_00 = 0
AD_B1_01 = 4
AD_B1_02 = 8
AD_B1_03 = 12
AD_B1_04 = 16
AD_B1_05 = 20
AD_B1_06 = 24
AD_B1_07 = 28
AD_B1_08 = 32
AD_B1_09 = 36
AD_B1_10 = 40
AD_B1_11 = 44
IOMUXC_GPR_GPR26 = 0x400AC068
IOMUXC_GPR_GPR27 = 0x400AC06C
ARM_DWT_CYCCNT = 0xE0001004

.global ASMprog

.syntax unified
.cpu cortex-m7
.type ASMprog,%function
.align 4

ASMprog:
.fnstart
push {r2-r12,lr}

// Select GPIO function on pin 10,11,12 (5 selects GPIO mode)
ldr r1,=IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00
///////////5432109876543210 31-5 NU, 4 SION, 3-0 MUX_MODE
movw r0,#0b0000000000000101//ALT5 mux port:GPIO2_IO00 of instance: gpio2
str r0,[r1,#B0_00] //Pin 10 ALT5 mux port:GPIO2_IO00
str r0,[r1,#B0_02] //Pin 11 ALT5 mux port:GPIO2_IO02
str r0,[r1,#B0_01] //Pin 12 ALT5 mux port:GPIO2_IO01

// Select GPIO function on pin 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 (5 selects GPIO mode)
ldr r1,=IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_00
///////////5432109876543210 31-5 NU, 4 SION, 3-0 MUX_MODE
movw r0,#0b0000000000000101//ALT5 mux port:GPIO1_IO16 of instance: gpio1
str r0,[r1,#AD_B1_00] //Pin 19 ALT5 mux port:GPIO1_IO16
str r0,[r1,#AD_B1_01] //Pin 18 ALT5 mux port:GPIO1_IO17
str r0,[r1,#AD_B1_02] //Pin 14 ALT5 mux port:GPIO1_IO18
str r0,[r1,#AD_B1_03] //Pin 15 ALT5 mux port:GPIO1_IO19
str r0,[r1,#AD_B1_06] //Pin 17 ALT5 mux port:GPIO1_IO22
str r0,[r1,#AD_B1_07] //Pin 16 ALT5 mux port:GPIO1_IO23
str r0,[r1,#AD_B1_08] //Pin 22 ALT5 mux port:GPIO1_IO24
str r0,[r1,#AD_B1_09] //Pin 23 ALT5 mux port:GPIO1_IO25
str r0,[r1,#AD_B1_10] //Pin 20 ALT5 mux port:GPIO1_IO26
str r0,[r1,#AD_B1_11] //Pin 21 ALT5 mux port:GPIO1_IO27

// Optimise for 100MHz range, 34-23 Ohm o/p resistance @ 3.3V, Fast slew rate
ldr r1,=IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_00
///////////10987654321098765432109876543210 31-17 NU, 16 HYS 15-14 PUS, 13 PUE, 12 PKE, 11 ODE, 10-8 NU, 7-6 SPEED, 5-3 DSE, 2-1 NU 0 SRE
ldr r0,=#0b00000000000000000001000010111001
str r0,[r1,#B0_00] //Pin 10
str r0,[r1,#B0_02] //Pin 11
str r0,[r1,#B0_01] //Pin 12

// Optimise for 100MHz range, 34-23 Ohm o/p resistance @ 3.3V, Fast slew rate
ldr r1,=IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00
///////////10987654321098765432109876543210 31-17 NU, 16 HYS 15-14 PUS, 13 PUE, 12 PKE, 11 ODE, 10-8 NU, 7-6 SPEED, 5-3 DSE, 2-1 NU 0 SRE
ldr r0,=#0b00000000000000000001000010111001
str r0,[r1,#AD_B1_00] //Pin 19 ALT5 mux port:GPIO1_IO16
str r0,[r1,#AD_B1_01] //Pin 18 ALT5 mux port:GPIO1_IO17
str r0,[r1,#AD_B1_02] //Pin 14 ALT5 mux port:GPIO1_IO18
str r0,[r1,#AD_B1_03] //Pin 15 ALT5 mux port:GPIO1_IO19
str r0,[r1,#AD_B1_06] //Pin 17 ALT5 mux port:GPIO1_IO22
str r0,[r1,#AD_B1_07] //Pin 16 ALT5 mux port:GPIO1_IO23
str r0,[r1,#AD_B1_08] //Pin 22 ALT5 mux port:GPIO1_IO24
str r0,[r1,#AD_B1_09] //Pin 23 ALT5 mux port:GPIO1_IO25
str r0,[r1,#AD_B1_10] //Pin 20 ALT5 mux port:GPIO1_IO26
str r0,[r1,#AD_B1_11] //Pin 21 ALT5 mux port:GPIO1_IO27


ldr r1,=IOMUXC_GPR_GPR26// Connect high speed GPIO6 not GPIO1 to pins
ldr r0,=0xFFFFFFFF
str r0,[r1]
ldr r1,=IOMUXC_GPR_GPR27// Connect high speed GPIO7 not GPIO2 to pins
ldr r0,=0xFFFFFFFF
str r0,[r1]

ldr r11,=GPIO6_DR //GPIO6 base address
///////////10987654321098765432109876543210
ldr r8,=#0b00000000000000000000000000000000
str r8,[r11,#GPIO6_GDIR]
//Pin 19 AD_B1_00 GPIO1_IO16 - Input
//Pin 18 AD_B1_01 GPIO1_IO17 - Input
//Pin 14 AD_B1_02 GPIO1_IO18 - Input
//Pin 15 AD_B1_03 GPIO1_IO19 - Input
//Pin 17 AD_B1_06 GPIO1_IO22 - Input
//Pin 16 AD_B1_07 GPIO1_IO23 - Input
//Pin 22 AD_B1_08 GPIO1_IO24 - Input
//Pin 23 AD_B1_09 GPIO1_IO25 - Input
//Pin 20 AD_B1_10 GPIO1_IO26 - Input
//Pin 21 AD_B1_11 GPIO1_IO27 - Input

ldr r12,=GPIO7_DR //GPIO7 base address
///////////5432109876543210
movw r8,#0b0000000000000001
str r8,[r12,#GPIO7_GDIR]
//Pin 10 B0_00 - Output
//pin 12 B0_01 - Input
//pin 11 B0_02 - Input

ldr r7,=0
ldr r8,=1

Loop:
str r7,[r12] //pin 10 low
LoopL:
ldr r9,[r11] //Read port
//////////10987654321098765432109876543210
tst r9,#0b00001000000000000000000000000000
beq LoopL

str r8,[r12] //pin 10 high
LoopH:
ldr r9,[r11] //Read port
//////////10987654321098765432109876543210
tst r9,#0b00001000000000000000000000000000
bne LoopH
b Loop

pop {r2-r12,pc}
bx lr // Return by branching to the address in the link register.


.fnend


Any help would be much appreciated.

Clive
 
Using the included Teensy ADC library will give a full range of pins and adjustments in a library.

Most of the time for ADC reading is waiting for the sample to complete with a data value - then retrigger and wait.

The ADC library can use one or two channels and use DMA and other features to maximize the read rate.
 
I can set up all the other pins but pin 16 seems to stay as an output.

What specifically are you observing which indicates pin 16 is an output?

For example, lack of response to applied signals is a very different observation than connecting a resistor divider and measuring either 0 or 3.3V instead of 1.65 volts. We can't see what you're doing. How you actually tested and what you actually saw matters for helping solve the problem.


The code below is a test.

If you will post in a form I can copy into Arduino and quickly run on a Teensy 4.1 without guesswork to recreate the same test, I'll give it a quick try.


Otherwise, all I can do is blind guesswork (sorry, not going to spend a lot of time trying to run a code fragment). So here's some guesses...

Move the GPR writes to the beginning. May be a lag from a instruction which writes these until the hardware is actually reconfigured.

Might need to set the SION bit. Will admit, it's been years since I wrote the earliest code. As I recall, input mode worked without it, but we still needed SION set for something. As you can see in the pinMode() source code, we're setting always the SION bit for GPIO usage on Teensy 4.

Whether assembly is actually any faster than C / C++ is debatable. The compiler will generate similar code as you've shown here. This code fragment doesn't seem to use the ADC at all. But when you do use the ADC, dealing with the complexity of using both ADCs in parallel will be much harder in assembly than C. Even if all the trouble to use assembly is worthwhile for tight loops, it's certainly not needed for initializing the hardware. Well, unless this is some sort of academic project which requires assembly for the sake of learning (and even then, mixing C / C++ and assembly is a far more valuable skill than 100% assembly).
 
Hello, thanks for your reply,

Sorry if it was not clear, the code I have shown is a test, I just want to make sure all the inputs are working.

I am using platformIO IDE, the main.cpp file is:

#include <Arduino.h>

extern "C" void ASMprog();

void setup()
{
}

void loop()
{
noInterrupts();
ASMprog();
}

The ASMprog.S file is as I posted.

I am testing the inputs one at a time by running the program and looking at pin 10 with an oscilloscope while trying to pull the input high and low.

The assembler code I have posted is for testing Pin 21 GPIO1_IO27.

If I want to test Pin 16 GPIO1_IO23 I change the code to:

Loop:
str r7,[r12] //pin 10 low
LoopL:
ldr r9,[r11] //Read port
//10987654321098765432109876543210
tst r9,#0b00000000100000000000000000000000
beq LoopL

str r8,[r12] //pin 10 high
LoopH:
ldr r9,[r11] //Read port
//10987654321098765432109876543210
tst r9,#0b00000000100000000000000000000000
bne LoopH
b Loop

It just seems strange why all the other pins work as expected except for pin 16.

I am using the Teensy 4 and a AD9203 10bit ADC to read a 5MHz signal. The signal is transmitted in 100ms bursts. When the start of a burst is detected, I sample the signal and store the values using the fastest loop I can. I should be able to sample the 5MHz signal at 35 to 40MSPS. I will then process the samples using DSP methods to demodulate the signal. This will all be done in assembler.

I think this project is just possible now using the amazing speed of the i-mx RT 1062, and the cost/size of the Teensy 4 modules. if not I will have to try to learn how to use FPGA. Although I don't think the cost and current consumption of FPGA would compare.

If I can get this working, I will be purchasing many TEENSY41_NE_LOCK modules to sell in my products.

Clive

 
'Might need to set the SION bit. Will admit, it's been years since I wrote the earliest code. As I recall, input mode worked without it, but we still needed SION set for something. As you can see in the pinMode() source code, we're setting always the SION bit for GPIO usage on Teensy 4'

I have just looked up the SION bit in the i.MX RT1060X Processor Reference Manual, yes that looks promising, I will try that.

Clive
 
Back
Top