WROOM32 UART sample 2 

先日に引き続き、EspressifにあるUARTのサンプルを動かしてみました。

試したのは以下のコードです。

- /esp-idf/examples/peripherals/uart_events

#Step1  デバイスの接続
今回は特にないです。
理由は以下です。

ソースコードのコメントを確認します。

> /**
 * This example shows how to use the UART driver to handle special UART events.
 *
 * It also reads data from UART0 directly, and echoes it to console.
 *
 * - port: UART0
 * - rx buffer: on
 * - tx buffer: on
 * - flow control: off
 * - event queue: on
 * - pin assignment: txd(default), rxd(default)
 */

このサンプルではUART0を使用
ハードウェアフロー制御なしなので、CTS/RTSの接続がなくても通信できます。
前回のUARTのサンプルuart_echoではピンを指定しましたが、今回はデフォルトのPINを使うようです。

> uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

UARTのポート0の txd(default), rxd(default)を接続すれば良いですね。

データシートのPINアサインでUART0を確認します

![UART0.png](https://qiita-image-store.s3.amazonaws.com/0/165672/c6670f1c-964c-8a45-2b9a-bad93903bb82.png)
ボードの回路図を確認します。
![UART0_Doit.png](https://qiita-image-store.s3.amazonaws.com/0/165672/0da24ee1-72f6-32b1-11a3-85dd5efaea97.png)
![UART0_Doit_USBpart.png](https://qiita-image-store.s3.amazonaws.com/0/165672/7efc9c92-1f2c-de06-a0e6-f2aec9832f95.png)

回路図のUSB Partを見ると、UART0はボード上のシリアル通信チップに接続されていますので、PCとWROOM32の書き込み時に使用しているUSBで動作確認できます。なので特に外部基盤との接続は必要ないです。

<補足>
TX0, RX0を外部基盤を接続することも可能ですが、試したところ、WROOM32のプログラム書き込み時にバッティングしてしまい書き込みエラーになりました。外部基盤を書き込み時に外す、もしくは動作していない条件であれば書き込みできます。外部基盤との接続はStep4に書きます。

#Step2  コードのビルド　
変更しないのでビルドするだけです。

`make -j5 flash monitor`
ここでつまずいたら、[WROOM-32 セットアップ](http://qiita.com/T-YOSH/items/fac86e29e86b91d23136#step-1-quick-steps)の投稿を見てください。

```uart_echo/main/uart_events_example_main.c

/* Uart Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "soc/uart_struct.h"

static const char *TAG = "uart_events";

/**
 * This example shows how to use the UART driver to handle special UART events.
 *
 * It also reads data from UART0 directly, and echoes it to console.
 *
 * - port: UART0
 * - rx buffer: on
 * - tx buffer: on
 * - flow control: off
 * - event queue: on
 * - pin assignment: txd(default), rxd(default)
 */

#define EX_UART_NUM UART_NUM_0

#define BUF_SIZE (1024)
static QueueHandle_t uart0_queue;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
            ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.
                in this example, we don't process data in event, but read data outside.*/
                case UART_DATA:
                    uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                    ESP_LOGI(TAG, "data, len: %d; buffered len: %d", event.size, buffered_size);
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow\n");
                    //If fifo overflow happened, you should consider adding flow control for your application.
                    //We can read data out out the buffer, or directly flush the rx buffer.
                    uart_flush(EX_UART_NUM);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full\n");
                    //If buffer full happened, you should consider encreasing your buffer size
                    //We can read data out out the buffer, or directly flush the rx buffer.
                    uart_flush(EX_UART_NUM);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break\n");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error\n");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error\n");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    ESP_LOGI(TAG, "uart pattern detected\n");
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d\n", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

/* Configure the UART events example */
void app_main()
{
    uart_config_t uart_config = {
       .baud_rate = 115200,
       .data_bits = UART_DATA_8_BITS,
       .parity = UART_PARITY_DISABLE,
       .stop_bits = UART_STOP_BITS_1,
       .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
       .rx_flow_ctrl_thresh = 122,
    };
    //Set UART parameters
    uart_param_config(EX_UART_NUM, &uart_config);
    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0);

    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_intr(EX_UART_NUM, '+', 3, 10000, 10, 10);
    //Create a task to handler UART event from ISR
    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);
    //process data
    uint8_t* data = (uint8_t*) malloc(BUF_SIZE);
    do {
        int len = uart_read_bytes(EX_UART_NUM, data, BUF_SIZE, 100 / portTICK_RATE_MS);
        if(len > 0) {
            ESP_LOGI(TAG, "uart read : %d", len);
            uart_write_bytes(EX_UART_NUM, (const char*)data, len);
        }
    } while(1);
}


```

前回のコード違う点は、以下の設定
> //Set uart pattern detect function.
    uart_enable_pattern_det_intr(EX_UART_NUM, '+', 3, 10000, 10, 10);
    


#Step3 動作確認

Msysのコンソールにキーボードで文字を打ち込むと、WROOM32から、以下のメッセージが送られてきます。

- rxイベントの検知　　
    - uart_events: uart[0] event:
- 受信したdataパケット数の通知　
    - uart_events: data, len: 1; buffered len: 1
- 読み込みバイト数の通知　
    - uart_events: uart read : 1
- 読み込んだデータのコールバック　(例はaを入力した場合)
    - a　

![UART0_MsysWindow.png](https://qiita-image-store.s3.amazonaws.com/0/165672/3c0171ee-ce63-f8fa-8ac0-0389a2d0383f.png)

今回はコンソールからの文字入力なので、データ受信メッセージしか確認できませんでしたが、バッファオーバーフローなどのエラーもキャッチできると思われます。
デバッグなどにも役にたちそうなサンプルですね。

#Step4 別デバイスを使用する場合

ここからは参考情報です。
UART0はプログラム書き込みに使用するポートなので、外部基盤を接続してしまうとプログラム書き込み時に問題があります。
外部基盤を接続できるように、別のUARTポートで確認します。

[前回](http://qiita.com/T-YOSH/items/ebda7142f9518a2c1ed0)同様、Switch Scienceさんの[FT231XS USB-シリアル変換ボード](https://www.switch-science.com/catalog/2499/)を使って確認することにします。
フロー制御なしなので、TX RXのみ接続します。

FT231XS USB-シリアル変換ボードの接続

>WROOM32  ---  FT231XS USB-シリアル変換ボード
 TXD D4  -> 　RX
 RXD D5  ->　 TX

ソースコードを変更します。
変更点は以下です。

- UART_NUM_0 →　UART_NUM_2 に変更
- uart_set_pin関数で、TXDをPIN 4に、RXDをPIN5に指定

```uart_echo/main/uart_events_example_main.c

/* Uart Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "soc/uart_struct.h"

static const char *TAG = "uart_events";

/**
 * This example shows how to use the UART driver to handle special UART events.
 *
 * It also reads data from UART0 directly, and echoes it to console.
 *
 * - port: UART0
 * - rx buffer: on
 * - tx buffer: on
 * - flow control: off
 * - event queue: on
 * - pin assignment: txd(default), rxd(default)
 */

//#define EX_UART_NUM UART_NUM_0
#define EX_UART_NUM UART_NUM_2

#define BUF_SIZE (1024)

#define TEST_TXD  (4)
#define TEST_RXD  (5)

static QueueHandle_t uart0_queue;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
            ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.
                in this example, we don't process data in event, but read data outside.*/
                case UART_DATA:
                    uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                    ESP_LOGI(TAG, "data, len: %d; buffered len: %d", event.size, buffered_size);
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow\n");
                    //If fifo overflow happened, you should consider adding flow control for your application.
                    //We can read data out out the buffer, or directly flush the rx buffer.
                    uart_flush(EX_UART_NUM);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full\n");
                    //If buffer full happened, you should consider encreasing your buffer size
                    //We can read data out out the buffer, or directly flush the rx buffer.
                    uart_flush(EX_UART_NUM);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break\n");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error\n");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error\n");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    ESP_LOGI(TAG, "uart pattern detected\n");
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d\n", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

/* Configure the UART events example */
void app_main()
{
    uart_config_t uart_config = {
       .baud_rate = 115200,
       .data_bits = UART_DATA_8_BITS,
       .parity = UART_PARITY_DISABLE,
       .stop_bits = UART_STOP_BITS_1,
       .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
       .rx_flow_ctrl_thresh = 122,
    };
    //Set UART parameters
    uart_param_config(EX_UART_NUM, &uart_config);
    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0);

    //Set UART pins (using UART0 default pins ie no changes.)
    //uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_set_pin(EX_UART_NUM, TEST_TXD, TEST_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_intr(EX_UART_NUM, '+', 3, 10000, 10, 10);
    //Create a task to handler UART event from ISR
    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);
    //process data
    uint8_t* data = (uint8_t*) malloc(BUF_SIZE);
    do {
        int len = uart_read_bytes(EX_UART_NUM, data, BUF_SIZE, 100 / portTICK_RATE_MS);
        if(len > 0) {
            ESP_LOGI(TAG, "uart read : %d", len);
            uart_write_bytes(EX_UART_NUM, (const char*)data, len);
        }
    } while(1);
}

```

FT231XS USB-シリアル変換ボードにつないだTeraTermからコメントを打つとこのようになります。

![UART0_TeraTerm_外部基盤.png](https://qiita-image-store.s3.amazonaws.com/0/165672/62657f8c-e0f3-9492-4dd5-c4f888c1f2af.png)

UART0につながったポートにはWROOMからのログメッセージが表示され、シリアル変換ボードにつないだTeraTermのほうは入力した文字がコールバックされているのがわかります。