Wir beschäftigen uns weiterhin mit der Struktur des GD32VF103CBT6-Controllers. Nun wollen wir sehen, wie es mit Interrupts umgehen kann, um unter der Kontrolle von High-Level-Code zu arbeiten.
Der erste Teil ist hier
7. UART-Verbindung
Bei der Auswahl eines Problems für die Rekursion stieß ich auf das Problem, dass drei LEDs nicht ausreichen, um komplexe Algorithmen zu debuggen. Fügen wir also eine vollwertige Debugging-Oberfläche hinzu, an die sich ein Terminalprogramm wie screen anschließen und mit einfachem Text mit dem Controller kommunizieren kann. Dazu verwenden wir den gleichen USART0, der für die Firmware verwendet wird.
Ein kleiner Exkurs in Bezug auf die Terminologie: USART (Universal Synchron-Asynchronous Receiver-Transmitter) kann, wie der Name schon sagt, sowohl im synchronen als auch im asynchronen Modus arbeiten. Und in ein paar anderen, aber sie sind fĂĽr uns noch nicht interessant. In der Praxis habe ich noch nie gesehen, dass es im synchronen Modus funktioniert. Daher werde ich zusammen mit USART die UART-Bezeichnung verwenden, die genau den asynchronen Modus impliziert.
Wie bei den Ports besteht der erste Schritt darin, dieses Modul zu aktivieren. Wir sehen in der Dokumentation nach, welchem ​​RCU-Bit es entspricht, und sehen das 14. Bit von RCU_APB2EN_USART0EN. Das nächste Merkmal des GD32VF103 nach dem STM ist die Notwendigkeit, die Betriebsart des Ausgangspins vom üblichen GPIO auf eine alternative Funktion umzuschalten, die durch den Wert GPIO_APP50 = 0b1011 aktiviert wird. Und nur zur Ausgabe: Der Eingabezweig bleibt der übliche GPIO_HIZ. Oh ja, in der RCU muss auch die Möglichkeit aktiviert werden, alternative Funktionen zu nutzen. Dies erfolgt durch Bit 0, auch bekannt als RCU_APB2EN_AFEN.
Die UART-Einstellung selbst ist jedoch nicht schwierig: Im USART0_CTL0-Register aktivieren wir einfach den Betrieb (USART_CTL0_UEN), schalten den Sender (USART_CTL0_TEN) und den Empfänger (USART_CTL0_REN) ein und stellen anschließend den Wechselkurs im USART0_BAUD-Register als Taktfrequenzteiler ein. Genauer gesagt, nicht die Taktfrequenz, sondern nur die APB2-Busfrequenzen, aber bis wir die Taktung herausgefunden haben, sind die Frequenzen aller Busse gleich und gleich 8 MHz:
la t0, USART0_BASE li t1, 8000000 / 9600 sw t1, USART_BAUD_OFFSET(t0) li t1, USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_TEN sw t1, USART_CTL0_OFFSET(t0) la t0, USART0_BASE li t1, 'S' sb t1, USART_DATA_OFFSET(t0)
, … , .
USART0_DATA.
, ,
$ screen /dev/ttyUSB0 9600
'S' . screen, ctrl+a, k, y.
8.
. UART : . , . , UART : 9600 , 115200. 8 , 108 , , . USART_STAT_TBE (Transmit data buffer empty) USART0_STAT.
:
void uart_puts(char *str){
while(str[0] != '\0'){
while(! (USART0_STAT & USART_STAT_TBE) ){}
USART0_DATA = str[0];
str++;
}
}
, , 14 .
, USART_STAT_RBNE (Read data buffer not empty), '\r' '\n' .
UART , , .
9.
, . , , . , ?
— , , . (polling) . , . UART , , — .
, , USB, . , , (-, ), . ?
— , . : , . , .
RISC-V : , , ( ), . , . : , , . , , . , , , . , , , . , , .
, , sp.
, . GD32VF103 eclic (Enhanced Core Local Interrupt Controller). , . , , , . : (NMI), (traps) (interrupts). , . ( breakpoint ecall ebreak), . , ( ) . UART`.
eclic . , . scrr () scrw (). , , mtvec. 26 , 6 — : 3 eclic, — , clic ( ?):
la t0, trap_entry andi t0, t0, ~(64-1) # 64 ori t0, t0, CSR_MTVEC_ECLIC csrw CSR_MTVEC, t0
, , , 64- . .align 6:
.align 6 trap_entry: push t0 push t1 push a0 la t0, GPIOB_OCTL lh t1, 0(t0) xori t1, t1, (1<<GLED) sh t1, 0(t0) la t0, USART0_BASE la t1, USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_TEN sw t1, USART_CTL0_OFFSET(t0) la t1, 'I' sw t1, USART_DATA_OFFSET(t0) la a0, 100000 call sleep pop a0 pop t1 pop t0 mret
UART`, . , - . , — . UART USART_CTL0_TBEIE, , . . 'I' . . , , - .
USART_CTL0_TBEIE USART0_CTL0, . eclic . :
# USART0 (eclic_int_ie[i] = 1) la t0, (ECLIC_ADDR_BASE + ECLIC_INT_IE_OFFSET + USART0_IRQn*4) la t1, 1 sb t1, 0(t0) # csrrs zero, CSR_MSTATUS, MSTATUS_MIE
. ECLIC_ADDR_BASE + ECLIC_INT_IP_OFFSET , . :
struct{
uint8_t clicintip; //interrupt pending
uint8_t clicintie; //interrupt enable
uint8_t clicintattr; //attributes
uint8_t clicintctl; //level and priority
}eclic_interrupt[ECLIC_NUM_INTERRUPTS];
- clicintip — . . .
- clicintie — . , clicintip . .
- clicintattr — . clicintip ( 0->1 1->0) . .
- clicintctl — . .
, 8-, sb. , - , . , , , , . , , .
USART0_IRQ 56- , clicintie, 1.
, USART_CTL0_TBEIE, . , , , .
UPD: : . , ? , — , ( ?), . ( RISC-V ) mscratchcsw. :
csrrw sp, mscratchcsw, sp # - csrrw sp, mscratchcsw, sp
10.
, , , . . , ecall. , . , , 16-, 32-. , . 32-. ra, mepc, 4 .
, . , . mcause, 31- , . 1, , 0 — . . 0-11 ( 31- 0) ( 1). :
0 — instruction address misaligned,
1 — instruction access fault,
2 — illegal instruction,
3 — breakpoint, ebreak
4 — load address misaligned,
5 — load address fault,
6 — store/AMO misaligned,
7 — store/AMO access fault,
8 — enviroment call from U-mode, ecall,
9 — ?
10 — ?
11 — Enviroment call from M-mode, ecall,
2, 3 11.
( 2) . , 0xFFFF'FFFF ( ).
ebreak ( 3) . 32-. , ebreak 2 . , .
ecall 11- , 8- . , , . .
( 0xFFFF'FFFF), ecall. .
. , eclic? mcause. . UART` . "" , . , :
.align 6 trap_entry: push t0 push t1 push a0 csrr a0, CSR_MCAUSE la t1, (1<<31) and t1, a0, t1 #t1 - interrupt / trap beqz t1, trap_exception #interrupt la t0, GPIOB_OCTL lh t1, 0(t0) xori t1, t1, (1<<GLED) sh t1, 0(t0) la t0, 0xFFF and a0, a0, t0 la t0, USART0_IRQn bne t0, a0, trap_end la t0, USART0_BASE la t1, USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_TEN sw t1, USART_CTL0_OFFSET(t0) la t1, 'I' sw t1, USART_DATA_OFFSET(t0) trap_end: la a0, 100000 call sleep pop a0 pop t1 pop t0 mret trap_exception: la t0, GPIOB_OCTL lh t1, 0(t0) xori t1, t1, (1<<RLED) sh t1, 0(t0) csrr t0, CSR_MEPC addi t0, t0, 4 csrw CSR_MEPC, t0 j trap_end
11.
: . , . mtvt2: 30 , 1- , (mtvt2 + mtvec) 1, . , 4- . :
la t0, irq_entry csrw CSR_MTVT2, t0 # 4 csrs CSR_MTVT2, 1
. , mcause:
align 2 irq_entry: push t0 push t1 push a0 csrr a0, CSR_MCAUSE la t0, 0xFFF and a0, a0, t0 la t0, USART0_IRQn bne t0, a0, irq_end la t0, USART0_BASE la t1, USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_TEN sw t1, USART_CTL0_OFFSET(t0) la t1, 'I' sw t1, USART_DATA_OFFSET(t0) la t0, GPIOB_OCTL lh t1, 0(t0) xori t1, t1, (1<<YLED) sh t1, 0(t0) la a0, 100000 call sleep irq_end: pop a0 pop t1 pop t0 mret
, .
12.
. . 64, 128, 256, 512, 1024, 2048, 4096, 8192 16384 . , : - (OR) . 86 , 4 , 344 . , — 512, .align 9. , , . . : . , . , 4 :
.text .section .init ... .align 9 vector_base: j _start .align 2 .word 0 .word 0 .word eclic_msip_handler ... .word RTC_IRQHandler ... .word SPI1_IRQHandler .word USART0_IRQHandler ... .align 2 .text .global _start _start: la sp, _stack_end ...
. . , UART
USART0_IRQHandler: push t0 push a0 la t0, USART0_BASE la a0, USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_TEN sw a0, USART_CTL0_OFFSET(t0) la a0, 'U' sw a0, USART_DATA_OFFSET(t0) la t0, GPIOB_OCTL lh a0, 0(t0) xori a0, a0, (1<<GLED) sh a0, 0(t0) la a0, 100000 call sleep pop a0 pop t0 mret
mtvt:
la t0, vector_base csrw CSR_MTVT, t0
clicintattr . : 1 2 :
0b00, 0b01 — , clicintip
0b10 — , 0 1
0b11 — , 1 0.
, EXTI, . .
0 - . 0 ( ) - , 1 — .
# (eclic_int_attr[i] = 1) la t0, (ECLIC_ADDR_BASE+ECLIC_INT_ATTR_OFFSET+USART0_IRQn*4) la t1, 1 sw t1, 0(t0)
- , UART .
- , .
la t0, nmi_entry csrs CSR_MNVEC, t0 li t0, (1<<9) csrs CSR_MMISC_CTL, t0
13.
, . . . , , . , startup.S, main.c. ` , UART' , , . -. , . pinmacro.h :
#define RLED B, 5, 1, GPIO_PP50
#define SBTN B, 0, 0, GPIO_HIZ
...
GPIO_config( RLED );
GPIO_config( SBTN );
GPO_ON( RLED );
if( GPI_ON( SBTN ) )GPIO_OFF( RLED);
main . argc argv. - return.
li a0, 0 li a1, 0 call main INF_LOOP: .weak UnhandledInterruptHandler UnhandledInterruptHandler: j INF_LOOP
, . , :
.weak IRQHandler IRQHandler: .weak NMIHandler NMIHandler: .weak TrapHandler TrapHandler: j UnhandledInterruptHandler
, . , . . UnhandledInterruptHandler .
.weak, , , (, , ...) - , , , , , "".
, , '. , , .start, , .
, ' . , . lib.
14.
, . , , . , lib/Firmware/RISCV/drivers/n200_func.c. eclic_set_vmode ( ) eclic_enable_interrupt ( ). - . , :
#define eclic_global_interrupt_enable() set_csr(mstatus, MSTATUS_MIE)
#define eclic_global_interrupt_disable() clear_csr(mstatus, MSTATUS_MIE)
n200_func.c makefile src. , eclic_init, ( !). , . , SystemCoreClock. , .
, : ( t0-t6), mret ret. ' , , :
__attribute__((interrupt)) void USART0_IRQHandler(void)
, , lib/interrupt_util.h . , .
, , main , — , . , , :
__attribute__((naked)) int main();
, , .
, .
RISC-V , AVR ARM . , , , , . : , — . , , .
USART_DATA( USART0 ) DMA , stm32. .
RISC-V ARM, , . RISC-V : - ( li, , , "Myriad sequences"). , .
GD32VF103 ? . . GigaDevice stm32f103, . , stm32l151. — , , stm32f103. , RISC-V — x86, ARM, RISC-V - .
https://habr.com/ru/post/516006/
https://www.youtube.com/watch?v=M0dEugoU8PM&list=PL6kSdcHYB3x4okfkIMYgVzmo3ll6a9dPZ
https://www.youtube.com/watch?v=LyQcTmNcSpY&list=PL6kSdcHYB3x6KOBxEP1YZAzR8hkMQoEva
https: //doc.nucleisys.com/nuclei_spec/isa/eclic.html
http://www.gd32mcu.com/de/download/0?kw=GD32VF1