News:

Let's find out together what makes a PIC Tick!

Main Menu

ADC set to 8bit + Right justified - not working

Started by trastikata, Oct 13, 2022, 07:01 PM

Previous topic - Next topic

trastikata

Hello all,

I am not sure if this is a bug and how Positron converts ADC readings to lower resolution, but if I set Adin_Res to 8 bit and I keep ADFM right justified (ADFM = 1), the result given by Positron's command ADIn is always 0.

ADFM set to 1 was a remnant from the old code where 10bit ADC readings were required, took me a while to figure this out after some time spent tracing signals all over the PCB.  :)

Device in question where I observed that behaviour is PIC18F4550.

top204

#1
The ADIn command does not alter the ADFM bit, so if using the ADIn command for an 8-bit result, set ADFM bit for Left Justification, and for 10-bit, the ADFM bit is set for Right Justification.

The ADin command is working as expected on the PIC18Fx550 devices. A tested example program listing is below:

'
' Test the ADIn command on a PIC18F4550 device with a resolution of 8-bits
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F4550                    ' Tell the compiler what device to compile for
    Declare Xtal = 48                   ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut_Pin = PORTC.6
 
    Declare ADin_Res = 8                ' Tell the compiler to return the high byte of the ADC result
   
    Dim bADC_Value As Byte

'-------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    ADCON2bits_ADFM = 0                 ' Left justify the ADC result for 8-bit operation
    ADCON1 = 0b00001110                 ' Make AN0 an analogue input and +Vref is VDD and -Vref is VSS
   
    Do                                  ' Create a loop
        bADC_Value = ADIn 0             ' Read the ADC on AN0
        HRSOutLn Dec bADC_Value         ' Display the 8-bit ADC result   
        DelayMS 200                     ' A small delay
    Loop                                ' Do it forever

Or not using the Declare ADin_Res directive, and using the 8-bit value from the high-byte of the ADC result:

'
' Test the ADIn command on a PIC18F4550 device
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F4550                    ' Tell the compiler what device to compile for
    Declare Xtal = 48                   ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut_Pin = PORTC.6
 
    Dim wADC_Value As Word

'-------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    ADCON2bits_ADFM = 0                 ' Left justify the ADC result
    ADCON1 = 0b00001110                 ' Make AN0 an analogue input and +Vref is VDD and -Vref is VSS
   
    Do                                  ' Create a loop
        wADC_Value = ADIn 0             ' Read the ADC on AN0
        HRSOutLn Dec wADC_Value.Byte1   ' Display the 8-bit value from the 10-bit ADC result   
        DelayMS 200                     ' A small delay
    Loop                                ' Do it forever

The ADIn_Res declare does not alter the ADFM bit, it changes the compiler's ADIn library routine to return the high byte of the 10-bit or 12-bit result from the ADC, because the Justification setting of the ADFM bit moves the value of the ADC Left to Right or Right to left in the ADRESL and ADRESH SFRs. :-)

The screenshot below shows the Declare ADin_Res program listing working in a simulator, and I have tested it with a real device as well:

18F4550 - ADin Test.jpg


top204

#2
The newer, and future, 8-bit devices are altering their ADC peripheral, so they are also altering the justification bit from them, which means the ADin_Res declare will eventually have no effect on them.

With the newer devices, it is becoming mandatory to create a procedure or subroutine that sets up the ADC before it is used, because they are becoming more and more complex. For example, a typical PIC18F26K40 ADC setup procedure I use is:

'------------------------------------------------------------------------------
' Setup the ADC peripheral on a PIC18F26K40 device
' Input     : None
' Output    : None
' Notes     : Set for 10-bit operation
'
Proc ADC_Setup()
    ADLTHL  = 0b00000000
    ADLTHH  = 0b00000000
    ADUTHL  = 0b00000000
    ADUTHH  = 0b00000000
    ADSTPTL = 0b00000000
    ADSTPTH = 0b00000000
    ADRPT   = 0b00000000
    ADPCH   = 0b00000000
    ADCAP   = 0b00000000
    ADCON0  = 0b10000100        ' ADC enabled and right justified for 10-bit operation
    ADCON1  = 0b00000000        
    ADCON2  = 0b00000000        
    ADCON3  = 0b00000000        
    ADSTAT  = 0b00000000        
    ADREF   = 0b00000000        ' ADNREF is VSS. ADPREF is VDD
    ADACT   = 0b00000000        
    ADCLK   = 0b00000100        ' FOSC/16 (FOSC / (2 * (n + 1)))
    ADACQ   = 0b00000000
EndProc

With the original 8-bit devices, and devices pre-2011 (ish), there were about four or five SFRs for the ADC peripheral, but now there are many SFRs to manipulate. Even if they are not required, it is wise to set them as disabled or a known default value, in case Microchip change their default settings in future devices, as they have done many, many times before!

John Lawton

I prefer to setup PIC peripherals manually using the datasheet because these settings seem to continually develop with new devices and their new features and there is no better way to know exactly what you are doing with a device than to set it up the hard way even if you were able to heroically make sufficient declares that worked for all Microchip's parts.

trastikata

Thank you Les, as always a thorough explanation of the compiler's intrinsic work. It makes it much easier to understand why things happen :).