Explorar el Código

Merge branch 'bugfix/ticks_to_wait_for_uart_and_i2c_v3.3' into 'release/v3.3'

driver: Fix ticks_to_wait for uart and i2c (v3.3)

See merge request espressif/esp-idf!5247
Angus Gratton hace 6 años
padre
commit
c9f1cb2f4c
Se han modificado 3 ficheros con 134 adiciones y 5 borrados
  1. 20 5
      components/driver/i2c.c
  2. 64 0
      components/driver/test/test_i2c.c
  3. 50 0
      components/driver/test/test_uart.c

+ 20 - 5
components/driver/i2c.c

@@ -1380,13 +1380,18 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType
 
     portBASE_TYPE res;
     int cnt = 0;
-    portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+    portTickType ticks_start = xTaskGetTickCount();
 
     res = xSemaphoreTake(p_i2c->slv_tx_mux, ticks_to_wait);
     if (res == pdFALSE) {
         return 0;
     }
-    ticks_to_wait = ticks_end - xTaskGetTickCount();
+    TickType_t ticks_end = xTaskGetTickCount();
+    if (ticks_end - ticks_start > ticks_to_wait) {
+        ticks_to_wait = 0;
+    } else {
+        ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start);
+    }
     res = xRingbufferSend(p_i2c->tx_ring_buf, data, size, ticks_to_wait);
     if (res == pdFALSE) {
         cnt = 0;
@@ -1421,18 +1426,28 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
 
     i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
     portBASE_TYPE res;
-    portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+    portTickType ticks_start = xTaskGetTickCount();
     res = xSemaphoreTake(p_i2c->slv_rx_mux, ticks_to_wait);
     if (res == pdFALSE) {
         return 0;
     }
-    ticks_to_wait = ticks_end - xTaskGetTickCount();
+    TickType_t ticks_end = xTaskGetTickCount();
+    if (ticks_end - ticks_start > ticks_to_wait) {
+        ticks_to_wait = 0;
+    } else {
+        ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start);
+    }
     int cnt = i2c_slave_read(i2c_num, data, max_size, ticks_to_wait);
     if (cnt > 0) {
         I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
         I2C[i2c_num]->int_ena.rx_fifo_full = 1;
         I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
-        ticks_to_wait = ticks_end - xTaskGetTickCount();
+        ticks_end = xTaskGetTickCount();
+        if (ticks_end - ticks_start > ticks_to_wait) {
+            ticks_to_wait = 0;
+        } else {
+            ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start);
+        }
         if (cnt < max_size && ticks_to_wait > 0) {
             cnt += i2c_slave_read(i2c_num, data + cnt, max_size - cnt, ticks_to_wait);
         }

+ 64 - 0
components/driver/test/test_i2c.c

@@ -506,3 +506,67 @@ static void i2c_slave_repeat_read()
 }
 
 TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read);
+
+static volatile bool exit_flag;
+static bool test_read_func;
+
+static void test_task(void *pvParameters)
+{
+    xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
+
+    uint8_t *data = (uint8_t *) malloc(DATA_LENGTH);
+    i2c_config_t conf_slave = i2c_slave_init();
+    TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
+    TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
+                                   I2C_SLAVE_RX_BUF_LEN,
+                                   I2C_SLAVE_TX_BUF_LEN, 0));
+    while (exit_flag == false) {
+        if (test_read_func) {
+            i2c_slave_read_buffer(I2C_SLAVE_NUM, data, DATA_LENGTH, 0);
+        } else {
+            i2c_slave_write_buffer(I2C_SLAVE_NUM, data, DATA_LENGTH, 0);
+        }
+    }
+
+    free(data);
+    xSemaphoreGive(*sema);
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("test i2c_slave_read_buffer is not blocked when ticks_to_wait=0", "[i2c]")
+{
+    xSemaphoreHandle exit_sema = xSemaphoreCreateBinary();
+    exit_flag = false;
+
+    test_read_func = true;
+    xTaskCreate(test_task, "tsk1", 2048, &exit_sema, 5, NULL);
+
+    printf("Waiting for 5 sec\n");
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
+    exit_flag = true;
+    if (xSemaphoreTake(exit_sema, 1000 / portTICK_PERIOD_MS) == pdTRUE) {
+        vSemaphoreDelete(exit_sema);
+    } else {
+        TEST_FAIL_MESSAGE("i2c_slave_read_buffer is blocked");
+    }
+    TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM));
+}
+
+TEST_CASE("test i2c_slave_write_buffer is not blocked when ticks_to_wait=0", "[i2c]")
+{
+    xSemaphoreHandle exit_sema = xSemaphoreCreateBinary();
+    exit_flag = false;
+
+    test_read_func = false;
+    xTaskCreate(test_task, "tsk1", 2048, &exit_sema, 5, NULL);
+
+    printf("Waiting for 5 sec\n");
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
+    exit_flag = true;
+    if (xSemaphoreTake(exit_sema, 1000 / portTICK_PERIOD_MS) == pdTRUE) {
+        vSemaphoreDelete(exit_sema);
+    } else {
+        TEST_FAIL_MESSAGE("i2c_slave_write_buffer is blocked");
+    }
+    TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM));
+}

+ 50 - 0
components/driver/test/test_uart.c

@@ -118,6 +118,56 @@ static void uart_config(uint32_t baud_rate, bool use_ref_tick)
     uart_driver_install(UART_NUM1, BUF_SIZE * 2, BUF_SIZE * 2, 20, NULL, 0);
 }
 
+static volatile bool exit_flag;
+
+static void test_task(void *pvParameters)
+{
+    xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
+    char* data = (char *) malloc(256);
+
+    while (exit_flag == false) {
+        uart_tx_chars(UART_NUM1, data, 256);
+        // The uart_wait_tx_done() function does not block anything if ticks_to_wait = 0.
+        uart_wait_tx_done(UART_NUM1, 0);
+    }
+
+    free(data);
+    xSemaphoreGive(*sema);
+    vTaskDelete(NULL);
+}
+
+static void test_task2(void *pvParameters)
+{
+    while (exit_flag == false) {
+        // This task obstruct a setting tx_done_sem semaphore in the UART interrupt.
+        // It leads to waiting the ticks_to_wait time in uart_wait_tx_done() function.
+        uart_disable_intr_mask(UART_NUM1, UART_TX_DONE_INT_ENA_M);
+    }
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("test uart_wait_tx_done is not blocked when ticks_to_wait=0", "[uart]")
+{
+    uart_config(UART_BAUD_11520, false);
+
+    xSemaphoreHandle exit_sema = xSemaphoreCreateBinary();
+    exit_flag = false;
+
+    xTaskCreate(test_task,  "tsk1", 2048, &exit_sema, 5, NULL);
+    xTaskCreate(test_task2, "tsk2", 2048, NULL,       5, NULL);
+
+    printf("Waiting for 5 sec\n");
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
+    exit_flag = true;
+
+    if (xSemaphoreTake(exit_sema, 1000 / portTICK_PERIOD_MS) == pdTRUE) {
+        vSemaphoreDelete(exit_sema);
+    } else {
+        TEST_FAIL_MESSAGE("uart_wait_tx_done is blocked");
+    }
+    TEST_ESP_OK(uart_driver_delete(UART_NUM1));
+}
+
 TEST_CASE("test uart get baud-rate","[uart]")
 {
     uint32_t baud_rate1 = 0;