collapse

* Links de Robótica

* Posts Recentes

URGENTE - display de 7 segmentos com backpack por helderjsd
[Hoje às 12:03]


Preços e fabricantes de pcb por Sérgio_Sena
[Ontem às 10:20]


Palavras Cruzadas por Njay
[Ontem às 02:24]


Isaac Asimov - I, Robot por senso
[18 de Setembro de 2017, 03:41]


Apresentação por TigPT
[17 de Setembro de 2017, 07:31]


ic SL440 da Plessey? por senso
[16 de Setembro de 2017, 13:11]


Compra Colectiva RS-Amidata por brunus
[15 de Setembro de 2017, 22:31]


Ideias para construir um quadrúpede simples por zordlyon
[15 de Setembro de 2017, 10:18]


Preparar bancada de testes por jm_araujo
[14 de Setembro de 2017, 10:24]


Mitos: mudança da ilumação tradicional p/ iluminação a LEDs? por LVirtual
[14 de Setembro de 2017, 07:46]

Autor Tópico: NoInterrupts(), interrupts(), cli() e sei()  (Lida 2429 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline MAntunes

  • Mini Robot
  • *
  • Mensagens: 56
NoInterrupts(), interrupts(), cli() e sei()
« em: 27 de Janeiro de 2015, 21:36 »
Boas pessoal, antes de mais nada não sei se este é o sitio mais correto para por esta duvida, mas cá vai :)
Estava aqui a portar uma biblioteca de Arduino para TivaWare e deparei-me com duas funções: noInterrupts() e interrupts(). Pelo que estive a ler são equivalentes às funções cli() e sei() dos AVR e desativam e activam os interrupts.
O unico interrupt que tenho activo penso ser o Systick (está a contar em microsegundos) e se o desativar fico sem acesso à função Wait, por isso não sei o que fazer..
Em anexo deixo o codigo da biblioteca e o meu codigo, caso alguém queira ver.
Cumprimentos!

Código: [Seleccione]
#define PART_TM4C123GH6PM
#define MAXTIMINGS 85

#include <stdint.h>
#include <stdbool.h>
#include "stdlib.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_uart.h"
#include "inc/hw_gpio.h"
#include "inc/hw_pwm.h"
#include "inc/hw_timer.h"
#include "inc/hw_types.h"
#include "driverlib/timer.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "driverlib/pwm.h"
#include "driverlib/ssi.h"
#include "driverlib/systick.h"
#include "utils/uartstdio.c"
#include <string.h>

volatile uint32_t millis=0;

struct DHT
{
uint8_t data[6];
uint32_t lastreadtime;
bool firstreading;
};

void SycTickInt(){
  millis++;
}

void SysTickbegin(){
  SysTickPeriodSet(80);
  SysTickIntRegister(SycTickInt);
  SysTickIntEnable();
  SysTickEnable();
}

void Wait(uint32_t time){
uint32_t temp = millis;
while( (millis-temp) < time){
}
}

void Init(struct DHT aux)
{
aux.firstreading = 1;
aux.lastreadtime = 0;
}

bool Read(struct DHT aux)
{
uint32_t laststate = 1;
uint32_t counter = 0;
uint32_t j = 0, i;
uint32_t currenttime = 0;

GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_7, GPIO_PIN_7);
Wait(250000); //delay 250*1000 microseconds

currenttime = millis;
if (currenttime < aux.lastreadtime)
{
aux.lastreadtime = 0;
}
if (!aux.firstreading & ((currenttime - aux.lastreadtime) < 2000000))
{
return true;
}
aux.firstreading = 0;
aux.lastreadtime = millis;

aux.data[0] = aux.data[1] = aux.data[2] = aux.data[3] = aux.data[4] = 0;

GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7);
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_7, 0);
Wait(20000); //delay 20*1000 microseconds
//noInterrupts();
GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_7, GPIO_PIN_7);
Wait(40);
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_7);
for (i = 0; i < MAXTIMINGS; i++)
{
counter = 0;
while (GPIOPinRead(GPIO_PORTA_BASE, GPIO_PIN_7) == laststate)
{
counter++;
Wait(1);
if (counter == 255)
break;
}
laststate = GPIOPinRead(GPIO_PORTA_BASE, GPIO_PIN_7);
if (counter == 255)
break;
if(i >= 4 && i%2 == 0)
{
aux.data[j/8] <<= 1;
if (counter > 6)
aux.data[j/8] |= 1;
j++;
}
}
//interrupts();
if((j >= 40) && (aux.data[4] == ((aux.data[0] + aux.data[1] + aux.data[2] + aux.data[3]) & 0xFF)))
return (true);
return (false);
}

float ReadTemperature(struct DHT aux)
{
float f;
if (Read(aux))
{
f = aux.data[2] & 0x7F;
f *= 256;
f += aux.data[3];
f /=10;
if (aux.data[2] & 0x80)
f *=-1;
return (f);
}
return(0);
}

float ReadHumidity(struct DHT aux)
{
float f;
if (Read(aux))
{
f = aux.data[0];
f *= 256;
f += aux.data[1];
f /= 10;
return (f);
}
return(0);
}

int main(void) {
SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
SysTickbegin();
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7);
//Init console

GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioConfig(0, 115200, 16000000);

struct DHT sensor;
float temperature = 0, humidity = 0;

Init(sensor);

while(1)
{
temperature = ReadTemperature(sensor);
humidity = ReadHumidity(sensor);
UARTprintf("Temperature: %2dºC \n", temperature);
UARTprintf("Humidity: %2d%% \n", humidity);
Wait(1000);
}
return 0;
}
A minha duvida está na função Read().
Código: [Seleccione]
/* DHT library

MIT license
written by Adafruit Industries
*/

#include "DHT.h"
#include <math.h>

#if defined(__MSP430G2452__) || defined(__MSP430G2553__) || defined(__MSP430G2231__) // LaunchPad specific
#define NAN 0xffff
#endif

DHT::DHT(uint8_t pin, uint8_t type) {
  _pin = pin;
  _type = type;
  firstreading = true;
}

void DHT::begin(void) {
  // set up the pins!
  pinMode(_pin, INPUT);
  digitalWrite(_pin, HIGH);
  _lastreadtime = 0;
}

//boolean S == Scale.  True == Farenheit; False == Celcius
float DHT::readTemperature(bool S) {
  float f;

  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[2];
      if(S)
      f = convertCtoF(f);
     
      return f;
    case DHT22:
    case DHT21:
      f = data[2] & 0x7F;
      f *= 256;
      f += data[3];
      f /= 10;
      if (data[2] & 0x80)
f *= -1;
      if(S)
f = convertCtoF(f);

      return f;
    }
  }
//  mySerial.print("Read fail");
  return 0;
}

float DHT::convertCtoF(float c) {
return c * 9 / 5 + 32;
}

float DHT::readHumidity(void) {
  float f;
  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[0];
      return f;
    case DHT22:
    case DHT21:
      f = data[0];
      f *= 256;
      f += data[1];
      f /= 10;
      return f;
    }
  }
//  mySerial.print("Read fail");
  return NAN;
}


boolean DHT::read(void) {
  uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0, i;
  unsigned long currenttime;

  // pull the pin high and wait 250 milliseconds
  digitalWrite(_pin, HIGH);
  delay(250);

  currenttime = millis();
  if (currenttime < _lastreadtime) {
    // ie there was a rollover
    _lastreadtime = 0;
  }
  if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
    return true; // return last correct measurement
    //delay(2000 - (currenttime - _lastreadtime));
  }
  firstreading = false;
  /*
    mySerial.print("Currtime: "); mySerial.print(currenttime);
    mySerial.print(" Lasttime: "); mySerial.print(_lastreadtime);
  */
  _lastreadtime = millis();

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
 
  // now pull it low for ~20 milliseconds
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delay(20);
//  cli();
  noInterrupts();
 
  digitalWrite(_pin, HIGH);
  delayMicroseconds(40);
  pinMode(_pin, INPUT);

  // read in timings
  for ( i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while (digitalRead(_pin) == laststate) {
      counter++;
      delayMicroseconds(1);
      if (counter == 255) {
        break;
      }
    }
    laststate = digitalRead(_pin);

    if (counter == 255) break;

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 6)
        data[j/8] |= 1;
      j++;
    }

  }

//  sei();
    interrupts();

  /*
  mySerial.println(j, DEC);
  mySerial.print(data[0], HEX); mySerial.print(", ");
  mySerial.print(data[1], HEX); mySerial.print(", ");
  mySerial.print(data[2], HEX); mySerial.print(", ");
  mySerial.print(data[3], HEX); mySerial.print(", ");
  mySerial.print(data[4], HEX); mySerial.print(" =? ");
  mySerial.println(data[0] + data[1] + data[2] + data[3], HEX);
  */

  // check we read 40 bits and that the checksum matches
  if ((j >= 40) &&
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    return true;
  }
 

  return false;

}
« Última modificação: 27 de Janeiro de 2015, 21:39 por MAntunes »

Offline KammutierSpule

  • Mini Robot
  • *
  • Mensagens: 1.123
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #1 em: 27 de Janeiro de 2015, 21:54 »
Nao se consegue percebem directamente a tua duvida. Sub-entendo que tenha a ver com o seguinte:
O objectivo de desabilitar interrupts pode ser para responder eventualmente a dois propósitos, o mais normal 'e impossibilitar que outra tarefa aceda a esse recursos. Por exemplo quando estas a ler os valores convertidos, nao queres que outras tarefas estejam a aceder a esse recurso.

Outro propósito, (quando os drivers sao feitos estilo bitbanging, ou em Portugues: "a martelo") 'e para garantir os timmings dos pinos. O que me parece ser esse o caso.

Se for esse o proposito, entao tens de garantir que nesse meio, nao vao acontecer interrupcoes que possam alterar drasticamente o resultado temporal do ciclo que estas a fazer.

A função do Systick 'e bastante curta na generalidade das implementações.
Se o tempo minimo de espera que tens e' de 40us, nao creio que a funcao Systick cause muito jitter se estiveres a usar um clk bastante rapido.

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.389
  • Helpdesk do sitio
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #2 em: 27 de Janeiro de 2015, 22:02 »
O Atmega é relativamente lento, e com digitalWrites em cima então é o degredo, ultra lento, mas ai a ideia é garantir os tempos especificados na datasheet e não perder nenhum ciclo, isso dá bem para fazer num micro mais capaz tendo interrupções a cair, ou usar interrupções no pino de dados e ver o estado que ele está, usar um timer para medir quanto tempo é que o pino está a High e a Low, isso é o tipico código Adafruit, funciona, mas é feito em cima do joelho, nunca mais ninguem olha para ele e toda a gente e a prima usam, porque é da Ada logo é bom...  :-X
Avr fanboy

Offline MAntunes

  • Mini Robot
  • *
  • Mensagens: 56
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #3 em: 27 de Janeiro de 2015, 22:12 »
Obrigado pela ajuda até agora..
Este codigo é para um sensor DHT22, o tipico de humidade e temperatura.
O problema deste sensor é que não tem um protocolo especifico tipo (I2C ou SPI), e o unico codigo que encontrei para ele foi esse da Adafruit..
Tenho que dar outra vista de olhos no datasheet do sensor, e tentar perceber melhor como comunicar com ele e ver se faço um código de raiz.. Não vai ser facil  :-\

Offline LuísR.A.

  • Mini Robot
  • *
  • Mensagens: 1.223
    • Clube de Robotica
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #4 em: 27 de Janeiro de 2015, 22:20 »
Queria-te a ver fazer isso de raiz, tou curioso em saber como fazias :3
Tiva MCU é que é.

Tutoriais Tiva+codigos exemplo:
https://sites.google.com/site/luiselectronicprojects/

Offline MAntunes

  • Mini Robot
  • *
  • Mensagens: 56
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #5 em: 27 de Janeiro de 2015, 22:25 »
Pois, Luis eu também não sei como fazia! Isto não me parece ser nada facil  :'(

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.389
  • Helpdesk do sitio
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #6 em: 27 de Janeiro de 2015, 22:29 »
Isso é uma espécie de one wire, em que medes o tamanho dos pulsos, basicamente toda a gente faz o mesmo:
https://github.com/kapusy/stm32/blob/master/libs/dht22.c

Mas podes usar um pin-change interrupt num pino com Input Capture de um timer, de cada vez que o pino muda de estado vês quanto esteve a high ou a low e sabes se é um 1 ou um 0, é basicamente como os leds WS28xx mas em vez de ser a fazer escrita é a fazer uma leitura.
Avr fanboy

Offline LuísR.A.

  • Mini Robot
  • *
  • Mensagens: 1.223
    • Clube de Robotica
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #7 em: 27 de Janeiro de 2015, 22:30 »
Com um raio de um ARM-M4 a 80Mhz nem deves precisar de usar funções especiais dos timers de captura ou envio nem acesso directo a registos.

Analiza o sinal. È tudo uma questão de timings.



« Última modificação: 27 de Janeiro de 2015, 22:32 por LuísR.A. »
Tiva MCU é que é.

Tutoriais Tiva+codigos exemplo:
https://sites.google.com/site/luiselectronicprojects/

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.389
  • Helpdesk do sitio
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #8 em: 27 de Janeiro de 2015, 22:33 »
Bit bang é melhor, a contar ciclos com delays?
Os input capture são para isso mesmo  ::)

Cuidado é com os 80Mhz que ainda levas com 2 ou 3 wait sates da Flash e tens stalls do pipeline  ;D

Tipicamente ARM's a fundo é a correr código da RAM e não da flash.
Avr fanboy

Offline LuísR.A.

  • Mini Robot
  • *
  • Mensagens: 1.223
    • Clube de Robotica
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #9 em: 27 de Janeiro de 2015, 22:44 »
Lembro-me de verificar e isto consegue ter 0 wait states acima de 40Mhz se o código for executado de forma linear ou caso aquilo consigo calcular bem o branch.
Olha ai uma razão para ter loops pequenos, isto tb é possivel em loops mas têm de ter no máximo 32 instruções assembly


Quais delays? Timers dedicados em One-shot com interrupt ou um while à espera do interrupt não mascarado. Aquilo tem 24 timers (que exagero). Era meter um pouco de DMA para lá e dava
O miguel ainda não sabe usar os input capture (boa desculpa para ires ver deles)
Tiva MCU é que é.

Tutoriais Tiva+codigos exemplo:
https://sites.google.com/site/luiselectronicprojects/

StarRider

  • Visitante
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #10 em: 28 de Janeiro de 2015, 01:43 »
Boas,

Por experiência tenho que:
- Cortex-M3/M4 (STM) SEMPRE zero wait states a correr da flash até um clock de 30Mhz
- Cortex-M3/M4 (STM) com Instruction Cache, zero wait states a correr da flash em qualquer clock em 80%
do tempo de execução
- Cortex-M4 com "flash accelerator" (STM e Freescale Kinetis) sempre com zero wait states a qualquer clock.
- Os NXP têm uma performance mais baixa por falta de cache
- Não conheço pessoalmente os TM4C12x mas pelo que já li vêm sem cache
- Os Freescale Kinetis neste campo batem todas as outras implementações do Cortex-M4 que já me passaram pelas mãos.

MAntunes, para ler o DHT22 (one wire) não necessitas desligar globalmente as INTR, e mesmo a INT do Systick
num sistema a 80Mhz os timmings do DHT22 são "flexíveis" o suficiente para permitir uma leitura sem ser
necessário desligar o timer do Systick, alias, vais necessitar mesmo dele.

Tenho um controlador de focagem com compensação de temperatura a correr num Cortex M3 a 80Mhz com
um RTOS em multi-tarefa (Round-Robin de 5 microsegundos) e consigo ler o DHT22 sem desligar as INTR
e dentro de um thread (tenho 4 threads a correr em simultâneo)

Posso partilhar o código se existir interesse, foi implementado para um STM32 mas como é bastante
genérico é facilmente portável para qualquer MCU. Esta função para ler o DHT22 usa somente o Systick
para os delays e nada mais, e a leitura é feita numa só passagem para a temperatura e humidade e
tem 55 linhas de código.

Abraços,
PA
« Última modificação: 28 de Janeiro de 2015, 01:49 por StarRider »

Offline MAntunes

  • Mini Robot
  • *
  • Mensagens: 56
Re: NoInterrupts(), interrupts(), cli() e sei()
« Responder #11 em: 28 de Janeiro de 2015, 17:58 »
Obrigado a todos pela ajuda até agora!
Vou tentar procurar e fazer como me disseram, alguma duvida volto cá :)