본문 바로가기
미니 프로젝트/라즈베리파이 REST API for SPI

라즈베리파이 4 UART 연결 테스트

by 시샐 2023. 7. 21.
새로 라즈베리파이 4를 입수해서, 기존에 했던 것들을 그대로 옮기는 작업이 필요해졌다. 우선 1 단계로 UART 작업을 시작하기로 했다.

 

들리는 바에 따르면 라즈베리파이 4는 6 개까지 UART를 지원한다고 한다. 정말 그런지 테스트를 다 해보고 싶었으나, UART는 현 프로젝트에 별로 중요한  내용이 아닌 관계로, 라즈베리파이 3에서 했던 내용, 특히 할당된 하드웨어 핀을 그대로 쓰는 것에 초점을 맞추고자 한다.

 

라즈베리파이 3에는 '/dev/ttyS0'와 '/dev/ttyAMA0' 두 개의 시리얼 디바이스가 지원이 되었다. 이 중에 miniuart인 '/dev/ttyS0'는 좀 불안한 구석이 있어서, '/dev/ttyAMA0'로 작업을 진행했었다.
 
세부적인 사항에 대해서는   라즈베리파이 UART에 대해 잘 정리되어 있는 글로  아래 황제곰님의 글을 추천한다. 라즈베리파이 4의 여러 UART를 골라 쓰는법,   기존의 UART0를 쓰는 법들이 잘 정리되어있다.
 

 

여기서는 핀 연결 변경없이 기존의 GPIO 14, 15를 사용해야 하므로 전과 동일하게 UART0를 사용한다. 

초기 상태에서 tty 디바이스를 찾아보면 수많은 tty 중에 ttyS0는 없고, ttyAMA0 하나만 나타난 것을 알 수 있다. 
마찬가지로 uart로 사용할 GPIO14-15핀 할당을 확인해 보면, 그냥 일반 GPIO(input)로 되어있는 것을 알 수 있다.
 
$ raspi-gpio get 14-15
GPIO 14: level=1 fsel=0 func=INPUT pull=NONE
GPIO 15: level=1 fsel=0 func=INPUT pull=UP​
 
/boot/config.txt를 열고 다음 줄을 추가하여 UART0를 enable 시켜준다.
 
enable_uart=1
dtoverlay=miniuart-bt
 
리부팅을 한 후에 gpio를 재 확인 해 보면 GPIO가 alternate function으로 변경된 것을 확인할 수 있다.
 
$ raspi-gpio get 14-15
GPIO 14: level=1 fsel=2 alt=5 func=TXD0 pull=NONE
GPIO 15: level=1 fsel=2 alt=5 func=RXD0 pull=UP
 
이 설정은 하드웨어 UART0를 pin14,15로, UART1인 miniuart는 블루투스로 연결하는 것으로 생각된다.

아무튼 UART0, miniuart는 여러가지 것들이 복잡하게 얽혀 있어서 차라리 다른 UART를(uart2-5) 쓰라고 권하기도 한다. 여기에서는 기존의 GPIO핀을 그대로 써야해서 그냥 진행.


이 상태로 uart 터미널을 연결해 보면, 다음과 같이 터미널 로그인 화면이 나온다. 
 
Raspbian GNU/Linux 11 raspberrypi ttyS0

raspberrypi login:

 

지난 번과 같이
/boot/cmdline.txt에서 console=serial0,115200
를 지우거나, serial0를 serial1으로 바꾼다.

마찬가지로 이전과 동일한 파이선 프로그램으로 간단한 출력 테스트를 해보았다.
 
import serial
import time

ser = serial.Serial(
    port='/dev/ttyAMA0',
    baudrate=115200, 
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)
time.sleep(1)
# Send 'A' repeatedly to the serial port
while True:
    ser.write(b'A')
    time.sleep(1)

 

여기까지 별  문제가 없었고,

이번에는 좀 더 복잡해 보이도록 C 테스트 프로그램을 만들어 테스트 해보았다.
간단한 터미널 에코 기능을 한다.

 

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int open_serial_port(char *port_name, speed_t baudrate) {
    int fd;
    struct termios tty;

    fd = open(port_name, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        perror("error opening serial port");
        return -1;
    }
    memset(&tty, 0, sizeof(tty));
    if (tcgetattr(fd, &tty) != 0) {
        perror("error from tcgetattr");
        close(fd);
        return -1;
    }
    cfsetospeed(&tty, baudrate);
    cfsetispeed(&tty, baudrate);

    tty.c_cflag |= (CLOCAL | CREAD);
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    tty.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK | PARMRK);
    tty.c_oflag &= ~OPOST;

    tty.c_cc[VTIME] = 10;
    tty.c_cc[VMIN] = 0; 

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        perror("error from tcsetattr");
        close(fd);
        return -1;
    }
    return fd;
}

int write_serial_port(char *data, size_t len) {
    int num = write(fd, data, len);
    if (num != len) {
        perror("error writing to serial port");
        return -1;
    }
    return num;
}

int read_serial_port(char *buf, size_t len) {
    int num = read(fd, buf, len);
    if (num < 0) {
        perror("error reading from serial port");
        return -1;
    }
    return num;
}

void close_serial(){
    close(fd);
}

int main(){
    int fd;
    int num;
    char buf[256];

    fd = open_serial_port("/dev/ttyAMA0", B115200);
    if(fd < 0)
        return -1;

    write_serial_port(fd, "Hello, world!\n", 14);

    while(TRUE){
        num = read_serial_port(fd, buf, 1);
        if(num > 0){
            printf("Received: %c\n", buf[0]);
        }
    }
    close(fd);
}
 
 
반응형