i2c: Implement I2C controller via GPIO and bitbanging #58
Loading…
Reference in New Issue
There is no content yet.
Delete Branch "harry/zynq-rs:i2c"
Deleting a branch is permanent. Although the deleted branch may exist for a short time before cleaning up, in most cases it CANNOT be undone. Continue?
Overview
This PR implements an I2C bitbanging controller using GPIOs on Zynq, currently supporting only the ZC706 board. This would help circumvent inconspicuous issues pertaining to the official I2C controller module for Zynq.
Sidenote: Possible Pitfall with Register Macros
During my implementation process, I discovered a possible pitfall when defining registers with the
libregister
macros. Specifically, if you only plan to use some non-contiguous registers in a block of registers, instead of a regular C-representation (#[repr(C)]
)RegisterBlock
that are often retrieved via anew()
function as a mutable borrow from a static (&'static mut
), you should define a simple class whose fields are individual&'static mut
s pointing to each of the non-contiguous registers, and then simply let other parts of the code to retrieve this class via anew()
. For example, you should do:Then finally, in your code, you can access this block of registers using:
@ -0,0 +20,4 @@
impl I2C {
#[cfg(feature = "target_zc706")]
pub fn i2c() -> Self {
Shouldn't this function be called
new
?I named it this way by referring to the UART implementation (the constructor function on lines 16-60). But I do realise
new()
would be more suitable. I wonder: why is the constructor named this way on UART?I don't think there's a good reason for this and I think it should be named
new
in the UART as well.I see. For future reference, the
Eth
class in theeth
module also has its constructor named something other thannew()
(line 151). So in the experimentmain.rs
code, the Ethernet driver is instantiated withzynq::eth::Eth::default(hardware_addr);
.@ -0,0 +11,4 @@
const INVALID_BUS: &'static str = "Invalid I2C bus";
#[cfg(feature = "target_zc706")]
const GPIO_OUTPUT_MASK: u16 = 0xFFFF - 0x000C;
This does not need to be a global constant. I suggest simply passing the value as a parameter to
ctor_common()
innew
(akai2c()
)Fixed in harry/zynq-rs:
219df29f4e