Índice:

Parte 1 Conjunto ARM TI RSLK Currículo de aprendizagem de robótica Laboratório 7 STM32 Nucleo: 16 etapas
Parte 1 Conjunto ARM TI RSLK Currículo de aprendizagem de robótica Laboratório 7 STM32 Nucleo: 16 etapas

Vídeo: Parte 1 Conjunto ARM TI RSLK Currículo de aprendizagem de robótica Laboratório 7 STM32 Nucleo: 16 etapas

Vídeo: Parte 1 Conjunto ARM TI RSLK Currículo de aprendizagem de robótica Laboratório 7 STM32 Nucleo: 16 etapas
Vídeo: Introduction to the TI Robotics System Lab Kit Curriculum 2024, Julho
Anonim
Image
Image

O foco deste Instructable é o microcontrolador STM32 Nucleo. A motivação para isso é poder criar um projeto de montagem a partir do esqueleto. Isso nos ajudará a aprofundar e entender o projeto MSP432 Launchpad (o TI-RSLK) que já foi o tópico de vários Instructables.

Não há muita ajuda online para criar um projeto apenas de montagem para o MSP432, usando o Code Composer Studio. Até agora, estivemos apenas copiando / colando de um projeto de montagem pré-existente. Essa abordagem nos serviu bem.

No entanto, agora, para o Laboratório 7, encontramos um pequeno problema. Ou pelo menos um soluço temporário. O Laboratório 7 apresenta máquinas de estados finitos e a primeira coisa que encontramos é a necessidade de criar e usar uma matriz de valores. Como o curso de TI usa principalmente programação C - isso não é um problema. Mas esses Instructables têm foco na montagem, não no C.

Além disso, como o array possui valores somente leitura, seria bom colocá-lo na memória flash, não na RAM.

Parece haver muito mais ajuda online para projetos de montagem usando o MCU STM32, portanto, começamos com este Instructable, com o objetivo de usar o que foi aprendido, para então aplicar ao MSP432 e ao Code Composer Studio.

No caminho para esse objetivo, também obteremos experiência com outro microcontrolador popular.

Etapa 1: teste inicial do dispositivo

Teste Inicial do Dispositivo
Teste Inicial do Dispositivo
Teste Inicial do Dispositivo
Teste Inicial do Dispositivo
Teste Inicial do Dispositivo
Teste Inicial do Dispositivo

Novamente, por que escolher o Núcleo STM32 em particular?

Honestamente? Porque eu estava procurando por bons artigos sobre projetos de montagem bare-metal para controladores ARM, e me deparei com esta série. E também porque o STM32 parece ser um MCU popular.

Eu fiz algumas pesquisas (existem várias versões para escolher - veja a imagem acima), mas no final se tornou o que eu realmente posso conseguir, já que eu iria usar a Amazon (nos EUA).

Ele vem em um pacote simples, mas profissional, com algumas instruções de inicialização. Foi um pouco engraçado ver que o demo gravado no controlador era quase exatamente o que fizemos no Instructables anterior - um LED pisca e muda a velocidade de acordo com o pressionamento de um botão.

Parece que esta placa de desenvolvimento é muito semelhante à MSP432, pois há 2 LEDs e um botão de pressão do usuário. O MSP432 possui 2 botões de usuário.

Como você pode ver nas fotos, fiquei um pouco surpreso ao ver que a placa tem um mini e não um micro USB. Tive que correr para comprar um cabo.

Outro bom teste é que quando você o conecta ao seu computador (estou usando uma máquina Linux), ele aparece no meu gerenciador de arquivos, como um sistema de arquivos, chamado "NODE_F303RE". A abertura que revela dois arquivos, um HTML e um texto.

É isso, mas pelo menos também diz que a conectividade parece bastante fácil.

Agora estamos prontos para começar.

Vou tentar não repetir nenhuma das boas informações da série de artigos da IVONOMICON Bare Metal, mas sim aumentá-la.

Etapa 2: o essencial

A primeira coisa que precisamos é de um compilador.

E então, precisamos de um depurador:

devchu @ chubox: ~ $ sudo apt-get install gdb-arm-none-eabi Lendo as listas de pacotes … Concluído Construindo árvore de dependências Lendo informações de estado … Concluído Os seguintes NOVOS pacotes serão instalados: gdb-arm-none-eabi 0 atualizado, 1 recentemente instalado, 0 para remover e 8 não atualizado. Precisa obter 2, 722 kB de arquivos. Após esta operação, 7,738 kB de espaço em disco adicional serão usados. Obter: 1 https://us.archive.ubuntu.com/ubuntu xenial / universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3 + 9 [2, 722 kB] Obtido 2, 722 kB em 1s (1, 988 kB / s) Seleção do pacote anteriormente não selecionado gdb-arm-none-eabi. (Lendo o banco de dados… 262428 arquivos e diretórios instalados atualmente.) Preparando para descompactar… / gdb-arm-none-eabi_7.10-1ubuntu3 + 9_amd64.deb… Descompactando gdb-arm-none-eabi (7.10-1ubuntu3 + 9)… Processando gatilhos para man-db (2.7.5-1)… Configurando gdb-arm-none-eabi (7.10-1ubuntu3 + 9)…

Etapa 3: O essencial - Windows

A etapa acima presume que estamos usando Linux. E se estivermos usando o Windows?

Você pode acessar o site do desenvolvedor arm, e há várias opções de download disponíveis. Estou usando uma máquina com Windows 8.

Durante a instalação, optei por instalá-lo na unidade raiz "C: \" em vez de Arquivos de programas apenas porque também estou usando o cygwin e foi mais fácil criar um link do meu compartimento local para uma pasta raiz C: do que todos os bagunça no caminho para Arquivos de Programas (com espaços, etc).

Assim, meu ambiente e caminho cygwin, etc, é assim:

C: / cygwin64 / home / bin / arm-none-eabi-gcc, onde arm-none-eabi-gcc é um link para C: / GNUToolsArmEmbedded / 7.2018.q2.update / bin / arm-none-eabi- gcc.

Em seguida, criei uma pasta "dev" em cygwin home, e é onde coloquei o arquivo core. S e executei o comando do compilador. (veja mais abaixo para o material do compilador).

Fiz exatamente a mesma coisa para gdb (arm-none-eabi-gdb).

Etapa 4: quais são os fundamentos

Então, o que é "gcc-arm-none-eabi"?

O compilador GNU (GCC) irá compilar linguagens de programação (como C) em código nativo para a máquina em que está sendo executado. Por exemplo, se você fosse compilar algum código C usando GCC em sua máquina Windows, ele seria construído para rodar na máquina Windows. O executável gerado não será (normalmente) executado no microcontrolador ARM.

Portanto, para construir programas a serem baixados e gravados no microcontrolador ARM (em nosso caso presente seria o STM32 Nucelo), precisamos dar ao GCC outra coisa: a capacidade de "compilação cruzada". Ou seja, a capacidade de gerar um executável, não para seu sistema nativo (e processador), mas para o sistema de destino (o microcontrolador ARM). É aí que "gcc-arm-none-eabi" entra em jogo.

Então, o que é "gdb-arm-none-eabi"?

Depois de fazer o download e gravar (flashear) o executável recém-gerado no microcontrolador, provavelmente vamos querer depurá-lo - passo a passo linha por linha do código. O GDB é o depurador gnu e também precisa de uma maneira de fazer seu trabalho, mas visando um sistema diferente.

Portanto, gdb-arm-none-eabi está para o GDB, o que gcc-arm-none-eabi está para o GCC.

Outra sugestão de instalação de pacote foi "libnewlib-arm-none-eabi". O que é isso?

Newlib é uma biblioteca C e uma biblioteca matemática destinada ao uso em sistemas embarcados. É um conglomerado de várias partes de biblioteca, todas sob licenças de software livre que as tornam facilmente utilizáveis em produtos embarcados.

E, finalmente, o pacote "libstdc ++ - arm-none-eabi". Esse é bastante óbvio; é a biblioteca C ++ para o compilador cruzado; para microcontroladores ARM incorporados.

Etapa 5: o arquivo de vinculação

O arquivo de vinculação
O arquivo de vinculação
O arquivo de vinculação
O arquivo de vinculação

Vamos criar um script de vinculador.

Uma parte ou bloco chave neste arquivo seria o comando MEMORY.

--- em sourceware.org:

A configuração padrão do vinculador permite a alocação de toda a memória disponível. Você pode substituir isso usando o comando MEMORY. O comando MEMORY descreve a localização e o tamanho dos blocos de memória no destino. Você pode usá-lo para descrever quais regiões de memória podem ser usadas pelo vinculador e quais regiões de memória ele deve evitar. Você pode então atribuir seções a regiões de memória específicas. O vinculador definirá endereços de seção com base nas regiões de memória e avisará sobre regiões que ficam muito cheias. O vinculador não embaralhará as seções para caber nas regiões disponíveis. Um script de vinculador pode conter muitos usos do comando MEMÓRIA, no entanto, todos os blocos de memória definidos são tratados como se tivessem sido especificados dentro de um único comando MEMÓRIA. A sintaxe para MEMÓRIA é:

MEMÓRIA

{nome [(atr)]: ORIGEM = origem, COMPRIMENTO = len…}

O exemplo do artigo:

/ * Defina o fim da RAM e o limite da memória da pilha * // * (SRAM de 4KB na linha STM32F031x6, 4096 = 0x1000) * / / * (a RAM começa no endereço 0x20000000) _estack = 0x20001000;

MEMÓRIA

{FLASH (rx): ORIGEM = 0x08000000, COMPRIMENTO = 32K RAM (rxw): ORIGEM = 0x20000000, COMPRIMENTO = 4K}

Portanto, precisamos descobrir quanto FLASH (para nosso programa e constantes, etc) e quanta RAM (para uso pelo programa; heap e pilha, etc) para nossa placa em particular. Isso fica um pouco interessante.

O simpático cartãozinho que vem com o Nucleo diz que tem memória flash de 512 Kbytes e SRAM de 80 Kbytes. No entanto, conectando-o ao USB, ele é montado como um sistema de arquivos com dois arquivos, e tanto o gerenciador de arquivos quanto o GParted indicam que ele tem mais de 540+ Kbytes de espaço. (RAM?).

MAS, tentando excluir os dois arquivos usando o gerenciador de arquivos, desconectando e reconectando o dispositivo, ainda mostra os dois arquivos. (e o gerenciador de arquivos reconheceu algo porque há um pequeno ícone de "cadeado" em cada arquivo.

Então, vamos com os números do cartão. Portanto, agora pegamos o exemplo acima e o convertemos em nosso painel específico.

Você pode querer usar algo como este conversor de memória online, para ir do KB geral para um número específico de bytes.

Então você pode querer usar um conversor decimal em hexadecimal online.

/ * Definir o fim da RAM e o limite da pilha de memória * /

/ * (SRAM de 4KB na linha STM32F031x6, 4096 = 0x1000) * // * o exemplo * /

/ * etapa 1: (80 KB SRAM no STM32F303RE, 81920 = 0x14000) * // * nossa placa * /

/ * etapa 2, adicione o tamanho hexadecimal ao endereço inicial hexadecimal (abaixo). * /

/ * (RAM começa no endereço 0x20000000) * /

_estack = 0x20001000; /* o exemplo */

_estack = 0x20014000; / * nossa placa * /

MEMÓRIA {

FLASH (rx): ORIGIN = 0x08000000, LENGTH = 512K

RAM (rxw): ORIGIN = 0x20000000, LENGTH = 80K

}

Vamos chamar o arquivo acima de "linker.script.ld".

Etapa 6: a tabela de vetores

A Tabela de Vetores
A Tabela de Vetores

Agora vamos criar um pequeno arquivo de montagem (com diretivas) para fazer um tratamento básico de interrupções. Seguiremos o exemplo do artigo e criaremos o arquivo denominado "core. S".

Novamente, aqui está o conteúdo do arquivo de exemplo, mas fiz uma alteração em nosso quadro específico:

// Estas instruções definem os atributos do nosso chip e

// a linguagem assembly que usaremos:.syntax unified / * Veja abaixo após esta área de código * / /*.cpu cortex-m0 * / / * comente esta linha do exemplo * /.cpu cortex-m4 / * em vez disso, adicione o córtex do nosso tabuleiro. veja a imagem acima neste passo * / /*.fpu softvfp * / / * comente esta linha do exemplo * /.fpu vfpv4 / * adicione ao invés do nosso tabuleiro; ele tem um FPU * /.thumb // Locais de memória global..global vtable.global reset_handler / * * A tabela de vetores real. * Apenas o tamanho da RAM e o manipulador de 'redefinição' * estão incluídos, para simplificar. * /.type vtable,% object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Hmm.. Sem diretiva '.align'

No entanto, isso não é crítico. Mais sobre isso (talvez) mais tarde.

.syntax unified

.syntax [unificado | dividido]

Esta diretiva define a sintaxe do conjunto de instruções conforme descrito na seção ARM-Instruction-Set

9.4.2.1 Sintaxe do conjunto de instruções Duas sintaxes ligeiramente diferentes são compatíveis com as instruções ARM e THUMB. O padrão, dividido, usa o estilo antigo em que as instruções ARM e THUMB tinham suas próprias sintaxes separadas. A nova sintaxe unificada, que pode ser selecionada por meio da diretiva.syntax.

.fpu vfpv4

O compilador GCC pode produzir binários com várias opções em relação ao ponto flutuante: soft - adequado para execução em CPU sem FPU - os cálculos são feitos no software por softfp gerado pelo compilador - adequado para execução em CPU com ou sem FPU - usará uma FPU se houver. Para nosso caso específico (você terá que fazer sua própria pesquisa), a FPU desta placa em particular está em conformidade com o vfpv4. Você pode ter que brincar com isso. Ou até mesmo deixe em softfp.

.thumb (vs.arm)

Na verdade, esses microcontroladores ARM possuem uma combinação de conjuntos de instruções. Um é ARM, outro é THUMB. Uma diferença são as instruções de 16 bits e as instruções de 32 bits. Portanto, essa diretiva diz ao compilador para tratar as instruções subsequentes como THUMB ou ARM.

Vamos apenas pegar o restante do arquivo como está, uma vez que esses Instructables ainda não se aprofundaram na programação de montagem orientada a interrupções.

Etapa 7: A versão de montagem de um programa 'Hello World'

O seguinte também pode ir para o arquivo "core. S" criado anteriormente. Isso, novamente, vem do exemplo do artigo.

/ * * O manipulador Reset. Chamado na redefinição. * /.type reset_handler,% function reset_handler: // Define o ponteiro da pilha para o final da pilha. // O valor '_estack' é definido em nosso script de vinculador. LDR r0, = _estack MOV sp, r0

// Defina alguns valores fictícios. Quando vemos esses valores

// em nosso depurador, saberemos que nosso programa // está carregado no chip e funcionando. LDR r7, = 0xDEADBEEF MOVS r0, # 0 main_loop: // Adicione 1 ao registro 'r0'. ADDS r0, r0, # 1 // Volta para trás. B main_loop.size reset_handler,.-Reset_handler

Assim, o impulso do programa acima é carregar um padrão reconhecível em um registro MCU principal (neste caso R7), e um valor incremental começando em zero em outro registro MCU principal (neste caso R0). Se percorrermos o código em execução, devemos ver o incremento de dados de R0.

Se você tem acompanhado os Instructables sobre o MSP432 e os cursos / laboratórios da TI-RSLK, então, praticamente todos os programas acima devem ser familiares para você.

A única coisa nova que posso ver é o uso de "=" ao carregar "DEADBEEF" no registro R7. Nós não tínhamos usado isso.

O arquivo "core. S" anexado aqui agora contém a fonte completa.

Etapa 8: Compilando o Código

É hora de fazer algumas coisas de linha de comando. Algo real, finalmente.

No entanto, ainda não chegamos lá. Novamente, temos que ajustar o comando dado no artigo e modificá-lo para nossa própria situação.

Aqui está o código de exemplo:

arm-none-eabi-gcc -x assembler-with-cpp -c -O0 -mcpu = cortex-m0 -mthumb -Wall core. S -o core.o

Se formos ao site gnu.org para GCC, (neste caso, versão 7.3),

x

O -x é para especificar o idioma. Caso contrário, se não houver -x, o compilador tentará adivinhar usando a extensão do arquivo. (no nosso caso, *. S).

O exemplo acima do artigo especifica assembler-with-cpp, mas poderíamos apenas fazer assembler.

c

O -c diz compilar, mas não vincular.

O0

O -O é para definir o nível de otimização. Usar -O0 (oh-zero) diz "reduza o tempo de compilação e faça com que a depuração produza os resultados esperados. Este é o padrão".

mcpu = cortex-m0

O -mcpu especifica o nome do processador de destino. Em nosso caso, seria cortex-m4.

mthumb

O -mthumb especifica a seleção entre a geração de código que executa os estados ARM e THUMB.

Muro

O -Wall é obviamente muito comum e conhecido. Ele ativa todos os sinalizadores de aviso.

Finalmente, ao final do comando temos o arquivo de entrada core. S e o arquivo de saída core.o.

Aqui está a nova linha de comando resultante para se adequar ao nosso caso específico.

arm-none-eabi-gcc -x assembler -c -O0 -mcpu = cortex-m4 -mthumb -Wall core. S -o core.o

E isso compilado.

Etapa 9: Vinculando o programa

Diretamente do exemplo do artigo, temos o seguinte:

arm-none-eabi-gcc core.o -mcpu = cortex-m0 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

A maioria dos itens acima você viu. Abaixo está o que há de novo.

specs = nosys.specs

Este é um pouco complicado de explicar.

Tem a ver com "semihosting" e "retargeting", e tem a ver com entrada / saída. Também tem a ver com chamadas de sistema e bibliotecas.

Normalmente, os sistemas incorporados não fornecem dispositivos de entrada / saída padrão. Isso afetaria as chamadas do sistema ou da biblioteca (exemplo: printf ()).

Semihosting significa que o depurador (veja a imagem da Etapa 11 com a parte do depurador circulada em vermelho) tem um canal especial e usa o protocolo de semihosting, e você pode ver a saída de printf () na máquina host (por meio do depurador).

Retargeting, por outro lado, significa que essas mesmas chamadas de sistema ou biblioteca significam outra coisa. Eles fazem outra coisa, que faz sentido para o sistema embarcado. Em certo sentido, digamos para printf (), há uma nova implementação, uma implementação redirecionada dessa função.

Tendo dito tudo isso, o --specs = nosys.specs significa que não iremos semi-hospedagem. Isso normalmente significaria que estamos redirecionando. Isso nos leva à próxima bandeira.

nostdlib

A opção do vinculador -nostdlib é usada para vincular um programa destinado a ser executado de forma autônoma. -nostdlib implica nas opções individuais -nodefaultlibs e -nostartfiles. Abaixo, discutimos as duas opções separadamente, mas o uso mais típico é apenas nostdlib para compras completas. Ao vincular um programa hospedado, as bibliotecas do sistema padrão, como libc, são vinculadas por padrão, dando ao programa acesso a todas as funções padrão (printf, strlen e amigos). A opção do vinculador -nodefaultlibs desativa a vinculação com essas bibliotecas padrão; as únicas bibliotecas vinculadas são exatamente aquelas que você nomeia explicitamente para o vinculador usando o sinalizador -l.

lgcc

libgcc.a é uma biblioteca padrão que fornece sub-rotinas internas para superar as deficiências de máquinas específicas. Por exemplo, o processador ARM não inclui uma instrução de divisão. A versão ARM de libgcc.a inclui uma função de divisão e o compilador emite chamadas para essa função quando necessário.

T

Essa é apenas uma maneira de dizer ao vinculador para usar esse arquivo como o script do vinculador. Em nosso caso, o nome do arquivo é linker.script.ld.

o main.elf

Por fim, informamos ao vinculador qual será o nome do arquivo de imagem de saída final que será gravado / flasheado em nosso dispositivo.

Aqui está nossa versão da linha de comando completa, modificada para nossa situação específica:

arm-none-eabi-gcc core.o -mcpu = cortex-m4 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Certificamo-nos de que o arquivo de script e o arquivo core.o estão no mesmo diretório, onde executaremos a linha de comando acima.

E se conecta sem problemas.

Um cheque

Em seguida, executamos:

arm-none-eabi-nm main.elf

e obtemos:

devchu @ chubox: ~ / Development / Atollic / TrueSTUDIO / STM32_workspace_9.1 $ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Parece bom. O comando arm-none-eabi-nm é uma maneira de listar símbolos dentro de arquivos de objeto.

Etapa 10: Testando a conexão ao STM32 Nucleo-64

Testando a conexão ao STM32 Nucleo-64
Testando a conexão ao STM32 Nucleo-64
Testando conexão com o STM32 Nucleo-64
Testando conexão com o STM32 Nucleo-64

Sua primeira missão, caso decida aceitá-la, é fazer com que seu sistema veja o quadro de desenvolvimento.

Usando Windows

Para Windows, decidi instalar o TrueSTUDIO do Atollic (versão gratuita). Foi uma instalação fácil e o driver foi instalado automaticamente para que eu pudesse usar o st-link para testar a conexão. Assim que instalei o TrueSTUDIO e o gerenciador de dispositivos viu o dispositivo, baixei as ferramentas texan / stlink sugeridas pelo artigo da Bare Metal que estamos acompanhando. Coloquei novamente a pasta diretamente em "C: \" e novamente criei alguns links do meu compartimento home cygwin local para os comandos.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~ / bin / st-info

Como um teste inicial para ver se realmente podemos nos comunicar com o dispositivo, executei:

st-info --probe

E voltou:

Encontrados 1 programadores stlink

Portanto, agora sabemos que podemos conversar / consultar nossa placa de desenvolvimento.

Usando Linux

Para Linux, você realmente não precisa de um driver. Mas para o Debian, você terá que construir as ferramentas st a partir do código-fonte.

git clone

Certifique-se de ter o libusb-1.0-0-dev instalado.

lista de apt | grep -E "* libusb. * dev *"

Você deveria ver:

libusb-1.0-0-dev / xenial, agora 2: 1.0.20-1 amd64 [instalado]

ou algo assim.

Para instalar:

sudo apt-get install libusb-1.0-0-dev

Observe que o acima não é o mesmo que:

sudo apt-get install libusb-dev

O dev libusb ausente correto pode causar problemas no cmake.

Erro CMake: As seguintes variáveis são usadas neste projeto, mas são definidas como NOTFOUND. Defina-as ou certifique-se de que estejam definidas e testadas corretamente nos arquivos CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Mude para o diretório raiz do projeto (… blah / blah / stlink). Faça um "make release".

Depois disso, as ferramentas devem estar em ".. / build / Release".

Você pode então executar "st-info --probe". Aqui está a saída com o Nucleo conectado, então não.

devchu @ chubox: ~ / Development / stlink $./build/Release/st-info --probeFound 1 stlink programmers serial: 303636414646353034393535363537 openocd: "\ x30 / x36 / x36 / x41 / x46 / x46 / x35 / x30 / x34 / x39 / x35 / x35 / x36 / x35 / x37 "flash: 524288 (tamanho da página: 2048) sram: 65536 chipid: 0x0446 descr: F303 dispositivo de alta densidade devchu @ chubox: ~ / Development / stlink $./build/Release/st- info --probe Encontrado 0 programadores stlink devchu @ chubox: ~ / Development / stlink $

Etapa 11: vamos usar GDB com Linux

Vamos usar GDB com Linux
Vamos usar GDB com Linux
Vamos usar GDB com Linux
Vamos usar GDB com Linux

Se você tem tentado tudo isso e chegou até aqui - ótimo! Excelente. Vamos nos divertir um pouco agora.

Quando você compra essas placas de desenvolvimento ARM, sejam elas a MSP432 Launchpad da Texas Instruments ou esta que estamos discutindo agora, a Nucleo-F303 (STM32 Nucleo-64), elas geralmente chegam já atualizadas com um programa em execução, normalmente algum programa intermitente que também inclui o pressionamento de um interruptor para alterar a taxa de flash dos LEDs.

Antes de nos apressarmos em sobrescrever isso, vamos ver o que há para ver e fazer.

Com o Linux, abra um terminal, altere o diretório do projeto stlink git que acabamos de criar e encontre a ferramenta st-util.

devchu @ chubox: ~ / Development / stlink $ find. -name st-util

./build/Release/src/gdbserver/st-util

Execute essa ferramenta. Como já testamos anteriormente nossa conexão com st-info --probe, devemos obter alguma saída como esta:

devchu @ chubox: ~ / Development / stlink $./build/Release/src/gdbserver/st-util

st-util 1.4.0-50-g7fafee2 2018-10-20T18: 33: 23 INFO common.c: Carregando parâmetros do dispositivo…. 2018-10-20T18: 33: 23 INFO common.c: O dispositivo conectado é: F303 dispositivo de alta densidade, id 0x10036446 2018-10-20T18: 33: 23 INFO common.c: Tamanho SRAM: 0x10000 bytes (64 KiB), Flash: 0x80000 bytes (512 KiB) em páginas de 2048 bytes 2018-10-20T18: 33: 23 INFO gdb-server.c: Chip ID é 00000446, Core ID é 2ba01477. 2018-10-20T18: 33: 23 INFO gdb-server.c: Ouvindo em *: 4242…

Esse é o servidor GDB em execução agora, e ele vê nossa placa de desenvolvimento e, mais importante, está escutando na porta 4242 (a porta padrão).

Agora estamos prontos para iniciar o cliente GDB.

No Linux, abra outro terminal, digite o seguinte:

arm-none-eabi-gdb -tui

Isso é exatamente o mesmo que executar gdb estritamente na linha de comando, no entanto, ele produz um terminal baseado em texto (meu palpite é que ele usa curses).

Temos o cliente GDB e o servidor GDB em execução. No entanto, o cliente não está conectado ao servidor. No momento, ele não sabe nada sobre nosso Núcleo (ou placa de sua escolha). Temos que contar. No terminal, seu prompt agora deve ser o "(gdb)". Digitar:

ajuda alvo

Isso lhe dará uma lista. Observe que o que queremos é remoto estendido de destino - Use um computador remoto por meio de uma linha serial.

Mas também temos que fornecer a localização. Portanto, no prompt (gdb), digite:

(gdb) localhost remoto estendido de destino: 4242

Você deve receber uma resposta mais ou menos assim:

(gdb) localhost remoto estendido de destino: 4242

Depuração remota usando localhost: 4242 0x080028e4 em ?? ()

Enquanto isso, no terminal que executa o gdbserver st-util, temos o seguinte:

2018-10-20 T18: 42: 30 INFO gdb-server.c: Registros de ponto de interrupção de 6 hw encontrados

2018-10-20T18: 42: 30 INFO gdb-server.c: GDB conectado.

Etapa 12: vamos repetir, com Windows e Flash nosso programa

Vamos repetir, com Windows e Flash nosso programa
Vamos repetir, com Windows e Flash nosso programa
Vamos repetir, com Windows e Flash nosso programa
Vamos repetir, com Windows e Flash nosso programa
Vamos repetir, com Windows e Flash nosso programa
Vamos repetir, com Windows e Flash nosso programa

As etapas para executar o gdbserver st-util e o cliente arm-none-eabi-gdb são essencialmente as mesmas que fizemos durante a Etapa anterior. Você abre dois terminais (cygwin, DOS cmd ou Windows Powershell), encontra a localização do st-util e executa-o. No outro terminal, execute o cliente arm-none-eabi-gdb. A única diferença é que o modo -tui (visualização de texto baseada em terminal) provavelmente não é suportado.

Se tudo isso funcionou no Windows, provavelmente você terá que parar (apenas o cliente). Neste ponto, de alguma forma, você precisará executar o cliente GDB onde está seu arquivo de construção ("core.out") ou adicionar o caminho inteiro a esse arquivo como um argumento para o cliente GDB.

Simplifiquei minha vida usando cygwin e criando links do meu diretório $ HOME // bin local para onde ambas as ferramentas residem.

Ok, compilamos e vinculamos como antes, e temos o arquivo main.elf pronto para ser atualizado.

Temos st-util rodando em uma janela. Reiniciamos o cliente GDB, desta vez fazemos:

arm-none-eabi-gdb main.elf

Deixamos iniciar, esperamos pelo prompt (gdb), fazemos nosso mesmo comando de conexão com o servidor GDB (st-util) e estamos prontos para fazer o flash do executável. É muito anti-climático:

(gdb) carregar

Executando com terminais cygwin, há um problema conhecido com a saída de comandos do console às vezes. Portanto, em nosso caso, a janela de execução do servidor ficou completamente silenciosa. Aquele que está executando o cliente, em que executamos a carga, tem a seguinte saída:

Seção de carregamento.text, tamanho 0x1c lma 0x8000000Endereço inicial 0x8000000, tamanho de carga 28 Taxa de transferência: 1 KB / s, 28 bytes / gravação.

Etapa 13: Flashing com Linux - Mais recompensador: D

Flashing with Linux - Mais recompensador: D
Flashing with Linux - Mais recompensador: D

Etapa 14: vamos mergulhar um pouco mais fundo

Se você chegou aqui, excelente. Vamos continuar.

Por que não olhar dentro do arquivo main.elf, o executável? Execute o seguinte:

arm-none-eabi-objdump -d main.elf

Você deve ver uma saída parecida com esta:

main.elf: formato de arquivo elf32-littlearm

Desmontagem da seção.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [pc, # 8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, # 8]; (8000018) 800000e: 2000 movs r0, # 0

08000010:

8000010: 3001 adiciona r0, # 1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

Que pequenas pepitas podemos obter da saída acima?

Se você se lembra de quando discutimos e criamos o arquivo linker.script.ld, afirmamos que esses dispositivos ARM têm RAM começando em 0x20000000 e que a memória FLASH começa em 0x08000000.

Assim, podemos ver que de fato o programa é tal que tudo reside na memória FLASH.

Então, acima, mas em um passo posterior, quando estávamos discutindo a parte "Hello World", havia uma instrução onde carregamos um valor literal constante e imediato ("0xDEADBEEF") em um registrador central MCU ("R7").

A declaração foi:

LDR R7, = 0xDEADBEEF

Em nosso código, esse é o único lugar onde mencionamos DEADBEEF. Em nenhum outro lugar. E ainda, se você olhar para as instruções desmontadas / reconstruídas acima, etc, há mais coisas relacionadas ao DEADBEEF do que pensávamos.

Portanto, o compilador / vinculador de alguma forma decidiu atualizar permanentemente o valor de DEADBEEF em um endereço FLASH, na localização 0x8000018. E então, o compilador mudou nossa instrução LDR acima para ser:

LDR R7, [PC, # 8]

Até gerou um comentário para nós. Que legal. E nos diz para pegar o valor atual do contador do programa (o registro do PC), adicionar 0x8 a esse valor, e é aí que DEADBEEF foi queimado, pegar esse valor e colocá-lo em R7.

Isso também significa que o contador do programa (PC) estava apontando para o endereço 0x8000010, que é o início do main_loop, e que o valor DEADBEEF fica em dois endereços após o final do main_loop.

Etapa 15: finalmente, uma breve olhada no programa em execução

Mesmo se você sair do GDB, basta inserir o comando novamente. Você nem mesmo precisa fornecer nenhum arquivo; não estamos mais piscando, apenas rodando.

Depois de reconectar o cliente GDB ao servidor GDB, no prompt de comando (gdb):

(gdb) registros de informação

Você deve ver algo assim:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x20014000 lr 0xffffffff 4294967295 pc77 0x800000 0x800 0x800 1600000

Mas então, no prompt (gdb), digite:

(gdb) continue

E rapidamente pressione CTRL-C. Isso deve pausar o programa. Digite o comando "info registers" novamente.

Desta vez, parece diferente:

(gdb) registros de informação

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 spp. 16777216

O que aconteceu? Exatamente o que queríamos. DEADBEEF foi carregado em R7 e R0 foi incrementado (extremamente rápido). Se você repetir, verá R0 novamente com outro valor.

Etapa 16: Queríamos criar uma matriz somente leitura no Flash

Uma maneira de criar o equivalente a uma matriz usando assembly e diretivas é a seguinte:

.type myarray,% object // o nome ou rótulo 'myarray' é definido como um tipo de objeto.

myarray: // este é o início da declaração de 'myarray' // (em que consistirá)..word 0x11111111 // o primeiro membro ou valor contido em 'myarray'..word 0x22222222 // o segundo valor (endereços contíguos)..word 0x33333333 // e assim por diante..size myarray,.-myarray // o compilador / montador agora sabe onde termina ou // o limite de 'myarray'.

Agora que o configuramos na memória FLASH, podemos usá-lo no programa. Abaixo está uma parte:

LDR R1, myarray // carrega os dados contidos na 1ª localização de 'myarray'. ' // isso não é o que queremos.

LDR R1, = myarray // carrega o próprio valor de localização (o primeiro endereço), // não os dados.. // isso É o que queremos.

MOV R2, # 0 // R2 manterá uma contagem para garantir que não saiamos

// fim da matriz. LDR R3, = myarrsize // R3 será o equivalente a 'myarrsize'.

// R0 manterá nossos dados

main_loop:

LDR R0, [R1] // Carrega os dados apontados por R1 ('myarray') em R0. CMP R2, R3 // Estamos no limite do array? BEQ main_loop // Se estivermos, estamos prontos, então vamos apenas fazer um loop para sempre.

ADD R2, # 1 // Caso contrário, podemos continuar iterando através do array.

ADICIONE R1, # 4 // Adicione 4 ao registro R1, para que aponte corretamente para o próximo

// Morada..

B main_loop // Loop de volta.

O vídeo passa por tudo isso, e há um bug nele. É bom; mostra que é importante executar e depurar o código. Mostra um caso clássico de sair do final de um array.

Recomendado: