Mês: dezembro 2015

Orvibo Allone Versus Geeklink Thinker

Esqueça o Orvibo Allone. Comprei o aparelho para não somente usar nos aparelhos de casa como também para acender luzes e abrir portões. Não funciona. Ele não tem modo RF Learning Code.

Até que achei o maravilhoso: 

Universal GeekLink Thinker

Sim. Muito melhor. Ele realmente automatiza uma casa. Este aparelho tem um modo RF Learning que permite acender luzes e controlar portões que tenham a tecnologia Learning Code (código fixo).

E não é só isso ele embute muitas funções:

  • WiFi Router com Linux OpenWrt;
  • Conecta à internet com PPOE;
  • Tem dois Ethernet e um USB;
  • Modo de aprender códigos RF em 433Mhz/315Mhz 
  • Clonagem de controles remotos infravermelhos
  • IFTTT que significa IF This Then That (QBASIC!!?). O sistema de programação de regras
  • Monitoração remota pelo smartphone.
  • Ponte das cameras IP.

Achei um comprador no AliExpress com promoção que vem com o aparelho e uma camera IP por U$68,00. Bom preço.

Este aparelho nasceu do site de financiamento público Kickstarter e muitos outros estão nascendo por lá.

d298f63ee94925aa3f106c07b01e6660_original

E pensando bem eu tinha comprado o VoCore por lá (um micro linux com WiFi, USB e Ethernet e algumas GPIOS) e ele parado aqui pode fazer tudo isto que o GeekLink faz. Basta ligar os fios, conectores, e programá-lo … que trabalho!

STM32 no Linux

Programar Kits ou microcontroladores STM32 no Linux é perfeitamente possível graças ao GNU ARM Toolchain para tanto é necessário instalar este e outros pacotes primos como veremos neste post. Será mostrado aqui a instalação destes pacotes e um simples programa blink sem bibliotecas de suporte.

Há vários toolchains disponíveis para uC ARMs alguns que se utilizam das syscall de algum SO como o Linux e outros que não esperam nenhum Sistema Operacional por trás, programar assim é chamado comumente como ‘baremetal’.

Para debugar e gravar um STM32 será utilizado o ST-Util e o OpenOCD.

Instalando os pacotes

GCC + GDB + OpenOCD

Eu utilizo o ArchLinux mas não poderia discriminar o Ubuntu.
Para o Ubuntu:

sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded
sudo apt-get update
sudo apt-get install gcc-arm-none-eabi
sudo apt-get install gdb-arm-none-eabi
sudo apt-get install openocd

ArchLinux users:

sudo pacman -S arm-none-eabi-binutils arm-none-eabi-gcc arm-none-eabi-gdb arm-none-eabi-newlib openocd stlink

Se tudo ocorreu corretamente teste a instalação abrindo um shell e digitando arm-none <TAB> isso fará o bash autocompletar a sequência e mostrar os executáveis instalados como nesta saída tipica:

arm-none-eabi-addr2line arm-none-eabi-gcc-4.7.4 arm-none-eabi-ld.bfd
arm-none-eabi-ar arm-none-eabi-gcc-ar arm-none-eabi-nm
arm-none-eabi-as arm-none-eabi-gcc-nm arm-none-eabi-objcopy
arm-none-eabi-c++ arm-none-eabi-gcc-ranlib arm-none-eabi-objdump
arm-none-eabi-c++filt arm-none-eabi-gcov arm-none-eabi-ranlib
arm-none-eabi-cpp arm-none-eabi-gdb arm-none-eabi-readelf
arm-none-eabi-elfedit arm-none-eabi-gdbtui arm-none-eabi-size
arm-none-eabi-g++ arm-none-eabi-gprof arm-none-eabi-strings
arm-none-eabi-gcc arm-none-eabi-ld arm-none-eabi-strip

Primeiro Programa

Antes de tudo vamos iniciar a configuração do vetor de interrupções, a routina de reset e alguns Defines para alguns registradores que iremos usar. Este programa foi feito para o kit STM32 Discovery F0. Com poucas modificações e entendendo o processo a migração para outros (M3/M4) será fácil.

O primeiro arquivo boot.h contém alguns typedefs e Defines para registradores de clock e GPIOs, declaração de váriaveis externas do arquivo de link, prototypes de funções e o vetor de interrupções (que neste caso só cobrirá as interrupções ARM). Também o Reset e SystemInit bem como as funções de tratamento de interrupções serão declaradas.

boot.h

// boot.h
#define uint32_t unsigned int
#define IO_Uint32 volatile unsigned int
typedef struct
{
IO_Uint32 ACR;
IO_Uint32 KEYR;
IO_Uint32 OPTKEYR;
IO_Uint32 SR;
IO_Uint32 CR;
IO_Uint32 AR;
IO_Uint32 RESERVED;
IO_Uint32 OBR;
IO_Uint32 WRPR;
} _FLASH;

typedef struct
{
IO_Uint32 CR;
IO_Uint32 CFGR;
IO_Uint32 CIR;
IO_Uint32 APB2RSTR;
IO_Uint32 APB1RSTR;
IO_Uint32 AHBENR;
IO_Uint32 APB2ENR;
IO_Uint32 APB1ENR;
IO_Uint32 BDCR;
IO_Uint32 CSR;
IO_Uint32 AHBRSTR;
IO_Uint32 CFGR2;
IO_Uint32 CFGR3;
IO_Uint32 CR2;
} _RCC;

typedef struct {
IO_Uint32 MODER;
IO_Uint32 OTYPER;
IO_Uint32 OSPEEDR;
IO_Uint32 PUPDR;
IO_Uint32 IDR;
IO_Uint32 ODR;
IO_Uint32 BSRR;
IO_Uint32 LCKR;
IO_Uint32 AFRL[2];
IO_Uint32 BRR;
} _GPIO ;

#define GPIOC ((_GPIO *) 0x48000800)
#define RCC ((_RCC *) 0x40021000)
#define FLASH ((_FLASH *) 0x40022000)

// Globais do arquivo do linker
extern void *_estack;
extern unsigned char _sidata;
extern unsigned char _sdata;
extern unsigned char _edata;
extern unsigned char _sbss;
extern unsigned char _ebss;
extern void main (void);

// Entry Point
void Reset (void);
// Default Interrupt Handler
void Default_Handler(void) __attribute__( ( interrupt ) );
static void HardFault_Handler( void )/* __attribute__( ( naked ) )*/;

__attribute__ ((section(".isr_vector")))
void (* const Vectors[])(void) = {
(void(*)(void)) &amp;_estack,
Reset,
Default_Handler, //NMI_Handler,
HardFault_Handler, //FaultHandler,
0,
0,
0,
0,
0,
0,
0,
Default_Handler, //SVC_Handler,
0,
0,
Default_Handler, //PendSV_Handler,
Default_Handler, //SysTick_Handler,
};

static void HardFault_Handler( void ){
__asm__("BKPT");
while (1);
}

#pragma weak _exit = Default_Handler
void Default_Handler(void) {
__asm__("BKPT");
while (1);
}

void SystemInit(void)
{
/* Reseta o RCC clock para  o padrão ------------*/
/* Set HSION bit */
RCC-&gt;CR |= (uint32_t)0x00000001;

/* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */
RCC-&gt;CFGR &amp;= (uint32_t)0x08FFB80C;

/* Reset HSEON, CSSON and PLLON bits */
RCC-&gt;CR &amp;= (uint32_t)0xFEF6FFFF;

/* Reset HSEBYP bit */
RCC-&gt;CR &amp;= (uint32_t)0xFFFBFFFF;

/* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
RCC-&gt;CFGR &amp;= (uint32_t)0xFFC0FFFF;

/* Reset PREDIV[3:0] bits */
RCC-&gt;CFGR2 &amp;= (uint32_t)0xFFFFFFF0;

/* Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
RCC-&gt;CFGR3 &amp;= (uint32_t)0xFFFFFE2C;

/* Reset HSI14 bit */
RCC-&gt;CR2 &amp;= (uint32_t)0xFFFFFFFE;

/* Desabilita todas as interrupções*/
RCC-&gt;CIR = 0x00000000;

FLASH-&gt;ACR = 0x00000011;

}
// O começo de tudo antes de main
__attribute__( ( naked ) ) void Reset (void) {

register unsigned char *src, *dst;

// Copia os dados da flash para a ram (const, static initialized variables)
src = &amp;_sidata;
dst = &amp;_sdata;
while(dst &lt; &amp;_edata) *dst++ = *src++;

// Inicializa o bss (C static variables non initialized)
dst = &amp;_sbss;
while(dst &lt; &amp;_ebss) *dst++ = 0;

SystemInit();
//__libc_init_array();
// ... and finally call main saving sp
__asm__("b main");

}

A função Reset inicializa a variáveis estáticas com zero, chama SystemInit e finalmente chama a função Main com um brunch para economizar RAM na pilha.

main.h

O segundo arquivo é o fluxo principal do programa onde esta a função Main. Este programa irá piscar os LEDs do kit nas portas PC9 e PC8. O tipo GPIO foi declarado anteriormente em boot.h.

#include "boot.h"

__attribute__( ( naked ) ) void main (void){

RCC-&gt;AHBENR |= ((unsigned int) 0x00080000); // Enable GPIOC otherwise a hardfault
GPIOC-&gt;MODER = 0x55555555; // Output mode for all PORTC

volatile register int i;

while (1) {

GPIOC-&gt;BSRR = 0x0000ffff;
for (i = 0; i &lt; 50000; i++); GPIOC-&gt;BSRR = 0xffff0000;
for (i = 0; i &lt; 50000; i++);

};

__asm__("b .");
};

Makefile e Link Script

Acabou? Não  Ainda faltam dois arquivos o MakeFile e o Script do Linker.

Este MakeFile é completo o que compilará, mostrará o tamanho do código, converterá ELF para BIN, irá gerar uma listagem em assembly e finalmente grava na flash o programa. Simplesmente execute o make no terminal de onde estão estes arquivos.

all:
arm-none-eabi-gcc -mcpu=cortex-m0 -gdwarf-2 -mthumb -nostdlib -mlittle-endian -Tlink.ld main.c -o main
arm-none-eabi-size main
arm-none-eabi-nm -S main
arm-none-eabi-objdump -d -M intel -S main &gt; bin.asm
arm-none-eabi-objcopy -O binary main main.bin
st-flash erase
st-flash --reset write main.bin 0x08000000
debug:
arm-none-eabi-gdb main -tui --eval-command="target extended-remote :4242"

E por fim o link  script. Lugar onde as posições de memória são definidos, o Entry Point e algumas globais usadas pelo Reset para inicializar a variáveis estaticas e constantes.

/* Entry Point */
ENTRY(Reset)

/* Highest address of the user mode stack */
_estack = 0x20001FFF; /* end of RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* Only usefull if you use alloc, malloc */
_Min_Stack_Size = 0x800;

MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}

/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} &gt;FLASH

/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)

KEEP (*(.init))
KEEP (*(.fini))

. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} &gt;FLASH

/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} &gt;FLASH

.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } &gt;FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} &gt;FLASH

.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} &gt;FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} &gt;FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} &gt;FLASH

/* used by the startup to initialize data */
_sidata = LOADADDR(.data);

/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */

. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} &gt;RAM AT&gt; FLASH

/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)

. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} &gt;RAM

._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . ); /* Necessary for newlibc */
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} &gt;RAM

/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}

.ARM.attributes 0 : { *(.ARM.attributes) }
}

Foi apresentado aqui como programar microcontroladores STM32 no Linux utilizando as ferramentas gratuitas disponíveis. Não utilizei o conjunto de bibliotecas oficiais da ST chamado Cube para demonstrar também como é um programar um uC sem este suporte.

Como evolução o leitor irá integrar o Cube e utilizar o CubeMX para facilmente inicializar o uC e partir para a programação em si.

Eu programo microcontroladores STM32 no Linux profissionalmente com estas ferramentas e integro tudo no Code:Blocks que é uma ótima alternativa aos ambientes caros como IAR e Keil. Eu não me adaptei muito aos derivados gratuitos do Eclipse porque não gosto de programas que demoram para inicializar …

EDIT: O WordPress vive mudando meu código postado transformando caracteres especiais em formato HTML Entity e não sei como mudar isso. Se alguém ai souber me ajude por favor porque se você copiar e colar os códigos daqui será necessário corrigir muita pontuação.

Usando Ulimit para evitar que o computador trave (Opera)

O Scheduler sofre na minha mão em qualquer sistema operacional. Abro um monte de programas ao mesmo tempo e dentro deles muitos outros threads. As vezes uso o Firefox, Opera e Chromium de uma vez só com várias abas … isso quando não há o VirtuaBox rodando o WinXP com 1,5GB de memória reservada e ainda teimosamente estou rodando o ‘pacman -Syu’.

E roda bem! O problema são esses browsers  que as vezes descambam tudo e saem comendo memória como loucos. Cada um tem seu fraco, mas em geral o Flash complica tudo. Um java script muito pesado faz alguns browsers se perderem. Assistir a um video torna tudo mais lento por aqui.

Faz tempo que queria uma solução que mate ou limite os recursos desses browsers até que achei o óbvio: ulimit.

Ulimit

Facil de usar este comando embutido faz o que o nome sugere: Limitar os recursos para um terminal. E esses recursos podem ser memória, arquivos abertos, tamanho de arquivo, tempo de CPU e outros recursos.

Para ver seus limites atuais comande:

ulimit -a

E uma saída tipica como esta deverá ser mostrada:

core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 15217
max locked memory (kbytes, -l) 1024
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 15217
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Para alterar o limite da memória de um terminal user:

ulimit -v MEMORIA_EM_KILO

Para voltar ao normal:

ulimit -v unlimited

Tenha em mente que somente para o terminal que ele for chamado estes limites funcionarão. Muito útil.

Opera

O executável do Opera para nossa sorte é um script em /usr/bin/opera. O default deve ser este:

#!/bin/bash
# Allow users to override command-line options
# Based on Gentoo's chromium package (and by extension, Debian's)
if [[ -f /etc/opera/default ]]; then
. /etc/opera/default
fi
# Prefer user defined CHROMIUM_USER_FLAGS (from env) over system
# default CHROMIUM_FLAGS (from /etc/chromium/default)
OPERA_FLAGS=${OPERA_USER_FLAGS:-$OPERA_FLAGS}
exec /usr/lib/opera/opera $OPERA_FLAGS "$@"

Então adicionei ulimit acima de exec e testei com 1G. Com três páginas o Opera já reclamava de falta de memória. As vezes desligava e voltava sozinho, com todas as páginas anteriores reabrindo! Isso é bom. Sem travar nada!
Então aumentei para 2G e nunca mais ele matou meu computador.

Quer testar se seu browser sofre com sites pesados? Tente nestes sites de jogos online por exemplo: diverti.com.br, poki.com.br, y8, miniclips.

Segue alteração:

#!/bin/bash
# Allow users to override command-line options
# Based on Gentoo's chromium package (and by extension, Debian's)
if [[ -f /etc/opera/default ]]; then
. /etc/opera/default
fi
# Prefer user defined CHROMIUM_USER_FLAGS (from env) over system
# default CHROMIUM_FLAGS (from /etc/chromium/default)
OPERA_FLAGS=${OPERA_USER_FLAGS:-$OPERA_FLAGS}
ulimit -v 2048576;
exec /usr/lib/opera/opera $OPERA_FLAGS "$@"

Perigos

Não se deve matar um processo do nada. E  limitar sua memória pode trazer problemas já que a maioria dos programadores não tratam falta de memória. Felizmente o Opera se comporta bem. Fique alerta que talvez você perca algum serviço em andamento. Porém como eu uso os browsers em edições remotas e para usos não criticos se eles se desligam é muito melhor para mim que impedir de fato de usar os outros programas críticos.