Skip to content
This repository has been archived by the owner on Dec 6, 2018. It is now read-only.

stm32f4 IRQ manager correct static members initialization #17

Merged
merged 2 commits into from
Apr 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 17 additions & 7 deletions platform/stm32f4xx/CMakeLists.txt
@@ -1,4 +1,4 @@
add_library(stm32f4xx STATIC platform.cpp)
add_library(stm32f4xx STATIC platform.cpp irq_manager.cpp)
add_library(stm32f4xx_utils STATIC utils.c)

target_include_directories(stm32f4xx PUBLIC export)
Expand Down Expand Up @@ -29,15 +29,25 @@ set(TARGET_PROCESSOR_ARCHITECTURE "arm_cm4" CACHE STRING "Processor arch")
# corresponds to smaller logical priorities)

message(STATUS "Checking [CONFIG_MAX_ISR_PRIORITY]...")
if (NOT DEFINED CONFIG_MAX_ISR_PRIORITY)
if(NOT DEFINED CONFIG_MAX_ISR_PRIORITY)
set(CONFIG_MAX_ISR_PRIORITY 0xff)
message(STATUS "CONFIG_MAX_ISR_PRIORITY not set,"
" using default value: ${CONFIG_MAX_ISR_PRIORITY}")
endif ()

target_compile_definitions(
stm32f4xx
PUBLIC
endif()

message(STATUS "Checking [CONFIG_PLATFORM_DEVICE]...")
if (CONFIG_PLATFORM_DEVICE STREQUAL STM32F40_41xxx)
# Count of user-overridable interrupts.
# For this particular platform it doesn't include system exceptions,
# but only peripheral interrupts. Yet.
target_compile_definitions(stm32f4xx PUBLIC -DCONFIG_IRQ_COUNT=82)
else()
# Additional implementation will be required to cover unsupported
# devices from stm32f4xx line.
message(FATAL_ERROR "Not supported device specified: ${CONFIG_PLATFORM_DEVICE}")
endif()

target_compile_definitions(stm32f4xx PUBLIC
-DCONFIG_MAX_ISR_PRIORITY=${CONFIG_MAX_ISR_PRIORITY})


136 changes: 59 additions & 77 deletions platform/stm32f4xx/export/platform/irq_manager.hpp
@@ -1,10 +1,18 @@
//!
//! \file
//! \brief stm32f4xx IRQ manager.
//!
#ifndef PLATFORM_IRQ_MANAGER_HPP
#define PLATFORM_IRQ_MANAGER_HPP

#include <stm32f4xx.h>
#include <core_cm4.h>

#include <functional>
#include <type_traits>

// TODO: wrap whole module into the namespace
// TODO: convert it to the snake_case

using IRQn_t = IRQn_Type;

Expand All @@ -13,96 +21,70 @@ using IRQn_t = IRQn_Type;
class IRQ_manager
{
public:
using handler_type = std::function< void() >;

// TODO: setup VTOR?
IRQ_manager() = delete;
~IRQ_manager() = delete;

static void init()
{
for (auto &h : m_handlers) {
h = default_handler;
}

__enable_irq();
}

static int subscribe(IRQn_t IRQn, const std::function< void() > &handler)
{
// TODO: error check

__disable_irq();

// Magic here.
// Logical priority of *any* user interrupt that use
// FreeRTOS API must not be greather than
// configMAX_SYSCALL_INTERRUPT_PRIORITY
NVIC_SetPriority(IRQn, CONFIG_MAX_ISR_PRIORITY);
m_handlers[IRQn] = handler;
__enable_irq();
return 0;
}

static int unsubscribe(IRQn_t IRQn)
{
__disable_irq();
m_handlers[IRQn] = default_handler;
__enable_irq();
return 0;
}

static int mask(IRQn_t IRQn)
{
// TODO: error check
NVIC_DisableIRQ(IRQn);
return 0;
}

static int unmask(IRQn_t IRQn)
{
// TODO: error check
NVIC_EnableIRQ(IRQn);
return 0;
}

static int clear(IRQn_t IRQn)
{
// TODO: error check
NVIC_ClearPendingIRQ(static_cast< IRQn_t > (IRQn));
return 0;
}
//! Initializes IRQ manager and setups default handlers for every IRQ.
static void init();

//!
//! \brief Subscribes to given IRQ.
//! \param[in] irqn Valid IRQ number.
//! \param[in] handler New IRQ handler for given IRQ.
//! \retval 0 Success.
//!
static int subscribe(IRQn_t irqn, const handler_type &handler);

//!
//! \brief Unsubscribes from given IRQ.
//! \detail Default handler will be used for given IRQ if this call succeed.
//! \param[in] irqn Valid IRQ number.
//! \retval 0 Success.
//!
static int unsubscribe(IRQn_t irqn);

//!
//! \brief Masks or disables given IRQ.
//! \param[in] irqn Valid IRQ number.
//! \retval 0 Success.
//!
static int mask(IRQn_t irqn);

//!
//! \brief Unmasks or enables given IRQ.
//! \param[in] irqn Valid IRQ number.
//! \retval 0 Success.
//!
static int unmask(IRQn_t irqn);

//!
//! \brief Clears pending interrupt of given IRQ.
//! \param[in] irqn Valid IRQ number.
//! \retval 0 Success.
//!
static int clear(IRQn_t irqn);

private:
// Prevent optimizing out an ISR routine
__attribute__ ((used)) static void ISR()
{
volatile int IRQn;
using handler_storage =
std::aligned_storage< sizeof(handler_type), alignof(handler_type) >::type;

asm volatile (
"mrs %0, ipsr" : "=r" (IRQn)
);
// Prevent optimizing out an ISR routine
__attribute__ ((used)) void isr();

// IPSR holds exception numbers starting from 0
// Valid IRQ number starts from -15
// See Cortex-M4 processors documentation
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDBIBGJ.html
IRQn -= 16;
//! Default iRQ handler. Terminates execution if called.
static void default_handler();

// TODO: Is it needed?
mask(static_cast< IRQn_t >(IRQn));
m_handlers[IRQn]();
}
//! Storage for registered IRQ handlers.
static handler_storage m_storage[CONFIG_IRQ_COUNT];

static void default_handler()
static constexpr auto extract_handlers()
{
__disable_irq();
for(;;);
return reinterpret_cast< handler_type* >(&m_storage);
}

// Registered IRQ handlers
// TODO: magic numbers
static std::function< void() > m_handlers[82];
};



#endif
113 changes: 113 additions & 0 deletions platform/stm32f4xx/irq_manager.cpp
@@ -0,0 +1,113 @@
#include <platform/irq_manager.hpp>
#include <new>

IRQ_manager::handler_storage IRQ_manager::m_storage[CONFIG_IRQ_COUNT];


void IRQ_manager::init()
{
// Initialize storage
for (auto &h : m_storage) {
new (&h) handler_type{default_handler};
}

__enable_irq();
}

int IRQ_manager::subscribe(IRQn_t irqn, const std::function< void() > &handler)
{
Copy link
Collaborator

@vadimol vadimol Apr 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

irqn can be negative (as IRQn_t defined in stm32f4xx.h). Would be nice to add a check at least.

Does this also mean that I can't set a custom handler for first 15 interrupts (say UsageFault_IRQn) ?

Copy link
Collaborator Author

@forGGe forGGe Apr 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IRQ manager in current implementation doesn't support handling of system exceptions. To subscribe for exception events one may override handlers at compile time via the weak symbol mechanism.

// TODO: Use platform assert when it will be ready
if (irqn < 0) {
return -1;
}

auto handlers = extract_handlers();

__disable_irq();

// Magic here.
// Logical priority of *any* user interrupt that use
// FreeRTOS API must not be greather than
// configMAX_SYSCALL_INTERRUPT_PRIORITY
NVIC_SetPriority(irqn, CONFIG_MAX_ISR_PRIORITY);
handlers[irqn] = handler;
__enable_irq();
return 0;
}

int IRQ_manager::unsubscribe(IRQn_t irqn)
{
// TODO: Use platform assert when it will be ready
if (irqn < 0) {
return -1;
}

auto handlers = extract_handlers();
__disable_irq();
handlers[irqn] = default_handler;
__enable_irq();
return 0;
}

int IRQ_manager::mask(IRQn_t irqn)
{
// TODO: Use platform assert when it will be ready
if (irqn < 0) {
return -1;
}

NVIC_DisableIRQ(irqn);
return 0;
}

int IRQ_manager::unmask(IRQn_t irqn)
{
// TODO: Use platform assert when it will be ready
if (irqn < 0) {
return -1;
}

// TODO: error check
NVIC_EnableIRQ(irqn);
return 0;
}

int IRQ_manager::clear(IRQn_t irqn)
{
// TODO: Use platform assert when it will be ready
if (irqn < 0) {
return -1;
}

// TODO: error check
NVIC_ClearPendingIRQ(static_cast< IRQn_t > (irqn));
return 0;
}

//------------------------------------------------------------------------------

void IRQ_manager::isr()
{
volatile int irqn;
auto handlers = extract_handlers();

asm volatile (
"mrs %0, ipsr" : "=r" (irqn)
);

// IPSR holds exception numbers starting from 0
// Valid IRQ number starts from -15
// See Cortex-M4 processors documentation
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDBIBGJ.html
irqn -= 16;

// TODO: Is it needed?
mask(static_cast< IRQn_t >(irqn));
handlers[irqn]();
}

void IRQ_manager::default_handler()
{
__disable_irq();
for(;;);
}
7 changes: 4 additions & 3 deletions platform/stm32f4xx/platform.cpp
Expand Up @@ -3,14 +3,15 @@
#include <misc.h>
#include <core_cm4.h>

// TODO: move it elsewhere
std::function< void() > IRQ_manager::m_handlers[82];

// TODO: decide if to make as a class member or not
extern "C" __attribute__((used)) void platform_init()
{
// Required for FreeRTOS
// TODO: find better place for it
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

// IRQ must be ready before anything else will start work
IRQ_manager::init();
}

namespace ecl
Expand Down
2 changes: 1 addition & 1 deletion platform/stm32f4xx/startup/start.s
Expand Up @@ -64,7 +64,7 @@ clear_bss_end:
.long PendSV_Handler /* PendSV Handler */
.long SysTick_Handler /* SysTick Handler */
.rept 81 @ Repeat ASM statement
.long _ZN11IRQ_manager3ISREv @ All other handlers
.long _ZN11IRQ_manager3isrEv @ All other handlers
.endr
.align

Expand Down
13 changes: 5 additions & 8 deletions sys/sys.cpp
Expand Up @@ -8,15 +8,15 @@
// TODO: move it somewhere
void operator delete(void *)
{
// Abort - delete is forbidden
for (;;);
// TODO: call to abort routine
for(;;);
}

// TODO: move it somewhere
void operator delete(void *, unsigned int)
{
// Abort - delete is forbidden
for (;;);
// TODO: call to abort routine
for(;;);
}

// TODO: move this to toolchain-dependent module
Expand All @@ -33,7 +33,7 @@ uintptr_t __stack_chk_guard = STACK_CHK_GUARD;
extern "C" __attribute__((noreturn))
void __stack_chk_fail(void)
{
ecl::cout << "Fail!!!" << ecl::endl;
// TODO: call to abort routine
for(;;);
}

Expand Down Expand Up @@ -97,12 +97,9 @@ extern "C" void core_main(void)
((void (*)()) *p)();
}

IRQ_manager::init();

// Due to undefined static init order, this initialization is placed here
ecl::console_device.init();


kernel_main();
}

Expand Down