InterruptManager.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* mbed Microcontroller Library
  2. * Copyright (c) 2006-2013 ARM Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "cmsis.h"
  17. #if defined(NVIC_NUM_VECTORS)
  18. // Suppress deprecation warnings since this whole
  19. // class is deprecated already
  20. #include "mbed_toolchain.h"
  21. #undef MBED_DEPRECATED_SINCE
  22. #define MBED_DEPRECATED_SINCE(...)
  23. #include "drivers/InterruptManager.h"
  24. #include "platform/mbed_critical.h"
  25. #include <string.h>
  26. #define CHAIN_INITIAL_SIZE 4
  27. namespace mbed {
  28. typedef void (*pvoidf)(void);
  29. InterruptManager *InterruptManager::_instance = (InterruptManager *)NULL;
  30. InterruptManager *InterruptManager::get()
  31. {
  32. if (NULL == _instance) {
  33. InterruptManager *temp = new InterruptManager();
  34. // Atomically set _instance
  35. core_util_critical_section_enter();
  36. if (NULL == _instance) {
  37. _instance = temp;
  38. }
  39. core_util_critical_section_exit();
  40. // Another thread got there first so delete ours
  41. if (temp != _instance) {
  42. delete temp;
  43. }
  44. }
  45. return _instance;
  46. }
  47. InterruptManager::InterruptManager()
  48. {
  49. // No mutex needed in constructor
  50. memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain *));
  51. }
  52. void InterruptManager::destroy()
  53. {
  54. // Not a good idea to call this unless NO interrupt at all
  55. // is under the control of the handler; otherwise, a system crash
  56. // is very likely to occur
  57. if (NULL != _instance) {
  58. delete _instance;
  59. _instance = (InterruptManager *)NULL;
  60. }
  61. }
  62. InterruptManager::~InterruptManager()
  63. {
  64. for (int i = 0; i < NVIC_NUM_VECTORS; i++)
  65. if (NULL != _chains[i]) {
  66. delete _chains[i];
  67. }
  68. }
  69. bool InterruptManager::must_replace_vector(IRQn_Type irq)
  70. {
  71. lock();
  72. int ret = false;
  73. int irq_pos = get_irq_index(irq);
  74. if (NULL == _chains[irq_pos]) {
  75. _chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE);
  76. _chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq));
  77. ret = true;
  78. }
  79. unlock();
  80. return ret;
  81. }
  82. pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front)
  83. {
  84. lock();
  85. int irq_pos = get_irq_index(irq);
  86. bool change = must_replace_vector(irq);
  87. pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function);
  88. if (change) {
  89. NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
  90. }
  91. unlock();
  92. return pf;
  93. }
  94. bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq)
  95. {
  96. int irq_pos = get_irq_index(irq);
  97. bool ret = false;
  98. lock();
  99. if (_chains[irq_pos] != NULL) {
  100. if (_chains[irq_pos]->remove(handler)) {
  101. ret = true;
  102. }
  103. }
  104. unlock();
  105. return ret;
  106. }
  107. void InterruptManager::irq_helper()
  108. {
  109. _chains[__get_IPSR()]->call();
  110. }
  111. int InterruptManager::get_irq_index(IRQn_Type irq)
  112. {
  113. // Pure function - no lock needed
  114. return (int)irq + NVIC_USER_IRQ_OFFSET;
  115. }
  116. void InterruptManager::static_irq_helper()
  117. {
  118. InterruptManager::get()->irq_helper();
  119. }
  120. void InterruptManager::lock()
  121. {
  122. _mutex.lock();
  123. }
  124. void InterruptManager::unlock()
  125. {
  126. _mutex.unlock();
  127. }
  128. } // namespace mbed
  129. #endif