Sonsivri
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
December 03, 2016, 01:18:55 01:18


Login with username, password and session length


Pages: [1]
Print
Author Topic: extern "C" Question  (Read 1223 times)
0 Members and 1 Guest are viewing this topic.
LzEn
Junior Member
**
Offline Offline

Posts: 78

Thank You
-Given: 45
-Receive: 82


Lazy Efficient


« on: October 21, 2014, 09:53:35 09:53 »

After spending 2 days trying to figure out why my STM32L1 EXTI is not branching to my IRQHandler, I found out the problem. First I will state I am new to the ARM architecture, and probably my first time writing C++ code for MCUs.

So back to the problem, it turned out that there was a linker problem. I added an ' extern "C" ' in front of the IRQHandler and now it works normally.
Can someone please explain to me in some basic language what did this 'extern "C"' do exactly. Why C++ could not link the functions together.

Code:
extern "C" void EXTI0_IRQHandler(void)
{
     if (EXTI->PR & (1<<0))
   {                        
        EXTI->PR |= (1<<0);                          
        Led1.Set();

   }
}

extern "C" void EXTI9_5_IRQHandler(void)
{
if (EXTI->PR & (1<<6))
{                      
                EXTI->PR |= (1<<6);                          
Led1.Toggle();

        }
}

Thanks.
Logged

~ Laziness Is The Mother Of Efficiency ~
hate
Hero Member
*****
Offline Offline

Posts: 556

Thank You
-Given: 156
-Receive: 354


« Reply #1 on: October 21, 2014, 11:04:21 11:04 »

In brief, C++ compiler adds extra information to function headers i.e. class information to distinguish functions of different classes with the same name. C compiler doesn't normally add anything to the headers as there is normally nothing needed. Adding 'extern C' takes care of that issue basically. It tells the C++ compiler not to mangle the function header so external C code can be linked successfully.

Edit: Using 'extern C' on interrupt handlers doesn't seem right, I believe the compiler should take care of that. Have you checked other examples on interrupt syntax?
« Last Edit: October 21, 2014, 11:14:07 11:14 by hate » Logged

Regards...
LzEn
Junior Member
**
Offline Offline

Posts: 78

Thank You
-Given: 45
-Receive: 82


Lazy Efficient


« Reply #2 on: October 21, 2014, 11:31:46 11:31 »

Ahh makes sense, thanks for the clear answer and right to the point.

After I found the problem, I read in many places of people having the same problem and it was fixed with the extern C. I didn't try a C code yet, but I tried many different codes. I am actually writing to the registers directly now, so I don't think the problem can be elsewhere. But I will check again, with some example code.

That is what I am doing exactly, the code is just for testing so it is not in its best shape :

Code:
//MCU : STM32L151
//The user will pass pin and port enumeration that I created. On my turn I will enable the corresponding Interrupt.
// The user will also pass an Edge for the interrupt.

RCC->APB2ENR |=  (1ul << 0);                   // Enable SYSCFG clock
SYSCFG->EXTICR[registerIndex] &= ~(15ul      << 4* (pinIndex %4));    //pinIndex is an enumaration on Pins I created
SYSCFG->EXTICR[registerIndex] |=  (portIndex << 4* (pinIndex %4));   
EXTI->IMR |= (1ul << pinIndex);
switch(edgeLevel)
{
case FALLING_EDGE:
       EXTI->RTSR |= (1ul << pinIndex);
break;
case RISING_EDGE:
EXTI->FTSR |= (1ul << pinIndex);
break;
case BOTH_EDGES:
EXTI->RTSR |= (1ul << pinIndex);
EXTI->FTSR |= (1ul << pinIndex);
break;
}

if(pinIndex == 0)
{
    NVIC_SetPriority(EXTI0_IRQn,priority);
    NVIC_EnableIRQ(EXTI0_IRQn);
}
else if (pinIndex ==1)
{
NVIC_SetPriority(EXTI1_IRQn,priority);
NVIC_EnableIRQ(EXTI1_IRQn);
}
else if(pinIndex ==2)
{
NVIC_SetPriority(EXTI2_IRQn,priority);
NVIC_EnableIRQ(EXTI2_IRQn);
}
else if(pinIndex ==3)
{
NVIC_SetPriority(EXTI3_IRQn,priority);
NVIC_EnableIRQ(EXTI3_IRQn);
}
else if(pinIndex ==4)
{
NVIC_SetPriority(EXTI4_IRQn,priority);
NVIC_EnableIRQ(EXTI4_IRQn);
}
else if(pinIndex >4 && pinIndex <=9 )
{
NVIC_SetPriority(EXTI9_5_IRQn,priority);
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
else if(pinIndex >9 && pinIndex <=15 )
{
NVIC_SetPriority(EXTI15_10_IRQn,priority);
NVIC_EnableIRQ(EXTI15_10_IRQn);
}


Here are the enumerations, nothing special:
Code:
typedef enum PINn
{
PIN0,
PIN1,
PIN2,
PIN3,
PIN4,
PIN5,
PIN6,
PIN7,
PIN8,
PIN9,
PIN10,
PIN11,
PIN12,
PIN13,
PIN14,
PIN15,
}PINn_Type;

typedef enum PORTn
{
  PORTA,
  PORTB,
  PORTC,
  PORTD,
  PORTE
}PORTn_Type;

Logged

~ Laziness Is The Mother Of Efficiency ~
hate
Hero Member
*****
Offline Offline

Posts: 556

Thank You
-Given: 156
-Receive: 354


« Reply #3 on: October 21, 2014, 11:57:12 11:57 »

I checked the links below and it seems using 'extern C' on interrupt handlers is the official way of doing things. Although seems strange, quite logical.
http://embdev.net/topic/191474
http://processors.wiki.ti.com/index.php/Invoke_a_C%2B%2B_Class_Member_Function_from_an_Interrupt

Sorry for the trouble, it's my lack of C++ experience with microcontrollers.
Logged

Regards...
LzEn
Junior Member
**
Offline Offline

Posts: 78

Thank You
-Given: 45
-Receive: 82


Lazy Efficient


« Reply #4 on: October 21, 2014, 12:48:27 12:48 »

I checked the links below and it seems using 'extern C' on interrupt handlers is the official way of doing things. Although seems strange, quite logical.
http://embdev.net/topic/191474
http://processors.wiki.ti.com/index.php/Invoke_a_C%2B%2B_Class_Member_Function_from_an_Interrupt

Sorry for the trouble, it's my lack of C++ experience with microcontrollers.


No trouble at all, on the contrary. I was looking for some solid link about it, the one you provided from TI should do the trick.
Thanks again, helped a lot.
Logged

~ Laziness Is The Mother Of Efficiency ~
nPn
Newbie
*
 Warned
Offline Offline

Posts: 10

Thank You
-Given: 6
-Receive: 2


« Reply #5 on: October 25, 2014, 02:57:18 02:57 »

For future reference, "nm" utility in GNU tools lets you see symbols contained in binary objects, which helps when debugging this kind of thing.

In ARM I'd do "arm-none-eabi-nm main.o" to see symbols contained and referenced in file main.o.

And I should see "00000000 T Start" for Start symbol in T (.text section). If you have C++ symbols it looks like "00000000 T _ZN3Foo5StartEv" so if you pipe into arm-none-eabi-c++filt you get "Foo::Start()." Of course if object from C file reference _ZN3Foo5StartEv it won't work so you use extern "C" to make it C linkage and match reference.
Logged
ficho
Newbie
*
Offline Offline

Posts: 19

Thank You
-Given: 6
-Receive: 6


« Reply #6 on: September 23, 2016, 09:43:47 09:43 »

HI,
It depends also witch compiler you are using, try to find compilers manual.
Lot of things are explained in it...
regards ficho
Logged
bobcat1
Active Member
***
Offline Offline

Posts: 151

Thank You
-Given: 1117
-Receive: 29


« Reply #7 on: September 25, 2016, 09:02:46 09:02 »

The best way is NOT to use EXTERN to access variable or function in your code
It will save lot of bugs and debugging time
I always use module functions to access variables or structure with in the code 
Logged
Pages: [1]
Print
Jump to:  


DISCLAIMER
WE DONT HOST ANY ILLEGAL FILES ON THE SERVER
USE CONTACT US TO REPORT ILLEGAL FILES
ADMINISTRATORS CANNOT BE HELD RESPONSIBLE FOR USERS POSTS AND LINKS

... Copyright 2003-2999 Sonsivri.to ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC