今天,我们将讨论一种时尚的产品-RIS-V微控制器。我一直很想了解这个内核,并等待类似于STM32的出现,现在我等待,见面-中国的GigaDevice-GD32V。
该微控制器的基础设施不如STM32广泛,但您需要具备入门所需的一切。幸运的是,例如,可以在alikexpress上订购调试板,例如:Longan Nano GD32VF103CBT6 RISC-V MCU
中国人正在推广此微控制器的Platform IO开发环境,该环境可以作为Visual Studio Code的扩展提供。但是我们不会使用它,这不是根据工程概念,我们是工程师,我们想自己弄清楚它。因此,让我们尝试在IAR上运行该板,从头开始编写所有内容。
顺便说一下,IAR正在分发调试工具包(调试板+ I-Jet调试器+ 30天完整许可证)IAR RISC-V GD32V评估工具包。您可以在此处留下“开发工具请求”。不知道他们是否将工具包发送给所有人,但是我们在5天内收到了它。谢谢他们!
好吧,有兴趣的人,欢迎下切
介绍
CortexM, - IAR ( IAR ), , , .
— , . , , , , , , , , , , RISC-V , , , RISC-V .
, ( RISC-V). , , RISC-V.
RISC-V , , , . , , , , , , , .
RISC-V ( RISC-V, Syntacore), , , . , .
GD32VF103
, , - .
- ISA RISC-V RISC-V :
ISA
ISA - GD32VF103. , . GD32VF103CBT6 — GD32 RISC-V Microcontroller
- GD32VF103 Bumblebee, Nuclei processor core
- ECLIC.
- . .
- Nuclei RISC-V , IAR n200 drivers
- GigaDevice, IAR
- FreeRTOS uCOS II n200 sdk
- , Platform IO , . .
4 , ++ — , . :
100 200
RISC-V . , , RISC-V, :
- Hart ( ) — , . (hart) . (hart) ID 0. hart.
- Trap() — , . , — , — , , . :
- (exception) — , . , NMI.
- (interrupt) — , , . , NMI, .
- (NMI) — . NMI NMI, NMI , NMI . , , , .
- Machine () — — , , . machine() . , , , .
… .
RISC-V
, :
RISC-V (-) — (ISA — Instruction Set Architecture) RISC . , . .
, , , :
RV32I | 32- 32 | 2.1 | Ratified |
RV32E | 32- 16 | 1.9 | Draft |
RV64I | 64- 32 | 2.1 | Ratified |
RV128I | 128- | 1.7 | Draft |
M | (Integer Multiplication and Division) | 2.0 | Ratified |
A | (Atomic Instructions) | 2.1 | Ratified |
F | (Single-Precision Floating-Point) | 2.2 | Ratified |
D | (Double-Precision Floating-Point) | 2.2 | Ratified |
G | / | / | |
Q | 2.2 | Ratified | |
L | (Decimal Floating-Point) | 0.0 | Open |
C | (Compressed Instructions) | 2.2 | Ratified |
B | (Bit Manipulation) | 0.36 | Open |
J | (Dynamically Translated Languages) | 0.0 | Open |
T | (Transactional Memory) | 0.0 | Open |
P | SIMD- (Packed-SIMD Instructions) | 0.1 | Open |
V | (Vector Operations) | 0.2 | Open |
N | (User-Level Interrupts) | 1.1 | Open |
, , . .
, 32 , :
:
- RV32: 32 16
- RV32I: 32 32
:
- M:
- C: 16
- :
- F:
- D:
— .
.
RISC-V 32 x0-x31. ABI .
:
t0-t6(x5-x7, x28-x31) a0-a7(x10-x17), . - , .
:
s0-s11 (x8, x9, x18-x27 ) ( ) , .
, , , :
Register | ABI Name | Description | Saver |
---|---|---|---|
x0 | zero | Hard-wired zero | — |
x1 | ra | Return address | Caller |
x2 | sp | Stack pointer | Callee |
x3 | gp | Global pointer | — |
x4 | tp | Thread pointer | — |
x5 | t0 | Temporary/alternate link register | Caller |
x6–7 | t1–2 | Temporaries | Caller |
x8 | s0/fp | Saved register/frame pointer | Callee |
x9 | s1 | Saved register | Callee |
x10–11 | a0–1 | Function arguments/return values | Caller |
x12–17 | a2–7 | Function arguments | Caller |
x18–27 | s2–11 | Saved registers | Callee |
x28–31 | t3–6 | Temporaries | Caller |
pc | pc | Program counter |
.
x0/zero:
0 CSR( ), , CSRRS (Atomic Read and Set Bits in CSR), x0 , CSR . , CSR, , zero.
x1/ra:
(Link register Return Address ). . , , , ret, .
x2/sp:
. — . , CortexM, .
x3/gp:
(The global pointer register). (gp/x3) 4 .
gp, 4 , /pc- gp- , . .
4K , , , . .
x4/tp:
(The thread pointer). . (Thread Local Storage (TLS)), thread_local ++.
, — , .
, , , ISA, . :
.
, .. . : ISA
— , Linux, .
, , .
, . : ISA
, , . , , .
, - , .
RISC-V 3 . (, ). , , .
:
0 | 00 | User/Application | U | |
1 | 01 | Supervisor | S | |
2 | 10 | Reserved | ||
3 | 11 | Machine | M |
M | |
M, U | |
M,S,U | Unix |
, , GD32VF103 M U. . U, , mtvt, mepc, . , , GD32VF103, .
.. M . — ecall — , , . mret — .
, , , , .
:
RISC-V, (, ).
GD32VF103
F GD32VF103 — , GD32F103 CortexM3. . , , - GD32F103 STM32F103 … GD32VF103 c GD32F103. ( , ), GD32F103, GD32VF103.
RV32IMAC — RISC-V 32- 32- , , 16 .
, :
- (Machine Mode), , .
- (User Mode), .
, . , . : Nuclei privileged ISA
4 :
- (Normal Mode — 0x0)
, (NMI) . - (Exception Handling Mode — 0x2)
. - (NMI Handling Mode — 0x3)
NMI. - (Interrupt Handling Mode — 0x1)
.
TYP msumbm
0 ( ) , .
, , , , , . , , mret — , mstatus MPP , mepc. .
CSR (Control and Status Registers)
mstatus, mepc, msumbm, mtvt ..., ?
, , cssr csrr.
, .
, . — , , IAR CSR . ( IAR, , GCC ).
// Get , ,
template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<ReadMode, T>::value ||
std::is_base_of<ReadWriteMode, T>::value>>
inline static Type Get()
{
return __read_csr(address) ;
}
unsigned long get_mstatus()
{
unsigned long value;
asm volatile("csrr %0, 0x300" : "=r"(value));
return value;
}
auto mstatus = get_mstatus() ;
auto mstatus = CSR::MSTATUS::Get() ;
, , , . CSR , x, xstatus — mstatus — , ustatus — . , , m , u .
.
, , . — .
mcause
. , .
INTERRUPT | 31 | : 0x0: NMI 0x1: |
MINHV | 30 | , . ECLIC . |
MPP | 29:28 | mstastus.MIE : 0x0: , 0x1: , 0x2: , 0x3: . |
MPIE | 27 | mstastus.MIE : 0x1: . 0x0: |
Reserved | 26:24 | Reserved 0 |
MPIL | 23:16 | |
Reserved | 15:12 | Reserved 0 |
EXCCODE | 11:0 | (ID) . EXCCODE NMI 0x1 0xfff. mmisc_ctl. |
mtvt2
- ECLIC .
CMMON-CODE-ENTRY | 31:2 | mtvt2.MTVT2EN=1, - ECLIC . |
1 | 0 | |
MTVT2EN | 0 | mtvt2. 0x0: - ECLIC mtvec. 0x1: - ECLIC mtvt2.CMMON-CODE-ENTRY |
msumb
Bumblebee, , .
31:10 | 0 | |
PTYP | 9:8 | . 0x0: , 0x1: 0x2: 0x3: NMI |
TYP | 7:6 | . 0x0: , 0x1: x02: 0x3: NMI |
5:0 | 0 |
mstatus
mstatus (hart). .
SD | 31 | SD — , , FS XS Dirty , . : SD = (((FS == 0x3)) or (DS == 0x3)). SD , , FPU |
XS | 16:15 | XS , CSR . 0x0: — (Off) , , 0x1: (Initial) , 0x2: (Clear) , . 0x3: (Dirty) . |
FS | 13:14 | XS FPU, (f0-f31) CSR . 0x0: — (Off) FPU , FPU , 0x1: (Initial) , 0x2 — (Clear) , . 0x3: (Dirty) . |
MPP | 11:12 | . 0x0: , 0x1: , 0x3: — |
MPIE | 7 | MIE . |
MIE | 3 | 0x0: — . 0x1: — . |
mmisc_ctl
, mnvec, NMI.
— 9 (NMI_CAUSE_FF). , 9 — , .
, NMI_CAUSE_FF( 9) 0x0, mnvec . 0x1, mnvec , mtvec, .. NMI , 0xFFF.
mepc
. . pc.
, RTOS .
mtvec
. , , mmisc_ctl
, . .
, 3 , .
- ( ),
- NMI( ),
- ( ).
-.
. Bumblebee :
/ | / | ||
---|---|---|---|
0 | PC . ( ). | ||
1 | |||
2 | |||
3 | RISC-V BREAK. . , . | ||
4 | () | Bumblebee , . | |
5 | |||
6 | () | Bumblebee , . | |
7 | |||
8 | ( ecall) | RISC-V ECALL. . . | |
11 | ( ecall) | RISC-V ECALL. . . |
:
— . RISC-V PLIC(Platform-Level Interrupt Controller) CLIC (Core-Local Interrupt Controller). PLIC , CLIC
PLIC mie and mip, RISC-V. , Linux.
CLIC. CLIC.
PLIC CLIC. CSR mtvec . (00b) PLIC - .
CLIC 11b. GD32VF103 ECLIC ( ) — CLIC,
:
4096 , , . , 19 , . ECLIC .
:
, / , , , , .
. , . 87 .
3 | CLIC_INT_SFT | 0x0000_000C |
7 | CLIC_INT_TMR | 0x0000_001C |
17 | CLIC_INT_BWEI | 0x0000_0044 |
18 | CLIC_INT_PMOVI | 0x0000_0048 |
19 | WWDGT interrupt | 0x0000_004C |
20 | LVD from EXTI interrupt | 0x0000_0050 |
21 | Tamper interrupt | 0x0000_0054 |
22 | RTC global interrupt | 0x0000_0058 |
23 | FMC global interrupt | 0x0000_005C |
24 | RCU global interrupt | 0x0000_0060 |
25 | EXTI Line0 interrupt | 0x0000_0064 |
26 | EXTI Line1 interrupt | 0x0000_0068 |
27 | EXTI Line2 interrupt | 0x0000_006C |
28 | EXTI Line3 interrupt | 0x0000_0070 |
29 | EXTI Line4 interrupt | 0x0000_0074 |
30 | DMA0 channel0 global interrupt | 0x0000_0078 |
31 | DMA0 channel1 global interrupt | 0x0000_007C |
32 | DMA0 channel2 global interrupt | 0x0000_0080 |
33 | DMA0 channel3 global interrupt | 0x0000_0084 |
34 | DMA0 channel4 global interrupt | 0x0000_0088 |
35 | DMA0 channel5 global interrupt | 0x0000_008C |
36 | DMA0 channel6 global interrupt | 0x0000_0090 |
37 | ADC0 and ADC1 global interrupt | 0x0000_0094 |
38 | CAN0 TX interrupts | 0x0000_0098 |
39 | CAN0 RX0 interrupts | 0x0000_009C |
40 | CAN0 RX1 interrupts | 0x0000_00A0 |
41 | CAN0 EWMC interrupts | 0x0000_00A4 |
42 | EXTI line[9:5] interrupts | 0x0000_00A8 |
43 | TIMER0 break interrupt | 0x0000_00AC |
44 | TIMER0 update interrupt | 0x0000_00B0 |
45 | TIMER0 trigger and channel commutation interrupts | 0x0000_00B4 |
46 | TIMER0 channel capture compare interrupt | 0x0000_00B8 |
47 | TIMER1 global interrupt | 0x0000_00BC |
48 | TIMER2 global interrupt | 0x0000_00C0 |
49 | TIMER3 global interrupt | 0x0000_00C4 |
50 | I2C0 event interrupt | 0x0000_00C8 |
51 | I2C0 error interrupt | 0x0000_00CC |
52 | I2C1 event interrupt | 0x0000_00D0 |
53 | I2C1 error interrupt | 0x0000_00D4 |
54 | SPI0 global interrupt | 0x0000_00D8 |
55 | SPI1 global interrupt | 0x0000_00DC |
56 | USART0 global interrupt | 0x0000_00E0 |
57 | USART1 global interrupt | 0x0000_00E4 |
58 | USART2 global interrupt | 0x0000_00E8 |
59 | EXTI line[15:10] interrupts | 0x0000_00EC |
60 | RTC alarm from EXTI interrupt | 0x0000_00F0 |
61 | USBFS wakeup from EXTI interrupt | 0x0000_00F4 |
62 | Reserved | 0x0000_00F8 |
63 | Reserved | 0x0000_00FC |
64 | Reserved | 0x0000_0100 |
65 | Reserved | 0x0000_0104 |
66 | Reserved | 0x0000_0108 |
67 | Reserved | 0x0000_010C |
68 | Reserved | 0x0000_0110 |
69 | TIMER4 global interrupt | 0x0000_0114 |
70 | SPI2 global interrupt | 0x0000_0118 |
71 | UART3 global interrupt | 0x0000_011C |
72 | UART4 global interrupt | 0x0000_0120 |
73 | TIMER5 global interrupt | 0x0000_0124 |
74 | TIMER6 global interrupt | 0x0000_0128 |
75 | DMA1 channel0 global interrupt | 0x0000_012C |
76 | DMA1 channel1 global interrupt | 0x0000_0130 |
77 | DMA1 channel2 global interrupt | 0x0000_0134 |
78 | DMA1 channel3 global interrupt | 0x0000_0138 |
79 | DMA1 channel4 global interrupt | 0x0000_013C |
80 | Reserved | 0x0000_0140 |
81 | Reserved | 0x0000_0144 |
82 | CAN1 TX interrupt | 0x0000_0148 |
83 | CAN1 RX0 interrupt | 0x0000_014C |
84 | CAN1 RX1 interrupt | 0x0000_0150 |
85 | CAN1 EWMC interrupt | 0x0000_0154 |
86 | USBFS global interrupt | 0x0000_0158 |
. , //NMI , :
- CSR
- mcause
- mepc
- mstatus
- mintstatus
- PC , — , NMI. .
, .
— , .
, .
, :
- , PC , mepc
- CSR :
- mstatus
- mcause
- mintstatus
- , , .
.
RISC-V stacking unstacking CortexM , , 16 .
. — , - — . (, Interrupt Tail-Chaining) .
, , - . .
ECLIC — , . . , (- ). , , , . , . -.
, ( CortexM).
-
- . .. .
CLICINTATTR[i] SHV. 0 — - , .. , , mtvec mtvt2, .
, . , mcause — EXCCODE.
ECLIC
. 7 , , i — . .. 87 clicintip, 87 clicintie, 87 clicintattr 87 clicintctl, .
0x0000 | RW | cliccfg | 8-bit |
0x0004 | R | clicinfo | 32-bit |
0x000b | RW | mth | 8-bit |
0x1000+4*i | RW | clicintip[i] | 8-bit |
0x1001+4*i | RW | clicintie[i] | 8-bit |
0x1002+4*i | RW | clicintattr[i] | 8-bit |
0x1003+4*i | RW | clicintctl[i] | 8-bit |
, , …
MTH
, . , , , - , , .
, clicintctl[i].
— mth. 8- , .
CLICINTCTL[i]
. , ( ), CLICCFG , — . CLICINFO CLICINTCTLBITS.
CLICCFG
. , . , .
? nlbits , .
7 | R | N/A | , 0 | |
nmbits | 6:5 | R | N/A | . 0: . |
nlbits | 4:1 | RW | 0 | clicintctl[i]. .. 4, clicintctl[i] 4 , . 2 8. |
nvbits | 0 | R | N/A | 1: . , 0 |
CLICINFO
31:25 | R | N/A | , 0 | |
CLICINTCTLBITS | 24:21 | R | N/A | clicintctl[i]. |
VERSION | 20:13 | R | N/A | . |
NUM_INTERRUPT | 12:0 | R | N/A | , . |
CLICINTIP[i]
. i — . 87 , 87 .
7:1 | RO | N/A | , 0 | |
IP | 0 | RW | 0 | . 1 — . , . . |
CLICINTIE[i]
. 87.
7:1 | RO | N/A | , 0 | |
IE | 0 | RW | 0 | 1 — |
CLICINTATTR[i]
. , . , , . 87.
7:6 | R | N/A | , 11b | |
5:3 | R | N/A | , 0 | |
TRIG | 2:1 | RW | 0 | 00b 10b: . 01b: . 11b: . |
SHV | 0 | RW | 0 | 0x0: . 0x1: . |
, , … .
— CortexM, . , (hart). mtime mtimecmp.
, CSR. , , .
. mtime 0xd1000000, mtimecmp 0xd1000008.
64 . :
- mtime —
- mtimecmp — . mtime mtimecmp CLICINTIP[7].
, , . , - , .
Writes to mtime and mtimecmp are guaranteed to be reflected in MTIP eventually, but not necessarily immediately.
A spurious timer interrupt might occur if an interrupt handler increments mtimecmp then immediately returns, because MTIP might not yet have fallen in the interim. All software should be
written to assume this event is possible, but most software should assume this event is extremely unlikely. It is almost always more performant to incur an occasional spurious timer interrupt than to poll MTIP until it falls.
, mtimecmp, mtime 0 , .
msip — . . RTOS , .
7:1 | RO | N/A | , 0 | |
MSIP | 0 | RW | 0 | 1 — |
STM32, , . .
, Port control register 0 (GPIOx_CTL0, x=A..E).
Port output control register (GPIOx_OCTL, x=A..E), , .
svd , STM32. , .
… , , . . , . , ECLIC - .
, , mcause, mepc msubm, , , , . .
, , __interrupt, , , mret .
, stackless ++ … .
, .
__interrupt void IrqEntry()
{
const auto mcause = CSR::MCAUSE::Get();
const auto mepc = CSR::MEPC::Get();
const auto msubm = CSRCUSTOM::MSUBM::Get();
// mcause
const auto exceptionCode = mcause & 0xFFF ;
//
NonVectoredInt::HandleInterrupt(exceptionCode);
__disable_interrupt();
CSR::MCAUSE::Write(mcause);
CSR::MEPC::Write(mepc);
CSRCUSTOM::MSUBM::Write(msubm) ;
}
-, ( , __interrupt), .
-, CSR , , , .
-, . , ( IAR).
namespace NonVectoredInt
{
static void HandleInterrupt(std::uint32_t interruptId)
{
// ,
assert(interruptId < InterruptVectorTable.size());
//
tInterruptFunction fp = InterruptVectorTable[interruptId];
if (fp != nullptr)
{
fp(); //
}
}
} ;
, .
using tInterruptFunction = void(*)() ;
inline constexpr std::array<tInterruptFunction,87> InterruptVectorTable
{
nullptr,
nullptr,
nullptr,
DummyModule::HandleInterrupt,//
nullptr,
nullptr,
nullptr,
SystemTimer::HandleInterrupt, //
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
DummyModule::HandleInterrupt,//eclic_bwei_handler,
DummyModule::HandleInterrupt, //eclic_pmovi_handler,
DummyModule::HandleInterrupt, //WWDGT_IRQHandler,
DummyModule::HandleInterrupt,//LVD_IRQHandler,
....
} ;
, 7 , , , SystemTimer::HandleInterrupt
struct SystemTimer
{
static void HandleInterrupt()
{
auto mtime = MACHINETIMER::MTIME::Get() -
MACHINETIMER::MTIMECMP::Get();
MACHINETIMER::MTIME::Write(mtime);
AppTimerService::OnSystemTick() ;
}
};
OnSystemTick()
. , NMI.
, "". , 12.
inline constexpr std::array<tInterruptFunction,12> ExceptionVectorTable
{
DummyModule::HandleInterrupt, //0 - Instruction address misaligned
DummyModule::HandleInterrupt, //1 - Instruction access fault
DummyModule::HandleInterrupt, //2 - Illegal instruction
DummyModule::HandleInterrupt, //3 - Breakpoint
DummyModule::HandleInterrupt, //4 - Load address misaligned
DummyModule::HandleInterrupt, //5 - Load access fault
DummyModule::HandleInterrupt, //6 - Store/AMO address misaligned
DummyModule::HandleInterrupt, //7 - Store/AMO access fault
EnvironmentCall::HandleInterrupt, //8 - Environment call from U-mode
nullptr,
nullptr,
EnvironmentCall::HandleInterrupt, //11 - Environment call from M-mode
};
namespace NonVectoredInt
{
static void HandleException(std::uint32_t exceptiontId)
{
assert(exceptiontId < ExceptionVectorTable.size());
tInterruptFunction fp = ExceptionVectorTable[exceptiontId];
if (fp != nullptr)
{
fp();
}
}
} ;
NMI . — 0xFFF.
__interrupt void ExceptionEntry()
{
const auto mcause = CSR::MCAUSE::Get();
const auto mepc = CSR::MEPC::Get();
const auto msubm = CSRCUSTOM::MSUBM::Get();
const auto exceptionCode = mcause & 0xFFF ;
if (exceptionCode != 0xFFF) // NMI
{
NonVectoredInt::HandleException(exceptionCode);
} else
{
DummyModule::HandleInterrupt() ; // NMI
}
__disable_interrupt();
CSR::MCAUSE::Write(mcause);
CSR::MEPC::Write(mepc);
CSRCUSTOM::MSUBM::Write(msubm) ;
}
, NMI , , mtvec, NMI 0xFFF, MMISC_CTL .
// NMI ,
// mtvec. NMI 0xFFF
CSRCUSTOM::MMISC_CTL::NMI_CAUSE_FFF::MnvecIsMtvecNmiIsFFF::Set();
// .
// , MTVT2
CSRCUSTOM::MTVT2::Write(
CSRCUSTOM::MTVT2::MTVT2EN::Mtvt2IsTrapAddress::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::IrqEntry));
a ECLIC NMI mtvec
// ECLIC
CSR::MTVEC::Write(
CSR::MTVEC::MODE::Eclic::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::ExceptionEntry));
… .
extern "C"
{
int __low_level_init(void)
{
{
CriticalSection cs;
// NMI ,
// mtvec. NMI 0xFFF
CSRCUSTOM::MMISC_CTL::NMI_CAUSE_FFF::MnvecIsMtvecNmiIsFFF::Set();
// .
// , MTVT2
CSRCUSTOM::MTVT2::Write(
CSRCUSTOM::MTVT2::MTVT2EN::Mtvt2IsTrapAddress::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::IrqEntry));
// ECLIC
//
CSR::MTVEC::Write(CSR::MTVEC::MODE::Eclic::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::ExceptionEntry));
// mycycle_minstret
CSRCUSTOM::MCOUNTINHIBITPack<CSRCUSTOM::MCOUNTINHIBIT::IR::MinstretOn,
CSRCUSTOM::MCOUNTINHIBIT::CY::McyclesOn
>::Set();
}
}
.
//
// CLICINTCTL_7. 3
ECLIC::CLICCFG::NLBITS::MaxBitsForLevel3::Set();
// 0
ECLIC::MTH::Write<0U>();
//
ECLIC::CLICINTATTR_7::SHV::NonVectored::Set();
// 1,
ECLIC::CLICINTCTL_7::Write<
1U << (8U - ECLIC::CLICCFG::NLBITS::MaxBitsForLevel3::Value)>();
// . 1 .
MACHINETIMER::MTIMECMP::MTIMEField::Value<SystemTimerPeriod>::Write() ;
MACHINETIMER::MTIME::Write<0U>();
// - 7
ECLIC::CLICINTIE_7::IE::Enable::Write();
//
CSR::MSTATUSPack<CSR::MSTATUS::MIE::InterruptEnabled>::SetValueBitsAtomic();
, . GPIOC.7 GPIOB.6
RCU::APB2EN::PCEN::Enable::Set();
RCU::APB2EN::PBEN::Enable::Set();
GPIOC::CTL0::CTLMD7::GpioOutputPushPull50Mhz::Set();
GPIOB::CTL0::CTLMD6::GpioOutputPushPull50Mhz::Set();
#include "gpiocregisters.hpp"
#include "gpiobregisters.hpp"
#include "rcuregisters.hpp" //for RCU
#include "csrregisters.hpp" //for CSR
#include "eclicregisters.hpp" // for ECLIC
#include "machinetimerregisters.hpp"
#include "systemconfig.hpp" // for SystemTimerPeriod
#include "criticalsection.hpp" // for CriticalSection
#include "csrcustomregisters.hpp"
#include "vectortable.hpp" //for InterruptVectorTable
namespace NonVectoredInt
{
static void HandleInterrupt(std::uint32_t interruptId)
{
assert(interruptId < InterruptVectorTable.size());
tInterruptFunction fp = InterruptVectorTable[interruptId];
if (fp != nullptr)
{
fp();
}
}
static void HandleException(std::uint32_t exceptiontId)
{
assert(exceptiontId < ExceptionVectorTable.size());
tInterruptFunction fp = ExceptionVectorTable[exceptiontId];
if (fp != nullptr)
{
fp();
}
}
__interrupt void ExceptionEntry()
{
const auto mcause = CSR::MCAUSE::Get();
const auto mepc = CSR::MEPC::Get();
const auto msubm = CSRCUSTOM::MSUBM::Get();
const auto exceptionCode = mcause & 0xFFF;
if (exceptionCode != 0xFFF) // if not NMI
{
NonVectoredInt::HandleException(exceptionCode);
}
else
{
DummyModule::HandleInterrupt(); // for NMI handling
}
__disable_interrupt();
CSR::MCAUSE::Write(mcause);
CSR::MEPC::Write(mepc);
CSRCUSTOM::MSUBM::Write(msubm);
}
__interrupt void IrqEntry()
{
const auto mcause = CSR::MCAUSE::Get();
const auto mepc = CSR::MEPC::Get();
const auto msubm = CSRCUSTOM::MSUBM::Get();
const auto exceptionCode = mcause & 0xFFF;
NonVectoredInt::HandleInterrupt(exceptionCode);
__disable_interrupt();
CSR::MCAUSE::Write(mcause);
CSR::MEPC::Write(mepc);
CSRCUSTOM::MSUBM::Write(msubm);
}
}
extern "C"
{
int __low_level_init(void)
{
{
CriticalSection cs;
// NMI ,
// mtvec. NMI 0xFFF
CSRCUSTOM::MMISC_CTL::NMI_CAUSE_FFF::MnvecIsMtvecNmiIsFFF::Set();
// .
// , MTVT2
CSRCUSTOM::MTVT2::Write(
CSRCUSTOM::MTVT2::MTVT2EN::Mtvt2IsTrapAddress::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::IrqEntry));
// ECLIC
//
CSR::MTVEC::Write(
CSR::MTVEC::MODE::Eclic::Value |
reinterpret_cast<std::uintptr_t>(&NonVectoredInt::ExceptionEntry));
// mycycle_minstret
CSRCUSTOM::MCOUNTINHIBITPack<CSRCUSTOM::MCOUNTINHIBIT::IR::MinstretOn,
CSRCUSTOM::MCOUNTINHIBIT::CY::McyclesOn
>::Set();
}
ECLIC::CLICCFG::NLBITS::MaxBitsForLevel3::Set();
// 0
ECLIC::MTH::Write(0U);
//
ECLIC::CLICINTATTR_7::SHV::NonVectored::Set();
// 1,
ECLIC::CLICINTCTL_7::Write<
1U << (8U - ECLIC::CLICCFG::NLBITS::MaxBitsForLevel3::Value)>();
MACHINETIMER::MTIMECMP::MTIMECMPField::Value<SystemTimerPeriod>::Write() ;
MACHINETIMER::MTIME::Write<0U>();
// - 7
ECLIC::CLICINTIE_7::IE::Enable::Write();
//Enable machine interrupt
CSR::MSTATUSPack<CSR::MSTATUS::MIE::InterruptEnabled>::SetValueBits();
RCU::APB2ENPack<RCU::APB2EN::PCEN::Enable,
RCU::APB2EN::PBEN::Enable>::Set();
GPIOC::CTL0::CTLMD7::GpioOutputPushPull50Mhz::Set();
GPIOB::CTL0::CTLMD6::GpioOutputPushPull50Mhz::Set();
return 1;
}
}
int main()
{
while (true)
{
asm volatile(" ");
}
return 0;
}
.
, . . OnTick()
template<typename ...Timers>
struct TimerService
{
static void OnSystemTick()
{
(Timers::OnTick(), ...);
}
};
— , OnTimeout(), .
template <std::uint32_t TimerFrequency, std::uint32_t msPeriod, typename ... Subscribers>
class SoftwareTimer
{
public:
static void OnTick()
{
--ticksRemain ;
if (ticksRemain == 0U)
{
ticksRemain = ticksReload ;
(Subscribers::OnTimeout(),...) ;
}
}
private:
static constexpr std::uint32_t msInSec = 1000UL ;
static constexpr std::uint32_t ticksReload =
static_cast<std::uint32_t>((msPeriod * TimerFrequency) / msInSec) ;
static inline volatile std::uint32_t ticksRemain = ticksReload;
} ;
, 100 ms, 200ms
//
using Led1Timer = SoftwareTimer<SystemTimerPeriod, 100UL, Led1> ;
using Led2Timer = SoftwareTimer<SystemTimerPeriod, 200UL, Led2> ;
//
using AppTimerService = TimerService<Led1Timer, Led2Timer> ;
, Led1 Led2 — GPIOB.6 GPIOC.7
template<typename Pin>
struct Leds
{
static void OnTimeout()
{
// ,
Pin::Toggle();
}
};
template<typename Port, uint32_t num>
struct DummyPin
{
static void Toggle()
{
Port::OCTL::Toggle(1 << num);
}
};
using Led1 = Leds<DummyPin<GPIOC, 7>>;
using Led2 = Leds<DummyPin<GPIOB, 6>>;
main, ,
int main()
{
while (true)
{
asm volatile(" ");
}
return 0;
}
, :
. 1 , OnTick()
. , , OnTimeout()
, .
, - , RISC-V.
ZY RISC-V给人留下了双重印象,一方面是非常可扩展且灵活的事情,您可以做任何事情,另一方面,存在将生产者带到一边的风险,每个人都将自己的花园围起来。我希望所有规范都将很快获得批准,并且一切都会解决。
根据指示进行更正 雷普卡 用名称空间替换了NonVectoredInt结构