PDA

View Full Version : how do I speed up an existing pic18f2525 program ?



J_norrie
- 1st November 2010, 15:06
Hi there, I am trying to get my existing program that outputs 2-3 readings per second of serial data at 19200 at an internal clock frequency of 8Mhz. If I increase the clock frequency to 25Mhz by fitting an external HS crystal, I dont seem to get many more readings per second. PS I changed the Oscillator to HS in the INC file
Here is my code can anyone advise on what is wrong.

thanks again in advance John



' file : RS232CW.bas
' author : John Norrie
' date : 26/10/10
' purpose : Seariak output of load and battery condition
' includes : none
' notes : 10.00 te weight Read 16 bit ADC, convert to actual load value,
' :
' inverted 19200 baud value is 16416 used direct wire no 232 driver chip
' at pic end. AD7705 gain set to 4,unipolar 20hz cal test 178k//702R = 1mV/V or kg
' pic pin 18 RX to 9 way 'D' pin 2 crossed at rx end
' pic pin 17 TX to 9 way 'D' pin 3 crossed at rx end
' AD627 gain resistor 909R 0.1 % = gain of approx 200
' Bridge output mV/V for 10.00 te Cal = 0.681mV/V = te
' Bridge supply 2.5VDC REF03
' battery low set at 4.0vdc for 6.0v (4xC type bats) in via 2 x 5M5 resistor potential divider
' compiler : PICBasic Pro Compiler Ver 2.50A




PAUSE 1000 ' Allow power to stabilize on power-up

' Variable definition
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
DEFINE OSC 25
OSCTUNE = %11111100 ' external primary osc block
'DEFINE LOADER_USED 1 ' Comment out if not using boot-loader
INCLUDE "modedefs.bas"

INTCON2.7 = 0 'enable weak pull-ups on PORTB
output portc.4 ' set pin to output operates cal relay
'AIN Channel setup
DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 5 ' Set clock source (rc = 3)
DEFINE ADC_SAMPLEUS 5000
ADCON1 = %00001101 ' Set PORTA analog and select chs
ADCON2 = %10111110 ' Set PORTA analog and right justify res
ADCON0 = %00000001 ' Set enable analog
'AD7705 setup

output portb.7 'adc Clock pin
output portA.5 'AD7705 Data in pin
input portA.4 ' AD7705 Data out pin
input portA.3 'AD7705 Ready pin
input portA.0 ' Battery voltage input
input portA.1 ' Overload setting voltage input
symbol SCK=PORTB.7 'Clock pin
Symbol SI=PORTA.5 ' AD7705 Data in pin
Symbol SO=PORTA.4' AD7705 Data out pin
Symbol ADCready = PortA.3 'AD7705 Ready pin
'Symbol CS = PORTA.2'AD7705 Chip Select pin
symbol CalOut=PORTc.4


'AD7705 variables
adcSend var Byte 'byte sent to communication register of AD7705
adcrec var Byte 'byte received from AD7705:only for communication register, set-up register and clock register (8 bit registers)
ad1 var Word 'ad converter value read from AD7705
'ad2 var Word 'ad converter value read from AD7705
' ADC variables
Volt1 var word
VoltsA var word
Voltx var word
Total1 var word
i var byte
pass var byte
MaxVal var byte
MinVal var byte
Load var word
ADCvalue var word
gtare var byte
counts var byte
ScaleBits con 4096 '12 bit
z VAR Byte
c VAR Byte
B0 var byte
B1 VAR BYTE
B2 VAR word
d0 VAR BYTE
d1 VAR BYTE
d2 VAR BYTE
d3 VAR BYTE
p0 VAR BYTE
p1 VAR BYTE
p2 VAR BYTE
p3 VAR BYTE
t0 VAR BYTE
t1 VAR BYTE
t2 VAR BYTE
t3 VAR BYTE

x VAR Byte
p VAR Byte
a VAR Byte
b VAR Byte
v VAR Byte
tm var word
' Define keypad program variables
col var byte ' Keypad column
row var byte ' Keypad row
key var byte ' Key value
press var byte
db var byte
Total VAR WORD
totaly var word
Value VAR WORD
Value1 VAR WORD
Tare VAR WORD
TXBat var word
TXBat1 var word
RXBat var byte
Loadx var word
Loady var word
Range var word
NewVal var word

Calval var word
Cal1 var byte
peak var Word
peak1 var byte
peak2 var byte
load1 var byte
load2 var byte
CX var byte
DAout var word
cal1 = 100
B0 = 0
B2 = 0
tare = 0
Range = 2000
Calval = 850
volt1 = 0
peak = 0
CX = 1
calout = 0
key = 20
counts = 0
'EEPROMDATA:
'write 1,Cal1
'write 4,Calval.byte0 :write 5,Calval.byte1
'write 6,Range.byte0 :write 7,Range.byte1
Read 1,Cal1
Read 6,Range.byte0 :Read 7,Range.byte1
'Read 2,Tare.byte0 :read 3,Tare.byte1
if range < 1000 then range = 2000
if range > 2500 then range = 2000
if Cal1 < 1 then Cal1 = 100
if Cal1 > 255 then Cal1 = 100
Calval = Cal1 + 600
Tare = 0


' Main software
Start:

gosub MAX7705
gosub calibrate
gOTO Main

Main:

gosub ADCloop
gosub GetBatValue
volt1 = Newval
gosub AutoZero
gosub GetDigits
SEROUT2 PortC.6,16416,["L",#d3,#d2,".",#d1,#d0,"B",#t2,#t1,#t0] '19200 baud
goto Main

GetDigits:
d3 = Volt1 Dig 3
d2 = Volt1 Dig 2
d1 = Volt1 Dig 1
d0 = Volt1 Dig 0
t3 = txbat Dig 3
t2 = txbat Dig 2
t1 = txbat Dig 1
t0 = txbat Dig 0

return
MAX7705:
tare = 0
gosub MX7705Ini
pause 50
gosub mxch1
gosub mxcal1
return

ADCloop:
gosub getad1
return
getad1: 'for counterA = 0 to 15
Total1 = 0
For x = 1 to 8
adcsend=$38 ' Read the 16 bit DATA Register, channel 0.
shiftout SI, SCK, 5, [adcsend\8] ' adcsend read command and data register address
shiftin SO, SCK, 6, [ad1\16] ' Read 16 bit data
While ADCready = 1 'wait for valid data to be received
Wend 'wait for valid data to be received
value1 = abs (ad1/8)
Total1 = Total1 + value1
next x
value1 = abs (Total1/16) '65535/8 = 8192
if value1 < 1 then value1 = 0
if value1 > 4096 then value1 = 4096
value = value1 * Range
NewVal = div32 ScaleBits ' scalebits = 4096 (12 active bits)
return

GetAdValue:
Total1 = 0
For x = 1 to 8
adcsend=$38 ' Read the 16 bit DATA Register, channel 0.
shiftout SI, SCK, 5, [adcsend\8] ' adcsend read command and data register address
shiftin SO, SCK, 6, [ad1\16] ' Read 16 bit data
While ADCready = 1 'wait for valid data to be received
Wend 'wait for valid data to be received
ADCvalue = abs (ad1/8)
Total1 = Total1 + ADCvalue
next x
ADCvalue = abs (Total1/16) ' 4096 bits
return



AutoZero:
If volt1 < 3 then
counts = counts + 1
goto AutoZ
else
counts = 0
endif
return
AutoZ:
if counts = 5 then
volt1 = 0
counts = 0
endif
return

MX7705Ini:
'Reset MX7705
adcsend=$ff
adcrec=$ff
shiftout SI, SCK, 5, [adcsend\8] ' adcsend command to communication register
shiftout SI, SCK, 5, [adcrec\8] ' adcsend value to the selecte register
shiftout SI, SCK, 5, [adcsend\8] ' adcsend command to communication register
shiftout SI, SCK, 5, [adcrec\8] ' adcsend value to the selecte register
return
'SetADGAIN:
' if gainval = 1 then ADGAIN = $44 'decimal 68 gain = 1
' if gainval = 2 then ADGAIN = $4c 'decimal 76 gain = 2
' if gainval = 3 then ADGAIN = $54 'decimal 84 gain = 4
' if gainval = 4 then ADGAIN = $5c 'decimal 92 gain = 8
' if gainval = 5 then ADGAIN = $64 'decimal 100 gain = 16
' if gainval = 6 then ADGAIN = $6c 'decimal 108 gain = 32
' if gainval = 7 then ADGAIN = $74 'decimal 116 gain = 64
' if gainval = 8 then ADGAIN = $7c 'decimal 124 gain = 128
' return
mxch1:'CH1 AD7705 set-up Start. SEE AD7705.XLS FOR TABLE OF SETTINGS
adcsend=$20 ' WRITE TO THE COMMUNICATIONS REGISTER. SELECT CHANNEL 0 AND SET NEXT OPERATION AS A WRITE TO THE CLOCK REG
' CLOCK REGISTER.(0x20)
adcrec=$00 ' write on clock register: clock division=1, clock bit=1, master clock enabled (bit set to 0),
' bit output rate set to 20hz
gosub mxsend
'adcsend=$28
'GOSUB adread
return

mxcal1: 'CH1 Calib 'self-calibration
adcsend=$10 ' WRITE TO THE COMMUNICATIONS REGISTER. SELECT CHANNEL 0 AND SET NEXT OPERATION AS A WRITE TO THE SETUP REGISTER.(0x10).
adcrec=$54 ' WRITE TO THE SETUP REGISTER. SET SELF-CALIBRATION MODE, GAIN TO 4, UNIPOLAR MODE, BUFFERED MODE.
' BEGIN SELF-CALIBRATION/CONVERSION BY CLEARING FSYNC.(0x44)
gosub mxsend
gosub adcrdy
'adcsend=$8
'GOSUB adread
return
mxsend:
shiftout SI, SCK, 5, [adcsend\8] ' adcsend command to communication register
shiftout SI, SCK, 5, [adcrec\8] ' adcsend value to the selecte register
return

adcrdy:
While ADCready = 1:Wend 'wait for valid data to be adceived. Er angivet under self calibration mode.
' Note that after the self calibration, AD7705 start free conversion cycle.
Return
' ----------------------------------------------------------------------------
' Get Battery level Value A to D routine
' ----------------------------------------------------------------------------

' usable battery 2.7-5.4vdc (4xAAbats)
GetBatValue: 'potential divider of 2x 5m6 res accross bat
Total = 0 ' 0-1024 bits for 0-10.00 vin (o/p max650)
For z = 1 to 64 'Average of 64 readings to reduce noise
ADCIN 0, value1
Total = Total + value1
next
TXbat = Total >> 6 ' Same as divide by 64
TXbat = TXbat-722 'usable range 300 bits
TXbat = TXbat/3
if Txbat < 1 then Txbat = 0
if Txbat > 100 then Txbat = 100
if TXbat < 20 then
freqout portc.2, 500,5 'gosub Battlow '10.0 volt level '1024 bits for 12.9vdc usable range
else
freqout portc.2,10,10
endif
return

GetRange:
REAd 6,Range.byte0 :read 7,Range.byte1
if range < 1000 then range = 2000
if range > 4096 then range = 2000
goto Main

' ----------------------------------------------------------------------------
' Auto calibrate
' ----------------------------------------------------------------------------

calibrate:
portc.4 = 0
PAUSE 5000
gosub getadvalue
if ADCvalue > 800 then
goto GetRange
else
gosub GetAdValue
Loadx = ADCvalue
portc.4 = 1: pause 5000 ' Apply calibration signal & wait 5 sec's
gosub GetAdValue
Loady = ADCvalue
portc.4 = 0 ' Switch off calibration signal
Loady = abs (Loady - Loadx)
gosub calspan
Return
endif
' ----------------------------------------------------------------------------
' Calspan
' ----------------------------------------------------------------------------

calspan:
if (calval < 650 ) or ( calval > 999) then calval = 750
x = Calval * ScaleBits
Range = div32 Loady
peak = 0
write 6,Range.byte0 :write 7,Range.byte1
return

Acetronics2
- 1st November 2010, 17:30
Hi,

1) I do not think you have to modify the OSCTUNE register ...

2) Place PAUSE 1000 AFTER " DEFINE OSC ..."

3) You can use PLL x 4 Setting, with a 10 to 16 Mhz Xtal ... will give 40 to 64 Mhz Osc speed. Should be enough ...
40 and 48 Mhz are commonly admitted ... 64 is experimental ... but works fine !!!

You first have to change your 18F2525.inc file ( in the PBP/ INC folder ) for :



;************************************************* ***************
;* 18F2525.INC *
;* *
;* By : Leonard Zerman, Jeff Schmoyer *
;* Notice : Copyright (c) 2008 microEngineering Labs, Inc. *
;* All Rights Reserved *
;* Date : 09/15/08 *
;* Version : 2.60 *
;* Notes : *
;************************************************* ***************
NOLIST
ifdef PM_USED
LIST
"Error: PM does not support this device. Use MPASM."
NOLIST
else
LIST
LIST p = 18F2525, r = dec, w = -311, w = -230, f = inhx32
INCLUDE "P18F2525.INC" ; MPASM Header
;__CONFIG _CONFIG1H, _OSC_HS_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
;__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
;__CONFIG _CONFIG3H, _CCP2MX_PORTC_3H & _PBADEN_OFF_3H
_LPT1OSC_OFF_3H & _MCLRE_ON_3H
;__CONFIG _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _XINST_OFF_4L
Messg " Think to WRITE the correct CONFIGURATION ... "
Messg " Think to WRITE the correct CONFIGURATION ... "
Messg " Think to WRITE the correct CONFIGURATION ... "
NOLIST
endif
LIST
EEPROM_START EQU 0F00000h
BLOCK_SIZE EQU 64



THEN

add to the top of your code, just past the Header :



'************************************************* ****************************
'Config processeur
'************************************************* ****************************
@ __CONFIG _CONFIG1H, _IESO_OFF_1H & _OSC_HSPLL_1H & _FCMEN_OFF_1H
@ __CONFIG _CONFIG2L, _BOREN_OFF_2L & _PWRT_ON_2L
@ __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H
@ __CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H & _CCP2MX_PORTBE_3H
@ __CONFIG _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L & _XINST_OFF_4L
@ __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
@ __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
@ __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L
@ __CONFIG _CONFIG6H, _WRTB_OFF_6H & _WRTC_OFF_6H & _WRTD_OFF_6H
@ __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L
@ __CONFIG _CONFIG7H, _EBTRB_OFF_7H



You'll have to use " DEFINE OSC xx " Where XX will be 4 x your choosen Xtal frequency.

an also think to modify Serin2/Serout2 to match your Osc speed ...

after that ... check your program flow ... if not enough !!! ;)

Alain

J_norrie
- 2nd November 2010, 15:50
Hi Alain, Thanks for your help. It turns out that the main reason I cant get it to go faster seems to be the time it needs to carry out the analog to digital conversions if I took out the get ADCloop and the getbatlevel it goes like the clappers. If I reintroduce either it slows right down. I have all the averaging loops for both and the signals are still steady and the speed went up to 40 samples per second. I then reduced the times it went to get the battary level to every 150 samples. I am now getting 80 samples per second which is quite acceptable. It didnt seem to make a differance changing the clock to 40mHz using HSPLL and a 10Mhz crystal, but I have left it at that.

Again many thanks Alain for your help. Its great knowing that this forum is here with such helpful people.

cheers and many thanks John

tenaja
- 2nd November 2010, 16:46
I realize you have reached your target, but here are some tips to help in the future.

The shiftin/shiftout commands are dreadfully, painfully, pathetically slow. And also very slow. If you use an onboard a/d, or at the least, use the hardware SPI module to talk to an external a/d, you will gain a huge amount of thru-put... On the order of 10x faster, if the off-chip a/d can handle it.

Another trick is to send the data as raw values, and format it on the receiving end since it's fixed width. That will save a minimum of 30% in your case, 20% if you want to leave an alignment byte.

Acetronics2
- 3rd November 2010, 09:02
Hi Alain, Thanks for your help. It turns out that the main reason I cant get it to go faster seems to be the time it needs to carry out the analog to digital conversions

Hi, John

You also could reduce Adc sampling time to 100 or 200 µs ... instead of 5 ms !

Alain