text: #include <rthw.h>
  #include <rtthread.h>
  #include <rtdevice.h>
  
  #include <board.h>
  
  /* CME-M7 uart driver */
  struct CME_M7_uart
  {
      UART0_Type* uart_device;
      IRQn_Type irq;
  };
  
  #ifdef RT_USING_UART0
  struct CME_M7_uart uart0 =
  {
      UART0,
      UART0_INT_IRQn,
  };
  static struct rt_serial_device serial0;
  #endif /* RT_USING_UART0 */
  
  #ifdef RT_USING_UART2
  struct CME_M7_uart uart2 =
  {
      UART2,
      UART2_INT_IRQn,
  };
  static struct rt_serial_device serial2;
  #endif /* RT_USING_UART2 */
  
  static rt_err_t CME_M7_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  {
      struct CME_M7_uart* uart;
      UART_InitTypeDef init;
  
      RT_ASSERT(serial != RT_NULL);
      RT_ASSERT(cfg != RT_NULL);
  
      uart = (struct CME_M7_uart *)serial->parent.user_data;
  
      init.UART_BaudRate = cfg->baud_rate;
      init.UART_StopBits = UART_StopBits_1;
      init.UART_Parity = UART_Parity_None;
      init.UART_LoopBack = FALSE;
      init.UART_RxEn = TRUE;
      init.UART_CtsEn = FALSE;
  
      UART_Init(uart->uart_device, &init);
      uart->uart_device->RX_RESET = 1;
      UART_Enable(uart->uart_device, TRUE);
      uart->uart_device->RX_RESET = 0;
  
      return RT_EOK;
  }
  
  static rt_err_t CME_M7_control(struct rt_serial_device *serial, int cmd, void *arg)
  {
      struct CME_M7_uart* uart;
      NVIC_InitTypeDef NVIC_InitStructure;
  
      RT_ASSERT(serial != RT_NULL);
      uart = (struct CME_M7_uart *)serial->parent.user_data;
  
      switch (cmd)
      {
      case RT_DEVICE_CTRL_CLR_INT:
          /* disable rx irq */
          NVIC_InitStructure.NVIC_IRQChannel = uart->irq;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE;
          NVIC_Init(&NVIC_InitStructure);
  
          UART_EnableInt(uart->uart_device, UART_Int_RxNotEmpty, FALSE);
          break;
  
      case RT_DEVICE_CTRL_SET_INT:
          /* enable rx irq */
          NVIC_InitStructure.NVIC_IRQChannel = uart->irq;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelCmd = TRUE;
          NVIC_Init(&NVIC_InitStructure);
  
          UART_ClearInt(uart->uart_device, UART_Int_RxNotEmpty);
          UART_EnableInt(uart->uart_device, UART_Int_RxNotEmpty, TRUE);
          break;
      }
  
      return RT_EOK;
  }
  
  static int CME_M7_putc(struct rt_serial_device *serial, char ch)
  {
      struct CME_M7_uart* uart;
  
      RT_ASSERT(serial != RT_NULL);
      uart = (struct CME_M7_uart *)serial->parent.user_data;
  
      while(uart->uart_device->STATUS_b.TF); //waits for transmitter FIFO not full.
      uart->uart_device->TX_BUF = ch;
  
      return 1;
  }
  
  static int CME_M7_getc(struct rt_serial_device *serial)
  {
      int ch;
      struct CME_M7_uart* uart;
  
      RT_ASSERT(serial != RT_NULL);
      uart = (struct CME_M7_uart *)serial->parent.user_data;
  
      ch = -1;
  
      if(uart->uart_device->STATUS_b.RNE)
      {
          ch = uart->uart_device->RX_BUF & 0x00FF; /* Get Data from UART RX  */
      }
  
      return ch;
  }
  
  static const struct rt_uart_ops CME_M7_uart_ops =
  {
      CME_M7_configure,
      CME_M7_control,
      CME_M7_putc,
      CME_M7_getc,
  };
  
  int rt_hw_uart_init(void)
  {
      struct CME_M7_uart* uart;
      struct rt_serial_device *serial;
      struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  
  #ifdef RT_USING_UART0
      uart = &uart0;
      serial = &serial0;
  
      serial->ops    = &CME_M7_uart_ops;
      serial->config = config;
  
      /* register UART device */
      rt_hw_serial_register(serial,
                            "uart0",
                            RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                            uart);
  #endif /* RT_USING_UART0 */
  
  #ifdef RT_USING_UART2
      uart = &uart2;
      serial = &serial2;
  
      serial->ops    = &CME_M7_uart_ops;
      serial->config = config;
  
      /* register UART device */
      rt_hw_serial_register(serial,
                            "uart2",
                            RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                            uart);
  #endif /* RT_USING_UART2 */
  
      return RT_EOK;
  }
  INIT_BOARD_EXPORT(rt_hw_uart_init);
  
  static void CME_UART_IRQHandler(struct rt_serial_device *serial)
  {
      struct CME_M7_uart* uart;
  
      RT_ASSERT(serial != RT_NULL);
      uart = (struct CME_M7_uart *)serial->parent.user_data;
  
      if(UART_GetIntStatus(uart->uart_device, UART_Int_RxNotEmpty))
      {
          UART_ClearInt(uart->uart_device, UART_Int_RxNotEmpty);
          rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
      }
  
      if(UART_GetIntStatus(uart->uart_device, UART_Int_RxThresholdReach))
      {
          UART_ClearInt(uart->uart_device, UART_Int_RxThresholdReach);
      }
  
      if(UART_GetIntStatus(uart->uart_device, UART_Int_OverrunError))
      {
          UART_ClearInt(uart->uart_device, UART_Int_OverrunError);
      }
  
      if(UART_GetIntStatus(uart->uart_device, UART_Int_FrameError))
      {
          UART_ClearInt(uart->uart_device, UART_Int_FrameError);
      }
  
      if(UART_GetIntStatus(uart->uart_device, UART_Int_ParityError))
      {
          UART_ClearInt(uart->uart_device, UART_Int_ParityError);
      }
  }
  
  #ifdef RT_USING_UART0
  void UART0_IRQHandler(void)
  {
      CME_UART_IRQHandler(&serial0);
  }
  #endif /* RT_USING_UART0 */
  
  #ifdef RT_USING_UART2
  void UART2_IRQHandler(void)
  {
      CME_UART_IRQHandler(&serial2);
  }
  #endif /* RT_USING_UART2 */
  