quarta-feira, 27 de agosto de 2008

Computador de Bordo


Taí pessoal, muita gente me questiona sobre o que a Youlink! faz além de ter um cara que fica escrevendo no 5Vcc... pois bem ... está aí... um computador de bordo para tratores, caminhões e máquinas de campo.
Teclado reforçado, display de 40x2 linhas, Armazenamento de dados em EEPROM (128Kbytes) e comunicação via Bluetooth. Tá certo isso que está na foto é o protótipo, falta muito detalhe para o produto final, principalmente de acabamento, manzzz já dá pra ter uma boa idéia do que fazemos por aqui ...
Claro... o processador usado é um Renesas R8C/25, o bluetooth utilizado é o ESD-100 da SENA.
Se alguém estiver interessado, o contato está em http://www.youlink.com.br.

terça-feira, 26 de agosto de 2008

[Renesas] I2C BitBang para 24XX256

Faz tempo que não consigo parar e escrever um bom POST. Pois bem, chego aqui com algo que havia prometido para muitos. Um código para barramento I2C para o 24C256 que usei num projeto meu.
Após ter alguns problemas em relação a configuração do R8C/25 com I2C via hardware, que já foi sanado, me sobrou este código desenvolvido, que aliás eu gostei mais que o I2C via device. Não pela versatilidade ou velocidade mas pela portabilidade. Acredito que este código que eu vou apresentar funciona com poucas altrações nos PICs e nos AVRs da vida.
Mas antes de falarmos do código vamos falar um pouco mais de I2C.
O I2C é um barramento serial, onde temos um canal de dados bidirecional e um canal de clock, regido pelo device Master, no caso o nosso R8C/25.

A ligação é feita de forma serial, vide esquema abaixo:


Notem que temos dois resitores de Pull-Up que devem ser instalados um para cada linha, SDA e SCL. Na prática com PIC geralmente uso resitores de 10k e com o R8C/25 uso resitores de 15k, ambos em 5V, não sei explicar o porquê mas com os Renesas só consegui estabilidade no Bus usando 50% a mais de carga no resitor de Pull-Up, vale como dica para não perderem tempo, como eu perdi tentando buscar outros motivos de "não funcionamento".

Os dados são transferidos, setando o estado do bit a ser transferido no SDA e chaveando o SCL. O dado é transferido na transição UP->Down. Acompanhe no diagrama abaixo:



Existem alguns poréns entre os estados de comunicação, dentre eles posso citar o Start Condition e o Stop Condition, no qual colocam.
O Start Condition serve para iniciar uma comunicação e o Stop Condition analogamente serve para encerrar a mesma.


De acordo com o diagrama acima, notamos que o Start Condition é gerado partindo dos sinais do SCL e do SDA em nível 1, chaveamos o SDA para nível baixo e no próximo tempo do Clock baixamos o nível do SCL.
Analogamente mais uma vez, o Stop Condition é gerado partindo dos sinals SCL e SDA em nível 0, chaveamos o SCL para nível 1 e em seguida, mais uma vez no tempo do Clock, elevamos o nível do SDA para 1.

Vide o seguinte código abaixo:

void startCondition(void) {
setSCLHigh();
setSDAHigh();
setSDALow();
waitFactor(2);
setSCLLow();
waitFactor(2);
}

Mais uma vez conforme o diagrama, antes elevamos os níveis para 1, em seguida baixamos o nível do SDA para 0, aguardamos 2 tempos do Clock, e em seguida baixamos o nível do SCL para 0. E mais uma vez aguardamos 2 tempos do Clock. Com este código geramos um Start Condition.

E agora o StopCondition:

void stopCondition(void) {
setSDALow();
waitFactor(1);
setSCLLow();
waitFactor(1);
setSCLHigh();
waitFactor(2);
setSDAHigh();
waitFactor(2);
}

Nesta função, note que chaveamos o SDA para nível 0 e aguardamos um tempo do Clock para em seguida descer o nível do Clock para 0. Fazemo isso para evitar que geremos um Erro no bus I2C no caso de um término de transação. Em seguida conforme diagrama do Stop Condition subimos o nível do SCL para nivel 1 e aguardamos dois tempos do Clock, em seguida subimos o nível do SDA para 1 e aguardamos mais uma vez dois tempos do Clock. Assim geramos um Stop Condition.

Um outro status importante na transação I2C é o Acknowlodge ou simplesmente Ack. Ele é a resposta do periférico que está sendo comunicado de que foi aceito o último byte.
O Ack é reconhecido após a escrita, colocando o pino do SDA em modo Input após o envio do oitavo bit. O pino SDA deverá ir para nível 0, forçado pelo dispositivo que se está comunicando. Ao gerar um novo pulso do Clock, é sinalizado ao dispositivo slave que foi lido o Ack, então o controle de SDA volta para o dispositivo Master, no nosso caso o R8C/25, onde o pino do SDA deve novamente ser setado como Output.
Acompanhe o código abaixo:

char getSDAState(void) {
_24C256_sda_d = 0;
asm("NOP");
return(_24C256_sda);
}

char readAck(void) {
char state=0;
setSCLHigh();
waitFactor(1);
state=getSDAState();
setSCLLow();
setSDAHigh();
waitFactor(3);
return(state);
}

Neste trecho setamos o SCL como nível 1 para finalizar o processo do último bit enviado, esperamos um ciclo de Clock, e lemos o estado do SDA. Em seguida setamos o SCL como nível 0 para sinalizar a leitura do Ack e ao mesmo tempo setamos o pino SDA como 1 para podermos iniciar uma nova comunicação ou enviar um Start/Stop Condition.
No caso do recebimento de bytes, nós não setamos o SDA como nível 1, somente baixamos o nível do SCL. Conforme código abaixo:

char readAckRcv(void) {
char state=0;
setSCLHigh();
waitFactor(1);
state=getSDAState();
setSCLLow();
waitFactor(1);
return(state);
}

Agora vamos abordar a comunicação I2C propriamente dita.
Os dois tipos de comunicação que podemos fazer são leitura randomica e escrita randomica. Na verdade há mais dois tipos que são leitura sequencial e escrita sequencial, no entanto não vamos tratar destes dois tipos aqui neste artigo.

Vamos falar inicialmente da gravação de 1 byte num endereço qualquer do 24C256.

O 24C256 é uma memória do tipo EEPROM com 256kBits ou 32kBytes. Potanto temos um endereçamento de 15Bits (2^15 = 32768 bytes).

Um outro aspecto que devemos considerar é que ao nos comunicarmos com periféricos I2C devemos saber seu "endereço" no BUS. No caso das memórias em geral elas iniciam com 0b1010 e em seguida temos os sinais dos pinos A2, A1 e A0 na sequencia, desta forma podemos usar mais de uma memória no Bus. 0b1010000[r/w], o último bit é 0 para escrita e 1 para leitura.

A comunicação na gravação é feita enviando uma sequencia de 4 bytes. Como descritos abaixo:

1.Byte = 7 bits do endereçamento do periférico mais 1 bit sinalizando leitura/gravação, neste caso gravação (0b10100000);
2.Byte = MSB do endereço de gravação na memória EEPROM;
3.Byte = LSB do endereço de gravação na memória EPPROM;
4.Byte = Byte a ser escrito na posição de memória.

Acompanhe o código abaixo para ver os quatro bytes sendo enviados, e a leitura do Ack em cada intervalo.

void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte) {
unsigned char myAck=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb <<>> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
startCondition();
if(!(myAck=writeByte(deviceAddress,0))) {
if(!(myAck=writeByte(msb,0))) {
if(!(myAck=writeByte(lsb,0))) {
if(!(myAck=writeByte(byte,0))) {
stopCondition();
waitFactor(100);
}
}
}
}
if(myAck) stopCondition();
}

Primeiro calculamos os MSB e LSB rotacionando os bits necessários, e guardando isso em variáveis de 8Bits para poderem ser usadas posteriormente no processo de gravação.
Em seguida geramos um Start Condition para iniciar transação, e enviamos nosso primeiro Byte, no Caso o conteúdo da variável deviceAddress, em seguida lemos o Ack para podermos continuar o processo, em seguida enviamos o MSB, e lemos o Ack, e enviamos o LSB na sequencia. Após tudo isso perfeitamente e o Ack afirmativo, enviamos o byte a ser gravado.
Se tudo correr bem enviamos um Stop Condition e agurdamos 100 ciclos do processador. É tempo suficiente (algo por volta de 5Ms) para que a EEPROM possa gravar o byte na memória indicada. Por fim, se houver algum problema e o Ack retornar positivo (status negativo ou "não aceito") é enviada um Stop Condition colocando Bus em stand by novamente.
Notem que no processo de gravação, usamos a função writeByte passando como parâmetro o byte a ser escrito e o indicador zero(0) sinalizando que deverá ser utilizada leitura de Ack para escrita e não leitura.

A comunicação na leitura é feita enviando uma sequencia de escrita de 3 bytes, um Start Condition, uma escrita de 1 byte e em seguida realizada a leitura. Como descrito abaixo:

1.Byte = 7 bits do endereçamento do periférico mais 1 bit sinalizando leitura/gravação, neste caso gravação (0b10100000);
2.Byte = MSB do endereço de gravação na memória EEPROM;
3.Byte = LSB do endereço de gravação na memória EPPROM;
4. **** Gerar Start Condition
5.byte = 7 bits do endereçamento do periférico mais 1 bit sinalizando leitura/gravação, neste caso leitura(0b10100001) * compara com passo 1;
Realizar a leitura do Byte (Colocar o SDA em modo Input e o Chavear o clock entre os Bits)

Eis o código:

unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress) {
unsigned char myAck=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb <<>> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
startCondition();
if(!(myAck=writeByte(deviceAddress,0))) {
if(!(myAck=writeByte(msb,0))) {
if(!(myAck=writeByte(lsb,0))) {
startCondition();
if(!(myAck=writeByte((deviceAddress|0x01),1))) {
myAck=getByte();
}
}
}
}
stopCondition();
return(myAck);
}

Basicamente esta função é identica ao processo de leitura, com exceção que no lugar do quarto byte, temos um Start Condition, e a escrita do deviceAddress com o bit 0 marcado como 1 (leitura). E obviamente após o Ack, a leitura do bit em si.

Eis o código completo dos dois arquivos... 24C256.h e 24C256.c ...

-------------- Inicio 24C256.h --------------
#ifndef _24C256_H
#define _24C256_H

#define _24C256_sda_d pd3_4
#define _24C256_sda p3_4
#define _24C256_scl_d pd3_5
#define _24C256_scl p3_5
#define waitUnit 100

// ---------------------- High Level Functions ---------------

void Init_24C256(void);
void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte);
unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress);

#endif
-------------- Fim 24C256.h --------------

-------------- Inicio 24C256.c --------------
#include "sfr_r825.h"
#include "24C256.h"

// ---------------------- Low Level Functions ---------------

void waitFactor(unsigned int factor) {
unsigned int fc=0;
factor*=waitUnit;
for(fc=0; fc}

char getSDAState(void) {
_24C256_sda_d = 0;
asm("NOP");
return(_24C256_sda);
}

char getSCLState(void) {
_24C256_scl_d = 0;
asm("NOP");
return(_24C256_scl);
}

void setSDAHigh(void) {
_24C256_sda_d = 1;
_24C256_sda = 1;
}

void setSCLHigh(void) {
_24C256_scl_d = 1;
_24C256_scl = 1;
}

void setSDALow(void) {
_24C256_sda_d = 1;
_24C256_sda = 0;
}

void setSCLLow(void) {
_24C256_scl_d = 1;
_24C256_scl = 0;
}

void startCondition(void) {
setSCLHigh();
setSDAHigh();
setSDALow();
waitFactor(2);
setSCLLow();
waitFactor(2);
}

void sendHighBit(void) {
setSDAHigh();
setSCLHigh();
waitFactor(1);
setSCLLow();
waitFactor(1);
}

void sendLowBit(void) {
setSDALow();
setSCLHigh();
waitFactor(1);
setSCLLow();
waitFactor(1);
}

char readAck(void) {
char state=0;
setSCLHigh();
waitFactor(1);
state=getSDAState();
setSCLLow();
setSDAHigh();
waitFactor(3);
return(state);
}

char readAckRcv(void) {
char state=0;
setSCLHigh();
waitFactor(1);
state=getSDAState();
setSCLLow();
waitFactor(1);
return(state);
}

void stopCondition(void) {
setSDALow();
waitFactor(1);
setSCLLow();
waitFactor(1);
setSCLHigh();
waitFactor(2);
setSDAHigh();
waitFactor(2);
}

unsigned char getByte(void) {
unsigned char byte=0;
unsigned char pos=0;
_24C256_sda_d=0;
while(pos<8) {
byte|=getSDAState();
if(pos<7) byte<<=1;
pos++;
setSCLHigh();
waitFactor(1);
setSCLLow();
waitFactor(1);
}
setSDALow();
waitFactor(1);
setSCLHigh();
waitFactor(1);
setSCLLow();
waitFactor(1);
return(byte);
}

unsigned char writeByte(unsigned char byte,unsigned char forRead) {
unsigned char rotateLeft;
unsigned char tmp;
rotateLeft = 0;
while(rotateLeft<8) {
tmp=byte;
tmp = (tmp <<>> 7;
rotateLeft++;
if(tmp) {
sendHighBit();
} else {
sendLowBit();
}
}
if(forRead) return(readAckRcv());
return(readAck());
}

// ---------------------- High Level Functions ---------------

void Init_24C256(void) {
_24C256_sda=1;
_24C256_scl=1;
_24C256_sda_d = 1;
_24C256_scl_d = 1;
_24C256_sda=1;
_24C256_scl=1;
}

void Write_24C256(unsigned char deviceAddress, unsigned int menAddress, unsigned char byte) {
unsigned char myAck=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb <<>> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
startCondition();
if(!(myAck=writeByte(deviceAddress,0))) {
if(!(myAck=writeByte(msb,0))) {
if(!(myAck=writeByte(lsb,0))) {
if(!(myAck=writeByte(byte,0))) {
stopCondition();
waitFactor(100);
}
}
}
}
if(myAck) stopCondition();
}

unsigned char Read_24C256(unsigned char deviceAddress, unsigned int menAddress) {
unsigned char myAck=0;
unsigned int tmsb,tlsb;
unsigned char msb, lsb;
tlsb = tmsb = menAddress;
tmsb = tmsb >> 8;
tlsb = (tlsb <<>> 8;
msb = (unsigned char) tmsb;
lsb = (unsigned char) tlsb;
startCondition();
if(!(myAck=writeByte(deviceAddress,0))) {
if(!(myAck=writeByte(msb,0))) {
if(!(myAck=writeByte(lsb,0))) {
startCondition();
if(!(myAck=writeByte((deviceAddress|0x01),1))) {
myAck=getByte();
}
}
}
}
stopCondition();
return(myAck);
}
-------------- Fim 24C256.c --------------

Aqui eis um link para a especificação do Barramento I2C no site da NXP (Philips).
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf

Enjoy!!!

sexta-feira, 22 de agosto de 2008

Matéria sobre IOs está finalizada!

Pessoal a matéria que eu comecei a escrever falando dos IOs no Renesas e fazendo um paralelo com os PICs está completa.

Decidi terminar a matéria sem entrar muito em detalhes profundos. Vai seguir em breve um exemplo de IOs no Renesas fazendo um BitBang para Bus I2C, mais especificamente para o 24C256 da ATMEL.

Bom é isso, segue o link para quem ainda não viu...

http://5vcc.blogspot.com/2008/07/ios-com-r8c25-e-um-breve-comparativo.html

Boa sorte e estamos por aqui se alguém quiser alguma info!!!

quarta-feira, 13 de agosto de 2008

Analizador Lógico

Pois bem pessoal, aproveitando a deixa, vou mostrar o que me tirou o sono do dia de ontem...
Depois de muito discutir e ver todo mundo falar... mas ninguém fazer, eu resolvi botar a mão na massa e fazer um analizador lógico para resolver um probleminha que ando tendo com I2C aqui.
Como não estava com paciência para fazer placa etc... usei meu kit da Mosico, gravei um 16F877 jogando pela serial o scan do port d e recebendo isso num programa em .NET que eu montei as pressas ...
Tá aí uma telinha do danado depois de uma captura.

Ainda tem alguns probleminhas para resolver, como a velocidade de captura dos samples, 20Mhz no PIC não é muita coisa quando programado em CCS C. E velocidade de transmissão / processamento no PC. Mas como gambia... quer dizer "solução técnica alternativa" funciona direitinho. A captura acima foi feita em cima de uma BUS I2C a 78.1kHz.
Em breve vou postar mais detalhes e abrir o projeto pra comunidade!!!
Enjoy!

Limpando as COMs do seu Windows

Pessoal,

Depois de um hiato de alguns dias, continuo aqui meus POSTs para ajudar a galera da eletrônica. Pois bem. Desta vez vamos falar um pouco sobre Bluetooth e como os Dongles entopem nossa máquina de portas seriais inativas e que não podem ser associadas para outras aplicações.
Isso em determinado momento pode causar alguns problemas, como por exemplo, alguns programas que não conseguem acessar portas seriais além das padrões (COM1, COM2, COM3, COM4) que eram as mais comuns nas versões antigas de muitos sistemas.
Recentemente eu tive um problema parecido e tiver que descobrir como fazer uma limpeza.
Eu precisei instalar um adaptador USB-Serial e mapear o mesmo como COM3 ou COM4, no entanto o meu windows não permitia, alegando que a porta já estava sendo usada por outra aplicação.
Daí descobri que cada vez que colocamos um Dongle BLuetooth novo no nosso Windows, ele associa uma nova porta para ele. E quando você tira ele, essa porta não é liberada, causando assim um acumulo gigantesco de portas inativas e inacessíveis. Para vocês terem uma idéia a porta mais baixa disponível era COM48 no meu computador e como não usava o USB-Serial há fazia um tempinho, as portas COM3 e COM4 que eu geralmente associo para o conversor, foi ocupada por alguma antena, onde o Windows escolheu a porta mais baixa disponível e capturou ela.
Pois bem o procedimento para resolver o problema é:

  1. Chame o regedit através do menu iniciar (clique em menu iniciar e escreva regedit e se for Windows Vista, ou clique em menu iniciar -> executar e escreva regedit se for Windows XP ou anterior)
  2. No regedit vá em HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter.
  3. Clique com o botão direito dobre a chave COM Name Arbiter e irá aparecer uma lista de bytes contendo o mapeamento de todas as suas COMs.
  4. Apague o que está nesta lista, e feche a janela de edição.
  5. Feche o regedit.

Até este ponto ok. Ele libera todas os portas para você criar novas associações, no entanto os conversores USB-Serial não funcionavam. Conclusão: Desinstale todos os adaptadores sem mandar apagar os drivers que já estão na máquina. Tire o adaptador fisicamente, espere pelo sinal de retirada de hardware do Windows e recoloque o mesmo. O Windows vai reinstalar os drivers do seu adaptador, em seguida é só associar a porta que você quer e ser feliz!

Boa sorte a todos...

quinta-feira, 7 de agosto de 2008

10 de Setembro - Destruição da Terra?



Após alguns dias sem conseguir postar nada no Blog, eu retorno e para dar uma notícia nada trivial... a destruição da terra... bom... pelo menos para os que creêm que é possível, explico a seguir;

Se você é uma das pessoas que acreditam que o Acelerador de Partículas do CERN o Large Hadron Collider pode destruir o planeta por causa de uma reação em cadeia no ato da criação de partículas de antimatéria, prepare-se, dia 10 de setembro ele irá entrar em funcionamento.

E para aqueles que ainda não entenderam muito bem o que é tudo isso... aí vai um RapZinho para sacar o que os caras do CERN estão fazendo por lá!!! Enjoy!


CERN Rap from Will Barras on Vimeo.

Origem da Notícia: http://www.popsci.com/scitech/article/2008-08/and-we%E2%80%99re