View previous topic :: View next topic |
Author |
Message |
btondin
Joined: 19 May 2016 Posts: 5
|
DSPIC33E Interrupt Priority Issue |
Posted: Thu May 19, 2016 4:30 pm |
|
|
Hello
I'm getting some trouble dealing with the DSPIC33E interrupts. I wrote a code that are intended to generate variable frequency sinusoidal waveform trough PWM in this way: i have a constant PWM frequency of 20KHz (limited by my IGBT module) being generated, a 32bit timer4/5 interrupt that is designated to read a sinus table and send the values to PDC of PWM module. When i change the timer4/5 basetime, i can change the frequency of the sine.
I put the priority of the timer4/5 interrupt in level 6, higher than all the other interrupts, so i supposed that nothing could interfere with the pace of this routine. But when i enable a delay_ms(1000) in the main routine, or i send something via serial, the output of PWM became erratic. Not only extends the sine width, but totally deforms it. The interrupt nesting is enabled. Any suggestion?
Thanks very much
Code: | void myputc(char caract) //My custom putc that are called in printf function
{
while(!U1TXIF);
U1TXREG = caract;
U1TXIF = 0;
}
void Config_UART(int32 baud = 115200) //UART configuration
{
RPOR2 = 1*256; //Configura pino RP39 como TX do UART [pino físico RB7]
RPINR18 = 38;// Configura pino RP38 como RX do UART [pino físico RB6]
STSEL = 0;// 1-Stop bit
PDSEL_1 = 0;// No Parity, 8-Data bits
PDSEL_0 = 0;
ABAUD = 0;// Auto-Baud disabled
BRGH = 0;// Standard-Speed mode
U1BRG = (int16)(FOSC/(32*baud) - 1);
UTXISEL_1 = 0;// Interrupt after one TX character is transmitted
UTXISEL_0 = 0;
URXISEL_1 = 0;// Interrupt after one RX character is received
URXISEL_0 = 0;
U1TXIP_2 = 0; U1TXIP_1 = 0; U1TXIP_0 = 0; //Prioridade 3
U1RXIP_2 = 0; U1RXIP_1 = 0; U1RXIP_0 = 0; //Prioridade 3
//U1TXIE = 1;// Enable UART TX interrupt
//U1RXIE = 1;// Enable UART RX interrupt
UARTEN = 1;// Enable UART
UTXEN = 1;// Enable UART TX
delay_us(50);
}
#INT_TIMER5
void TIMER32Bbit_interrupt(void) //Timer4/5 routine. Sweeps the sinLUT table to generate the sine in the PWM output
{
flag_timer32 = 1;
//PWM1IF = 0; //Desliga flag da interrupção do PWM 1
PDC1 = sinLUT[sinaLUTptr];
PDC2 = sinLUT[sinbLUTptr];
sinaLUTptr++;
sinbLUTptr++;
if(sinaLUTptr == 360) sinaLUTptr = 0;
if(sinbLUTptr == 360) sinbLUTptr = 0;
//LED2 = !LED2;
}
void ConfigTIMER32bit(float freq_sine) //Timer4/5 configuration
{
T32_PERIOD(freq_sine); //Hz
T324 = 1; // Habilita modo 32 bit
TON5 = 0; //Desliga Timer 5
TON4 = 0; //Desliga Timer 4
TGATE4 = 0; //Modo Timer
TCKPS4_1 = 0; TCKPS4_0 = 0; //Prescaler em 1:1
TCS4 = 0; //Clock é Fcy
TMR5 = 0; //Zera registrador de contagem
TMR4 = 0; //Zera registrador de contagem
T5IP_2 = 1; T5IP_1 = 1; T5IP_0 = 0; //Prioridade 6 da interrupção do timer de 32 bit
T5IF = 0; //Limpa flag de interrupção do TIMER 5
T5IE = 1; //Habilita interrupção do TIMER 5
}
void ConfigMEUMCPWM(void) //PWM module config
{
////// Configuração do time base [PTCON]//////
PTEN = 0; // PWM time base OFF
/* Set PWM Period on Primary Time Base */
PTPER = (FOSC/FPWM)/4; // Compute Period for desired frequency (20KHZ) Prescaller 1:4
/* Set Phase Shift */
PHASE1 = 0;
PHASE2 = 0;
PHASE3 = 0;
/* Set Duty Cycles */
PDC1 = 1;
PDC2 = 1;
PDC3 = 1;
/* Set Dead Time Values */
DTR1 = DTR2 = DTR3 = 1; //Deadtime de 10*7.14ns
ALTDTR1 = ALTDTR2 = ALTDTR3 = 1; //Deadtime de 10*7.14ns
/* Set PWM Mode to Complementary */
IOCON1 = IOCON2 = IOCON3 = 0xC000;
/* Set Primary Time Base, Edge-Aligned Mode and Independent Duty Cycles */
PWMCON1 = PWMCON2 = PWMCON3 = 0x0000;
/* Configure Faults */
FCLCON1 = FCLCON2 = FCLCON3 = 0x0003;
/* 1:4 Prescaler */
PTCON2 = 0x0002;
/* Enable PWM Module */
//PTEN = 1;
}
void main(void) //The main code ?!
{
////// CONFIGURAÇÃO DAS PORTAS //////
LATA = 0b0000000000000000;
LATB = 0b0000000000010000;
TRISA = 0b0000000000000001; //Entrada ADC
TRISB = 0b0000000111001100; //RB2 e RB3 entradas do comparador
ANSELA = ANSELB = 0; //Todas as portas sendo digitais
ANSA0 = ANSB2 = ANSB3 = 1; // PORTA.0 sendo analógica
///////// Clock em 70 MIPS com cristal de 12MHZ /////////
CLKDIV = 1; // PLLPOST /2
PLLFBD = 0b0000000001000100; //PLLDIV = 68 + 2
///////////////////////////////////
///// Interrupt Config ////////////
NSTDIS = 0; //Enable interrupt nesting
INT0EP = 0; //Interrupt 0 on POSITIVE edge
INT0IP_2 = 0; //Prioridade 1 para interrupção externa 0
INT0IP_1 = 0;
INT0IP_0 = 1;
INT0IF = 0;
INT0IE = 0; //Desabilitar interrupção externa 0
RPINR0 = 256*40; //Mapear no pino RB8 a entrada da INT1
INT1EP = 0; //Interrupt 1 on POSITIVE edge
INT1IP_2 = 0; //Prioridade 1 para interrupção externa 1
INT1IP_1 = 0;
INT1IP_0 = 1;
INT1IF = 0;
INT1IE = 0; //Desabilitar interrupção externa 1
///////////////////////////////////
delay_ms(10);
//Config_UART(115200);
Config_Comparator();
ConfigMEUMCPWM(); //Configura módulo PWM
ConfigTIMER2(30); //Amostragem
ConfigTIMER32bit(60); //Configura timer de 32 bit (4/5)
TON2 = 1; //Liga TIMER2
Start_PWM();
//INT0IE = 1; // habilita interrupção do encoder
//INT1IE = 1; // habilita interrupção do botão
while(1)
{
//delay_ms(1000);
//printf(myputc, "Teste\n");
}
} |
This code is working well while the delay and printf are commented ;)
CCS 5.025
DSPIC33EP256MC202
Standard Run Mode
3V3
140MHz |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 20, 2016 10:49 am |
|
|
Do you get any compiler warnings regarding interrupts being disabled ?
(Make sure warnings are enabled in your project options). |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Fri May 20, 2016 2:49 pm |
|
|
Just something to try, but have you considered using the built in compiler mechanisms for setting up priority. I don't have time to read through your data sheet, but perhaps you are making a setup mistake.
Try setting the level using the CCS directive:
Code: |
#INT_TIMER5 level=6
void TIMER32Bbit_interrupt(void) //Timer4/5 routine. Sweeps the sinLUT table to generate the sine in the PWM output
{
flag_timer32 = 1;
//PWM1IF = 0; //Desliga flag da interrupção do PWM 1
PDC1 = sinLUT[sinaLUTptr];
PDC2 = sinLUT[sinbLUTptr];
sinaLUTptr++;
sinbLUTptr++;
if(sinaLUTptr == 360) sinaLUTptr = 0;
if(sinbLUTptr == 360) sinbLUTptr = 0;
//LED2 = !LED2;
}
|
enable nesting using:
Code: |
#include <33EP256MC202.h>
#device NESTED_INTERRUPTS=TRUE
|
Position of this directive is important. I needs to be pretty early in the code. You will get compiler errors otherwise.
enable interrupts using the ccs functions:
Code: |
enable_interrupts(INT_TIMER5);
//other interrupt enables here
enable_interrupts(GLOBAL);
|
It helps to start with a smaller program too. As it is you have a lot of lines of code where you could have easily put in a slightly off value.
If it were me, I would start with a program that just had timer5 setup, the timer5 isr toggling an I/O, a second interrupt that triggers a long delay in the ISR (normally delays in an interrupt are bad, but we are testing nesting here, so it is only for testing...not production), and a small main with just enough config for all that plus a while loop with another long delay (a different value than the ISR test delay so you can tell the difference on a scope). CCS supplies functions for all of that.
Then you can see if the toggling happens with the right period or if either the ISR delay or the main delay (or both) inhibit it. If they do, trouble shoot that. Once you figure out what causes it, you can apply that to your actual program. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Sat May 21, 2016 2:24 am |
|
|
I have to agree with Jeremiah.
Classic example of having a C compiler, but trying to program in assembler!.
Each setups for the timers, for example could be done in a single line in CCS.
Learn the language you are using.
Realistically for 99.99% of code you should never have to touch a register directly. The fact that this code does this on just about every line, says 'not yet programming in CCS really'....
The whole code could be written in perhaps 1/4 the number of lines using CCS code.
However I suspect the actual problem is nothing to do with interrupt priorities.
Since there is no diagnostics shown, I'd suspect the chip is actually restarting. Probably stack overflow. |
|
|
btondin
Joined: 19 May 2016 Posts: 5
|
|
Posted: Mon May 23, 2016 10:53 am |
|
|
Thanks very much. I will try to fix the problems using the tips you have given me. I will post the results soon |
|
|
btondin
Joined: 19 May 2016 Posts: 5
|
|
Posted: Mon May 23, 2016 10:55 am |
|
|
PCM programmer wrote: | Do you get any compiler warnings regarding interrupts being disabled ?
(Make sure warnings are enabled in your project options). |
Just warnings about unused variables and condition always TRUE |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Mon May 23, 2016 11:09 am |
|
|
So, just try recompiling with the stack enlarged.
printf, is a heavy user of stack space. Only take an interrupt inside a printf, and the stack usage will leap up.
Add:
#build (stack=256)
After the processor include file.
if it starts working you know what the problem is. |
|
|
btondin
Joined: 19 May 2016 Posts: 5
|
|
Posted: Mon May 23, 2016 11:45 am |
|
|
Ttelmah wrote: | I have to agree with Jeremiah.
Classic example of having a C compiler, but trying to program in assembler!.
Each setups for the timers, for example could be done in a single line in CCS.
Learn the language you are using.
Realistically for 99.99% of code you should never have to touch a register directly. The fact that this code does this on just about every line, says 'not yet programming in CCS really'....
The whole code could be written in perhaps 1/4 the number of lines using CCS code.
However I suspect the actual problem is nothing to do with interrupt priorities.
Since there is no diagnostics shown, I'd suspect the chip is actually restarting. Probably stack overflow. |
I know that using the built in functions of CCS easy the process of programming. But i'm not confortable to be attached to this "arduino" like resource. |
|
|
btondin
Joined: 19 May 2016 Posts: 5
|
|
Posted: Mon May 23, 2016 11:52 am |
|
|
jeremiah wrote: |
enable nesting using:
Code: |
#include <33EP256MC202.h>
#device NESTED_INTERRUPTS=TRUE
|
Position of this directive is important. I needs to be pretty early in the code. You will get compiler errors otherwise.
|
OMG. I replaced the "NSTDIS = 0;" by the "#device NESTED_INTERRUPTS=TRUE" (in the beggining of the code) and everything is working fine. I really want to know what else the compiler did since the only thing i read on datasheet regarding enabling the nesting is keep NSTDIS low.
Thanks very much |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Mon May 23, 2016 4:06 pm |
|
|
btondin wrote: |
OMG. I replaced the "NSTDIS = 0;" by the "#device NESTED_INTERRUPTS=TRUE" (in the beggining of the code) and everything is working fine. I really want to know what else the compiler did since the only thing i read on datasheet regarding enabling the nesting is keep NSTDIS low.
Thanks very much |
To see what the compiler did, look at the LST file between where main starts and your first line of code. It is somewhere between those two points (can probably look for the address of the register the bit lies in). My guess is that there is an unlock sequence or a special order of operations for the bits, but I haven't looked at the datasheet, so that is just a guess.
That said, I know you don't want to rely on the built in features, but that is one of the main reasons to use CCS. If you want to directly manipulate all the registers, you are better off using a compiler that supports that better (like the microchip compiler). Using the built in capabilities of CCS allows the compiler to do more things at compile time, reducing your code footprint and optimizing the code much better than you can.
Ultimately it is up to you, but just wanted to at least help with that suggestion. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Tue May 24, 2016 1:02 am |
|
|
Or, the definitions being used are wrong.....
Could be a simple typo.
However there are quite a few 'deeper' things that have to change once you enable priorities. For instance DISI instructions may need to stop one level and not higher ones. Code used inside the lower priority interrupt routines, may have to disable interrupts around some instructions, that would not apply when priorities are not used. |
|
|
|