Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • avn/swd/miosix-kernel
  • emilio.corigliano/miosix-kernel
2 results
Select Git revision
Show changes
Showing
with 2080 additions and 157 deletions
......@@ -99,20 +99,20 @@ void __attribute__((noinline)) HardFault_impl()
#ifdef WITH_ERRLOG
IRQerrorLog("\r\n***Unexpected HardFault @ ");
printUnsignedInt(getProgramCounter());
#ifndef _ARCH_CORTEXM0
#if !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM0_STM32G0) && !defined(_ARCH_CORTEXM0_STM32L0)
unsigned int hfsr=SCB->HFSR;
if(hfsr & 0x40000000) //SCB_HFSR_FORCED
IRQerrorLog("Fault escalation occurred\r\n");
if(hfsr & 0x00000002) //SCB_HFSR_VECTTBL
IRQerrorLog("A BusFault occurred during a vector table read\r\n");
#endif //_ARCH_CORTEXM0
#endif // !_ARCH_CORTEXM0_STM32F0 && !_ARCH_CORTEXM0_STM32G0 && !_ARCH_CORTEXM0_STM32L0
#endif //WITH_ERRLOG
miosix_private::IRQsystemReboot();
}
// Cortex M0/M0+ architecture does not have the interrupts handled by code
// below this point
#ifndef _ARCH_CORTEXM0
#if !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM0_STM32G0) && !defined(_ARCH_CORTEXM0_STM32L0)
void __attribute__((naked)) MemManage_Handler()
{
......@@ -262,7 +262,7 @@ void DebugMon_Handler()
miosix_private::IRQsystemReboot();
}
#endif //_ARCH_CORTEXM0
#endif // !_ARCH_CORTEXM0_STM32F0 && !_ARCH_CORTEXM0_STM32G0 && !_ARCH_CORTEXM0_STM32L0
void PendSV_Handler()
{
......
/***************************************************************************
* Copyright (C) 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 "kernel/kernel.h"
#include "interfaces/os_timer.h"
#include "interfaces/arch_registers.h"
namespace miosix {
class STM32Timer2 : public TimerAdapter<STM32Timer2, 32>
{
public:
static inline unsigned int IRQgetTimerCounter() { return TIM2->CNT; }
static inline void IRQsetTimerCounter(unsigned int v) { TIM2->CNT=v; }
static inline unsigned int IRQgetTimerMatchReg() { return TIM2->CCR1; }
static inline void IRQsetTimerMatchReg(unsigned int v) { TIM2->CCR1=v; }
static inline bool IRQgetOverflowFlag() { return TIM2->SR & TIM_SR_UIF; }
static inline void IRQclearOverflowFlag() { TIM2->SR = ~TIM_SR_UIF; }
static inline bool IRQgetMatchFlag() { return TIM2->SR & TIM_SR_CC1IF; }
static inline void IRQclearMatchFlag() { TIM2->SR = ~TIM_SR_CC1IF; }
static inline void IRQforcePendingIrq() { NVIC_SetPendingIRQ(TIM2_IRQn); }
static inline void IRQstopTimer() { TIM2->CR1 &= ~TIM_CR1_CEN; }
static inline void IRQstartTimer() { TIM2->CR1 |= TIM_CR1_CEN; }
static unsigned int IRQTimerFrequency()
{
// The global variable SystemCoreClock from ARM's CMSIS allows to know
// the CPU frequency.
unsigned int result=SystemCoreClock;
// The timer frequency may however be a submultiple of the CPU frequency,
// due to the bus at whch the periheral is connected being slower. The
// RCC->CFGR register tells us how slower the APB1 bus is running.
// This formula takes into account that if the APB1 clock is divided by a
// factor of two or greater, the timer is clocked at twice the bus
// interface. After this, the freq variable contains the frequency in Hz
// at which the timer prescaler is clocked.
#if _ARCH_CORTEXM0_STM32F0
if(RCC->CFGR & RCC_CFGR_PPRE_2) result/=1<<((RCC->CFGR>>8) & 0x3);
#else
if(RCC->CFGR & RCC_CFGR_PPRE1_2) result/=1<<((RCC->CFGR>>8) & 0x3);
#endif
return result;
}
static void IRQinitTimer()
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC_SYNC();
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP; //Stop while debugging
// Setup TIM2 base configuration
// Mode: Up-counter
// Interrupts: counter overflow, Compare/Capture on channel 1
TIM2->CR1=TIM_CR1_URS;
TIM2->DIER=TIM_DIER_UIE | TIM_DIER_CC1IE;
NVIC_SetPriority(TIM2_IRQn,3); //High priority for TIM2 (Max=0, min=15)
NVIC_EnableIRQ(TIM2_IRQn);
// Configure channel 1 as:
// Output channel (CC1S=0)
// No preload(OC1PE=0), hence TIM2_CCR1 can be written at anytime
// No effect on the output signal on match (OC1M = 0)
TIM2->CCMR1 = 0;
TIM2->CCR1 = 0;
// TIM2 Operation Frequency Configuration: Max Freq. and longest period
TIM2->PSC = 0;
TIM2->ARR = 0xFFFFFFFF;
TIM2->EGR = TIM_EGR_UG; //To enforce the timer to apply PSC
}
};
static STM32Timer2 timer;
DEFAULT_OS_TIMER_INTERFACE_IMPLMENTATION(timer);
} //namespace miosix
void __attribute__((naked)) TIM2_IRQHandler()
{
saveContext();
asm volatile ("bl _Z11osTimerImplv");
restoreContext();
}
void __attribute__((used)) osTimerImpl()
{
miosix::timer.IRQhandler();
}
/***************************************************************************
* Copyright (C) 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 "kernel/kernel.h"
#include "interfaces/os_timer.h"
#include "interfaces/arch_registers.h"
#include "kernel/logging.h"
namespace miosix {
class STM32Timer4 : public TimerAdapter<STM32Timer4, 16>
{
public:
static inline unsigned int IRQgetTimerCounter() { return TIM4->CNT; }
static inline void IRQsetTimerCounter(unsigned int v) { TIM4->CNT=v; }
static inline unsigned int IRQgetTimerMatchReg() { return TIM4->CCR1; }
static inline void IRQsetTimerMatchReg(unsigned int v) { TIM4->CCR1=v; }
static inline bool IRQgetOverflowFlag() { return TIM4->SR & TIM_SR_UIF; }
static inline void IRQclearOverflowFlag() { TIM4->SR = ~TIM_SR_UIF; }
static inline bool IRQgetMatchFlag() { return TIM4->SR & TIM_SR_CC1IF; }
static inline void IRQclearMatchFlag() { TIM4->SR = ~TIM_SR_CC1IF; }
static inline void IRQforcePendingIrq() { NVIC_SetPendingIRQ(TIM4_IRQn); }
static inline void IRQstopTimer() { TIM4->CR1 &= ~TIM_CR1_CEN; }
static inline void IRQstartTimer() { TIM4->CR1 |= TIM_CR1_CEN; }
/*
* These microcontrollers unfortunately do not have a 32bit timer.
* 16bit timers overflow too frequently if clocked at the maximum speed,
* and this is bad both because it nullifies the gains of a tickless kernel
* and because if interrupts are disabled for an entire timer period the
* OS loses the knowledge of time. For this reason, we set the timer clock
* to a lower value using the prescaler.
*/
static const int timerFrequency=1000000; //1MHz
static unsigned int IRQTimerFrequency()
{
return timerFrequency;
}
static void IRQinitTimer()
{
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC_SYNC();
#ifndef _ARCH_CORTEXM3_STM32L1
DBGMCU->CR |= DBGMCU_CR_DBG_TIM4_STOP; //Stop while debugging
#else
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM4_STOP; //Stop while debugging
#endif
// Setup TIM4 base configuration
// Mode: Up-counter
// Interrupts: counter overflow, Compare/Capture on channel 1
TIM4->CR1=TIM_CR1_URS;
TIM4->DIER=TIM_DIER_UIE | TIM_DIER_CC1IE;
NVIC_SetPriority(TIM4_IRQn,3); //High priority for TIM4 (Max=0, min=15)
NVIC_EnableIRQ(TIM4_IRQn);
// Configure channel 1 as:
// Output channel (CC1S=0)
// No preload(OC1PE=0), hence TIM4_CCR1 can be written at anytime
// No effect on the output signal on match (OC1M = 0)
TIM4->CCMR1 = 0;
TIM4->CCR1 = 0;
// TIM4 Operation Frequency Configuration: Max Freq. and longest period
// The global variable SystemCoreClock from ARM's CMSIS allows to know
// the CPU frequency.
unsigned int timerInputFreq=SystemCoreClock;
// The timer frequency may however be a submultiple of the CPU frequency,
// due to the bus at whch the periheral is connected being slower. The
// RCC->CFGR register tells us how slower the APB1 bus is running.
// This formula takes into account that if the APB1 clock is divided by a
// factor of two or greater, the timer is clocked at twice the bus
// interface. After this, the freq variable contains the frequency in Hz
// at which the timer prescaler is clocked.
if(RCC->CFGR & RCC_CFGR_PPRE1_2) timerInputFreq/=1<<((RCC->CFGR>>8) & 0x3);
//Handle the case when the prescribed timer frequency is not achievable.
//For now, we just enter an infinite loop so if someone selects an
//impossible frequency it won't go unnoticed during testing
if(timerInputFreq % timerFrequency)
{
IRQbootlog("Frequency error\r\n");
for(;;) ;
}
TIM4->PSC = (timerInputFreq/timerFrequency)-1;
TIM4->ARR = 0xFFFF;
TIM4->EGR = TIM_EGR_UG; //To enforce the timer to apply PSC
}
};
static STM32Timer4 timer;
DEFAULT_OS_TIMER_INTERFACE_IMPLMENTATION(timer);
} //namespace miosix
void __attribute__((naked)) TIM4_IRQHandler()
{
saveContext();
asm volatile ("bl _Z11osTimerImplv");
restoreContext();
}
void __attribute__((used)) osTimerImpl()
{
miosix::timer.IRQhandler();
}
/***************************************************************************
* Copyright (C) 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 "kernel/kernel.h"
#include "interfaces/os_timer.h"
#include "interfaces/arch_registers.h"
namespace miosix {
class STM32Timer5 : public TimerAdapter<STM32Timer5, 32>
{
public:
static inline unsigned int IRQgetTimerCounter() { return TIM5->CNT; }
static inline void IRQsetTimerCounter(unsigned int v) { TIM5->CNT=v; }
static inline unsigned int IRQgetTimerMatchReg() { return TIM5->CCR1; }
static inline void IRQsetTimerMatchReg(unsigned int v) { TIM5->CCR1=v; }
static inline bool IRQgetOverflowFlag() { return TIM5->SR & TIM_SR_UIF; }
static inline void IRQclearOverflowFlag() { TIM5->SR = ~TIM_SR_UIF; }
static inline bool IRQgetMatchFlag() { return TIM5->SR & TIM_SR_CC1IF; }
static inline void IRQclearMatchFlag() { TIM5->SR = ~TIM_SR_CC1IF; }
static inline void IRQforcePendingIrq() { NVIC_SetPendingIRQ(TIM5_IRQn); }
static inline void IRQstopTimer() { TIM5->CR1 &= ~TIM_CR1_CEN; }
static inline void IRQstartTimer() { TIM5->CR1 |= TIM_CR1_CEN; }
static unsigned int IRQTimerFrequency()
{
// The global variable SystemCoreClock from ARM's CMSIS allows to know
// the CPU frequency.
unsigned int result=SystemCoreClock;
// The timer frequency may however be a submultiple of the CPU frequency,
// due to the bus at whch the periheral is connected being slower. The
// RCC->CFGR register tells us how slower the APB1 bus is running.
// This formula takes into account that if the APB1 clock is divided by a
// factor of two or greater, the timer is clocked at twice the bus
// interface. After this, the freq variable contains the frequency in Hz
// at which the timer prescaler is clocked.
#if defined(_ARCH_CORTEXM7_STM32H7)
if(RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_2) result/=1<<((RCC->D2CFGR>>4) & 0x3);
#else
if(RCC->CFGR & RCC_CFGR_PPRE1_2) result/=1<<((RCC->CFGR>>10) & 0x3);
#endif
return result;
}
static void IRQinitTimer()
{
#if defined(_ARCH_CORTEXM7_STM32H7)
RCC->APB1LENR |= RCC_APB1LENR_TIM5EN;
RCC_SYNC();
DBGMCU->APB1LFZ1 |= DBGMCU_APB1LFZ1_DBG_TIM5; //Stop while debugging
#elif defined(_ARCH_CORTEXM4_STM32L4)
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM5EN;
RCC_SYNC();
DBGMCU->APB1FZR1 |= DBGMCU_APB1FZR1_DBG_TIM5_STOP; //Stop while debugging
#else
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
RCC_SYNC();
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_TIM5_STOP; //Stop while debugging
#endif
// Setup TIM5 base configuration
// Mode: Up-counter
// Interrupts: counter overflow, Compare/Capture on channel 1
TIM5->CR1=TIM_CR1_URS;
TIM5->DIER=TIM_DIER_UIE | TIM_DIER_CC1IE;
NVIC_SetPriority(TIM5_IRQn,3); //High priority for TIM5 (Max=0, min=15)
NVIC_EnableIRQ(TIM5_IRQn);
// Configure channel 1 as:
// Output channel (CC1S=0)
// No preload(OC1PE=0), hence TIM5_CCR1 can be written at anytime
// No effect on the output signal on match (OC1M = 0)
TIM5->CCMR1 = 0;
TIM5->CCR1 = 0;
// TIM5 Operation Frequency Configuration: Max Freq. and longest period
TIM5->PSC = 0;
TIM5->ARR = 0xFFFFFFFF;
TIM5->EGR = TIM_EGR_UG; //To enforce the timer to apply PSC
}
};
static STM32Timer5 timer;
DEFAULT_OS_TIMER_INTERFACE_IMPLMENTATION(timer);
} //namespace miosix
void __attribute__((naked)) TIM5_IRQHandler()
{
saveContext();
asm volatile ("bl _Z11osTimerImplv");
restoreContext();
}
void __attribute__((used)) osTimerImpl()
{
miosix::timer.IRQhandler();
}
......@@ -25,7 +25,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include "sd_stm32f2_f4.h"
#include "sd_stm32f2_f4_f7.h"
#include "interfaces/bsp.h"
#include "interfaces/arch_registers.h"
#include "core/cache_cortexMx.h"
......@@ -52,9 +52,17 @@
*/
#if defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)
#if SD_SDMMC==1
#define SDIO SDMMC1
#define RCC_APB2ENR_SDIOEN RCC_APB2ENR_SDMMC1EN
#define SDIO_IRQn SDMMC1_IRQn
#elif SD_SDMMC==2
#define SDIO SDMMC2
#define RCC_APB2ENR_SDIOEN RCC_APB2ENR_SDMMC2EN
#define SDIO_IRQn SDMMC2_IRQn
#else
#error SD_SDMMC undefined or not in range
#endif
#define SDIO_STA_STBITERR 0 //This bit has been removed
#define SDIO_STA_RXOVERR SDMMC_STA_RXOVERR
......@@ -76,6 +84,7 @@
#define SDIO_CLKCR_CLKEN SDMMC_CLKCR_CLKEN
#define SDIO_CLKCR_PWRSAV SDMMC_CLKCR_PWRSAV
#define SDIO_CLKCR_PWRSAV SDMMC_CLKCR_PWRSAV
#define SDIO_CLKCR_WIDBUS_0 SDMMC_CLKCR_WIDBUS_0
#define SDIO_MASK_STBITERRIE 0 //This bit has been removed
#define SDIO_MASK_RXOVERRIE SDMMC_MASK_RXOVERRIE
......@@ -91,16 +100,32 @@
#define SDIO_POWER_PWRCTRL_1 SDMMC_POWER_PWRCTRL_1
#define SDIO_POWER_PWRCTRL_0 SDMMC_POWER_PWRCTRL_0
constexpr int ICR_FLAGS_CLR=0x5ff;
#else //defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)
constexpr int ICR_FLAGS_CLR=0x7ff;
#endif //defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
#define DMA_Stream DMA2_Stream0
#else
#define DMA_Stream DMA2_Stream3
#endif
/**
* \internal
* DMA2 Stream3 interrupt handler
* DMA2 Stream interrupt handler
*/
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
void __attribute__((naked)) DMA2_Stream0_IRQHandler()
#else
void __attribute__((naked)) DMA2_Stream3_IRQHandler()
#endif
{
saveContext();
asm volatile("bl _ZN6miosix18DMA2stream3irqImplEv");
asm volatile("bl _ZN6miosix12SDDMAirqImplEv");
restoreContext();
}
......@@ -108,14 +133,16 @@ void __attribute__((naked)) DMA2_Stream3_IRQHandler()
* \internal
* SDIO interrupt handler
*/
#if defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==1
void __attribute__((naked)) SDMMC1_IRQHandler()
#elif (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
void __attribute__((naked)) SDMMC2_IRQHandler()
#else //stm32f2 and stm32f4
void __attribute__((naked)) SDIO_IRQHandler()
#endif
{
saveContext();
asm volatile("bl _ZN6miosix11SDIOirqImplEv");
asm volatile("bl _ZN6miosix9SDirqImplEv");
restoreContext();
}
......@@ -130,16 +157,26 @@ static unsigned int sdioFlags; ///< \internal SDIO status flags
* \internal
* DMA2 Stream3 interrupt handler actual implementation
*/
void __attribute__((used)) DMA2stream3irqImpl()
void __attribute__((used)) SDDMAirqImpl()
{
dmaFlags=DMA2->LISR;
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
if(dmaFlags & (DMA_LISR_TEIF0 | DMA_LISR_DMEIF0 | DMA_LISR_FEIF0))
transferError=true;
DMA2->LIFCR = DMA_LIFCR_CTCIF0
| DMA_LIFCR_CTEIF0
| DMA_LIFCR_CDMEIF0
| DMA_LIFCR_CFEIF0;
#else
if(dmaFlags & (DMA_LISR_TEIF3 | DMA_LISR_DMEIF3 | DMA_LISR_FEIF3))
transferError=true;
DMA2->LIFCR=DMA_LIFCR_CTCIF3 |
DMA_LIFCR_CTEIF3 |
DMA_LIFCR_CDMEIF3 |
DMA_LIFCR_CFEIF3;
DMA2->LIFCR = DMA_LIFCR_CTCIF3
| DMA_LIFCR_CTEIF3
| DMA_LIFCR_CDMEIF3
| DMA_LIFCR_CFEIF3;
#endif
if(!waiting) return;
waiting->IRQwakeup();
......@@ -152,14 +189,14 @@ void __attribute__((used)) DMA2stream3irqImpl()
* \internal
* DMA2 Stream3 interrupt handler actual implementation
*/
void __attribute__((used)) SDIOirqImpl()
void __attribute__((used)) SDirqImpl()
{
sdioFlags=SDIO->STA;
if(sdioFlags & (SDIO_STA_STBITERR | SDIO_STA_RXOVERR |
SDIO_STA_TXUNDERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL))
transferError=true;
SDIO->ICR=0x7ff;//Clear flags
SDIO->ICR=ICR_FLAGS_CLR; //Clear flags
if(!waiting) return;
waiting->IRQwakeup();
......@@ -193,12 +230,22 @@ enum CardType
static CardType cardType=Invalid;
//SD card GPIOs
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
typedef Gpio<GPIOG_BASE,9> sdD0;
typedef Gpio<GPIOG_BASE,10> sdD1;
typedef Gpio<GPIOB_BASE,3> sdD2;
typedef Gpio<GPIOB_BASE,4> sdD3;
typedef Gpio<GPIOD_BASE,6> sdCLK;
typedef Gpio<GPIOD_BASE,7> sdCMD;
#else
typedef Gpio<GPIOC_BASE,8> sdD0;
typedef Gpio<GPIOC_BASE,9> sdD1;
typedef Gpio<GPIOC_BASE,10> sdD2;
typedef Gpio<GPIOC_BASE,11> sdD3;
typedef Gpio<GPIOC_BASE,12> sdCLK;
typedef Gpio<GPIOD_BASE,2> sdCMD;
#endif
//
// Class BufferConverter
......@@ -631,12 +678,12 @@ CmdResult Command::send(CommandType cmd, unsigned int arg)
{
if(SDIO->STA & SDIO_STA_CMDSENT)
{
SDIO->ICR=0x7ff;//Clear flags
SDIO->ICR=ICR_FLAGS_CLR;//Clear flags
return CmdResult(cc,CmdResult::Ok);
}
delayUs(1);
}
SDIO->ICR=0x7ff;//Clear flags
SDIO->ICR=ICR_FLAGS_CLR;//Clear flags
return CmdResult(cc,CmdResult::Timeout);
}
......@@ -646,7 +693,7 @@ CmdResult Command::send(CommandType cmd, unsigned int arg)
unsigned int status=SDIO->STA;
if(status & SDIO_STA_CMDREND)
{
SDIO->ICR=0x7ff;//Clear flags
SDIO->ICR=ICR_FLAGS_CLR;//Clear flags
if(SDIO->RESPCMD==cc) return CmdResult(cc,CmdResult::Ok);
else return CmdResult(cc,CmdResult::RespNotMatch);
}
......@@ -754,7 +801,7 @@ private:
#endif //SD_ONE_BIT_DATABUS
///\internal Maximum number of calls to IRQreduceClockSpeed() allowed
static const unsigned char MAX_ALLOWED_REDUCTIONS=1;
static const unsigned char MAX_ALLOWED_REDUCTIONS=5;
///\internal value returned by getRetryCount() while *not* calibrating clock.
static const unsigned char MAX_RETRY=10;
......@@ -768,6 +815,10 @@ private:
void ClockController::calibrateClockSpeed(SDIODriver *sdio)
{
#ifdef SD_DIVIDER
// The frequency will be divided by a factor of SD_DIVIDER + 2
setClockSpeed(SD_DIVIDER);
#else
//During calibration we call readBlock() which will call reduceClockSpeed()
//so not to invalidate calibration clock reduction must not be available
clockReductionAvailable=0;
......@@ -796,6 +847,7 @@ void ClockController::calibrateClockSpeed(SDIODriver *sdio)
setClockSpeed(minFreq);
DBG("Optimal CLKCR=%d\n",minFreq);
}
#endif
//Make clock reduction available
clockReductionAvailable=MAX_ALLOWED_REDUCTIONS;
......@@ -884,11 +936,18 @@ static void displayBlockTransferError()
static unsigned int dmaTransferCommonSetup(const unsigned char *buffer)
{
//Clear both SDIO and DMA interrupt flags
SDIO->ICR=0x7ff;
DMA2->LIFCR=DMA_LIFCR_CTCIF3 |
DMA_LIFCR_CTEIF3 |
DMA_LIFCR_CDMEIF3 |
DMA_LIFCR_CFEIF3;
SDIO->ICR=ICR_FLAGS_CLR;
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
DMA2->LIFCR = DMA_LIFCR_CTCIF0
| DMA_LIFCR_CTEIF0
| DMA_LIFCR_CDMEIF0
| DMA_LIFCR_CFEIF0;
#else
DMA2->LIFCR = DMA_LIFCR_CTCIF3
| DMA_LIFCR_CTEIF3
| DMA_LIFCR_CDMEIF3
| DMA_LIFCR_CFEIF3;
#endif
transferError=false;
dmaFlags=sdioFlags=0;
......@@ -937,24 +996,28 @@ static bool multipleBlockRead(unsigned char *buffer, unsigned int nblk,
SDIO_MASK_TXUNDERRIE | //Interrupt on tx underrun
SDIO_MASK_DCRCFAILIE | //Interrupt on data CRC fail
SDIO_MASK_DTIMEOUTIE; //Interrupt on data timeout
DMA2_Stream3->PAR=reinterpret_cast<unsigned int>(&SDIO->FIFO);
DMA2_Stream3->M0AR=reinterpret_cast<unsigned int>(buffer);
//Note: DMA2_Stream3->NDTR is don't care in peripheral flow control mode
DMA2_Stream3->FCR=DMA_SxFCR_FEIE | //Interrupt on fifo error
DMA_SxFCR_DMDIS | //Fifo enabled
DMA_SxFCR_FTH_0; //Take action if fifo half full
DMA2_Stream3->CR=DMA_SxCR_CHSEL_2 | //Channel 4 (SDIO)
DMA_SxCR_PBURST_0 | //4-beat bursts read from SDIO
DMA_SxCR_PL_0 | //Medium priority DMA stream
memoryTransferSize | //RAM data size depends on alignment
DMA_SxCR_PSIZE_1 | //Read 32bit at a time from SDIO
DMA_SxCR_MINC | //Increment RAM pointer
0 | //Peripheral to memory direction
DMA_SxCR_PFCTRL | //Peripheral is flow controller
DMA_SxCR_TCIE | //Interrupt on transfer complete
DMA_SxCR_TEIE | //Interrupt on transfer error
DMA_SxCR_DMEIE | //Interrupt on direct mode error
DMA_SxCR_EN; //Start the DMA
DMA_Stream->PAR=reinterpret_cast<unsigned int>(&SDIO->FIFO);
DMA_Stream->M0AR=reinterpret_cast<unsigned int>(buffer);
//Note: DMA_Stream->NDTR is don't care in peripheral flow control mode
DMA_Stream->FCR = DMA_SxFCR_FEIE //Interrupt on fifo error
| DMA_SxFCR_DMDIS //Fifo enabled
| DMA_SxFCR_FTH_0; //Take action if fifo half full
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
DMA_Stream->CR = (11 << DMA_SxCR_CHSEL_Pos) //Channel 4 (SDIO)
#else
DMA_Stream->CR = DMA_SxCR_CHSEL_2 //Channel 4 (SDIO)
#endif
| DMA_SxCR_PBURST_0 //4-beat bursts read from SDIO
| DMA_SxCR_PL_0 //Medium priority DMA stream
| memoryTransferSize //RAM data size depends on alignment
| DMA_SxCR_PSIZE_1 //Read 32bit at a time from SDIO
| DMA_SxCR_MINC //Increment RAM pointer
| 0 //Peripheral to memory direction
| DMA_SxCR_PFCTRL //Peripheral is flow controller
| DMA_SxCR_TCIE //Interrupt on transfer complete
| DMA_SxCR_TEIE //Interrupt on transfer error
| DMA_SxCR_DMEIE //Interrupt on direct mode error
| DMA_SxCR_EN; //Start the DMA
SDIO->DLEN=nblk*512;
if(waiting==0)
......@@ -977,8 +1040,8 @@ static bool multipleBlockRead(unsigned char *buffer, unsigned int nblk,
}
}
} else transferError=true;
DMA2_Stream3->CR=0;
while(DMA2_Stream3->CR & DMA_SxCR_EN) ; //DMA may take time to stop
DMA_Stream->CR=0;
while(DMA_Stream->CR & DMA_SxCR_EN) ; //DMA may take time to stop
SDIO->DCTRL=0; //Disable data path state machine
SDIO->MASK=0;
......@@ -1040,26 +1103,30 @@ static bool multipleBlockWrite(const unsigned char *buffer, unsigned int nblk,
SDIO_MASK_TXUNDERRIE | //Interrupt on tx underrun
SDIO_MASK_DCRCFAILIE | //Interrupt on data CRC fail
SDIO_MASK_DTIMEOUTIE; //Interrupt on data timeout
DMA2_Stream3->PAR=reinterpret_cast<unsigned int>(&SDIO->FIFO);
DMA2_Stream3->M0AR=reinterpret_cast<unsigned int>(buffer);
//Note: DMA2_Stream3->NDTR is don't care in peripheral flow control mode
DMA_Stream->PAR=reinterpret_cast<unsigned int>(&SDIO->FIFO);
DMA_Stream->M0AR=reinterpret_cast<unsigned int>(buffer);
//Note: DMA_Stream->NDTR is don't care in peripheral flow control mode
//Quirk: not enabling DMA_SxFCR_FEIE because the SDIO seems to generate
//a spurious fifo error. The code was tested and the transfer completes
//successfully even in the presence of this fifo error
DMA2_Stream3->FCR=DMA_SxFCR_DMDIS | //Fifo enabled
DMA_SxFCR_FTH_1 | //Take action if fifo full
DMA_SxFCR_FTH_0;
DMA2_Stream3->CR=DMA_SxCR_CHSEL_2 | //Channel 4 (SDIO)
DMA_SxCR_PBURST_0 | //4-beat bursts write to SDIO
DMA_SxCR_PL_0 | //Medium priority DMA stream
memoryTransferSize | //RAM data size depends on alignment
DMA_SxCR_PSIZE_1 | //Write 32bit at a time to SDIO
DMA_SxCR_MINC | //Increment RAM pointer
DMA_SxCR_DIR_0 | //Memory to peripheral direction
DMA_SxCR_PFCTRL | //Peripheral is flow controller
DMA_SxCR_TEIE | //Interrupt on transfer error
DMA_SxCR_DMEIE | //Interrupt on direct mode error
DMA_SxCR_EN; //Start the DMA
DMA_Stream->FCR = DMA_SxFCR_DMDIS //Fifo enabled
| DMA_SxFCR_FTH_1 //Take action if fifo full
| DMA_SxFCR_FTH_0;
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
DMA_Stream->CR = (11 << DMA_SxCR_CHSEL_Pos) // Channel 4 (SDIO)
#else
DMA_Stream->CR = DMA_SxCR_CHSEL_2 // Channel 4 (SDIO)
#endif
| DMA_SxCR_PBURST_0 //4-beat bursts write to SDIO
| DMA_SxCR_PL_0 //Medium priority DMA stream
| memoryTransferSize //RAM data size depends on alignment
| DMA_SxCR_PSIZE_1 //Write 32bit at a time to SDIO
| DMA_SxCR_MINC //Increment RAM pointer
| DMA_SxCR_DIR_0 //Memory to peripheral direction
| DMA_SxCR_PFCTRL //Peripheral is flow controller
| DMA_SxCR_TEIE //Interrupt on transfer error
| DMA_SxCR_DMEIE //Interrupt on direct mode error
| DMA_SxCR_EN; //Start the DMA
SDIO->DLEN=nblk*512;
if(waiting==0)
......@@ -1082,8 +1149,8 @@ static bool multipleBlockWrite(const unsigned char *buffer, unsigned int nblk,
}
}
} else transferError=true;
DMA2_Stream3->CR=0;
while(DMA2_Stream3->CR & DMA_SxCR_EN) ; //DMA may take time to stop
DMA_Stream->CR=0;
while(DMA_Stream->CR & DMA_SxCR_EN) ; //DMA may take time to stop
SDIO->DCTRL=0; //Disable data path state machine
SDIO->MASK=0;
......@@ -1161,6 +1228,22 @@ static void initSDIOPeripheral()
RCC_SYNC();
RCC->APB2ENR |= RCC_APB2ENR_SDIOEN;
RCC_SYNC();
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
sdD0::mode(Mode::ALTERNATE);
sdD0::alternateFunction(11);
#ifndef SD_ONE_BIT_DATABUS
sdD1::mode(Mode::ALTERNATE);
sdD1::alternateFunction(11);
sdD2::mode(Mode::ALTERNATE);
sdD2::alternateFunction(10);
sdD3::mode(Mode::ALTERNATE);
sdD3::alternateFunction(10);
#endif // SD_ONE_BIT_DATABUS
sdCLK::mode(Mode::ALTERNATE);
sdCLK::alternateFunction(11);
sdCMD::mode(Mode::ALTERNATE);
sdCMD::alternateFunction(11);
#else
sdD0::mode(Mode::ALTERNATE);
sdD0::alternateFunction(12);
#ifndef SD_ONE_BIT_DATABUS
......@@ -1175,9 +1258,16 @@ static void initSDIOPeripheral()
sdCLK::alternateFunction(12);
sdCMD::mode(Mode::ALTERNATE);
sdCMD::alternateFunction(12);
#endif
}
#if (defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)) && SD_SDMMC==2
NVIC_SetPriority(DMA2_Stream0_IRQn,15);//Low priority for DMA
NVIC_EnableIRQ(DMA2_Stream0_IRQn);
#else
NVIC_SetPriority(DMA2_Stream3_IRQn,15);//Low priority for DMA
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
#endif
NVIC_SetPriority(SDIO_IRQn,15);//Low priority for SDIO
NVIC_EnableIRQ(SDIO_IRQn);
......@@ -1186,7 +1276,11 @@ static void initSDIOPeripheral()
SDIO->CLKCR=0;
SDIO->CMD=0;
SDIO->DCTRL=0;
#if defined(_ARCH_CORTEXM7_STM32F7) || defined(_ARCH_CORTEXM7_STM32H7)
SDIO->ICR=0x4005ff;
#else
SDIO->ICR=0xc007ff;
#endif
SDIO->POWER=SDIO_POWER_PWRCTRL_1 | SDIO_POWER_PWRCTRL_0; //Power on state
//This delay is particularly important: when setting the POWER register a
//glitch on the CMD pin happens. This glitch has a fast fall time and a slow
......
This diff is collapsed.
This diff is collapsed.
......@@ -3,7 +3,7 @@
#ifdef _ARCH_ARM7_LPC2000
#include "serial_lpc2000.h"
#elif defined(_ARCH_CORTEXM0_STM32) || defined(_ARCH_CORTEXM3_STM32) \
#elif defined(_ARCH_CORTEXM0_STM32F0) || defined(_ARCH_CORTEXM3_STM32F1) \
|| defined(_ARCH_CORTEXM4_STM32F4) || defined(_ARCH_CORTEXM3_STM32F2) \
|| defined(_ARCH_CORTEXM3_STM32L1) || defined(_ARCH_CORTEXM7_STM32F7) \
|| defined(_ARCH_CORTEXM7_STM32H7) || defined(_ARCH_CORTEXM4_STM32F3) \
......
......@@ -83,7 +83,7 @@ ATSAMSerial::ATSAMSerial(int id, int baudrate)
port=USART2;
//TODO: USART2 hardcoded
PM->PM_UNLOCK=0xaa<<24 | PM_PBAMASK_OFFSET;
PM->PM_UNLOCK = PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(PM_PBAMASK_OFFSET);
PM->PM_PBAMASK |= PM_PBAMASK_USART2;
NVIC_SetPriority(USART2_IRQn,15);//Lowest priority for serial
NVIC_EnableIRQ(USART2_IRQn);
......@@ -233,7 +233,7 @@ ATSAMSerial::~ATSAMSerial()
//TODO: USART2 hardcoded
NVIC_DisableIRQ(USART2_IRQn);
NVIC_ClearPendingIRQ(USART2_IRQn);
PM->PM_UNLOCK=0xaa<<24 | PM_PBAMASK_OFFSET;
PM->PM_UNLOCK = PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(PM_PBAMASK_OFFSET);
PM->PM_PBAMASK &= ~PM_PBAMASK_USART2;
}
......
......@@ -30,7 +30,6 @@
#include "filesystem/console/console_device.h"
#include "kernel/sync.h"
#include "kernel/queue.h"
#include "board_settings.h"
namespace miosix {
......
......@@ -31,7 +31,6 @@
#include "filesystem/console/console_device.h"
#include "kernel/sync.h"
#include "kernel/queue.h"
#include "board_settings.h"
namespace miosix {
......
......@@ -171,8 +171,9 @@ private:
FastMutex txMutex;///< Mutex used to guard the tx queue
FastMutex rxMutex;///< Mutex used to guard the rx queue
Queue<char,swTxQueue> txQueue;///< Tx software queue
DynUnsyncQueue<char> txQueue;///< Rx software queue
DynUnsyncQueue<char> rxQueue;///< Rx software queue
Thread *txWaiting; ///< Thread waiting on rx queue
Thread *rxWaiting; ///< Thread waiting on rx queue
bool idle; ///< Receiver idle
......
This diff is collapsed.
This diff is collapsed.
......@@ -25,7 +25,6 @@
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include "board_settings.h"
#include "stm32_sgm.h"
#include <string.h>
#include "miosix.h"
......