Вопросы об этом серийном коде связи? [Cortex-M4] - PullRequest
0 голосов
/ 12 ноября 2018

Я смотрю на следующий код от STMicroelectronics по реализации связи USART с прерываниями

#include <stm32f10x_lib.h>                        // STM32F10x Library Definitions
#include <stdio.h>
#include "STM32_Init.h"                           // STM32 Initialization


/*----------------------------------------------------------------------------
  Notes:
  The length of the receive and transmit buffers must be a power of 2.
  Each buffer has a next_in and a next_out index.
  If next_in = next_out, the buffer is empty.
  (next_in - next_out) % buffer_size = the number of characters in the buffer.
 *----------------------------------------------------------------------------*/
#define TBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
#define RBUF_SIZE   256      /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/

/*----------------------------------------------------------------------------
 *----------------------------------------------------------------------------*/
#if TBUF_SIZE < 2
#error TBUF_SIZE is too small.  It must be larger than 1.
#elif ((TBUF_SIZE & (TBUF_SIZE-1)) != 0)
#error TBUF_SIZE must be a power of 2.
#endif

#if RBUF_SIZE < 2
#error RBUF_SIZE is too small.  It must be larger than 1.
#elif ((RBUF_SIZE & (RBUF_SIZE-1)) != 0)
#error RBUF_SIZE must be a power of 2.
#endif

/*----------------------------------------------------------------------------
 *----------------------------------------------------------------------------*/
struct buf_st {
  unsigned int in;                                // Next In Index
  unsigned int out;                               // Next Out Index
  char buf [RBUF_SIZE];                           // Buffer
};

static struct buf_st rbuf = { 0, 0, };
#define SIO_RBUFLEN ((unsigned short)(rbuf.in - rbuf.out))

static struct buf_st tbuf = { 0, 0, };
#define SIO_TBUFLEN ((unsigned short)(tbuf.in - tbuf.out))

static unsigned int tx_restart = 1;               // NZ if TX restart is required

/*----------------------------------------------------------------------------
  USART1_IRQHandler
  Handles USART1 global interrupt request.
 *----------------------------------------------------------------------------*/
void USART1_IRQHandler (void) {
  volatile unsigned int IIR;
  struct buf_st *p;

    IIR = USART1->SR;
    if (IIR & USART_FLAG_RXNE) {                  // read interrupt
      USART1->SR &= ~USART_FLAG_RXNE;             // clear interrupt

      p = &rbuf;

      if (((p->in - p->out) & ~(RBUF_SIZE-1)) == 0) {
        p->buf [p->in & (RBUF_SIZE-1)] = (USART1->DR & 0x1FF);
        p->in++;
      }
    }

    if (IIR & USART_FLAG_TXE) {
      USART1->SR &= ~USART_FLAG_TXE;              // clear interrupt

      p = &tbuf;

      if (p->in != p->out) {
        USART1->DR = (p->buf [p->out & (TBUF_SIZE-1)] & 0x1FF);
        p->out++;
        tx_restart = 0;
      }
      else {
        tx_restart = 1;
        USART1->CR1 &= ~USART_FLAG_TXE;           // disable TX interrupt if nothing to send

      }
    }
}

/*------------------------------------------------------------------------------
  buffer_Init
  initialize the buffers
 *------------------------------------------------------------------------------*/
void buffer_Init (void) {

  tbuf.in = 0;                                    // Clear com buffer indexes
  tbuf.out = 0;
  tx_restart = 1;

  rbuf.in = 0;
  rbuf.out = 0;
}

/*------------------------------------------------------------------------------
  SenChar
  transmit a character
 *------------------------------------------------------------------------------*/
int SendChar (int c) {
  struct buf_st *p = &tbuf;

                                                  // If the buffer is full, return an error value
  if (SIO_TBUFLEN >= TBUF_SIZE)
    return (-1);

  p->buf [p->in & (TBUF_SIZE - 1)] = c;           // Add data to the transmit buffer.
  p->in++;

  if (tx_restart) {                               // If transmit interrupt is disabled, enable it
    tx_restart = 0;
    USART1->CR1 |= USART_FLAG_TXE;                // enable TX interrupt
  }

  return (0);
}

/*------------------------------------------------------------------------------
  GetKey
  receive a character
 *------------------------------------------------------------------------------*/
int GetKey (void) {
  struct buf_st *p = &rbuf;

  if (SIO_RBUFLEN == 0)
    return (-1);

  return (p->buf [(p->out++) & (RBUF_SIZE - 1)]);
}


/*----------------------------------------------------------------------------
  MAIN function
 *----------------------------------------------------------------------------*/
int main (void) {

  buffer_Init();                                  // init RX / TX buffers
  stm32_Init ();                                  // STM32 setup

  printf ("Interrupt driven Serial I/O Example\r\n\r\n");

  while (1) {                                     // Loop forever
    unsigned char c;

    printf ("Press a key. ");
    c = getchar ();
    printf ("\r\n");
    printf ("You pressed '%c'.\r\n\r\n", c);
  } // end while
} // end main

У меня следующие вопросы:

  1. В функции обработчика, когдаутверждение ((p->in - p->out) & ~(RBUF_SIZE-1)) когда-либо оценивается как значение, отличное от нуля?Если RBUF_SIZE является степенью 2, как указано, то ~(RBUF_SIZE-1) всегда должно быть нулем.Проверяется ли p->in> p->out?Даже если это не так, условное выражение все равно должно равняться нулю, верно?
  2. В следующей строке выполняется оператор p->buf [p->in & (RBUF_SIZE-1)] = (USART1->DR & 0x1FF);.Почему код И p->in с RBUF_SIZE-1?
  3. Какой тип буфера мы используем в этом коде?FIFO?

1 Ответ

0 голосов
/ 12 ноября 2018
  1. Не так. Например, предполагая 32-битную арифметику, если RBUF_SIZE == 0x00000100, то RBUF_SIZE-1 == 0x000000FF и ~(RBUF_SIZE-1) == 0xFFFFFF00 (это побитовое НЕ, а не логическое НЕ). Следовательно, проверка, на которую вы ссылаетесь, фактически совпадает с (p->in - p->out) < RBUF_SIZE, и неясно, почему она выше. ARM GCC 7.2.1 производит одинаковый код длины для двух (-O1).

  2. p->in & (RBUF_SIZE-1) совпадает с p->in % RBUF_SIZE, когда p->in не подписано. Опять же, не уверен, почему первый будет использоваться, когда последний яснее; конечно, он фактически заставляет компилятор вычислять модуль по операции AND, но, учитывая, что во время компиляции известно, что RBUF_SIZE является степенью двойки, я предполагаю, что большинство компиляторов могут это выяснить (опять же, ARM GCC 7.2.1, конечно, может, я только что попробовал - он выдает те же инструкции в любом случае).

  3. Похоже на это. FIFO реализован как кольцевой буфер.

...