Condividi tramite


Considerazioni sulla gestione di memoria e latenza

Importante

Questa è la documentazione di Azure Sphere (legacy). Azure Sphere (legacy) viene ritirato il 27 settembre 2027 e gli utenti devono eseguire la migrazione ad Azure Sphere (integrato) entro questo periodo. Usare il selettore di versione posizionato sopra il sommario per visualizzare la documentazione di Azure Sphere (integrata).

Questo argomento contiene alcune considerazioni di base sull'uso della memoria e la latenza per le applicazioni con operazioni in tempo reale che vengono eseguite sul chip MT3620.

Nota

Per altri dettagli sulla configurazione della memoria o DMA, vedere il foglio dati MT3620 pubblicato da MediaTek. Se le domande rimangono, è possibile richiedere il foglio dati "MT3620 M4" da Avnet inviando un messaggio di posta elettronica a Azure.Sphere@avnet.com.

Layout della memoria sui core per operazioni in tempo reale

La tabella seguente presenta una sintesi della memoria disponibile nei core per operazioni in tempo reale:

Tipo di memoria Indirizzo di base
TCM 0x00100000
Flash XIP 0x10000000
SYSRAM 0x22000000

Ogni core per operazioni in tempo reale è dotato di 192 kB di memoria TCM (Tightly-Coupled Memory), mappati in tre banchi da 64 kB a partire dall'indirizzo 0x00100000. Gli accessi alla memoria TCM sono veloci, ma solo i core per operazioni in tempo reale possono accedervi. La memoria TCM non può essere condivisa con un'applicazione di alto livello o con un'applicazione con funzionalità in tempo reale (RTApp) eseguita su un altro core.

Ogni core per operazioni in tempo reale è inoltre dotato di 64 kB di SYSRAM, mappati a partire dall'indirizzo 0x22000000. Il controller DMA può anche gestire la memoria SYSRAM e consentire così alle periferiche di accedervi. Gli accessi alla memoria SYSRAM dal core in tempo reale sono più lenti rispetto agli accessi alla memoria TCM. Come la TCM, la SYSRAM non può essere condivisa con un'altra applicazione.

La memoria flash a esecuzione sul posto (XIP) è condivisa con applicazioni di alto livello. Una finestra del mapping XIP della memoria flash è visibile a ogni core all'indirizzo 0x10000000. Il sistema operativo configura il mapping XIP prima di avviare l'applicazione se il file ELF dell'applicazione contiene un segmento con le proprietà seguenti:

  • Indirizzo di caricamento (come specificato nella colonna VirtAddr dell'intestazione di programma) uguale a 0x10000000
  • Offset e dimensione del file (come specificato nei campi FileSiz e MemSiz nell'intestazione di programma) compresi nei valori definiti nel file ELF dell'applicazione

Se nel file ELF dell'applicazione è presente un'intestazione di programma con queste proprietà, la finestra XIP verrà posizionata in modo da rendere visibile il segmento all'indirizzo 0x10000000. Il file può avere un solo segmento XIP e deve puntare all'indirizzo 0x10000000. Non è possibile specificare altri indirizzi.

Distribuzione di ELF

Le immagini delle applicazioni con operazioni tempo reale devono essere costituite da file ELF. L'immagine ELF viene sottoposta a wrapping in un pacchetto di immagine di Azure Sphere e distribuita come applicazione. Per caricare l'applicazione, il sistema operativo Azure Sphere avvia un caricatore ELF che viene eseguito sul core per operazioni in tempo reale. Il caricatore elabora ogni segmento LOAD nel file ELF e lo carica nel tipo di memoria indicato dall'indirizzo virtuale nell'intestazione di programma.

Per visualizzare le intestazioni di programma per l'applicazione, usare arm-none-eabi-readelf.exe -l (L minuscola), che fa parte di GNU Arm Embedded Toolchain. La colonna dell'indirizzo virtuale (VirtAddr) visualizzata nell'intestazione indica l'indirizzo di destinazione per il segmento LOAD. Questo non significa che il processore stesso esegua altre conversioni. I caricatore ELF di Azure Sphere non usa l'indirizzo fisico (PhysAddr).

Si consideri questo esempio:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000098 0x00100000 0x00100000 0x00000 0x00e78 RW  0x8
  LOAD           0x0000a0 0x10000000 0x10000000 0x03078 0x03078 RWE 0x10
  LOAD           0x003118 0x00100e78 0x10003078 0x000f0 0x000f0 RW  0x4
  • Il segmento all'indirizzo 0x00100000 è destinato alla memoria TCM. Il caricatore copia i dati dal pacchetto dell'immagine nella RAM o inizializza a zero la memoria TCM, come necessario.

  • Il segmento all'indirizzo 0x10000000 è mappato alla finestra XIP per il core. In fase di runtime, gli accessi a 0x10000000 + offset vengono convertiti in <address-of-XIP-segment-in-flash> + offset quando lasciano il core per operazioni in tempo reale.

  • I segmento di dati in corrispondenza dell'indirizzo virtuale 0x00100e78 viene mappato alla memoria TCM.

Considerazioni sul runtime ELF

Il caricatore ELF esegue alcune delle operazioni che verrebbero eseguite all'avvio da un file binario non elaborato (o bootloader concatenato). In particolare, inizializza a zero i dati BSS (Block-Started-by-Symbol) e copia i dati inizializzati, ma modificabili, dalla memoria flash di sola lettura alla RAM, in base alle intestazioni di programma. L'applicazione viene quindi avviata ed esegue le proprie funzioni di inizializzazione. Nella maggior parte dei casi non sono necessarie modifiche alle applicazioni esistenti. L'azzeramento dei dati BSS nell'applicazione non è necessario, ma è innocuo, poiché il caricatore ha già azzerato la memoria.

La copia di dati modificabili dal flash alla RAM può causare problemi, a seconda della disposizione del file ELF. Il caricatore ELF elabora le intestazioni del programma in sequenza, senza modificare il layout complessivo dei segmenti nel file. Esegue quindi il mapping non solo del segmento XIP stesso all'indirizzo 0x10000000, ma anche di tutti i segmenti successivi nell'ordine specificato. Se i segmenti nel file ELF sono disposti in ordine sequenziale, senza allineamento né spazi vuoti, il codice di avvio del sistema operativo può usare l'aritmetica dei puntatori per trovare l'inizio del segmento di dati. Se il file ELF ha un layout diverso, tuttavia, l'aritmetica dei puntatori non consente di identificare l'indirizzo corretto e il codice di avvio dell'applicazione non deve provare a copiare la sezione di dati. Ciò può causare problemi se l'applicazione o l'RTOS usa un bootloader concatenato o deve configurare un canary stack prima di azzerare i dati BSS o inizializzare i dati modificabili.

Destinazioni di memoria

È possibile destinare il codice alla memoria TCM, alla memoria flash XIP o alla memoria SYSRAM modificando lo script linker.ld per l'applicazione. Le applicazioni di esempio di Azure Sphere vengono eseguite dalla memoria TCM, ma il file di script linker.ld per ogni applicazione descrive come specificare la memoria flash XIP come destinazione alternativa. Come illustrato di seguito, è possibile modificare un esempio in modo da consentirne l'esecuzione dalla memoria XIP specificando un alias FLASH in sostituzione del valore TCM predefinito per CODE_REGION e RODATA_REGION:

REGION_ALIAS("CODE_REGION", FLASH);
REGION_ALIAS("RODATA_REGION", FLASH);

Per determinare se un'applicazione compilata viene eseguita dalla memoria TCM o dalla memoria flash XIP, usare arm-none-eabi-readelf.exe, che fa parte di GNU Arm Embedded Toolchain. Eseguire il comando sul file con estensione out, ovvero nella stessa directory del pacchetto dell'immagine, e specificare il flag -l (con L minuscola) per visualizzare la posizione del codice e dei dati di sola lettura. Il codice e i dati di sola lettura destinati alla memoria flash vengono caricati in corrispondenza dell'indirizzo 0x10000000, mentre quelli destinati alla memoria TCM vengono caricati nell'area TCM.

L'esempio seguente mostra un'applicazione che viene eseguita dalla memoria flash.

arm-none-eabi-readelf.exe -l UART_RTApp_MT3620_BareMetal.out

Elf file type is EXEC (Executable file)
Entry point 0x10000000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000074 0x00100000 0x00100000 0x00284 0x003c0 RW  0x4
  LOAD           0x000300 0x10000000 0x10000000 0x013b9 0x013b9 R E 0x10

 Section to Segment mapping:
  Segment Sections...
   00     .data .bss
   01     .text .rodata

Posizione della tabella dei vettori

Nei dispositivi ARMv7-M la tabella dei vettori deve essere allineata a un limite che corrisponde a una potenza di due e le cui dimensioni sono di almeno 128 byte e non inferiori alle dimensioni della tabella, come indicato nel manuale di riferimento dell'architettura ARMv7-M. Ogni core I/O RT in MT3620 supporta 100 interrupt esterni. Pertanto, includendo il puntatore dello stack e 15 eccezioni standard, la tabella contiene 116 voci da 4 byte, per un totale di 464 byte di dimensioni, arrotondate a 512 byte.

Quando il codice viene eseguito dalla memoria flash XIP, la tabella dei vettori deve essere posizionata in corrispondenza di 0x10000000 e deve essere allineata a un limite di 32 byte all'interno del file ELF. Quando il codice non viene eseguito dalla memoria flash XIP, la tabella viene in genere posizionata all'inizio di TCM0, ossia in corrispondenza di 0x100000. In entrambi i casi, per assicurarsi che l'indirizzo virtuale della tabella sia allineato correttamente, inserire la tabella dei vettori in una sezione dedicata e impostare CODE_REGION su un indirizzo appropriato.

Gli esempi MT3620 BareMetal nel repository di esempi di Azure Sphere illustrano come fare. La dichiarazione della tabella dei vettori in main.c imposta il relativo attributo section su .vector_table. Lo script del linker imposta CODE_REGION come alias all'inizio di TCM o XIP e l'attributo ALIGN imposta l'allineamento della sezione di testo all'interno del file ELF come segue:

SECTIONS
{
    .text : ALIGN(32) {
        KEEP(*(.vector_table))
        *(.text)
    } >CODE_REGION
...
}

Considerazioni sull'elaborazione in tempo reale e la latenza

Le applicazioni di alto livello e quelle con operazioni in tempo reale competono per l'accesso alla memoria flash, anche se non comunicano tra loro. Di conseguenza, le applicazioni con operazioni in tempo reale eseguite dalla memoria flash XIP possono presentare problemi di latenza elevata e imprevedibile. Le scritture nella memoria flash, ad esempio durante un aggiornamento, possono comportare picchi di latenza fino a diverse centinaia di millisecondi. A seconda dei requisiti dell'applicazione, è possibile gestire questo problema in diversi modi:

  • Inserire tutto il codice e i dati nella memoria TCM. Il codice eseguito dalla memoria TCM non è vulnerabile a contese per la memoria flash.

  • Suddividere il codice in sezioni critiche e non critiche ed eseguire il codice non critico dalla memoria flash. Il codice che ha requisiti in tempo reale, ad esempio un timer di controllo, non dovrebbe essere eseguito quando altro codice accede alla memoria flash. La sezione Destinazioni di memoria descrive in che modo specificare la memoria flash XIP in sostituzione della memoria TCM come destinazione.

  • Usare la cache. Un'applicazione può usare i 32 kB più bassi della memoria TCM come cache XIP. Questo approccio non offre una garanzia assoluta di elaborazione in tempo reale in caso di mancato riscontro nella cache, ma migliora le prestazioni tipiche senza che sia necessario spostare tutto il codice nella RAM. Per informazioni sulla configurazione della cache XIP, vedere il foglio dati "MT3620 M4".