Conforme já sabemos, a arquitetura de microcontroladores ARM Cortex de 32 bits é bem mais potente e também mais complexa em relação a microcontroladores comuns de 8 ou 16 bits como, por exemplo, um Microchip PIC. Exatamente por essa maior complexidade, o software para esses dispositivos é usualmente programado em linguagem C e, recentemente, houve um esforço de várias indústrias no desenvolvimento e adoção do padrão CMSIS (Cortex Microcontroller Software Standard) que consiste um framework para aplicações embarcadas que visa padronizar a API utilizada na programação desses microcontroladores, simplificando todos os passos no desenvolvimento e manutenção do código-fonte.
Para demonstrarmos o início da utilização do padrão CMSIS e programação dos microcontroladores Cortex-M para leigos, publicamos a seguir um exemplo de código-fonte escrito em C com o intuito de piscar um LED conectado no pino 6 da porta I/O de propósito geral C (GPIOC) para demonstrar o quanto o código fica mais inteligível em relação a uma programação menos profissional com referências diretas a constantes binárias ou hexadecimais. Para o software não ficar muito trivial, estabelecemos um sistema operacional de tempo real (RTOS), também padronizado pelo CMSIS, e configuramos uma thread (código de execução paralela) com prioridade normal para execução do código de acendimento e desligamento do LED com atraso de tempo.
O leitor pode estranhar a ausência de código para programação da inicialização do microcontrolador. Pois uma das finalidades do CMSIS é justamente padronizar e facilitar também o código-fonte de toda a inicialização do microcontrolador (e independente da fabricante, família e modelo da melhor maneira possível). Neste exemplo, bastamos selecionar as opções "ARM::CMSIS:CORE:", "ARM::CMSIS:RTOS:", "Keil::Startup", "Keil::GPIO", "Keil::Device:StdPeriph Drives:GPIO"e "Keil::Device:StdPeriph Drives:RCC" em "Manage Run-Time Environment" na IDE Keil uVision e criarmos um novo arquivo template main em C. Impossível ser mais simples e inteligível: procure um código-fonte similar sem a utilização do CMSIS e perceba a dificuldade em ler o código, compreender rapidamente seu propósito e ter que decorar inúmeras constantes e posicionamento de bits que foram substituídos por estruturas (struct) com descrições melhores em C no CMSIS:
/*----------------------------------------------------------------------------
* CMSIS-RTOS 'main' function template
*---------------------------------------------------------------------------*/
#define osObjectsPublic // define objects in main module
#include "osObjects.h" // RTOS object definitions
#include "stm32f10x.h" // Device header
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#define LEDG GPIO_Pin_6
#define LEDPORT GPIOC
#define LEDPORTCLK RCC_APB2Periph_GPIOC
// Função thread piscar led
void Piscar (void const *argumento){
while (1){
GPIO_SetBits(LEDPORT, LEDG);
osDelay(100);
GPIO_ResetBits(LEDPORT, LEDG);
osDelay(100);
}
}
// Definir prioridade e definir thread
osThreadDef(Piscar, osPriorityNormal, 1, 0);
/*
* main: initialize and start the system
*/
int main (void) {
GPIO_InitTypeDef GPIO_InitStructure;
//SystemCoreClockUpdate();
osKernelInitialize (); // initialize CMSIS-RTOS
//GPIO structure used to initialize port
RCC_APB2PeriphClockCmd(LEDPORTCLK, ENABLE);
//select pins to initialize LED
GPIO_InitStructure.GPIO_Pin = LEDG;
//select output push-pull mode
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//highest speed available
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(LEDPORT, &GPIO_InitStructure);
//using same structure we will initialize button pin
// create 'thread' functions that start executing,
// example: tid_name = osThreadCreate (osThread(name), NULL);
osThreadCreate (osThread(Piscar), NULL);
osKernelStart (); // start thread execution
}