PDA

View Full Version : teensy 3 MAC address



cmason
11-06-2012, 09:10 AM
After a conversation with Paul, I think I've figured out how to access the unique Ethernet media access (MAC) address (http://en.wikipedia.org/wiki/MAC_address) burnt into the Teensy3. This number will be different on every teensy 3, and isn't overwritten by the bootloader flashing process like the EEPROM is.

Given this class:


/** Retrieve Ethernet MAC from Teensy 3 */
class mac_addr : public Printable {
public:
uint8_t m[6];

mac_addr() : m({0}) {
// Retrieve the 6 byte MAC address Paul burnt into two 32 bit words
// at the end of the "READ ONCE" area of the flash controller.
read(0xe,0);
read(0xf,3);
}

void read(uint8_t word, uint8_t loc) {

// To understand what's going on here, see
// "Kinetis Peripheral Module Quick Reference" page 85 and
// "K20 Sub-Family Reference Manual" page 548.

FTFL_FCCOB0 = 0x41; // Selects the READONCE command
FTFL_FCCOB1 = word; // read the given word of read once area
// -- this is one half of the mac addr.
FTFL_FSTAT = FTFL_FSTAT_CCIF; // Launch command sequence
while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {
// Wait for command completion
}
*(m+loc) = FTFL_FCCOB5; // collect only the top three bytes,
*(m+loc+1) = FTFL_FCCOB6; // in the right orientation (big endian).
*(m+loc+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0.
}

virtual size_t printTo(Print & p) const {
size_t count = 0;
for(uint8_t i = 0; i < 6; ++i) {
if (i!=0) count += p.print(":");
count += p.print((*(m+i) & 0xF0) >> 4, 16);
count += p.print(*(m+i) & 0x0F, 16);
}
return count;
}
};

You can print out the MAC like:

Serial.print("MAC: ");
mac_addr mac;
Serial.println(mac);

On mine, this prints:

MAC: 04:E9:E5:00:0D:59

I hope Paul can verify my work here. This number at least seems to line up with the PJRC IEEE registration (http://standards.ieee.org/cgi-bin/ouisearch?pjrc).

Hope this is useful.

-c

THT
12-25-2012, 07:25 PM
Thank you cmason. It works well for me. I removed the C++ stuff and made a small Ardiono Sketch (see attachment).

yeahtuna
12-10-2013, 02:55 AM
I just stumbled upon this. This is great as it can be used as copy protection system. Is there anything like this available on the Teensy 2?

stevech
12-10-2013, 04:04 AM
Is that an ethernet address or a generic IEEE OUI that's not coded as in the Ethernet MAC range?
IEEE 802.11 and 802.15.4 radios have a MAC in the OUI range, with MSBs to say which family.

This chip-unique number helps a great deal with devices like WizNet Ethernet devices that have no factory assigned MAC address.

PaulStoffregen
12-10-2013, 10:19 AM
Shortly before releasing Teensy 3.0, PJRC registered for an IEEE OUI usable for Ethernet. Every Teensy 3.0 and 3.1 has been programmed with this OUI and an incrementing 24 bit serial number. It was specifically intended for the Ethernet library with Wiznet chips.

If you use cmason's code, I would recommend disabling interrupts within the read() function. You might also want to declare read() as static, to avoid possible conflicts with such a generic function name possibly being used in any other files.

Headroom
12-11-2013, 12:11 AM
I have been using the version posted by user THT in post #2. The Teensy3 ID has served perfectly as an Ethernet MAC for the WIZ820io so I can register more that one Teensy3 on my network using Bonjour without having to worry about a conflict.

stevech
12-11-2013, 01:49 AM
If need be on the Teensy2 et al that have no S/N, you can use the IEEE 'self administered' MAC address range.
If I recall correctly, its a 0x02 in the MSByte.
With that bit on, you can use any bits you wish and no manufacturer's MAC will conflict.

stevech
02-21-2014, 04:41 PM
Shortly before releasing Teensy 3.0, PJRC registered for an IEEE OUI usable for Ethernet. Every Teensy 3.0 and 3.1 has been programmed with this OUI and an incrementing 24 bit serial number. It was specifically intended for the Ethernet library with Wiznet chips.

Another good but not well known thing!

mortonkopf
02-21-2014, 05:10 PM
thanks headroom,steve. That THT-cmason sketch is great, just pulled the mac out. now going to use this for the wiznet module.

Gene_R
04-24-2014, 05:48 AM
After a conversation with Paul, I think I've figured out how to access the unique Ethernet media access (MAC) address (http://en.wikipedia.org/wiki/MAC_address) burnt into the Teensy3. This number will be different on every teensy 3, and isn't overwritten by the bootloader flashing process like the EEPROM is.

Given this class:
------- snip -------
Hope this is useful.

-c

I made a few changes to this, here is the results:


// macAddress.h
#ifndef _MACADDR_H_
#define _MACADDR_H_

/** Retrieve Ethernet MAC from Teensy 3 */

/*
from http://forum.pjrc.com/threads/91-teensy-3-MAC-address
Edited by: Gene Reeves 04/23/2014
* added [] operator
* added uint8_t * operator for use in Ethernet.begin()
*/

class macAddress : public Printable {
protected:
uint8_t _m[6];
public:
macAddress() : _m({0}) {
// Retrieve the 6 byte MAC address Paul burnt into two 32 bit words
// at the end of the "READ ONCE" area of the flash controller.
read(0xe,0);
read(0xf,3);
}

// gives access to individual elements
uint8_t operator[](int index) const {return _m[index];}
uint8_t& operator[](int index) {return _m[index];}

// gives access to uint8_t array, use like this: Ethernet.begin(mac_address)
operator uint8_t *() {return &(_m[0]);}

void read(uint8_t word, uint8_t loc) {

// To understand what's going on here, see
// "Kinetis Peripheral Module Quick Reference" page 85 and
// "K20 Sub-Family Reference Manual" page 548.

cli();
FTFL_FCCOB0 = 0x41; // Selects the READONCE command
FTFL_FCCOB1 = word; // read the given word of read once area
// -- this is one half of the mac addr.
FTFL_FSTAT = FTFL_FSTAT_CCIF; // Launch command sequence
while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {
// Wait for command completion
}
*(_m+loc) = FTFL_FCCOB5; // collect only the top three bytes,
*(_m+loc+1) = FTFL_FCCOB6; // in the right orientation (big endian).
*(_m+loc+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0.
sei();
}

virtual size_t printTo(Print & p) const {
size_t count = 0;
for(uint8_t i = 0; i < 6; ++i) {
if (i!=0) count += p.print(":");
count += p.print((*(_m+i) & 0xF0) >> 4, 16);
count += p.print(*(_m+i) & 0x0F, 16);
}
return count;
}
friend class EthernetClass;
friend class UDP;
friend class Client;
friend class Server;
friend class DhcpClass;
friend class DNSClient;
};
#endif


with the above code you can do this:


macAddress myMac;
// print our MAC
Serial.print("My MAC is ");
Serial.println(myMac);

Serial.println("Starting Network using DHCP.");

if (Ethernet.begin(myMac)==0)
{
Serial.println("Failed to acquire IP address using DHCP, halting.");
while(1) {;}
}
Serial.print("My IP is ");
Serial.println(Ethernet.localIP());
//
// rest of your code here


Hope someone finds this useful. :cool:

if you see anything that does not look correct, please post a reply,
Gene_R

jimlux
04-24-2014, 01:57 PM
Per Paul's suggestion in December, you should probably be disabling interrupts around the manipulation of the flash.

Gene_R
04-24-2014, 04:09 PM
Per Paul's suggestion in December, you should probably be disabling interrupts around the manipulation of the flash.

i am doing a cli and sei in the read function.. is that what your referring to?

xxxajk
04-25-2014, 02:43 AM
Paul: this unique Ethernet MAC address is absolutely perfect for what I am doing, and solves a gigantic issue for me!
--THANK YOU!--
Now all I need to do is write the CDC EEM code and attach it to my IP stack! You rock!

johnnyfp
05-27-2014, 04:54 AM
Arduino IDE formatted library.

Just unpack into your arduino library dir and enjoy.

johnnyfp
05-29-2014, 01:27 AM
Is the K20 burnt with the MAC address or the MINI54T (bootloader) that then gets loaded into the K20?

Headroom
05-29-2014, 02:08 AM
IIRC the MAC address ins burnt into the K20. It has a small write-once memory area where the MAC is stored.

johnnyfp
05-29-2014, 02:19 AM
Ok that would explain why I get FF:FF:FF:FF:FF:FF from my custom board.

stevech
05-29-2014, 02:45 AM
Yes, Paul burns that MAC using a PJRC registered OUI.

Lloyd Olson
12-06-2014, 11:46 PM
This is not working with Teensy 3.1. Is it supposed to? I was hoping it would help me with using the SD Card and Wiznet820io which work separately but not together despite trying various CS pins. I will post this on a different thread, none of which have helped me get these working together.

Headroom
12-06-2014, 11:50 PM
Yes, this works on the Teensy 3.1 as well and Ethernet is one of the reason for the existence of the burned in code. This works perfectly with the WIZ820io. I have not tinkered around with SD card stuff yet, but you'll find many references to SD card related problems on the forum.
It depends often on the specific SD card used.

Why would the MAC burned into the K20 help you with the SD card ?

drjohnsmith
11-03-2015, 05:15 PM
Ive just tried the zip file mentioned,
and I'm getting an error on #include <Arduion.h> on the T3_readmac example.

Anything I should obviously do apart from cry !!

I know this is an old thread, so is there a different way of getting the MAC number off a teensy 3.2 ?

Frank B
11-03-2015, 05:29 PM
I dont think so. It is the same chip.

mortonkopf
11-03-2015, 05:49 PM
it should compile without errors. Have you put the lib into your lib folder and restarted arduino IDE?

drjohnsmith
11-04-2015, 08:49 AM
Even re booted the PC

here is the sketch

#include "T3Mac.h"

void setup() {
delay(1000);
Serial.begin(57600);

Serial.println("Reading MAC from hardware...");
read_mac();

Serial.print("MAC: ");
print_mac();
Serial.println();

Serial.print("Finished.");
}

void loop() {
}




and this is the message

In file included from T3_readmac.ino:1:0:
C:\Users\A123456\Documents\Arduino\libraries\T3Mac/T3Mac.h:4:21: warning: extra tokens at end of #include directive [enabled by default]
#include <Arduino.h>;
^
In file included from C:\Users\A123456\Documents\Arduino\libraries\T3Mac \T3Mac.cpp:1:0:
C:\Users\A123456\Documents\Arduino\libraries\T3Mac \T3Mac.h:4:21: warning: extra tokens at end of #include directive [enabled by default]
#include <Arduino.h>;

WMXZ
11-04-2015, 11:28 AM
Even re booted the PC

<snip\>

and this is the message

In file included from T3_readmac.ino:1:0:
C:\Users\A123456\Documents\Arduino\libraries\T3Mac/T3Mac.h:4:21: warning: extra tokens at end of #include directive [enabled by default]
#include <Arduino.h>;
^
In file included from C:\Users\A123456\Documents\Arduino\libraries\T3Mac \T3Mac.cpp:1:0:
C:\Users\A123456\Documents\Arduino\libraries\T3Mac \T3Mac.h:4:21: warning: extra tokens at end of #include directive [enabled by default]
#include <Arduino.h>;

this one is too easy!
remove the semicolon at the end of the #include line.
(the compiler suggested that this token is too much)

drjohnsmith
11-04-2015, 11:59 AM
thats great

I guessed that, and can modify my copy of said,

but its an example bundled with arduino / teensy,

so if the example needs to be modified,
who needs to know so the release can be fixed ?

drjohnsmith
11-04-2015, 12:16 PM
So

I have modified my copy of T3Mac.h.
this was originally in the zip file in post #14


this is what I now have , that compiles without error

#ifndef T3Mac_h
#define T3Mac_h

#include <Arduino.h>

extern uint8_t mac[6];

void read_mac();
void print_mac();

#endif

hope that helps someone

mortonkopf
11-04-2015, 12:19 PM
This begs the question of what has changed in the compiler to now throw this as an error, I am not running on the latest arduino IDE.

drjohnsmith
11-04-2015, 12:35 PM
thats all way above my simple head,
give us an ASIC and a simple language like VHDL any day...

bboyes
01-12-2016, 10:48 PM
This is great for use with the WIZ820io. I just learned today this existed. Someone needs to write a book about Teensy3, there is a lot there! Maybe we could all collaborate in a wiki!

It would be nice if some mention of this MAC address was made in the Ethernet examples, for example in DhcpAddressPrinter where mac is hardcoded

byte mac[] = {
0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
this does not conform to the guide for locallyadministered MAC addresses in which the second-least-significant bit of the most significant byte of the address, also referred to as the U/L bit, short for Universal/Local, should be a 1. If the bit is 0, the address is universally administered. If it is 1, the address is locally administered. I had to brush up on these nuances myself, wikipedia is a good reference: https://en.wikipedia.org/wiki/MAC_address. The organizational unique identifier (OUI) is just the most significant three bytes, the lower three bytes are the NIC portion and are assigned by the organization who licensed the OUI from the IEEE.

So in this example the mac address should more properly be

byte mac[] = {
0x02, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
which would prevent any possible conflict with a manufacturered device. I'll submit a fix for that to Arduino at Github
The PJRC OUI seems to be 04:E9:E5, confirmed by this OUI lookup tool https://www.wireshark.org/tools/oui-lookup.html

Thanks so much to Paul for putting this MAC address in Teensy 3!

Headroom
01-12-2016, 11:08 PM
That WiKi is in the works and there is already a thread on it that collects different topics.
Here is a link to another sticky thread with tips and tricks (https://forum.pjrc.com/threads/25395-Teensy-Quick-Reference-Code-Examples-Tips-and-Tricks?highlight=tips+tricks)

Not a book but very helpful!

bboyes
01-14-2016, 03:57 PM
Happy to contribute to the Wiki when it is up!
Thanks for all the support you provide too!

muggins
03-23-2016, 11:57 AM
Hi
I'm new to this ....
The T3Mac library provides functionality to print MAC address.
I need to extract it so I can write it to my ethernet module. I don't know how to do that.
Any one help?

Headroom
03-23-2016, 12:01 PM
What Ethernet module do you have ?
Some come with their own mac address and this would not work
The WIZ830io does not have it's own mac address and you can use the Teensy mac address for that.

I am off to work now but can post code tonight.

muggins
03-23-2016, 12:17 PM
Hi
My module is WIZ820. I have several and I want to get a unique MAC address from the Teensy in my sketch and then start an Ethernet session using it.
thanks
John

drjohnsmith
03-23-2016, 01:38 PM
Hi
My module is WIZ820. I have several and I want to get a unique MAC address from the Teensy in my sketch and then start an Ethernet session using it.
thanks
John

As per this thread

https://forum.pjrc.com/threads/91-teensy-3-MAC-address


the variable mac in this thread has the mac address from each teensy

muggins
03-23-2016, 02:24 PM
Hi thanks
I tried that but I'm not sure if I'm doing the right thing but..
I have put code (class) in my sketch and made a request for mac in setup. I get:

C:\JMstuff\ROBIN\JM-Robin-Servo\JM-Robin-Teensy8\JMvarious.ino: In constructor 'mac_addr::mac_addr()':
C:\JMstuff\ROBIN\JM-Robin-Servo\JM-Robin-Teensy8\JMvarious.ino:197:23: warning: list-initializer for non-class type must not be parenthesized [enabled by default]
mac_addr() : m({0}) {
^
exit status 1
call of overloaded 'println(byte [6])' is ambiguous

drjohnsmith
03-23-2016, 02:33 PM
Hi thanks
I tried that but I'm not sure if I'm doing the right thing but..
I have put code (class) in my sketch and made a request for mac in setup. I get:

C:\JMstuff\ROBIN\JM-Robin-Servo\JM-Robin-Teensy8\JMvarious.ino: In constructor 'mac_addr::mac_addr()':
C:\JMstuff\ROBIN\JM-Robin-Servo\JM-Robin-Teensy8\JMvarious.ino:197:23: warning: list-initializer for non-class type must not be parenthesized [enabled by default]
mac_addr() : m({0}) {
^
exit status 1
call of overloaded 'println(byte [6])' is ambiguous


OK.

step back a bit.

this might help. not certain where / when I got it but it works as an example

#include "T3Mac.h"


void setup()
{
delay( 2000);

Serial.begin(115200);

read_mac();

Serial.print(" Chip ID =: ");
Serial.print( ( mac[0] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[0] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[1] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[1] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[2] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[2] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[3] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[3] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[4] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[4] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[5] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[5] & 0x0F ) ,HEX );

Serial.println();

}
}

void loop() {
}

muggins
03-23-2016, 02:37 PM
OK I'll try messing picking the bones of that. thanks

drjohnsmith
03-23-2016, 02:55 PM
OK I'll try messing picking the bones of that. thanks

to give you a quick heads up

you include the T3mac library ,

you call read_mac

read_mac returns a variable called mac , which is an array of 6 bytes ( 0 to 5 ) of the mac address,

the print stuff is just so you can see it on a terminal,

muggins
03-23-2016, 03:05 PM
That's great, got it now..thanks

cr7pt0
04-28-2016, 05:23 PM
If anyone else is trying to get this to work this may help:

Download the library from post #14

Delete the ";" from the end of #include <Arduino.h>; in T3Mac.h

Use the sketch from post 38 but remove the extra closing bracket and add a delay after serial begin. This works with Teensy 3.2 on Arduino 1.6.5 r5.

#include "T3Mac.h"


void setup()
{
delay( 2000);
Serial.begin(115200);
delay( 2000);
read_mac();

Serial.print(" Chip ID =: ");
Serial.print( ( mac[0] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[0] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[1] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[1] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[2] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[2] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[3] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[3] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[4] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[4] & 0x0F ) ,HEX );
Serial.print( " : " ) ;
Serial.print( ( mac[5] & 0xF0 ) >> 4 ,HEX );
Serial.print( ( mac[5] & 0x0F ) ,HEX );

Serial.println();

}


void loop() {
}

defragster
05-03-2016, 10:17 AM
I decided it would be nice to have the Teensy Serial number to display - it is derived from the bottom 3 MAC bytes (24 bits if I read a PJRC post correctly - though TYQT uses four).

While looking I saw the posted t3Mac code didn't have the recommended interrupt disable for MAC read.

While I was there I put in the code I saw to read the processor CHIP_ID [T3 and T_LC] (I noticed that code putting 36 bytes into 32 reserved bytes for the MAC ID string, now in 36.)

Here is the version as I see it working: 7074

Sample Output from the Example sketch:

Chip MAC ID == 04: E9: E5: 01: E6: 65
Teensy Serial# 1245170
Reading 128-bit UniqueID from Teensy AA310000 716C002A 000E5016 31604E45


PROBLEM 1: (this may deserve a new thread?)
> On custom "Teensy programmer chip" T_3.2 compatible hardware the Serial # write once area is uninitialized. Does anyone have tested code to write to that area? that read pulls with:
FTFL_FCCOB0 = 0x41; // Selects the READONCE command

On this unit - since uninitialized flash is all 1's I get the following:

Chip MAC ID == FF: FF: FF: FF: FF: FF
Teensy Serial# 167772150
Reading 128-bit UniqueID from Teensy B3610000 8330002D 00093018 32204E45


PROBLEM 2:
> if I compile in the 1.6.8 IDE without re-saving the T3mac.cpp source file I get this error - that PAUL fixed in the TimeLib library he maintains:

GetFileAttributesEx C:\tCode\libraries\T3Mac\T3Mac.cpp C:\tCode\libraries\T3Mac\T3MacLib.h: The filename, directory name, or volume label syntax is incorrect.
Error compiling for board Teensy 3.2 / 3.1.
Does anyone else see this?
Paul: I tried to emulate what I thought your fix was - and missed something or found a new way to orphan an open file in the IDE.

<Minor edit> the zipped version of T3Mac.h doesn't look like this - it was not saved first - but it works that same with this intended code (if anyone sees other issues I'll update):

#include "T3MacLib.h"

defragster
05-04-2016, 07:35 AM
RE Problem #1 - the read part of those bytes is exemplified in above code. I find the K20 manual (K20P64M72SF1RM.pdf) on page 579 discusses that - but it doesn't speak to me how to start - PJRC must do this write offline as I only find read code similar to what is in T3Mac in the installed Teensy libraries - and I only have one device on hand to try a write once operation. Must be further reading on doing register writes - which FrankB and others probably understand.


28.34.5 Flash Common Command Object Registers (FTFL_FCCOBn)
The FCCOB register group provides 12 bytes for command codes and parameters. The individual bytes within the set append a 0-B hex identifier to the FCCOB register name: FCCOB0, FCCOB1, ..., FCCOBB.

cr7pt0
05-05-2016, 08:13 PM
I incorporated your new library and it works well to pull the MAC and the Chip ID on Arduino 1.6.5 r5. Example sketch here: https://github.com/onlykey/OnlyKey-Firmware-US/blob/master/Get-MAC/Get-MAC.ino

PaulStoffregen
08-26-2016, 01:10 PM
As a quick followup to this old but useful thread, on the new Teensy 3.6 board when running faster than 120 MHz, you need to temporarily drop down to a slower speed and disable HSRUN mode. The flash controller locks out all commands when HSRUN mode is active. Yes, that's silly since this command only reads the flash, but that's the way Freescale designed the chip.

Also, in Teensy 3.5 and 3.6, this special memory is organized as 64 bit words, not 32 bits as on Teensy LC, 3.0, 3.1 & 3.2. You need to perform a single read at location 0x07, not a pair at 0x0E & 0x0F. The low 32 bits are the IEEE-assigned OUI and the high 32 bits have the serial number.

MichaelMeissner
08-26-2016, 01:41 PM
It may be useful to have a Teensy official library function to return the unique number (and of course update the library page), so that most users don't have to delve into the Freescale data sheets.

Frank B
08-26-2016, 03:25 PM
Yup, and it could be read before switchig to hsrun!
If you want, I can do this on sunday..

Frank B
08-27-2016, 04:27 PM
@Paul, can you pls. confirm, that this prints the correct serial ?
Thank you!



uint64_t readMAC() {
uint64_t mac;

FTFL_FCCOB0 = 0x41;
FTFL_FCCOB1 = 0x07;

noInterrupts();
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}
interrupts();

mac = (uint64_t)FTFL_FCCOB5 << 40;
mac |= (uint64_t)FTFL_FCCOB6 << 32;
mac |= (uint64_t)FTFL_FCCOB7 << 24;
mac |= FTFL_FCCOB9 << 16;
mac |= FTFL_FCCOBA << 8;
mac |= FTFL_FCCOBB;

return mac;
}


void setup() {
delay(1000);
Serial.printf("MAC: 0x%012llX\n", readMAC());
Serial.printf("Serial: %u\n", readMAC() & 0xFFFFFF);
}
void loop() {}


(must run without HSRUN)

Edit: The code above is for T3.5/3.6 only

KurtE
08-27-2016, 06:20 PM
Yup, and it could be read before switchig to hsrun!
If you want, I can do this on sunday..
I have a pull request pending in Core that did this, that I issued 10 days ago:
https://github.com/PaulStoffregen/cores/pull/166

Frank B
08-27-2016, 07:03 PM
Hm, ok, does this work with disabled usb and/or lower fcpu or teensy 3.2?

KurtE
08-27-2016, 07:43 PM
The change I did was to add a call to the code that reads in the serial number, if it finds that it is going to go into HSRUN mode. I also added code into that call that made it only do stuff once. So in all other cases the current code path to call the function is still done.

defragster
08-27-2016, 10:33 PM
The change I did was to add a call to the code that reads in the serial number, if it finds that it is going to go into HSRUN mode. I also added code into that call that made it only do stuff once. So in all other cases the current code path to call the function is still done.

For affected MCU's (K66 only? Unless K64 has similar issue if it OC's over 120 MHz with similar limitation?) I envisioned this as something done on 'boot' before HSRUN is active so a static copy (like you suggest 'only once') was always present? In any case with a uniform TEENSY_Ser#() the same code could be used on boot with USB, or by any 'user'.

Wondering if PJRC planning mini_beta of K64 units? Since I have K66 & Ethernet Beta boards I opted for T_3.6 SIX pack , so I won't have any K64's until they go retail.

I was AWOL 3 weeks - now back home and should be online in coming days, once I unpack.

With a uniform function() to Drop/Restore HSRUN - the end user could do this and also batch EEPROM I/O so such things can be usable. It would compromise clock specific items during that time - but better than losing functionality, or having end user hacks. With 'plenty' of RAM - some/all of the EEPROM could be cached for R/W access and quickly sync'd with :: eeprom_read_block() and eeprom_write_block() [ or _dword() ?]

KurtE
08-28-2016, 03:32 PM
For affected MCU's (K66 only? Unless K64 has similar issue if it OC's over 120 MHz with similar limitation?) I envisioned this as something done on 'boot' before HSRUN is active so a static copy (like you suggest 'only once') was always present? In any case with a uniform TEENSY_Ser#() the same code could be used on boot with USB, or by any 'user'.

Wondering if PJRC planning mini_beta of K64 units? Since I have K66 & Ethernet Beta boards I opted for T_3.6 SIX pack , so I won't have any K64's until they go retail.

I was AWOL 3 weeks - now back home and should be online in coming days, once I unpack.

With a uniform function() to Drop/Restore HSRUN - the end user could do this and also batch EEPROM I/O so such things can be usable. It would compromise clock specific items during that time - but better than losing functionality, or having end user hacks. With 'plenty' of RAM - some/all of the EEPROM could be cached for R/W access and quickly sync'd with :: eeprom_read_block() and eeprom_write_block() [ or _dword() ?]
Welcome back,

I think you are right that maybe there should be some caching scheme for EEPROM. In my case often I only read from the EEPROM at startup. Maybe things like Servo offsets and the like. I may then have a special mode I go into that allows me to update these settings, but again this is in an isolated portion of the code.

I have not heard anything either about T3.5 beta, but thought these might be interesting as a drop in upgrade, that still gives me 5v tolerance. Obviously one issue will be the size of the board not fitting where the T3.2 would fit. Will talk more about this on another thread. So I ordered the 2+2 Kickstarter.

MichaelMeissner
08-28-2016, 04:29 PM
I have not heard anything either about T3.5 beta, but thought these might be interesting as a drop in upgrade, that still gives me 5v tolerance. Obviously one issue will be the size of the board not fitting where the T3.2 would fit. Will talk more about this on another thread. So I ordered the 2+2 Kickstarter.
I suspect KurtE already knows, but others thinking about the 3.5 as a drop in replacement, the touchRead function does not work on the 3.5. It should work on the 3.6. Also, the back row of pins (Vbattery, 3.3v, ground, program, DAC) have been relocated.

defragster
08-28-2016, 11:52 PM
Welcome back,

I think you are right that maybe there should be some caching scheme for EEPROM. In my case often I only read from the EEPROM at startup. Maybe things like Servo offsets and the like. I may then have a special mode I go into that allows me to update these settings, but again this is in an isolated portion of the code.

I have not heard anything either about T3.5 beta, but thought these might be interesting as a drop in upgrade, that still gives me 5v tolerance. Obviously one issue will be the size of the board not fitting where the T3.2 would fit. Will talk more about this on another thread. So I ordered the 2+2 Kickstarter.

Thanks Kurt!

Awesome to see that Paul is doing a mini_beta for T_3.5 (https://forum.pjrc.com/threads/34808-K66-Beta-Test?p=113530&viewfull=1#post113530), that will pave the way for the KS shipping in good shape out of the box.

Glad you see value: Indeed EEPROM usage varies - but some supported/generalized way to use it seems important - having no HSRUN access to it could be a real loss. Reading/Caching in setup() could cover most use cases without risking destabilizing anything. Having a way to write back without reprogramming to lower speed sketch (and back) would extend the functionality especially if the data changes during run time - even if it was followed by a restart to come up stable. But if the device can sleep() and return it should be able to recover without that?

Built in SD card could supplant the EEPROM - only problem would be getting that data to new cards consistently as they come and go, or go bad.

@MM - I put overt "lack of TOUCH in the KS specs" on the 'nit' thread (https://forum.pjrc.com/threads/36231-Nit-pick-on-3-6-kick-starter-maybe?p=112797&viewfull=1#post112797). I think that should be called out. Both MM and Kurt RTFM in posts 1110 & 1111 (https://forum.pjrc.com/threads/34808-K66-Beta-Test?p=112527&viewfull=1#post112527) confirmed it was not just a typo where T_3.6 has TOUCH and T_3.5 does not when I posted about that.

Wozzy
08-29-2016, 01:42 AM
Hm, ok, does this work with disabled usb and/or lower fcpu or teensy 3.2?

Frank,
I tried your code on my T3.6-r3 and get the following results:


CPU SPEED: 240MHz , COM3
MAC: 0x000000000000
Serial: 0

CPU SPEED: 180MHz , COM3
MAC: 0x000000000000
Serial: 0

CPU SPEED: 120MHz, COM6
MAC: 0x04E9E5032345
Serial: 205637

CPU SPEED: 96MHz, COM6
MAC: 0x04E9E5032345
Serial: 205637

CPU SPEED: 48MHz, No USB Emulated Serial
MAC: 0x04E9E5032345
Serial: 205637

Cmason Code / THT T3_mac.zip
CPU SPEED: 120MHz, COM6
Chip MAC ID == 04: E9: E5: 04: E9: E5
Teensy Serial# 3220210
Reading 128-bit UniqueID from Teensy 0017FFFF FFFFFFFF 4E453506 1001001E

defragster
08-29-2016, 01:56 AM
Frank,
I tried your code on my T3.6-r3 and get the following results:



If that is your ser# I think that is as expected as it doesn't alter speed - just does the 64 bit math operations - do you have TYQT installed - It gets the ser# from Paul's boot code you could compare.

If you merged KurtE's PULL code changes (https://forum.pjrc.com/threads/34808-K66-Beta-Test?p=113543&viewfull=1#post113543) I think you can emulate the timing of Paul's code before HSRUN goes active?

You might run Frank's code here in parallel at this change? : usb_init_serialnumber(); (https://github.com/KurtE/cores/blob/4276f875c101fe43687247e4917b1cc4700d1e93/teensy3/mk20dx128.c#L844)

Then compare the results?

I want to try this myself - but I'm not that far unpacked yet.

Wozzy
08-29-2016, 02:08 AM
Defragster,

TyQT V07.6 64-bit reports this serial number: 2056370
Identity: 2056370-Teensy

I tried KurtE's Core modifications, but did not see any changes, but I was looking for COM port changes, not Serial numbers.

defragster
08-29-2016, 02:28 AM
Looks like it is working.

AFAIK - Windows meshes the serial into recognized USB DEVICE, when that returns 0, it is a different device. Kurt's location precedes the hsrun loss of access right?

<edit> phone edit - wrong words.

defragster
08-29-2016, 04:03 AM
I hacked what I suggested - put FrankB's code into location suggested by KurtE's PULL - and I made subtle code change below as it is called once before HSRUN and then again twice after for my TYQT identified "2056390-Teensy":



uint64_t readMAC() {
static uint64_t mac = 0;

if ( 0 == mac ) {




MAC: 0x04E9E5032347
Serial: 205639

CPU is T_3.6 F_CPU =120000000




MAC: 0x04E9E5032347
Serial: 205639

CPU is T_3.6 F_CPU =240000000




MAC: 0x04E9E5032347
Serial: 205639

CPU is T_3.6 F_CPU =180000000

xxxajk
08-29-2016, 04:37 AM
Perhaps the best solution would be to read the area in the startup code, before everything else.

MichaelMeissner
08-29-2016, 05:48 AM
Perhaps the best solution would be to read the area in the startup code, before everything else.

Yep, it is not like the value is going to change.

defragster
08-29-2016, 05:55 AM
Perhaps the best solution would be to read the area in the startup code, before everything else.

Indeed that is what KurtE's code does (see post #58). But is does it for the specific purpose of setting the USB strings up just before HSRUN - so when it is needed later it is pre-saved in that storage area.

But it doesn't save it in the # only format used by FrankB's code (which won't work once HSRUN is enabled) as user code to get MAC id and serial #.

Kurt - I'm wondering it might be good save the 'num' in place of :: usb_init_serialnumber_called = 1. If that were made a public variable by PJRC - nobody would ever have to manually call code for MAC and ser#?



static uint32_t usb_init_serialnumber_called = 0;
void usb_init_serialnumber(void)
{
char buf[11];
uint32_t i, num;
if (usb_init_serialnumber_called)
return;

// 'num' collect code here (https://github.com/KurtE/cores/blob/4276f875c101fe43687247e4917b1cc4700d1e93/teensy3/usb_desc.c#L1219)

usb_init_serialnumber_called = num; // NOTE - this is 32 bit and is *10 in some cases
}


NOTE: DIY boards will have 0xF's in that flash until set. And Paul said Zero was set as serial # in the K66 Proto boards, though I read this now:
MAC: 0xFFFFFFFFFFFF
Serial: 16777215

defragster
08-29-2016, 11:02 AM
Discovered an anomaly? For the above I did KurtE's pre HSRUN addition. I also put FrankB's code local in the same mkdx128.c file for the above. The results in post #64 are misleading it seems

Doing NEITHER in the mkdx128.c file results in 0 being read once in HSRUN mode - as expected - and the assigned USB's COM# port changes (according to TYQT) based on the serial# and hardware USB port (once the device is removed and forgotten by TYQT).

However if EITHER is done in advance of HSRUN then BOTH work after HSRUN. So it 'seems' that HSRUN causes a 0 to be returned after reset if neither was called. If either was called - or both - before HSRUN that last returned value is returned again when HRUN mode stops it from getting 'current' data.

I followed this up additionally by removing this from KurtE's code :: // usb_init_serialnumber_called = 1;
The result is the same. Once the following is executed - repeat reads of FTFL_FCCOB# after HSRUN is set return the prior value:


FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}


Wondering if there are other such values that HSRUN affects with regard to actual versus value 'cached' or not - that is 'stale' data is being used?

I found this when I wondered if HSRUN alone caused the 'read' to fail - or if it was the subsequent clock setting. Finding the above I can confirm that after HSRUN is set - even if the clock speeds are not yet boosted over 120 MHz that the MAC/Ser# read fails. And I assume that without HSRUN {which I understand to boost the voltage, which must make EEPROM areas unsafe to touch?} putting the clock over 120MHz may cause instability without HSRUN - so to take the MCU out of HSRUN the clock would have to be set to a safe speed (120 MHz or less) to read the 4 KB of EEPROM for instance - then back to HSRUN and the clock setting restored. Though I also note that HSRUN is ALWAYS set ( SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode ) without regard to the clock speed final setting afterwards in mkdx128.c. But as expected: when the clock doesn't exceed 120 MHz it still works, but 144 MHz or above the MAC/Ser# read gets a zero - so I assume some other clock settings precede this code that change the effect of HSRUN?

AFAIK this is accurate - hopefully it is complete as far as I went, and makes sense and adds some value for this thread and any possible 'on the fly' speed changes for EEPROM or other.

defragster
08-31-2016, 04:46 AM
Following up on my prior post the following code change results in a valid serial at 120, 180 and 240 MHz. Both using FrankB's prior posted code (https://forum.pjrc.com/threads/91-teensy-3-MAC-address?p=113412&viewfull=1#post113412)and in TYQT reading the serial number on connecting to the device.

From the empirical results above it seems making this call results in this value being made 'static/local/cached' to the processor before HSRUN goes active.
> Is this a safe assumption and a sufficient solution?
> I did not "__disable_irq(); & __enable_irq();" across this call - I do not know if the interrupts are active at this time?

On my Win10 desktop - fresh install of IDE 1.6.11 and TeensyDuino 1.30b3 and programming to my T_3.6 I made the following change at line #842 of :: arduino_16_11\hardware\teensy\avr\cores\teensy3\mk 20dx128.c"




// if we need faster than the crystal, turn on the PLL
#if defined(__MK66FX1M0__)
#if F_CPU > 120000000
FTFL_FCCOB0 = 0x41;
FTFL_FCCOB1 = 0x07;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) {}
SMC_PMCTRL = SMC_PMCTRL_RUNM(3); // enter HSRUN mode
while (SMC_PMSTAT != SMC_PMSTAT_HSRUN) ; // wait for HSRUN
#endif




MAC: 0x04E9E5032347
Serial: 205639

CPU is T_3.6
F_CPU =240000000

<edit> I used FrankB's code - I see the PJRC code uses this line that may be more consistent::
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;

Frank B
09-03-2016, 01:50 PM
I've created a library that helps to retrieve the Serial and MAC from within your sketch:

https://github.com/FrankBoesing/TeensyMAC

Works with Teensy LC, Teensy 3.0 .. 3.6 and in HS_RUN-Mode.

usage: see "readme"

Wozzy
09-03-2016, 06:13 PM
I've created a library that helps to retrieve the Serial and MAC from within your sketch:
...
Works with Teensy LC, Teensy 3.0 .. 3.6 and in HS_RUN-Mode.

Frank,
It's working on my T3.6-R3, tested at 24, 48, 96, 120, 180 and 240MHz.
Also TyQT and Arduino report a constant Com Port # at all speeds after running TeensyMAC

I get the following output:

Serial: 2056370
MAC: 0x04E9E5032345

Thanks

Frank B
09-04-2016, 12:57 AM
Thank you for testing, Wozzy :o

MrGlasspoole
01-21-2017, 07:57 AM
I was using T3Mac.h on the Teensy 3.2 and it worked without defining:

uint8_t mac[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
How does this one work?
I wonder that:

Serial.printf("MAC: 0x%012llX\n", teensyMAC());
only shows 14 digits?
What does "0x%012llX\n" do?

Frank B
01-21-2017, 05:31 PM
I was using T3Mac.h on the Teensy 3.2 and it worked without defining:

uint8_t mac[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
How does this one work?
I wonder that:

Serial.printf("MAC: 0x%012llX\n", teensyMAC());
only shows 14 digits?


Nope, it shows 12 digits.
Whats makes you think a MAC has more digits ?

https://en.wikipedia.org/wiki/MAC_address

Output (one of T3.2 - just tested again) :


Serial: 1679610
MAC: 0x04E9E5029019


Please post your output, if it is different.


What does "0x%012llX\n" do?
It's a format string...
http://www.cplusplus.com/reference/cstdio/printf/

MrGlasspoole
01-21-2017, 07:30 PM
Yes a MAC has 12 but the one you put in by hand has more.
So i wonder how to use this now in:

uint8_t mac[] =
Ethernet.begin(mac, ip, dnsServer, gateway, subnet);

From your posting in the W5500 tread it sound the Teensy has a MAC?
I thought this one reads the serial and uses this as MAC.

On Arduinos i always used a Dallas DS18B20 as MAC:

// Set MAC via DS18B20
void setupEthernet(){
byte i;
byte dsAddress[8];
Serial.println( "Searching for DS18B20..." );
oneWire.reset_search(); // Start the search with the first device
if (!oneWire.search(dsAddress)) {
Serial.println( "None found. Using default MAC address." );
} else {
Serial.println( "Success! Setting MAC address:" );
Serial.print( " DS18B20 ROM =" );
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print( dsAddress[i], HEX );
}
Serial.println();
// Offset array to skip DS18B20 family code, and skip mac[0]
mac[1] = dsAddress[3];
mac[2] = dsAddress[4];
mac[3] = dsAddress[5];
mac[4] = dsAddress[6];
mac[5] = dsAddress[7];
}

Serial.print( " Ethernet MAC =" );
for( i = 0; i < 6; i++ )
{
Serial.write( ' ' );
Serial.print( mac[i], HEX );
}
Serial.println();
startEthernet();
}

Frank B
01-21-2017, 07:58 PM
Yup,, the serial is part of the mac.

Perhaps try something like this ?


uint64_t mac64;
uint8_t mac[6];

mac64 = teensyMAC();
mac[0] = mac64 >> 40;
mac[1] = mac64 >> 32;
mac[2] = mac64 >> 24;
mac[3] = mac64 >> 16;
mac[4] = mac64 >> 8;
mac[5] = mac64;

Ethernet.begin( mac, ..

MrGlasspoole
01-22-2017, 12:03 AM
Ok after 2 hours of trying i can't figure out how to formate that thing to something like:

D0 50 99 2A 3D F6
or
D0:50:99:2A:3D:F6


uint64_t mac64;
uint8_t mac[6];

// Set MAC via Teensy serial
void setupEthernet() {
byte i;
Serial.println("Reading MAC from hardware..." );
mac64 = teensyMAC();
mac[0] = mac64 >> 40;
mac[1] = mac64 >> 32;
mac[2] = mac64 >> 24;
mac[3] = mac64 >> 16;
mac[4] = mac64 >> 8;
mac[5] = mac64;
Serial.println("Success! Setting MAC address:");
Serial.print(" Ethernet MAC =");
for( i = 0; i < 6; i++ ) {
Serial.write(' ');
Serial.print("0x");
Serial.print(mac[i], HEX);
}

Serial.println();
Serial.printf(" Test 1 = 0x%012llX\n", mac[i], HEX);
Serial.printf(" Test 2 = 0x%012llX\n", mac[i]);
Serial.printf(" Test 3 = 0x%012llX\n", mac64);
Serial.printf(" Test 4 = 0x%012llX\n", teensyMAC());
Serial.println();

startEthernet();
}
Output:

Reading MAC from hardware...
Success! Setting MAC address:
Ethernet MAC = 0x4 0xE9 0xE5 0x3 0xA7 0xAE
Test 1 = 0x001000000000
Test 2 = 0x001B00000000
Test 3 = 0x04E9E503A7AE
Test 4 = 0x04E9E503A7AE

PaulStoffregen
01-22-2017, 04:24 AM
Give this a try:



for( i = 0; i < 6; i++ ) {
Serial.write(' ');
Serial.printf("%02X", mac[i]);
}

MrGlasspoole
01-22-2017, 05:06 AM
I wish my brain would work binary like yours and other peoples here.
Things i need hours or days you do in minutes.

Serial output looks nice now:

The radio frequency is 868 Mhz, Kenneth!
RFM69 ATC Enabled (Auto Transmission Control)

I2C Address Scanning ...
Found i2c Device Address: 32 (0x20)
Found i2c Device Address: 33 (0x21)
Scanning done!
Found 2 device(s).

Reading MAC from hardware...
Success! Setting MAC address:
Ethernet MAC = 04 E9 E5 03 A7 AE

Starting Network...
Connected to Network!
IPv4 address: 192.168.0.246

Syncing with NTP Server...
Transmitting NTP Request...
Receiving NTP Response...
RTC has set the system time
Time: 6:01:18 22 1 2017

Frank B
01-22-2017, 10:19 AM
Great that it works now :-)

You can print the MAC without loop, too:


Serial.printf("Ethernet MAC = %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

These are, again, format-strings. "%02X" means print the number as 2-digit hexadecimal, with leading zero, uppercase. ("%02x" would be lowercase)

sstaub
02-13-2017, 09:30 AM
I have made a new library called TeensID based on the TeensyMAC lib from frank.
You can find it at https://github.com/sstaub/TeensyID
I have extended the library with pointers and strings for MAC, USB#, Serial# and ChipID
It is only tested for Teensy 3.5

defragster
02-15-2017, 10:29 AM
Glancing at the code it looks like it has FrankB's work to get serial # before hsrun_disable was introduced for T_3.6 - that catching it in startup. Though that code is also there? The core of the code needs only do the work below to get the Serial #.

The PJRC code to set the Serial Number is here: teensy3/usb_desc.c#L1294 (https://github.com/PaulStoffregen/cores/blob/master/teensy3/usb_desc.c#L1294)


void usb_init_serialnumber(void)
{
char buf[11];
uint32_t i, num;

// ...

sstaub
02-15-2017, 03:04 PM
Yes I have added the kinetis_hsrun_disable / _enable from the PJRC code to the code of FrankB, so it is nearly the same code. For me the goal is to get an unique mac address and also an UUID (RFC4122), I have to work on next.

sstaub
02-15-2017, 10:53 PM
Glancing at the code it looks like it has FrankB's work to get serial # before hsrun_disable was introduced for T_3.6 - that catching it in startup. Though that code is also there? The core of the code needs only do the work below to get the Serial #.

The PJRC code to set the Serial Number is here: teensy3/usb_desc.c#L1294 (https://github.com/PaulStoffregen/cores/blob/master/teensy3/usb_desc.c#L1294)

So, when I really understood, you mean that this part of the code can deleted!?


#if defined(HAS_KINETIS_FLASH_FTFE) && (F_CPU > 120000000)

extern "C" void startup_early_hook(void) {
#if defined(KINETISK)
WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE;
#elif defined(KINETISL)
SIM_COPC = 0; // disable the watchdog
#endif
*(uint32_t*)(MY_SYSREGISTERFILE) = _getserialhw();
}

defragster
02-16-2017, 12:17 AM
Yes, that is the part that caught my eye. If that was indeed from the Beta posting - it was to get the SN before the hsrun state was entered and that value went 'offline'

sstaub
02-16-2017, 02:49 PM
Yes, that is the part that caught my eye. If that was indeed from the Beta posting - it was to get the SN before the hsrun state was entered and that value went 'offline'

Thank you for your advices, I have rewritten and optimized the code and published it. Also added a UUID (RFC4122) function.

bboyes
02-28-2017, 08:08 PM
I have made a new library called TeensID based on the TeensyMAC lib from frank.
You can find it at https://github.com/sstaub/TeensyID
I have extended the library with pointers and strings for MAC, USB#, Serial# and ChipID
It is only tested for Teensy 3.5

I forked your repo, fixed a decl in the example code, made an Arduino library example folder, tested on T3.2, added to the readme, and issued a pull request. Here is output with T3.2:
USB Serialnumber: 1244570
Array Serialnumber: 00-01-E6-29
String Serialnumber: 00-01-e6-29
Array MAC Address: 04:E9:E5:01:E6:29
String MAC Address: 04:e9:e5:01:e6:29
Array 128-bit UniqueID from chip: C7210000-714D001E-00496017-31384E45
String 128-bit UniqueID from chip: c7210000-714d001e-00496017-31384e45
Array 128-bit UUID RFC4122: 00496017-3138-404E-8045-04E9E501E629
String 128-bit UUID RFC4122: 00496017-3138-404e-8045-04e9e501e629

manitou
02-28-2017, 08:59 PM
I have made a new library called TeensID based on the TeensyMAC lib from frank.
You can find it at https://github.com/sstaub/TeensyID
I have extended the library with pointers and strings for MAC, USB#, Serial# and ChipID
It is only tested for Teensy 3.5

tested on T3.6 and LC. ok

sstaub
02-28-2017, 09:31 PM
I have done a new release v1.1.1 with the pull request from bboyes. Thanks for your help.

lorenzofattori
06-30-2017, 09:26 PM
I've created a library that helps to retrieve the Serial and MAC from within your sketch:

https://github.com/FrankBoesing/TeensyMAC

Works with Teensy LC, Teensy 3.0 .. 3.6 and in HS_RUN-Mode.

usage: see "readme"

Hi Frank,
I think there is a issue somewhere. I was debugging other stuff with wireshark and I saw my teensy sending out the last 3 MAC digits as 00:00:00
then I had a look around and found this:

- at the first run after loading teensy software I get the right SN and MAC
- if I unplug and replug teensy then I get 0 as a SN and 0x04E9E5000000 as a mac.

This also happens with the example in your github, so don't think is related with my code.

Any suggestions?

Frank B
06-30-2017, 10:00 PM
Hi Frank,
I think there is a issue somewhere. I was debugging other stuff with wireshark and I saw my teensy sending out the last 3 MAC digits as 00:00:00
then I had a look around and found this:

- at the first run after loading teensy software I get the right SN and MAC
- if I unplug and replug teensy then I get 0 as a SN and 0x04E9E5000000 as a mac.

This also happens with the example in your github, so don't think is related with my code.

Any suggestions?

Which Teensy ?

lorenzofattori
07-01-2017, 08:59 AM
Which Teensy ?

woups, sorry.... Teensy 3.6

lorenzofattori
07-03-2017, 09:33 PM
Hi Frank,
I think there is a issue somewhere. I was debugging other stuff with wireshark and I saw my teensy sending out the last 3 MAC digits as 00:00:00
then I had a look around and found this:

- at the first run after loading teensy software I get the right SN and MAC
- if I unplug and replug teensy then I get 0 as a SN and 0x04E9E5000000 as a mac.

This also happens with the example in your github, so don't think is related with my code.

Any suggestions?

Tried also with another Teensy 3.6, same thing. First boot everything ok, then the mac is 00:00:00 on the last 3 bytes.
Both teensy have something saved in the EEPROM, can be related?

Frank B
07-04-2017, 06:11 PM
Tried also with another Teensy 3.6, same thing. First boot everything ok, then the mac is 00:00:00 on the last 3 bytes.
Both teensy have something saved in the EEPROM, can be related?

Hi, at the moment, I can not reproduce this issue. It works well, for me, after power-off/on, too. On the other hand, I don't use the EEPROM.
For >120MHZ, the code kicks in early, and reads the MAC at "early startup", before initializing anything other, and stores it in the "System Register File" for later usage. I'd be surprised if this does not work with EEPROM, but who knows...

lorenzofattori
07-07-2017, 11:40 AM
Hi, at the moment, I can not reproduce this issue. It works well, for me, after power-off/on, too. On the other hand, I don't use the EEPROM.
For >120MHZ, the code kicks in early, and reads the MAC at "early startup", before initializing anything other, and stores it in the "System Register File" for later usage. I'd be surprised if this does not work with EEPROM, but who knows...

I will try to erase the eeprom and see if something changes, but seems strange.
where is the MAC address stored?

PaulStoffregen
07-07-2017, 02:21 PM
where is the MAC address stored?

Every Kinetis chip has a small, very special "write once" memory, which is used for the mac address. This memory has 8 words of 64 bits. The other chips have slightly different size memory and some are 32 bit words, but they all work the same way. It start as all 1s when Freescale makes the chip. There's a special command to write to this memory, one word at a time. After the word is written, changing any of its bits from 1 or 0, the entire 64 bits are forever locked. If you try to write again, the chip returns an error status and does not change any bits. Erasing the chip does not erase this very special memory. Once written, it's permanent. Well, at least as permanent as the flash memory retains data, which is at least 20 years at extreme temperature and probably hundreds of years at room temperature.

As each Teensy is tested, PJRC's test gear programs 64 bits of that special "write once" memory with PJRC's IEEE-assigned OUI (mac address upper 24 bits) and a unique serial number. All the other bits of that memory are not touched. But those 64 bits with the mac address are programmed here and can never be altered, even if you fully erase the chip.

lorenzofattori
07-07-2017, 02:28 PM
Every Kinetis chip has a small, very special "write once" memory, which is used for the mac address. This memory has 8 words of 64 bits. The other chips have slightly different size memory and some are 32 bit words, but they all work the same way. It start as all 1s when Freescale makes the chip. There's a special command to write to this memory, one word at a time. After the word is written, changing any of its bits from 1 or 0, the entire 64 bits are forever locked. If you try to write again, the chip returns an error status and does not change any bits. Erasing the chip does not erase this very special memory. Once written, it's permanent. Well, at least as permanent as the flash memory retains data, which is at least 20 years at extreme temperature and probably hundreds of years at room temperature.

As each Teensy is tested, PJRC's test gear programs 64 bits of that special "write once" memory with PJRC's IEEE-assigned OUI (mac address upper 24 bits) and a unique serial number. All the other bits of that memory are not touched. But those 64 bits with the mac address are programmed here and can never be altered, even if you fully erase the chip.

Good to know, thanks Paul.
I was thinking was saved somewhere in the EEPROM, and loading my stuff the EEPROM could cause issues retrive the MAC. But i think this is not related.

Both my teensy 3.6 behave the same even with the example of Frank's library.
After being programmed they are showing the entire MAC correctly, if I unplug and re-plug the USB then the last 3 digits of the MAC are 00.
I suppose something is wrong in getting the data, maybe some delay is needed before accessing this special memory?

PaulStoffregen
07-07-2017, 02:56 PM
Before I look into this, can you tell me which OS you're using, and which version of Arduino and Teensyduino you have (click Help > About to check)? These details can really matter for investigating startup speed issues.

lorenzofattori
07-08-2017, 01:29 PM
Before I look into this, can you tell me which OS you're using, and which version of Arduino and Teensyduino you have (click Help > About to check)? These details can really matter for investigating startup speed issues.

Just re-tried with my default configuration: MacOS 10.11 El capitan - Arduino 1.8.2 - Teensyduino 1.36
Tried to place a delay(10000) before the code and still the same behavior, when I unplug and replug Teensy the MAC is wrong


Serial: 0
MAC: 0x04E9E5000000

Update:
I lowered down the CPU speed at 120MHz and now is working fine all the time!
at 144 and 180 is not working after first reboot

PaulStoffregen
07-08-2017, 06:07 PM
I tried just now with a Teensy 3.6 at 180 MHz and default settings running Frank's code. I don't have El Capitan, so I tested on a Macbook Air running Sierra 10.12.5.

10970

I unplugged and reconnected the cable several time. I can't get it to reproduce the problem. Every time I plug it in, the serial monitor shows the correct info. This screenshot was after plugging in several times.

lorenzofattori
07-08-2017, 08:12 PM
I tried just now with a Teensy 3.6 at 180 MHz and default settings running Frank's code. I don't have El Capitan, so I tested on a Macbook Air running Sierra 10.12.5.

10970

I unplugged and reconnected the cable several time. I can't get it to reproduce the problem. Every time I plug it in, the serial monitor shows the correct info. This screenshot was after plugging in several times.

I also have a Ubuntu laptop, I will give it a try and let you know

lorenzofattori
07-10-2017, 06:17 PM
I tried just now with a Teensy 3.6 at 180 MHz and default settings running Frank's code. I don't have El Capitan, so I tested on a Macbook Air running Sierra 10.12.5.

10970

I unplugged and reconnected the cable several time. I can't get it to reproduce the problem. Every time I plug it in, the serial monitor shows the correct info. This screenshot was after plugging in several times.

Tested now With Ubuntu 17.04 - Teensy 3.6 - Arduino 1.8.3 and Teensyduino 1.37
Same issue here running at 180Mhz

Settings:
USB Type: Serial or Serial+Midi
CPU Speed: 180MHz
Optimize: Faster (edit: tried also Debug, same issue)


If you have any idea to test, I'm really willing to do that, I need to make this work
Lorenzo

manitou
07-11-2017, 11:28 AM
Using ubuntu 16.04, IDE 1.8.3/1.37 on T3.6@180mhz, works for me with Fast Faster or Fastest using Frank's example

#include <TeensyMAC.h>

void setup() {
Serial.begin(9600);
}

void loop() {
delay(500);
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
}


MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
...
still works after unplugging/plugging USB cable.

Tested on 2 different T3.6

lorenzofattori
07-11-2017, 05:17 PM
Using ubuntu 16.04, IDE 1.8.8/1.37 on T3.6@180mhz, works for me with Fast Faster or Fastest using Frank's example

#include <TeensyMAC.h>

void setup() {
Serial.begin(9600);
}

void loop() {
delay(500);
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
}


MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
MAC: 0x04E9E5032337
Serial: 2056230
...
still works after unplugging/plugging USB cable.

Tested on 2 different T3.6


wow, this is super strange
so, the only thing I have different is some data saved in the eeprom
I will try to erase the entire eeprom and test again, but this is really funny...

manitou
07-11-2017, 06:00 PM
perhaps you should post the sketch that is failing. And does the simple sketch above work for you ?

manitou
07-11-2017, 07:10 PM
Yeah, verily. the following sketch on T3.6@180mhz exhibits the bad behavior you describe.

/*
eeprom perf (cycle power to confirm)
*/
#include <TeensyMAC.h>
#include <EEPROM.h>


unsigned long t;
void setup()
{
int i,val,errs=0;

Serial.begin(9600); while(!Serial); delay(5000);
Serial.print("EEPROM length: ");
Serial.println(EEPROM.length());
Serial.println("initial read");
for (i=0;i<100;i++) {
val = EEPROM.read(i);
if (val != i) {
Serial.print(val);
Serial.print(" should be ");
Serial.println(i);
errs++;
}
}
Serial.print("read errs "); Serial.println(errs);
#if 0
t=micros();
for (i=0;i<100;i++) EEPROM.write(i, i);
t=micros()-t;
Serial.print("write "); Serial.println(t);
#endif
}

void loop()
{
int i,val;
t=micros();
for (i=0;i<100;i++) val = EEPROM.read(i);
t=micros()-t;
Serial.print("100 reads (us) "); Serial.println(t);
Serial.println(val); // reference val
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
delay(2000);
}


it runs correctly after compile/upload, but unplug/plug USB results in trailing 00's in MAC ?
(you need to run it once with EEPROM write block enabled #if 1 if you want to pass my EEPROM read check in loop())

I don't know why it fails with EEPROM :confused: (doesn't fail @120mhz)

Frank's system register 0x40041000 reads 0 after the unplug/plug, instead of having the stored value of the MAC ?

KurtE
07-11-2017, 07:23 PM
The sketch also works on my MAC running Mac Sierra Tried faster and Fastest with LTO at 180mhz. Also tried modifying and retrieved the serial number and MAC as first lines in code before Serial.begin()...

Is there anything else different about your hardware? Like are you powering from USB or is there external power turning it on and off?

PaulStoffregen
07-11-2017, 08:11 PM
so, the only thing I have different is some data saved in the eeprom


You could have save us quite a bit of time, and had an answer much sooner, if only you had posted the actual code you were really using!

This is why we have the "Forum Rule" about posting complete code. Please, follow this rule. It really is easy to post your *actual* code, and it really does make helping you much easier and faster.

lorenzofattori
07-11-2017, 08:35 PM
You could have save us quite a bit of time, and had an answer much sooner, if only you had posted the actual code you were really using!

This is why we have the "Forum Rule" about posting complete code. Please, follow this rule. It really is easy to post your *actual* code, and it really does make helping you much easier and faster.

Sorry Paul, I didn't want to upset you. I always try to post the code, but this time the code is the same of Frank's library.



#include <TeensyMAC.h>

void setup() {
Serial.begin(9600);
}

void loop() {
delay(500);
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
}


on post #90 I said that both teensy have something stored in the eeprom, but it's not used in the current Sketch
I will try to wipe the eeprom and see if something changes

Update: tried to clear the EEPROM with eeprom_clear but still not behaving correctly using Frank's code.
Tested on Ubuntu with arduino 1.8.3 and teensyduino 1.37

@KurtE: for this test is just teensy 3.6 with nothing connected, powered (and serial) over usb

PaulStoffregen
07-11-2017, 08:37 PM
Ok, I've put this one on my list of bugs to investigate.

manitou
07-11-2017, 08:50 PM
the sketch in post #103 exhibits the strange behavior ...

the smallest test case is to just add #include <EEPROM.h> to Frank's small sketch

lorenzofattori
08-06-2017, 10:15 AM
the sketch in post #103 exhibits the strange behavior ...

the smallest test case is to just add #include <EEPROM.h> to Frank's small sketch

So you confirm you get the same behavior when using eeprom?

manitou
08-06-2017, 12:36 PM
well, upon further review, Frank's sketch

#include <TeensyMAC.h>

void setup() {
Serial.begin(9600);
}

void loop() {
delay(500);
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
}
on T3.6@180mhz works after compile/upload, but if you unplug/plug in USB power, then it reports 0 in lower bytes of MAC. (with no EEPROM refs). @120mhz MAC value is good across power cycles. ? this contradicts what i was getting in earlier posts??, using 1.8.3/1.37.

EDIT: from the K66 beta test thread, this function

void mactst() {
uint64_t num64;
uint32_t num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num64 = *(uint64_t *)&FTFL_FCCOB7;
__enable_irq();
num = num64;
Serial.println(num,HEX);
num = num64>>32;
Serial.println(num,HEX);
}
properly prints the MAC address across power cycles @180mhz (though i actually had remembered that it did not work @180mhz)



EDIT: ARGH On another T3.6@180mhz, the simple sketch is working across power cycles ???? now i'm really confused.
? It will fail if EEPROM.h is present @180mhz, BUT after that, it fails across power cycles, even with EEPROM.h removed???
this is getting above my pay grade

defragster
08-06-2017, 12:49 PM
@Manitou : How is the 'Power Cycle' done if not pulling USB? Perhaps a warm reset/restart?

Where does the TeensyMAC.h in use come from?

Before Paul did the edit for T_3.6's MAC under HSRUN I discovered the MAC could be read before HSRUN was enabled, once the MCU does that it is cached so a failure returns what was there on subsequent calls. That could explain it surviving until power loss, assuming re-programming is not HSRUN speed and leaves the value in the process - and that area isn't cleared.

manitou
08-06-2017, 01:10 PM
@Manitou : How is the 'Power Cycle' done if not pulling USB? Perhaps a warm reset/restart?

Where does the TeensyMAC.h in use come from?

Before Paul did the edit for T_3.6's MAC under HSRUN I discovered the MAC could be read before HSRUN was enabled, once the MCU does that it is cached so a failure returns what was there on subsequent calls. That could explain it surviving until power loss, assuming re-programming is not HSRUN speed and leaves the value in the process - and that area isn't cleared.

yes, by power-cycling i meant, closing the monitor, pulling the USB cable, then plugging it back in, and enabling the monitor.

Frank's TeensyMAC https://github.com/FrankBoesing/TeensyMAC

EEPROM.h does an init() that messes with the FTFL stuff as i recall

lorenzofattori
08-06-2017, 01:25 PM
EDIT: from the K66 beta test thread, this function

void mactst() {
uint64_t num64;
uint32_t num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num64 = *(uint64_t *)&FTFL_FCCOB7;
__enable_irq();
num = num64;
Serial.println(num,HEX);
num = num64>>32;
Serial.println(num,HEX);
}
properly prints the MAC address across power cycles @180mhz (though i actually had remembered that it did not work @180mhz)



I will give it a try with my code and see

lorenzofattori
09-20-2017, 10:31 AM
Ok, I've put this one on my list of bugs to investigate.

will be back on this issue in the next days, any chance that you already had a look on that?


Thanks
Lorenzo

lorenzofattori
03-29-2018, 07:46 PM
Ok, I've put this one on my list of bugs to investigate.


@Paul, any chance you had a look on it? after a lot of months I now need to continue with this project and I was wondering to use the mac or serial for some security checking.

Thanks
Lorenzo

lorenzofattori
04-19-2018, 08:10 PM
well, upon further review, Frank's sketch

#include <TeensyMAC.h>

void setup() {
Serial.begin(9600);
}

void loop() {
delay(500);
Serial.printf("Serial: %u\n", teensySerial());
Serial.printf("MAC: 0x%012llX\n", teensyMAC());
}
on T3.6@180mhz works after compile/upload, but if you unplug/plug in USB power, then it reports 0 in lower bytes of MAC. (with no EEPROM refs). @120mhz MAC value is good across power cycles. ? this contradicts what i was getting in earlier posts??, using 1.8.3/1.37.

EDIT: from the K66 beta test thread, this function

void mactst() {
uint64_t num64;
uint32_t num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num64 = *(uint64_t *)&FTFL_FCCOB7;
__enable_irq();
num = num64;
Serial.println(num,HEX);
num = num64>>32;
Serial.println(num,HEX);
}
properly prints the MAC address across power cycles @180mhz (though i actually had remembered that it did not work @180mhz)



EDIT: ARGH On another T3.6@180mhz, the simple sketch is working across power cycles ???? now i'm really confused.
? It will fail if EEPROM.h is present @180mhz, BUT after that, it fails across power cycles, even with EEPROM.h removed???
this is getting above my pay grade



After a looong time I finally had time to test it, and the code posted here fixes the eeprom bug. thanks

brtaylor
09-26-2019, 12:30 AM
With Teensy 3.6 at any CPU setting above 120 MHz, running this code (https://github.com/FrankBoesing/TeensyMAC/blob/master/examples/PrintInfo/PrintInfo.ino) and library (https://github.com/FrankBoesing/TeensyMAC) works fine if the code is uploaded via USB; however, on power cycles (i.e. unplugging and re-plugging the USB cable) results in 0 for the serial and an incorrect mac address. Arduino version 1.8.9 and Teensyduino 1.46 on Linux Debian 9.

defragster
09-26-2019, 12:44 AM
Certain T_3.6 elements - EEPROM I recall - are inaccessible over 120 MHz when the CPU is overvolted for High Speed Run operation. There is a system call to drop speed& voltage - make the call - then return the voltage&speed:



kinetis_hsrun_disable();

// over 120 MHz restriced access

kinetis_hsrun_enable();


This drops the voltage and the CPU to 120 MHz between those calls. Certain system clocks will be changed with this and some buses will not function properly if active resulting in missed data - Serial UART ports was one for instance.

If more info is needed Paul probably left more distinct notes in the forum try search for :: kinetis_hsrun_

manitou
09-26-2019, 12:45 AM
With Teensy 3.6 at any CPU setting above 120 MHz, running this code (https://github.com/FrankBoesing/TeensyMAC/blob/master/examples/PrintInfo/PrintInfo.ino) and library (https://github.com/FrankBoesing/TeensyMAC) works fine if the code is uploaded via USB; however, on power cycles (i.e. unplugging and re-plugging the USB cable) results in 0 for the serial and an incorrect mac address. Arduino version 1.8.9 and Teensyduino 1.46 on Linux Debian 9.

here is the sketch I use https://github.com/manitou48/teensy3/blob/master/getmac.ino

brtaylor
09-26-2019, 12:52 AM
here is the sketch I use https://github.com/manitou48/teensy3/blob/master/getmac.ino

Awesome, I can confirm that works. Thanks!

manitou
09-26-2019, 01:09 AM
Awesome, I can confirm that works. Thanks!

hmmm, i just ran it on T3.6 and it seems to repeat the first 3 bytes ... need to find my working copy

maybe this


void prmac() {
uint64_t num64;
uint32_t num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num64 = *(uint64_t *)&FTFL_FCCOB7;
__enable_irq();
num = num64;
Serial.println(num,HEX);
num = num64>>32;
Serial.println(num,HEX);

}

brtaylor
09-26-2019, 01:56 AM
hmmm, i just ran it on T3.6 and it seems to repeat the first 3 bytes ... need to find my working copy

maybe this


void prmac() {
uint64_t num64;
uint32_t num;
__disable_irq();
FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL;
*(uint32_t *)&FTFL_FCCOB3 = 0x41070000;
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait
num64 = *(uint64_t *)&FTFL_FCCOB7;
__enable_irq();
num = num64;
Serial.println(num,HEX);
num = num64>>32;
Serial.println(num,HEX);

}

You're right, now that I take a closer look - the bytes are repeated.

The prmac function seems to work fine.

defragster
09-26-2019, 02:03 AM
I just went back to this thread: https://forum.pjrc.com/threads/57595-Serial-amp-MAC-Address-Teensy-4-0 - helped get user to find T4 Serial# - but updated T4 code wasn't integrated back to TeensyID yet.

It links to this : https://github.com/sstaub/TeensyID - that should work for T3.x and T_LC

I haven't tested - assume it works. Not sure if it does anything differently.

As posted on that thread - I pulled the startup code PJRC uses to get the Serial# - that is in the T_3 cores too. Not sure if it does anything differently.