Arduino UNO R4 - Driver Seriale, Modalita possibili

Se andiamo a guardare il reference del Serial.begin(), vediamo che ha due parametri (il secondo è opzionale); il primo la velocità in bps ed il secondo la modalità con cui trasmette (numero di bit, parità, stop bits) e, per tale secondo parametro ("config") è riportato un elenco che da tutte le possibili configurazioni accettate senza altre indicazioni sulla MCU utilizzata ... ma ...

... in realtà, se si legge il datasheet del RA4M1 Renesas si scopre che le uniche configurazioni ammesse sono quelle a 7, 8 e 9 bits e NON supporta configurazioni a 5 o 6 bits che, se selezionate, possono creare problemi.

Purtroppo, non basta ... prendiamo Serial.cpp del core Arduino UNO R4 ed esaminiamo cosa in realtà troviamo:

/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate, uint16_t config) {
/* -------------------------------------------------------------------------- */  
  int max_index = PINS_COUNT;

  init_ok = cfg_pins(max_index);
  
  if(init_ok) {
    UART::g_uarts[channel]        = this;

    uart_baud.semr_baudrate_bits_b.abcse          = 0;
    uart_baud.semr_baudrate_bits_b.abcs           = 0;
    uart_baud.semr_baudrate_bits_b.bgdm           = 1;
    uart_baud.cks                                 = 0;
    uart_baud.brr                                 = 25;
    uart_baud.mddr                                = (uint8_t) 256;
    uart_baud.semr_baudrate_bits_b.brme           = false;

    uart_cfg_extend.clock                         = SCI_UART_CLOCK_INT;
    uart_cfg_extend.rx_edge_start                 = SCI_UART_START_BIT_FALLING_EDGE;
    uart_cfg_extend.noise_cancel                  = SCI_UART_NOISE_CANCELLATION_DISABLE;
    uart_cfg_extend.rx_fifo_trigger               = SCI_UART_RX_FIFO_TRIGGER_MAX;
    uart_cfg_extend.p_baud_setting                = &uart_baud;
    uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_RTS;
    uart_cfg_extend.flow_control_pin              = (bsp_io_port_pin_t) UINT16_MAX;
    if (rts_pin != -1 && cts_pin != -1) {
      uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_HARDWARE_CTSRTS;
    }
    uart_cfg_extend.rs485_setting.enable          = SCI_UART_RS485_DISABLE;
    uart_cfg_extend.rs485_setting.polarity        = SCI_UART_RS485_DE_POLARITY_HIGH;
    uart_cfg_extend.rs485_setting.de_control_pin  = (bsp_io_port_pin_t) UINT16_MAX;
    
    uart_cfg.channel                              = channel; 
    uart_cfg.p_context                            = NULL;
    uart_cfg.p_extend                             = &uart_cfg_extend;
    uart_cfg.p_transfer_tx                        = NULL;
    uart_cfg.p_transfer_rx                        = NULL;
  
    switch(config){
      case SERIAL_8N1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8N2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8E1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8E2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8O1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8O2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
    }
    
    uart_cfg.p_callback = UART::WrapperCallback;
  }
  else {
    return;
  }

  init_ok &= setUpUartIrqs(uart_cfg);
  
  fsp_err_t err;
  const bool bit_mod = true;
  const uint32_t err_rate = 3000; //means 3%

  err = R_SCI_UART_BaudCalculate(baudrate, bit_mod, err_rate, &uart_baud);
  if (uart_baud.mddr == 0) {
    err = R_SCI_UART_BaudCalculate(baudrate, false, err_rate, &uart_baud);
  }
  err = R_SCI_UART_Open (&uart_ctrl, &uart_cfg);
  if(err != FSP_SUCCESS) while(1);
  err = R_SCI_UART_BaudSet(&uart_ctrl, (void *) &uart_baud);
  if(err != FSP_SUCCESS) while(1);

  rxBuffer.clear();
  txBuffer.clear();
}

... nello switch(config) vengono esaminate SOLO ed esclusivamente le possibilità ad 8 bit ignorando completamente tutte le altre !!!

Quindi ... il "core" rilasciato supporta solo trasmissioni a 8 bit :angry:

Guglielmo

Anche per questa cosa svariati utenti del forum si sono rimboccati le maniche e, almeno per i 7 bit, la modifica è risultata banale (poteva tranquillamente essere messa nel "core", ma ... tant'è) dato che occorre semplicemente duplicare le righe cambiando i valori del case, cosa che ha fatto l'utente Kurt_E:

/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate, uint16_t config) {
/* -------------------------------------------------------------------------- */  
  int max_index = PINS_COUNT;

  init_ok = cfg_pins(max_index);
  
  if(init_ok) {
    UART::g_uarts[channel]        = this;

    uart_baud.semr_baudrate_bits_b.abcse          = 0;
    uart_baud.semr_baudrate_bits_b.abcs           = 0;
    uart_baud.semr_baudrate_bits_b.bgdm           = 1;
    uart_baud.cks                                 = 0;
    uart_baud.brr                                 = 25;
    uart_baud.mddr                                = (uint8_t) 256;
    uart_baud.semr_baudrate_bits_b.brme           = false;

    uart_cfg_extend.clock                         = SCI_UART_CLOCK_INT;
    uart_cfg_extend.rx_edge_start                 = SCI_UART_START_BIT_FALLING_EDGE;
    uart_cfg_extend.noise_cancel                  = SCI_UART_NOISE_CANCELLATION_DISABLE;
    uart_cfg_extend.rx_fifo_trigger               = SCI_UART_RX_FIFO_TRIGGER_MAX;
    uart_cfg_extend.p_baud_setting                = &uart_baud;
    uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_RTS;
    uart_cfg_extend.flow_control_pin              = (bsp_io_port_pin_t) UINT16_MAX;
    if (rts_pin != -1 && cts_pin != -1) {
      uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_HARDWARE_CTSRTS;
    }
    uart_cfg_extend.rs485_setting.enable          = SCI_UART_RS485_DISABLE;
    uart_cfg_extend.rs485_setting.polarity        = SCI_UART_RS485_DE_POLARITY_HIGH;
    uart_cfg_extend.rs485_setting.de_control_pin  = (bsp_io_port_pin_t) UINT16_MAX;
    
    uart_cfg.channel                              = channel; 
    uart_cfg.p_context                            = NULL;
    uart_cfg.p_extend                             = &uart_cfg_extend;
    uart_cfg.p_transfer_tx                        = NULL;
    uart_cfg.p_transfer_rx                        = NULL;
  
    switch(config){
      case SERIAL_8N1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8N2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8E1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8E2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8O1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8O2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      // add 7 bit support
      case SERIAL_7N1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7N2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_7E1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7E2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_7O1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7O2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;

    }
    
    uart_cfg.p_callback = UART::WrapperCallback;
  }
  else {
    return;
  }

  init_ok &= setUpUartIrqs(uart_cfg);
  
  fsp_err_t err;
  const bool bit_mod = true;
  const uint32_t err_rate = 3000; //means 3%

  err = R_SCI_UART_BaudCalculate(baudrate, bit_mod, err_rate, &uart_baud);
  if (uart_baud.mddr == 0) {
    err = R_SCI_UART_BaudCalculate(baudrate, false, err_rate, &uart_baud);
  }
  err = R_SCI_UART_Open (&uart_ctrl, &uart_cfg);
  if(err != FSP_SUCCESS) while(1);
  err = R_SCI_UART_BaudSet(&uart_ctrl, (void *) &uart_baud);
  if(err != FSP_SUCCESS) while(1);

  rxBuffer.clear();
  txBuffer.clear();
}

che ha anche fatto, su github, una pull-request per implementare la cosa nel core. Speriamo venga accettata ed implementata in tempi brevi ... :roll_eyes:

Intanto, comunque, se vi occorre lavorare a 7 bits ... avete la soluzione :wink:

Guglielmo

P.S.: Per i 9 bits la cosa sembra un po' più complicata ... chuygen, nella sua modifica al driver seriale, sembra aver implementato la modalità 9N1, ma non mi è ben chiaro come utilizzarla ... mi informerò ...

Ups ... non mi ero accorto che il thread era nella sezione sbagliata ... ora è in quella giusta, scusate.

Guglielmo

Ahi, ahi, ora ti devi autobannare per 2 gg :rofl: :rofl:

1 Like