Flash Teensy 3.0 from sd card?

Status
Not open for further replies.

renasis

Active member
Hello,

I have a bootloader for an Arduino 328 that will allow you to flash the chip from a program stored on a sd card. I would like to create the same thing on the Teensy 3.0, but I don't think this is possible, because the bootloader code is not available for the Mini54, so I was wondering what my options are. Perhaps there is another way, without modifying the bootloader code on the Mini54. Maybe I could use an Arduino to feed in the flash code via serial to the Mini54 to load onto arm 4 chip. Would this be possible? If not, are there any other options? (Maybe arm chips have another way to do this?)

Thanks,

-ren
 
It is possible to write to the flash memory on Teensy3. There isn't much in the way of examples, however. You need to actually execute the code which does the write from RAM. Interrupts should be disabled, since you don't want an interrupt to cause any flash access while the write is in progress.

In eeprom.c is a tiny chunk of code which uses the flash controller to reconfigure the eeprom storage. That's probably the closest thing to any example that exists today. There's plenty of documentation on the flash controller in the MK20's reference manual. The basic idea is you write the command and its parameters to the FTFL_FCC0B* registers, then (running from RAM), write 0x80 to FTFL_FSTAT to start the flash programming command. While the flash is busy, FTFL_FSTAT's high bit will be zero. When it's a 1 again, the command is completed. The other bits indicate if any error occurred. Remember to disable interrupts before you start this process!

The reference manual details all the available flash controller commands. They're really pretty simple, once you jump through the hoops of running the flash write stuff from RAM. The code in eeprom.c is definitely worth reusing, since the C syntax is a bit tricky.

If you try this, be extremely careful if you write to memory location 0x0000040C. That byte configures the lock bits when the chip boots up. If you set the protection bits, the Mini54 will be locked out. The Mini54 will try to mass erase the flash to gain access, if you press the pushbutton. If you also disable mass erase, your Teensy3's MK20 will become forever inaccessible to the Mini54, so you'll never be able to access it again with Teensy Loader.

During the normal upload process, the bootloader checks that byte and prevents disable of mass erase. But if you directly access the flash controller, you gain complete access to change the flash in any way. Be careful.
 
The idea is good, but Freescale's flash controller has different commands than Atmel's, so that code won't work directly. You'll need to modify it. The eeprom.c example I mentioned is the best place to start.

Again, be extremely careful if you try to write to 0x0000040C. Best to try writing to somewhere near the end of the flash for testing.
 
Paul,

Thanks for the info. I looked over the documentation. For the most part I understand it. Also looked over eeprom.c. The do_ flash_cmd

(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);

is used to activate the command placed in the ffcob# registers, correct? It would be the same regardless of command? Where did you come up with the numbers for the do_flash_ cmd array?

Also you have a couple lines in there to check status

if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY)

while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {

I don't see any bit to check the program flash status. Am I missing something?

-ren
 
Paul,

I have the code needed to program the flash memory, only issue that I am having now is making the functions work in memory only. Do you have any examples or could you point me to a good resource? Never had to do this before, so I did some research on the internet. Looks like I need an __attribute__ in front of the functions that I need to run from memory and need to update the linker. Based on this I have done the modifications below, but so far have not been able to get it to compile in the Arduino IDE. I get an error indicating that it cannot find the main.cpp file.

main.ino file:

"__attribute__((section(“.mydata”)))" void writetoflash()

mk20dx256.ld file:

SECTIONS
{
.text : {
. = 0;
KEEP(*(.vectors))
*(.startup*)
/* TODO: does linker detect startup overflow onto flashconfig? */
. = 0x400;
KEEP(*(.flashconfig*))
*(.text*)
*(.rodata*)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > FLASH = 0xFF
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} > FLASH
_etext = .;


.mydata : {
*(.mydata*)
} > RAM


.usbdescriptortable (NOLOAD) : {
/* . = ORIGIN(RAM); */
. = ALIGN(512);
*(.usbdescriptortable*)
} > RAM
.dmabuffers (NOLOAD) : {
. = ALIGN(4);
*(.dmabuffers*)
} > RAM
.usbbuffers (NOLOAD) : {
. = ALIGN(4);
*(.usbbuffers*)
} > RAM
.data : AT (_etext) {
. = ALIGN(4);
_sdata = .;
*(.data*)
. = ALIGN(4);
_edata = .;
} > RAM
.noinit (NOLOAD) : {
*(.noinit*)
} > RAM
.bss : {
. = ALIGN(4);
_sbss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
__bss_end = .;
} > RAM
_estack = ORIGIN(RAM) + LENGTH(RAM);
}

Thanks,

-ren
 
Yes, that' interesting.
I'm looking for an solution to run code from ram, too.
Since flash is only 25 Mhz, it should run faster from ram.
 
Paul,

I think that I have resolved the issue with running the functions in memory, just need to know the flash start address. Can you tell me what that is?

Thanks,

-ren
 
Hi

you could try (not tested) something like that, without changing the linkerscript:
Code:
#define __relocate_code__ __attribute__((section("relocate_code"), long_call, noinline))
void myfunc() __relocate_code__;
...
then
Code:
extern  unsigned long __start_relocate_code__;
extern  unsigned long __stop_relocate_code__;

&__start_relocate_code should give the adress, and
(&__stop_relocate_code - &__start_relocate_code) the length

then you should be able to copy - with a loop- the function into an array and call it.

Tell me if it works :)
 
Last edited:
Frank,

Thanks for the tip, I will give it a try, let you know how it works out. I thought that I had the flash programming code working, but there are some items I need to fix.

-ren
 
I think that I have resolved the issue with running the functions in memory, just need to know the flash start address. Can you tell me what that is?

I do not understand this question. Literally, it seems like you're asking where the flash memory begins, but I'm pretty sure you know it starts at location 0x00000000.
 
I think he's talking about the address of a function's code in flash, like &foo. Copying it to RAM should start at that address.

If the compiler provides a means of "moving" a function to RAM, it should add it to a list of to-be-copied values (like those that go into .data) and provide start and end of those values (=of that code).
 
To run same-code in RAM, don't you need to use a compiler/linker switch to force it to generate position-independent code?
 
Paul,

I would like to know the flash address that I should start writting the hex file to. Yes, I understand that flash starts at 0x00000000. I thought that there was an offset into the flash, for the arduino I remember it being something like 0x7800. I thought that this would be the case for the teensy 3 also. I have seen some K20 code on the internet referencing location 0x0C00.

Also, you mentioned earlier not to write to memory location 0x0000040C. Thanks for pointing that out. I thought that would be address that I would skip over. If I am supposed to program that location, what value should I use?

Thanks,

-ren
 
This one works, if you add -mlong-calls to the compiler options:
Code:
extern  unsigned long __start_ram_blink;
extern  unsigned long __stop_ram_blink;

#define __ram_blink__ __attribute__((section("ram_blink"), long_call, used, noinline, aligned (4)))


const int ledPin = 13;
uint32_t ram_blink_arr[500] __attribute__ ((aligned (4)));
void *(*ram_blink_func)();

volatile int i;


static void  blink() __ram_blink__;
static void  blink() 
{
  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(250);                  // wait
  digitalWrite(ledPin, LOW);    // set the LED off
  delay(250);                  // wait
}


void setup()
{  

    delay(1000);
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);

	//copy rom to ram
	//idea taken from mk20dx128.c
	uint32_t *src = &__start_ram_blink;
	uint32_t *dest = &ram_blink_arr[0];
	while (src < &__stop_ram_blink) *dest++ = *src++;
    blink();
}

void loop()
{ 
  Serial.printf("Running function from ram..."); 
  (*((void (*)())((uint32_t)ram_blink_arr+1)))();
}


But calling - for example - printf inside blink() does not work.
I don't know, why (?)

Frank


Edit: printf and other functions work perfectly. i had an other problem :)
 
Last edited:
Paul,

I am trying to allocate a 48kb to a section I call flashboot in the mk20dx128.ld file, but I think that I am having an issue with how the linker is organizing the code. I would like to output a map file from the linker, so I can verify the code location. Does Teensyduino have the ability to do that? Is there command switch that I could use?

Thanks,

-ren
 
The linker has a -Map=filename option. Assuming you are invoking the linker via the compiler driver you would do:

Code:
gcc -Wl,-Map=link.out ...

There is an option, --cref that adds a cross reference table to the link map if you desire it:

Code:
gcc -Wl,--cref,-Map=link.out ...

If you find the link map is causing the linker to run out of memory, you can use the much slower option --reduce-memory-overheads to use the old O(n**2) algorithm instead of the new O(n) algorithm that uses 40% more memory.
 
Michael,

Yes, I see about the compiler options. The issue I am having is trying to specify those options with the Arduino IDE and Teensyduino. I tried setting this option in ..\hardware\teensy\cores\teensy3\Makefile like so

LDFLAGS = -Os -Wl,-Map=link.out --gc-sections -mcpu=cortex-m4 -mthumb -Tmk20dx128.ld

but it doesn't appear to have any effect on the compiler output. The output I see during compilation is such

..\hardware\tools\arm-none-eabi\bin\arm-none-eabi-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mcpu=cortex-m4 -DF_CPU=48000000 ..nothing about mapfile

Perhaps I am editing the wrong Makefile? Do I have the ability to edit these options? The changes that I make in the linker file mk20dx128.ld seem to effect the compiler output, but not the Makefile. If I don't have access to the Makefile options used by Teensyduino, maybe I could specify a command inside the linker to generate a map file? I think you talking about compiling outside of Arduino IDE/Teensyduino, correct? I would rather not do this if not necessary.

Thanks,

-ren
 
I could also use a bootloader that could program the Flash on the Teensy 3.x. I would like to be able to update firmware via Ethernet. I'm interested in knowing how this works out for you.

Eric
 
In theory, we don't need a big shield because the K20 implements a host-mode ?
in theory, yes... but I am unaware of actual code for this. Same for the teensy++2.0... in theory that one can do host mode too, and there is no software there either ;-)

In any case, I need the CDC serial emulation.
 
Status
Not open for further replies.
Back
Top