- Introdução ao microcontrolador ARM Cortex M3
- O design do Processador Cortex-M3 e seus periféricos
- Usando o STM32CubeIDE criaremos nosso projeto Hello World
- Usando o STM32CubeIDE como imprimiremos “Hello World” no Target?
- Modos Operacionais do Processador ARM Cortex-M3
- Níveis de Acesso ao Processador ARM Cortex-M3
- Os Registradores do Núcleo (Core) do Processador ARM Cortex-M3
- Alguns Registradores do Núcleo (Core) do Processador ARM Cortex-M3 na Pratica
- Usando a GNU Compiler Collection (GCC) para ARM Cortex-M3
- Memória do Microcontrolador STM32F103C8T6
- Usando uma calculadora para operações Bit a Bit (Bitwise)
- Programação Bare Metal do STM32F103C8T6 – LED Blink
Vamos construir um aplicativo do zero (from scratch), que fará piscar o LED interno da Blue Pill (PC13), usando apenas o STM32CubeIDE, os documentos de referência do MCU STM32F103C8T6, e alguns conceitos que já vimos nos artigos anteriores.
Os documentos que vamos usar são:
- ST – STM32F103xx Manual de Referência (RM0008 – DocID13902 Rev 16)
- Blue Pill (original schematic STM32F103C8T6)
O LED interno da Blue Pill está conectado no pino 13 da porta C do MCU, conforme ilustrado na figura 1. Como estamos partindo do zero, precisamos saber o que vem como padrão? Quais os status dos Registradores quando o MCU é resetado? E o que temos que configurar?
Como padrão, para economia de energia, a maioria dos periféricos vem desabilitados, incluindo todas as portas do STM32F103C8T6. Como vamos utilizar a porta C, será necessário habilitar o clock para a porta C, mas, antes vamos analisar a arquitetura macro do MCU, ilustrada na figura 2, para termos uma boa noção do que temos que fazer.
A Porta C é acessada pelo Bus APB2, ver figura 2. Conforme o manual de referência, temos que configurar o Registrador RCC_APB2ENR, que habilita o clock dos periféricos do Bus APB2, ilustrado na figura 3. Se setarmos o bit 4 o clock para a Porta C será habilitado.
Observe na figura 3, que o Registrador RCC_APB2ENR tem seu endereço com deslocamento 0x18. Isso significa que teremos que encontrar o endereço base do Registrador RCC – Reset and Clock Control. No manual de referência, em mapa de memória, podemos obter o endereço de base, que é 0x4002.1000, portanto, o endereço do Registrador RCC_APB2ENR = 0x4002.1000 + 0x18. Usando a calculadora do Programador, artigo especial dessa série, podemos efetuar essa soma na base hexadecimal. O resultado é 0x4002.1018, conforme ilustrado na figura 4.
Também o clock do MCU deveria ser habilitado, mas, a condição inicial, isto é, o estado dos bits do Registrador RCC_CR depois do reset, como padrão, deixa configurado o clock interno de 8 MHz, então, vamos conferir. Na figura 5 temos o primeiro Registrador que Controla o Clock do MCU. Observe o valor depois do reset = 0x0000.XX83. Vamos verificar os bits afetados.
Usando a calculadora do Programador o valor x83 = b1000.0011. Confira na figura 5 que os bits 0 e 1, indicam que o clock HSI foi setado e está pronto. O bit 7 significa que o clock HSI vem calibrado de fábrica com o valor 16 (padrão), para o HSITRIM[4:0], Bits 7:3. Esses bits fornecem um valor de corte adicional programável pelo usuário que é adicionado ao HSICAL, bits [7: 0]. Ele pode ser programado para se ajustar às variações de tensão e temperatura que influenciam a frequência do RC interno do HSI . O valor padrão é 16, que, quando adicionado ao valor HSICAL, deve ajustar o HSI para 8 MHz ± 1%.
Depois que verificamos o clock do MCU e habilitamos o clock da Porta C, agora temos outras configurações a realizar na Porta C, que são:
- Configurar o pino 13 da Porta C como uma saída digital;
- E saber como escrever, zero e um, no pino 13 da Porta C.
Na figura 6 podemos ver o circuito básico de entrada e saída de um pino do MCU. Obviamente dependendo da configuração, um determinado pino de uma porta pode ser uma entrada (caminho amarelo) ou uma saída (caminho azul). Em nosso caso precisamos ligar e desligar um LED, então, devemos configurar como uma saída digital.
Primeiro encontraremos o endereço base do Registrador da Porta C. No manual de referência, em mapa de memória, podemos obter o endereço de base da Porta C, que é 0x4001.1000. Agora configuraremos o Registrador GPIOC_CRH – Port C Configuration Register High. Vamos tratar somente a parte HIGH porque o pino 13, está contido na parte HIGH (pinos 8 à 15). Se fossemos usar, por exemplo, o pino 3, então, o Registrador seria o GPIOC_CRL – Port C Configuration Register Low (pinos 0 à 7).
Na figura 7 podemos ver que para cada pino da Porta C, temos quatro bits de configuração, divididos em dois grupos de dois bits, que são: CNF e MODE. Também o deslocamento do endereço desse Registrador é 0x04, portanto, o endereço exato será 0x4001.1000 + 0x04 = 0x4001.1004.
Para configurar somente o pino 13 da Porta C, os bits envolvidos são CNF13[23:22] e MODE13[21:20], conforme pode ser confirmado na figura 7. Vamos fazer as seguintes configurações:
- MODE13[21:20] = 10 → Saída, com velocidade máxima de 2MHz;
- CNF13[23:22] = 00 → Saída de propósito geral push-pull.
Foi configurado a menor velocidade máxima de saída, porque para piscar um LED, onde o olho humano perceba as transições, não requer uma frequência alta, e 2 MHz é suficiente. Também o tipo push-pull utilizaremos os MOSFET, que são os Drivers de saída, puxando para nível 1 ou empurrando para nível 0.
Para escrevermos no pino 13 da Porta C, temos que fazer isso através do Registrador GPIO_ODR, que escreve o dado na saída, como podemos vê-lo na figura 6, no circuito de saída. O endereço do Registrador GPIOC_ODR tem o deslocamento 0x0C, conforme ilustrado na figura 9. O endereço base da Porta C nós já havíamos obtido, que é 0x4001.1000, portanto, o endereço exato é 0x4001.100C.
Um resumo do que fizemos até aqui:
- O Clock HSI 8MHz já é configurado como padrão (estado de reset);
- Obtivemos o endereço do Registrador RCC_APB2ENR = 0x4002.1018;
- Temos que setar o bit 4 do RCC_APB2ENR;
- Obtivemos o endereço do Registrador GPIOC_CRH = 0x4001.1004;
- Temos que configurar MODE13[21:20] = 10 do GPIOC_CRH;
- Temos que configurar CNF13[23:22] = 00 do GPIOC_CRH;
- Obtivemos o endereço do Registrador GPIOC_ODR = 0x4001.100C;
- Temos que setar/resetar o bit 4 do RCC_APB2ENR para acender/apagar o LED 13.
Agora é escrever nossa aplicação no STM32CubeIDE, partindo do zero, conforme a proposta inicial desse artigo. Não vou detalhar os passos para criar um projeto, porque isso já foi visto várias vezes nos artigos dessa série. No STM32CubeIDE criei um projeto “06LEDBLINK” com o seguinte arquivo main.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#if !defined(__SOFT_FP__) && defined(__ARM_FP) #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use." #endif #include<stdio.h> int main(void) { //Define os ponteiros para os Registradores RCC_APB2ENR, GPIOC_CRH e GPIOC_ODR uint32_t *pRCC_APB2ENR = (uint32_t)0x40021018; uint32_t *pGPIOC_CRH = (uint32_t)0x40011004; uint32_t *pGPIOC_ODR = (uint32_t)0x4001100C; //1. Habilita o clock da Porta C *pRCC_APB2ENR |= 0x10; //CNF13[23:22] = 00 e MODE13[21:20] = 10 //2a. Reseta os bits [23:20] *pGPIOC_CRH &= 0xFF0FFFFF; //2b. Seta o bit [21] *pGPIOC_CRH |= 0x00200000; //3. Seta o pino 13 da Porta C (apaga o LED) *pGPIOC_ODR |= 0x00002000; while(1) { //Delay para ver o LED piscar for (uint32_t i = 0; i < 500000; i++); //Reseta o pino 13 da Porta C (acende o LED) *pGPIOC_ODR &= 0xFFFFDFFF; //Delay para ver o LED piscar for (uint32_t i = 0; i < 500000; i++); //Seta o pino 13 da Porta C (apaga o LED) *pGPIOC_ODR |= 0x00002000; } } |
No STM32CubeIDE, na nova aplicação “06LEDBLINK”, dê um “Clean Project”, “Build Project” e “RUN as” → “STM32 Cortex-M C/C++ Application”, e o programa será escrito na Blue Pill e o LED BLINK. Também se quiser depurar o programa e ver passo a passo os Registradores sendo modificados, então, basta utilizar os recursos do STM32CubeIDE, conforme já mostrado nesta série.
Ismael parabens pelo post! Muito bacana sua iniciativa e a simplicidade com que aborda um tema que muitas vezes é bem complexo.
Pedro, agradeço por suas palavras. Um abraço.
Ótima serie, está me ajudando muitíssimo. Espero que faça mais series assim. Muito obrigado!
Cristiano, obrigado pela atenção e feedback. Bom saber que lhe ajuda. Tenho comentado que eu estudo e compartilho, porque sempre alguém pode se interessar. Quantas vezes eu pesquisei algo que queria, e quando achava é muito bom, então, essa é a intenção. Um abraço.