Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2023:gpatru:retropm [2023/05/07 23:05]
irina_cristina.nita created
pm:prj2023:gpatru:retropm [2023/05/30 12:09] (current)
irina_cristina.nita [Download]
Line 4: Line 4:
 Proiectul constă în implementarea unui "​PC"​ inspirat de cele old school pentru care interfața cu utilizatorul se rezuma la introducerea unor comenzi în terminal. O sa îl numesc RetroPM. Proiectul constă în implementarea unui "​PC"​ inspirat de cele old school pentru care interfața cu utilizatorul se rezuma la introducerea unor comenzi în terminal. O sa îl numesc RetroPM.
  
-RetroPM va sta intr-o stare de "​oprit"​ (LED-ul pentru afișarea stării va fi roșu) până când utilizatorul va apăsa butonul de "​ON"​ pentru a porni execuția programului principal (Butonul se va afla atât pe tastatura cât și pe ). Utilizatorul va fi întâmpinat cu un prompt pentru logare și o melodie redata de buzzer. By default, user-ul o sa fie "​root"​. Sunt luate în considerare privilegiile pentru că utilizatorii vor avea acces și la un sistem ​de fișiere ​stocat într-un microSD pe care pot sa îl modifice prin comenzi(text/​imagini tip bitmap) +Prin acest proiect, mi-am propus ​sa replic ​un sistem ce poate reproduce într-un mod minimal gestionarea ​de fișiere ​și utilizatori.
 ===== Descriere generală ===== ===== Descriere generală =====
-Cateva feature-uri+RetroPM se bazează în principal pe comunicarea dintre 3 microcontrollere cu scopuri diferite
-  * La pornire, se va reda o melodie prin intermediul buzzer-ului+  * ESP32: Se ocupa de afișarea pe 2 display-uri a input-ului si output-ului pentru utilizator (comenzile ​în timp ce se tastează, un prompt cu utilizatorul curent etc.și cu conectarea la un server NTP pentru ​a afișa ora actuala pe display. ​ 
-  * Utilizatorii și privilegiile lor vor fi stocați ​în memoria EEPROM. +  * STM32F103: Se ocupa de logica principala (FSM-ulsistemului. Acesta este responsabil de procesarea input-ului, de a decide dacă o comanda este invalida, ce privilegii are un user când când dorește sa modifice un fișier etc
-  * Prin intermediul terminalului,​ se pot scrie și salva fișiere text în memoria din microSD. +  * Raspberry Pi Pico: Se ocupa de prelucrarea input-ului ​de la utilizator ​(tastele sunt procesate în caractere ASCII) pentru a le comunica către STM32.
-  * ESP32 va fi folosit pentru ​conectarea ​la anumite servere pentru a expanda funcționalități fără sa fie nevoie de hardware suplimentar (de ex. la un server NTP pentru ​redarea timpului actual) +
-  * Tastatura este conceputa pentru a evita ghosting-ul și suporta 2 taste apăsate simultan+
-  * Combinatii ​de taste de tip Shift+(Keypentru Uppercase sau "ANSI escape sequences" ​pentru a controla pozitia cursorului vor fi implementate. +
- +
-{{:​pm:​prj2023:​gpatru:​irina_retropm.png?900|}}+
  
 +{{pm:​prj2023:​gpatru:​retro-pm-diagr.png?​800}}
 ===== Hardware Design ===== ===== Hardware Design =====
  
 Lista componente: Lista componente:
-  * Arduino Uno+  * STM32F103 
 +  * Raspberry Pi Pico
   * ESP32   * ESP32
-  * Modul microSD + microSD ​16GB+  * Modul microSD + microSD ​32GB
   * Shift registers   * Shift registers
-  * Diode, Resistori..+  * Diode, Resistori
   * Pushbuttons   * Pushbuttons
-  * Buzzer +  * Memorie ​EEPROM
-  * RGB LED +
-  * Memorii ​EEPROM+
   * Ecran OLED   * Ecran OLED
 +  * Ecran LCD 16x2
   * Sursa alimentare   * Sursa alimentare
   * Level shifter   * Level shifter
  
-<note tip> +Schema pentru Raspberry Pi Pico (partea ​de "​tastatura"​)
-Aici puneţi tot ce ţine de hardware design+ 
-  * listă de piese +{{:​pm:​prj2023:​gpatru:​keyboard.png?​770|}} 
-  * scheme electrice ​(se pot lua şi de pe Internet şi din datasheet-urie.g. http://www.captain.at/​electronic-atmega16-mmc-schematic.png+ 
-  * diagrame de semnal ​ +Schema pentru ESP32 (celelalte periferice: displaymicroSD): 
-  * rezultatele simulării + 
-</​note>​+{{:​pm:​prj2023:​gpatru:​eps32.png?​500|}} 
 + 
 +(Notita: Am uitat sa pun in schema I2C-ul pentru ESP32, are rezistenta de pull-up ca STM32 si foloseste un singur bus pentru ambele display-uri
 + 
 +Schema pentru STM32 (microcontroller principal): 
 + 
 +{{:​pm:​prj2023:​gpatru:​bluepill.png?​500|}}
  
 ===== Software Design ===== ===== Software Design =====
 +Pentru STM32 și Raspeberry Pi Pico am folosit Rust, cu biblioteci de Hardware Layer Abstraction. Pentru ESP32, am folosit Arduino IDE și C++.
 +Lista bibliotecilor folosite:
 +  * C++
 +    * SPI.h, SD.h pentru modulul de microSD
 +    * Adafruit_GFX,​ Adafruit_SH110X,​ hd44780 pentru cele doua display-uri
 +    * Wire pentru I2C
 +    * HardwareSerial pentru UART
 +  * Rust
 +    * rp2040_hal - pentru Pico
 +    * stm32f1xx_hal,​ eeprom34x (pentru a scrie/citi din IC-ul de memorie) - pentru STM32F103
  
 +Pentru partea de procesare de tastatura, a trebuit în primul rând sa implementez o funcție asemănătoare cu cea de shiftOut din Arduino.h (nu am găsit-o în vreu crate de Rust). Folosind 2 shift registeri ca output-uri (fiecare cu 5 coloane din matricea de butoane asignate), și 4 coloane ca input-uri pentru a reduce numărul de pini folosiți pe placa, am folosit o tehnica de matrix scanning pentru a decide ce buton a fost apăsat de utilizator. Astfel am putut sa scanez mai multe butoane în același ciclu de loop. (Lucrul acesta a fost folosit pentru a reproduce efectul de shift + lowercase = uppercase).
  
-<note tip> +Code snippet
-Descrierea codului aplicaţiei (firmware)+Prima parte din loop se ocupa cu scanarea șstocarea intr-o matrice de tip bool dacă tasta de la poziția ​i,j a fost apăsată. 
-  * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) +<code c> 
-  * librării şsurse 3rd-party (e.g. Procyon AVRlib) +        // Bits 9:5 for first shift register 
-  * algoritmi şi structuri pe care plănuiţsă le implementaţi +        // Bits 4:0 for second shift register 
-  * (etapa 3) surse şi funcţii implementate +        let mut bits = 0x0200u16; // 0000_0010_0000_0000
-</note>+
  
-===== Rezultate Obţinute =====+        // Mask for second shift register -> 0000_0000_0001_1111 
 +        let mask 0x001Fu16;
  
-<note tip> +        for col in (0u8..10u8).rev() { 
-Care au fost rezultatele obţinute în urma realizării proiectului vostru+            // Byte to serial input for first shift register. 
-</note>+            let byte_higher = !((bits ​>> 5).to_be_bytes()[1]);​
  
-===== Concluzii =====+            // Byte to serial input for second shift register. 
 +            let byte_lower ​!((bits & mask).to_be_bytes()[1]);​
  
-===== Download =====+            latch_pin_1.set_low().unwrap();​ 
 +            latch_pin_2.set_low().unwrap();​ 
 +            // Shift out value from register 
 +            kb_lib::​shift_out(&​byte_lower,​ &mut data_pin_2, &mut clock_pin_2,​ &mut delay, kb_lib::​BitOrder::​LSBFIRST);​ 
 +            kb_lib::​shift_out(&​byte_higher,​ &mut data_pin_1, &mut clock_pin_1,​ &mut delay, kb_lib::​BitOrder::​LSBFIRST);​
  
-<note warning>​ +            // Read from the input pins for scanning: 
-O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectuluisurse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).+            let idx = if col == 9 { 9usize } else { 8 col as usize };
  
-Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**Namespace-ul în care se încarcă fişierele este de tipul **:​pm:​prj20??:​c?​** sau **:​pm:​prj20??:​c?:​nume_student** ​(dacă este cazul). **Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**. +            if rows0.is_low().unwrap() {  
-</​note>​+                keyState[0][idx] = true; 
 +            } else { 
 +                keyState[0][idx] = false; 
 +            }
  
-===== Jurnal =====+            if rows1.is_low().unwrap() { 
 +                keyState[1][idx] ​true; 
 +            } else { 
 +                keyState[1][idx] ​false; 
 +            }
  
-<note tip> +            if rows2.is_low().unwrap() { 
-Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului+                if idx == 0 { 
-</​note>​+                    is_shift_pressed = true; 
 +                } else { 
 +                    keyState[2][idx] = true; 
 +                } 
 +            } else { 
 +                keyState[2][idx] = false; 
 +            }
  
-===== Bibliografie/Resurse =====+            if rows3.is_low().unwrap() { 
 +                keyState[3][idx] ​true; 
 +            } else { 
 +                keyState[3][idx] ​false; 
 +            } 
 + 
 +            bits >>1; 
 +            latch_pin_1.set_high().unwrap();​ 
 +            latch_pin_2.set_high().unwrap();​ 
 +        } 
 +</code> 
 + 
 +A doua parte se ocupa cu comunicarea către STM32: 
 + 
 +<code c> 
 +for i in 0..4 { 
 +            for j in 0..10 { 
 +                if keyState[i][j] { 
 + 
 +                    if is_shift_pressed { 
 +                        last_key_pressed ​kb_lib::​SHIFT_KEYS[i][j];​ 
 +                        is_shift_pressed ​!is_shift_pressed;​ 
 +                    } else { 
 +                        last_key_pressed ​KEYS[i][j];​ 
 +                    } 
 +                    delay.delay_ms(100);​ 
 +                    write!(uart,"​{}",​ &​last_key_pressed).unwrap();​ 
 +                    delay.delay_ms(100);​ 
 +                    break; 
 +                } 
 +            } 
 +        } 
 +</​code>​ 
 + 
 +Pentru partea de logica principala, atât în STM32, cât și în ESP32 am folosit logica unor FSM-uri. 
 + 
 +ESP32 are FSM-uri separate pentru procesarea de SSID/Parola (pentru conectarea cu serverul NTP), procesarea comenzilor speciale pentru SD, rulării comenzilor:​ 
 + 
 +<code c> 
 +enum State { 
 +  MW_LOADING,​ 
 +  MW_RUNNING,​ 
 +  MW_RUNNING_SETUP 
 +}; 
 + 
 +enum CredentialsState { 
 +  CRED_NOT_PROV,​ 
 +  CRED_PROV,​ 
 +  CRED_NO_CHECK 
 +}; 
 + 
 +enum CredentialsProvStatus { 
 +    NONE, 
 +    SSID, 
 +    BOTH 
 +}; 
 + 
 +enum NTPState { 
 +  NTP_NOT_CONN,​ 
 +  NTP_CONN 
 +}; 
 + 
 +enum SDState { 
 +    SD_PROC_B,​ 
 +    SD_NO_PROC_B,​ 
 +    SD_PROC_FN 
 +}; 
 + 
 +enum SDCommand { 
 +    SD_COMM_NONE,​ 
 +    SD_COMM_WR,​ 
 +    SD_COMM_RD,​ 
 +    SD_COMM_AP,​ 
 +    SD_COMM_CR,​ 
 +    SD_COMM_LS,​ 
 +    SD_COMM_RM 
 +}; 
 +</​code>​ 
 + 
 +FSM-ul pentru STM32 se ocupa de inițializare,​ iar apoi intra într-un loop Procesare Comanda <-> Afișare Status. 
 + 
 +<code Rust> 
 +pub enum State { 
 +    StateGetSsid,​ 
 +    StateGetSsidPwd,​ 
 +    StateInit,​ 
 +    StateLoadCmd,​ 
 +    StateDoneLoadCmd 
 +
 +</​code>​
  
 <​note>​ <​note>​
-Listă cu documentedatasheet-uriresurse Internet folosite, eventual grupate pe **Resurse Software** ş**Resurse Hardware**.+Comunicarea dintre ESP32 și STM32 a fost cea mai "​tricky"​ parte din software. Fiind doar 2 canale de comunicare seriale (unul prin care ESP32 trebuia sa proceseze o comanda legată de sistemul de fișiereși unul pentru afișarea pe display a input-ului)șpentru ca a evita procesarea comenzilor la nivel de string de fiecare data (și pentru a mapa mai ușor la numărul de argumente așteptate),​ am folosit un byte de start pentru a determina tipul unei comenzi. 
 + 
 +Code snippet ca exemplu: 
 +<code c> 
 +match processed_cmd.cmd_type { 
 +        CommandType::​CmdLs => { 
 +            first_byte = '​5'​ as u8; 
 +        } 
 + 
 +        CommandType::​CmdAp => { 
 +            first_byte = '​2'​ as u8; 
 +        } 
 + 
 +        CommandType::​CmdRd => { 
 +            first_byte = '​1'​ as u8; 
 +        } 
 + 
 +        CommandType::​CmdRm => { 
 +            first_byte = '​6'​ as u8; 
 +        } 
 + 
 +        CommandType::​CmdWr => { 
 +            first_byte = '​3'​ as u8; 
 +        } 
 + 
 +        CommandType::​CmdCr => { 
 +            first_byte = '​4'​ as u8; 
 +        } 
 +    } 
 +</​code>​
 </​note>​ </​note>​
 +===== Rezultate Obţinute =====
  
-<​html><​a class="media mediafile mf_pdf" ​href="?do=export_pdf">Export to PDF</a></​html>​+Ferris facandu-si prezenta simitita Ła power-up: 
 + 
 +{{ pm:​prj2023:​gpatru:​ferris_startup.jpeg?​500 }} 
 + 
 +Cum arata circuitul final (utilizatorul logat default este root, se vede ca LCD-ul 16x2 este folosit pentru ca utilizatorul sa vadă ce tastează, iar display-ul OLED este folosit pentru informații despre sistemul de fișiere + afișarea orei). 
 + 
 +Comanda ls care implicit afișează numele și dimensiunea fișierelor din /: 
 + 
 +{{ pm:​prj2023:​gpatru:​retro-final.jpeg?​500 }} {{ pm:​prj2023:​gpatru:​ls_example1.jpeg?​500 }} 
 + 
 +Video: (just in case): 
 + 
 +<​html>​ 
 +<iframe width="560" ​height="315" src="https://​www.youtube.com/​embed/​11CuGCW_KQc"​ title="​YouTube video player"​ frameborder="​0"​ allow="​accelerometer;​ autoplay; clipboard-write;​ encrypted-media;​ gyroscope; picture-in-picture;​ web-share"​ allowfullscreen></iframe> 
 +</​html>​ 
 +===== Concluzii ===== 
 + 
 +Mi-ar fi plăcut sa pot sa implementez alte funcționalități ( de ex. mutarea cursorului printr-o secvența de caractere apăsate etc.), dar am subestimat dificultatea proiectului. 
 + 
 +Concluzie finala: o experienta placuta (mai ales cand am făcut câteva scurturi XD).  
 +===== Download ===== 
 + 
 +{{:​pm/​prj2023/​gpatru/​source_code_retro_pm_2.zip|Download source code & .sch}} 
 + 
 + 
 + 
 +===== Bibliografie/​Resurse =====
  
 +  * [[https://​docs.rust-embedded.org/​book/​| The Embedded Rust Book]]
 +  * [[http://​www.openmusiclabs.com/​learning/​digital/​input-matrix-scanning/​index.html| Matrix Scanning]]
pm/prj2023/gpatru/retropm.1683489912.txt.gz · Last modified: 2023/05/07 23:05 by irina_cristina.nita
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0