kopia lustrzana https://github.com/OpenRTX/OpenRTX
Miosix: added support for ARM Cortex M7 devices
rodzic
07c4ea6753
commit
04401c6eeb
|
@ -26,3 +26,14 @@ miosix_cm4f_inc = miosix_inc + ['lib/miosix-kernel/miosix/arch/cortexM4F']
|
|||
miosix_cm4f_src = miosix_src + ['lib/miosix-kernel/miosix/arch/cortexM4F/portability.cpp',
|
||||
'lib/miosix-kernel/miosix/arch/common/core/interrupts_cortexMx.cpp']
|
||||
miosix_cm4f_def = miosix_def + {'_ARCH_CORTEXM4' : ''}
|
||||
|
||||
|
||||
##
|
||||
## ARM Cortex M7
|
||||
##
|
||||
miosix_cm7_inc = miosix_inc + ['lib/miosix-kernel/miosix/arch/cortexM7']
|
||||
miosix_cm7_src = miosix_src + ['lib/miosix-kernel/miosix/arch/cortexM7/portability.cpp',
|
||||
'lib/miosix-kernel/miosix/arch/common/core/cache_cortexMx.cpp',
|
||||
'lib/miosix-kernel/miosix/arch/common/core/mpu_cortexMx.cpp',
|
||||
'lib/miosix-kernel/miosix/arch/common/core/interrupts_cortexMx.cpp']
|
||||
miosix_cm7_def = miosix_def + {'_ARCH_CORTEXM7' : ''}
|
||||
|
|
|
@ -122,6 +122,9 @@ void IRQconfigureCache(const unsigned int *xramBase=nullptr, unsigned int xramSi
|
|||
*/
|
||||
inline void markBufferBeforeDmaWrite(const void *buffer, int size)
|
||||
{
|
||||
(void) buffer;
|
||||
(void) size;
|
||||
|
||||
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT==1)
|
||||
// You may think that since the cache is configured as write-through,
|
||||
// there's nothing to do before the DMA can read a memory buffer just
|
||||
|
@ -145,7 +148,11 @@ inline void markBufferBeforeDmaWrite(const void *buffer, int size)
|
|||
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT==1)
|
||||
void markBufferAfterDmaRead(void *buffer, int size);
|
||||
#else
|
||||
inline void markBufferAfterDmaRead(void *buffer, int size) {}
|
||||
inline void markBufferAfterDmaRead(void *buffer, int size)
|
||||
{
|
||||
(void) buffer;
|
||||
(void) size;
|
||||
}
|
||||
#endif
|
||||
|
||||
} //namespace miosix
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2012-2021 by Terraneo Federico *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* As a special exception, if other files instantiate templates or use *
|
||||
* macros or inline functions from this file, or you compile this file *
|
||||
* and link it with other works to produce a work based on this file, *
|
||||
* this file does not by itself cause the resulting work to be covered *
|
||||
* by the GNU General Public License. However the source code for this *
|
||||
* file must still be made available in accordance with the GNU General *
|
||||
* Public License. This exception does not invalidate any other reasons *
|
||||
* why a work based on this file might be covered by the GNU General *
|
||||
* Public License. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace miosix {
|
||||
|
||||
/**
|
||||
* \addtogroup Settings
|
||||
* \{
|
||||
*/
|
||||
|
||||
/// \internal size of vector to store registers during ctx switch
|
||||
/// ((10+16)*4=104Bytes). Only sp, r4-r11, EXC_RETURN and s16-s31 are saved
|
||||
/// here, since r0-r3,r12,lr,pc,xPSR, old sp and s0-s15,fpscr are saved by
|
||||
/// hardware on the process stack on Cortex M4F CPUs. EXC_RETURN, or the lr,
|
||||
/// value to use to return from the exception is necessary to know if the
|
||||
/// thread has used fp regs, as an extension specific to Cortex-M4F CPUs.
|
||||
const unsigned char CTXSAVE_SIZE=10+16;
|
||||
|
||||
/// \internal some architectures save part of the context on their stack.
|
||||
/// ((8+17)*4=100Bytes). This constant is used to increase the stack size by
|
||||
/// the size of context save frame. If zero, this architecture does not save
|
||||
/// anything on stack during context save. Size is in bytes, not words.
|
||||
/// 8 registers=r0-r3,r12,lr,pc,xPSR
|
||||
/// 17 registers=s0-s15,fpscr
|
||||
/// MUST be divisible by 4.
|
||||
const unsigned int CTXSAVE_ON_STACK=(8+17)*4;
|
||||
|
||||
/// \internal stack alignment for this specific architecture
|
||||
const unsigned int CTXSAVE_STACK_ALIGNMENT=8;
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
} //namespace miosix
|
|
@ -0,0 +1,385 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2010-2021 by Terraneo Federico *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* As a special exception, if other files instantiate templates or use *
|
||||
* macros or inline functions from this file, or you compile this file *
|
||||
* and link it with other works to produce a work based on this file, *
|
||||
* this file does not by itself cause the resulting work to be covered *
|
||||
* by the GNU General Public License. However the source code for this *
|
||||
* file must still be made available in accordance with the GNU General *
|
||||
* Public License. This exception does not invalidate any other reasons *
|
||||
* why a work based on this file might be covered by the GNU General *
|
||||
* Public License. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include "interfaces/portability.h"
|
||||
#include "kernel/kernel.h"
|
||||
#include "kernel/error.h"
|
||||
#include "interfaces/bsp.h"
|
||||
#include "kernel/scheduler/scheduler.h"
|
||||
#include "kernel/scheduler/tick_interrupt.h"
|
||||
#include "core/interrupts.h"
|
||||
#include "kernel/process.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* timer interrupt routine.
|
||||
* Since inside naked functions only assembler code is allowed, this function
|
||||
* only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
|
||||
* the implementation code in ISR_preempt()
|
||||
*/
|
||||
void SysTick_Handler() __attribute__((naked));
|
||||
void SysTick_Handler()
|
||||
{
|
||||
saveContext();
|
||||
//Call ISR_preempt(). Name is a C++ mangled name.
|
||||
asm volatile("bl _ZN14miosix_private11ISR_preemptEv");
|
||||
restoreContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* software interrupt routine.
|
||||
* Since inside naked functions only assembler code is allowed, this function
|
||||
* only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
|
||||
* the implementation code in ISR_yield()
|
||||
*/
|
||||
void SVC_Handler() __attribute__((naked));
|
||||
void SVC_Handler()
|
||||
{
|
||||
saveContext();
|
||||
//Call ISR_yield(). Name is a C++ mangled name.
|
||||
asm volatile("bl _ZN14miosix_private9ISR_yieldEv");
|
||||
restoreContext();
|
||||
}
|
||||
|
||||
#ifdef SCHED_TYPE_CONTROL_BASED
|
||||
/**
|
||||
* \internal
|
||||
* Auxiliary timer interupt routine.
|
||||
* Used for variable lenght bursts in control based scheduler.
|
||||
* Since inside naked functions only assembler code is allowed, this function
|
||||
* only calls the ctxsave/ctxrestore macros (which are in assembler), and calls
|
||||
* the implementation code in ISR_yield()
|
||||
*/
|
||||
void TIM3_IRQHandler() __attribute__((naked));
|
||||
void TIM3_IRQHandler()
|
||||
{
|
||||
saveContext();
|
||||
//Call ISR_auxTimer(). Name is a C++ mangled name.
|
||||
asm volatile("bl _ZN14miosix_private12ISR_auxTimerEv");
|
||||
restoreContext();
|
||||
}
|
||||
#endif //SCHED_TYPE_CONTROL_BASED
|
||||
|
||||
namespace miosix_private {
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Called by the timer interrupt, preempt to next thread
|
||||
* Declared noinline to avoid the compiler trying to inline it into the caller,
|
||||
* which would violate the requirement on naked functions. Function is not
|
||||
* static because otherwise the compiler optimizes it out...
|
||||
*/
|
||||
void ISR_preempt() __attribute__((noinline));
|
||||
void ISR_preempt()
|
||||
{
|
||||
IRQstackOverflowCheck();
|
||||
miosix::IRQtickInterrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Called by the software interrupt, yield to next thread
|
||||
* Declared noinline to avoid the compiler trying to inline it into the caller,
|
||||
* which would violate the requirement on naked functions. Function is not
|
||||
* static because otherwise the compiler optimizes it out...
|
||||
*/
|
||||
void ISR_yield() __attribute__((noinline));
|
||||
void ISR_yield()
|
||||
{
|
||||
#ifdef WITH_PROCESSES
|
||||
// WARNING: Temporary fix. Rationale:
|
||||
// This fix is intended to avoid kernel or process faulting due to
|
||||
// another process actions. Consider the case in which a process statically
|
||||
// allocates a big array such that there is no space left for saving
|
||||
// context data. If the process issues a system call, in the following
|
||||
// interrupt the context is saved, but since there is no memory available
|
||||
// for all the context data, a mem manage interrupt is set to 'pending'. Then,
|
||||
// a fake syscall is issued, based on the value read on the stack (which
|
||||
// the process hasn't set due to the memory fault and is likely to be 0);
|
||||
// this syscall is usually a yield (due to the value of 0 above),
|
||||
// which can cause the scheduling of the kernel thread. At this point,
|
||||
// the pending mem fault is issued from the kernel thread, causing the
|
||||
// kernel fault and reboot. This is caused by the mem fault interrupt
|
||||
// having less priority of the other interrupts.
|
||||
// This fix checks if there is a mem fault interrupt pending, and, if so,
|
||||
// it clears it and returns before calling the previously mentioned fake
|
||||
// syscall.
|
||||
if(SCB->SHCSR & (1<<13))
|
||||
{
|
||||
if(miosix::Thread::IRQreportFault(miosix_private::FaultData(
|
||||
MP,0,0)))
|
||||
{
|
||||
SCB->SHCSR &= ~(1<<13); //Clear MEMFAULTPENDED bit
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // WITH_PROCESSES
|
||||
IRQstackOverflowCheck();
|
||||
|
||||
#ifdef WITH_PROCESSES
|
||||
//If processes are enabled, check the content of r3. If zero then it
|
||||
//it is a simple yield, otherwise handle the syscall
|
||||
//Note that it is required to use ctxsave and not cur->ctxsave because
|
||||
//at this time we do not know if the active context is user or kernel
|
||||
unsigned int threadSp=ctxsave[0];
|
||||
unsigned int *processStack=reinterpret_cast<unsigned int*>(threadSp);
|
||||
if(processStack[3]!=miosix::SYS_YIELD)
|
||||
miosix::Thread::IRQhandleSvc(processStack[3]);
|
||||
else miosix::Scheduler::IRQfindNextThread();
|
||||
#else //WITH_PROCESSES
|
||||
miosix::Scheduler::IRQfindNextThread();
|
||||
#endif //WITH_PROCESSES
|
||||
}
|
||||
|
||||
#ifdef SCHED_TYPE_CONTROL_BASED
|
||||
/**
|
||||
* \internal
|
||||
* Auxiliary timer interupt routine.
|
||||
* Used for variable lenght bursts in control based scheduler.
|
||||
*/
|
||||
void ISR_auxTimer() __attribute__((noinline));
|
||||
void ISR_auxTimer()
|
||||
{
|
||||
IRQstackOverflowCheck();
|
||||
miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
|
||||
if(miosix::kernel_running!=0) miosix::tick_skew=true;
|
||||
TIM3->SR=0;
|
||||
}
|
||||
#endif //SCHED_TYPE_CONTROL_BASED
|
||||
|
||||
void IRQstackOverflowCheck()
|
||||
{
|
||||
const unsigned int watermarkSize=miosix::WATERMARK_LEN/sizeof(unsigned int);
|
||||
for(unsigned int i=0;i<watermarkSize;i++)
|
||||
{
|
||||
if(miosix::cur->watermark[i]!=miosix::WATERMARK_FILL)
|
||||
miosix::errorHandler(miosix::STACK_OVERFLOW);
|
||||
}
|
||||
if(miosix::cur->ctxsave[0] < reinterpret_cast<unsigned int>(
|
||||
miosix::cur->watermark+watermarkSize))
|
||||
miosix::errorHandler(miosix::STACK_OVERFLOW);
|
||||
}
|
||||
|
||||
void IRQsystemReboot()
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
|
||||
void *argv)
|
||||
{
|
||||
unsigned int *stackPtr=sp;
|
||||
stackPtr--; //Stack is full descending, so decrement first
|
||||
*stackPtr=0x01000000; stackPtr--; //--> xPSR
|
||||
*stackPtr=reinterpret_cast<unsigned long>(
|
||||
&miosix::Thread::threadLauncher); stackPtr--; //--> pc
|
||||
*stackPtr=0xffffffff; stackPtr--; //--> lr
|
||||
*stackPtr=0; stackPtr--; //--> r12
|
||||
*stackPtr=0; stackPtr--; //--> r3
|
||||
*stackPtr=0; stackPtr--; //--> r2
|
||||
*stackPtr=reinterpret_cast<unsigned long >(argv); stackPtr--; //--> r1
|
||||
*stackPtr=reinterpret_cast<unsigned long >(pc); //--> r0
|
||||
|
||||
ctxsave[0]=reinterpret_cast<unsigned long>(stackPtr); //--> psp
|
||||
//leaving the content of r4-r11 uninitialized
|
||||
ctxsave[9]=0xfffffffd; //EXC_RETURN=thread mode, use psp, no floating ops
|
||||
//leaving the content of s16-s31 uninitialized
|
||||
}
|
||||
|
||||
#ifdef WITH_PROCESSES
|
||||
|
||||
//
|
||||
// class FaultData
|
||||
//
|
||||
|
||||
void FaultData::print() const
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case MP:
|
||||
iprintf("* Attempted data access @ 0x%x (PC was 0x%x)\n",arg,pc);
|
||||
break;
|
||||
case MP_NOADDR:
|
||||
iprintf("* Invalid data access (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case MP_XN:
|
||||
iprintf("* Attempted instruction fetch @ 0x%x\n",pc);
|
||||
break;
|
||||
case UF_DIVZERO:
|
||||
iprintf("* Dvide by zero (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_UNALIGNED:
|
||||
iprintf("* Unaligned memory access (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_COPROC:
|
||||
iprintf("* Attempted coprocessor access (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_EXCRET:
|
||||
iprintf("* Invalid exception return sequence (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_EPSR:
|
||||
iprintf("* Attempted access to the EPSR (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_UNDEF:
|
||||
iprintf("* Undefined instruction (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case UF_UNEXP:
|
||||
iprintf("* Unexpected usage fault (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case HARDFAULT:
|
||||
iprintf("* Hardfault (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
case BF:
|
||||
iprintf("* Busfault @ 0x%x (PC was 0x%x)\n",arg,pc);
|
||||
break;
|
||||
case BF_NOADDR:
|
||||
iprintf("*Busfault (PC was 0x%x)\n",pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void initCtxsave(unsigned int *ctxsave, void *(*pc)(void *), unsigned int *sp,
|
||||
void *argv, unsigned int *gotBase)
|
||||
{
|
||||
unsigned int *stackPtr=sp;
|
||||
stackPtr--; //Stack is full descending, so decrement first
|
||||
*stackPtr=0x01000000; stackPtr--; //--> xPSR
|
||||
*stackPtr=reinterpret_cast<unsigned long>(pc); stackPtr--; //--> pc
|
||||
*stackPtr=0xffffffff; stackPtr--; //--> lr
|
||||
*stackPtr=0; stackPtr--; //--> r12
|
||||
*stackPtr=0; stackPtr--; //--> r3
|
||||
*stackPtr=0; stackPtr--; //--> r2
|
||||
*stackPtr=0; stackPtr--; //--> r1
|
||||
*stackPtr=reinterpret_cast<unsigned long >(argv); //--> r0
|
||||
|
||||
ctxsave[0]=reinterpret_cast<unsigned long>(stackPtr); //--> psp
|
||||
ctxsave[6]=reinterpret_cast<unsigned long>(gotBase); //--> r9
|
||||
//leaving the content of r4-r8,r10-r11 uninitialized
|
||||
ctxsave[9]=0xfffffffd; //EXC_RETURN=thread mode, use psp, no floating ops
|
||||
//leaving the content of s16-s31 uninitialized
|
||||
}
|
||||
|
||||
#endif //WITH_PROCESSES
|
||||
|
||||
void IRQportableStartKernel()
|
||||
{
|
||||
//Enable fault handlers
|
||||
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk
|
||||
| SCB_SHCSR_MEMFAULTENA_Msk;
|
||||
//Enable traps for division by zero. Trap for unaligned memory access
|
||||
//was removed as gcc starting from 4.7.2 generates unaligned accesses by
|
||||
//default (https://www.gnu.org/software/gcc/gcc-4.7/changes.html)
|
||||
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk;
|
||||
NVIC_SetPriorityGrouping(7);//This should disable interrupt nesting
|
||||
NVIC_SetPriority(SVCall_IRQn,3);//High priority for SVC (Max=0, min=15)
|
||||
NVIC_SetPriority(SysTick_IRQn,3);//High priority for SysTick (Max=0, min=15)
|
||||
NVIC_SetPriority(MemoryManagement_IRQn,2);//Higher priority for MemoryManagement (Max=0, min=15)
|
||||
SysTick->LOAD=SystemCoreClock/miosix::TICK_FREQ;
|
||||
//Start SysTick, set to generate interrupts
|
||||
SysTick->CTRL=SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk |
|
||||
SysTick_CTRL_CLKSOURCE_Msk;
|
||||
|
||||
#ifdef WITH_PROCESSES
|
||||
//NOTE: if caches are enabled, the MPU will be enabled also if processes are
|
||||
//not enabled, so this is here for the rare configuration of caches disabled
|
||||
//but processes enabled
|
||||
miosix::IRQenableMPUatBoot();
|
||||
#endif //WITH_PROCESSES
|
||||
#ifdef SCHED_TYPE_CONTROL_BASED
|
||||
AuxiliaryTimer::IRQinit();
|
||||
#endif //SCHED_TYPE_CONTROL_BASED
|
||||
|
||||
//create a temporary space to save current registers. This data is useless
|
||||
//since there's no way to stop the sheduler, but we need to save it anyway.
|
||||
unsigned int s_ctxsave[miosix::CTXSAVE_SIZE];
|
||||
ctxsave=s_ctxsave;//make global ctxsave point to it
|
||||
//Note, we can't use enableInterrupts() now since the call is not mathced
|
||||
//by a call to disableInterrupts()
|
||||
__enable_fault_irq();
|
||||
__enable_irq();
|
||||
miosix::Thread::yield();
|
||||
//Never reaches here
|
||||
}
|
||||
|
||||
void sleepCpu()
|
||||
{
|
||||
__WFI();
|
||||
}
|
||||
|
||||
#ifdef SCHED_TYPE_CONTROL_BASED
|
||||
void AuxiliaryTimer::IRQinit()
|
||||
{
|
||||
RCC->APB1ENR|=RCC_APB1ENR_TIM3EN;
|
||||
RCC_SYNC();
|
||||
DBGMCU->APB1FZ|=DBGMCU_APB1_FZ_DBG_TIM3_STOP; //Tim3 stops while debugging
|
||||
TIM3->CR1=0; //Upcounter, not started, no special options
|
||||
TIM3->CR2=0; //No special options
|
||||
TIM3->SMCR=0; //No external trigger
|
||||
TIM3->CNT=0; //Clear timer
|
||||
//get timer frequency considering APB1 prescaler
|
||||
//consider that timer clock is twice APB1 clock when the APB1 prescaler has
|
||||
//a division factor greater than 2
|
||||
int timerClock=SystemCoreClock;
|
||||
int apb1prescaler=(RCC->CFGR>>10) & 7;
|
||||
if(apb1prescaler>4) timerClock>>=(apb1prescaler-4);
|
||||
TIM3->PSC=(timerClock/miosix::AUX_TIMER_CLOCK)-1;
|
||||
TIM3->ARR=0xffff; //Count from zero to 0xffff
|
||||
TIM3->DIER=TIM_DIER_CC1IE; //Enable interrupt on compare
|
||||
TIM3->CCR1=0xffff; //This will be initialized later with setValue
|
||||
NVIC_SetPriority(TIM3_IRQn,3);//High priority for TIM3 (Max=0, min=15)
|
||||
NVIC_EnableIRQ(TIM3_IRQn);
|
||||
TIM3->CR1=TIM_CR1_CEN; //Start timer
|
||||
//This is very important: without this the prescaler shadow register may
|
||||
//not be updated
|
||||
TIM3->EGR=TIM_EGR_UG;
|
||||
}
|
||||
|
||||
int AuxiliaryTimer::IRQgetValue()
|
||||
{
|
||||
return static_cast<int>(TIM3->CNT);
|
||||
}
|
||||
|
||||
void AuxiliaryTimer::IRQsetValue(int x)
|
||||
{
|
||||
TIM3->CR1=0; //Stop timer since changing CNT or CCR1 while running fails
|
||||
TIM3->CNT=0;
|
||||
TIM3->CCR1=static_cast<unsigned short>(std::min(x,0xffff));
|
||||
TIM3->CR1=TIM_CR1_CEN; //Start timer again
|
||||
//The above instructions cause a spurious if not called within the
|
||||
//timer 2 IRQ (This happens if called from an SVC).
|
||||
//Clearing the pending bit prevents this spurious interrupt
|
||||
TIM3->SR=0;
|
||||
NVIC_ClearPendingIRQ(TIM3_IRQn);
|
||||
}
|
||||
#endif //SCHED_TYPE_CONTROL_BASED
|
||||
|
||||
} //namespace miosix_private
|
|
@ -0,0 +1,207 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2010, 2011, 2012 by Terraneo Federico *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* As a special exception, if other files instantiate templates or use *
|
||||
* macros or inline functions from this file, or you compile this file *
|
||||
* and link it with other works to produce a work based on this file, *
|
||||
* this file does not by itself cause the resulting work to be covered *
|
||||
* by the GNU General Public License. However the source code for this *
|
||||
* file must still be made available in accordance with the GNU General *
|
||||
* Public License. This exception does not invalidate any other reasons *
|
||||
* why a work based on this file might be covered by the GNU General *
|
||||
* Public License. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
//Miosix kernel
|
||||
|
||||
#ifndef PORTABILITY_IMPL_H
|
||||
#define PORTABILITY_IMPL_H
|
||||
|
||||
#include "interfaces/arch_registers.h"
|
||||
#include "interfaces/portability.h"
|
||||
#include "config/miosix_settings.h"
|
||||
|
||||
/**
|
||||
* \addtogroup Drivers
|
||||
* \{
|
||||
*/
|
||||
|
||||
/*
|
||||
* This pointer is used by the kernel, and should not be used by end users.
|
||||
* this is a pointer to a location where to store the thread's registers during
|
||||
* context switch. It requires C linkage to be used inside asm statement.
|
||||
* Registers are saved in the following order:
|
||||
* *ctxsave+100 --> s31
|
||||
* ...
|
||||
* *ctxsave+40 --> s16
|
||||
* *ctxsave+36 --> lr (contains EXC_RETURN whose bit #4 tells if fpu is used)
|
||||
* *ctxsave+32 --> r11
|
||||
* *ctxsave+28 --> r10
|
||||
* *ctxsave+24 --> r9
|
||||
* *ctxsave+20 --> r8
|
||||
* *ctxsave+16 --> r7
|
||||
* *ctxsave+12 --> r6
|
||||
* *ctxsave+8 --> r5
|
||||
* *ctxsave+4 --> r4
|
||||
* *ctxsave+0 --> psp
|
||||
*/
|
||||
extern "C" {
|
||||
extern volatile unsigned int *ctxsave;
|
||||
}
|
||||
const int stackPtrOffsetInCtxsave=0; ///< Allows to locate the stack pointer
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \def saveContext()
|
||||
* Save context from an interrupt<br>
|
||||
* Must be the first line of an IRQ where a context switch can happen.
|
||||
* The IRQ must be "naked" to prevent the compiler from generating context save.
|
||||
*
|
||||
* A note on the dmb instruction, without it a race condition was observed
|
||||
* between pauseKernel() and IRQfindNextThread(). pauseKernel() uses an strex
|
||||
* instruction to store a value in the global variable kernel_running which is
|
||||
* tested by the context switch code in IRQfindNextThread(). Without the memory
|
||||
* barrier IRQfindNextThread() would occasionally read the previous value and
|
||||
* perform a context switch while the kernel was paused, leading to deadlock.
|
||||
* The failure was only observed within the exception_test() in the testsuite
|
||||
* running on the stm32f429zi_stm32f4discovery.
|
||||
*/
|
||||
#define saveContext() \
|
||||
{ \
|
||||
asm volatile(" mrs r1, psp \n"/*get PROCESS stack ptr */ \
|
||||
" ldr r0, =ctxsave \n"/*get current context */ \
|
||||
" ldr r0, [r0] \n" \
|
||||
" stmia r0!, {r1,r4-r11,lr} \n"/*save r1(psp),r4-r11,lr */ \
|
||||
" lsls r2, lr, #27 \n"/*check if bit #4 is set */ \
|
||||
" bmi 0f \n" \
|
||||
" vstmia.32 r0, {s16-s31} \n"/*save s16-s31 if we need*/ \
|
||||
"0: dmb \n" \
|
||||
); \
|
||||
}
|
||||
|
||||
/**
|
||||
* \def restoreContext()
|
||||
* Restore context in an IRQ where saveContext() is used. Must be the last line
|
||||
* of an IRQ where a context switch can happen. The IRQ must be "naked" to
|
||||
* prevent the compiler from generating context restore.
|
||||
*/
|
||||
#define restoreContext() \
|
||||
{ \
|
||||
asm volatile(" ldr r0, =ctxsave \n"/*get current context */ \
|
||||
" ldr r0, [r0] \n" \
|
||||
" ldmia r0!, {r1,r4-r11,lr} \n"/*load r1(psp),r4-r11,lr */ \
|
||||
" lsls r2, lr, #27 \n"/*check if bit #4 is set */ \
|
||||
" bmi 0f \n" \
|
||||
" vldmia.32 r0, {s16-s31} \n"/*restore s16-s31 if need*/ \
|
||||
"0: msr psp, r1 \n"/*restore PROCESS sp*/ \
|
||||
" bx lr \n"/*return*/ \
|
||||
); \
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
namespace miosix_private {
|
||||
|
||||
/**
|
||||
* \addtogroup Drivers
|
||||
* \{
|
||||
*/
|
||||
|
||||
inline void doYield()
|
||||
{
|
||||
asm volatile("movs r3, #0\n\t"
|
||||
"svc 0"
|
||||
:::"r3");
|
||||
}
|
||||
|
||||
inline void doDisableInterrupts()
|
||||
{
|
||||
// Documentation says __disable_irq() disables all interrupts with
|
||||
// configurable priority, so also SysTick and SVC.
|
||||
// No need to disable faults with __disable_fault_irq()
|
||||
__disable_irq();
|
||||
//The new fastDisableInterrupts/fastEnableInterrupts are inline, so there's
|
||||
//the need for a memory barrier to avoid aggressive reordering
|
||||
asm volatile("":::"memory");
|
||||
}
|
||||
|
||||
inline void doEnableInterrupts()
|
||||
{
|
||||
__enable_irq();
|
||||
//The new fastDisableInterrupts/fastEnableInterrupts are inline, so there's
|
||||
//the need for a memory barrier to avoid aggressive reordering
|
||||
asm volatile("":::"memory");
|
||||
}
|
||||
|
||||
inline bool checkAreInterruptsEnabled()
|
||||
{
|
||||
register int i;
|
||||
asm volatile("mrs %0, primask \n\t":"=r"(i));
|
||||
if(i!=0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WITH_PROCESSES
|
||||
|
||||
//
|
||||
// class SyscallParameters
|
||||
//
|
||||
|
||||
inline SyscallParameters::SyscallParameters(unsigned int *context) :
|
||||
registers(reinterpret_cast<unsigned int*>(context[0])) {}
|
||||
|
||||
inline int SyscallParameters::getSyscallId() const
|
||||
{
|
||||
return registers[3];
|
||||
}
|
||||
|
||||
inline unsigned int SyscallParameters::getFirstParameter() const
|
||||
{
|
||||
return registers[0];
|
||||
}
|
||||
|
||||
inline unsigned int SyscallParameters::getSecondParameter() const
|
||||
{
|
||||
return registers[1];
|
||||
}
|
||||
|
||||
inline unsigned int SyscallParameters::getThirdParameter() const
|
||||
{
|
||||
return registers[2];
|
||||
}
|
||||
|
||||
inline void SyscallParameters::setReturnValue(unsigned int ret)
|
||||
{
|
||||
registers[0]=ret;
|
||||
}
|
||||
|
||||
inline void portableSwitchToUserspace()
|
||||
{
|
||||
asm volatile("movs r3, #1\n\t"
|
||||
"svc 0"
|
||||
:::"r3");
|
||||
}
|
||||
|
||||
#endif //WITH_PROCESSES
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
} //namespace miosix_private
|
||||
|
||||
#endif //PORTABILITY_IMPL_H
|
Ładowanie…
Reference in New Issue