collapse

* Links de Robótica

* Posts Recentes

Feira de electricidade e eletrónica por edeweld
[Hoje às 02:02]


Recomendação de um opamp para um DAC r2r por jm_araujo
[Ontem às 10:48]


RN42 e TP-Link MR3020 por doiga
[22 de Novembro de 2017, 19:22]


Ajuda Projecto IR / RF por senso
[22 de Novembro de 2017, 13:15]


Ideias para construir um quadrúpede simples por dropes
[21 de Novembro de 2017, 22:43]


Ajuda com TRIAC por senso
[17 de Novembro de 2017, 18:00]


TV LG White Screen por almamater
[15 de Novembro de 2017, 08:37]


Pergunta sobre prototipagem ( Pesquisa ) por luisjustin
[14 de Novembro de 2017, 23:22]


Medir Agua que está no Poço por Njay
[14 de Novembro de 2017, 13:28]


Amplificador audio por beirao
[12 de Novembro de 2017, 23:43]

Autor Tópico: Mini "Pseudo" Osciloscópio  (Lida 4682 vezes)

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

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
Mini "Pseudo" Osciloscópio
« em: 10 de Julho de 2014, 21:38 »
Boas

Já por várias vezes que precisei de um osciloscópio para coisas básicas, mas nunca comprei nenhum por ser uma ferramenta cara e que iria ficar encostado por ser algo que raramente uso...

Quando não se tem o dinheiro improvisa-se, decidi fazer um brinquedo com componentes que por aqui tenho e ir evoluindo a coisa até se tornar algo minimamente usável.

Material que estou a usar:
  • Atmega328 a 20mhz
  • TFT 1.8' com o cotrolador ST7735 (SPI) com um 74HC4050 como level shifter

O plano é começar com o avr, com que estou mais familiarizado, com o ADC interno, de seguida juntar um ADC externo que já tenho montado na breadboard ao lado, é um TLC5510, 20MSps, 8 bit, output paralelo, já tenho a parte analógica a funcionar, mas vai ficar encostado para já até ter tudo a funcionar com o ADC interno, assim que tiver o atmega a funcionar com o adc externo a ideia é portar o código para um LPC1313 (cortex m3) e por fim deitar as mãos a um LPC4370 que tem um ADC interno de 80MSps

Por agora, comecei por escrever o código para o SPI e o driver para o TFT, por fim o código do ADC, neste momento já consigo mostrar uma onda no ecrã, em seguida vou tentar fazer um trigger simples e é aqui que preciso de ajuda, ideias precisam-se  ;D

Código fonte:
Código: [Seleccione]
#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "ST7735.h"
#include "ADC.h"

uint8_t amostra[160], amostraAntiga[160];

int main(void)
{

ST7735_init();
ADC_init();

while(1)
{
for (int i = 0; i < 160; i++)
amostraAntiga[i] = amostra[i];

for (int i = 0; i < 160; i++)
amostra[i] = ADC_read(0)/2;

for (int i = 0; i < 160; i++)
{
ST7735_draw_pixel(amostraAntiga[i], i, COLOR_BLACK);
ST7735_draw_pixel(amostra[i], i, COLOR_GREEN);
}
}
}

O código é bastante simples, são lidas 160 amostras o mais rápido possível (comprimento em pixeis do ecrã) e os pixeis são escritos no lcd um a um, para apagar o conteúdo do ecrã o mais rápido possível no inicio do loop copio o array com as amostras lidas para outro antes de ser renovado e antes de um pixel ser "escrito" o pixel na mesma posição horizontal é apagado

O ADC está a funcionar com um clock de 1,25Mhz (20Mhz/16), o máximo recomendado penso que seja 1Mhz, mas não é critico neste ponto...

Em funcionamento a mostrar uma onda quadrada de ~450Hz do PWM de um atmega8:



Projecto do atmel studio 6.1 em anexo

O que acham?

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Mini "Pseudo" Osciloscópio
« Responder #1 em: 10 de Julho de 2014, 22:06 »
Conheces o XprotoLab?
Se não, pesquisa, tem código disponivel e faz exactamente o que queres fazer.
O trigger é onde está a magia de um osciloscópio, e por software não será de todo super fiavel, convinha teres um comparador externo.
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
Re: Mini "Pseudo" Osciloscópio
« Responder #2 em: 10 de Julho de 2014, 22:14 »
sim conheço o xprotolab, tive a olhar para o esquemático e parece que o trigger é feito por software, vou dar uma vista de olhos no código...

de qualquer forma devo poder usar o comparador interno do atmega...
« Última modificação: 10 de Julho de 2014, 22:16 por CBX »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Mini "Pseudo" Osciloscópio
« Responder #3 em: 10 de Julho de 2014, 22:41 »
Se estiver depois do condicionamento de sinal, possivelmente, depois precisas é de um DAC para mudar o ponto de comparação.
O xprotolab é por software, referi porque sempre terás código para tirar umas ideias.
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
Re: Mini "Pseudo" Osciloscópio
« Responder #4 em: 11 de Julho de 2014, 17:46 »
fui ler o código do xprotolab e não consegui perceber nada, o código é extremamente difícil de ler mesmo com os comentários, fui então investigar e encontrei esta explicação bastante boa: http://www.radio-electronics.com/info/t_and_m/oscilloscope/oscilloscope-trigger.php

após alguma diarreia cerebral temos um trigger funcional, acrescentei o seguinte código ao loop principal:

Código: [Seleccione]
max = 0;
min = amostra[0];

for (int i = 0; i < 160; i++) // encontrar o valor minimo e maximo das amostras
{
if (amostra[i] > max)
max = amostra[i];

if (amostra[i] < min)
min = amostra[i];
}

if (max != min)
trigger = (((max - min) / 2) + min); // o valor do trigger será o meio da onda capturada
else
trigger = max;

flag = 1;
contador = 0;
amostra2Antiga = 0;
passo = 0;

for (int i = 0; i < 10000; i++) // loop até que o inicio da onda capturada se repita
{
amostra2 = ADC_read(0)/2;

if ((passo == 0) && (amostra2 > trigger) && (amostra2Antiga < amostra2)) // encontrar o inicio do periodo
passo = 1;

if ((passo == 1) && (amostra2 < trigger) && (amostra2Antiga < amostra2)) // encontrar o "rising edge"
passo = 2;

if ((passo == 1) && (amostra2 > trigger) && (amostra2Antiga < amostra2)) // quando o inicio do proximo periodo for encontrado
break;         // iniciar novamente a amostragem
}

basicamente calcula o meio da onda capturada inicialmente e um novo loop vai lendo amostras até encontrar o novo período.

o próximo passo é adicionar dois botões para aumentar\diminuir o delay entre a captura das amostras

em que biblioteca do avrgcc é que estão as variáveis do tipo booleano?
« Última modificação: 11 de Julho de 2014, 17:49 por CBX »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Mini "Pseudo" Osciloscópio
« Responder #5 em: 11 de Julho de 2014, 17:55 »
Penso que nativamente não tem, faz uma struct e usas um byte para meter 8 bools, a nivel de velocidade de código vai dar exactamente ao mesmo.
Avr fanboy

Offline dropes

  • Mini Robot
  • *
  • Mensagens: 1.930
Re: Mini "Pseudo" Osciloscópio
« Responder #6 em: 07 de Outubro de 2014, 11:17 »
Evita usar divisões ou multiplicações, neste caso shift right funcionaria para as divisões por 2 já que os números são inteiros.
Recomendaria assembler para alguns procedimentos, mas isso já é um pouco distante...

Offline LuísR.A.

  • Mini Robot
  • *
  • Mensagens: 1.223
    • Clube de Robotica
Re: Mini "Pseudo" Osciloscópio
« Responder #7 em: 07 de Outubro de 2014, 12:18 »
Vi fazerem um osciloscopio, obviamente tambem assim  muito fraco com um MSP430 mais fraco que o atmega328 e não foi preciso assembly... mas foi em acesso directo de registos
Tiva MCU é que é.

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

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Mini "Pseudo" Osciloscópio
« Responder #8 em: 07 de Outubro de 2014, 12:18 »
typedef unsigned char bool;

Quanto às divisões/multiplicações por uma constante, quase de certeza que o GCC a compilar com optimizações ligadas reconhece a operação por uma potência de 2 e optimiza para um shift. Mas pode-se olhar para o .LST (que tem o assembly) e confirmar. Aí até poderás perceber se o código está a sair mesmo optimizado ou se está a haver alguma "promoção" a int aí pelo meio levando a código maior.

p.s. Aliás, estás a usar um contador do tipo int no for; o tipo int são 16 bits, logo o teu ciclo de aquisição for é bastante lento face ao que podia ser, mas por outro lado estás a usar uma função para a leitura do ADC e isso deita logo por terra qualquer desejo de performance (a não ser que a função esteja implementada com performance em mente, do género ser uma macro etc).
« Última modificação: 07 de Outubro de 2014, 12:22 por Njay »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Mini "Pseudo" Osciloscópio
« Responder #9 em: 07 de Outubro de 2014, 13:17 »
Isso devia correr praticamente tudo na interrupção do ADC, mas o ADC do atmega tambem é horrivelmente lento..
Avr fanboy

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
Re: Mini "Pseudo" Osciloscópio
« Responder #10 em: 07 de Outubro de 2014, 17:20 »
Antes de mais isto é um "proof of concept", não tem em mente performance, também não conseguia retirar muita do ADC interno do atmega...

Tenho duas opções, utilizar um ADC externo que aqui tenho de 20Msps (estaria limitado a 10) ou saltar directamente para o LCP4370 que tem um ADC interno de 80Msps, que para além de ser um cortex m4 tem mais dois cores cortex m0 em que um deles poderia estar encarregue do lcd e o outro dos inputs por exemplo.

Evita usar divisões ou multiplicações, neste caso shift right funcionaria para as divisões por 2 já que os números são inteiros.
Recomendaria assembler para alguns procedimentos, mas isso já é um pouco distante...

O meu assembly é muito mau e penso que o incremento de performance não seria assim tão grande se o compilador estiver a fazer o seu trabalho como deve ser

typedef unsigned char bool;

Quanto às divisões/multiplicações por uma constante, quase de certeza que o GCC a compilar com optimizações ligadas reconhece a operação por uma potência de 2 e optimiza para um shift. Mas pode-se olhar para o .LST (que tem o assembly) e confirmar. Aí até poderás perceber se o código está a sair mesmo optimizado ou se está a haver alguma "promoção" a int aí pelo meio levando a código maior.

p.s. Aliás, estás a usar um contador do tipo int no for; o tipo int são 16 bits, logo o teu ciclo de aquisição for é bastante lento face ao que podia ser, mas por outro lado estás a usar uma função para a leitura do ADC e isso deita logo por terra qualquer desejo de performance (a não ser que a função esteja implementada com performance em mente, do género ser uma macro etc).

Não tenho nenhum ficheiro .LST, o mais parecido é um .LSS e parece que está a optimizar, um excerto:

Código: [Seleccione]
for (uint8_t i = 0; i < 160; i++)
{
amostra[i] /= 2;
 1ce: f6 01        movw r30, r12
 1d0: 80 81        ld r24, Z
 1d2: 86 95        lsr r24
 1d4: 81 93        st Z+, r24
 1d6: fc 83        std Y+4, r31 ; 0x04
 1d8: eb 83        std Y+3, r30 ; 0x03
 1da: 48 01        movw r8, r16
 1dc: 8a 18        sub r8, r10
 1de: 9b 08        sbc r9, r11

Entretanto substituí todos os int por uint8_t, expecto uma das variáveis que tem de ser de 16bits

Isso devia correr praticamente tudo na interrupção do ADC, mas o ADC do atmega tambem é horrivelmente lento..

Podes elaborar?  :P

Obrigado pelas sugestões

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Mini "Pseudo" Osciloscópio
« Responder #11 em: 07 de Outubro de 2014, 17:24 »
Sim, nessa gama de preço era preferível uma placa de prototipagem PSoC4, sempre tem um ADC de 1Msps e ampops e interface USB, e ainda DACs e comparadores de tensão + alguma lógica programável que deve ser fixe para implementar o trigger em hw.

Mas tamos a falar dum AVR :) . Mostra lá a tua função de leitura do ADC, CBX. 1.25MHz de clock no ADC é na boa, o que se perde são bits de resolução, mas para esta aplicação não é critico perder 2 ou 3 bits.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.141
    • Tróniquices
Re: Mini "Pseudo" Osciloscópio
« Responder #12 em: 07 de Outubro de 2014, 17:32 »
Tens espaço para código, o mais rápido é desdobrar o ciclo

amostra[0] = ADC_read(0);
amostra[1] = ADC_read(0);
amostra[2] = ADC_read(0);
....
amostra[159] = ADC_read(0);

Isto quando tiveres um ADC externo, o do mega é lento portanto é quase irrelevante.

O código assembly que aí tens já é depois da tua alteração para uint8_t, portanto não vês a diferença.
Mas que ciclo é esse do excerto de assembly? Não vejo esse código no que já colocaste aqui.
« Última modificação: 07 de Outubro de 2014, 17:46 por Njay »

Offline CBX

  • Mini Robot
  • *
  • Mensagens: 1.315
Re: Mini "Pseudo" Osciloscópio
« Responder #13 em: 07 de Outubro de 2014, 17:51 »
o que eu queria destacar era a divisão estar a ser optimizada.

o adc já está a funcionar a 1,25MHZ (20Mhz / prescaler de 16)

o código está todo no primeiro post, mas fica apenas o do ADC:

Código: [Seleccione]
#include <avr/io.h>

void ADC_init()
{
ADMUX |= (1<<REFS0) | (1<<ADLAR); // AVCC as reference voltage, value left adjusted; comment ADLAR for full 10 bit
ADCSRA |= (1<<ADPS2) | (1<<ADEN) | (1<<ADSC); // prescaler set to 16, enable ADC, free-running mode, start conversion
}

uint8_t ADC_read(uint8_t c) // should be uint16_t if working with 10 bit values
{
ADMUX &= 0xF0; // clear the older channel
ADMUX |= c; // select the channel
ADCSRA |= (1<<ADSC); // start conversion
while(ADCSRA & (1<<ADSC)); // wait until ADC conversion is completed
return ADCH; // 8 bit only
//return ADCW; // 10 bit value
}

Já agora aproveito para perguntar, o ADC que aqui tenho é um TLC5510 e pelo que percebi da datasheet tenho de ler os outputs no falling edge do sinal de clock, se usar o PB0 como clock output existe algum registo que me diga quando devo ler o porto completo?

obrigado  ;)
« Última modificação: 07 de Outubro de 2014, 17:54 por CBX »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Mini "Pseudo" Osciloscópio
« Responder #14 em: 07 de Outubro de 2014, 18:03 »
Usas interrupção de conversão completada e metes o sample novo para um array/buffer e siga.
Comparações lógicas e mais umas coisas no gcc são promovidos a 16bits para o caso de haver carry, nem sempre é simples de seguir o porquê de o compilador o fazer, mas tipicamente tentar ser mais esperto que o compilador corre mal, até porque já dizia o Knutt algo sobre optimização prematura..

Se isso é SPI tens os CPOL e outro registo, basicamente existem 4 modos de SPI, está na datasheet como configurar isso.
Avr fanboy