I2C and UART parallel

VadimKHL
Posts: 7
Joined: Thu May 21, 2020 1:19 am

I2C and UART parallel

Postby VadimKHL » Thu May 21, 2020 1:28 am

Hello everyone!
Is it possible to use reading on I2С bus with core 1 and at that time transmitting other data to uart, by the processor 0 core?

ESP_Sprite
Posts: 3911
Joined: Thu Nov 26, 2015 4:08 am

Re: I2C and UART parallel

Postby ESP_Sprite » Thu May 21, 2020 8:07 am

Yes. You should even be able to do both on the same core.

VadimKHL
Posts: 7
Joined: Thu May 21, 2020 1:19 am

Re: I2C and UART parallel

Postby VadimKHL » Wed Jun 10, 2020 1:50 pm

And how to do it right? If UART transmission occurs, incomprehensible interruptions occur on the i2c bus:
Image

ESP_Sprite
Posts: 3911
Joined: Thu Nov 26, 2015 4:08 am

Re: I2C and UART parallel

Postby ESP_Sprite » Thu Jun 11, 2020 7:44 am

No clue what's happening there. Can you post your code? No analog interference between the IO pins?

VadimKHL
Posts: 7
Joined: Thu May 21, 2020 1:19 am

Re: I2C and UART parallel

Postby VadimKHL » Thu Jun 11, 2020 3:23 pm

There is no interference. Here is the code:
  1. #include <Wire.h>
  2.  
  3. #include "MLX90640_API.h"
  4. #include "MLX90640_I2C_Driver.h"
  5.  
  6. TaskHandle_t Task1; // Присваиваем индификаторы задач.
  7. TaskHandle_t Task2;
  8.  
  9. const byte MLX90640_address = 0x33; //Slave адрес I2C MLX90640 по умолчанию.
  10.  
  11. #define TA_SHIFT 8 //Default shift for MLX90640 in open air
  12. //#define LED_UART 23 // Нога индикации передачи буфера по UART (D23-MODULE, 36-CHIP).
  13. //const byte LED_UART = 23;
  14. //#define LED_CALC 19 // Нога индикации передачи буфера по UART (D19-MODULE, 38-CHIP).
  15.  
  16. float mlx90640To[768]; // Массив для расчетов кадра.
  17. float mlx90640Se[768]; // Массив для выдачи кадра.
  18. byte newframe = 0; // Флаг нового кадра.
  19. paramsMLX90640 mlx90640;
  20.  
  21. void setup()
  22. {
  23. //  pinMode(LED_UART, OUTPUT);
  24. //  pinMode(LED_CALC, OUTPUT);
  25.  
  26.   Wire.begin();
  27.   Wire.setClock(400000); // Установить скорость шины I2C 400kHz.
  28.  
  29.   Serial.begin(921600); // Установить скорость шины UART 921600.
  30.   //Serial.begin(256000); // Установить скорость шины UART 256000.
  31.   //Serial.begin(115200); // Установить скорость шины UART 115200.
  32.  
  33.   if (isConnected() == false)
  34.   {
  35.     Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing.");
  36.     while (1);
  37.   }
  38.  
  39.   // Далее получаем данные EEPROM датчика.
  40.   int status;
  41.   uint16_t eeMLX90640[832];
  42.   status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);
  43.   if (status != 0) Serial.println("Failed to load system parameters");
  44.  
  45.   status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
  46.   if (status != 0) Serial.println("Parameter extraction failed");
  47.  
  48.   //Once params are extracted, we can release eeMLX90640 array
  49.  
  50.   // Установка частоты обновления датчика (указана в полных кадрах).
  51.   //MLX90640_SetRefreshRate(MLX90640_address, 0x00); //Set rate to 0.25Hz effective - OK
  52.   //MLX90640_SetRefreshRate(MLX90640_address, 0x01); //Set rate to 0.5Hz effective - OK
  53.   //MLX90640_SetRefreshRate(MLX90640_address, 0x02); //Set rate to 1Hz effective - OK
  54.   //MLX90640_SetRefreshRate(MLX90640_address, 0x03); //Set rate to 2Hz effective - OK
  55.   //MLX90640_SetRefreshRate(MLX90640_address, 0x04); //Set rate to 4Hz effective - OK
  56.   MLX90640_SetRefreshRate(MLX90640_address, 0x05); //Set rate to 8Hz effective - OK_D
  57.   //MLX90640_SetRefreshRate(MLX90640_address, 0x06); //Set rate to 16Hz effective - Works at 800kHz !!! -???
  58.   //MLX90640_SetRefreshRate(MLX90640_address, 0x07); //Set rate to 32Hz effective - fails !!! -???
  59.  
  60.   // После получения EPPROM данных с датчика, увеличиваем скорость шины I2C до 1Mhz.
  61.   Wire.setClock(1000000); // Скорость шины I2C 800kHz (из за внутреннего делителя частоты такта).
  62.  
  63.   delay(500);  // small delay
  64.   // Ref: http://esp32.info/docs/esp_idf/html/db/da4/task_8h.html#a25b035ac6b7809ff16c828be270e1431
  65.  
  66.   // Создаем задачу с кодом из функции Task1code(),
  67.   // с приоритетом 1 и выполняемую на ядре 0:
  68.   xTaskCreatePinnedToCore(
  69.                     Task1code,   /* Функция задачи */
  70.                     "Task1",     /* Название задачи */
  71.                     10000,       /* Размер стека задачи */
  72.                     NULL,        /* Параметр задачи */
  73.                     1,           /* Приоритет задачи */
  74.                     &Task1,      /* Идентификатор задачи,
  75.                                     чтобы ее можно было отслеживать */
  76.                     0);          /* Ядро для выполнения задачи (0) */                  
  77.   delay(500);
  78.  
  79.   // Создаем задачу с кодом из функции Task2code(),
  80.   // с приоритетом 1 и выполняемую на ядре 1:
  81.   xTaskCreatePinnedToCore(
  82.                     Task2code,   /* Функция задачи */
  83.                     "Task2",     /* Название задачи */
  84.                     10000,       /* Размер стека задачи */
  85.                     NULL,        /* Параметр задачи */
  86.                     1,           /* Приоритет задачи */
  87.                     &Task2,      /* Идентификатор задачи,
  88.                                     чтобы ее можно было отслеживать */
  89.                     1);          /* Ядро для выполнения задачи (1) */
  90.   delay(500);
  91. }
  92.  
  93. // =============================================== Ядро 1 =========================================================
  94.  
  95. void Task2code( void * pvParameters )
  96. {
  97.   for(;;) // Бесконечный цикл.
  98.   {
  99.     for (byte x = 0 ; x < 2 ; x++)
  100.     {
  101.       uint16_t mlx90640Frame[834];
  102.       int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);
  103. //      digitalWrite(LED_CALC, HIGH);
  104.       float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
  105.       float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);
  106.      
  107.       float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
  108.       float emissivity = 0.95;
  109.  
  110.       MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To);
  111. //      digitalWrite(LED_CALC, LOW);
  112. //Calculation time on a Teensy 3.5 is 71ms.
  113. //Calculation time on a ESP32 is 27,79ms - 27,83ms.
  114.     }
  115.     for (int a = 0 ; a < 768 ; a++)  // Скопировать массив кадра для дальнейшего вывода.
  116.     {
  117.       mlx90640Se[a] = mlx90640To[a];
  118.     }
  119.     newframe = 1; // Поднять флаг нового кадра.
  120.   }
  121. }
  122.  
  123. // =============================================== Ядро 1  (по умолчанию) =========================================
  124.  
  125. void loop()
  126. {
  127.   delay(100);
  128. }
  129.  
  130. // =============================================== Ядро 0 =========================================================
  131.  
  132. void Task1code( void * pvParameters )
  133. {
  134.   for(;;) // Бесконечный цикл.
  135.   {
  136.     if ( newframe == 1)
  137.     {
  138.       newframe = 0; // Сбросить флаг нового кадра.
  139.       Serial.write(158); // Передать температуру -250,00 (число -25000).
  140.       Serial.write(88);
  141.       Serial.write(158); // Передать температуру -250,00 (число -25000).
  142.       Serial.write(88);
  143.       // Вывод кадра через UART (1536 байт при скорости 921600 - 15,27 ms).
  144. //      digitalWrite(LED_UART, HIGH);
  145.       for (int z = 0 ; z < 768 ; z++)
  146.       {
  147.         short tempx = mlx90640Se[z] * 100; // Выделяем только два занака после запятой в целое число и передаем в порт.
  148.         byte raw[2];                       // Выделить два байта из short переменной и передать.
  149.         (short&)raw = tempx;
  150.         Serial.write(raw[1]);
  151.         Serial.write(raw[0]);
  152.       }
  153.       Serial.write(154); // Передать температуру -260,00 (число -26000).
  154.       Serial.write(112);
  155.       Serial.write(154); // Передать температуру -260,00 (число -26000).
  156.       Serial.write(112);  
  157. //      digitalWrite(LED_UART, LOW);
  158.     }
  159.     delay(1);
  160.   }
  161. }
  162.  
  163. // ========================================== пока не понятно =====================================================
  164.  
  165. // Возвращает TRUE, если датчик ответил на шине I2C.
  166. boolean isConnected()
  167. {
  168.   Wire.beginTransmission((uint8_t)MLX90640_address);
  169.   if (Wire.endTransmission() != 0) return (false); //Датчик не ответил ACK.
  170.   return (true);
  171. }

ESP_Sprite
Posts: 3911
Joined: Thu Nov 26, 2015 4:08 am

Re: I2C and UART parallel

Postby ESP_Sprite » Thu Jun 11, 2020 6:51 pm

Just guessing as I don't know the Arduino drivers that well, but can you try initializing the serial port and the Wire interface inside the tasks you spawn instead of in the main function? Thing is that the drivers likely register the interrupts on the CPU they're initialized on, which in your case is CPU0 for both drivers. That could lead to what you're seeing.

(Additionally, instead of using a variable (NewFrame) it's better to use something like a FreeRTOS semaphore or a queue for inter-task communication.)

VadimKHL
Posts: 7
Joined: Thu May 21, 2020 1:19 am

Re: I2C and UART parallel

Postby VadimKHL » Fri Jun 12, 2020 1:19 am

Just guessing as I don't know the Arduino drivers that well, but can you try initializing the serial port and the Wire interface inside the tasks you spawn instead of in the main function? Thing is that the drivers likely register the interrupts on the CPU they're initialized on, which in your case is CPU0 for both drivers. That could lead to what you're seeing.
A good idea. I will try. By default, the "void setup" and the "void loop" on the arduino ide are executed on 1 core.
(Additionally, instead of using a variable (NewFrame) it's better to use something like a FreeRTOS semaphore or a queue for inter-task communication.)
Can an example how to implement this?

Another question, the priority of tasks, the same on both cores, can this be a problem? What is she responsible for and how to ask her correctly?
Image

VadimKHL
Posts: 7
Joined: Thu May 21, 2020 1:19 am

Re: I2C and UART parallel

Postby VadimKHL » Sat Jun 20, 2020 12:22 pm

Good day!
The problem is resolved.
Arduino IDE always launches UART on core 1.
After castling tasks on the cores, everything worked as it should (I2C is no longer interrupted by UART transfer):
Image

Thank you all for your help!

Who is online

Users browsing this forum: No registered users and 12 guests