-
Notifications
You must be signed in to change notification settings - Fork 8
analog_digital_conversion_code_optimisation
About Analog/Digital Conversion Code Optimisation
The analog to digital converter (ADC or A/D) module support is implemented by Great Cow BASIC to provide 8-bit, 10-bit and 12-bit Single channel measurement mode and Differential Channel Measurement with support up to 34 channels. For compatibility all channels are supported.
There are two methods to optimise the code.
- To mimise the code, use the contstants to disable support for a specfic channels
- To adapt the ADC configuration by inserting specfic commands to set registers or register bits.
1. Minimise the code
The example below would disable support for ADC port 0 (AD0).
#define USE_AD0 FALSE
The following tables show the #defines that can be used to reduce the code size - these are the defines for the standard microcontrollers. For 16f1688x and similar microcontrollers please see the second table.
Channel | Optimisation Value | Default Value |
---|---|---|
USE_AD0 |
FALSE |
TRUE |
USE_AD1 |
FALSE |
TRUE |
USE_AD2 |
FALSE |
TRUE |
USE_AD3 |
FALSE |
TRUE |
USE_AD4 |
FALSE |
TRUE |
USE_AD5 |
FALSE |
TRUE |
USE_AD6 |
FALSE |
TRUE |
USE_AD7 |
FALSE |
TRUE |
USE_AD8 |
FALSE |
TRUE |
USE_AD9 |
FALSE |
TRUE |
USE_AD10 |
FALSE |
TRUE |
USE_AD11 |
FALSE |
TRUE |
USE_AD12 |
FALSE |
TRUE |
USE_AD13 |
FALSE |
TRUE |
USE_AD14 |
FALSE |
TRUE |
USE_AD15 |
FALSE |
TRUE |
USE_AD16 |
FALSE |
TRUE |
USE_AD17 |
FALSE |
TRUE |
USE_AD18 |
FALSE |
TRUE |
USE_AD19 |
FALSE |
TRUE |
USE_AD20 |
FALSE |
TRUE |
USE_AD21 |
FALSE |
TRUE |
USE_AD22 |
FALSE |
TRUE |
USE_AD23 |
FALSE |
TRUE |
USE_AD24 |
FALSE |
TRUE |
USE_AD25 |
FALSE |
TRUE |
USE_AD26 |
FALSE |
TRUE |
USE_AD27 |
FALSE |
TRUE |
USE_AD28 |
FALSE |
TRUE |
USE_AD29 |
FALSE |
TRUE |
USE_AD30 |
FALSE |
TRUE |
USE_AD31 |
FALSE |
TRUE |
USE_AD32 |
FALSE |
TRUE |
USE_AD33 |
FALSE |
TRUE |
USE_AD34 |
FALSE |
TRUE |
For 16f1688x devices see the table below.
Channel | Optimisation Value | Default Value |
---|---|---|
USE_ADA0 |
FALSE |
TRUE |
USE_ADA1 |
FALSE |
TRUE |
USE_ADA2 |
FALSE |
TRUE |
USE_ADA3 |
FALSE |
TRUE |
USE_ADA4 |
FALSE |
TRUE |
USE_ADA5 |
FALSE |
TRUE |
USE_ADA6 |
FALSE |
TRUE |
USE_ADA7 |
FALSE |
TRUE |
USE_ADC0 |
FALSE |
TRUE |
USE_ADC1 |
FALSE |
TRUE |
USE_ADC2 |
FALSE |
TRUE |
USE_ADC3 |
FALSE |
TRUE |
USE_ADC4 |
FALSE |
TRUE |
USE_ADC5 |
FALSE |
TRUE |
USE_ADC6 |
FALSE |
TRUE |
USE_ADC7 |
FALSE |
TRUE |
USE_ADD0 |
FALSE |
TRUE |
USE_ADD1 |
FALSE |
TRUE |
USE_ADD2 |
FALSE |
TRUE |
USE_ADD3 |
FALSE |
TRUE |
USE_ADD4 |
FALSE |
TRUE |
USE_ADD5 |
FALSE |
TRUE |
USE_ADD6 |
FALSE |
TRUE |
USE_ADD7 |
FALSE |
TRUE |
USE_ADE0 |
FALSE |
TRUE |
USE_ADE1 |
FALSE |
TRUE |
USE_ADE2 |
FALSE |
TRUE |
This is a example - disables every channel except the specified channel by defining every channel except USE_AD0 as FALSE.
This will save 146 bytes of program memory.
; ----- Configuration
#chip 16F1939
'USART settings
#define USART_BAUD_RATE 9600
#define USART_TX_BLOCKING
'Set the input pin direction
Dir PORTA.0 In
'Print 255 reading
For CurrentAddress = 0 to 255
'Take a reading and show it
HSerPrint str(ReadAD10(AN0))
'Wait 10 minutes before getting another reading
Wait 10 min
Next
#define USE_AD0 TRUE
#define USE_AD1 FALSE
#define USE_AD2 FALSE
#define USE_AD2 FALSE
#define USE_AD3 FALSE
#define USE_AD4 FALSE
#define USE_AD5 FALSE
#define USE_AD6 FALSE
#define USE_AD7 FALSE
#define USE_AD8 FALSE
#define USE_AD9 FALSE
#define USE_AD10 FALSE
#define USE_AD11 FALSE
#define USE_AD12 FALSE
#define USE_AD13 FALSE
#define USE_AD14 FALSE
#define USE_AD15 FALSE
#define USE_AD16 FALSE
#define USE_AD17 FALSE
#define USE_AD18 FALSE
#define USE_AD19 FALSE
#define USE_AD20 FALSE
#define USE_AD21 FALSE
#define USE_AD22 FALSE
#define USE_AD23 FALSE
#define USE_AD24 FALSE
#define USE_AD25 FALSE
#define USE_AD26 FALSE
#define USE_AD27 FALSE
#define USE_AD28 FALSE
#define USE_AD29 FALSE
#define USE_AD30 FALSE
#define USE_AD31 FALSE
#define USE_AD32 FALSE
#define USE_AD33 FALSE
#define USE_AD34 FALSE
For 16f18855 family of microcontrollers this is a example. This will save 149 bytes of program memory.
''' PIC: 16F18855
''' Compiler: GCB
''' IDE: GCB@SYN
'''
''' Board: Xpress Evaluation Board
''' Date: 13.3.2021
'''
'Chip Settings.
#chip 16f18855,32
#Config MCLRE_ON
'' -------------------LATA-----------------
'' Bit#: -7---6---5---4---3---2---1---0---
'' LED: ---------------|D5 |D4 |D3 |D1 |-
''-----------------------------------------
''
#define USART_BAUD_RATE 19200
#define USART_TX_BLOCKING
#define LEDD2 PORTA.0
#define LEDD3 PORTA.1
#define LEDD4 PORTA.2
#define LEDD5 PORTA.3
Dir LEDD2 OUT
Dir LEDD3 OUT
Dir LEDD4 OUT
Dir LEDD5 OUT
#define SWITCH_DOWN 0
#define SWITCH_UP 1
#define SWITCH PORTA.5
'Setup an Interrupt event when porta.5 goes negative.
IOCAN5 = 1
On Interrupt PORTBChange Call InterruptHandler
do
'Read the value from the EEPROM from register Zero in the EEPROM
EPRead ( 0, OutValue )
'Leave the Top Bytes alone and set the lower four bits
PortA = ( PortA & 0XF0 ) OR ( OutValue / 16 )
Sleep
loop
sub InterruptHandler
if IOCAF5 = 1 then 'S2 was just pressed
IOCAN5 = 0 'Prevent the event from reentering the InterruptHandler routine
IOCAF5 = 0 'We must clear the flag in software
wait 5 ms 'debounce by waiting and seeing if still held down
if ( SWITCH = DOWN ) then
'Read the ADC
adc_value = readad ( AN4 )
'Write the value to register Zero in the EEPROM
EPWrite ( 0, adc_value )
end if
IOCAN5 = 1 'ReEnable the InterruptHandler routine
end if
end sub
#define USE_ADA0 FALSE
#define USE_ADA1 FALSE
#define USE_ADA2 FALSE
#define USE_ADA3 FALSE
#define USE_ADA4 TRUE
#define USE_ADA5 FALSE
#define USE_ADA6 FALSE
#define USE_ADA7 FALSE
#define USE_ADB0 FALSE
#define USE_ADB1 FALSE
#define USE_ADB2 FALSE
#define USE_ADB3 FALSE
#define USE_ADB4 FALSE
#define USE_ADB5 FALSE
#define USE_ADB6 FALSE
#define USE_ADB7 FALSE
#define USE_ADC0 FALSE
#define USE_ADC1 FALSE
#define USE_ADC2 FALSE
#define USE_ADC3 FALSE
#define USE_ADC4 FALSE
#define USE_ADC5 FALSE
#define USE_ADC6 FALSE
#define USE_ADC7 FALSE
#define USE_ADD0 FALSE
#define USE_ADD1 FALSE
#define USE_ADD2 FALSE
#define USE_ADD3 FALSE
#define USE_ADD4 FALSE
#define USE_ADD5 FALSE
#define USE_ADD6 FALSE
#define USE_ADD7 FALSE
#define USE_ADE0 FALSE
#define USE_ADE1 FALSE
#define USE_ADE2 FALSE
2. Adapt the ADC configuration
Example 1:
The following example will set the specific register bits. The instruction will be added to the compiled code.
#define ADReadPreReadCommand ADCON.2=0:ANSELA.0=1
The constant ADReadPreReadCommand can be used to adapt the ADC methods. The constant can enable registers or register bit(s) that are required to managed for a specfic solution.
In the example above the following ASM will be added to your code. This WILL be added just before the ADC is enabled and the setting of the acquisition delay.
;ADReadPreReadCommand
banksel ADCON
bcf ADCON,2
banksel ANSELA
bsf ANSELA,0
Example 2:
The following example can be used to change the ADMUX to support a sensor on ADC4.
This supports reading the internal temperature sensor on the ATTINY85. This method will work on other similar chips. Please refer the chip specific datasheet.
This will call a macro to change the ADMUX to read the ATTINY85 internal temperature sensor, set the reference voltage to 1v1 and then wait 100 ms.
#define ADREADPREREADCOMMAND ATTINY85ReadInternalTemperatureSensor
Macro ATTINY85ReadInternalTemperatureSensor
/*
17.12 of the datasheet
The temperature measurement is based on an on-chip temperature sensor that is coupled to a single ended ADC4
channel. Selecting the ADC4 channel by writing the MUX[3:0] bits in ADMUX register to �1111� enables the temperature sensor. The internal 1.1V reference must also be selected for the ADC reference source in the
temperature sensor measurement. When the temperature sensor is enabled, the ADC converter can be used in
single conversion mode to measure the voltage over the temperature sensor.
The measured voltage has a linear relationship to the temperature as described in Table 17-2 The sensitivity is
approximately 1 LSB / ?C and the accuracy depends on the method of user calibration. Typically, the measurement
accuracy after a single temperature calibration is ±10?C, assuming calibration at room temperature. Better
accuracies are achieved by using two temperature points for calibration.
*/
IF ADReadPort=4 then
ADMUX = ( ADMUX and 0X20 ) or 0X8F
wait 100 ms
End if
End Macro
This will generate the following ASM.
;ADREADPREREADCOMMAND 'adds user code below
lds SysCalcTempA,ADREADPORT
cpi SysCalcTempA,4
brne ENDIF2
ldi SysTemp2,32
in SysTemp3,ADMUX
and SysTemp3,SysTemp2
mov SysTemp1,SysTemp3
ldi SysTemp2,143
or SysTemp1,SysTemp2
out ADMUX,SysTemp1
ldi SysWaitTempMS,100
ldi SysWaitTempMS_H,0
rcall Delay_MS
ENDIF2: