Table of Contents

12 - Propojení STM32F446RE sériovou linkou

(Pro vyučující)

Jednobytová komunikace na straně Nucleo

Online prostředí Keil bývá nestabilní. Můžete využít experimentální offline prostředí.

https://gitlab.fel.cvut.cz/valoudav/mbed-cli-setup-for-prg

mbed-cli-setup-for-prg.zip

Z pohledu hlubšího porozumění fungování vyčítání dat může být vhodnější variantou použití UnbufferedSerial s definicí obsluhy přerušení pro přijem o odeslání jednoho bajtů s využitím vlastní kruhové fronty. Zejména se to hodí pro vícebajtové zprávy. Např. jako v předchozích bězích předmětu.

#include "mbed.h"
 
DigitalOut myled(LED1);
BufferedSerial serial (USBTX, USBRX, 115200);
 
void blink(uint32_t i, Kernel::Clock::duration_u32 t = 50ms){
    for(; i > 0; i--){
        myled = true;
        ThisThread::sleep_for(t);
        myled = false;
        ThisThread::sleep_for(t);
    }
}
 
int main() {
    serial.set_blocking(true);
    const char init_msg = 'i';
    serial.write(&init_msg, 1);
    blink(5);
    while(true){
        char received_value;
        ssize_t received_in_fact = serial.read(&received_value, 1);
        char acknowledge_msg = 'a';
        if(received_in_fact == 1){
            switch(received_value){
                case 's': myled = true; break;
                case 'e': myled = false; break;
                case 'f': myled = !myled; break;
                default: acknowledge_msg = '!';
            }
        }else{
            acknowledge_msg = '*';
        }
        serial.write(&acknowledge_msg, 1);
    }
}

Jednobytová komunikace na straně počítače s OS

V rámci operačního systému je zpravidla sériový port zpřístupňěn jako soubor (tzv. blokového zařízení) v adresáři /dev, např. /dev/ttyUSB0, /dev/cuaU0 nebo /dev/ttyACM0, v závislosti na konkrétním operačním systému a příslušném ovladači. (Po připojení Nuclea k počítači například spusťte příkaz dmesg, který zobrazí jak bylo Nucleo rozpoznáno.) Možností otevření a konfigurace sériového rozhraní je několik. Pro jednoduchost lze využít funkce z modulu prg_serial, který je dostupný na návodné stránce.

S využítím funkcí z prg_serial.h nahraďte virtuální termínál použitý v minulé úloze (GTKterm apod.) vlastní aplikaci pro komunikaci s Nucleo boardem. Aplikaci rozšiřte například popisem jednotlivých akcí výpisem na terminal. Uvědomte si, se kterými všemi soubory se pracuje (stdin, stdout, sériové rozhraní).

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include "prg_serial.h"
 
int main(int argc, char *argv[]){
  int ret = 0;
  const char *serial = argc > 1 ? argv[1] : "/dev/ttyACM0";
  fprintf(stderr, "INFO: open serial port at %s\n", serial);
  int fd = serial_open(serial);
  if (fd != -1) { // read from serial port
    _Bool quit = false;
    while (!quit) {
      int c = getchar();
      _Bool write_read_response = false;
      switch (c) {
        case 'q':
          printf("Quit the program\n");
          quit = true;
          break;
        case 's':
          printf("Send 's' - LED on\n");
          write_read_response = true;
          break;
        case 'e':
          printf("Send 'e' - LED off\n");
          write_read_response = true;
          break;
        case 'f':
          printf("Send 'f' - LED switch\n");
          write_read_response = true;
          break;
        default:
          printf("Ignoring char '%d'\n", c);
          break;
      }
      if (write_read_response) {
        int r = serial_putc(fd, c);
        if (r != -1) {
          fprintf(stderr, "DEBUG: Received response '%d'\n", r);
        } else {
          fprintf(stderr, "ERROR: Error in received responses\n");
        }
      }
    }
    serial_close(fd);
  } else {
    fprintf(stderr, "ERROR: Cannot open device %s\n", serial);
  }
  return ret;
}

Nastavení režimu "raw"

Načítání stisku klávesy vyžaduje z důvodu bufferování standardního vstupu potvrzení koncem řádku (stisknutí klávesy enter), což není příliš šikovné. Proto nastate terminál do tzv. “raw” režimu např. prostřednictvím funkce cfmakeraw() nebo stty raw -echo, viz 6. přednáška. Po skončení programu je vhodné terminál opět přepnout do běžného režimu, proto implementujte funkce pro přepínání do/z raw řežimu např.

void set_raw(_Bool set)
{
   static struct termios tio, tioOld;
   tcgetattr(STDIN_FILENO, &tio);
   if (set) { // put the terminal to raw 
      tioOld = tio; //backup 
      cfmakeraw(&tio);
      tio.c_lflag &= ~ECHO; // assure echo is disabled
      tio.c_oflag |= OPOST; // enable output postprocessing
      tcsetattr(STDIN_FILENO, TCSANOW, &tio);
   } else {    // set the previous settingsreset
      tcsetattr(STDIN_FILENO, TCSANOW, &tioOld);
   }
}

Nebo využitím volání externího procesu funkcí system(), jejímž argumentem je jméno programu spolu s příslušnými argumenty, např.

void set_raw(_Bool set)
{
   if (set) {
      system("stty raw -echo");  // enable raw, disable echo
   } else {
      system("stty -raw echo"); // disable raw, enable echo
   }
}

S využitím raw režimu terminálu zjednodušíme aplikaci pro ovládání LED na Nucleo desce

Možné řešení

Program vyzkoušejte a také otestujte chování při náhlem odpojení Nucleo desky při běhu programu nebo resetu Nuclea desky.

Rozbitý terminál po ukončení programu v "raw" režimu

Pokud program nastaví terminál do režimu “raw” a skončí (například příkazem kill, nebo-li signálem SIGINT), terminál si může zachovat s původní nastavení. V takovém případě je možné zkusit příkaz reset, nebo program vybavit handlerem signálu:

void handler(int signal_code) {
  set_raw_1(0);
  exit(0);
}
 
int main(){
  signal(SIGINT, intHandler);
  ...
}

Aplikace pro ovládání blikání LED na Nucleo desce

Oba programy rozšiřte pro ovládání blikání LED zasláním znaků

Nucleo pošle po spuštění znak i a každé přijetí příkazu pro nastavení periody potvrdí znakem a. Aplikace na straně počítače bude fungovat v režimu “raw” a bude zobrazovat zprávy zaslané Nucleem.

Blikání LED v programu pro Nucleo je možno realizovat třemi způsoby:

Vypracováním a předvedením této úlohy cvičícímu na tomto nebo příštím cvičení lze získat až 6 bodů do hodnocení v rámci celého předmětu PRG. Kontrolovat se bude program na Nucleu a program na počítači nezávisle proti referenčnímu řešení.