ÍNDICE DE CONTEÚDO
Olá meu caro leitor, como vai? Nesse artigo trago mais uma novidade pra você que está procurando uma plataforma de desenvolvimento para aplicações embarcadas voltadas (mas não limitado apenas) para IoT, ou internet das coisas, o MBED OS. Já falei por aqui em posts anteriores sobre outros frameworks como o Zephyr (que inclusive estou devendo pra vocês o passo-a-passo de construir um driver personalizado, logo voltaremos lá), existem soluções estáveis como o Contiki OS e RIOT. E o que a ARM fez? Resolveu pegar o seu conhecido framework de desenvolvimento online, juntou um kernel de tempo real, pilhas de comunicação e segurança e empacotou no que chamamos de MBED OS que em tradução livre se lê como algo parecido como: Sistema operacional MBED.
Mas o MBED OS, é um RTOS com drivers?
Basicamente, mas a ARM foi mais além. O primeiro passo foi adicionar o suporte a operação multi-tarefa e para isso a fabricante recorreu a um velho conhecido, o kernel de tempo real da Keil, o RTX. Para quem não sabe, este é um sistema operacional de tempo real (relembrando, tempo real pois todas as suas seções executam código em tempo constante) que vem junto do Keil uVision. Por já ser um projeto estável e bem testado, a equipe MBED adicionou o porting para o RTX e estendeu suas chamadas em formas de classes, permitindo seu uso como objetos em C++.
Mas tem mais, a equipe Mbed resolveu trazer também toda a solução para comunicação de dispositivos, e trouxe toda sua pilha de networking, incluindo device drivers para rádios dos mais diversos fabricantes, tornando o pacote bem atrativo para o uso de aplicações para internet das coisas.
E não para por ai, o Mbed nasceu com o ideal de ser flexível, permitindo que o usuário utilize o compilador online mbed, mas que possa também debugar seu projeto com a sua toolchain favorita. Para isso ela fornece a versão offline do Mbed OS, o utilitário CLI, que como o nome sugere, é uma ferramenta de linha de comando, que permite que você crie, compile e exporte seu projeto usando o framework Mbed para as mais diversas IDE para processadores ARM do mercado, variando do padrão KEIL até alternativas grátis como GNU-ARM, tudo isso suportando Windows, Linux e MAC. Nesse artigo vamos demonstrar a a capacidade do Mbed OS em seu modo online, para facilitar a vida de todos os leitores e deixar o projeto independente de configuração do seu computador.
Quero usar o MBED OS! É fácil assim mesmo?
É muito simples utilizar o Mbed OS. A maneira mais fácil de começar a desenvolver suas aplicações é acessando o ambiente de desenvolvimento online clicando aqui. Configure um projeto com o template do Mbed OS, e você já pode utilizar todos os recursos fornecidos inclusive para as ferramentas de suporte mais populares. Atenção especial para o suporte a LPC4337 e a placa de expansão OM13070, a mesma placa fornecida para uso no Embarcados Contest, Conectando a Internet das Coisas com a NXP. Para mostrar a simplicidade de como se fazer algo, criei um pequeno código de demonstração, utilizando a placa do Contest e o acelerômetro que vem no shield OM13080, também fornecida para uso no concurso.
Para testar o exemplo, vamos ate o ambiente de desenvolvimento online, clique em import, e na caixa de texto para buscar, digite meu nome (Felipe Neves) pra facilitar a busca, você deve ver o seguinte:
De um duplo clique, e o projeto ira aparecer na sua workspace dessa forma:
O código já contem todas as dependências envolvidas devidamente configuradas e pronto para compilação, mas antes vamos dar uma olhada no código principal, para isso, de um duplo clique em main.cpp, vamos nos deparar com o seguinte código:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
/ * @brief simple accelerometer reading demo */ #include "mbed.h" #include "rtos.h" #include "ST7567.h" /* defines the axis for acc */ #define ACC_NOOF_AXIS 3 /* defines the time of acquisition in ms */ #define ACC_SAMPLE_RATE 200 /* acc event flags */ #define ACC_EVENT 0x00000001 /* bmi160 slave address */ #define BMI160_ADDR ((0x68)<<1) /* LCD parameters */ #define LCD_HEIGHT 64 #define LCD_WIDTH 128 #define FONT_HEIGHT 10 #define FONT_WIDTH 5 /* Debug LED */ DigitalOut debug_led(LED1); /* thread for accelerometer and LCD */ unsigned char acc_stack[1024]; unsigned char lcd_stack[1024]; Thread acc_thread(osPriorityRealtime, 1024 ,&acc_stack[0]); Thread lcd_thread(osPriorityNormal, 1024, &lcd_stack[0]); /* semaphore to sync acc reading to lcd printing */ Semaphore acc_sema; /* buffer to store acc samples */ int16_t acc_sample_buffer[ACC_NOOF_AXIS] = {0x5555, 0x5555, 0x5555}; uint8_t acc_status = 0; /** * @brief i2c event callback */ /** * @brief accelerometer processing task */ static void acc_task(void) { I2C *imu_comm = new I2C(P2_3, P2_4); char i2c_reg_buffer[2] = {0}; /* setup the frequency */ imu_comm->frequency(20000); /* issue a sw reset */ i2c_reg_buffer[0] = 0x7E; i2c_reg_buffer[1] = 0xB6; imu_comm->write(BMI160_ADDR, i2c_reg_buffer, sizeof(i2c_reg_buffer), false); /* wait property time for device reset */ Thread::wait(200); /* enable the accelerometer */ i2c_reg_buffer[0] = 0x7E; i2c_reg_buffer[1] = 0x11; imu_comm->write(BMI160_ADDR, i2c_reg_buffer, sizeof(i2c_reg_buffer), false); /* sets the output data rate to 100 Hz */ i2c_reg_buffer[0] = 0x40; i2c_reg_buffer[1] = 0x28; imu_comm->write(BMI160_ADDR, i2c_reg_buffer, sizeof(i2c_reg_buffer), false); for(;;) { int err = 0; /* reads status register */ i2c_reg_buffer[0] = 0x1B; err = imu_comm->write(BMI160_ADDR, i2c_reg_buffer, 1, true); err = imu_comm->read(BMI160_ADDR, (char *)&acc_status, sizeof(acc_status), false); /* reads the acc register */ i2c_reg_buffer[0] = 0x12; err = imu_comm->write(BMI160_ADDR, i2c_reg_buffer, 1, true); err = imu_comm->read(BMI160_ADDR, (char *)&acc_sample_buffer, sizeof(acc_sample_buffer), false); acc_sema.release(); Thread::wait(ACC_SAMPLE_RATE); } } /** * @brief lcd update task */ static void lcd_task(void) { const char banner[] = {"Embarcados IMU demo\0"}; const char x_axis_text[] = {"x raw axis:\0"}; const char y_axis_text[] = {"y raw axis:\0"}; const char z_axis_text[] = {"z raw axis:\0"}; const char status_text[] = {"acc status:\0"}; DigitalOut *lcd_led = new DigitalOut(LED3); char acc_buffer[8] = {0}; *lcd_led = 1; /* creates an spi lcd object */ ST7567 *lcd = new ST7567(D11, D13, D12, D9, D10); lcd->set_contrast(0x35); lcd->cls(); /* center the text banner */ lcd->locate((LCD_WIDTH - (sizeof(banner) * FONT_WIDTH))/2,1); lcd->printf(banner); lcd->locate(0, FONT_HEIGHT * 2); lcd->printf(x_axis_text); lcd->locate(0, FONT_HEIGHT * 3); lcd->printf(y_axis_text); lcd->locate(0, FONT_HEIGHT * 4); lcd->printf(z_axis_text); lcd->locate(0, FONT_HEIGHT * 5); lcd->printf(status_text); for(;;) { /* wait for accelerometer event */ acc_sema.wait(); *lcd_led = 0; /* new samples arrived, format and prints on lcd */ sprintf(&acc_buffer[0],"%d", acc_sample_buffer[0]); lcd->locate(sizeof(x_axis_text)*FONT_WIDTH, FONT_HEIGHT * 2); lcd->printf(acc_buffer); sprintf(&acc_buffer[0],"%d", acc_sample_buffer[1]); lcd->locate(sizeof(y_axis_text)*FONT_WIDTH, FONT_HEIGHT * 3); lcd->printf(acc_buffer); sprintf(&acc_buffer[0],"%d", acc_sample_buffer[2]); lcd->locate(sizeof(z_axis_text)*FONT_WIDTH, FONT_HEIGHT * 4); lcd->printf(acc_buffer); sprintf(&acc_buffer[0],"%x", acc_status); lcd->locate(sizeof(status_text)*FONT_WIDTH, FONT_HEIGHT * 5); lcd->printf(acc_buffer); *lcd_led = 1; /* block this task until the next semaphore trigger */ } } /** * @brief main application entry point */ int main(void) { debug_led = 1; /* starts the two threads of this app */ acc_thread.start(acc_task); lcd_thread.start(lcd_task); debug_led = 0; } |
Na sua workspace, clique em Compile ou utilize o atalho CTRL + D, isso irá compilar o programa e gerar um arquivo .bin, pronto para ser gravado na placa. Assim sendo, conecte a placa na porta USB do seu computador, procure o arquivo .bin copie, procure por uma unidade de disco com o nome de DAPLINK ou MBED ou CMSIS_xxx e cole o arquivo .bin. Aguarde o final do processo até que a placa desconecte e se reconecte automaticamente. Quando a unidade de disco reaparecer pressione o reset da placa no canto superior esquerdo, você devera ver o seguinte resultado:
Explicando rapidamente o código
O código desenvolvido é extremamente simples, mas demonstra um pouco do poder e da rapidez de desenvolvimento oferecido pelo Mbed OS. São instanciados dois objetos do tipo Thread, sendo uma para o acelerômetro e outra para o LCD da placa, um terceiro objeto do tipo Semaphore também é declarado pois sera útil para sincronizar as duas tasks. Na função main, pouco trabalho e realizado, no contexto de execução do Mbed OS a função main também e uma Thread com prioridade padrão do sistema (conhecida por osPriorityNormal). Assim as Threads criadas são executada. Reparem na simplicidade, uma única linha cria a Thread e dispara sua execução. Nesse momento main é suspensa e apenas as duas Threads ficam ativas, a Thread do lcd, configura o display da placa, renderiza algum texto, e pega um semáforo para aguardar uma ordem de execução.
A tarefa do acelerômetro configura a I2C. Um pouco de trabalho a mais foi exigido pois até o presente momento não existe um driver oficial para o bosch BMI160 que é o acelerômetro presente no shield, então para facilitar configurei o chip com funcionalidade minima. Assim, a cada 200ms, a tarefa do acelerômetro (que possui a prioridade mais alta do sistema) efetua a leitura dos eixos x, y,z, e guarda em um buffer, em seguida o semáforo criado e sinalizado, e a tarefa do acelerômetro suspende novamente por 200ms. Nesse momento a tarefa do lcd fica livre para rodar, e então ela pega dos dados do buffer do acelerômetro, formata e imprime no lcd, para que ela não fique tomando processamento toda hora. Uma vez que ela atualiza o display, novamente pega o semáforo do acelerômetro, até que este rode novamente e sinalize-o, repetindo o ciclo ate que o sistema seja desligado.
Conclusão
O Mbed OS veio para competir com grandes frameworks voltados para internet das coisas que já possuem muita estrada como Contiki e RIOT, e também tem que enfrentar outros sistemas jovens que prometem ser um padrão da industria como o Zephyr. Nesse artigo falamos um pouco da composição do Mbed OS e demos alguns passos para que o leitor possa provar um pouco dessa ferramenta legal fornecida aos usuários de processadores ARM. Espero que o leitor tenha gostado e que mais esse recurso seja em breve aproveitado. Bons projetos!
Referências
Mbed OS: https://docs.mbed.com/
Mbed OS Handbook: https://docs.mbed.com/docs/mbed-os-handbook/en/5.1/
Será que posso criar meu próprio Hardware com MBed? Ou só dá pra usar nessas placas de desenvolvimento?