Aujourd'hui, nous allons parler de la mode - du microcontrĂŽleur RIS-V. J'ai longtemps voulu me familiariser avec ce noyau et j'ai attendu que quelque chose de similaire Ă STM32 apparaisse et maintenant j'ai attendu, rencontrez - le GigaDevice chinois - GD32V.
L'infrastructure de ce microcontrĂŽleur n'est pas aussi Ă©tendue que celle du STM32, mais il y a tout ce dont vous avez besoin pour commencer. Heureusement, les cartes de dĂ©bogage peuvent ĂȘtre commandĂ©es sur alikexpress, par exemple ici: MCU Longan Nano GD32VF103CBT6 RISC-V
Les Chinois font la promotion de l'environnement de dĂ©veloppement Platform IO pour ce microcontrĂŽleur, qui peut ĂȘtre fourni en tant qu'extension pour Visual Studio Code. Mais nous ne l'utiliserons pas, ce n'est pas selon des concepts d'ingĂ©nierie, nous sommes des ingĂ©nieurs et nous voulons le comprendre nous-mĂȘmes. Essayons donc d'exĂ©cuter le tableau sur IAR, en Ă©crivant tout Ă partir de zĂ©ro.
à propos, IAR distribue un kit de débogage (carte de débogage + débogueur I-Jet + licence complÚte de 30 jours) Kit d'évaluation IAR RISC-V GD32V. Ici, vous pouvez laisser une demande d'outils de développement . Je ne sais pas s'ils envoient le kit à tout le monde, mais nous l'avons reçu dans les 5 jours. Remerciez-les!
Eh bien, qui sont intéressés, bienvenue sous la coupe
introduction
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 a laissé une double impression, d'une part c'est une chose trÚs extensible et flexible, vous pouvez tout faire, d'autre part, il y a un risque que les producteurs soient mis de cÎté et que chacun clÎturera son propre jardin. J'espÚre que toutes les spécifications seront bientÎt approuvées et que tout se réglera.
Corrections, par instruction Ryppka a remplacé la structure NonVectoredInt par un espace de noms