\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}