I am trying to get the I2C adapter working, but for some reason it is blocking forever when I call ad_i2c_write_read().
For context, I am using the adapter in following way:
- 有一个任务具有处理I2C事务的唯一功能。
- The task has a FreeRTOS queue of pending transactions.
- The task fetches the next transaction from the queue (blocks if empty), and then performs
the transaction synchronously.
- When the transaction is complete, the task sends a signal to the transaction's originating task.
- 没有其他任务使用I2C外设。
This design is pretty simple, and means that all the other threads can use I2C without ever
blocking. This matches the way I've implemented I2C drivers on other processors, and it works
很好。
The task looks like this (it's part of a C++ class):
void I2CMasterDriver::task_func_impl()
{
// Initialise the I2C device.
ad_i2c_init();
//可能有休息或暂停条件。
而(真实)
{
//如果队列中没有任何内容,则将阻止。
m_queue.receive(m_trans);
// The caller may pass in a pointer to a data buffer (for larger blocks).
// If null, we point this to our own buffer. Note: do this at this point
// because the structure is copied by value, and any other pointer is likely
// to be invalid.
if (m_trans.data == nullptr)
{
m_trans.data = &m_trans.buffer[0];
}
// Open the I2C slave device we want to talk to. This is the oddest achitecture
// I've yet seen for managing slaves.
i2c_device device = ad_i2c_open(NFC_CHIP);
// This is a blocking call.
int ret_code = ad_i2c_write_read(
device,
(m_trans.tx_length> 0)?&m_trans.data [0]:nullptr,
m_trans.tx_length,
(m_trans.rx_length > 0) ? &m_trans.data[m_trans.tx_length] : nullptr,
m_trans.rx_length,
HW_I2C_F_ADD_STOP);
// We are going to return by value - via the scheduler - so restore the data pointer to
// indicate that we used own buffer or external buffer.
if (m_trans.data == &m_trans.buffer[0])
{
m_trans.data = nullptr;
}
// Let the clients know that we're all done.
m_on_complete.emit(m_trans);
// Close the device in preparation for the next transaction.
ad_i2c_close(device);
}
}
The following lines are included in my configuration:
#define dg_configUSE_HW_I2C ( 1 )
#define dg_configI2C_ADAPTER ( 1 )
The following lines are included in periph_init:
hw_gpio_configure_pin(HW_GPIO_PORT_0, HW_GPIO_PIN_0, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_I2C_SCL, true);
hw_gpio_configure_pin(HW_GPIO_PORT_0, HW_GPIO_PIN_1, HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_I2C_SDA, true);
The following lines are included in platform_devices.h:
I2C_BUS(I2C1)
I2C_SLAVE_DEVICE_DMA(I2C1, nfc_chip, 0x28, HW_I2C_ADDRESSING_7B, HW_I2C_SPEED_STANDARD, 0)
I2C_BUS_END
此问题是对AD_I2C_WRITE_READ()块的调用,而不是返回。如果我发表评论
排队,以便排队的事务刚刚被抛弃,任务完全按预期工作。
What other settings, macros or options might I have missed? Since only one task used the I2C, perhaps I should used the low-level driver instead...
事情的方式,我想我早期er just write my own bare metal driver for this. Are there any example of this available?
谢谢。
It seems that I need to acquire the bus before starting the transaction - this is what initialises the peripheral itself and enables the interrupts. So it doesn't block now. However....
Nothing is coming out on the wire. There is no device attached, but I should at least see the address.
谢谢。
Ah! Answered my own question. It helps a lot if you make the pins output open drain and stick a device on the bus to pull up the lines.
谢谢。
Hi UnicycleBloke,
I would strongly recommend you to have a look at theI2C适配器概念(HTML)从DA14680的支持页面。本教程解释了I2C适配器以及如何将DA1468x配置为I2C主设备。适配器未实现为单独的任务,并且应视为应用程序和LLD之间的附加层。建议使用适配器来访问硬件块。
Thanks, PM_Dialog
谢谢,但我已经完成了所有这些。我理解I2C适配器概念。不幸的是,我认为设计是理想的。这就是为什么我创建了一个线程到序列式调用的线程,而不停止应用程序中的任何其他线程。它现在运作得很好,并且更适合我的活动驱动应用程序框架。
I do have a follow up question: if I were to use two I2C peripherals, it seems like the adapter would prevent concurrent transactions on them. Is that true?
谢谢。
Hi UnicycleBloke,
Yes, that’s true! The adapters will prevent concurrent transactions on them.
Thanks, PM_Dialog
Hmm. Thanks for letting me know. That seems like quite a poor design to me.