Leitura analógica do ADXL337 através do periférico ADC em FreeRTOS

20/07/2016 18:11

Introdução

 Grandezas como temperatura, pressão, nível, vazão entre outras são comumente encontradas no quotidiano do ser humano, sendo atualmente inviável manter o cenário industrial sem a perfeita aquisição de tais grandezas. Com isso, o presente trabalho visa estabelecer o monitoramento do sensor ADXL337 através da placa de desenvolvimento STM32 Primer1 com um Sistema Operativo em Tempo Real, freeRTOS, capaz de tanto realizar a converção analógico-digital por seu periférico ADC embebido, quanto gerênciar as tarefas necessárias para o seu correto funcionamento.

Sensor ADXL337

 O sensor ADXL337 fabricado pela SparkFun, trata-se de um sensor de aceleração, ou acelerômetro, sensível a variações mínimas de ± 3 g nos eixos x, y e z. Sua fonte de alimentação pode variar de 1.8 V a 3.6 V. Os dados de saída são no formato analógico. Ele pode medir a aceleração da gravidade estática em aplicações de detecção de inclinação , bem como aceleração dinâmica resultante do movimento , choque ou vibração [1].

Periférico ADC

 O STM32 Primer1, possui dois periféricos ADC embebidos, o ADC1 e ADC2, cada um com 16 canais de entrada, sendo estas multiplexadas por um seletor. A resolução de conversão é de 12 bits [2]. O procedimento primário para que o ADC possa funcionar é sua configuração. A estrutura do ADC do STM32 possui o seguinte formato:

typedef struct { 

    u32 ADC_Mode ; 

    FunctionalState ADC_ScanConvMode ;

    FunctionalState ADC_ContinuousConvMode ; 

    u32 ADC_ExternalTrigConv ; 

    u32 ADC_DataAlign ; 

    u8 ADC_NbrOfChannel ; 

} ADC_InitTypeDef

O ADC Mode é o modo em que o ADC irá trabalhar, visto que o microcontrolador possui mais de um ADC, o ADC ScanConvMode especifica se a conversão será realizada em multi-canais ou apensa um único canal, o ADC ContinuousConvMode especifica se a conversão será realizada de forma contínua ou de forma única, o ADC ExternalTrigConv determina se será utilizado um trigger externo para dar início ao processo de conversão AD, o ADC DataAlign determina se os dados serão alinhados para esquerda ou direita e o ADC N brOfChannel determina o número de canais que serão utilizados. Para realizar o processo de leitura dos dados do ADXL337, o periférico ADC1 foi configurado da seguinte forma:

RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA , ENABLE ) ; // Habilita o clock do GPIOA para os canais do ADC 

RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1 , ENABLE ) ; // Habilita o clock para o ADC1

ADC_InitTypeDef ADC_InitStructure ; 

ADC_InitStructure . ADC_Mode = ADC_Mode_Independent ; 

ADC_InitStructure . ADC_ScanConvMode = DISABLE ; 

ADC_InitStructure . ADC_ContinuousConvMode = DISABLE ;

 ADC_InitStructure . ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; 

ADC_InitStructure . ADC_DataAlign = ADC_DataAlign_Right ;

 ADC_InitStructure . ADC_NbrOfChannel = 3; 

ADC_Init ( ADC1 , & ADC_InitStructure ) ;

ADC_Cmd ( ADC1 , ENABLE ) ; // Habilita o ADC1 

ADC_ResetCalibration ( ADC1 ) ; // Habilita o RESET do registo de calibracao 

while ( ADC_GetResetCalibrationStatus ( ADC1 ) ) ; // Verificar o fim do RESET da calibracao

ADC_StartCalibration ( ADC1 ) ; // Inicia a calibracao 

while ( ADC_GetCalibrationStatus ( ADC1 ) ) ; // Verificar o fim da calibracao

Posteriormente é realizado um processo de calibração do ADC1. Já o processo de amostragem dos sinais para a conversão digital é controlado por vários comandos realizados por software, de acordo com o seu respetivo datasheet. Sendo assim, segue-se abaixo a sequência correta de execução do código:

ADC_RegularChannelConfig ( ADC1 , ADC_Channel_4 , 1 , ADC_SampleTime_41Cycles5 ) ; // Seleciona o canal a ser lido 

ADC_SoftwareStartConvCmd ( ADC1 , ENABLE ) ; // Inicia a conversao AD do periferico ADCx 

while (! ADC_GetFlagStatus ( ADC1 , ADC_FLAG_EOC ) ) ; // Aguarda a conversao finalizar 

ADCx_value = ADC_GetConversionValue ( ADC1 ) ; // Recolhe e armazena os dados em uma determinada variavel

FreeRTOS

O FreeRTOS é um sistema operativo em tempo real livre e apoiado, mesmo quando utilizado em aplicações comerciais [3]. Os RTOS permitem o desenvolvimento de aplicações através de tarefas independentes (thread e recursos), baseados num algoritmo de sequenciamento que vai executando alternadamente os “threads” concorrentes, onde cada tarefa tem seu contexto. Assim é possível separar todo o código em diferentes tarefas, cada uma dedicada a apenas um determinado processo. O código completo será formado pelas seguintes tarefas:

  • static void prvreadADC( void *pvParameters );
  • static void prvLcdTask( void *pvParameters );

A tarefa prvreadADC() será responsável por selecionar o canal do ADC, inicializar a conversão e armazenar o valor lido em uma variável. Já a tarefa prvLCD() será responsável por exibir os dados convertidos do ADC no display LCD do STM32 Primer1. O código também irá utilizar funções comuns com o intuito de auxiliar no processo de configuração do Clock, GPIO, ADC e USART e conversão dos valores obtidos do ADC para valores de aceleração. Como forma de aproveitar, ou libertar, o processamento do microcontrolador, será utilizado o conceito de filas de mensagens. Assim em vez do código ficar executando polling de uma flag, como é o caso da linha do código acima, em que o microcontrolador permanece a espera da flag de fim de conversão (EOC) ir a ”1”. Portanto com o uso de filas de mensagens, basta configurar o ADC como interrupção, através do NVIC, e assim que houver uma interrupção, fim da conversão, na rotina de interrupção é inserido o valor lido pelo ADC na fila, e na tarefa prvreadADC() ter uma fila no modo bloqueante a espera dos dados. Como o código também enviará os dados pela USART, o mesmo procedimento das filas foi implementado. De forma a associar cada leitura do sensor com seu respetivo instante de leitura, foi criada uma estrutura de dados ”Accelerometer”ao qual possui dois campos de dados, o acel e o tick, onde o acel recebe o valor do ADC e o tick recebe o valor do tickcount atual, como é mostrado no código abaixo:

struct Accelerometer {

    uint16_t acel ; // recebe o valor do ADC 

    TickType_t tick ; // recebe o valor do tickcount 

} recebe ;

Quanto à ordem de prioridades das tarefas, foi definido que a tarefa responsável por fazer a leitura dos dados do ADC possui maior prioridade, já a tarefa responsável por exibir os dados no display LCD ficou com prioridade inferior a do ADC. Em relação à ordem de prioridade das interrupções presentes, ADC e USART2, foi defindo novamente a maior prioridade a ISR do ADC e posteriormente a da USART2. Por fim, de forma a otimizar o aproveitamento da memória RAM do microcontrolador, foi desenvolvido durante a etapa de depurção uma função que determina o tamanho que determinada tarefa possui na Stack. De posse dos resultados, foi realizado um ajuste do tamanho da Stack da tarefa no momento de sua criação, como é mostrado abaixo:

xTaskCreate ( prvreadADC , " ADC", configMINIMAL_STACK_SIZE -30 , NULL , mainADC_TASK_PRIORITY , & HandleTask1 ) ; 

xTaskCreate ( prvLcdTask , " LCD", configMINIMAL_STACK_SIZE -30 , NULL , mainLCD_TASK_PRIORITY , & HandleTask2 ) ;

Conclusão

Portanto com a utilização de um sistema operativo em tempo real para gerenciar diversas tarefas concorrentes de um microcontrolador, há uma ampliação significativa dos recursos e horizontes de aplicações destes no cenário tecnológico atual.

Referências

[1] SparkFun. ADXL337, 2016. 

[2] STMicroelectronics. ARM-based 32-bit MCU STM32F101xx and STM32F103xx firmware library, 2015.

[3] FreeRTOS. FreeRTOS, 2016.