Hi all,
Here I am giving a C-language code to test the V to F function using NCO (Numerically Controlled Oscillator) of PIC16F1718. It gives me a response time of 30uS for a step voltage input (0 to 5V). Actually I need much faster response about 10uS.
At first, when you think about response time do not forget about analog filter delay, accuracy(noise) of ADC and native responsiveness of output signal of relatively low frequency.
PIC16F1718 datasheet (
http://ww1.microchip.com/downloads/en/DeviceDoc/40001740A.pdf)
page 415:
ADC clock period (Tad): minimum 1 us
Conversion time: 11*Tad
Acquisition time: typ.: 5 us (see page 247: 21.4 ADC Acquisition Requirements to refine your values)
Note: ADIF is 1 Tcy earlier than DONE
So practical value for ADC conversion time without trade-offs is about 16-17 us (AD133+AD131+1Tcy+InterruptLatency). (see figures: 21-2, 34-13, 34-14)
1) You did not show in code the selection of clock source for ADC.
2) Acquisition time must be added before _each_ conversion. Not only at init stage. The purpose of that delay is to give enough time for "holding" capacitor to recharge to actual measured voltage through given serial resistance of voltage source.
3) I'm not sure about XC8 compiler if it adds run-time checks for indexes. Then 16(10)-bit index to 44 element array (frq_tbl[adc_val]) is not good, nor working (just draft dummy?).
I suggest to use Fosc-based ADC clock (set Tad=1us), set Autoconversion trigger (See 21.2.5) to automatically set GO each say 17 us (refine your Tacq) through CCP and use ADC interrupt to handle new measured value.
Note: ADRES register pair will be updated by ADC module only at very end of next conversion.
I hope that it is not coincidence that you correctly update NCO1INCL last (20.1.4).
If you want to further decrease response time (ADC conversion period plus data conditioning) then I'd try to adjust NCOx_clk (Fosc?) and ADRES justification to omit table conversion - to just copy ADRES to NCO1INCH:NCO1INCL. As a variant - simple shifts could be faster than two table reads. Another variant - use CCP instead of NCO with its fixed 20-bit period. More work though and use of NCO is much nicer.
Posted on: October 10, 2015, 10:42:03 22:42 - Automerged
But You may be able to simplify the address calculation, if You split Your table of frequencies
into a high- and a low-table. That way the processor is operating on 8 bit data only.
const unsigned char frq_tbl_lo[]={ 131 & 0xff, 136 & 0xff, 141 & 0xff, 146 & 0xff, ...
const unsigned char frq_tbl_hi[]={ (131 << 8) & 0xff, (136 << 8) & 0xff, (141 << 8) & 0xff, (146 << 8) & 0xff, ...
It needs tests to compare. For example for given processor the following code could be more effective without table split.
movlw LOW conversion_table
movwf FSR1L
movlw HIGH conversion_table
movwf FSR1H
lslf ADRESL, W ;double index value
rlf ADRESH, F
addwf FSR1L, F ;add it to FSR
movf ADRESH, W
addwfc FSR1H, F
moviw FSR1++
movwf freq_nco_inc_hi
moviw FSR1++
movwf freq_nco_inc_lo
Though I know nothing about xc8 capabilities, it is quite usual operation so they could optimize 16-bit tables well. I personally prefer manual asm optimization in case of strict necessity.
Posted on: October 10, 2015, 11:23:14 23:23 - Automerged
If FSR1 is not used elsewhere then following "swap" will reduce delay of updating NCO1INC.
ADC_INT_handler:
lslf ADRESL, W ;double index value
rlf ADRESH, F
addwf FSR1L, F ;add it to FSR
movf ADRESH, W
addwfc FSR1H, F
moviw FSR1++
banksel NCO1INCH
movwf NCO1INCH ;update NCO increment step
moviw FSR1++
movwf NCO1INCL
movlw LOW conversion_table ;prepare table address for next conversion
movwf FSR1L
movlw HIGH conversion_table
movwf FSR1H
banksel ADRESL ;if there is no banksel commands outside this interrupt handler then this banksel can be placed here