Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Ricerca personalizzata

[MCU Kinetis] Distribuire firmware su diverse memorie

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

0
voti

[1] [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto UtenteGuidoB » 28 dic 2017, 10:16

Buongiorno a tutti i partecipanti.

Sto facendo delle prove su una scheda della Freescale (ora NXP) FRDM-K82F, contenente un microcontrollore Kinetis MK82FN256VLL15 (ARM Cortex M4).

Il codice eseguibile può risiedere su tre memorie interne al micro (32 kB di ROM, 256 kB di Flash interna e 256 kB di RAM) e su una memoria esterna (8 MB di QSPI Flash). I 32 kB di ROM contengono un bootloader semi-bacato di fabbrica.

Le dimensioni del firmware che verrà caricato sono superiori a 256 KB, per cui è obbligato l'uso della QSPI Flash (esterna). Tuttavia non tutto il firmware può stare lì, per diversi motivi.

Il problema per cui adesso sto cercando una soluzione è: alcune procedure devono essere eseguite alla massima velocità possibile e pertanto devono essere memorizzate nella Flash interna, più rapida e dotata di cache migliore.

Alcune procedure corte di esempio che ho visto vengono implementate in assembly e scritte in RAM o Flash interna, e da lì cambiano la frequenza di clock della QSPI, o ne cancellano e scrivono blocchi (non possono stare nella QSPI Flash, altrimenti quando vengono eseguite il micro si blocca).

Ma non posso applicare questa soluzione perché le procedure da spostare in Flash interna non sono piccole, sono librerie piuttosto corpose scritte in C.

L'ideale per me sarebbe indicare al linker dove memorizzare una procedura o una singola libreria, se in QSPI Flash o in Flash interna, ma non so come fare.

Qualcuno ha qualche suggerimento o documento da indicarmi?

L'IDE che utilizzo è Kinetis Design Studio 3.2.0. Avrei qualche vantaggio al passare a MCUXpresso?

Grazie.
Big fan of ƎlectroYou! \O-<
Avatar utente
Foto UtenteGuidoB
13,0k 5 12 13
G.Master EY
G.Master EY
 
Messaggi: 1943
Iscritto il: 3 mar 2011, 15:48
Località: Madrid

1
voti

[2] Re: [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto Utenteharpefalcata » 28 dic 2017, 11:53

Pur ammettendo di non aver studiato il datasheet del controller che stai usando, tutto dipende da come, questa memoria esterna venga vista dal tuo controller.

Da come ne parli, sembra che l'MCU ammetta l'impiego di memorie esterne, come estensione della sua flash interna, e quindi che possa eseguire codice sorgente, anche se messo su memoria esterna.

Ammesso e non concesso che queste mie supposizioni siano corrette, ti sarebbe sufficiente modificare il linker in maniera tale da specificare l'indirizzo esatto nel quale comincia la memoria esterna e, dire in quella sezione del linker che, quella particolare routine, con quel particolare nome, deve essere messa a partire da quel particolare indirizzo.

In questo modo, ci penserà poi il compilatore a programmare la memoria esterna con quel frammento di codice che tu hai specificato di mettere lì, e ripeti lo stesso per tutte le routine che vuoi mettere sulla memoria esterna invece che sulla flash interna.

Ribadisco però il concetto: tutto dipende da come questa memoria esterna venga vista in termini di espansione di memoria.

Mi sembra una procedura un po' atipica per un controller, per la ROM di solito viene decisa in fabbrica ed integrata nel controller stesso.

Se ho capito male comunque, magari spiegami un po meglio. Grazie.
Avatar utente
Foto Utenteharpefalcata
198 3 5
Frequentatore
Frequentatore
 
Messaggi: 208
Iscritto il: 28 lug 2015, 20:03

0
voti

[3] Re: [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto UtenteGuidoB » 28 dic 2017, 12:47

harpefalcata ha scritto:Da come ne parli, sembra che l'MCU ammetta l'impiego di memorie esterne, come estensione della sua flash interna, e quindi che possa eseguire codice sorgente, anche se messo su memoria esterna.

Sì, è così.
Le memorie vengono viste a vari indirizzi, ad esempio la Flash interna inizia all'indirizzo 0x0000 0000, la QSPI all'indirizzo 0x6800 0000 e così via.

harpefalcata ha scritto:Ammesso e non concesso che queste mie supposizioni siano corrette, ti sarebbe sufficiente modificare il linker in maniera tale da specificare l'indirizzo esatto nel quale comincia la memoria esterna e, dire in quella sezione del linker che, quella particolare routine, con quel particolare nome, deve essere messa a partire da quel particolare indirizzo.

È proprio questo che non so fare. C'è un file (MK82FN256xxx15.ld) che dovrebbe aver qualcosa a che fare, ma le sezioni non vanno per nome di procedura o libreria. Qui un esempio che carica il codice principale nella QSPI:

Codice: Seleziona tutto
/*
** ###################################################################
**     Processors:          MK82FN256CAx15
**                          MK82FN256VDC15
**                          MK82FN256VLL15
**                          MK82FN256VLQ15
**
**     Compiler:            GNU C Compiler
**     Reference manual:    K82P121M150SF5RM, Rev. 0, May 2015
**     Version:             rev. 1.0, 2015-04-09
**     Build:               b151118
**
**     Abstract:
**         Linker file for the GNU C Compiler
**
**     Copyright (c) 2015 Freescale Semiconductor, Inc.
**     All rights reserved.
**
**     Redistribution and use in source and binary forms, with or without modification,
**     are permitted provided that the following conditions are met:
**
**     o Redistributions of source code must retain the above copyright notice, this list
**       of conditions and the following disclaimer.
**
**     o Redistributions in binary form must reproduce the above copyright notice, this
**       list of conditions and the following disclaimer in the documentation and/or
**       other materials provided with the distribution.
**
**     o Neither the name of Freescale Semiconductor, Inc. nor the names of its
**       contributors may be used to endorse or promote products derived from this
**       software without specific prior written permission.
**
**     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
**     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
**     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
**     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
**     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
**     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
**     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
**     ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
**     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**     http:                 www.freescale.com
**     mail:                 support@freescale.com
**
** ###################################################################
*/

/* Entry Point */
ENTRY(Reset_Handler)

HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x0400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400;
M_VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0x03C0 : 0x0;

/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x000003C0
  m_bootloader_config   (RX)  : ORIGIN = 0x000003C0, LENGTH = 0x00000040
  m_flash_config        (RX)  : ORIGIN = 0x00000400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x68001000, LENGTH = 0x01000000
  m_data                (RW)  : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000
  m_data_2              (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00030000
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into internal flash */
  .interrupts :
  {
    __VECTOR_TABLE = .;
    . = ALIGN(4);
    KEEP(*(.isr_vector))     /* Startup code */
    . = ALIGN(4);
  } > m_interrupts

  .bootloader_config :
  {
    . = ALIGN(4);
    KEEP(*(.BootloaderConfig)) /* Bootloader Configuration Area (BCA) */
    . = ALIGN(4);
  } > m_bootloader_config

  .flash_config :
  {
    . = ALIGN(4);
    KEEP(*(.FlashConfig))    /* Flash Configuration Field (FCF) */
    . = ALIGN(4);
  } > m_flash_config

  /* The program code and other data goes into internal flash */
  .text :
  {
    . = ALIGN(4);
    *(.text)                 /* .text sections (code) */
    *(.text*)                /* .text* sections (code) */
    *(.rodata)               /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)               /* glue arm to thumb code */
    *(.glue_7t)              /* glue thumb to arm code */
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
  } > m_text

  .ARM.extab :
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > m_text

  .ARM :
  {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } > m_text

.ctors :
  {
    __CTOR_LIST__ = .;
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       from the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
    __CTOR_END__ = .;
  } > m_text

  .dtors :
  {
    __DTOR_LIST__ = .;
    KEEP (*crtbegin.o(.dtors))
    KEEP (*crtbegin?.o(.dtors))
    KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
    __DTOR_END__ = .;
  } > m_text

  .preinit_array :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } > m_text

  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } > m_text

  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } > m_text

  __etext = .;    /* define a global symbol at end of code */
  __DATA_ROM = .; /* Symbol is used by startup for data initialization */

  .interrupts_ram :
  {
    . = ALIGN(4);
    __VECTOR_RAM__ = .;
    __interrupts_ram_start__ = .; /* Create a global symbol at data start */
    *(.m_interrupts_ram)     /* This is a user defined section */
    . += M_VECTOR_RAM_SIZE;
    . = ALIGN(4);
    __interrupts_ram_end__ = .; /* Define a global symbol at data end */
  } > m_data

  __VECTOR_RAM = DEFINED(__ram_vector_table__) ? __VECTOR_RAM__ : ORIGIN(m_interrupts);
  __RAM_VECTOR_TABLE_SIZE_BYTES = DEFINED(__ram_vector_table__) ? (__interrupts_ram_end__ - __interrupts_ram_start__) : 0x0;

  .data : AT(__DATA_ROM)
  {
    . = ALIGN(4);
    __DATA_RAM = .;
    __data_start__ = .;      /* create a global symbol at data start */
    *(.data)                 /* .data sections */
    *(.data*)                /* .data* sections */
    KEEP(*(.jcr*))
    . = ALIGN(4);
    __data_end__ = .;        /* define a global symbol at data end */
  } > m_data

  __DATA_END = __DATA_ROM + (__data_end__ - __data_start__);
  text_end = ORIGIN(m_text) + LENGTH(m_text);
  ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data")

  USB_RAM_GAP = DEFINED(__usb_ram_size__) ? __usb_ram_size__ : 0x800;
  /* Uninitialized data section */
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    . = ALIGN(4);
    __START_BSS = .;
    __bss_start__ = .;
    *(.bss)
    *(.bss*)
    . = ALIGN(512);
    USB_RAM_START = .;
    . += USB_RAM_GAP;
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
    __END_BSS = .;
  } > m_data

  .heap :
  {
    . = ALIGN(8);
    __end__ = .;
    PROVIDE(end = .);
    __HeapBase = .;
    . += HEAP_SIZE;
    __HeapLimit = .;
  } > m_data_2

  .stack :
  {
    . = ALIGN(8);
    . += STACK_SIZE;
  } > m_data_2

  m_usb_bdt USB_RAM_START :
  {
    *(m_usb_bdt)
    USB_RAM_BDT_END = .;
  }

  m_usb_global USB_RAM_BDT_END :
  {
    *(m_usb_global)
  }

  /* Initializes stack on the end of block */
  __StackTop   = ORIGIN(m_data_2) + LENGTH(m_data_2);
  __StackLimit = __StackTop - STACK_SIZE;
  PROVIDE(__stack = __StackTop);

  .ARM.attributes 0 : { *(.ARM.attributes) }

  ASSERT(__StackLimit >= __HeapLimit, "region m_data_2 overflowed with stack and heap")
}


Non trovo la spiegazione di questa sintassi e come scegliere la memoria per ogni libreria.

harpefalcata ha scritto:Mi sembra una procedura un po' atipica per un controller, per la ROM di solito viene decisa in fabbrica ed integrata nel controller stesso.

La ROM infatti ha un contenuto fisso di fabbrica, comincia all'indirizzo 0x1C00 0000 e non la posso né devo modificare.

Grazie per l'interessamento.
Big fan of ƎlectroYou! \O-<
Avatar utente
Foto UtenteGuidoB
13,0k 5 12 13
G.Master EY
G.Master EY
 
Messaggi: 1943
Iscritto il: 3 mar 2011, 15:48
Località: Madrid

1
voti

[4] Re: [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto Utenteluxinterior » 28 dic 2017, 13:01

A me sembra strano che in runtime esegua codice da una memoria seriale.
Non so aiutarti col linker ma penso che sia come ogni linker
devi definire dei segmenti e poi piazzi i segmenti nell'area di indirizzi che vuoi.

Domanda: come carichi il codice ? Non è che devi fare due file distinti e quindi due compialzioni distinte una per ili codice e una per la libreria da mettere nella flash seriale ?

Hai il file di startup del progetto ? In quel file dovrebbe esserci la definizione dle segmento .text dove poi accoda tutto il codice.

Dovresti vedere come si definisce un nuovo segmento con lo GNU Poi devi indcare la sezione (l'area di memoria) come fa con m_text nel tuo esempio e infine dentro la sezione ci piazzi il o i segmenti che vuoi (Vedi ad esempio le righe sopra > m_text)
Avatar utente
Foto Utenteluxinterior
1.668 1 4 8
Expert EY
Expert EY
 
Messaggi: 826
Iscritto il: 6 gen 2016, 16:48

1
voti

[5] Re: [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto Utentexyz » 28 dic 2017, 13:43

GuidoB ha scritto:Non trovo la spiegazione di questa sintassi e come scegliere la memoria per ogni libreria.

Stai usando il toolchain del GCC ?

La sintassi è quella dei "Linker Scripts", qui trovi la documentazione:

https://sourceware.org/binutils/docs/ld ... ml#Scripts
http://www.bravegnu.org/gnu-eprog/lds.html

Si tratta della sintassi usata da linker "LD" presente nelle Binutils usati dal compilatore GCC per generare i file binari finali. Permette di specificare in modo preciso dove mettere ogni singolo segmento, parti di codice, funzioni, ecc... all'interno dello spazio di memoria dell'architettura selezionata per generare i file binari.
Avatar utente
Foto Utentexyz
4.165 2 4 5
Master EY
Master EY
 
Messaggi: 1108
Iscritto il: 5 dic 2009, 17:37
Località: Italy Turin

0
voti

[6] Re: [MCU Kinetis] Distribuire firmware su diverse memorie

Messaggioda Foto UtenteGuidoB » 28 dic 2017, 15:08

luxinterior ha scritto:A me sembra strano che in runtime esegua codice da una memoria seriale.

Ti assicuro che lo fa (ho provato) e non è l'unica marca di micro in grado di farlo.

luxinterior ha scritto:Domanda: come carichi il codice ?

O lo faccio con l'IDE (con interfaccia di debug via USB) o uso il bootloader in ROM (da un'altra USB, i file da caricare in formato .srec e .bin prodotti da vari tool e trasformati in formato .sb da elftosb, e il programma blhost che parla col bootloader e carica il file .sb sul micro: un bel casino, ma ho fatto uno script che lo automatizza e dribbla i bachi dei vari tool).

luxinterior ha scritto:Non è che devi fare due file distinti e quindi due compialzioni distinte una per ili codice e una per la libreria da mettere nella flash seriale ?

Così dovrei poi linkare "a mano" le varie chiamate, ma sicuramente ci sarebbero ulteriori problemi come doppia allocazione di stack e aree dati, insufficiente dimensione dello stack ecc. Quindi preferisco farlo fare al linker in un file solo.

luxinterior ha scritto:Hai il file di startup del progetto ? In quel file dovrebbe esserci la definizione dle segmento .text dove poi accoda tutto il codice.

Dovresti vedere come si definisce un nuovo segmento con lo GNU Poi devi indcare la sezione (l'area di memoria) come fa con m_text nel tuo esempio e infine dentro la sezione ci piazzi il o i segmenti che vuoi (Vedi ad esempio le righe sopra > m_text)

Ok, guardo.


xyz ha scritto:Stai usando il toolchain del GCC ?
La sintassi è quella dei "Linker Scripts", qui trovi la documentazione:
...
Permette di specificare in modo preciso dove mettere ogni singolo segmento, parti di codice, funzioni, ecc... all'interno dello spazio di memoria dell'architettura selezionata per generare i file binari.

:ok: :ok: :ok: Sì, uso GCC con la sua toolchain. Grazie, mi studio i documenti che mi hai indicato!!!
Big fan of ƎlectroYou! \O-<
Avatar utente
Foto UtenteGuidoB
13,0k 5 12 13
G.Master EY
G.Master EY
 
Messaggi: 1943
Iscritto il: 3 mar 2011, 15:48
Località: Madrid


Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 3 ospiti