go_away

Author Topic: Mixing C and assembly  (Read 2106 times)

0 Members and 1 Guest are viewing this topic.

Offline dsPICgyTopic starter

  • Beginner
  • *
  • Posts: 4
  • Helpful? 0
Mixing C and assembly
« on: January 07, 2009, 06:22:11 AM »
Dear all,

I am confused with how project with mixed C and assembly is handled in Microchip C30. I have a very simple project that uses TMR1 interrupt to toggle an LED. I tried this project on dsPIC3312GP202 which is used in Microchip 16-bit 28-pin Starter kit.

I have a project that contains two files, one coded with C language and the other one coded in assembly. The C listing is as follows (main.c)

#include "P33FJ12GP202.h"

/*
 * Internal FRC Oscillator
 *
 */
_FOSCSEL(FNOSC_FRC);
/*
 * Clock switching is enabled and fail-safe clock monitor is disabled
 * OSC2 pin function: OSC2 is clock output
 * Primary oscillator mode is disabled
 *
 */
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF  & POSCMD_NONE);
/*
 * Watchdog timer is disabled
 *
 */
_FWDT(FWDTEN_OFF);

/*
 * Function prototypes
 *
 */
void initialisePorts( void );
void initialiseTimer1( void );
void performClockSwitching( void );

/*
 * Main program entry
 *
 */
int main( void ) {

    /*
     * Initialise clock-switching
     *
     */
    performClockSwitching();

    /*
     * Initialise port direction and value
     *
     */
    initialisePorts();

    /*
     * Initialise Timer1
     *
     */
    initialiseTimer1();

    /*
     * Loop here doing nothing - waiting for Timer1 interrupt to occur
     *
     */
    while (1) {
    }
   
    return 0;
}

/*
 * Initialise input and output ports
 *
 */
void initialisePorts( void ) {
    /*
     * At the moment we are only interested in port B, where
     *  o Pin 5  - incoming data
     *  o Pin 6  - re-timed data
     *  o Pin 10 - recovered clock
     *  o Pin 12 - LED4
     *  o Pin 13 - LED3
     *  o Pin 14 - LED2
     *  o Pin 15 - LED1
     *
     * Note 0 - output, 1 - input
     *
     */
    TRISB = 0b0000101110111111;

    /*
     * Initial value of port B
     *
     */
    LATB = 0xF000;
}

/*
 * Initialise Timer1
 * Interrupt Service Routine will be called when Timer1 overflows
 *
 */
void initialiseTimer1( void ) {
    TMR1 = 0x00;
    PR1  = 53;           /* timer preload value */

    /*
     * T1CON register
     *
     *  bit | Value | Description
     * -----+-------+--------------------------------------
     *  15  |   1   | TON - enable Timer1
     *  14  |   0   | Reserved
     *  13  |   0   | TSIDL - Not stop in idle mode
     * 12-7 |000000 | Reserved
     *   6  |   0   | TSYNC - sync to ext. clock disabled
     *  5-4 |  00   | TCKPS - prescaler of 1:1
     *  3-2 |  00   | Reserved
     *   1  |   0   | TCS - Internal clock as source
     *   0  |   0   | Reserved
     *
     */
     T1CON = 0b1000000000000000;

     /*
      * Set Timer1 interrupt priority
      *
      */
     IPC0 &= 0x0FFF;
     IPC0 ^= 0x1000;

     /*
      * Clear Timer1 interrupt flag and enable Timer1
      *
      */
     IFS0bits.T1IF = 0;
     IEC0bits.T1IE = 1;
}

/*
 * Perform clock switching
 *
 */
void performClockSwitching( void ) {
 OSCTUN = 0;     /* Tune FRC oscillator, if FRC is used */
   
    /*
     * Configure oscillator to operate the device at Fcy = 40Mhz
     * Fosc = Fin*M/(N1*N2)
     * Fcy = Fosc/2
     * Fosc = 7.37Mhz * 43/(2 * 2) = 80MHz for 7.37MHz input clock
     *
     */
 PLLFBD = 43;    /* M = 43 */
 CLKDIVbits.PLLPOST = 0;  /* N1 = 2 */
 CLKDIVbits.PLLPRE = 0;  /* N2 = 2 */

    /*
     * Disable Watch Dog Timer
     *
     */
 RCONbits.SWDTEN = 0;

    /*
     * Initiate clock switch to FRC with PLL
     * NOSC = 0b001
     *
     */
 __builtin_write_OSCCONH(0b001);

    /*
     * Start clock switching
     *
     */
 __builtin_write_OSCCONL(0b001);

    /*
     * Wait for clock switch to occur
     *
     */
 while (OSCCONbits.COSC != 0b001)

    /*
     * Wait for PLL to lock
     *
     */
 while(OSCCONbits.LOCK!=1) {};
}


The assembly listing (T1Interrupt.s) contains the ISR of TMR1. All it does is to clear TMR1 interrupt flag and toggle an LED. The listing is as follows

   .text

      .include "p33FJ12GP202.inc"

;--------------------------------------------------------------------
; T1Interrupt - ISR of Timer1
;
;--------------------------------------------------------------------
__T1Interrupt:

             bclr IFS0, #T1IF                   ; clear interrupt flag
         
             btg  PORTB, #15
         
             retfie                             ; Return from interrupt

             .end

I built the project and then programmed with using RealICE to my starter kit. Everytime when I ran this project, it would be halted almost immediately.


However, instead of coding TMR1 ISR in assembly, if I added the following code to main.c and remove T1Interrupt.s from the project, the project ran perfectly.

void __attribute__((__interrupt__)) __attribute__((no_auto_psv)) _T1Interrupt( void )
{
    LATB ^= 0x8000;

 /* reset Timer 1 interrupt flag */
  IFS0bits.T1IF = 0;
}

Any idea why?

I look forward to hearing your feedback.


Thanks
dsPICgy

Offline cosminprund

  • Robot Overlord
  • ****
  • Posts: 284
  • Helpful? 8
Re: Mixing C and assembly
« Reply #1 on: January 07, 2009, 11:54:34 AM »
What are you confused about?
Any ideas about what?
You're confused about something in the code or about how the compiler manages to generate code from two distinct files, one in C and one in Assembler?
« Last Edit: January 07, 2009, 11:55:44 AM by cosminprund »

Offline dsPICgyTopic starter

  • Beginner
  • *
  • Posts: 4
  • Helpful? 0
Re: Mixing C and assembly
« Reply #2 on: January 07, 2009, 01:44:02 PM »
Thanks for your reply. I was confused on why two same programs did not behave in the same way. One written as a mix of C and assembly, and the other one C only.

Anyway I have figured out the answer. The assembly code requires a function declaration of the ISR, otherwise default ISR will be executed. This explains why the program halts as soon as it is run.


 


Get Your Ad Here

data_list