 |
 |
View previous topic :: View next topic |
Author |
Message |
tinley
Joined: 09 May 2006 Posts: 69
|
dsPIC33CK64MC105 ADC interrupt |
Posted: Mon Sep 08, 2025 5:40 am |
|
|
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
|
|
Posted: Tue Sep 09, 2025 2:13 am |
|
|
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
|
|
Posted: Tue Sep 09, 2025 3:57 am |
|
|
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. |
|
 |
|
|
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
|