Files
lab-rv32i-freertos-isr-drivers/doc/main.tex
T

199 lines
7.4 KiB
TeX

\documentclass[10pt]{article}
\usepackage[T1]{fontenc}\usepackage[utf8]{inputenc}\usepackage[polish]{babel}
\usepackage[a4paper,margin=1.55cm]{geometry}
\usepackage{array,tabularx,booktabs,amsmath,amssymb,xcolor,listings,hyperref,fancyhdr,lastpage,enumitem}
\definecolor{accent}{HTML}{16324A}\definecolor{accentlight}{HTML}{EEF3F7}\definecolor{rulegray}{HTML}{D7DEE5}
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
\newcommand{\PublisherDomain}{mpabi}
\newcommand{\CardArea}{inf}
\newcommand{\CardSeries}{freertos-cpp}
\newcommand{\CardNumber}{15}
\newcommand{\CardCount}{16}
\newcommand{\CardSlug}{isr-drivers}
\newcommand{\CardVersion}{v00.01}
\newcommand{\DocumentUUID}{02f6cd71-5c85-4883-a237-1d4ba08d9469}
\newcommand{\blank}[1]{\rule{#1}{.2pt}}
\lstset{language=C++,basicstyle=\ttfamily\scriptsize,columns=fullflexible,keepspaces=true,frame=single,breaklines=true,showstringspaces=false,numbers=none,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}}
\pagestyle{fancy}\fancyhf{}
\lhead{\textbf{K15 · FreeRTOS C++ · FromISR}}\rhead{\small L14 · UART + GPIO}
\lfoot{\scriptsize commit \BuildCommit}\cfoot{\scriptsize \thepage/\pageref{LastPage}}\rfoot{\scriptsize V11.3.0 / \CardVersion}
\setlength{\headheight}{14pt}\setlength{\footskip}{19pt}
\setlist[itemize]{nosep,leftmargin=1.45em}\setlist[enumerate]{nosep,leftmargin=1.65em}
\begin{document}\sloppy
\begin{center}
{\LARGE\bfseries Jawne FromISR: UART RX i GPIO edge}\par
\vspace{.25em}{\large jeden IsrContext, jedna decyzja yield, jawny backpressure}\par
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.75cm}X@{}}
\toprule
Karta & K15 / \CardCount & Czas & 30 minut \\
Platforma & Hazard3 / RV32I & IRQ & machine external \\
RX queue & capacity 1 & Overflow & drop-newest \\
Wersja & \CardVersion & UUID karty & \texttt{02f6cd71-...} \\
\bottomrule
\end{tabularx}
\section*{Jawny kontrakt handlera}
\begin{lstlisting}
IsrContext isr;
auto byte = uart.isr_view().read_rx_from_isr();
rx.send_from_isr(byte, isr);
notify.give_from_isr(isr);
isr.yield_if_needed(); // dokladnie raz
\end{lstlisting}
\noindent\fcolorbox{accent}{accentlight}{\begin{minipage}{.94\textwidth}
\textbf{Kontrakt K15.} ISR view nie ma timeoutu ani blocking API. Każde
\texttt{...FromISR} dokłada żądanie wake do jednego contextu. Handler czyści
źródła, publikuje bounded dane i dopiero na końcu raz podejmuje decyzję yield.
\end{minipage}}
\section*{Plan 30 minut}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.1cm}X@{}}
\toprule Czas & Tryb & Dowód \\
\midrule
0--5 & views & task view kontra ISR view \\
5--10 & IRQ & \texttt{mcause=0x8000000b}, ISR stack \\
10--15 & UART & 0x41 queued, 0x42 dropped \\
15--20 & GPIO & edge 1--0, notification=1 \\
20--25 & wake & flag true, yield calls=1 \\
25--30 & order & receiver przed resume stimulus \\
\bottomrule
\end{tabularx}
\section*{Predykcja}
Czy drugi bajt zmieści się w pełnej kolejce capacity 1? \blank{2cm}.
Ile razy handler powinien wywołać yield dla dwóch publikacji? \blank{2cm}.
\newpage
\section{Realny external IRQ i bounded handler}
\begin{center}
\texttt{stimulus: UART[41,42] + GPIO edge + SET\_IRQ}\\
$\downarrow$ \texttt{machine external trap / ISR stack}\\
$\downarrow$ \texttt{queue FromISR + notify FromISR + clear sources}\\
$\downarrow$ \texttt{one yield -- rx-worker -- resume stimulus}
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.3cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
\texttt{mcause} & \texttt{0x8000000b} & \blank{2.5cm} \\
ISR SP różny od task SP & true & \blank{2.5cm} \\
external IRQ state po clear & 0 & \blank{2.5cm} \\
UART ready przed / po ISR & 1 / 0 & \blank{2.5cm} \\
GPIO edge przed / po ISR & 1 / 0 & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section{UART RX i backpressure}
Dwa bajty czekają w modelu rejestrów, lecz queue ma jedno miejsce. Handler ma
limit dwóch odczytów; nie wykonuje parsowania ani oczekiwania.
\noindent\begin{tabularx}{\textwidth}{@{}p{5.3cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
queued count / byte & 1 / \texttt{0x41} & \blank{2.5cm} \\
dropped count / byte & 1 / \texttt{0x42} & \blank{2.5cm} \\
overflow policy & drop-newest & \blank{2.5cm} \\
receiver byte & \texttt{0x41} & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
Porównaj drop-newest, drop-oldest i overwrite dla UART:\\[.4em]
\blank{16cm}\\[.8em]\blank{16cm}
\newpage
\section{Task view i ISR view}
\noindent\begin{tabularx}{\textwidth}{@{}p{3.2cm}XX@{}}
\toprule Wrapper & Task view & ISR view \\
\midrule
\texttt{Uart} & enable/configure, test inject & ready/read, bez wait \\
\texttt{GpioPin} & direction/write output & edge pending/clear \\
\texttt{Queue} & receive(timeout) & send\_from\_isr \\
\texttt{Notification} & task odbiera & give\_from\_isr \\
\bottomrule
\end{tabularx}
\section{Akumulacja wake i jeden yield}
\begin{lstlisting}
BaseType_t local = pdFALSE;
xQueueSendFromISR(queue, &byte, &local); isr.merge(local);
local = pdFALSE;
vTaskNotifyGiveFromISR(worker, &local); isr.merge(local);
isr.yield_if_needed();
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.3cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
notification sent/taken & 1 / 1 & \blank{2.5cm} \\
higher priority task woken & true & \blank{2.5cm} \\
yield requested & true & \blank{2.5cm} \\
\texttt{yield\_if\_needed} calls & 1 & \blank{2.5cm} \\
receiver tick & 1 & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section*{Dowód natychmiastowego przełączenia}
\begin{itemize}
\item receiver widzi \texttt{stimulus\_after=0};
\item po powrocie z IRQ stimulus widzi \texttt{receiver\_done=1};
\item receiver ustawia GPIO output z bitu 0 bajtu \texttt{0x41}: data=1.
\end{itemize}
Co zmieniłby brak yield przy wake=true?\\[.4em]
\blank{16cm}\\[.8em]\blank{16cm}
\section*{Granica ISR}
Parsing, debounce, logowanie i retry są pracą taska. ISR tylko odczytuje bounded
FIFO, czyści źródło i publikuje. Static queue/task storage daje heap delta 0.
\newpage
\section{Hazard3/GDB i zaliczenie}
\begin{lstlisting}[language=bash]
make check
riscv64-unknown-elf-gdb build/task01_isr_drivers/prog.elf
b isr_drivers_debug_checkpoint
\end{lstlisting}
\begin{lstlisting}
p/x g_mcause
p g_uart_status_before_isr
p g_uart_status_after_isr
p g_gpio_edge_before_isr
p g_gpio_edge_after_isr
p g_rx_queued
p/x g_queued_byte
p g_rx_dropped
p/x g_dropped_byte
p g_notification_taken
p g_higher_priority_task_woken
p g_isr_yield_calls
p g_stimulus_after_seen_by_receiver
p g_receiver_done_at_stimulus_resume
p g_isr_drivers_pass
\end{lstlisting}
\section*{Zaliczenie}
\begin{itemize}
\item $\square$ pokazuję realny external IRQ i osobny ISR stack;
\item $\square$ używam wyłącznie jawnych metod \texttt{from\_isr};
\item $\square$ kolejkuję 0x41 i jawnie liczę drop-newest 0x42;
\item $\square$ clear UART/GPIO zmienia status 1 na 0;
\item $\square$ akumuluję wake=true i wywołuję yield dokładnie raz;
\item $\square$ receiver działa przed resume stimulus i ustawia GPIO=1.
\end{itemize}
\section*{Wyjście}
Dlaczego automatyczne zgadywanie task/ISR contextu osłabia API?\\[.5em]
\blank{16cm}\\[1em]
Gdzie zaimplementujesz parsing i debounce, i dlaczego?\\[.5em]
\blank{16cm}
\vfill
\noindent\textbf{Następna karta K16:} integracja usług RTOS, end-to-end trace,
memory/stack report, pressure injection i uzasadnienie każdej granicy.
\end{document}