BaseFlight_USART - FabLabSeoul/WingProject GitHub Wiki

์˜คํ”ˆ์†Œ์Šค Multiwii BaseFlight์˜ USART ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ถ„์„ํ•œ ๊ธ€์ด๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ๋ณด๋‹ค๋Š” ๊ฐœ๋…์ ์œผ๋กœ ์„ค๋ช…ํ•œ๋‹ค. ์ž์„ธํžˆ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด ์†Œ์Šค๋ฅผ ๋ณด์ž.

์ด ๊ธ€์€ Stm32 value line discovery ๋ณด๋“œ๋ฅผ ํ† ๋Œ€๋กœ ํ•˜๊ณ  ์žˆ๋‹ค.

์˜ˆ์ œ๋Š” STM32\stm32vldiscovery_package\Project\Examples\Serial_Baseflight ๊ฒฝ๋กœ์— ์žˆ๋‹ค. Base flight์˜ USART ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด PC์™€ ์‹œ๋ฆฌ์–ผ ํ†ต์‹ ํ•˜๋Š” ์˜ˆ์ œ๋‹ค. ์‹œ์ž‘ํ•˜๋ฉด Start ๋ฌธ์ž์—ด์„ ๋ณด๋‚ด๊ณ , ์—ด ๊ฐœ์˜ ๋ฌธ์ž๋ฅผ ๋ฐ›์œผ๋ฉด, ๊ทธ ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ์žฌ์ „์†กํ•˜๋Š” ์˜ˆ์ œ๋‹ค.

###Baseflight USART

baseflight์˜ USART๋Š” ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฌถ์—ฌ์žˆ๋Š” ํ˜•ํƒœ๋‹ค.

  • drv_uart.c,h : usart ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™”, ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ
  • drv_serial.c,h : usart ์ถ”์ƒํ™”
  • serial.c : baseflight ์ „์šฉ ์‹œ๋ฆฌ์–ผํ†ต์‹  ์ฒ˜๋ฆฌ, CLI(command line interface)

์‹ค์ œ baseflight์˜ USART ๋ถ€๋ถ„๋งŒ ๊ฐ€์ ธ๋‹ค ์“ฐ๊ณ  ์‹ถ์œผ๋ฉด, drv_uart.c,h ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์žˆ์œผ๋ฉด ๋œ๋‹ค. ๋‚˜๋จธ์ง€ ๋‘ ๊ฐœ๋Š” baseflight์—์„œ ์“ฐ์ด๊ธฐ ์œ„ํ•ด ๋ชจ๋“ˆํ™” ๋œ ํ˜•ํƒœ๋กœ ๋˜์–ด์žˆ๋‹ค.

drv_serial.c,h

์‹œ๋ฆฌ์–ผ ํ†ต์‹ ์„ ์œ„ํ•œ ํฌํŠธ ๊ตฌ์กฐ์ฒด์™€, ์‹œ๋ฆฌ์–ผ ํฌํŠธ ์ถ”์ƒํ™”๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ํ…Œ์ด๋ธ”์„ ์„ ์–ธํ•˜๊ณ  ์žˆ๋‹ค.

๊ฐ€์žฅ ํ•ต์‹ฌ์ธ serialPort_t ๊ตฌ์กฐ์ฒด๋ฅผ ๋ˆˆ์—ฌ๊ฒจ๋ณด์ž.

typedef enum portMode_t {
    MODE_RX = 1 << 0,
    MODE_TX = 1 << 1,
    MODE_RXTX = MODE_RX | MODE_TX,
    MODE_SBUS = 1 << 2,
} portMode_t;

typedef struct serialPort {

    const struct serialPortVTable *vTable; // serial port ๊ฐ€์ƒํ•จ์ˆ˜ ํ…Œ์ด๋ธ”, ํ˜„์žฌ๋Š” ํ•˜๋‚˜๋งŒ ์“ฐ์ž„.

    portMode_t mode; // Rx,Tx ์„ค์ •
    uint32_t baudRate;

    uint32_t rxBufferSize; // receiver buffer size
    uint32_t txBufferSize; // transmitter buffer size
    volatile uint8_t *rxBuffer; // receiver buffer pointer
    volatile uint8_t *txBuffer; // transmitter buffer size
    uint32_t rxBufferHead; // receiver buffer ์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋  index
    uint32_t rxBufferTail; // receiver buffer ์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ์ฒซ ๋ฒˆ์งธ index
    uint32_t txBufferHead; // transmitter buffer ์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋  index
    uint32_t txBufferTail; // transmitter buffer ์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ์ฒซ ๋ฒˆ์งธ index

    // FIXME rename member to rxCallback
    serialReceiveCallbackPtr callback;
} serialPort_t;

mode, baudRate ๋ณ€์ˆ˜๋กœ ์“ฐ๊ธฐ์šฉ, ์ฝ๊ธฐ์šฉ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•˜๋ฉฐ, Serial BaudRate๋ฅผ ์„ค์ •ํ•œ๋‹ค.

์‹œ๋ฆฌ์–ผํ†ต์‹ ์„ ์œ„ํ•ด ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๋ฒ„ํผ๋Š” Ringํ˜•ํƒœ์ด๋ฉฐ, xxBufferHead ๋ณ€์ˆ˜๊ฐ€ ์ •๋ณด๊ฐ€ ์ €์žฅ๋  index๋ฅผ ๊ฐ€๋ฅดํ‚ค๋ฉฐ, xxBufferTail์€ ์ฒซ ๋ฒˆ์งธ ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ index๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ๋ฒ„ํผ์ •๋ณด๋ฅผ transmittํ•œ๋‹ค๋ฉด, Tail index๋ถ€ํ„ฐ Head index๊นŒ์ง€ ํ•˜๋‚˜์”ฉ ์ „์†กํ•˜๊ฒŒ ๋œ๋‹ค. ๋ชจ๋“  ๋ฒ„ํผ๊ฐ€ ์ „์†ก ๋˜์—ˆ๋‹ค๋ฉด, Tail index == Head index ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ์ด ๋น„๊ต๋กœ ๋ฒ„ํผ๊ฐ€ ๋น„์–ด์žˆ๋Š”์ง€ ํŒ๋‹จํ•œ๋‹ค.

C์–ธ์–ด๋กœ C++์˜ virtual function์„ ํ‰๋‚ด๋‚ธ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๊ตฌ์กฐ์ฒด serialPortVTable์ด ์žˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๋˜‘๊ฐ™์€ ํ•จ์ˆ˜๋งŒ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๊ตฌ์กฐ์ฒด๋Š” ์“ฐ๊ณ ๋Š” ์žˆ์ง€๋งŒ, ์ œ๋Œ€๋กœ ์“ฐ์ง€ ์•Š๊ณ  ์žˆ๋‹ค.

serialPortVTable์€ ์‹œ๋ฆฌ์–ผ read, write์™€ ์‹œ๋ฆฌ์–ผ ํ†ต์‹  ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๊ณ , ์–ป์–ด์˜ค๋Š” ํ•จ์ˆ˜ํฌ์ธํ„ฐ ๋ชจ์Œ ๊ตฌ์กฐ์ฒด๋‹ค.

struct serialPortVTable {
    void (*serialWrite)(serialPort_t *instance, uint8_t ch);

    uint8_t (*serialTotalBytesWaiting)(serialPort_t *instance);

    uint8_t (*serialRead)(serialPort_t *instance);

    // Specified baud rate may not be allowed by an implementation, use serialGetBaudRate to determine actual baud rate in use.
    void (*serialSetBaudRate)(serialPort_t *instance, uint32_t baudRate);

    bool (*isSerialTransmitBufferEmpty)(serialPort_t *instance);

    void (*setMode)(serialPort_t *instance, portMode_t mode);
};

drv_serial.c ์—์„œ๋Š” drv_uart.c,h ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์žˆ๋Š” ํ•จ์ˆ˜๋“ค์„ ๋ž˜ํ•‘ํ•˜๊ณ  ์žˆ๋‹ค. ์‹œ๋ฆฌ์–ผํ†ต์‹ ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ drv_uart ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

drv_uart.c,h

USART ํ†ต์‹ ์„ ์œ„ํ•œ ํ•ต์‹ฌ ๊ตฌ์กฐ์ฒด๊ฐ€ ์„ ์–ธ๋˜์–ด์žˆ๊ณ , ์‹œ๋ฆฌ์–ผํฌํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , DMA, Interrupt๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค. ๋‹ค์‹œ๋งํ•˜๋ฉด, ์‹œ๋ฆฌ์–ผํ†ต์‹ ์˜ ํ•ต์‹ฌ ์ฝ”๋“œ๊ฐ€ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์žˆ๋‹ค.

typedef struct {
    serialPort_t port; // ์‹œ๋ฆฌ์–ผ ํ†ต์‹  ํฌํŠธ ์ •๋ณด

    // FIXME these are uart specific and do not belong in here
    DMA_Channel_TypeDef *rxDMAChannel; // receiver DMA ์ฑ„๋„ ํฌ์ธํ„ฐ
    DMA_Channel_TypeDef *txDMAChannel; // transmitter DMA ์ฑ„๋„ ํฌ์ธํ„ฐ

    uint32_t rxDMAIrq;
    uint32_t txDMAIrq;

    uint32_t rxDMAPos; // DMA reciever์ผ ๋•Œ, ๋ฒ„ํผ๋ฅผ ์ฝ์„ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
    bool txDMAEmpty; // DMA buffer๊ฐ€ ๋น„์–ด์žˆ์„ ๋•Œ true๊ฐ€ ๋œ๋‹ค.

    USART_TypeDef *USARTx; // ํ†ต์‹ ํ•˜๋Š” UART ํฌ์ธํ„ฐ
} uartPort_t;

๊ตฌ์กฐ์ฒด uartPort_t๋Š” DMA๋ฐฉ์‹๊ณผ Interrupt ๋ฐฉ์‹ ๋ชจ๋‘๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค. ์ž์„ธํžˆ ์–˜๊ธฐํ•˜์ž๋ฉด rxDMAChannel ์ด NULL์ด๋ผ๋ฉด ์ธํ„ฐ๋ŸฝํŠธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ , NULL์ด ์•„๋‹ˆ๋ผ๋ฉด DMA๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด ์‹œ๋ฆฌ์–ผํ†ต์‹ ์„ ํ•œ๋‹ค.

์‹œ๋ฆฌ์–ผํ†ต์‹ ์— ๊ด€๋ จ๋œ ์ •๋ณด๋Š” serialPort_t port;์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค. uartPort_t๋Š” DMA, Interrupt๋ฅผ ์ œ์–ด๋ฅผ ์œ„ํ•œ ๊ฐ์ฒด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

drv_uart ํ—ค๋” ํŒŒ์ผ

#pragma once

#define UART_BUFFER_SIZE    64

#define UART1_RX_BUFFER_SIZE    256
#define UART1_TX_BUFFER_SIZE    256
#define UART2_RX_BUFFER_SIZE    128
#define UART2_TX_BUFFER_SIZE    64
#define UART3_RX_BUFFER_SIZE    256
#define UART3_TX_BUFFER_SIZE    256
#define MAX_SERIAL_PORTS        3

// FIXME this is a uart_t really.  Move the generic properties into a separate structure (serialPort_t) and update the code to use it
typedef struct {
    serialPort_t port;

    // FIXME these are uart specific and do not belong in here
    DMA_Channel_TypeDef *rxDMAChannel; // receiver DMA ์ฑ„๋„ ํฌ์ธํ„ฐ
    DMA_Channel_TypeDef *txDMAChannel; // transmitter DMA ์ฑ„๋„ ํฌ์ธํ„ฐ

    uint32_t rxDMAIrq;
    uint32_t txDMAIrq;

    uint32_t rxDMAPos; // DMA reciever์ผ ๋•Œ, ๋ฒ„ํผ๋ฅผ ์ฝ์„ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
    bool txDMAEmpty; // DMA buffer๊ฐ€ ๋น„์–ด์žˆ์„ ๋•Œ true๊ฐ€ ๋œ๋‹ค.

    USART_TypeDef *USARTx;
} uartPort_t;

extern const struct serialPortVTable uartVTable[];

serialPort_t *uartOpen(USART_TypeDef *USARTx, serialReceiveCallbackPtr callback, uint32_t baudRate, portMode_t mode);

// serialPort API
void uartWrite(serialPort_t *instance, uint8_t ch);
uint8_t uartTotalBytesWaiting(serialPort_t *instance);
uint8_t uartRead(serialPort_t *instance);
void uartSetBaudRate(serialPort_t *s, uint32_t baudRate);
bool isUartTransmitBufferEmpty(serialPort_t *s);

์‹œ๋ฆฌ์–ผํฌํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋Š” uartOpen() ๋‹ค. USART1,2,3 ํฌํŠธ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋˜๋Š”๋ฐ, baseflight๋Š” ๊ฐ USARTํฌํŠธ๋งˆ๋‹ค ์ •ํ•ด์ง„ ์—ญํ• ์ด ์žˆ๋Š” ๋“ฏํ•˜๋‹ค. ๊ณต์šฉ usart ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์“ฐ๊ณ  ์‹ถ๋‹ค๋ฉด, serialUSART1,2,3() ํ•จ์ˆ˜๋ฅผ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

serialUSART1()๋กœ ์‹œ๋ฆฌ์–ผํฌํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋ฉด, Transmitter๋Š” DMA channel4 ๋กœ ๋™์ž‘ํ•œ๋‹ค. DMA1_Channel4_IRQn ์œผ๋กœ DMA ์ธํ„ฐ๋ŸฝํŠธ๋กœ ์ œ์–ด ๋œ๋‹ค. receiver๋Š” DMA๋กœ ๋™์ž‘ํ•œ๋‹ค. ์‹œ๋ฆฌ์–ผํ†ต์‹ ์œผ๋กœ ๋ถ€ํ„ฐ ๋ฐ›์€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด, uartPort_t.rxDMAPos๋ฅผ ์ด์šฉํ•ด์•ผํ•œ๋‹ค. rxDMAPos๋Š” ํ†ต์‹ ์œผ๋กœ๋ถ€ํ„ฐ ์ฝ์„ ์ •๋ณด ๊ฐœ์ˆ˜๋ฅผ ๋œปํ•˜๋ฉฐ, read() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ๋งˆ๋‹ค -1 ์”ฉ ์ค„์–ด๋“ ๋‹ค. rxDMAPos ๊ฐ’๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ ์‹ค์ œ ๋ฒ„ํผ์—์„œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ๋Š” 0 ~ buffersize ์ˆœ์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ uartRead()ํ•จ์ˆ˜์—์„œ ํ™•์ธํ•˜์ž.