I2C Interrupt
I2C Interrupt
Hi,
I want to use I2C interrupt on esp-idf. What can I do? I couldn’t find any examples. (bare-metal)
I want to use I2C interrupt on esp-idf. What can I do? I couldn’t find any examples. (bare-metal)
Last edited by zeynep01 on Mon Dec 11, 2023 7:26 am, edited 3 times in total.
Re: I2C Interrupt
I tried with this code but I don't work.
Code: Select all
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/i2c.h>
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include <soc/i2c_reg.h>
#include <esp32/rom/gpio.h>
#include <soc/gpio_sig_map.h>
#include <hal/i2c_ll.h>
#include <hal/i2c_hal.h>
#include <hal/gpio_hal.h>
#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_MASTER_SCL_IO 2
#define I2C_MASTER_SDA_IO 8
#define I2C_MASTER_FREQ_HZ 100000
#define DEVICE_ADDRESS 0x03
static const char *TAG = "I2C_TASK";
uint8_t receivedData;
static void i2c_master_init()
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
.clk_flags = 0,
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
}
static void i2c_master_read_data()
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (DEVICE_ADDRESS << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &receivedData, I2C_MASTER_ACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(50));
i2c_cmd_link_delete(cmd);
if (ret == ESP_OK)
{
ESP_LOGI(TAG, "I2C data read successfully");
ESP_LOGI(TAG, "value: %d\n", receivedData);
}
else
{
ESP_LOGE(TAG, "I2C data read failed.");
}
vTaskDelay(pdMS_TO_TICKS(500));
}
static void IRAM_ATTR i2c_master_isr_handler(void *arg)
{
i2c_master_read_data();
}
void app_main()
{
i2c_master_init();
esp_intr_alloc(I2C_MASTER_NUM, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, i2c_master_isr_handler, NULL, NULL);
}
Last edited by zeynep01 on Mon Dec 11, 2023 7:26 am, edited 5 times in total.
-
- Posts: 1736
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: I2C Interrupt
No, you don't want that. And you can't while still using the IDF's I2C driver.
You can create a dedicated task which handles the I2C communication and processes read data as desired, including calling a callback or posting a message to a queue for another task to consume.
Last edited by MicroController on Fri Dec 08, 2023 12:48 pm, edited 1 time in total.
Re: I2C Interrupt
why ?MicroController wrote: ↑Fri Dec 08, 2023 12:38 pmNo, you don't want that. And you can't while still using the IDF's I2C driver.
-
- Posts: 1736
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: I2C Interrupt
1) The I2C driver controls the I2C peripheral, and for that it uses its own I2C interrupt handler.
2) This interrupt handler does all the low-level interaction with the I2C peripheral, which you don't want to implement yourself.
3) The driver's API is designed to be blocking. This precludes any use from within an ISR, but allows for convenient use inside of a task.
4) You probably don't actually want to write an ISR but rather have some kind of 'I'm done' callback function approach. If you really want to use that pattern, you can 'emulate' it from a custom task.
(For reference, this is the I2C driver's ISR. You don't want to re-implement that )
2) This interrupt handler does all the low-level interaction with the I2C peripheral, which you don't want to implement yourself.
3) The driver's API is designed to be blocking. This precludes any use from within an ISR, but allows for convenient use inside of a task.
4) You probably don't actually want to write an ISR but rather have some kind of 'I'm done' callback function approach. If you really want to use that pattern, you can 'emulate' it from a custom task.
(For reference, this is the I2C driver's ISR. You don't want to re-implement that )
-
- Posts: 1736
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: I2C Interrupt
With I2C, the master is in charge of all communication. A slave cannot send a value to the master by itself, it can only respond to a read request from the master. So either the master has to loop polling the slave for the value of interest, or the slave needs some other way to notify the master that it has new data ready for the master to read. Many I2C slave chips/devices have a dedicated 'interrupt' output pin which can be used by the master to know when to issue a new read to the slave.When I press my button on my slave device I send value to my master device.
Re: I2C Interrupt
zeynep01 wrote: ↑Fri Dec 08, 2023 12:42 pmwhy ?MicroController wrote: ↑Fri Dec 08, 2023 12:38 pmNo, you don't want that. And you can't while still using the IDF's I2C driver.
Re: I2C Interrupt
so @MicroController is this code a faulty algorithm?zeynep01 wrote: ↑Fri Dec 08, 2023 11:35 amI am using two microcontroller. I communicate via I2C. When I press my button on my slave device I send value to my master device. I can do it without interrupt, isr.
But I want to use Interrupt. I tried with this code but I don't work. When I send a value I can't read .
Code: Select all
#include <stdio.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <driver/i2c.h> #include "esp_log.h" #include "esp_intr_alloc.h" #include <soc/i2c_reg.h> #include <esp32/rom/gpio.h> #include <soc/gpio_sig_map.h> #include <hal/i2c_ll.h> #include <hal/i2c_hal.h> #include <hal/gpio_hal.h> #define I2C_MASTER_NUM I2C_NUM_0 #define I2C_MASTER_SCL_IO 2 #define I2C_MASTER_SDA_IO 8 #define I2C_MASTER_FREQ_HZ 100000 #define DEVICE_ADDRESS 0x03 static const char *TAG = "I2C_TASK"; uint8_t receivedData; static void i2c_master_init() { i2c_config_t conf = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_MASTER_SDA_IO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_io_num = I2C_MASTER_SCL_IO, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = I2C_MASTER_FREQ_HZ, .clk_flags = 0, }; i2c_param_config(I2C_MASTER_NUM, &conf); i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0); } static void i2c_master_read_data() { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (DEVICE_ADDRESS << 1) | I2C_MASTER_READ, true); i2c_master_read_byte(cmd, &receivedData, I2C_MASTER_ACK); i2c_master_stop(cmd); esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(50)); i2c_cmd_link_delete(cmd); if (ret == ESP_OK) { ESP_LOGI(TAG, "I2C data read successfully"); ESP_LOGI(TAG, "value: %d\n", receivedData); } else { ESP_LOGE(TAG, "I2C data read failed."); } vTaskDelay(pdMS_TO_TICKS(500)); } static void IRAM_ATTR i2c_master_isr_handler(void *arg) { i2c_master_read_data(); } void app_main() { i2c_master_init(); esp_intr_alloc(I2C_MASTER_NUM, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, i2c_master_isr_handler, NULL, NULL); }
-
- Posts: 1736
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: I2C Interrupt
As I said, I see two main issues with this code:
1) You can't allocate the I2C interrupt to your own handler and use the IDF's I2C driver, and
2) you cannot call i2c_master_cmd_begin(...) from an ISR.
And possibly
3) I2C will not do anything (interrupt...) while the master isn't actively performing a transaction.
1) You can't allocate the I2C interrupt to your own handler and use the IDF's I2C driver, and
2) you cannot call i2c_master_cmd_begin(...) from an ISR.
And possibly
3) I2C will not do anything (interrupt...) while the master isn't actively performing a transaction.
Re: I2C Interrupt
I don't use FreeRTOS I use bare-metal. I want to use I2C Interrupt. What can I do?MicroController wrote: ↑Fri Dec 08, 2023 2:00 pmAs I said, I see two main issues with this code:
1) You can't allocate the I2C interrupt to your own handler and use the IDF's I2C driver, and
2) you cannot call i2c_master_cmd_begin(...) from an ISR.
And possibly
3) I2C will not do anything (interrupt...) while the master isn't actively performing a transaction.
Who is online
Users browsing this forum: iParcelBox and 78 guests