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

Passing variables into ISR's

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



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

Passing variables into ISR's
PostPosted: Fri Jan 27, 2017 3:16 pm     Reply with quote

Using: CCS v5.065 / MPLAB X v3.40 / PIC18F46J50

Is it possible to pass variables ( global or otherwise ) into ISR's using the CCS framework?

An example: I've set up a low-frequency software PWM using CCP and interrupts. I define a static pin PWM_PIN = PIN_A5. The test code cyclically brightens an LED from min to max and then resets back to min.

Code:

#include <18F46J50.h>
#fuses NOWDT,NOPROTECT,NODSBOR
#device PIC18F46J50 ICD=TRUE 
#use delay(internal=8MHz, clock=48MHz)   // Use internal 8MHz osc;  setup CPU clock to 48MHz

#define PWM_PIN PIN_A5

#define PWM_PERIOD   5460L               // 1/48e6 * 4 * 8 = 83.33ns per timer1 tick
                                         // Timer1 divisor of 8 means 666.66ns per timer1 tick
                                         // We want a pwm frequency of 275Hz or period of 3.64ms
                                         // 3.64ms / 2 / 666.66ns = 2730 timer1 ticks
                                         // Aiming for a PWM frequency of 275Hz

float duty = 50;            // Default to 50% duty cycle
volatile float dutyDiv100;
volatile long  high_time;
volatile float cMinusDuty;
volatile long  low_time;

#int_ccp1
void ccp1_isr( void )


    if(!input_state(PWM_PIN)){          // If the pin is low,
        output_high(PWM_PIN);           // Set the pin high ...
        set_compare_time(1, high_time); // .. and change timer to time the low state
    }
    else{
        output_low(PWM_PIN);             // Set the pin low...
        set_compare_time(1, low_time);   // .. change timer to now time the high state
    }
   
    set_timer1(0);                       // Reset the timer1 to start counting from zero
}

long setSoftPwmDuty( float localDuty ){       
    dutyDiv100 = localDuty/100;                 
    high_time  = dutyDiv100 * PWM_PERIOD;
    cMinusDuty = (100 - localDuty)/100;
    low_time   =  cMinusDuty * PWM_PERIOD;
    return high_time, low_time;   
}
                       
void main(void)
{
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);   // Timer1 ticks every 1/48e-6  * 4  * 8 = 666.66ns
                                   
    setup_ccp1(CCP_COMPARE_INT);              // CCP1 setup to interrupt on compare
    output_low(PWM_PIN);                      // Ensure pin starts in OFF state
 
    clear_interrupt(INT_CCP1);
    enable_interrupts(INT_CCP1);             
    enable_interrupts(GLOBAL);
    set_timer1(0);                            // Ensure timer starts at zero
   
    while(1)
    {         
        for(int8 i = 1; i<20; i++){
            setSoftPwmDuty(i*5);
            delay_ms(100);
        }//for
       
       
       
    }//while(1)
   
    return;
 }//main())
     



Now the task is to implement a switch statement inside main() that will choose which pin is the PWM_PIN. Something akin to ...

Code:


// #define PWM_PIN PIN_A6      // Comment this out from above code

int16 PWM_PIN;               // Defined outside of main() as a global

//...within main, while(1) loop ... //
switch( toggleSwitch ){
    case POSITION1:
        PWM_PIN = PIN_A5;
        break;
    case POSITION2:
        PWM_PIN = PIN_E0;
        break;
    case POSITION3:
        PWM_PIN = PIN_E1;
        break;
}




The error I am getting back from the compiler says:

\main.c:381:21: Error#27 Expression must evaluate to a constant ::
\main.c:385:5: Error#51 A numeric expression must appear here


flagged on the line input_state(PWM_PIN) within the ISR.

Either the ISR or the compiler doesn't like the fact that PWM_PIN is a variable. Is there a way to get around this error and be able to pass in a dynamic PWM_PIN for use in the ISR?
temtronic



Joined: 01 Jul 2010
Posts: 9215
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jan 27, 2017 4:23 pm     Reply with quote

Yes, a globally declared variable can be acessed within an ISR.

According to the manual I have , the function "input_state(pin)", pin HAS to be a PIN not a variable.

That would explain the error you've got.
Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 27, 2017 4:25 pm     Reply with quote

It appears that input_state() will not accept a variable for the parameter.
But output_low() and output_high() do. That looks like an oversight
by CCS and they probably should be told of it.

There is a work-around. You can substitute the read_bit_var() macro
as shown below. But keep in mind that if you use variables for the pin
functions, it generates a massive amount of ASM code in the .LST file.
It will be slow. It's better to have a global index, and set that in your
main(), then have a switch-case or if-else structure in the isr to select
the correct block of code to use. The pin functions with constant
parameters are quite compact.
Code:
#include <18F46J50.h>
#fuses HS, NOWDT
#use delay(clock=4M)

// This macro will read a Port pin.  Give it a parameter
// such as PIN_A1, PIN_B0, PIN_C5, etc.
#define read_bit_var(x)  bit_test(*(int8 *)(x >> 3), x & 7)

int16 PWM_PIN;               

#int_ccp1
void ccp1_isr(void)

int8 temp;

temp = read_bit_var(PWM_PIN);   // Use instead of input_state()
output_high(PWM_PIN);         
output_low(PWM_PIN);             
}

//========================================                       
void main(void)
{
PWM_PIN = PIN_A5;

while(TRUE);
}
     
Ttelmah



Joined: 11 Mar 2010
Posts: 19477

View user's profile Send private message

PostPosted: Sat Jan 28, 2017 2:02 am     Reply with quote

However in fact the code will be much tidier just using a toggle.

So:
Code:

#int_ccp1
void ccp1_isr( void )
{
    static int1 toggle=FALSE;
    if (toggle)
    {         
        set_compare_time(1, high_time); // .. and change timer to time the low state
        output_high(PWM_PIN);           // Set the pin high ...
        toggle=FALSE;
    }
    else
    {
        set_compare_time(1, low_time);   // .. change timer to now time the high state
        output_low(PWM_PIN);             // Set the pin low...
        toggle=TRUE;
    }
    //see comment below
    //set_timer1(0);                       // Reset the timer1 to start counting from zero
}


As a comment, use the CCP in 'special event trigger' mode (CCP_COMPARE_RESET_TIMER). You can then get rid of the timer reset in the handler, and timings will be more accurate. This still triggers the CCPIF.
Since the pin I/O will be quite slow with a programmable pin, I've put it after the timer reset.

Use FAST_IO for the port with the PWM pin. This reduces the amount of code for a programmable pin very significantly.

At this point it depends on just how many pins you want to involve?. For perhaps four pins or less, it'll be smaller and faster to just branch in the ISR to routines for the required pins.

Remember if you change the pin number in the code, you should probably as the next instruction set the old pin 'low', otherwise if it was 'on' at the moment you make the change, it'll stay on....
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