LusoRobótica - Robótica em Português
Sistemas específicos => ARM => Tópico iniciado por: MAntunes 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!
#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().
/* 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;
}
-
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.
-
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
-
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 :-\
-
Queria-te a ver fazer isso de raiz, tou curioso em saber como fazias :3
-
Pois, Luis eu também não sei como fazia! Isto não me parece ser nada facil :'(
-
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.
-
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.
-
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.
-
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)
-
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
-
Obrigado a todos pela ajuda até agora!
Vou tentar procurar e fazer como me disseram, alguma duvida volto cá :)