Modification of Mbed-dev library for LQFP48 package microcontrollers: STM32F103C8 (STM32F103C8T6) and STM32F103CB (STM32F103CBT6) (Bluepill boards, Maple mini etc. )

Fork of mbed-STM32F103C8_org by Nothing Special

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CThunk.h Source File

CThunk.h

00001 
00002 /** \addtogroup platform */
00003 /** @{*/
00004 /* General C++ Object Thunking class
00005  *
00006  * - allows direct callbacks to non-static C++ class functions
00007  * - keeps track for the corresponding class instance
00008  * - supports an optional context parameter for the called function
00009  * - ideally suited for class object receiving interrupts (NVIC_SetVector)
00010  *
00011  * Copyright (c) 2014-2015 ARM Limited
00012  *
00013  * Licensed under the Apache License, Version 2.0 (the "License");
00014  * you may not use this file except in compliance with the License.
00015  * You may obtain a copy of the License at
00016  *
00017  *     http://www.apache.org/licenses/LICENSE-2.0
00018  *
00019  * Unless required by applicable law or agreed to in writing, software
00020  * distributed under the License is distributed on an "AS IS" BASIS,
00021  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00022  * See the License for the specific language governing permissions and
00023  * limitations under the License.
00024  */
00025 
00026 /* General C++ Object Thunking class
00027  *
00028  * - allows direct callbacks to non-static C++ class functions
00029  * - keeps track for the corresponding class instance
00030  * - supports an optional context parameter for the called function
00031  * - ideally suited for class object receiving interrupts (NVIC_SetVector)
00032  */
00033 
00034 #ifndef __CTHUNK_H__
00035 #define __CTHUNK_H__
00036 
00037 #define CTHUNK_ADDRESS 1
00038 #define CTHUNK_VARIABLES volatile uint32_t code[2]
00039 
00040 #if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__CORTEX_M7) || defined(__CORTEX_A9))
00041 /**
00042 * CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2):
00043 * * adr  r0, #4
00044 * * ldm  r0, {r0, r1, r2, pc}
00045 *
00046 * This instruction loads the arguments for the static thunking function to r0-r2, and
00047 * branches to that function by loading its address into PC.
00048 *
00049 * This is safe for both regular calling and interrupt calling, since it only touches scratch registers
00050 * which should be saved by the caller, and are automatically saved as part of the IRQ context switch.
00051 */
00052 #define CTHUNK_ASSIGMENT do {                              \
00053                              m_thunk.code[0] = 0xE890A001; \
00054                              m_thunk.code[1] = 0x00008007; \
00055                          } while (0)
00056 
00057 #elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0))
00058 /*
00059 * CTHUNK disassembly for Cortex M0/M0+ (thumb):
00060 * * adr  r0, #4
00061 * * ldm  r0, {r0, r1, r2, r3}
00062 * * bx   r3
00063 */
00064 #define CTHUNK_ASSIGMENT do {                              \
00065                              m_thunk.code[0] = 0xC80FA001; \
00066                              m_thunk.code[1] = 0x00004718; \
00067                          } while (0)
00068 
00069 #else
00070 #error "Target is not currently suported."
00071 #endif
00072 
00073 /* IRQ/Exception compatible thunk entry function */
00074 typedef void (*CThunkEntry)(void);
00075 
00076 /**
00077  * Class for created a pointer with data bound to it
00078  *
00079  * @Note Synchronization level: Not protected
00080  */
00081 template<class T>
00082 class CThunk
00083 {
00084     public:
00085         typedef void (T::*CCallbackSimple)(void);
00086         typedef void (T::*CCallback)(void* context);
00087 
00088         inline CThunk(T *instance)
00089         {
00090             init(instance, NULL, NULL);
00091         }
00092 
00093         inline CThunk(T *instance, CCallback callback)
00094         {
00095             init(instance, callback, NULL);
00096         }
00097 
00098         ~CThunk() {
00099 
00100         }
00101 
00102         inline CThunk(T *instance, CCallbackSimple callback)
00103         {
00104             init(instance, (CCallback)callback, NULL);
00105         }
00106 
00107         inline CThunk(T &instance, CCallback callback)
00108         {
00109             init(instance, callback, NULL);
00110         }
00111 
00112         inline CThunk(T &instance, CCallbackSimple callback)
00113         {
00114             init(instance, (CCallback)callback, NULL);
00115         }
00116 
00117         inline CThunk(T &instance, CCallback callback, void* context)
00118         {
00119             init(instance, callback, context);
00120         }
00121 
00122         inline void callback(CCallback callback)
00123         {
00124             m_callback = callback;
00125         }
00126 
00127         inline void callback(CCallbackSimple callback)
00128         {
00129             m_callback = (CCallback)callback;
00130         }
00131 
00132         inline void context(void* context)
00133         {
00134             m_thunk.context = (uint32_t)context;
00135         }
00136 
00137         inline void context(uint32_t context)
00138         {
00139             m_thunk.context = context;
00140         }
00141         
00142         inline uint32_t entry(void)
00143         {
00144             return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
00145         }
00146 
00147         /* get thunk entry point for connecting rhunk to an IRQ table */
00148         inline operator CThunkEntry(void)
00149         {
00150             return (CThunkEntry)entry();
00151         }
00152 
00153         /* get thunk entry point for connecting rhunk to an IRQ table */
00154         inline operator uint32_t(void)
00155         {
00156             return entry();
00157         }
00158 
00159         /* simple test function */
00160         inline void call(void)
00161         {
00162             (((CThunkEntry)(entry()))());
00163         }
00164 
00165     private:
00166         T* m_instance;
00167         volatile CCallback m_callback;
00168 
00169 // TODO: this needs proper fix, to refactor toolchain header file and all its use
00170 // PACKED there is not defined properly for IAR
00171 #if defined (__ICCARM__)
00172         typedef __packed struct
00173         {
00174             CTHUNK_VARIABLES;
00175             volatile uint32_t instance;
00176             volatile uint32_t context;
00177             volatile uint32_t callback;
00178             volatile uint32_t trampoline;
00179         }  CThunkTrampoline;
00180 #else
00181         typedef struct
00182         {
00183             CTHUNK_VARIABLES;
00184             volatile uint32_t instance;
00185             volatile uint32_t context;
00186             volatile uint32_t callback;
00187             volatile uint32_t trampoline;
00188         } __attribute__((__packed__)) CThunkTrampoline;
00189 #endif
00190 
00191         static void trampoline(T* instance, void* context, CCallback* callback)
00192         {
00193             if(instance && *callback) {
00194                 (static_cast<T*>(instance)->**callback)(context);
00195             }
00196         }
00197 
00198         volatile CThunkTrampoline m_thunk;
00199 
00200         inline void init(T *instance, CCallback callback, void* context)
00201         {
00202             /* remember callback - need to add this level of redirection
00203                as pointer size for member functions differs between platforms */
00204             m_callback = callback;
00205 
00206             /* populate thunking trampoline */
00207             CTHUNK_ASSIGMENT;
00208             m_thunk.context = (uint32_t)context;
00209             m_thunk.instance = (uint32_t)instance;
00210             m_thunk.callback = (uint32_t)&m_callback;
00211             m_thunk.trampoline = (uint32_t)&trampoline;
00212 
00213 #if defined(__CORTEX_A9)
00214             /* Data cache clean */
00215             /* Cache control */
00216             {
00217                 uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0;
00218                 uint32_t end_addr   = (uint32_t)&m_thunk + sizeof(m_thunk);
00219                 uint32_t addr;
00220                 
00221                 /* Data cache clean and invalid */
00222                 for (addr = start_addr; addr < end_addr; addr += 0x20) {
00223                     __v7_clean_inv_dcache_mva((void *)addr);
00224                 }
00225                 /* Instruction cache invalid */
00226                 __v7_inv_icache_all();
00227                 __ca9u_inv_tlb_all();
00228                 __v7_inv_btac();
00229             }
00230 #endif
00231 #if defined(__CORTEX_M7)
00232             /* Data cache clean and invalid */
00233             SCB_CleanInvalidateDCache();
00234 
00235             /* Instruction cache invalid */
00236             SCB_InvalidateICache();
00237 #endif
00238             __ISB();
00239             __DSB();
00240         }
00241 };
00242 
00243 #endif/*__CTHUNK_H__*/
00244 
00245 /** @}*/