Seeeduino XiaoをUART複数ポートで使う。(SERCOM+SoftweaUART)

ここを観に来る人はすでにXiaoについていろいろと調べていることでしょう。基本としてXiaoはUART、I2C、SPIが各1portづつ使用できる。

ところがCPUの機能SERCOMを使用すると3portを好きに割り当てられる。(SPIは使用する端子数が多いので2portまで)

ここではSERCOMの設定とIDEのメニューで変更できるように記述を掲載したいと思います。

このやり方を見つけるのにここのサイトを参考にしました。

次の3つのファイルを書き換えます。

C:\Users\ユーザー名\AppData\Local\Arduino15\packages\Seeeduino\hardware\samd\1.7.9\variants\XIAO_m0\variant.h

/*
 * SPI Interfaces
 */
#define SPI_INTERFACES_COUNT 0

#ifndef DNO_SERCOM0_INTERFACE
#ifndef DSERCOM0_I2C
#ifndef DSERCOM0_USART
//#ifdef  DSERCOM0_SPI
 // SPI interface for QSPI flash
#define PIN_SPI_MISO         (9u)
#define PIN_SPI_SCK          (8u)
#define PIN_SPI_MOSI         (10u)
#define PERIPH_SPI           sercom0
#define PAD_SPI_TX           SPI_PAD_2_SCK_3  // MOSI / SCK
#define PAD_SPI_RX           SERCOM_RX_PAD_1  // MISO

static const uint8_t SS = 4;
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
//#endif
#endif
#endif
#endif

#ifndef DNO_SERCOM2_INTERFACE
#ifndef DSERCOM2_I2C
#ifndef DSERCOM2_USART
//#ifdef  DSERCOM2_SPI
// SPI interface for QSPI flash
#define PIN_SPI_MISO1         (5u)
#define PIN_SPI_SCK1          (3u)
#define PIN_SPI_MOSI1         (2u)
#define PERIPH_SPI           sercom2
#define PAD_SPI_TX           SPI_PAD_2_SCK_3  // MOSI / SCK
#define PAD_SPI_RX           SERCOM_RX_PAD_1  // MISO

static const uint8_t SS2 = 1;
static const uint8_t MOSI2 = PIN_SPI_MOSI1;
static const uint8_t MISO2 = PIN_SPI_MISO1;
static const uint8_t SCK2 = PIN_SPI_SCK1;
//#endif
#endif
#endif
#endif

/*
 * Wire Interfaces
 */
#define WIRE_INTERFACES_COUNT 0


#ifndef DNO_SERCOM2_INTERFACE
#ifndef DSERCOM2_SPI
#ifndef DSERCOM2_USART
//#ifdef  DSERCOM2_I2C
 // "external" public i2c_1 interface
#define PIN_WIRE_SDA         (4u)
#define PIN_WIRE_SCL         (5u)
#define PERIPH_WIRE          sercom2
#define WIRE_IT_HANDLER      SERCOM2_Handler
static const uint8_t SDA = PIN_WIRE_SDA;
static const uint8_t SCL = PIN_WIRE_SCL;
//#endif
#endif
#endif
#endif

#ifndef DNO_SERCOM0_INTERFACE
#ifndef DSERCOM0_SPI
#ifndef DSERCOM0_USART
//#ifdef  DSERCOM0_I2C
// "external" public i2c_1 interface
#define PIN_WIRE1_SDA         (1u)
#define PIN_WIRE1_SCL         (9u)
#define PERIPH_WIRE          sercom0
#define WIRE_IT_HANDLER      SERCOM0_Handler
static const uint8_t SDA1 = PIN_WIRE1_SDA;
static const uint8_t SCL1 = PIN_WIRE1_SCL;
//#endif
#endif
#endif
#endif

#ifndef DNO_SERCOM4_INTERFACE
#ifndef DSERCOM4_USART
//#ifdef  DSERCOM4_I2C
// "external" public i2c_1 interface
#define PIN_WIRE2_SDA         (6u)
#define PIN_WIRE2_SCL         (7u)
#define PERIPH_WIRE          sercom4
#define WIRE_IT_HANDLER      SERCOM4_Handler
static const uint8_t SDA2 = PIN_WIRE2_SDA;
static const uint8_t SCL2 = PIN_WIRE2_SCL;
//#endif
#endif
#endif


// USB
// ---
#define PIN_USB_HOST_ENABLE (14ul)
#define PIN_USB_DM          (15ul)
#define PIN_USB_DP          (16ul)

// I2S Interfaces
// --------------
#define I2S_INTERFACES_COUNT 3

// Serial ports
// ------------
#ifdef __cplusplus
#include "SERCOM.h"
#include "Uart.h"

// Instances of SERCOM
extern SERCOM sercom0;
extern SERCOM sercom1;
extern SERCOM sercom2;
extern SERCOM sercom3;
extern SERCOM sercom4;
extern SERCOM sercom5;

#ifndef DNO_SERCOM4_INTERFACE
#ifndef DSERCOM4_I2C
//#ifdef  DSERCOM4_USART
extern Uart Serial1;
#define PIN_SERIAL1_TX       (6ul)
#define PIN_SERIAL1_RX       (7ul)
#define PAD_SERIAL1_TX       (UART_TX_PAD_0)
#define PAD_SERIAL1_RX       (SERCOM_RX_PAD_1)
//#endif
#endif
#endif

#ifndef DNO_SERCOM0_INTERFACE
#ifndef DSERCOM0_I2C
#ifndef DSERCOM0_SPI
//#ifdef  DSERCOM0_USART
extern Uart Serial2;
#define PIN_SERIAL2_TX       (10ul)
#define PIN_SERIAL2_RX       (8ul)
#define PAD_SERIAL2_TX       (UART_TX_PAD_2)
#define PAD_SERIAL2_RX       (SERCOM_RX_PAD_3)
//#endif
#endif
#endif
#endif

#ifndef DNO_SERCOM2_INTERFACE
#ifndef DSERCOM2_I2C
#ifndef DSERCOM2_SPI
//#ifdef  DSERCOM2_USART
extern Uart Serial3;
#define PIN_SERIAL3_TX       (4ul)
#define PIN_SERIAL3_RX       (5ul)
#define PAD_SERIAL3_TX       (UART_TX_PAD_0)
#define PAD_SERIAL3_RX       (SERCOM_RX_PAD_1)
//#endif
#endif
#endif
#endif

#endif // __cplusplus



// These serial port names are intended to allow libraries and architecture-neutral
// sketches to automatically default to the correct port name for a particular type
// of use.  For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
// the first hardware serial port whose RX/TX pins are not dedicated to another use.
//
// SERIAL_PORT_MONITOR        Port which normally prints to the Arduino Serial Monitor
//
// SERIAL_PORT_USBVIRTUAL     Port which is USB virtual serial
//
// SERIAL_PORT_LINUXBRIDGE    Port which connects to a Linux system via Bridge library
//
// SERIAL_PORT_HARDWARE       Hardware serial port, physical RX & TX pins.
//
// SERIAL_PORT_HARDWARE_OPEN  Hardware serial ports which are open for use.  Their RX & TX
//                            pins are NOT connected to anything by default.
#define SERIAL_PORT_USBVIRTUAL      SerialUSB
#define SERIAL_PORT_MONITOR         SerialUSB

#ifndef DNO_SERCOM4_INTERFACE

#define SERIAL_PORT_HARDWARE        Serial1
#define SERIAL_PORT_HARDWARE_OPEN   Serial1

#endif

// Alias Serial to SerialUSB
#define Serial                      SerialUSB

この記述で動作させた際、ALT-SERCOM0(PAD0,PAD1)に割り当てたUARTが上手く動作しませんでした。調査はしてないのですが、ALT-SERCOM0とSERCOM0が干渉したのではないかと思っています。なので現在はSERCOM0はPAD2,PAD3に割り当てています。

I2CとSPIについては未検証です。どなたか検証したら結果教えてください。

あぁ、やっぱり動作確認しなければいけませんね。UARTも動かなくなってました。記述を修正しました(2020/12/02)。申し訳ありません!!

C:\Users\ユーザー名\AppData\Local\Arduino15\packages\Seeeduino\hardware\samd\1.7.9\variants\XIAO_m0\variant.cpp

// Multi-serial objects instantiation
SERCOM sercom0( SERCOM0 ) ;
SERCOM sercom1( SERCOM1 ) ;
SERCOM sercom2( SERCOM2 ) ;
SERCOM sercom3( SERCOM3 ) ;
SERCOM sercom4( SERCOM4 ) ;
SERCOM sercom5( SERCOM5 ) ;

#ifndef DNO_SERCOM4_INTERFACE
#ifndef DSERCOM4_I2C
//#ifdef  DSERCOM4_USART
Uart Serial1(&sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX);
void SERCOM4_Handler()
{
	Serial1.IrqHandler();
}
//#endif
#endif
#endif

#ifndef DNO_SERCOM0_INTERFACE
#ifndef DSERCOM0_I2C
#ifndef DSERCOM0_SPI
//#ifdef  DSERCOM0_USART
Uart Serial2(&sercom0, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
void SERCOM0_Handler()
{
	Serial2.IrqHandler();
}
//#endif
#endif
#endif
#endif

#ifndef DNO_SERCOM2_INTERFACE
#ifndef DSERCOM2_I2C
#ifndef DSERCOM2_SPI
//#ifdef  DSERCOM2_USART

Uart Serial3(&sercom2, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
void SERCOM2_Handler()
{
	Serial3.IrqHandler();
}
//#endif
#endif
#endif
#endif

この記述にしてから動作確認していないので面倒くさい人は少しおまちください。近日中に動作報告をこのページに載せる予定です。

C:\Users\ユーザー名\AppData\Local\Arduino15\packages\Seeeduino\hardware\samd\1.7.9\boards

# Copyright (c) 2014-2015 Arduino LLC.  All right reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      :
      :
      :
menu.sercom0 = SERCOM0
menu.sercom2 = SERCOM2
menu.sercom4 = SERCOM4
      :
      :
      :
# Seeed XIAO M0 (SAMD21)
# ------------------------------
seeed_XIAO_m0.name=Seeeduino XIAO
seeed_XIAO_m0.vid.0=0x2886
seeed_XIAO_m0.pid.0=0x802F
seeed_XIAO_m0.vid.1=0x2886
seeed_XIAO_m0.pid.1=0x002F
seeed_XIAO_m0.upload.tool=bossac
seeed_XIAO_m0.upload.protocol=sam-ba
seeed_XIAO_m0.upload.maximum_size=262144
seeed_XIAO_m0.upload.offset=0x2000
seeed_XIAO_m0.upload.use_1200bps_touch=true
seeed_XIAO_m0.upload.wait_for_upload_port=true
seeed_XIAO_m0.upload.native_usb=true
seeed_XIAO_m0.build.mcu=cortex-m0plus
seeed_XIAO_m0.build.f_cpu=48000000L
seeed_XIAO_m0.build.usb_product="Seeed XIAO M0"
seeed_XIAO_m0.build.usb_manufacturer="Seeed"
seeed_XIAO_m0.build.board=SEEED_XIAO_M0
seeed_XIAO_m0.build.core=arduino
seeed_XIAO_m0.build.extra_flags= -DARDUINO_SAMD_ZERO -D__SAMD21__ -D__SAMD21G18A__ -DARM_MATH_CM0PLUS -DSEEED_XIAO_M0 {build.usb_flags} {sercom0_flag} {sercom2_flag} {sercom4_flag} 
seeed_XIAO_m0.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld
seeed_XIAO_m0.build.openocdscript=openocd_scripts/XIAO_m0.cfg
seeed_XIAO_m0.build.variant=XIAO_m0
seeed_XIAO_m0.build.variant_system_lib=
seeed_XIAO_m0.build.vid=0x2886
seeed_XIAO_m0.build.pid=0x802F
seeed_XIAO_m0.bootloader.tool=openocd
seeed_XIAO_m0.bootloader.file=XIAOM0/bootloader-XIAO_m0-v3.7.0-33-g90ff611-dirty.bin
seeed_XIAO_m0.menu.usbstack.arduino=Arduino
seeed_XIAO_m0.menu.usbstack.tinyusb=TinyUSB
seeed_XIAO_m0.menu.usbstack.tinyusb.build.flags.usbstack=-DUSE_TINYUSB
seeed_XIAO_m0.menu.debug.off=Off
seeed_XIAO_m0.menu.debug.on=On
seeed_XIAO_m0.menu.debug.on.build.flags.debug=-g -DDEBUG=1
seeed_XIAO_m0.menu.sercom2.include1=USART
seeed_XIAO_m0.menu.sercom2.include1.sercom2_flag=-DSERCOM2_USART
seeed_XIAO_m0.menu.sercom2.include2=I2C
seeed_XIAO_m0.menu.sercom2.include2.sercom2_flag=-DSERCOM2_I2C
seeed_XIAO_m0.menu.sercom2.include3=SPI
seeed_XIAO_m0.menu.sercom2.include3.sercom2_flag=-DSERCOM2_SPI
seeed_XIAO_m0.menu.sercom2.exclude4=None
seeed_XIAO_m0.menu.sercom2.exclude4.sercom2_flag=-DNO_SERCOM2_INTERFACE
seeed_XIAO_m0.menu.sercom0.include5=USART
seeed_XIAO_m0.menu.sercom0.include5.sercom0_flag=-DSERCOM0_USART
seeed_XIAO_m0.menu.sercom0.include6=I2C
seeed_XIAO_m0.menu.sercom0.include6.sercom0_flag=-DSERCOM0_I2C
seeed_XIAO_m0.menu.sercom0.include7=SPI
seeed_XIAO_m0.menu.sercom0.include7.sercom0_flag=-DSERCOM0_SPI
seeed_XIAO_m0.menu.sercom0.exclude8=None
seeed_XIAO_m0.menu.sercom0.exclude8.sercom0_flag=-DNO_SERCOM0_INTERFACE
seeed_XIAO_m0.menu.sercom4.include9=USART
seeed_XIAO_m0.menu.sercom4.include9.sercom4_flag=-DSERCOM4_USART
seeed_XIAO_m0.menu.sercom4.include10=I2C
seeed_XIAO_m0.menu.sercom4.include10.sercom4_flag=-DSERCOM4_I2C
seeed_XIAO_m0.menu.sercom4.exclude11=None
seeed_XIAO_m0.menu.sercom4.exclude11.sercom4_flag=-DNO_SERCOM4_INTERFACE

ここまで入れるとarduinoIDEのメニューがSSのようになります。

となれば成功です。

ハードウェアで実装できるUARTは3portが限界。しかしソフトウェアシリアルを使用すれば最大5ポートとして使用できます。これはスケッチ例にあるのでここでは説明しませんが、このソフトウェアシリアルは「listen()」しているポートしか読み書きできないのでよく使い方を考える必要があります。

私は5portはあきらめて完全動作する4portハブとして使用しています。