Рубрика «HART»

Ведение

Попав в отпуске в город на Неве и посетив множество красивых мест, я все таки, вечерами за чашкой пива, разбирался с UARTом. Тем более, что я купил не плохие наушники Fisher FA011, к которым пришлось прикупить USB SOUND BLASTER X-FI HD и хотел послушать музыку.
Предыдущие статьи вначале переехали на Geektime потом я обратно их перегнал, даже и не знаю, куда теперь их деть :)
Но так на всякий случай они тут:
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 1
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 2 и
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 3 (LCD и Экраны)

UART

После детального изучения микроконтроллера, мне казалось, что все просто. Настройка и тестовая посылка байта в порт прошла без задоринки, все работало как часы, и тут я решил использовать прерывания. Нужно было сделать так, чтобы обработчик прерывания был статическим методом класса. И IAR в руководстве на компилятор, так и писал:

Special function types can be used for static member functions. For example, in the
following example, the function handler is declared as an interrupt function:

class Device
{
 static __irq void handler();
};

Но вот незадача, для Cortex M такой способ не подходит и

On ARM Cortex-M, an interrupt service routine enters and returns in the same way as a
normal function, which means no special keywords are required. Thus, the keywords
__irq, __fiq, and __nested are not available when you compile for ARM Cortex-M.

These exception function names are defined in cstartup_M.c and cstartup_M.s.
They are referred to by the library exception vector code:
NMI_Handler
HardFault_Handler
MemManage_Handler
BusFault_Handler

The vector table is implemented as an array. It should always have the name
__vector_table,

Или по простому, ваш обработчик прерывания должен иметь такое же имя, какое он имеет в таблице векторов определенной в startup файле. Это делается с помощью специального ключевого слова — слабой ссылки __weak (в ассемблере PUBWEAK), которая означает, что данное определение будет использоваться до тех пора, пока не найдется хотя бы одно совпадающее по написанию без ключевого слова __week. Ну т.е., если вы определите функцию с точно таким же именем без этой директивы, то компилятро будет использовать это определение, а если не определите, то которое помечено __weak.
Понятное дело, что я не могу в файл startup_stm32l1xx_md.s или startup_stm32l1xx_md.с вставить С++ имя статического метода типа cUart::USART2_IRQHandler(), ассемблер его просто не поймет.
А просто «USART2_IRQHandler» не совпадает с определением «cUart::USART2_IRQHandler()».
Можно использовать extern «C» { void USART2_IRQHandler(void) {...}}, но это означает, что я тут буду делать встаки из Си, что мне совсем не надо, и вообще доступа из такой функции к атрибутам моего класса, например буферу — не будет, и надо будет городить кучу некрасивого кода :).
Поэтому, я решил пойти другим путем и создать файл startup_stm32l1xx_md.cpp. Поиск в интернете обнаружил, что точно такая же проблема была у некоторых людей
В общем идея заключается в следующем: Определяем startup_stm32l1xx_md.cpp в классы со статическими методами (которые и будут являться обработчиками прерываний), создаем таблицу __vector_table, где на каждом из векторов прерываний стоит указатель на на эти статические методы. Дальше делаем __weak определение каждого метода
И теперь когда в коде компилятор видет реализацию void cUart1::handler(), он не задумываясь берет её. Конечно же при этом ваши классы и методы должны называться точь в точь так, как они определены в startup_stm32l1xx_md.cpp.
Нужно еще не забыть про функции FreeRtos: vPortSVCHandler, xPortPendSVHandler, xPortSysTickHandler и поставить их на нужное прерывание и вуаля — все работает:

startup_stm32l1xx_md.cpp

#pragma language = extended
#pragma segment = "CSTACK"
extern "C" void __iar_program_start( void );
extern "C" void vPortSVCHandler(void);
extern "C" void xPortPendSVHandler(void);
extern "C" void xPortSysTickHandler(void);
class cNMI
{
public:
    static void handler(void);
};
class cHardFault
{
public:
    static void handler(void);
};
class cMemManage
{
public:
    static void handler(void);
};
class cBusFault
{
public:
    static void handler(void);
};
class cUsageFault
{
public:
    static void handler(void);
};
class cDebugMon
{
public:
    static void handler(void);
};
class cWindowWatchdog
{
public:
    static void handler(void);    
};
class cPvd
{
public:
    static void handler(void);    
};
class cTamperTimeStamp
{
public:
    static void handler(void);    
};
class cRtcWakeup
{
public:
    static void handler(void);    
};
class cFlash
{
public:
    static void handler(void);    
};
class cRcc
{
public:
    static void handler(void);    
};
class cExti
{
public:
    static void line0Handler(void);
    static void line1Handler(void);
    static void line2Handler(void);
    static void line3Handler(void);
    static void line4Handler(void);
    static void line9Handler(void);
    static void line15_10Handler(void);
};
class cDma
{
public:
    static void channellHandler(void);    
    static void channel2Handler(void);    
    static void channel3Handler(void);    
    static void channel4Handler(void);    
    static void channel5Handler(void);    
    static void channel6Handler(void);    
    static void channel7Handler(void);    
};
class cAdc
{
public:
    static void handler(void);    
};
class cDac
{
public:
    static void handler(void);    
};
class cUsb
{
public:
    static void highPriorityHandler(void);    
    static void lowPriorityHandler(void);
    static void fsWakeupHandler(void);
};
class cComp
{
public:
    static void handler(void);    
};
class cLcdDriver
{
public:
    static void handler(void);    
};
class cTim9
{
public:
    static void handler(void);    
};
class cTim2
{
public:
    static void handler(void);    
};
class cTim3
{
public:
    static void handler(void);    
};
class cTim4
{
public:
    static void handler(void);    
};
class cTim10
{
public:
    static void handler(void);    
};
class cTim6
{
public:
    static void handler(void);    
};
class cTim7
{
public:
    static void handler(void);    
};
class cTim11
{
public:
    static void handler(void);    
};
class cI2C1
{
public:
    static void eventHandler(void);
    static void errorHandler(void);
};
class cI2C2
{
public:
    static void eventHandler(void);
    static void errorHandler(void);
};
class cSpi1
{
public:
    static void handler(void);    
};
class cSpi2
{
public:
    static void handler(void);    
};
class cUart1
{
public:
    static void handler(void);    
};
class cUart2
{
public:
    static void handler(void);    
};
class cUart3
{
public:
    static void handler(void);    
};
class cRtcAlarm
{
public:
    static void handler(void);    
};
typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;
// The vector table is normally located at address 0.
// When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
// If you need to define interrupt service routines,
// make a copy of this file and include it in your project.
// The name "__vector_table" has special meaning for C-SPY:
// it is where the SP start value is found, and the NVIC vector
// table register (VTOR) is initialized to this address if != 0.
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
  { .__ptr = __sfe( "CSTACK" ) },
  __iar_program_start,

  cNMI::handler,
  cHardFault::handler,
  cMemManage::handler,
  cBusFault::handler,
  cUsageFault::handler,
  0,
  0,
  0,
  0,
  vPortSVCHandler,             //функции freeRTOS не трогать!
  cDebugMon::handler,
  0,
  xPortPendSVHandler,          //функции freeRTOS не трогать!
  xPortSysTickHandler,         //функции freeRTOS не трогать!
  //External Interrupts
  cWindowWatchdog::handler,    //Window Watchdog
  cPvd::handler,               //PVD through EXTI Line detect
  cTamperTimeStamp::handler,   //Tamper and Time Stamp
  cRtcWakeup::handler,         //RTC Wakeup
  cFlash::handler,             //FLASH
  cRcc::handler,               //RCC
  cExti::line0Handler,         //EXTI Line 0
  cExti::line1Handler,         //EXTI Line 1
  cExti::line2Handler,         //EXTI Line 2
  cExti::line3Handler,         //EXTI Line 3
  cExti::line4Handler,         //EXTI Line 4
  cDma::channellHandler,       //DMA1 Channel 1
  cDma::channel2Handler,       //DMA1 Channel 2
  cDma::channel3Handler,       //DMA1 Channel 3
  cDma::channel4Handler,       //DMA1 Channel 4
  cDma::channel5Handler,       //DMA1 Channel 5
  cDma::channel6Handler,       //DMA1 Channel 6
  cDma::channel7Handler,       //DMA1 Channel 7
  cAdc::handler,               //ADC1
  cUsb::highPriorityHandler,   //USB High Priority
  cUsb::lowPriorityHandler,    //USB Low  Priority
  cDac::handler,               //DAC
  cComp::handler,              //COMP through EXTI Line
  cExti::line9Handler,         //EXTI Line 9..5
  cLcdDriver::handler,         //LCD
  cTim9::handler,               //TIM9
  cTim10::handler,             //TIM10
  cTim11::handler,             //TIM11
  cTim2::handler,             //TIM2
  cTim3::handler,              //TIM3
  cTim4::handler,              //TIM4
  cI2C1::eventHandler,         //I2C1 Event
  cI2C1::errorHandler,         //I2C1 Error
  cI2C2::eventHandler,         //I2C2 Event
  cI2C2::errorHandler,         //I2C2 Error
  cSpi1::handler,              //SPI1
  cSpi2::handler,              //SPI2
  cUart1::handler,             //USART1
  cUart2::handler,             //USART2
  cUart3::handler,             //USART3
  cExti::line15_10Handler,     //EXTI Line 15..10
  cRtcAlarm::handler,          //RTC Alarm through EXTI Line
  cUsb::fsWakeupHandler,       //USB FS Wakeup from suspend
  cTim6::handler,              //TIM6
  cTim7::handler                //TIM7
};
__weak void cNMI::handler()          { while (1) {} }
__weak void cHardFault::handler()    { while (1) {} }
__weak void cMemManage::handler()    { while (1) {} }
__weak void cBusFault::handler()     { while (1) {} }
__weak void cUsageFault::handler()   { while (1) {} }
__weak void cDebugMon::handler()     { while (1) {} }
__weak void cWindowWatchdog::handler()  { while (1) {} }
__weak void cPvd::handler()             { while (1) {} }
__weak void cTamperTimeStamp::handler() { while (1) {} }
__weak void cRtcWakeup::handler()       { while (1) {} }
__weak void cFlash::handler()           { while (1) {} }
__weak void cRcc::handler()             { while (1) {} }
__weak void cExti::line0Handler()       { while (1) {} }
__weak void cExti::line1Handler()       { while (1) {} }
__weak void cExti::line2Handler()       { while (1) {} }
__weak void cExti::line3Handler()       { while (1) {} }
__weak void cExti::line4Handler()       { while (1) {} }
__weak void cExti::line9Handler()       { while (1) {} }
__weak void cExti::line15_10Handler()   { while (1) {} }
__weak void cDma::channellHandler()     { while (1) {} }
__weak void cDma::channel2Handler()     { while (1) {} }
__weak void cDma::channel3Handler()     { while (1) {} }
__weak void cDma::channel4Handler()     { while (1) {} }
__weak void cDma::channel5Handler()     { while (1) {} }
__weak void cDma::channel6Handler()     { while (1) {} }
__weak void cDma::channel7Handler()     { while (1) {} }
__weak void cAdc::handler()             { while (1) {} }
__weak void cUsb::fsWakeupHandler()     { while (1) {} }
__weak void cUsb::highPriorityHandler() { while (1) {} }
__weak void cUsb::lowPriorityHandler()  { while (1) {} }
__weak void cDac::handler()             { while (1) {} }
__weak void cComp::handler()            { while (1) {} }
__weak void cLcdDriver::handler()       { while (1) {} }
__weak void cTim2::handler()            { while (1) {} }
__weak void cTim3::handler()            { while (1) {} }
__weak void cTim4::handler()            { while (1) {} }
__weak void cTim6::handler()            { while (1) {} }
__weak void cTim7::handler()            { while (1) {} }
__weak void cTim9::handler()            { while (1) {} }
__weak void cTim10::handler()           { while (1) {} }
__weak void cTim11::handler()           { while (1) {} }
__weak void cI2C1::errorHandler()       { while (1) {} }
__weak void cI2C1::eventHandler()       { while (1) {} }
__weak void cI2C2::errorHandler()       { while (1) {} }
__weak void cI2C2::eventHandler()       { while (1) {} }
__weak void cSpi1::handler()            { while (1) {} }
__weak void cSpi2::handler()            { while (1) {} }
__weak void cUart1::handler()           { while (1) {} }
__weak void cUart2::handler()           { while (1) {} }
__weak void cUart3::handler()           { while (1) {} }
__weak void cRtcAlarm::handler()        { while (1) {} }
extern "C" void __cmain( void );
extern "C" __weak void __iar_init_core( void );
extern "C" __weak void __iar_init_vfp( void );

#pragma required=__vector_table
void __iar_program_start( void )
{
  __iar_init_core();
  __iar_init_vfp();
  __cmain();
}

image

Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js