PSoC : UART + Capsense Tuner 2023/10/12

2023年の6月に「PSoC4 : UART + Capsense Tuner」の記事をアップしたのですが、10月になって気がつくと、こっそりアップデートしていて、6月時点のプログラムでは文字化けがたくさん起こりました。

シリアル通信で、タッチの情報を出力していたのですが、けっこうな頻度で文字化けしました。

画像に alt 属性が指定されていません。ファイル名: 1a79b0f35061008ed9df73a214ba98fc-1024x255.png

文字化けのタイミングを観察すると、タッチセンサのスキャンをすると割り込みが入るようで、UARTでデータを送る間にその割り込みが入ると、通信速度が合わなくなる感じです。6月の時点ではその割り込みをブロックしてくれる「Cy_SCB_UART_PutArrayBlocking」関数が使われているだけでしたが、10月には送信完了待ちの処理が追加されていました。

ModusToolBoxの「CAPSENSE Tuner」に読み込むだけだとこれでよいのですが、ArduinoUnoで使えるようにしたく、「SoftwareSerialでPSoCとシリアル通信をして、ArduinoのハードウェアシリアルでPC側に表示する」と考えました。

SoftwareSerialは、ArduinoUnoだと「57600bps」が最大なのか、それ以上で通信するとうまくいきません。そこで、57600bpsで受信したデータを、115200bpsでPCに送信するようにしました。逆にPCへの送信側を遅くすると、その間に受信したデータがバンバン届くので、取りこぼすだろうなと思います。

どんなデータが届くのか、Arduino側でデータを見たのですが、1つのタッチボタンの情報だけなのに、94バイトもありました。プログラムを調べてみるとタッチボタンの場合、センサの数に関係なく共通した情報が24バイト、センサ1つごとに56バイトが連続し、その後にタッチ情報(欲しい部分)が10バイト連続します。

ボタン1つの場合、欲しいタッチ情報までは、24+56バイト進んで、次の10バイトを読みます。
ボタン2つの場合、欲しいタッチ情報までは、24+56+56+10バイト進んで、次の10バイトを読みます。
プログラムで計算すると、以下のようになりました。

int commonText_size = 24;
int widgetContext_size = 56;
int sensorContext_size = 10;

//1つ目のタッチ情報先頭までの計算
uint16_t address1 = commonText_size + (widgetContext_size * 2) + (sensorContext_size * 0);

//2つ目のタッチ情報先頭までの計算
uint16_t address2 = commonText_size + (widgetContext_size * 2) + (sensorContext_size * 1);

以下のプログラムは、3つのタッチボタンの情報をArduinoのソフトウェアシリアル通信(57600bps)で読み出し、同じくArduinoからシリアル通信(115200bps)でPCに表示するプログラムです。

#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);  // RX, TX

uint8_t buff[500];
int last_buff[2];
int pos;
int tc = 3;

typedef struct {
  unsigned int raw;
  unsigned int bsln;
  unsigned int diff;
  uint8_t status;
  uint8_t negBslnRstCnt;
  uint8_t idacComp;
  uint8_t bslnExt;
} sensor_context;

typedef struct {
  sensor_context sensorContext[3];
} cy_stc_capsense_tuner_t;

cy_stc_capsense_tuner_t capsense = {
  .sensorContext = {
    {
      /* Button0 */
      .raw = 0u,
      .bsln = 0u,
      .diff = 0u,
      .status = 0u,
      .negBslnRstCnt = 0u,
      .idacComp = 32u,
      .bslnExt = 0u,
    },
    {
      /* Button1 */
      .raw = 0u,
      .bsln = 0u,
      .diff = 0u,
      .status = 0u,
      .negBslnRstCnt = 0u,
      .idacComp = 32u,
      .bslnExt = 0u,
    },
    {
      /* Button2 */
      .raw = 0u,
      .bsln = 0u,
      .diff = 0u,
      .status = 0u,
      .negBslnRstCnt = 0u,
      .idacComp = 32u,
      .bslnExt = 0u,
    } }
};

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  // while (!Serial) {
  //   ;  // wait for serial port to connect. Needed for native USB port only
  // }
  mySerial.begin(57600);
}

void loop() {
  while (mySerial.available() > 0) {
    uint8_t c = mySerial.read();

    if (c == 0x0a && last_buff[0] == 0x0d) {
      pos = 0;
    } else if (c == 0xFF && last_buff[0] == 0xFF && last_buff[1] == 0x00) {

      int commonText_size = 24;
      int widgetContext_size = 56;
      int sensorContext_size = 10;

      for (int i = 0; i < tc; i++) {
        uint16_t ad = commonText_size + (widgetContext_size * tc) + (sensorContext_size * i) -1;
        capsense.sensorContext[i].raw = (buff[++ad]) | (buff[++ad] << 8);
        capsense.sensorContext[i].bsln = (buff[++ad]) | (buff[++ad] << 8);
        capsense.sensorContext[i].diff = (buff[++ad]) | (buff[++ad] << 8);
        capsense.sensorContext[i].status = (buff[++ad]);
        capsense.sensorContext[i].negBslnRstCnt = (buff[++ad]);
        capsense.sensorContext[i].idacComp = (buff[++ad]);
        capsense.sensorContext[i].bslnExt = (buff[++ad]);

        Serial.print(capsense.sensorContext[i].diff);    //近接の数値
        Serial.print(",");
        Serial.print(capsense.sensorContext[i].status);  //タッチのオンオフ(0か1)
        Serial.print(",");
      }
      Serial.println();
    } else {
      buff[pos] = c;
      pos++;
    }

    last_buff[1] = last_buff[0];
    last_buff[0] = c;
  }

}