• AVR Freaks

Helpful ReplyHot!dsPIC33EP32GS502 context saving problem

Starting Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2011/09/17 10:32:52
  • Location: 0
  • Status: offline
2019/11/13 05:14:10 (permalink)

dsPIC33EP32GS502 context saving problem

Im trying to write ADC oversampling filter ISR with context saving, ADC is triggered in every 100us so I really need this context saving optimalization.
At begining I used MCC code configurator, it generates most of ADC code but unfortunly it didnt generate too much code for oversampling filter, it ignore ADFLTR ISR, so I wrote missing code according to data sheet or just copy some examples.
According to xc16 Compiler Users Guide, chapter 14.5 "INTERRUPT SERVICE ROUTINE CONTEXT SAVING" if context switchin is desired CTXT1 should be set equal to ADFLTR0 interrupt priotity, so I set both to priority 5 via MCC. Next step is add attribute "context" to ISR declaration, in chapter 14.5 example there was no "no_auto_psv" in ISR, but even after remove it, problem persist.
Unfortunlly context save is not working, when run code with simulator or with tagret device via PICKIT3 I cannot see any CTXTSTAT change (I roll over SFR view to let it refresh). Also in disassembly I cannot find any CTXTSWP instruction generated by compiler, ofcourse if change any working register (via asm code) in ISR it cause address trap error at exit, any C code adds just PUSH/POP instructions. So Im pretty sure context is not saved/switched.
Also attempted to manually switch context by typing asm("CTXTSWP #1"); at ISR first line of code, it made CTXTSTAT change but, according to device data sheet RETFIE should restore also CTXTSWP to default value 0, unfortunlly not in this case, maybe it was only about C code. When add asm("CTXTSWP #0"); at ISR end it wont trigger ADC anymore.
Have no idea what I missed, In errata found only information about CTXT issue with interrupt nesting thats why I turn off timer to avoid this problem during tests.
ADC initialize code, mostly MCC/code examples:

void ADC1_Initialize (void)
// Configure the I/O pins to be used as analog inputs.
ANSELAbits.ANSA0 = 1; TRISAbits.TRISA0 = 1; // AN0/RA0 connected the dedicated core 0
// Configure the common ADC clock.
ADCON3Hbits.CLKSEL = 3; // clock from AUXclk = 117 964 800 Hz
ADCON3Hbits.CLKDIV = 0; // no clock divider (1:1) TCORE = 8.48ns

// Configure the cores ADC clock.
ADCORE0Hbits.ADCS = 0; // clock divider (1:2) Tadcore = 16.96 ns > 14.3 ns
// Configure the ADC reference sources.
ADCON3Lbits.REFSEL = 0; // AVdd as voltage reference
// Configure the integer of fractional output format.
ADCON1Hbits.FORM = 0; // integer format
// Select single-ended input configuration and unsigned output format.
ADMOD0Lbits.SIGN0 = 0; // AN0/RA0
ADMOD0Lbits.DIFF0 = 0; // AN0/RA1
// Set initialization time to maximum
// Turn on ADC module
ADCON1Lbits.ADON = 1;

// Enable and calibrate cores
// Set software common trigger as AN0 input Egde sensitive trigger source.
ADFL0CONbits.FLCHSEL = 0; // Select the AN0 input for the filter.
ADFL0CONbits.MODE = 3; // Averaging, 12-bit result.
ADFL0CONbits.OVRSAM = 6; // x256
// Enable delay between trigger and the conversion start (SAMC bits).
ADCON4Lbits.SAMC0EN = 1;
// Set sampling time (26x Tad) = 26 * 16,96 = 440.96ns
ADCORE0Lbits.SAMC = 26;
// Filter Interrupts
ADFL0CONbits.IE = 1;
// Enable the filter.
ADFL0CONbits.FLEN = 1;


void ADC1_Core0PowerEnable (void)
ADCON5Lbits.C0PWR = 1;
while(ADCON5Lbits.C0RDY == 0);
ADCON3Hbits.C0EN = 1;

void ADC1_Core0Calibration (void)
ADCAL0Lbits.CAL0EN = 1;
ADCAL0Lbits.CAL0RUN = 1;
while(ADCAL0Lbits.CAL0RDY == 0);
ADCAL0Lbits.CAL0EN = 0;

When try to add more code i got forum crash:
Access Denied
You don't have permission to access "http://www.microchip.com/forums/post.aspx?" on this server.
Reference #18.8dd6dd58.1573647752.174c8a31
What a day....
post edited by abel11 - 2019/11/13 05:33:31
Starting Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2011/09/17 10:32:52
  • Location: 0
  • Status: offline
Re: dsPIC33EP32GS502 context saving problem 2019/11/13 05:30:24 (permalink)
More code here because forum didnt allow me to add it above...
MCC generated configuration:

// Configuration bits: selected in the GUI
#pragma config BWRP = OFF //Boot Segment Write-Protect bit->Boot Segment may be written
#pragma config BSS = DISABLED //Boot Segment Code-Protect Level bits->No Protection (other than BWRP)
#pragma config BSEN = OFF //Boot Segment Control bit->No Boot Segment
#pragma config GWRP = OFF //General Segment Write-Protect bit->General Segment may be written
#pragma config GSS = DISABLED //General Segment Code-Protect Level bits->No Protection (other than GWRP)
#pragma config CWRP = OFF //Configuration Segment Write-Protect bit->Configuration Segment may be written
#pragma config CSS = DISABLED //Configuration Segment Code-Protect Level bits->No Protection (other than CWRP)
#pragma config AIVTDIS = OFF //Alternate Interrupt Vector Table bit->Disabled AIVT
#pragma config BSLIM = 8191 //Boot Segment Flash Page Address Limit bits->8191
#pragma config FNOSC = FRC //Oscillator Source Selection->FRC
#pragma config IESO = ON //Two-speed Oscillator Start-up Enable bit->Start up device with FRC, then switch to user-selected oscillator source
#pragma config POSCMD = NONE //Primary Oscillator Mode Select bits->Primary Oscillator disabled
#pragma config OSCIOFNC = OFF //OSC2 Pin Function bit->OSC2 is clock output
#pragma config IOL1WAY = ON //Peripheral pin select configuration bit->Allow only one reconfiguration
#pragma config FCKSM = CSECMD //Clock Switching Mode bits->Clock switching is enabled,Fail-safe Clock Monitor is disabled
#pragma config PLLKEN = ON //PLL Lock Enable Bit->Clock switch to PLL source will wait until the PLL lock signal is valid
#pragma config WDTPOST = PS32768 //Watchdog Timer Postscaler bits->1:32768
#pragma config WDTPRE = PR128 //Watchdog Timer Prescaler bit->1:128
#pragma config WDTEN = OFF //Watchdog Timer Enable bits->WDT and SWDTEN disabled
#pragma config WINDIS = OFF //Watchdog Timer Window Enable bit->Watchdog Timer in Non-Window mode
#pragma config WDTWIN = WIN25 //Watchdog Timer Window Select bits->WDT Window is 25% of WDT period
#pragma config ICS = PGD3 //ICD Communication Channel Select bits->Communicate on PGEC3 and PGED3
#pragma config JTAGEN = OFF //JTAG Enable bit->JTAG is disabled
#pragma config BTSWP = OFF //BOOTSWP Instruction Enable/Disable bit->BOOTSWP instruction is disabled
#pragma config PWMLOCK = ON //PWMx Lock Enable bit->Certain PWM registers may only be written after key sequency
#pragma config ALTI2C1 = OFF //Alternate I2C1 Pin bit->I2C1 mapped to SDA1/SCL1 pins
#pragma config ALTI2C2 = OFF //Alternate I2C2 Pin bit->I2C2 mapped to SDA2/SCL2 pins
#pragma config DBCC = OFF //DACx Output Cross Connection bit->No Cross Connection between DAC outputs
#pragma config CTXT1 = IPL5 //Specifies Interrupt Priority Level (IPL) Associated to Alternate Working Register 1 bits->Alternate Register set assigned to IPL level 5
#pragma config CTXT2 = IPL7 //Specifies Interrupt Priority Level (IPL) Associated to Alternate Working Register 2 bits->Alternate Register set assigned to IPL level 7

MCC generated Interrupt initialization:
void INTERRUPT_Initialize (void)
// CNI: Change Notification Interrupt
// Priority: 7
IPC4bits.CNIP = 7;

// ADFLTR0: ADC OverSampling Filter 0 Int
// Priority: 5
IPC44bits.ADFLTR0IP = 5;

ADC Filter ISR:
uint16_t temp;
void __attribute__((interrupt, no_auto_psv, context)) _ADFLTR0Interrupt ( void )
/* Switch context */
//asm("CTXTSWP #1");

/* Set next conversion trigger - conversion time = 101us */

/* Set LED */

/* Filter sample */
temp = ADFL0DAT;

/* Clear LED */

/* clear flag */

/* restore context */
//asm("CTXTSWP #0");

Called in ISR function (just cyclic buffer):
void FiltrAB_AddSample(){

//*DataSamples->buffWritePtr = FiltrAlfaBeta(); // asm function

/* Loop the buffer if needed */
if (DataSamples->buffWritePtr >= &DataSamples->buffPtr[FILTER_BUFF_LEN-1]){
DataSamples->buffWritePtr = &DataSamples->buffPtr[0];
/* If buffer is overflowed ensure Read is pointing to oldest measure
* and Write pointing to latest measure */
if (DataSamples->buffWritePtr == DataSamples->buffReadPtr){

if (DataSamples->buffReadPtr == &DataSamples->buffPtr[FILTER_BUFF_LEN-1]){
DataSamples->buffReadPtr = &DataSamples->buffPtr[0];

/* Actualize number of filtered samples */
if ( DataSamples->numberOfSamples <= ( FILTER_BUFF_LEN-1 ) ) DataSamples->numberOfSamples++;

Starting Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2011/09/17 10:32:52
  • Location: 0
  • Status: offline
Re: dsPIC33EP32GS502 context saving problem 2019/11/21 04:50:22 (permalink)
I found solution, so I post it here.
Oversampling filter ISR context switch have to be done in asm (manually) and ISR need to be marked as naked to avoid pushing working registers when its not nessesery. Have no idea why its not working in C with "context" but following code works with few other ISR working around.
void __attribute__((interrupt, no_auto_psv, naked)) _ADFLTR0Interrupt ( void )
/* Save RCOUNT */
    asm("PUSH RCOUNT");
/* Switch context */
    asm("CTXTSWP #1");

// do ISR stuff
/* Clear flag */
    _ADFLTR0IF = 0;

/* Restore context */
    asm("CTXTSWP #0");

/* Restore RCOUNT */
    asm("POP RCOUNT");


post edited by abel11 - 2019/11/21 04:52:01
Super Member
  • Total Posts : 6176
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: dsPIC33EP32GS502 context saving problem 2019/11/21 08:17:57 (permalink) ☄ Helpfulby abel11 2019/11/22 03:02:13
The register set is switched automatically in hardware, you don't need to do anything. The only thing you need to do is to assign the correct IPL level to your interrupt using the corresponding IPCxx register.
Also, do not manipulate read pointer in the ISR. Imagine the code in the main fetches the read poiner, then ISR happens which moves the read pointer, then ISR returns, but the main code already has the old read pointer and will access incorrect data.
Instead of handling overflowing buffers, consider making the buffers big enough so that they never overflow. Since you know the communication speed, it's always possible to calculate the required buffer size. This saves processing time and makes the program more reliable.
Starting Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2011/09/17 10:32:52
  • Location: 0
  • Status: offline
Re: dsPIC33EP32GS502 context saving problem 2019/11/22 03:02:02 (permalink)
For the moment Im gonna stay with manually context switch (at least its working), later Ill try again what I missed with switching in C. Set IPC44bits.ADFLTR0IP = 5; in ADC interupt setup, and #pragma config CTXT1 = IPL5 in configuration word (+ context keyword in ISR) is not enought to get context switch in this case. Yesterday my pickit 3 failed (output stage short circuit) maybe it was failing gradually and that was a reason why I cannot see correct register changes during debug. On monday I should have got pickit 4 (and output stage parts for pickit 3) so gonna try it again.
Thanks for Your advice about buffer overflow, I never considered ISR could interfere with read pointer. Im gonna change it to avoid pointer mismatch.
Jump to:
© 2020 APG vNext Commercial Version 4.5