Teensy 3 using IO pins

Status
Not open for further replies.

kriko

New member
Hello!

I've cooked a quick example, which sets bits on port C, pin 13 (LED):
Code:
void setup() {
  //set pins to output
  pinMode(13, OUTPUT);
}

void loop(void) {
//   digitalWrite(13, HIGH);
  PORTC |= (1<<5);
  delay(500);
//   digitalWrite(13, LOW);
  PORTC &= ~(1<<5);
  delay(500);
}

Acording to Teensy 3 schematics:
http://www.pjrc.com/teensy/schematic.html

pin 13 should be on 5th bit of PORTC, unfortunately this doesn't work. What could be the problem?
 
pin 13 should be on 5th bit of PORTC, unfortunately this doesn't work. What could be the problem?

The AVR emulation is actually mapped to Arduino Uno's pinout (as almost all Arduino code with hard-coded I/O assumes that pinout), not the native Freescale pins as shown on the schematic.

The above code would need PORTB |= (1<<5). (but really, you should avoid AVR-like I/O)

For Teensy 3.0, there is a digitalWriteFast(pin, value) function that will compile to the fastest possible ARM code using only a single bus cycle. If fact, if you look inside the AVR emulation code, you'll see the PORT registers are emulated by translating your code into digitalWriteFast(). If you look deeper, you'll see digitalWriteFast() is an optimized inline function that always compiles to a single bus cycle when both inputs are constants.

Since digitalWriteFast(pin, value) is the same as PORT |= (1<<pin) on Teensy 3.0, you might as well use the nicer, self-documenting digitalWriteFast() many much more portable function. The AVR emulation is mainly intended to allow Arduino programs hard-coded for Arduino Uno or other 328-based boards to run without modification.
 
Also, if you really wanted to use truly native code, on these Freescale ARM parts the native code would be:

GPIOC_PSOR = (1<<5); // pin high

GPIOC_PCOR = (1<<5); // pin low

Notice there's not |= or &= operations. These registers are documented in the MK20DX128 manual, which you can get here.

http://www.pjrc.com/teensy/datasheets.html

Look at section 47.2.2 on page 1182 for the GPIOx_PSOR, and the next page for the clear register.

However, I highly recommend you use digitalWriteFast(pin, value) in your code. It really does compile to this native operation, without cluttering your code with hardware registers. It will also port nicely to future Teensy boards, and be easily adaptable to other Arduino-compatible boards. Native register access makes for difficult porting later....
 
Last edited:
Thank you very much for detailed explanation.
I was using native code for faster bit writing (on arduino). I'm working with shift registers which use 3 pins - clock, latch, data and using the bitSet / bitClear was much faster way to send bits to them.
Will try now digitalWriteFast.

Thanks again!
 
Hello Paul, I have a question? I'm trying to optimize this UTFT library for Teensy 3.0 & I was wondering what is the fastest way to write to 16 i/o pins at once? Currently I have been using digitalWriteFast() like such

((cl & 0x01)) ? digitalWriteFast(PIN0, HIGH) : digitalWriteFast(PIN0, LOW);
((cl & 0x02)) ? digitalWriteFast(PIN1, HIGH) : digitalWriteFast(PIN1, LOW);
((cl & 0x04)) ? digitalWriteFast(PIN2, HIGH) : digitalWriteFast(PIN2, LOW);
((cl & 0x08)) ? digitalWriteFast(PIN3, HIGH) : digitalWriteFast(PIN3, LOW);
((cl & 0x10)) ? digitalWriteFast(PIN4, HIGH) : digitalWriteFast(PIN4, LOW);
((cl & 0x20)) ? digitalWriteFast(PIN5, HIGH) : digitalWriteFast(PIN5, LOW);
((cl & 0x40)) ? digitalWriteFast(PIN6, HIGH) : digitalWriteFast(PIN6, LOW);
((cl & 0x80)) ? digitalWriteFast(PIN7, HIGH) : digitalWriteFast(PIN7, LOW);
((ch & 0x01)) ? digitalWriteFast(PIN8, HIGH) : digitalWriteFast(PIN8, LOW);
((ch & 0x02)) ? digitalWriteFast(PIN9, HIGH) : digitalWriteFast(PIN9, LOW);
((ch & 0x04)) ? digitalWriteFast(PIN10, HIGH) : digitalWriteFast(PIN10, LOW);
((ch & 0x08)) ? digitalWriteFast(PIN11, HIGH) : digitalWriteFast(PIN11, LOW);
((ch & 0x10)) ? digitalWriteFast(PIN12, HIGH) : digitalWriteFast(PIN12, LOW);
((ch & 0x20)) ? digitalWriteFast(PIN13, HIGH) : digitalWriteFast(PIN13, LOW);
((ch & 0x40)) ? digitalWriteFast(PIN14, HIGH) : digitalWriteFast(PIN14, LOW);
((ch & 0x80)) ? digitalWriteFast(PIN15, HIGH) : digitalWriteFast(PIN15, LOW);

I was thinking you could use a version of what you said above like such:
GPIOC_PSOR = (cl << PIN0);
GPIOC_PCOR = (!cl << PIN0);
or something similar?
 
Hello Paul, I have a question? I'm trying to optimize this UTFT library for Teensy 3.0 & I was wondering what is the fastest way to write to 16 i/o pins at once? Currently I have been using digitalWriteFast() like such

((cl & 0x01)) ? digitalWriteFast(PIN0, HIGH) : digitalWriteFast(PIN0, LOW);
((cl & 0x02)) ? digitalWriteFast(PIN1, HIGH) : digitalWriteFast(PIN1, LOW);
((cl & 0x04)) ? digitalWriteFast(PIN2, HIGH) : digitalWriteFast(PIN2, LOW);
((cl & 0x08)) ? digitalWriteFast(PIN3, HIGH) : digitalWriteFast(PIN3, LOW);
((cl & 0x10)) ? digitalWriteFast(PIN4, HIGH) : digitalWriteFast(PIN4, LOW);
((cl & 0x20)) ? digitalWriteFast(PIN5, HIGH) : digitalWriteFast(PIN5, LOW);
((cl & 0x40)) ? digitalWriteFast(PIN6, HIGH) : digitalWriteFast(PIN6, LOW);
((cl & 0x80)) ? digitalWriteFast(PIN7, HIGH) : digitalWriteFast(PIN7, LOW);
((ch & 0x01)) ? digitalWriteFast(PIN8, HIGH) : digitalWriteFast(PIN8, LOW);
((ch & 0x02)) ? digitalWriteFast(PIN9, HIGH) : digitalWriteFast(PIN9, LOW);
((ch & 0x04)) ? digitalWriteFast(PIN10, HIGH) : digitalWriteFast(PIN10, LOW);
((ch & 0x08)) ? digitalWriteFast(PIN11, HIGH) : digitalWriteFast(PIN11, LOW);
((ch & 0x10)) ? digitalWriteFast(PIN12, HIGH) : digitalWriteFast(PIN12, LOW);
((ch & 0x20)) ? digitalWriteFast(PIN13, HIGH) : digitalWriteFast(PIN13, LOW);
((ch & 0x40)) ? digitalWriteFast(PIN14, HIGH) : digitalWriteFast(PIN14, LOW);
((ch & 0x80)) ? digitalWriteFast(PIN15, HIGH) : digitalWriteFast(PIN15, LOW);

I was thinking you could use a version of what you said above like such:
GPIOC_PSOR = (cl << PIN0);
GPIOC_PCOR = (!cl << PIN0);
or something similar?

Hi
Compiling my code cannot recognise the compiler the labels: PIN0, PIN1, PIN2....

How are mapped those GPIO in Teensy 3.0 ? Which labels are usable?

Regards
 
Use just "0" instead of "PIN0".

Code:
((cl & 0x01)) ? digitalWriteFast(0, HIGH) : digitalWriteFast(0, LOW);
((cl & 0x02)) ? digitalWriteFast(1, HIGH) : digitalWriteFast(1, LOW);
((cl & 0x04)) ? digitalWriteFast(2, HIGH) : digitalWriteFast(2, LOW);
((cl & 0x08)) ? digitalWriteFast(3, HIGH) : digitalWriteFast(3, LOW);
 
Dear Paul,

Would the use of registers not be preferable when controlling multiplexers? When going from one state to the other you will have intermediate states, which you might not want, when using digitalWrite. Would using GPIOx_PDOR change the pins simultaneously? This would be useful especially when scanning....

Best, Hans.
 
I was wondering what is the fastest way to write to 16 i/o pins at once?

One fast way is to map the data port to PTD0..PTD7 (see http://forum.pjrc.com/attachment.php?attachmentid=1847&d=1398128869) and write to to the screen using macros such as

Code:
#define _write8bCommand(cmd) { \
    digitalWriteFast(GRAPHICS_HARDWARE_CD_PIN, 0);\
    *(volatile uint8_t *)(&GPIOD_PDOR) = (cmd); \
    digitalWriteFast(GRAPHICS_HARDWARE_WR_PIN, 0);\
    asm("nop"); \
    digitalWriteFast(GRAPHICS_HARDWARE_WR_PIN, 1);\
    digitalWriteFast(GRAPHICS_HARDWARE_CD_PIN, 1);\
}

Using 8b data, with such code, you can fill a 240x320 screen in less than 6ms at 144Mhz.
You could also use 2 ports such as PTD0..PTD7 and PTC0..PTC7 to build your 16b data if you don't need these pin functions.
 
Status
Not open for further replies.
Back
Top