CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

dsPIC33CK64MC105 ADC interrupt

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
tinley



Joined: 09 May 2006
Posts: 69

View user's profile Send private message Visit poster's website

dsPIC33CK64MC105 ADC interrupt
PostPosted: Mon Sep 08, 2025 5:40 am     Reply with quote

This is a cut-down project to run on a Microchip Explorer with MC PIM fitted. The real project is running a similar CK chip and has the same issue... the interrupts for ADC don't fire.

Code:
#include <33CK64MC105.h>
#device ADC=12
#device ICSP=1
#use delay(clock=100MHz,crystal=8MHz)

#FUSES NOWDT                     //No Watch Dog Timer
#FUSES CKSFSM                    //Clock Switching is enabled, fail Safe clock monitor is enabled

#pin_select U1TX=PIN_D1
#pin_select U1RX=PIN_C8
#use rs232(UART1, baud=9600, stream=UART_PORT1)

#define LED PIN_C12

unsigned int8 count = 0;
unsigned int16 result;
int1 trig = 0;

#INT_ADC1
void  adc1_isr(void)
{
    trig = TRUE;
}

#INT_AN4DONE
void  an2done_isr(void)
{
    trig = TRUE;
}

void main()
{
    setup_adc_ports( sAN4 );
    setup_adc(ADC_CLOCK_SYSTEM | ADC_CLOCK_DIV_1 | ADC_WARMTIME_16 | ADC_SHARED_CLOCK_DIV_2 | ADC_SHARED_TAD_MUL_2 | ADC_ENABLE_SHARED_CORE);

    clear_interrupt(INT_ADC1);
    clear_interrupt(INT_AN4DONE);
   
    enable_interrupts(INT_ADC1);
    enable_interrupts(INT_AN4DONE);
    enable_interrupts(INTR_GLOBAL);
   
    set_adc_channel( 4 );

    while(true)
    {
        output_high(LED);
        delay_ms(100);
        read_adc( ADC_START_ONLY );
        delay_ms(1);
        result = read_adc( ADC_READ_ONLY );
        output_low(LED);
        delay_ms(400);
        printf(">%u %lu %u\r\n", count++, result, trig);
    }

}


I have tried setting/resetting all the registers I can think of, but I still get no interrupt. It all got a bit messy, so I just started from scratch with the Explorer board.

Any help would be appreciated, please?
tinley



Joined: 09 May 2006
Posts: 69

View user's profile Send private message Visit poster's website

PostPosted: Tue Sep 09, 2025 2:13 am     Reply with quote

I had a very fast and helpful response from CCS:

What you need to do is enable the individual interrupt for each channel you want to generate an interrupt for. The compiler does have built-in functions for enabling and disabled them, unfortunately it looks like we forgot to document them and add the prototypes to the device's header file. I'm working on correcting that however you can still use them. For enabling the individual ADC interrupts you can use the enable_adc_interrupt() function, this works similar to the set_adc_channel() function were you pass it the number of the ADC channel you want to enable the individual ADC interrupt for. For example to enable it for AN4 you would do the following:

enable_adc_interrupt(4); //enable individual ADC interrupt for AN4

Additionally if you want to disable the individual ADC interrupt for a channel you can use the disable_adc_interrupt() function, were you pass it the number of the individual ADC interrupt you want to disable. By default all of the individual ADC channel interrupts are disabled so you only need to use the disable_adc_interrupt() function if you want to disabled one that you previously enabled.

Once the individual ADC channel interrupt is enabled it will cause both the INT_ADC1 and INT_ANxDONE interrupts to occur, if they are enabled. The only way to completely clear the interrupt is to read the buffer for the ADC channel that caused the interrupt, which the read_adc() function will do. If you don't read it in the ISR it will get caught in an infinite loop servicing the ISR. Since it causes both interrupts to occur I recommend using either the ADC1 ISR or the individual ANxDONE ISRs. However both can be used as long as you make sure you read the ADC result in the one that occurs first and not in the other one, you can use the adc_done() function for that. By default the ADC1 ISR has a higher natural priority, so it will be serviced first. You can make it service the other ISR first by setting it to a higher level, that can be done by adding the level=x option to the ISR, x being the level to set it to. By default all ISR are set to level 4 so setting the ANxD ONE to level 5 will cause it to be serviced before the ADC1 ISR, for example:


#INT_AN4DONE level=5
void an2done_isr(void)
{
trig = TRUE;

result = read_adc(ADC_READ_ONLY);
}

The most important part here was reading the ADC within the interrupt. Not doing this was causing my code to hang when I set the register bit ADIEL.IE4, which is the bit set by the undocumented enable_adc_interrupt(4);
Ttelmah



Joined: 11 Mar 2010
Posts: 19939

View user's profile Send private message

PostPosted: Tue Sep 09, 2025 3:57 am     Reply with quote

Worth also saying, that you would not normally bother with this doing a
manual trigger as you show, since the ADC will take a reading in less time
than it'd take to get into, and out of the interrupt. Normally you would
trigger off a timer so you get synchronous sampling, or off an external
event.

I'd suspect this interrupt may be 'unclearable', until the ADC reading is
done. Hence the hang.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group