Gerenciar considerações de memória e latência

Este tópico descreve considerações básicas sobre uso de memória e latência para aplicativos em tempo real executados no chip MT3620.

Nota

Para obter mais detalhes sobre a configuração de memória ou DMA, consulte a planilha de dados MT3620 publicada da MediaTek; se as perguntas permanecerem, você poderá solicitar o "MT3620 M4 Datasheet" da Avnet por email Azure.Sphere@avnet.com.

Layout de memória nos núcleos em tempo real

A tabela a seguir resume a memória disponível nos núcleos em tempo real:

Tipo de memória Endereço Base
TCM 0x00100000
Flash XIP 0x10000000
SYSRAM 0x22000000

Cada núcleo em tempo real tem 192 KB de TCM (memória fortemente acoplada), que é mapeado em três bancos de 64 KB a partir de 0x00100000. Os acessos TCM são rápidos, mas somente o núcleo em tempo real pode acessar a memória. O TCM não pode ser compartilhado com um aplicativo de alto nível ou com um RTApp (aplicativo capaz em tempo real) que é executado em um núcleo diferente.

Cada núcleo em tempo real também tem 64 KB de SYSRAM, que é mapeado a partir de 0x22000000. O controlador DMA também pode atingir o SYSRAM, para que os periféricos possam acessá-lo. Os acessos ao SYSRAM do núcleo em tempo real são mais lentos do que os acessos ao TCM. Assim como no TCM, o SYSRAM não pode ser compartilhado com outro aplicativo.

A memória flash de execução no local (XIP) é compartilhada com aplicativos de alto nível. Uma janela para o mapeamento XIP do flash é visível para cada núcleo no endereço 0x10000000. O sistema operacional configura o mapeamento XIP antes de iniciar o aplicativo se o arquivo ELF do aplicativo contiver um segmento que tenha as seguintes propriedades:

  • O endereço de carga (conforme especificado na coluna VirtAddr do Cabeçalho do Programa) é igual a 0x10000000
  • Deslocamento e tamanho do arquivo (conforme especificado nos campos FileSiz e MemSiz no Cabeçalho do Programa) se encaixam no arquivo ELF do aplicativo

Se um cabeçalho de programa com essas propriedades estiver presente no arquivo ELF do aplicativo, a janela XIP será posicionada para que o segmento fique visível em 0x10000000. O arquivo não pode ter mais de um segmento XIP e deve apontar para 0x10000000; ele não pode especificar nenhum outro endereço.

Implantação de ELF

As imagens RTApp devem ser arquivos ELF. A imagem ELF é encapsulada em um pacote de imagens do Azure Sphere e implantada como um aplicativo. Para carregar o aplicativo, o sistema operacional do Azure Sphere inicia um carregador ELF que é executado no núcleo em tempo real. O carregador processa cada segmento LOAD no arquivo ELF e o carrega no tipo de memória indicado pelo endereço virtual no cabeçalho do programa.

Use arm-none-eabi-readelf.exe -l (lowercase L), que faz parte do GNU Arm Embedded Toolchain, para exibir os cabeçalhos do programa para seu aplicativo. A coluna de endereço virtual (VirtAddr) exibida no cabeçalho indica o endereço de destino para o segmento de carga. Isso não significa que o próprio processador execute nenhuma tradução adicional. O carregador ELF do Azure Sphere não usa o endereço físico (PhysAddr).

Considere este exemplo:

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
  • O segmento em 0x00100000 é direcionado a TCM (memória fortemente acoplada). O carregador copia dados do pacote de imagem em RAM ou inicializa zero o TCM conforme necessário.

  • O segmento em 0x10000000 é mapeado para a janela XIP para o núcleo. Em tempo de execução, os acessos a 0x10000000 + offset são traduzidos para <address-of-XIP-segment-in-flash> + offset quando saem do núcleo em tempo real.

  • O segmento de dados no endereço virtual 0x00100e78 é mapeado para TCM.

Considerações sobre o runtime do ELF

O carregador ELF executa algumas das tarefas que um binário bruto (ou inicializador encadeado) executaria na inicialização. Especificamente, ele inicializa dados BSS (block-started-by-symbol) e copia dados inicializados, mas mutáveis do flash somente leitura na RAM, de acordo com os cabeçalhos do programa. Em seguida, o aplicativo inicia e executa suas próprias funções de inicialização. Na maioria dos casos, as alterações em aplicativos existentes não são necessárias. Zerar os dados do BSS no aplicativo é desnecessário, mas inofensivo, porque o carregador já zerou a memória.

Copiar dados mutáveis do flash para a RAM pode, em algumas circunstâncias, resultar em problemas, dependendo de como o arquivo ELF é definido. O carregador ELF processa os cabeçalhos do programa sequencialmente, sem alterar o layout geral dos segmentos no arquivo. Em seguida, ele mapeia não apenas o segmento XIP em si para 0x10000000, mas também todos os segmentos subsequentes em ordem. Se os segmentos no arquivo ELF estiverem em ordem sequencial sem nenhum alinhamento ou lacunas, o código de inicialização do sistema operacional poderá usar aritmética de ponteiro para localizar o início do segmento de dados. No entanto, se o arquivo ELF tiver um layout diferente, a aritmética do ponteiro não resultará no endereço correto, portanto, o código de inicialização do aplicativo não deve tentar copiar a seção de dados. Isso pode causar problemas se o aplicativo ou o RTOS usar um bootloader encadeado ou precisar configurar um canário de pilha antes de zerar o BSS ou inicializar dados mutáveis.

Destinos de memória

Você pode direcionar o código no TCM, no flash XIP ou no SYSRAM editando o script linker.ld para seu aplicativo. Os aplicativos de exemplo do Azure Sphere são executados a partir do TCM, mas o arquivo de script linker.ld para cada aplicativo descreve como direcionar o flash XIP. Como o exemplo a seguir mostra, você pode alterar um exemplo para ser executado no XIP, aliasing CODE_REGION e RODATA_REGION para FLASH em vez do TCM padrão:

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

Para determinar se um aplicativo compilado é executado do flash TCM ou XIP, use arm-none-eabi-readelf.exe, que faz parte do Conjunto de Ferramentas Incorporados do Braço GNU. Execute-o no arquivo .out, que está no mesmo diretório que o pacote de imagem, e especifique o -l sinalizador (minúscula L) para ver onde o código e os dados somente leitura foram colocados. Os dados somente código e leitura que estão na memória flash são carregados no endereço 0x10000000; código e dados no TCM são carregados na região do TCM.

O exemplo a seguir mostra um aplicativo que é executado a partir da memória 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

Local da tabela do vetor

Em dispositivos ARMv7-M, a tabela vetor deve ser alinhada em um limite de potência de dois que seja pelo menos 128 bytes e não menor que o tamanho da tabela, conforme observado no Manual de Referência de Arquitetura ARMv7-M. Cada núcleo RT de E/S no MT3620 dá suporte a 100 interrupções externas. Portanto, incluindo o ponteiro de pilha e 15 exceções padrão, a tabela tem 116 entradas de 4 bytes, para um tamanho total de 464 bytes, que arredonda até 512 bytes.

Quando o código é executado do flash XIP, a tabela de vetor deve ser colocada em 0x10000000 e deve ser alinhada em um limite de 32 bytes dentro do arquivo ELF. Quando o código não é executado do flash XIP, a tabela normalmente é colocada no início do TCM0, que é 0x100000. Em ambos os casos, para garantir que o endereço virtual da tabela esteja corretamente alinhado, coloque a tabela do vetor em uma seção dedicada e defina CODE_REGION para o endereço apropriado.

Os exemplos do MT3620 BareMetal no repositório Exemplos do Azure Sphere mostram como fazer isso. A declaração da tabela de vetor em main.c define seu section atributo como .vector_table. Os aliases de script do vinculador CODE_REGION ao início do TCM ou XIP e o atributo ALIGN define o alinhamento da seção de texto no arquivo ELF da seguinte maneira:

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

Considerações sobre tempo real e latência

RTApps e aplicativos de alto nível exigem acesso à memória flash, mesmo que não se comuniquem entre si. Como resultado, os RTApps que estão em execução do flash XIP podem encontrar latência alta e imprevisível. Gravações no flash, como durante uma atualização, podem envolver picos de latência de até várias centenas de milissegundos. Dependendo dos requisitos do aplicativo, você pode gerenciar isso de várias maneiras:

  • Coloque todos os códigos e dados no TCM. O código que é executado do TCM não é vulnerável à contenção de flash.

  • Divida o código em seções críticas e não críticas e execute o código não crítico do flash. O código que tem requisitos em tempo real, como um temporizador de cão de guarda, não deve ser executado quando outro código estiver acessando o flash. Os destinos de memória descrevem como direcionar o flash XIP em vez de TCM.

  • Use cache. Um aplicativo pode usar os 32KB mais baixos do TCM como cache XIP. Essa abordagem não fornece garantias difíceis em tempo real no caso de uma falha de cache, mas melhora o desempenho típico sem exigir que você mova todo o código para a RAM. Consulte o "Mt3620 M4 Datasheet" para obter informações sobre a configuração de cache XIP.