Sari la conținut
ELFORUM - Forumul electronistilor

Viteza maxima de achizitie ADC PIC18F2550,PIC18F4550


gsabac

Postări Recomandate

In documentatii se indica o viteza de achizitie in jur de 40KHz. Eu nu am reusit in

simularea virtuala decit 16KHz, probabil cu setarile implicite si cu urmatorul cod.

main:
CMCON = CMCON or 7 ' Disable comparators
TRISA=0xFF ' PORTA is input
TRISB=0 ' PORTB is output
TRISC=0 ' PORTC is output
HID_Enable(@readbuff,@adread) ' Enable HID communication
while TRUE ' USB servicing is done inside the while loop
USB_Polling_Proc() ' Call this routine periodically
for i=0 to
adread=(ADC_Read(0) / 4) ' maximum 256 din 1024 la 10 biti. Si memoria este de 8 biti
next i
adread[0]=70
HID_Write(@adread[0],64)
Delay_ms(5)
wend

end.

Cu ajutorul sau doresc sa proiectez un osciloscop USB, deocamdata pentru 10-20KHz, dar asa cum

este poate merge doar la 5KHz datorita ratei mici de esantionare pe care am realizat-o, 16KHz.

Asa arata imaginea pentru 2KHz la intrare si se vad pe ea cite 8 puncte care corespund esantionarii pe o perioada.

post-238209-0-10761800-1495891975_thumb.jpg

Stie cineva mai avansat decit mine, cum se poate seta ADC-ul pentru rata maxima de asantionare.

Precizez ca acum uC-ul este la 48MHz.

 

@gsabac

Editat de gsabac
Link spre comentariu

Nu ma pricep cine stie ce la PICe dar cand m-am jucat cu ADC-ul la 887, in mikroC, am observat ca functia lor de citire ADC era mai lenta fata de functia facuta de mine. Functia ADC_Read este fcuta de dvs.? Intreb pentru ca nu vad nimic despre setarea registrului ADCON2.

Link spre comentariu

Functia ADC_Read(0) este Mikroe pentru mikroBasic intrarea "0" . Buna idee, am sa ma uit in

fisierul de definitie al ADC-ului.

Edit.

M-am uitat si sunt 25 de linii in fisierul asm.

 

@gsabac

Editat de gsabac
Link spre comentariu

Nu cred ca progamul HEX este cheia problemei, sunt ceva setari ale ADC-ului pe care nu le stiu.

Desi am incercat multe variante, nici una nu merge. Fie sunt erori la compilarea Mikroe, fie erori

la executie in Proteus. Unele chiar blocheaza conexiunea USB-HID.

 

@gsabac

Editat de gsabac
Link spre comentariu

Intr-un exemplu de calcul din data-sheet (pagina 270), timpul de achizitie (incarcarea condensatorului sample&hold) le iese 2,45 us. Adaugand si timpul necesar conversiei, se mai lungeste putin, dar ar trebui sa dea mai bine decat ce ai tu.

In afara de diversele setari pentru modulul ADC (ceas, timp de achizitie... - vezi data-sheet-ul pentru detalii), eu as implementa propria functie "read_adc".

Tinand cont ca nu te intereseaza decat cei mai semnificativi 8 biti, poti scrie o functie care sa citeasca si sa returneze numai ADRESH. In felul asta economisesti doua conversii - doi registri in 10 biti, 10 biti in 8 biti.


Un exemplu de functie de citire a unui ADC (nu e optima, nu m-a interesat viteza) am pus intr-un proiect "de pornire" pentru un VA-metru.

unsigned long adcRead(unsigned char adcCh)
{
  ADCON0bits.CHS = adcCh; //select the channel
  ADCON0bits.ADON = 1; //activate the ADC
  __delay_ms(1); //wait the acquisition time
  ADCON0bits.GO = 1; //start the conversion
  do{ //wait the conversion to complete
    NOP();
  }while(ADCON0bits.GO);
  
  ADCON0bits.ADON = 0;  //deactivate the ADC
  
  return(ADRESH * 256 + ADRESL); //return the ADC value
}

Tu trebuie sa optimizezi delay-ul de dupa activarea modulului si sa renunti la conversia rezultatului.


Daca ma gandesc mai bine, as face intreaga achizitie intr-o astfel de functie. Ai economisi pentru fiecare sample apelul functiei si return-ul.

 

PS: for-ul tau nu se termina:

 for i=0 to
      adread[i]=(ADC_Read(0) / 4)                   ' maximum 256 din 1024 la 10 biti. Si memoria este de 8 biti
    next i
Link spre comentariu

Am studiat inainte de topic adresele propuse si acum chiar am incercat sa le implementez

si toate variantele dau erori la compilare, nu sunt coduri compatibile mikroe.

Interesanta idea cu renuntarea la 2 biti, cu scuze va anunt ca eu chiar doresc +/- 512 esantioane pentru osciloscop

si voi trece la 10 biti, dupa probele de acum, care sunt aproape reusite.

 

@gsabac

Editat de gsabac
Link spre comentariu

nu sunt coduri compatibile mikroe.

A, clar, al meu e C (compilatorul e xc8 de la uChip).

OK, daca-ti trebuie toti bitii nu ramane decat sa muti toata achizitia intr-o functie dedicata si sa faci "de mana" toate operatiile.

Editat de Liviu M
Link spre comentariu

Asa este cu for-ul, eroare de editare, era 64 caci probele le fac cu 64 de esantioane pentru inceput.

 

Codul complet din ASM este mai jos. HID_Read_Write_Polling.mbas provine de la clonarea

programului initial pe care l-am modificat.

_main:

;HID_Read_Write_Polling.mbas,15 :: main:
;HID_Read_Write_Polling.mbas,18 :: CMCON = CMCON or 7 ' Disable comparators
MOVLW 7
IORWF CMCON+0, 1
;HID_Read_Write_Polling.mbas,19 :: TRISA=0xFF ' PORTA is input
MOVLW 255
MOVWF TRISA+0
;HID_Read_Write_Polling.mbas,20 :: TRISB=0 ' PORTB is output
CLRF TRISB+0
;HID_Read_Write_Polling.mbas,21 :: TRISC=0 ' PORTC is output
CLRF TRISC+0
;HID_Read_Write_Polling.mbas,22 :: HID_Enable(@readbuff,@adread) ' Enable HID communication
MOVLW _readbuff+0
MOVWF FARG_HID_Enable_readbuff+0
MOVLW hi_addr(_readbuff+0)
MOVWF FARG_HID_Enable_readbuff+1
MOVLW _adread+0
MOVWF FARG_HID_Enable_writebuff+0
MOVLW hi_addr(_adread+0)
MOVWF FARG_HID_Enable_writebuff+1
CALL _HID_Enable+0, 0
;HID_Read_Write_Polling.mbas,23 :: while TRUE ' USB servicing is done inside the while loop
L__main2:
;HID_Read_Write_Polling.mbas,24 :: USB_Polling_Proc() ' Call this routine periodically
CALL _USB_Polling_Proc+0, 0
;HID_Read_Write_Polling.mbas,25 :: for i=0 to 64
CLRF _i+0
CLRF _i+1
L__main7:
;HID_Read_Write_Polling.mbas,26 :: adread = (ADC_Read(0) / 4) ' maximum 256 din 1024 la 10 biti. Si memoria este de 8 biti
MOVLW _adread+0
ADDWF _i+0, 0
MOVWF FLOC__main+0
MOVLW hi_addr(_adread+0)
ADDWFC _i+1, 0
MOVWF FLOC__main+1
CLRF FARG_ADC_Read_channel+0
CALL _ADC_Read+0, 0
MOVF R0, 0
MOVWF R2
MOVF R1, 0
MOVWF R3
RRCF R3, 1
RRCF R2, 1
BCF R3, 7
RRCF R3, 1
RRCF R2, 1
BCF R3, 7
MOVFF FLOC__main+0, FSR1
MOVFF FLOC__main+1, FSR1H
MOVF R2, 0
MOVWF POSTINC1+0
;HID_Read_Write_Polling.mbas,27 :: next i
MOVLW 0
XORWF _i+1, 0
BTFSS STATUS+0, 2
GOTO L__main13
MOVLW 64
XORWF _i+0, 0
L__main13:
BTFSC STATUS+0, 2
GOTO L__main10
INFSNZ _i+0, 1
INCF _i+1, 1
GOTO L__main7
L__main10:
;HID_Read_Write_Polling.mbas,28 :: adread[0]=70
MOVLW 70
MOVWF _adread+0
;HID_Read_Write_Polling.mbas,29 :: HID_Write(@adread[0],64)
MOVLW _adread+0
MOVWF FARG_HID_Write_writebuff+0
MOVLW hi_addr(_adread+0)
MOVWF FARG_HID_Write_writebuff+1
MOVLW 64
MOVWF FARG_HID_Write_len+0
CALL _HID_Write+0, 0
;HID_Read_Write_Polling.mbas,30 :: Delay_ms(5)
MOVLW 78
MOVWF R12, 0
MOVLW 235
MOVWF R13, 0
L__main11:
DECFSZ R13, 1, 1
BRA L__main11
DECFSZ R12, 1, 1
BRA L__main11
;HID_Read_Write_Polling.mbas,31 :: wend
GOTO L__main2
L_end_main:
GOTO $+0

; end of _main

 

De fapt trebuie o crestere a vitezei de 3-4ori pentru ca in final sa obtin o curba vizualizata acceptabil, la 20KHz pe intrare.

 

@gsabac

Editat de gsabac
Link spre comentariu

... e un motiv pentru care cei care fac (comercial sau home-made) osciloscoape DSO cam evită ADC-urile integrate în microcontrollere...sunt pur şi simplu prea lente! :)
dar dacă e vorba de "hai să văd cum merge"... :)

Link spre comentariu

Asa este, vreau sa vad aplicatia cu maximum din ce poate.

Vreau sa cresc acesti mini 16K esantioane pe secunda la normalul de 50K.

Stiu teoria si am soft implementat care realizeaza o vizualizare de buna calitatate chiar la 0,95 din

frecventa Nyquist. Daca realizez o esantionare la 50K, pot realiza osciloscopul la peste 20K, cu acest uC.

Desigur sunt si modele de viteza mai mare din seria PIC18xxxxx, urmeaza sa le incerc capabilitatile.

 

@gsabac

Link spre comentariu

Viteza nu-i totul :)

La pagina 273 din data-sheet e un tabel cu configurarea ceasului de esantionare in functie de frecventa de lucru. Cu cat frecventa de lucru e mai mare, cu atat frecventa de esantionare e generata folosind un divizor mai "tare".

Editat de Liviu M
Link spre comentariu

Un sfat: folositi ADC_get_sample in loc de ADC_read. Ultima face initializarea ADC la fiecare chemare a functiei. Mai scutiti ceva cicluri de program.

 

ADC_read are acelasi comportament indiferent de C, Pascal sau Basic.

 

ADC_read : Initializes PIC’s internal ADC module to work with RC clock. Clock determines the time period necessary for performing AD conversion (min 12TAD)

 

ADC_get_sample : The function aquires analog value from the specified channel.

ADC_init trebuie chemata in rutina de initializare a PIC-ului.

Editat de thunderer
Link spre comentariu

Multumesc, am vazut capitolul din documentatie. Nimic din ce este acolo nu se regaseste in ASM.

O constatare de confirmare este ca si prin simularea de la 4MHz la 48MHz, frecventa de esantionare ramine constanta,

datorita automatismului intern.

Am remarcat ca si la frecvente peste 10KHz virfurile de esantionare nu scad ca amplitudine,

deci esantioanele convertorului ADC sunt corecte, doar frecventa este aceea ce trebuie crescuta.

Nu am acces decit la codul mikroC sau mikroBasic pentru cresterea vitezei.

@thunderer, am incercat si compilatorul spune ca nu este declarata, desi exista ca functie in descrierea ADC la librarie.

Oare se poate adauga referinta in ASM ?

 

 

Editare ulterioara si multumesc.

Comanda merge bine, dar are urmatoarea forma: ADC_get_sample(0)

 

@gsabac

Editat de gsabac
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări