哈Ha!
几年来,我一直在为C ++中的stm32微控制器系列做所有项目。
在这段时间内,我积累了一些其他开发人员可能感兴趣的材料。
为了避免不必要的问题:我使用了一堆QtCreator + gcc + gdb + openocd。如何使用它已经被描述了很多次,所以我不会止步于此,但是我将向您详细介绍我使用微控制器的方法。
通常,在项目的较低级别上,有外围驱动程序。让我们从他们开始。
如果可能,我会尽量避免与SPL,HAL等怪物混为一谈,但上帝会原谅我CubeMX,只是为了金钱而完成其他人的项目。在我看来,“针对大型机器”框架的思想在那里是恶毒的。通过灵活,易于使用的构想(尽管有人会对此争论),功能变成了相当大且次优的机器代码,在运行时对微控制器执行了许多不必要的操作。是的,现代控制器功能强大,但是用于组装项目的计算机功能强大得多,因此让它执行所有操作。
我为自己确定了实施外围设备管理的基本要求:
- 所有常量表达式都应在编译阶段进行计算,并以数字形式落入机器代码中;
- 编译器必须承担大部分工作,并控制传递给函数的类型;
- 巨集
并不需要 应尽量减少使用,以免削弱类型控制; - 实现编程接口应支持代码可读性。
可能只有懒惰的人没有发明他的自行车来与收割台打交道。这是CMSIS中的一种移位加逻辑运算,并且各种宏都将相同的运算隐藏在复杂的肠子中,并采用ST的库样式。一次,我什至都研究了位字段,直到最终,我想出了一个解决方案,并向您介绍。
在下文中,作为示例,我将使用中文STM32f103所钟爱的STM32f103及其闪存访问控制寄存器(那里是其中之一),因此该示例将简单而简短。

flash CMSIS 72:
FLASH->ACR = (FLASH->ACR &
(~(FLASH_ACR_LATENCY_Msk
| FLASH_ACR_PRFTBE_Msk )))
| FLASH_ACR_LATENCY_1
| FLASH_ACR_PRFTBE;
, ? , - , , . . , , :
0x80001ec 04 4a ldr r2, [pc, #16] ; (0x8000200 <main()+20>)
0x80001ee <+ 2> 13 68 ldr r3, [r2, #0]
0x80001f0 <+ 4> 23 f0 17 03 bic.w r3, r3, #23
0x80001f4 <+ 8> 43 f0 12 03 orr.w r3, r3, #18
0x80001f8 <+ 12> 13 60 str r3, [r2, #0]
, : --. ?
. .
, . . flash :
struct Regs {
uint32_t ACR;
};
:
struct ACR {
constexpr static uint8_t LATENCY[]{ 0, 3 };
constexpr static uint8_t HLFCYA[]{ 3, 1 };
constexpr static uint8_t PRFTBE[]{ 4, 1 };
constexpr static uint8_t PRFTBS[]{ 5, 1 };
};
— , — . Python SVD .
, . constexpr :
constexpr static uint32_t base = 0x40022000;
INLINE constexpr static volatile Regs* rg()
{
return reinterpret_cast<volatile Regs*>(base);
}
base , (, , , , ) . .
INLINE
#ifndef INLINE
#define INLINE __attribute__((__always_inline__)) inline
#endif
, . , , gcc .
flash :
INLINE static void setLatency(Flash::Latency latency, bool prefetchBufferEnable = false)
{
setRegister(rg()->ACR,
ACR::LATENCY, static_cast<uint8_t>(latency),
ACR::PRFTBE, prefetchBufferEnable
);
}
, : , . latency , . static_cast<uint8_t>(latency) , , , Latency :
enum class Latency : uint8_t {
zeroWaitState = 0b000,
oneWaitState = 0b001,
twoWaitStates = 0b010
};
Flash::setLatency(Flash::Latency::twoWaitStates, true);
:
0x80001ec 04 4a ldr r2, [pc, #16] ; (0x8000200 <main()+20>)
0x80001ee <+ 2> 13 68 ldr r3, [r2, #0]
0x80001f0 <+ 4> 23 f0 17 03 bic.w r3, r3, #23
0x80001f4 <+ 8> 43 f0 12 03 orr.w r3, r3, #18
0x80001f8 <+ 12> 13 60 str r3, [r2, #0]
CMSIS: --, .
? setRegister. :
template<typename T, typename V, typename... Args>
INLINE constexpr static void setRegister(volatile uint32_t& reg,
const T field,
const V value,
const Args... args)
{
uint32_t mask = setMaskR(field, value, args...);
uint32_t val = setBitsR(field, value, args...);
reg = (reg & (~mask)) | val;
}
( uint32_t) — . .
:
template<typename V, typename T>
INLINE constexpr static uint32_t setBitsR(T field, V val)
{
return (val << (field[0]));
}
template<typename V, typename T, typename... Args>
INLINE constexpr static uint32_t setBitsR(T field, V val, Args... args)
{
return (val << (field[0])) | setBitsR(args...);
}
template<typename V, typename T>
INLINE constexpr static uint32_t setMaskR(T field, V val)
{
return ((((1 << field[1]) - 1) << field[0]));
}
template<typename V, typename T, typename... Args>
INLINE constexpr static uint32_t setMaskR(T field, V val, Args... args)
{
return ((((1 << field[1]) - 1) << field[0])) | setMaskR(args...);
}
"" . " " , , , , , , .
setRegister? . , - - — . , , , , volatile, , . , , .
. :
Flash::setLatency(Flash::Latency::twoWaitStates, true);
Flash::setLatency(Flash::Latency::oneWaitState, true);
--:
0x80001ec 07 4a ldr r2, [pc, #28] ; (0x800020c <main()+32>)
0x80001ee <+ 2> 13 68 ldr r3, [r2, #0]
0x80001f0 <+ 4> 23 f0 17 03 bic.w r3, r3, #23
0x80001f4 <+ 8> 43 f0 12 03 orr.w r3, r3, #18
0x80001f8 <+ 12> 13 60 str r3, [r2, #0] ;
0x80001fa <+ 14> 13 68 ldr r3, [r2, #0]
0x80001fc <+ 16> 23 f0 17 03 bic.w r3, r3, #23
0x8000200 <+ 20> 43 f0 11 03 orr.w r3, r3, #17
0x8000204 <+ 24> 13 60 str r3, [r2, #0] ;
:
template<typename T>
INLINE constexpr static uint32_t getRegField(volatile uint32_t& reg,
const T field)
{
uint32_t mask = (((1 << field[1]) - 1) << field[0]);
return ((reg & mask) >> field[0]);
}
.
— :
INLINE static bool getLatencyPrefetch()
{
return getRegField(rg()->ACR,
ACR::LATENCY,
ACR::PRFTBE);
}
flash :
struct Flash {
constexpr static uint32_t base = 0x40022000;
struct ACR {
constexpr static uint8_t LATENCY[]{ 0, 3 };
constexpr static uint8_t HLFCYA[]{ 3, 1 };
constexpr static uint8_t PRFTBE[]{ 4, 1 };
constexpr static uint8_t PRFTBS[]{ 5, 1 };
};
enum class Latency : uint8_t {
zeroWaitState = 0b000,
oneWaitState = 0b001,
twoWaitStates = 0b010
};
INLINE constexpr static volatile Regs* rg()
{
return reinterpret_cast<volatile Regs*>(base);
}
INLINE static void setLatency(Flash::Latency latency, bool prefetchBufferEnable = false)
{
Utility::setRegister(rg()->ACR,
ACR::LATENCY, static_cast<uint8_t>(latency),
ACR::PRFTBE, prefetchBufferEnable
);
}
INLINE static bool getLatencyPrefetch()
{
return getRegField(rg()->ACR,
ACR::LATENCY,
ACR::PRFTBE);
}
};
. , , . .
- , .
, . , DSP-. — .