AnsweredHot!PIC32MZ ADC confusion

Author
PhilY
Starting Member
  • Total Posts : 41
  • Reward points : 0
  • Joined: 2016/12/06 13:09:46
  • Location: 0
  • Status: offline
2017/07/04 13:39:35 (permalink)
0

PIC32MZ ADC confusion

Environment is PIC32MZ1024EFH100, Harmony v1.10 and MPLAB v3.60.
 
I need to detect when a switch is pressed on any one of 4 analog inputs.
Each analog input is connected to a button switch.
The input voltage is normally 3.3 volts.
When the switch is depressed the input voltage is 2.8 volts.
Pins AN2, AN3, AN4 and AN6 are used as the inputs.
 
This would be so easy for a digital input but for whatever reason the requirement is to use analog.
 
I've been going through the ADCHS examples in the Harmony help trying to decide what framework to choose.
My initial thought was to use the Channel Scanning example using Channel 7 - original code included below.
 

{
int result[4]; // storage for results
// Configure the ADC
PLIB_ADCHS_Setup
(
MY_ADCHS_INSTANCE,
ADCHS_VREF_AVDD_AVSS, // AVDD and AVSS as reference
ADCHS_CHARGEPUMP_DISABLE, // No charge pump
ADCHS_OUTPUT_DATA_FORMAT_FRACTIONAL, // Use fractional format
true, // Do stop in idle
ADCHS_FAST_SYNC_SYSTEM_CLOCK_ENABLE, // Enable Fast synchronous system clock
ADCHS_FAST_SYNC_PERIPHERAL_CLOCK_DISABLE, // Disable Fast synchronous peripheral clock
ADCHS_INTERRUPT_BIT_SHIFT_LEFT_0_BITS, // vector shift unused, interrupt not used
0, // vector base address unused, interrupt not used
ADCHS_CLOCK_SOURCE_SYSCLK, // SYSCLK is the clock source
1, // TQ = 1/SYSCLK * 2
ADCHS_WARMUP_CLOCK_32 // Warm-up time = 32 clocks
);
// Configure the ADC SAR Channel-7
PLIB_ADCHS_ChannelSetup
(
MY_ADCHS_INSTANCE,
ADCHS_CHANNEL_7, // Channel - 7
ADCHS_DATA_RESOLUTION_12BIT, // resolution is set to 12bits
1, // clock divider bit is, TAD7 = 2 * TQ
1, // Sample time is 3 * TAD7
ADCHS_EARLY_INTERRUPT_PRIOR_CLOCK_1 // 1 clock early interrupt (ignored, interrupt not used)
);
// Select analog channel AN8 and scan sequence to be triggered with global scan trigger
PLIB_ADCHS_AnalogInputScanSetup
(
MY_ADCHS_INSTANCE,
ADCHS_AN8,
ADCHS_SCAN_TRIGGER_SENSITIVE_EDGE,
ADCHS_SCAN_TRIGGER_SOURCE_GLOBAL_SOFTWARE_EDGE
);
// Now, add further analog inputs, AN31, AN32, AN33 to scan list
PLIB_ADCHS_AnalogInputScanSelect(MY_ADCHS_INSTANCE, ADCHS_AN31);
PLIB_ADCHS_AnalogInputScanSelect(MY_ADCHS_INSTANCE, ADCHS_AN32);
PLIB_ADCHS_AnalogInputScanSelect(MY_ADCHS_INSTANCE, ADCHS_AN33);
// Select input mode for AN8, AN31, AN32, AN33
PLIB_ADCHS_AnalogInputModeSelect ( MY_ADCHS_INSTANCE, ADCHS_AN8, ADCHS_INPUT_MODE_SINGLE_ENDED_UNIPOLAR );
 
PLIB_ADCHS_AnalogInputModeSelect( MY_ADCHS_INSTANCE, ADCHS_AN31,
ADCHS_INPUT_MODE_SINGLE_ENDED_UNIPOLAR );
 
PLIB_ADCHS_AnalogInputModeSelect( MY_ADCHS_INSTANCE, ADCHS_AN32,
ADCHS_INPUT_MODE_SINGLE_ENDED_UNIPOLAR );
 
PLIB_ADCHS_AnalogInputModeSelect( MY_ADCHS_INSTANCE, ADCHS_AN33,
ADCHS_INPUT_MODE_SINGLE_ENDED_UNIPOLAR );
 
// Select individual trigger for class-2 channels viz. AN8 to be scan trigger.
// AN31, AN32 and AN33 are class-3 channels, and do not have individual trigger
PLIB_ADCHS_AnalogInputTriggerSourceSelect ( MY_ADCHS_INSTANCE, ADCHS_CLASS12_AN8,
ADCHS_TRIGGER_SOURCE_SCAN );
 
// Select AN8 to be edge trigger (not level trigger).
// Calling this function is needed for class-1 and 2 analog inputs
PLIB_ADCHS_AnalogInputEdgeTriggerSet( MY_ADCHS_INSTANCE, ADCHS_CLASS12_AN8);
// Enable ADC
PLIB_ADCHS_Enable(MY_ADCHS_INSTANCE);
// Check VREF to be ready
While(!PLIB_ADCHS_VREFIsReady(MY_ADCHS_INSTANCE));
// Check for VREF Fault
While(PLIB_ADCHS_VREFFaultHasOccurred(MY_ADCHS_INSTANCE));
// Enable analog circuit for channel-7
PLIB_ADCHS_ChannelAnalogFeatureEnable( MY_ADCHS_INSTANCE, ADCHS_CHANNEL_7);
// Wait for the channel-7 to be ready
while(!PLIB_ADCHS_ChannelIsReady( MY_ADCHS_INSTANCE, ADCHS_CHANNEL_7) );
// Enable digital circuit for channels 7
PLIB_ADCHS_ChannelDigitalFeatureEnable( MY_ADCHS_INSTANCE, ADCHS_CHANNEL_7);
while(1)
{
// Enable global software trigger
PLIB_ADCHS_GlobalSoftwareTriggerEnable( MY_ADCHS_INSTANCE );
// Wait for conversion complete for AN8
while(!PLIB_ADCHS_AnalogInputDataIsReady(MY_ADCHS_INSTANCE, ADCHS_AN8));
result[0] = PLIB_ADCHS_AnalogInputResultGet( MY_ADCHS_INSTANCE, ADCHS_AN8 );
// Wait for conversion complete for AN31
while(!PLIB_ADCHS_AnalogInputDataIsReady(MY_ADCHS_INSTANCE, ADCHS_AN31));
result[1] = PLIB_ADCHS_AnalogInputResultGet( MY_ADCHS_INSTANCE, ADCHS_AN31 );
// Wait for conversion complete for AN32
while(!PLIB_ADCHS_AnalogInputDataIsReady(MY_ADCHS_INSTANCE, ADCHS_AN32));
result[2] = PLIB_ADCHS_AnalogInputResultGet( MY_ADCHS_INSTANCE, ADCHS_AN32 );
// Wait for conversion complete for AN33
while(!PLIB_ADCHS_AnalogInputDataIsReady(MY_ADCHS_INSTANCE, ADCHS_AN33));
result[3] = PLIB_ADCHS_AnalogInputResultGet( MY_ADCHS_INSTANCE, ADCHS_AN33 );
}
return(1);
}

 
I substituted AN8 for AN2 and substituted AN31, AN32 and AN33 for AN3, AN4 and AN6.
This example did NOT work. The first call to PLIB_ADCHS_AnalogInputDataIsReady() did not return.
 
After trying more examples and getting totally confused with all the ADC options I finally had success with the example "Simultaneous Sampling and Conversion of Three Class 1 Inputs". I only tried it for a single analog input i.e. AN2 and this did work.  I was able to read values of 0xFFD0000 (switch open) and 0x400000 (switch closed). The modified code is below:

// Configure the ADC
PLIB_ADCHS_Setup
(
    DRV_ADC_ID_1,
    ADCHS_VREF_AVDD_AVSS, // AVDD and AVSS as reference
    ADCHS_CHARGEPUMP_DISABLE, // No charge pump
    ADCHS_OUTPUT_DATA_FORMAT_FRACTIONAL, // Use fractional format
    true, // Do stop in idle
    ADCHS_FAST_SYNC_SYSTEM_CLOCK_ENABLE, // Enable Fast synchronous system clock
    ADCHS_FAST_SYNC_PERIPHERAL_CLOCK_DISABLE, // Disable Fast synchronous peripheral clock
    ADCHS_INTERRUPT_BIT_SHIFT_LEFT_0_BITS, // vector shift unused, interrupt not used
    0, // vector base address unused, interrupt not used
    ADCHS_CLOCK_SOURCE_SYSCLK, // SYSCLK is the clock source
    1, // TQ = 1/SYSCLK * 2
    ADCHS_WARMUP_CLOCK_32 // Warm-up time = 32 clocks
);

// Configure the ADC SAR Channel-2
PLIB_ADCHS_ChannelSetup
(
    DRV_ADC_ID_1,
    DCHS_CHANNEL_2,
    ADCHS_DATA_RESOLUTION_12BIT, // resolution is set to 12bits
    1, // clock divider bit is, TAD2 = 2 * TQ
    1, // Sample time is 3 * TAD
    ADCHS_EARLY_INTERRUPT_PRIOR_CLOCK_1 // 1 clock early interrupt (ignored, interrupt not used)
 );

// Configure the synchronous sampling for Channel-2
if( false == PLIB_ADCHS_ChannelTriggerSampleSelect( DRV_ADC_ID_1, ADCHS_CHANNEL_2,   ADCHS_CHANNEL_SYNC_SAMPLING) )
{
    // error has occurred
    while(1);
}
 
 
// Select inputs for Channel
if( false == PLIB_ADCHS_ChannelInputSelect(DRV_ADC_ID_1, ADCHS_CHANNEL_2, ADCHS_CHANNEL_2_DEFAULT_INP_AN2 ) )
{
    // error has occurred
    while(1);
}
// Select input mode for AN0, AN1, AN2
PLIB_ADCHS_AnalogInputModeSelect( DRV_ADC_ID_1, ADCHS_AN2, ADCHS_INPUT_MODE_SINGLE_ENDED_UNIPOLAR );
 
// Select AN0, AN1 and AN2 as edge trigger
PLIB_ADCHS_AnalogInputEdgeTriggerSet( DRV_ADC_ID_1, ADCHS_CLASS12_AN2 );
 
// Select AN0, AN1 and AN2 to be software triggered
PLIB_ADCHS_AnalogInputTriggerSourceSelect( DRV_ADC_ID_1, ADCHS_CLASS12_AN2, ADCHS_TRIGGER_SOURCE_GLOBAL_SOFTWARE_EDGE );
 
//Enable ADC
PLIB_ADCHS_Enable(DRV_ADC_ID_1);

// Check VREF to be ready
while(!PLIB_ADCHS_VREFIsReady(DRV_ADC_ID_1));
 
// Check for VREF Fault
while(PLIB_ADCHS_VREFFaultHasOccurred(DRV_ADC_ID_1));
 
// Enable analog circuit for channel-0, 1 and 2
PLIB_ADCHS_ChannelAnalogFeatureEnable( DRV_ADC_ID_1, ADCHS_CHANNEL_2 );
 
// Wait for the channels to be ready
while( !PLIB_ADCHS_ChannelIsReady( DRV_ADC_ID_1, ADCHS_CHANNEL_2) );
 
// Enable digital circuit for channels 0, 1, 2
PLIB_ADCHS_ChannelDigitalFeatureEnable( DRV_ADC_ID_1, ADCHS_CHANNEL_2 );
 
while(1)
{
    // Enable global software trigger
    PLIB_ADCHS_GlobalSoftwareTriggerEnable( MY_ADCHS_INSTANCE );
   
    // Wait for conversion complete for AN2
    while(!PLIB_ADCHS_AnalogInputDataIsReady(MY_ADCHS_INSTANCE, ADCHS_AN2));
    result[0] = PLIB_ADCHS_AnalogInputResultGet( MY_ADCHS_INSTANCE, ADCHS_AN2 );

}
return(1);
 

 
The problem with this solution is that it uses Class 1 inputs and only certain analog pins are available. For the PIC32MZ1024EFH100 I believe I can only use ADCHS channels 0 to 4 which also require inputs AN0 to AN4 respectively and one of my inputs is AN6.
 
For such a simple problem what is the correct solution for doing this (please don't say read the pins digitally!!)
 
Any ideas?
 
Thnaks
 
 
#1
PhilY
Starting Member
  • Total Posts : 41
  • Reward points : 0
  • Joined: 2016/12/06 13:09:46
  • Location: 0
  • Status: offline
Re: PIC32MZ ADC confusion 2017/07/05 07:40:23 (permalink)
0
So after further reading I've confirmed that to use individual ADC modules my switches need to be connected to any CLASS 1 input from AN0 to AN4 or the alternate AN45 to AN49.
 
To use the shared ADC module 7 I believe the inputs need to be CLASS 2(AN5 to AN11) or CLASS 3 (AN32 to AN44).
The trigger for sampling needs to be a CLASS 2 input.
 
I have not found a definitive answer as to which CLASS all the AN inputs belong to for the PIC32MZ1024EFH100. The above information has been gleaned from different parts of the data sheet.
 
In conclusion I'll need to connect the button switches to the correct AN input.
 
I'd still like to know if using the shared ADC module 7 would be less demanding on the system?
 
Thanks.
 
#2
GDA
Starting Member
  • Total Posts : 63
  • Reward points : 0
  • Joined: 2015/08/31 16:46:40
  • Location: 0
  • Status: offline
Re: PIC32MZ ADC confusion 2017/07/06 14:45:43 (permalink) ☼ Best Answerby PhilY 2017/07/07 07:14:16
0
Did you look at the adchs_pot demo?  It demonstrates configuration of the digital comparators.  They allow you to generate one event for an ADC which exceeds a range, is below a range, or falls within a range.  From your description, it sounds like your software would only get a notice (interrupt) when one of the channels moved from above to below the value ranges you described.
#3
PhilY
Starting Member
  • Total Posts : 41
  • Reward points : 0
  • Joined: 2016/12/06 13:09:46
  • Location: 0
  • Status: offline
Re: PIC32MZ ADC confusion 2017/07/07 07:31:30 (permalink)
0
Yes I have looked at most of the examples.
You are correct that using a digital comparator is probably the way to go.
However, I have not been able to generate an interrupt using a digital comparator.
 
The adchs_pot demo generates an interrupt after every sample (when data is ready). It then checks each comparator for an event.
 
In my case I have 4 switches which are sampled every 250mS.
I don't want to be interrupted every time a sample and conversion takes place since a switch will not be depressed that often.
I'd like to be interrupted when a button is depressed. I should be able to do this using the digital comparator if it drops below a specific level.
 
I'm posting this problem in a new thread.
 
Cheers.
#4
Bata KAN KAN
New Member
  • Total Posts : 22
  • Reward points : 0
  • Joined: 2017/01/11 08:12:10
  • Location: 0
  • Status: offline
Re: PIC32MZ ADC confusion 2017/10/13 02:26:13 (permalink)
0
Hi,
 
Did you get this to work?
#5
PhilY
Starting Member
  • Total Posts : 41
  • Reward points : 0
  • Joined: 2016/12/06 13:09:46
  • Location: 0
  • Status: offline
Re: PIC32MZ ADC confusion 2017/10/13 05:41:33 (permalink)
0
No I didn't get it the digital comparator to generate an interrrupt.
In the end the requirement was changed to use digital inputs, much simpler.
#6
Jump to:
© 2017 APG vNext Commercial Version 4.5