LusoRobótica - Robótica em Português

Software => C/C++ => Tópico iniciado por: TigPT em 08 de Janeiro de 2010, 15:40

Título: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 15:40
Boas,

Alguém já implementou I2C por software em C/C++

Preciso fazer lib disso para o ARM e não me está a apetecer reinventar a roda porque estou muito apertado de timings para outros projectos.
Título: Re: I2C por software em C/C++
Enviado por: Tyran em 08 de Janeiro de 2010, 15:48
Já mas foi em assembly 8051 ;D

Hmm, mas penso que no JeeLabs ele tem por lá qualquer coisa disso na biblioteca Ports penso eu de que...

EDIT: Acabei de ver na ports que tenho das libs do arduino e tem mesmo pelo menos assim rapidamente parece ser pois está a puxar ele as linhas :)
Título: Re: I2C por software em C/C++
Enviado por: ricardo-reis em 08 de Janeiro de 2010, 15:50
tiago, a lib wire do arduino faz tudo o k precisas de i2c, dá uma olhada nisso.. ;)
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 15:51
Tenho estado a ver mas ela baseia-se na twi.c e está demasiado orientada à arquitectura avr, creio que até utiliza i2c no avr por hardware em vez de implementar td em software.

Obrigado pelas ajudas.
Título: Re: I2C por software em C/C++
Enviado por: Tyran em 08 de Janeiro de 2010, 16:02
Pois, mas na do ports já é por software penso eu.

EDIT: Sim já confirmei as rotinas todas, não encontrava a sdaOut porque estava inline na classe  ;D
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 16:03
Estava agora a ler :P

http://code.jeelabs.org/viewvc/svn/jeelabs/trunk/libraries/Ports/Ports.cpp?revision=4752&view=markup (http://code.jeelabs.org/viewvc/svn/jeelabs/trunk/libraries/Ports/Ports.cpp?revision=4752&view=markup)
Título: Re: I2C por software em C/C++
Enviado por: metRo_ em 08 de Janeiro de 2010, 17:14
mas o arm já tem algum hardware para isso certo?
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 17:16
Tem mas o prof quer implementado por software  :-\

creio que já esteja minimamente funcional, ainda não testei mas deve de estar bom, depois faço debug:
Código: [Seleccione]
#define SDA 2
#define SCL 3

//TODO rever tempos
#define I2C_SETUP_TIME 1
#define I2C_PULSE_TIME 1
#define I2C_HOLD_TIME  1


#include "types.h"
#include "io.h"

#define _SCL(val) (digitalWrite(SCL, val))
#define _SDA(val) (digitalWrite(SDA, val))
#define _SDA_IN (digitalRead(SDA))

void i2c_init()
{
pinMode(SDA, OUTPUT);
pinMode(SCL, OUTPUT);
_SDA(HIGH);
_SCL(HIGH);
}

void i2c_start_seq()
{
_SDA(HIGH);
_SCL(HIGH);
_SDA(LOW);
_SCL(LOW);
_SDA(HIGH);
_SCL(HIGH);
}

void i2c_stop_seq()
{
_SCL(LOW);
_SDA(LOW);
_SCL(HIGH);
_SDA(HIGH);
}

void i2c_begin_transmission(int addr)
{
i2c_start_seq();
i2c_send(addr);
//shiftOut(SDA, SCL, MSBFIRST, addr);
//scl(HIGH);
}

void i2c_end_transmission()
{
i2c_stop_seq();
}

void i2c_send(int byte)
{
_SCL(LOW);
int mask = 0x80;
for (; mask != 0; mask >>= 1) {
_SDA(data & mask);
_SCL(HIGH);
_SCL(LOW);
}
_SDA(HIGH);
_SCL(HIGH);
int ack = ! _SDA_IN();
_SCL(LOW);
return ack;
}

//TODO confirm with datasheet
int i2c_read(){
int data = 0;
int mask = 0x80;
for (; mask != 0; mask >>= 1) {
_SCL(HIGH);
if (_SDA_IN())
    data |= mask;
_SCL(LOW);
}
_SCL(HIGH);
_SCL(LOW);
_SDA(HIGH);
return data;
}

Título: Re: I2C por software em C/C++
Enviado por: Raul em 08 de Janeiro de 2010, 19:49
Estás a fazer um braço robotico?
Não sei ao certo o que queres dizer com ARM
Cumprimentos
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 19:53
http://www.arm.com/ (http://www.arm.com/)

É uma familia de microcontroladores tal como a AVR, Microchip, NXP, etc..
Título: Re: I2C por software em C/C++
Enviado por: Njay em 08 de Janeiro de 2010, 20:43
É melhor colocares uns delays para garantires uma frequência máxima de execução... a não ser que o teu chip sejam bem lentinho.
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 21:05
Tinha me esquecido, está a 60Mhz, é melhor! Obrigado ;)
Título: Re: I2C por software em C/C++
Enviado por: metRo_ em 08 de Janeiro de 2010, 21:55
É melhor colocares uns delays para garantires uma frequência máxima de execução... a não ser que o teu chip sejam bem lentinho.

Isto é para quando por exemplo faço:
Código: [Seleccione]
for(xpto<100){
   void i2c_send(blabla);
}

ele não enviar os bytes a uma maior frequência do que devia, certo?

Não seria melhor utilizar um timer com esse tempo que vais colocar nos delays e quando este gerar a interrupção alteras uma variável para saber se já foi enviado o byte ou não e se já podes enviar novamente.
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 08 de Janeiro de 2010, 22:09
É mais entre transições de sinais para garantir o bitrate i2c compatível.

Isto é só para nos fazer sentir o protocolo todo que depois fazemos por hardware e não é preciso preocupar com nada.
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 09 de Janeiro de 2010, 21:43
Tem mas o prof quer implementado por software  :-\

creio que já esteja minimamente funcional, ainda não testei mas deve de estar bom, depois faço debug:
Código: [Seleccione]
#define SDA 2
#define SCL 3

//TODO rever tempos
#define I2C_SETUP_TIME 1
#define I2C_PULSE_TIME 1
#define I2C_HOLD_TIME  1


#include "types.h"
#include "io.h"

#define _SCL(val) (digitalWrite(SCL, val))
#define _SDA(val) (digitalWrite(SDA, val))
#define _SDA_IN (digitalRead(SDA))

void i2c_init()
{
pinMode(SDA, OUTPUT);
pinMode(SCL, OUTPUT);
_SDA(HIGH);
_SCL(HIGH);
}

void i2c_start_seq()
{
_SDA(HIGH);
_SCL(HIGH);
_SDA(LOW);
_SCL(LOW);
_SDA(HIGH);
_SCL(HIGH);
}

void i2c_stop_seq()
{
_SCL(LOW);
_SDA(LOW);
_SCL(HIGH);
_SDA(HIGH);
}

void i2c_begin_transmission(int addr)
{
i2c_start_seq();
i2c_send(addr);
//shiftOut(SDA, SCL, MSBFIRST, addr);
//scl(HIGH);
}

void i2c_end_transmission()
{
i2c_stop_seq();
}

void i2c_send(int byte)
{
_SCL(LOW);
int mask = 0x80;
for (; mask != 0; mask >>= 1) {
_SDA(data & mask);
_SCL(HIGH);
_SCL(LOW);
}
_SDA(HIGH);
_SCL(HIGH);
int ack = ! _SDA_IN();
_SCL(LOW);
return ack;
}

//TODO confirm with datasheet
int i2c_read(){
int data = 0;
int mask = 0x80;
for (; mask != 0; mask >>= 1) {
_SCL(HIGH);
if (_SDA_IN())
    data |= mask;
_SCL(LOW);
}
_SCL(HIGH);
_SCL(LOW);
_SDA(HIGH);
return data;
}


Boas,

Não percebi bem, esse código é ser executado num ARM ? Com que compilador ?


Título: Re: I2C por software em C/C++
Enviado por: TigPT em 09 de Janeiro de 2010, 22:36
Sim, em arm com o arm-elf-gcc

O que não percebeste?
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 00:02
Sim, em arm com o arm-elf-gcc

O que não percebeste?


Boas,

Pois, a minha duvida está no facto de "digitalWrite()" e "pinMode()" serem funções nativas do
compilador do Arduino e eu desconhecer que as mesmas existam nas libs de qualquer toolchain
para ARM, incluindo o arm-gcc.

Mas é claro que podes sempre implementar tu as funções, se bem que uma vez que já tens o
define "#define _SCL(val)" o mais lógico seria definir logo aqui os GPIOs, algo no género:

#define BIT(NUM) (0x00000001 << NUM)
#define _SCL(val)  IO0SET = BIT(NUM)

Em que o NUM corresponde ao bit que controla a porta que desejas usar.

Mas como no ARM o estado dos GPIOs são tratados com dois registos separados, vais ter que
usar algo mais no género de:

#define BIT(NUM) (0x00000001 << NUM)
#define _SCL(val)  val==HIGH ? IO0SET = BIT(NUM) : IOCLR = BIT(NUM)

Isto se estivermos a falar do LPC210x, que se estou recordado é o que vais usar.

Abraços
Paulo A.
Título: Re: I2C por software em C/C++
Enviado por: Njay em 10 de Janeiro de 2010, 00:06
Já agora uma achegazinha em relação às macros em geral. É boa prática de programação envolver sempre os argumentos de uma macro entre parentesis, no corpo da macro. Por exemplo a macro bit acima,

#define BIT(NUM) (0x00000001 << NUM)

funciona bem enquanto usarmos argumentos "simples" como

BIT(2) ou BIT (ctr)

mas falha se fizermos

BIT(ctr + 1)  BIT(ctr == 1? 2 : 3)  (corrigido, ver mais abaixo no tópico, obrigado ao StarRider!)

Daí que convém definir com os argumentos entre parentesis, como

#define BIT(NUM) (0x00000001 << (NUM))
Título: Re: I2C por software em C/C++
Enviado por: metRo_ em 10 de Janeiro de 2010, 00:19
Já agora uma achegazinha em relação às macros em geral. É boa prática de programação envolver sempre os argumentos de uma macro entre parentesis, no corpo da macro. Por exemplo a macro bit acima,
#define BIT(NUM) (0x00000001 << NUM)
funciona bem enquanto usarmos argumentos "simples" como
BIT(2) ou BIT (ctr)
mas falha se fizermos
BIT(ctr + 1)
Daí que convém definir com os argumentos entre parentesis, como
#define BIT(NUM) (0x00000001 << (NUM))

Podes explicar o porque disto acontecer?
Título: Re: I2C por software em C/C++
Enviado por: msr em 10 de Janeiro de 2010, 00:30
Se não me engano, tem a ver com as precedências (http://www.difranco.net/cop2220/op-prec.htm).
Não tenho a certeza do que acontece neste caso (shift) mas provavelmente o que ele faz é NUM shifts e depois soma 1 ao resultado (no exemplo que o Njay deu) quando o que se pretendia era fazer (NUM+1) shifts.
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 10 de Janeiro de 2010, 00:35
Pois, a minha duvida está no facto de "digitalWrite()" e "pinMode()" serem funções nativas do
compilador do Arduino e eu desconhecer que as mesmas existam nas libs de qualquer toolchain
para ARM, incluindo o arm-gcc.
Não são funções nativas de Arduino porque o Arduino não é uma arquitectura nem um compilador, é uma mera API + bootloader.

Sim, implementei funções com esses nomes por ser mais sugestivo e permitir mais tarde fazer porte de Arduino para ARM se existir interesse e tempo.

Não é nada interessante utilizar valores expostos da arquitectura por uma simples razão, é uma biblioteca, é suposto ser portável e flexível. Em vez de ser um conjunto de horas de trabalho enorme que depois não são facilmente migráveis para outros projectos.

Depois posto o resto do código quando estiver mais organizado. (contudo está disponível no SVN para os curiosos)


Podes explicar o porque disto acontecer?

Simplesmente porque não sabes onde a tua macro vai ser utilizada e assim proteges de anomalias tais como pós notação.

#define BIT(NUM) (0x00000001 << NUM)

BIT(3) // origina 3 shifts
BIT(3+1) origina 3 shits e a soma do int 1 no fim dos shits pois o shit tem prioridade à soma.

PS - msr tinha respondido ao mesmo tempo que eu.
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 03:18
Não são funções nativas de Arduino porque o Arduino não é uma arquitectura nem um compilador, é uma mera API + bootloader.


Meu caro TigPT,

Arquitectura ? não mencionei essa palavra, o que eu mencionei foi compilador, e ai sim "I stand my
ground" !

A filosofia "Arduino", engloba varias componentes, sendo que o que realmente faz a diferença é
o "Ambiente" Arduino, aquilo que geralmente se chama de IDE e serve para desenvolver o
código "Arduino" que depois será carregado no AVR.

Como em qualquer outro IDE , o do Ambiente de Desenvolvimento do Arduino é constituído por
uma LINGUAGEM, que no caso é baseada no C/C++. A implantação da LINGUAGEM ARDUINO é
somente baseada em C/C++, não é 100% compatível com o padrão ISO/ANSI que especifica
a totalidade da linguagem C/C++.

Como em qualquer linguagem, o Arduino C/C++ tem as suas especificidades, e como qualquer
linguagem o "Ambiente de Desenvolvimento do Arduino" tem a sua "Language Reference".

Acontece que a "Language Reference" do COMPILADOR utilizado pelo IDE do Arduino refere
claramente um conjunto de funções e constantes que são NATIVAS do ambiente/compilador
em si, entre elas estão as funções que "tratam" dos IOs: pinMode,  digitalWrite e digitalRead.

Por isso, sim, o Arduino engloba um IDE com UM COMPILADOR, sendo o compilador baseado
no avr-gcc.

E  pinMode,  digitalWrite e digitalRead são funções que fazem parte da lib do COMPILADOR do
Arduino, dai serem NATIVAS ao COMPILADOR do Arduino e não existirem “nativamente” em mais
nenhum compilador de C/C++.

Já uma API é uma coisa totalmente diferente e que nada tem a ver para o caso, uma API é
uma interface entre um software e um cliente que usa as suas funcionalidades sem sequer
saber dos detalhes da implementação. Se quiseres podemos aprofundar este tema, mas nada
tem a ver para este caso.

No Arduino o que tu tens é IDE (Ambiente de Desenvolvimento) onde escreves o código, aquilo
que em Arduino se chama  “sketch” , fazes a COMPILAÇÃO, e fazes o upload do código compilado
para o AVR, que ai sim, tem um bootloader.

O bootloader  é um pequeno programa residente no AVR e que serve somente para que o IDE
Arduino possa carregar o código COMPILADO para o AVR, e depois de carregado faz o reset da
board e executa o código que foi carregado, deixando de ter qualquer posterior uso durante a
execução do mesmo.

Por acaso até é possível carregar o código gerado pelo COMPILADOR Arduino sem usar o bootloader
do Arduino, basta usar um programador externo, como o AVRDude ou o AVRprog, por exemplo.

É claro que o IDE Arduino ("Arduino software" ou "Arduino environment" como é descrito por vezes)
tem um compilador, de que outra forma achas tu que o AVR conseguia executar o código ? O AVR
não tem um interpretador. O Arduino usa a toolchain avr-gcc para compilar, o avrdude para
fazer o upload e a lib avr-libc.

O sucesso do Arduino, e a sua principal força, é o seu IDE e as funções disponibilizadas por este
nas suas libs, essas funções, como o pinMode,  digitalWrite e digitalRead, vieram permitir que
muitos que não compreendem nem sabem o que está “por detrás” possam utilizar um uC de uma
forma simples e rápida, mas isso vem com um preço, e o preço é depois nos faltam as bases
quando queremos ir mais alem, mas nada como ler as datasheets, está lá tudo, boa sorte na
tua demanda.

Não é nada interessante utilizar valores expostos da arquitectura por uma simples razão, é uma biblioteca, é suposto ser portável e flexível. Em vez de ser um conjunto de horas de trabalho enorme que depois não são facilmente migráveis para outros projectos.

Era somente um exemplo, usa-o da forma que consideres melhor para o projecto em causa, como
define, macro ou numa função, a ideia era somente partilhar a informação.


Abraços
Paulo A.
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 03:25
Já agora uma achegazinha em relação às macros em geral. É boa prática de programação envolver sempre os argumentos de uma macro entre parentesis, no corpo da macro. Por exemplo a macro bit acima,

#define BIT(NUM) (0x00000001 << NUM)

funciona bem enquanto usarmos argumentos "simples" como

BIT(2) ou BIT (ctr)

mas falha se fizermos

BIT(ctr + 1)

Daí que convém definir com os argumentos entre parentesis, como

#define BIT(NUM) (0x00000001 << (NUM))

Boas,

Sim, tens razão. 

Esse "define" serve somente para demonstrar que se trata de "um bit" para cada porta num registo
de 32 bits, dependendo da forma como o código é implementando, numa função por exemplo, acaba
por nem ser necessário.

Abraços,
Paulo A.

Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 12:22

Simplesmente porque não sabes onde a tua macro vai ser utilizada e assim proteges de anomalias tais como pós notação.

#define BIT(NUM) (0x00000001 << NUM)

BIT(3) // origina 3 shifts
BIT(3+1) origina 3 shits e a soma do int 1 no fim dos shits pois o shit tem prioridade à soma.

PS - msr tinha respondido ao mesmo tempo que eu.

Boas,

Não, desculpa mas estás errado,  na expressão (0x00000001 << 3+1), que é a
gerada pelo preprocessador,  ou pelo compilador em si se não tiver reprocessador,
e seguindo as normas  ISO/ANSI  usadas por todos os compiladores conhecidos
o operador "+" tem procedência sobre o "<<"  !

A expressão evolui para (0x00000001 << 4), e só depois é feito o shift!

Logo, o shift SERÁ SEMPRE 4 BITS !

Acho que se deve ter um pouco mais de cuidado com as afirmações que fazemos,
pois podemos estar a induzir os outros em erro.

Para quem não se "recorda" das regras, aqui ficam alguns links... muitos outras fontes
existem, ou então consultem os manuais dos vossos compiladores:
http://www.cppreference.com/wiki/operator_precedence (http://www.cppreference.com/wiki/operator_precedence)
http://msdn.microsoft.com/en-us/library/126fe14k.aspx (http://msdn.microsoft.com/en-us/library/126fe14k.aspx)

Ou então experimentem vocês mesmo, façam algo neste género:

#define BIT(NUM) (0x00000001 << NUM)
void main()
{
    long xpto;
    xpto = BIT(3+1);
    printf("%l", xpto);
}

E vão ver que o resultado é 16 ou seja b0000 0000 0000 0000 0000 0000 0001 0000

Abraços
Paulo A.


Título: Re: I2C por software em C/C++
Enviado por: TigPT em 10 de Janeiro de 2010, 12:35
Ainda não tive tempo de ler todo o post mas deixo já uma nota:

http://www.cplusplus.com/doc/tutorial/operators/ (http://www.cplusplus.com/doc/tutorial/operators/)

Tabela do fim da página:
Citar
From greatest to lowest priority, the priority order is as follows:

Título: Re: I2C por software em C/C++
Enviado por: TigPT em 10 de Janeiro de 2010, 13:06
Concordo com grande parte do que disseste, contudo há uma coisa que não entendo...

O que é uma "Linguagem de Programação"?
Para mim uma linguagem de programação é um conjunto de keywords e sintaxe que permite descrever de forma textual comportamentos do hardware que o vai executar.

Assembler, C, C++, C#, Java, Pascal, Cobol, PHP, entre muitas outras, têm uma coisa em comum entre elas, embora se baseiem todas umas nas outras (naturalmente) nenhuma é compatível entre si pois utilizam keywords e sintaxes diferentes.

Arduino, ObjectiveC, SWING, AWP, entre outras, são APIs, blocos de código compatíveis com uma linguagem base que permitem estende-la facilitando assim a vida ao programador evitando estar sempre a repetir código.

Vamos então olhar para writing_digital.c da API Arduino:
http://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/wiring_digital.c (http://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/wiring_digital.c)

Código: [Seleccione]
void pinMode(uint8_t pin, uint8_t mode)
{
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *reg;

        if (port == NOT_A_PIN) return;

        // JWS: can I let the optimizer do this?
        reg = portModeRegister(port);

        if (mode == INPUT) *reg &= ~bit;
        else *reg |= bit;
}

Como  se pode ver, de forma muito clara, esta função é um call a um boloco de código em C-AVR que permite alterar o modo de funcionamento do pin em questão para o segundo argumento passado.

Comparemos com o meu código para ARM:
http://code.google.com/p/lpc210x/source/browse/trunk/libs/io.c (http://code.google.com/p/lpc210x/source/browse/trunk/libs/io.c)

Código: [Seleccione]
void pinMode(int pin, int mode){
        if (mode)
                io_write_U32(GPIO + IODIR, io_read_U32(GPIO + IODIR) | (1 << pin));
        else
                io_write_U32(GPIO + IODIR, io_read_U32(GPIO + IODIR) & ~(1<<pin));     
}

void io_write_U32(U32 addr, U32 val)
{
        *(U32 *) addr = val;
}

Mais uma vez, uma call para um bloco de código que modifica o funcionamento de um pin nesta em C-ARM.

O que quero dizer é que no meu ponto de vista (muitos poderão discordar e gostava de ouvir porque para poder reeducar-me se achar que estou errado) são meras APIs, isto é, blocos de código que facilitam a vida ao programador, mas não são uma linguagem de programação pois não são conjuntos de keywords e sintaxes que permitem escrever código de forma diferente, apenas escondem parte das rotinas pois elas são tipicamente iguais.

Espero que todos estejam cientes que as minhas palavras são apenas minhas, neste meu processo critico de aprendizagem onde tento expor o que sei e o que penso para que possamos em conjunto criticar as minhas observações e molda-las para um conhecimento mais correcto.
Título: Re: I2C por software em C/C++
Enviado por: Njay em 10 de Janeiro de 2010, 14:49
Por acaso estava convencido que os operadores de deslocamento tinham precedência sobre a soma (na prática nunca tenho problemas com isso porque apenas "confio" na precedência das operações aritméticas e uso parentesis para tudo o resto).

De qualquer forma a achega mantém-se, pois há outras formas de a coisa correr mal nesta macro, como

BIT(ctr & 7)
BIT(ctr == 1? 2 : 3)

e outros.
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 10 de Janeiro de 2010, 14:53
Sou só eu que estou a ler de forma diferente?

http://www.cppreference.com/wiki/operator_precedence (http://www.cppreference.com/wiki/operator_precedence)
Citar
The operators at the top of this list are evaluated first.
Título: Re: I2C por software em C/C++
Enviado por: Njay em 10 de Janeiro de 2010, 14:59
Não percebi Tiago...
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 10 de Janeiro de 2010, 15:01
Esquece.. estou mesmo a dar em doido, é esta dor de estomago que tenho desde manhã que me está a afectar o raciocinio!
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 15:39
Por acaso estava convencido que os operadores de deslocamento tinham precedência sobre a soma (na prática nunca tenho problemas com isso porque apenas "confio" na precedência das operações aritméticas e uso parentesis para tudo o resto).

De qualquer forma a achega mantém-se, pois há outras formas de a coisa correr mal nesta macro, como

BIT(ctr & 7)
BIT(ctr == 1? 2 : 3)

e outros.

Sim, totalmente de acordo, o problema está com expressões mais complexas no argumento.

Abraços.
Paulo A.
Título: Re: I2C por software em C/C++
Enviado por: StarRider em 10 de Janeiro de 2010, 16:02
Concordo com grande parte do que disseste, contudo há uma coisa que não entendo...

O que é uma "Linguagem de Programação"?
Para mim uma linguagem de programação é um conjunto de keywords e sintaxe que permite descrever de forma textual comportamentos do hardware que o vai executar.

Assembler, C, C++, C#, Java, Pascal, Cobol, PHP, entre muitas outras, têm uma coisa em comum entre elas, embora se baseiem todas umas nas outras (naturalmente) nenhuma é compatível entre si pois utilizam keywords e sintaxes diferentes.

Arduino, ObjectiveC, SWING, AWP, entre outras, são APIs, blocos de código compatíveis com uma linguagem base que permitem estende-la facilitando assim a vida ao programador evitando estar sempre a repetir código.

Vamos então olhar para writing_digital.c da API Arduino:
http://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/wiring_digital.c (http://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/wiring_digital.c)

Código: [Seleccione]
void pinMode(uint8_t pin, uint8_t mode)
{
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *reg;

        if (port == NOT_A_PIN) return;

        // JWS: can I let the optimizer do this?
        reg = portModeRegister(port);

        if (mode == INPUT) *reg &= ~bit;
        else *reg |= bit;
}

Como  se pode ver, de forma muito clara, esta função é um call a um boloco de código em C-AVR que permite alterar o modo de funcionamento do pin em questão para o segundo argumento passado.

Comparemos com o meu código para ARM:
http://code.google.com/p/lpc210x/source/browse/trunk/libs/io.c (http://code.google.com/p/lpc210x/source/browse/trunk/libs/io.c)

Código: [Seleccione]
void pinMode(int pin, int mode){
        if (mode)
                io_write_U32(GPIO + IODIR, io_read_U32(GPIO + IODIR) | (1 << pin));
        else
                io_write_U32(GPIO + IODIR, io_read_U32(GPIO + IODIR) & ~(1<<pin));     
}

void io_write_U32(U32 addr, U32 val)
{
        *(U32 *) addr = val;
}

Mais uma vez, uma call para um bloco de código que modifica o funcionamento de um pin nesta em C-ARM.

O que quero dizer é que no meu ponto de vista (muitos poderão discordar e gostava de ouvir porque para poder reeducar-me se achar que estou errado) são meras APIs, isto é, blocos de código que facilitam a vida ao programador, mas não são uma linguagem de programação pois não são conjuntos de keywords e sintaxes que permitem escrever código de forma diferente, apenas escondem parte das rotinas pois elas são tipicamente iguais.

Espero que todos estejam cientes que as minhas palavras são apenas minhas, neste meu processo critico de aprendizagem onde tento expor o que sei e o que penso para que possamos em conjunto criticar as minhas observações e molda-las para um conhecimento mais correcto.


Boas Tiago,

Uma API (Application Programming Interface) é uma definição da implementação de uma interface
com o objectivo de fornecer ao programador uma forma de interagir com as funcionalidades
fornecidas por um determinado sistema computacional. Existem APIs implementadas por sistemas
operativos, sistemas de ficheiros, base dados, redes, etc., mas o denominador comum é que uma
API é implementada e disponibilizada por um software ou serviço já existente.

Traduzindo isto para Layers  do modelo OSI, eu diria que uma API não fica abaixo do layer 5, sendo
que no layer 1 temos o hardware.

Compreendo, e acaba por ser frequentemente usado, que uma lib (biblioteca como se diz em
português) seja por muitos considerada uma API, mas não é correcto considerar um conjunto de
funções que interagem directamente com o hardware (layer 1) como uma Application Programming
Interface, uma API está a um nível muito mais alto, e é muito mais abstracta para o programador a
nível de implementação.

Por exemplo, numa verdadeira API nunca terias acesso à implementação da função pinMode como
exemplificaste.

Não se esqueçam que estamos a falar de Embedded Systems , e a coisa que mais perto se pode
ficar de uma API é usar as funcionalidades disponibilizadas por um RTOS, e mesmo assim, se
recorrermos mais uma vez à analogia OSI, estamos a trabalhar num layer muito baixo.

Por isso, considero que o uso do termo API para descrever as funções disponibilizadas pelas libs
(biblioteca) fornecidas com o do IDE Arduino não é correcto, afinas de contas não passam disso
mesmo, um conjunto de funções de baixo nível. Mas compreendo a ideia por detrás do uso do termo
API neste contexto.

Voltando às linguagens.

Como tu dizes, e bem, as linguagem de programação caracteriza-se pela sua sintaxe, um pouco de
forma análoga ao que se passa nas linguagens e idiomas humanos.

Na base temos as instruções em Assembler, que são as que no fundo cada processador, seja ele um
AVR ou um Intel, entendem. As datasheets indicam o que cada instrução executa, e indicam um
opcode para cada uma dessas instruções. Como tudo o que um processador entende é números, o
que o compilador de Assemler faz é converter o nosso código assembler em opcodes e operandos,
que são depois executados pelo processador.

Tudo o que as linguagem de médio e alto nível fazem é introduzir uma forma ,de nós humanos,
escrevermos código de uma forma mais natural e mais simples do que usando Assembler ou os
opcodes directamente. Existem compiladores de linguagens de alto nível que geram directamente os
opcodes, outros geram assembler que é posteriormente compilado usando o compilador de
assembler especifico para cada processador, isto claro de forma transparente para o programador.

C, C++, C#, Java, Pascal, Cobol, PHP, ObjectiveC, e todas as outras são linguagens de
programação. O Arduino implementa uma variante de C/C++, mas ao fazê-lo ganhou o direito de
ser considerada uma linguagem, pois afinal de contas tem uma sintaxe, tem uma flow, e tem as
duas regras.

Por exemplo, na implementação C/C++ do IDE do Arduino a função “main”, que é o ponto de
entrada  executado depois do código startup correr (todos os compiladores/processadores geram
código startup e corre antes do “nosso” código, e que é na maioria só está acessível se formos à
procura dele), esta função “main” não é o ponto de entrada do nosso programa. Dai eu ter dito que
o código C/C++ Arduino não ser portável directamente para qualquer outro compilador de C/C++.

Cada linguagem tem a sua especificidade, algumas linkam com libs externas, outras o próprio
compilador insere código/chamadas que serão linkados internamente.

Para evitar divagar muito vamos somente cingir-nos ao C/C++. Tudo o que o compilador entende
está descrito nas especificações do mesmo, existe um padrão ANSI que define a implementação e
a sintaxe que um compilador de C/C++ deve perceber, essa especificação engloba também algumas
funções padrão, tais como o “printf”, “atoi”, “scanf”, etc, etc. Geralmente estas funções padrão são
as que podemos encontrar nos headers “stdio.h”, “stdargs.h”, “stddef.h”, “stdlib.h”, etc, etc.

Estas funções, e outras que possam acompanhar um qualquer compilador com header específicos,
são geralmente contidas em libs (bibliotecas) que são depois incorporadas no código final pelo linker
(lincador/linkador?).

Depois temos as nossas próprias funções, aquelas que nós escrevemos, e que podemos incluir numa
lib existente ou criar a nossa lib, ou  podemos simplesmente incluir a fonte junto com o resto do
nosso código.

Tal como qualquer outra função, seja interna (nossa) seja ela externa (vinda de uma lib) esses
“blocos de código” como tu lhes chamas, são isso mesmo, são simples funções contidas numa lib.
Uma função pode interagir com o hardware, ou pode simplesmente efectuar um qualquer
processamento lógico ou de dados, mas será sempre uma função, e como dizes, e bem, evita
duplicar código e poupa trabalho, mas mesmo as que interagem com o hardware, a este nível, nunca
podem ser consideradas uma API são meras funções... no máximo a este nível podemos
chamar-lhes “drivers” (controladores).

Pela sua própria definição, um “blocos de código reutilizável” é uma função, quer existe no código
quer exista numa lib e seja posteriormente linkada.

Mas como já disse, compreendo a tua ideia por trás do uso do termo API.

Existe muito mais coisas interessantes a dizer sobre estes assuntos, mas este post já vai longo
e maçador, qualquer dia voltamos a falar sobre isto.

Abraços
Paulo A.
Título: Re: I2C por software em C/C++
Enviado por: TigPT em 11 de Janeiro de 2010, 11:04
Realmente existe uma confusão generalizada entre API de serviços e API de desenvolvimento, coisa que a segunda nem faz parte do modelo OSI visto que passa a fazer parte integrante do software/firmware após compilação, em vez de ser um serviço disponível em runtime.

Obrigado por expores o teu ponto de vista, irei reflectir mais sobre o assunto!
Título: Re: I2C por software em C/C++
Enviado por: Njay em 11 de Janeiro de 2010, 19:48
Para mim tudo o que é uma interface de programação é uma API. Basta haver um conjunto de funcionalidade embrulhada numa Programming Interface, uma abstracção, que para mim já tá ok para lhe chamar API. Podia chamar-lhe PI que seria um nome mais apropriado para cobrir todos os casos, mas se eu usasse esse termo, na melhor das hipóteses pensariam que se tratava do 3.141592(...), portanto :)...
Título: Re: I2C por software em C/C++
Enviado por: metRo_ em 11 de Janeiro de 2010, 20:25
Podia chamar-lhe PI...

Ou um controlador Proporcional Integrador :)