Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ARM, C++, IAR. Проблема.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Geniok
Всем добрый день!
Возникла проблема следующего рода. При компиляции проекта на С++, программа стопорится при попытке вызова системного прерывания.
Используется IAR версии 6.40.2, стандартные библиотеки CMSIS.

Конкрентно виснет на функции delay(), которая реализована следующим образом:

Код
// Функция задержки (паузы) в работе
void Delay(__IO uint32_t nTime)
{
    TimingDelay = nTime;

    // Крутимся в бесконечном цикле, пока счетчик
    // оставшегося времени не станет равным нулю.
    // Уменьшение счетчика происходит с помощью
    // прерываний системного таймера.
    while(TimingDelay != 0);
}

// Функция уменьшения счетчика задержки (паузы)
void TimingDelay_Decrement(void)
{
    if (TimingDelay != 0x00)
    {
        TimingDelay--;
    }
}

В файле stm32f4xx_it.c определяем функцию

Код
void SysTick_Handler()
{
    TimingDelay_Decrement();
}


Виснет в файле startup_stm32f4xx.s в блоке

Код
PUBWEAK SysTick_Handler
        SECTION .text:CODE:REORDER(1)
SysTick_Handler
        B SysTick_Handler    ///  !!!!!!!!   Вот тут останавливается исполнение.


То есть как я понимаю, не может найти реализацию функции SysTick_Handler().

Когда проект был на С, данный код работал. Может кто знает, как его заставить работать на С++ ?
_Артём_
Цитата(Geniok @ Nov 12 2012, 00:02) *
То есть как я понимаю, не может найти реализацию функции SysTick_Handler().

Когда проект был на С, данный код работал. Может кто знает, как его заставить работать на С++ ?

Что-то мне кажется что это где-то было...

Можно попробовать например
1)
Код
extern  "C" void SysTick_Handler()
{
//код обработчика
}


2) Вариант посложней
Отредактировать хидеры от ST
Код
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

/*******************************************************************************
**************************   GLOBAL VARIABLES   *******************************
******************************************************************************/

extern uint32_t SystemCoreClock;    /**< System Clock Frequency (Core Clock) */

/*******************************************************************************
*****************************   PROTOTYPES   **********************************
******************************************************************************/

/* Interrupt routines - prototypes */
void Reset_Handler(void);
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
// и так далее
#ifdef __cplusplus
}
#endif

Ну и так далее - думаю там много чего можно добавить или выкинуть.
ReAl
Цитата(Geniok @ Nov 12 2012, 00:02) *
В файле stm32f4xx_it.c определяем функцию

Код
void SysTick_Handler()
{
    TimingDelay_Decrement();
}
Странно. Обработчик-то определен в файле с расширением С, он должен вызываться, только до этого не должно дойти, должна быть ошибка линковки, если TimingDelay_Decrement(); определена в C++ файле.
Или у него в режиме компиляции С++ все файлы компилируются в С++ режиме?
Попробуйте
Код
#ifdef __cplusplus
extern "C"
#endif
void SysTick_Handler()
{
    TimingDelay_Decrement();
}
Geniok
Цитата(_Артём_ @ Nov 12 2012, 02:27) *
Что-то мне кажется что это где-то было...

Можно попробовать например
1)
Код
extern  "C" void SysTick_Handler()
{
//код обработчика
}


Первый вариант помог, спасибо!

На всякий случай, если кому пригодится

в файле stm32f4xx_it.h объявляем

Код
extern  "C"
{
void SysTick_Handler(void);
}


а потом уже в файле stm32f4xx_it.с пишем

Код
extern  "C"
{
void SysTick_Handler()
{
    TimingDelay_Decrement();
}
}


Пробовал такой вариант, в начале файла stm32f4xx_it.с ставить

Код
#ifdef __cplusplus
extern "C" {
#endif


.......


в конце файла

#ifdef __cplusplus
}
#endif


начинают всплывать куча ошибок при компиляции.
_Артём_
Цитата(ReAl @ Nov 12 2012, 00:30) *
Странно. Обработчик-то определен в файле с расширением С, он должен вызываться, только до этого не должно дойти, должна быть ошибка линковки, если TimingDelay_Decrement(); определена в C++ файле.
Или у него в режиме компиляции С++ все файлы компилируются в С++ режиме?

У IAR AVR всегда так было - не особо важно какое расширение файла, если проект С++. С АРМ вроде также.
Geniok
Цитата(ReAl @ Nov 12 2012, 02:30) *
Странно. Обработчик-то определен в файле с расширением С, он должен вызываться, только до этого не должно дойти, должна быть ошибка линковки, если TimingDelay_Decrement(); определена в C++ файле.
Или у него в режиме компиляции С++ все файлы компилируются в С++ режиме?


Скорее всего для С++ компилятора расширения с и срр едины. Ну и соответственно компиляция должна быть в режиме С++.

Цитата(Geniok @ Nov 12 2012, 02:48) *
Вопрос еще возник такой, может кто знает, возможна ли своя замена файла stm32f4xx_it.с ?
То есть возможно ли все обработчики прописать в файле "MyFile.cpp" и чтобы при вызове прерывания перенаправление было туда, а не к stm32f4xx_it.с ?


Ответ уже нашел!

Спасибо всем, кто отозвался!

С Уважением!
Непомнящий Евгений
Цитата(ReAl @ Nov 12 2012, 02:30) *
Странно. Обработчик-то определен в файле с расширением С, он должен вызываться, только до этого не должно дойти, должна быть ошибка линковки, если TimingDelay_Decrement(); определена в C++ файле.
Или у него в режиме компиляции С++ все файлы компилируются в С++ режиме?


Там скорее всего сделано через weak-связывание. Так что он просто не находит обработчик при линковке и использует умолчательный.
Сергей Борщ
QUOTE (Geniok @ Nov 12 2012, 01:30) *
Скорее всего для С++ компилятора расширения с и срр едины. Ну и соответственно компиляция должна быть в режиме С++.
Насколько помню, там в настройках было три варианта:
1)Программист лох, не смог правильно обозвать файлы, на самом деле они все С
2)Программист лох, не смог правильно обозвать файлы, на самом деле они все С++
3)Компилить C/C++в зависимости от расширения файла.

И если вы выбрали один из первых двух - кто злобный Буратина?
MK2
Что бы не плодить лишних тем, рушил написать сюда.
Итак компилятор IAR 6.40 чип stm32f100
часть проекта уже написана на С, и сейчас решил остальное дописать на С++
поэтому поставил в настройках галку Auto на вкладке С/С++ compiler
Нажмите для просмотра прикрепленного файла
и написал простенький класс:
Код
// class.h
#include "stm32f10x.h"

#define MAX_BUF_UART    10

class UART1 {
          protected :
      uint8_t buf [MAX_BUF_UART];
      static uint8_t current, send_point;
          public :
      UART1(void)
      { current = 0;
              send_point = 0; }
      
       uint8_t cop_buf(uint8_t byte);
       void start_send(void);
            };

Код
class.cpp
#include "stm32f10x.h"
#include "class_UART.h"

#define current this->current
#define send_point this->send_point

uint8_t UART1::cop_buf(uint8_t byte)
{      
.....
    buf[current] = byte;
    current++;
    current %= MAX_BUF_UART;
    return 0;
}

void UART1::start_send(void)
{
      for(; send_point != current; send_point++)
      {
                 USART1->DR = buf[send_point];
     while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    
     send_point %= MAX_BUF_UART;
      };
}

void testcpp(void)
{
     UART1 port;
      port.cop_buf('t');
      ......
      port.start_send();
}


далее testcpp() вызываю в в ф-ции main

и ругается линковщик

Код
Error[Li005]: no definition for "testcpp" [referenced from Z:\bla-...-bla-bla\Obj\main.o]


хотя её объявление перед main присутствует;
и еще почему то не удается сделать UART1 port глобальным объектом (вынести перед void testcpp(void))
в этом случае добавляются такие error :
Код
Error[Li005]: no definition for "UART1::current" [referenced from Z:\bla-...-bla-bla\Obj\class_UART.o]
Error[Li005]: no definition for "UART1::send_point" [referenced from Z:\bla-...-bla-bla\Obj\class_UART.o]


что здесь не так? плюсы знаю не очень, как это подружить с IAR?
есть какие-нибудь примеры под него? гугл ничего не дал
_Артём_
Интересно, в чём смысл этих макросов:
Цитата(MK2 @ Nov 22 2012, 20:25) *
#define current this->current
#define send_point this->send_point

?

Цитата(MK2 @ Nov 22 2012, 20:25) *
и еще почему то не удается сделать UART1 port глобальным объектом (вынести перед void testcpp(void))
в этом случае добавляются такие error :
Код
Error[Li005]: no definition for "UART1::current" [referenced from Z:\bla-...-bla-bla\Obj\class_UART.o]
Error[Li005]: no definition for "UART1::send_point" [referenced from Z:\bla-...-bla-bla\Obj\class_UART.o]


что здесь не так? плюсы знаю не очень, как это подружить с IAR?
есть какие-нибудь примеры под него? гугл ничего не дал


Видимо надо объчвить переменные send_point и пт.
Код
uint8_t UART1::send_point;
Сергей Борщ
QUOTE (MK2 @ Nov 22 2012, 20:25) *
далее testcpp() вызываю в в ф-ции main

и ругается линковщик

CODE
Error[Li005]: no definition for "testcpp" [referenced from Z:\bla-...-bla-bla\Obj\main.o]


хотя её объявление перед main присутствует;
А main() находится в .c или .cpp? Если в .c, то в определении функции в файле class.cpp вы должны указать ей спецификатор extern "C":
CODE
extern "C" void testcpp(void)
{
    .....
}

QUOTE (MK2 @ Nov 22 2012, 20:25) *
и еще почему то не удается сделать UART1 port глобальным объектом
Так вы же эти две переменные указали статическими. Зачем - непонятно (буфер у вас нестатический), но раз уж вы их так объявили, то должны и определить их в глобальной области видимости:
CODE
uint8_t UART1::current = 0, UART1::send_point = 0;
UART1 port;

extern "C" void testcpp(void)
{
    .....
}

А то, что ошибки не было когда вы объявляли объект локально объясняется очень просто: ваша функция testcpp() не прилинковывалась и упомянутый в ней объект линкер не использовал.
MK2
Цитата(_Артём_ @ Nov 22 2012, 23:23) *
Интересно, в чём смысл этих макросов:

я поначалу думал что ошибки с переменными идут от того что надо к ним обращаться через указатель this, поэтому что бы не исправлять написал такой макрос

Цитата(Сергей Борщ @ Nov 22 2012, 23:26) *
А main() находится в .c или .cpp? Если в .c, то в определении функции в файле class.cpp вы должны указать ей спецификатор extern "C":

Да, main в .с файле.
extern тоже применял, но только наверно к main ф-ции, сегодня попробую так.

Цитата(Сергей Борщ @ Nov 22 2012, 23:26) *
Так вы же эти две переменные указали статическими. Зачем - непонятно (буфер у вас нестатический),

это мой косяк - буфер должен быть статическим.

Цитата(Сергей Борщ @ Nov 22 2012, 23:26) *
но раз уж вы их так объявили, то должны и определить их в глобальной области видимости:
[code]uint8_t UART1::current = 0, UART1::send_point = 0;
UART1 port;

я их специально в protected объявил, что бы они не были доступны из вне, а теперь они получаются будут глобальными переменными? Или все-таки в пределах модуля, но тогда поидеи перед ними static требуется
_Артём_
Цитата(MK2 @ Nov 22 2012, 23:14) *
Да, main в .с файле.
extern тоже применял, но только наверно к main ф-ции, сегодня попробую так.

Мне так кажется, что ИАРу фиолетово - с или cpp. По крайней мере иногда...

Цитата(MK2 @ Nov 22 2012, 23:14) *
я их специально в protected объявил, что бы они не были доступны из вне, а теперь они получаются будут глобальными переменными?

Глобальными они будут, но доступны будут тольке тем, кому положено.

Цитата(MK2 @ Nov 22 2012, 23:14) *
но тогда поидеи перед ними static требуется

У вас же не Си, и смысл static другой - статическая переменная будет одна на все экземпляры одного типа.
MK2
Программа завелась... правда подвели макросы...
Спасибо большое за разъяснения.
посмотрим дальше как он на статические методы будет реагировать, особенно если это будут обработчиками прерываний wink.gif
_Артём_
Цитата(MK2 @ Nov 23 2012, 13:58) *
посмотрим дальше как он на статические методы будет реагировать, особенно если это будут обработчиками прерываний wink.gif

Реагировать будет: выдаст кучу ошибок - оно ж вроде не можно так делать. Для АВР можно было, а тут почему-то нельзя.

P.S. Если получится выложте пример - интересно посмотреть.
MK2
Цитата(_Артём_ @ Nov 24 2012, 00:04) *
Реагировать будет: выдаст кучу ошибок - оно ж вроде не можно так делать. Для АВР можно было, а тут почему-то нельзя.

Вы правы, не получилось, но ошибок никаких не выдавала, просто взяла и не скомпилировала обработчик хотя специально как в reference manual от иара указал перед ней __irq....
вот это вообще для меня непонятка
Код
class UART1 {
          private :
      static uint8_t buf [MAX_BUF_UART];
      static uint8_t current, send_point;
    __irq static void USART1_IRQHandler(void);
.....

__irq void UART1::USART1_IRQHandler(void)
{
         if(USART_GetITStatus(USART1, USART_IT_RXNE) == RESET)
               return;
....
}

так же не получилось сделать обработчик дружественным к классу, что вообще не в какие ворота!
_Артём_
Цитата(MK2 @ Nov 29 2012, 17:18) *
так же не получилось сделать обработчик дружественным к классу, что вообще не в какие ворота!

Вот это уже странно. Как делали?
Код
class UART1 {
    friend void USART1_IRQHandler();
    // .....
};

Так не получается?
AHTOXA
Вот так точно работает:
Код
extern "C" void USART1_IRQHandler();
class UART1 {
    friend void USART1_IRQHandler();
};

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.