Comunicação entre núcleos assimétricos com o i.MX6SoloX da Freescale
- por Sergio Prado
Lançado em fevereiro na Embedded World 2015, o i.MX6SoloX da Freescale é o primeiro SoC (System on Chip) do mercado com os núcleos ARM Cortex-A9 e Cortex-M4. Devido à sua arquitetura assimétrica, este chip permite executar sistemas operacionais diferentes em cada núcleo, de forma independente.
Por exemplo, podemos ter o kernel Linux rodando no Cortex-A9 e gerenciando a comunicação e a interface com o usuário, e no Cortex-M4 podemos colocar um RTOS (FreeRTOS, MQX, etc) para tratar eventos de tempo real da aplicação. Tudo isso no mesmo SoC!
Além dos núcleos de processamento, o i.MX6SoloX possui uma GPU 2D/3D Vivante para processamento gráfico, suporte para câmera e display, além de diversas interfaces de comunicação e controle como ethernet, PCIe, USB, I2C, I2S, etc.
Eu fui um dos felizardos a receber em primeira mão da Freescale uma placa com o i.MX6SoloX para testar a comunicação entre os núcleos do SoC. Esta placa é a SABRE Board for Smart Devices Based on the i.MX 6SoloX.
Ela é bem completa, e além do i.MX6SoloX, possui 1G de RAM, 64MB de flash NOR, três interfaces de cartão SD, saída para display RGB e LVDS, câmera, entrada e saída de áudio, portas USB host e OTG, ethernet gigabit, CAN, PCIe, conversores A/D e sensores (acelerômetro, compasso e luz ambiente).
Uma das portas USB possui um chip da FTDI que, quando conectada ao host, cria automaticamente duas portas seriais, uma para acessar a console do Linux rodando no Cortex-A9 e outra para acessar a console do firmware rodando no Cortex-M4.
O objetivo deste artigo é descrever os passos necessários para compilar e testar uma aplicação de demonstração da Freescale para a comunicação entre os dois núcleos de processamento.
Rodaremos o Linux no Cortex-A9 e o MQX no Cortex-M4. Os dois kernels se comunicarão através de uma região de memória compartilhada utilizando a biblioteca MCC (MultiCore Communication) da Freescale.
Para realizar este trabalho, consultei o BSP (Board Support Package) liberado pela Freescale para esta plataforma. Tive problemas na execução de alguns passos específicos, mas consegui solucionar consultando o fórum do i.MX Community.
PREPARANDO O AMBIENTE
Todos os testes foram realizados em uma máquina com o sistema operacional Ubuntu 14.04 64 bits.
O primeiro passo é instalar na máquina de desenvolvimento as ferramentas que utilizaremos para compilar a distribuição Linux e testar a aplicação:
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm picocom |
Instale também a ferramenta repo, que será utilizada para baixar o código-fonte do BSP da Freescale (baseado no Yocto Project):
$ mkdir ~/bin $ curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo $ chmod a+x ~/bin/repo $ export PATH=${PATH}:~/bin |
Crie uma variável de ambiente para armazenar o nome do diretório que utilizaremos para compilar o firmware do MQX e a distribuição Linux (não se esqueça de recriar esta variável caso encerre o terminal corrente ou abra um novo terminal):
$ export IMX6SOLOX=~/imx6solox $ mkdir -p $IMX6SOLOX |
DISTRIBUIÇÃO LINUX
Vamos primeiro colocar o Linux para rodar no Cortex-A9.
O boot do sistema é realizado por uma das interfaces de cartão SD da placa. É possível gravar uma imagem pré-compilada distribuída junto com o BSP ou compilar uma imagem usando as ferramentas do Yocto Project. Neste tutorial vamos optar pela segunda opção.
Crie um diretório e baixe o código-fonte da camadas de BSP da Freescale:
$ cd $IMX6SOLOX $ mkdir -p fsl-release-bsp && cd fsl-release-bsp $ repo init -u git://git.freescale.com/imx/fsl-arm-yocto-bsp.git -b imx-3.10.53-1.1.0_ga $ repo sync |
Agora compile a distribuição Linux com os comandos abaixo:
$ MACHINE=imx6sxsabresd source fsl-setup-release.sh -b build $ bitbake core-image-minimal |
A compilação pode levar algumas horas, dependendo da capacidade da sua máquina de desenvolvimento. Ao final, as imagens estarão disponíveis no diretório abaixo:
$ cd tmp/deploy/images/imx6sxsabresd/ $ ls core-image-minimal-imx6sxsabresd-20150331171304.rootfs.ext3 zImage--3.10.53-r0-imx6sx-sdb-emmc-20150331171304.dtb core-image-minimal-imx6sxsabresd-20150331171304.rootfs.manifest zImage--3.10.53-r0-imx6sx-sdb-lcdif1-20150331171304.dtb core-image-minimal-imx6sxsabresd-20150331171304.rootfs.sdcard zImage--3.10.53-r0-imx6sx-sdb-ldo-20150331171304.dtb core-image-minimal-imx6sxsabresd-20150331171304.rootfs.tar.bz2 zImage--3.10.53-r0-imx6sx-sdb-m4-20150331171304.dtb core-image-minimal-imx6sxsabresd.ext3 zImage--3.10.53-r0-imx6sx-sdb-reva-20150331171304.dtb core-image-minimal-imx6sxsabresd.manifest zImage--3.10.53-r0-imx6sx-sdb-reva-ldo-20150331171304.dtb core-image-minimal-imx6sxsabresd.sdcard zImage--3.10.53-r0-imx6sx-sdb-sai-20150331171304.dtb core-image-minimal-imx6sxsabresd.tar.bz2 zImage-imx6sxsabresd.bin modules--3.10.53-r0-imx6sxsabresd-20150331171304.tgz zImage-imx6sx-sdb.dtb modules-imx6sxsabresd.tgz zImage-imx6sx-sdb-emmc.dtb README_-_DO_NOT_DELETE_FILES_IN_THIS_DIRECTORY.txt zImage-imx6sx-sdb-lcdif1.dtb u-boot.imx zImage-imx6sx-sdb-ldo.dtb u-boot-imx6sxsabresd-2014.04-r0.imx zImage-imx6sx-sdb-m4.dtb u-boot-imx6sxsabresd.imx zImage-imx6sx-sdb-reva.dtb zImage zImage-imx6sx-sdb-reva-ldo.dtb zImage--3.10.53-r0-imx6sxsabresd-20150331171304.bin zImage-imx6sx-sdb-sai.dtb zImage--3.10.53-r0-imx6sx-sdb-20150331171304.dtb |
Grave a imagem com extensão .sdcard no cartão SD (substitua /dev/sdX no comando abaixo pelo nome do arquivo de dispositivo do cartão SD):
$ sudo dd if=core-image-minimal-imx6sxsabresd.sdcard of=/dev/sdX bs=1M && sync |
Para testar, coloque o cartão SD na interface SD4 da placa e conecte sua máquina de desenvolvimento ao target com um cabo USB no conector J16 da placa.
Utilize sua aplicação de terminal preferida para testar o boot do Linux. Para logar, o usuário é root e não precisa de senha.
Booting Linux on physical CPU 0x0 Linux version 3.10.53-1.1.0_ga+g496fbe0b831b (sprado@sprado-desktop) (gcc version 4.8.2 (GCC) ) #1 SMP PREEMPT Tue Mar 31 14:47:46 BRT 2015 CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c53c7d CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache Machine: Freescale i.MX6 SoloX (Device Tree), model: Freescale i.MX6 SoloX SDB Board [...] Poky (Yocto Project Reference Distro) 1.6.2 imx6sxsabresd /dev/ttymxc0 imx6sxsabresd login: |
FIRMWARE MQX
No Cortex-M4 rodaremos uma aplicação baseada no MQX, o sistema operacional de tempo real da Freescale.
O primeiro passo é baixar a última versão do código-fonte do MQX para o i.MX6SoloX do site da Freescale. Nos meus testes, utilizei a versão 4.1.0. Não esqueça de baixar a versão para Linux (*.gz).
Crie um diretório e descompacte o código-fonte nele:
$ cd $IMX6SOLOX $ mkdir -p mqx && cd mqx $ tar xfv ~/Downloads/Freescale\ MQX\ RTOS\ 4.1.0\ for\ i.MX\ 6SoloX\ Linux\ Base.gz |
Verifique se o código-fonte foi descompactado corretamente:
$ ls build config doc mcc mqx tools |
Antes de compilar o MQX, precisamos de um toolchain. Baixe o instale o toolchain com os comandos abaixo:
$ cd $IMX6SOLOX $ mkdir -p toolchain && cd toolchain $ wget https://launchpad.net/gcc-arm-embedded/4.8/4.8-2014-q1-update/+download/gcc-arm-none-eabi-4_8-2014q1-20140314-linux.tar.bz2 $ tar xfv gcc-arm-none-eabi-4_8-2014q1-20140314-linux.tar.bz2 && rm gcc-arm-none-eabi-4_8-2014q1-20140314-linux.tar.bz2 |
Agora retorne ao diretório do código-fonte do MQX e compile-o:
$ cd $IMX6SOLOX/mqx/build/imx6sx_sdb_m4/make $ export TOOLCHAIN_ROOTDIR=$IMX6SOLOX/toolchain/gcc-arm-none-eabi-4_8-2014q1 $ ./build_gcc_arm.sh |
Por fim, compile a aplicação de demonstração:
$ cd $IMX6SOLOX/mqx/mcc/examples/pingpong/build/make/pingpong_example_imx6sx_sdb_m4 $ ./build_gcc_arm.sh |
A aplicação de demonstração é compilada no formato ELF. Converta-a para o formato binário:
$ arm-none-eabi-objcopy -O binary gcc_arm/extflash_release/pingpong_example_imx6sx_sdb_m4.elf m4_qspi.bin |
O boot do Cortex-M4 pode ser realizado pela memória flash NOR da placa. Para gravar o firmware, a Freescale implementou um comando no U-Boot capaz de ler a imagem do firmware do cartão SD e gravar na flash NOR.
Portanto, insira novamente o cartão SD na máquina de desenvolvimento e copie o binário para a primeira partição do cartão (não esqueça de montar a primeira partição do cartão SD e alterar o diretório do ponto de montagem no comando abaixo):
$ cp m4_qspi.bin /media/sprado/Boot\ imx6sx/ |
Acesse a console do Linux, reinicie a placa e pressione uma tecla para acessar o prompt de comandos do U-Boot. Execute o comando abaixo para gravar o firmware na flash NOR da placa:
> run update_m4_from_sd |
É também responsabilidade do U-Boot iniciar a execução do firmware no Cortex-M4 no boot. Para isso, configure os parâmetros de boot conforme abaixo:
> setenv fdt_file imx6sx-sdb-m4.dtb > setenv mmcargs "${mmcargs} uart_from_osc" > setenv bootcmd "run m4boot;${bootcmd}" > saveenv |
Agora abra um outro terminal para acessar a console do Cortex-M4 e reinicie a placa. Você deverá ver as mensagens abaixo:
***** MCC PINGPONG EXAMPLE ***** Please wait : 1) A9 peer is ready Then press "S" to start the demo ******************************** Press "S" to start the demo : |
Na console do Linux no target, faça o login e inicie a aplicação de teste da comunicação multicore:
# echo 1 > /sys/devices/soc0/soc.1/2200000.aips-bus/mcctest.17/pingpong_en & |
Na console do MQX no Cortex-M4, pressione “S” para iniciar a comunicação com o Linux.
A partir deste momento, o Linux e o MQX, rodando de forma independente em cada núcleo, começarão a trocar mensagens utilizando uma região de memória compartilhada através da biblioteca MCC da Freescale.
O QUE VEM POR AÍ?
Com este tipo de arquitetura assimétrica, podemos juntar o melhor dos dois mundos: aplicações de processamento geral e sistemas de tempo real. E a tendência é que mais fabricantes de hardware optem por este tipo de arquitetura.
Ainda falta um padrão de software para que possamos desenvolver aplicações portáveis, mas conforme a quantidade de SoCs com esta capacidade aumente, a comunidade do kernel Linux deverá trabalhar em um framework genérico para comunicação entre núcleos assimétricos. É esperar para ver!
Um abraço,
Sergio Prado