ESP32의 I2C slave측 샘플 코드(송신만)를 만들어 보았다

소개



ESP32를 I2C 통신의 슬레이브로 작동시키는 좋은 샘플 코드를 찾을 수 없었기 때문에 만들었습니다.

espressif github 코드 을 기반으로 간단한 코드로 변경한 것입니다.

※espressif의 github의 코드는 ESP-IDF(≠Arduino)이므로, 그 환경의 이야기가 됩니다(Arduino에서는 사용할 수 없는 샘플 코드입니다)

사용한 것



ESP-WROOM-32 피치 변환된 모듈《풀판》

샘플 코드 개요 사양


  • I2C 마스터 및 I2C 슬레이브에 대해 하나씩 작업을 실행합니다.
  • I2C 슬레이브 작업 (i2c_test_task_0) : 2 초 간격으로 I2C 전송을 수행합니다
  • I2C 마스터용 태스크(i2c_test_task_1):1초 간격으로 슬레이브용 태스크로부터 I2C 수신을 실시한다
    ※ I2C 송신하는 데이터의 선두에 0x55 (SYNC_BYTE)의 1 바이트를 붙이고 있습니다 (슬레이브가 데이터 갱신 한 것을 판정하기 위해)

  • ESP32의 결선



    아래와 같이 결선합니다.



    SDA
    SCL


    I2C Master
    GPIO18
    GPIO19

    I2C 슬레이브
    GPIO25
    GPIO26


    결선도 :


    코드



    변경 개요



    espressif 샘플 프로젝트 의 i2c_example_main.c 에 대해 다음과 같이 변경합니다.
  • 태스크 함수 i2c_test_task() : 삭제
  • i2c_master_task() 및 i2c_master_task() : 새로 만들기 (i2c_test_task 대신 작업 함수로 만들기)
  • app_main() : 위의 태스크 함수의 변경에 따라 변경

  • 변경 후 코드(상기의 「변경 개요」의 부분만 기재)


    #define DELAY_TIME_MASTER_MS 1000
    #define DELAY_TIME_SLAVE_MS 2000
    #define SYNC_BYTE 0x55
    
    static void i2c_master_task(void *arg)
    {
      int ret;
      uint32_t task_idx = (uint32_t)arg;
      uint8_t *data_rd = (uint8_t *)malloc(DATA_LENGTH);
      int cnt = 0;
      while (1) {
          ESP_LOGI(TAG, "TASK[%d](master) test cnt: %d", task_idx, cnt++);
          //---------------------------------------------------
          xSemaphoreTake(print_mux, portMAX_DELAY);
          ret = ESP_OK;
          while(ret == ESP_OK) {
            ret = i2c_master_read_slave(I2C_MASTER_NUM, data_rd, RW_TEST_LENGTH);
              if (ret == ESP_ERR_TIMEOUT) {
                  ESP_LOGE(TAG, "I2C Timeout");
              } else if (ret == ESP_OK) {
                  if (data_rd[0] == SYNC_BYTE) {
                    printf("*******************\n");
                    printf("TASK[%d]  MASTER READ FROM SLAVE\n", task_idx);
                    printf("*******************\n");
                    printf("====TASK[%d] Master read ====\n", task_idx);
                    disp_buf(data_rd, RW_TEST_LENGTH);
                  }
                  else {
                    printf("*******************\n");
                    printf("TASK[%d]  MASTER READ FROM SLAVE\n", task_idx);
                    printf("*******************\n");
                    printf("NO DATA\n\n");
                    ret = ESP_FAIL;
                  }
              } else {
                  ESP_LOGW(TAG, "TASK[%d] %s: Master read slave error, IO not connected...\n",
                           task_idx, esp_err_to_name(ret));
              }
          }
          xSemaphoreGive(print_mux);
          vTaskDelay((DELAY_TIME_MASTER_MS * (task_idx + 1)) / portTICK_RATE_MS);
        }
        vSemaphoreDelete(print_mux);
        vTaskDelete(NULL);
    }
    
    static void i2c_slave_task(void *arg)
    {
      int i = 0;
      uint32_t task_idx = (uint32_t)arg;
      uint8_t *data = (uint8_t *)malloc(DATA_LENGTH);
      int cnt = 0;
      while (1) {
          ESP_LOGI(TAG, "TASK[%d](slave) test cnt: %d", task_idx, cnt++);
    
          //---------------------------------------------------
          data[0] = SYNC_BYTE;
          for (i = 1; i < DATA_LENGTH; i++) {
              data[i] = i;
          }
          xSemaphoreTake(print_mux, portMAX_DELAY);
          size_t d_size = i2c_slave_write_buffer(I2C_SLAVE_NUM, data, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
          if (d_size == 0) {
              ESP_LOGW(TAG, "i2c slave tx buffer full");
          }
          else {
            printf("slave send size: %d\n", d_size);
          }
          printf("*******************\n");
          printf("TASK[%d]  SLAVE SEND TO MASTER\n", task_idx);
          printf("*******************\n");
          disp_buf(data, d_size);
          xSemaphoreGive(print_mux);
          vTaskDelay((DELAY_TIME_SLAVE_MS * (task_idx + 1)) / portTICK_RATE_MS);
      }
      vSemaphoreDelete(print_mux);
      vTaskDelete(NULL);
    
    }
    
    void app_main()
    {
        print_mux = xSemaphoreCreateMutex();
        ESP_ERROR_CHECK(i2c_slave_init());
        ESP_ERROR_CHECK(i2c_master_init());
        xTaskCreate(i2c_slave_task, "i2c_test_task_0", 1024 * 2, (void *)0, 10, NULL);
        xTaskCreate(i2c_master_task, "i2c_test_task_1", 1024 * 2, (void *)1, 10, NULL);
    }
    

    끝에



    위의 샘플 코드에서는 I2C 슬레이브는 전송만 했지만 i2c_slave_read_buffer() 같은 함수를 사용하여 I2C 슬레이브에서 수신할 수도 있습니다.

    또, I2C 슬레이브의 송신이라고 하는 것은 과거 기사 의 농척 측과 같습니다. 할 수 있을 것 같습니다(ΦωΦ) 후후후…

    보고 주셔서 감사합니다.
    tnejk чoμ_〆(・ω・。)



    I2C 슬레이브 송신을 인터럽트 방식으로 할 수 있으면 좋겠다.



    이번에 만든 샘플 코드는 기본 코드 과 같이 폴링 방식으로 I2C의 송신을 실시하고 있습니다만, 그 부분은 사용하기 어렵게 느낍니다.

    거기서, Arduino의 Wire.h의 인터럽트 핸들러 등록과 같이 사용할 수 없을까 생각해 조금 조사하면, 「함수 i2c_isr_register를 사용하면 좋겠다」라고 하는 기사를 곳곳에서 찾아냈습니다.

    그러나 i2c_driver_install이라는 초기 설정을 하는 함수 내에서 i2c_isr_handler_default라는 디폴트 핸들러가 이미 등록되어 있거나 하고 「미다리에 등록해도 괜찮지 않아」라고 조금 조사할 필요를 느끼면서도 그 수고를 현재 포기중 입니다・・・.

    업데이트 내역


  • 2019-04-01 : 신규 작성
  • 좋은 웹페이지 즐겨찾기