Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
H
Heizung
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
c3pb
Heizung
Commits
f81cdbdc
Commit
f81cdbdc
authored
1 year ago
by
Benjamin Koch
Browse files
Options
Downloads
Patches
Plain Diff
make a copy of embassy-rs' i2c implementation
parent
ba0b98e5
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
firmware/rust1/src/lib/i2c.rs
+876
-0
876 additions, 0 deletions
firmware/rust1/src/lib/i2c.rs
with
876 additions
and
0 deletions
firmware/rust1/src/lib/i2c.rs
0 → 100644
+
876
−
0
View file @
f81cdbdc
// This is a modified copy of embassy/embassy-rp/src/i2c.rs.
// We have changed:
// - allow empty buffer for write (for I2C scan)
// - don't block access to reserved addresses (also for I2C scan)
use
core
::
future
;
use
core
::
marker
::
PhantomData
;
use
core
::
task
::
Poll
;
use
embassy_cortex_m
::
interrupt
::
InterruptExt
;
use
embassy_hal_common
::{
into_ref
,
PeripheralRef
};
use
embassy_sync
::
waitqueue
::
AtomicWaker
;
use
pac
::
i2c
;
use
crate
::
gpio
::
sealed
::
Pin
;
use
crate
::
gpio
::
AnyPin
;
use
crate
::{
pac
,
peripherals
,
Peripheral
};
/// I2C error abort reason
#[derive(Debug)]
#[cfg_attr(feature
=
"defmt"
,
derive(defmt::Format))]
pub
enum
AbortReason
{
/// A bus operation was not acknowledged, e.g. due to the addressed device
/// not being available on the bus or the device not being ready to process
/// requests at the moment
NoAcknowledge
,
/// The arbitration was lost, e.g. electrical problems with the clock signal
ArbitrationLoss
,
Other
(
u32
),
}
/// I2C error
#[derive(Debug)]
#[cfg_attr(feature
=
"defmt"
,
derive(defmt::Format))]
pub
enum
Error
{
/// I2C abort with error
Abort
(
AbortReason
),
/// User passed in a read buffer that was 0 length
InvalidReadBufferLength
,
/// User passed in a write buffer that was 0 length
InvalidWriteBufferLength
,
/// Target i2c address is out of range
AddressOutOfRange
(
u16
),
/// Target i2c address is reserved
AddressReserved
(
u16
),
}
#[non_exhaustive]
#[derive(Copy,
Clone)]
pub
struct
Config
{
pub
frequency
:
u32
,
}
impl
Default
for
Config
{
fn
default
()
->
Self
{
Self
{
frequency
:
100_000
}
}
}
const
FIFO_SIZE
:
u8
=
16
;
pub
struct
I2c
<
'd
,
T
:
Instance
,
M
:
Mode
>
{
phantom
:
PhantomData
<
(
&
'd
mut
T
,
M
)
>
,
}
impl
<
'd
,
T
:
Instance
>
I2c
<
'd
,
T
,
Blocking
>
{
pub
fn
new_blocking
(
peri
:
impl
Peripheral
<
P
=
T
>
+
'd
,
scl
:
impl
Peripheral
<
P
=
impl
SclPin
<
T
>>
+
'd
,
sda
:
impl
Peripheral
<
P
=
impl
SdaPin
<
T
>>
+
'd
,
config
:
Config
,
)
->
Self
{
into_ref!
(
scl
,
sda
);
Self
::
new_inner
(
peri
,
scl
.map_into
(),
sda
.map_into
(),
config
)
}
}
impl
<
'd
,
T
:
Instance
>
I2c
<
'd
,
T
,
Async
>
{
pub
fn
new_async
(
peri
:
impl
Peripheral
<
P
=
T
>
+
'd
,
scl
:
impl
Peripheral
<
P
=
impl
SclPin
<
T
>>
+
'd
,
sda
:
impl
Peripheral
<
P
=
impl
SdaPin
<
T
>>
+
'd
,
irq
:
impl
Peripheral
<
P
=
T
::
Interrupt
>
+
'd
,
config
:
Config
,
)
->
Self
{
into_ref!
(
scl
,
sda
,
irq
);
let
i2c
=
Self
::
new_inner
(
peri
,
scl
.map_into
(),
sda
.map_into
(),
config
);
irq
.set_handler
(
Self
::
on_interrupt
);
unsafe
{
let
i2c
=
T
::
regs
();
// mask everything initially
i2c
.ic_intr_mask
()
.write_value
(
i2c
::
regs
::
IcIntrMask
(
0
));
}
irq
.unpend
();
debug_assert!
(
!
irq
.is_pending
());
irq
.enable
();
i2c
}
/// Calls `f` to check if we are ready or not.
/// If not, `g` is called once the waker is set (to eg enable the required interrupts).
async
fn
wait_on
<
F
,
U
,
G
>
(
&
mut
self
,
mut
f
:
F
,
mut
g
:
G
)
->
U
where
F
:
FnMut
(
&
mut
Self
)
->
Poll
<
U
>
,
G
:
FnMut
(
&
mut
Self
),
{
future
::
poll_fn
(|
cx
|
{
let
r
=
f
(
self
);
if
r
.is_pending
()
{
T
::
waker
()
.register
(
cx
.waker
());
g
(
self
);
}
r
})
.await
}
// Mask interrupts and wake any task waiting for this interrupt
unsafe
fn
on_interrupt
(
_
:
*
mut
())
{
let
i2c
=
T
::
regs
();
i2c
.ic_intr_mask
()
.write_value
(
pac
::
i2c
::
regs
::
IcIntrMask
::
default
());
T
::
waker
()
.wake
();
}
async
fn
read_async_internal
(
&
mut
self
,
buffer
:
&
mut
[
u8
],
restart
:
bool
,
send_stop
:
bool
)
->
Result
<
(),
Error
>
{
if
buffer
.is_empty
()
{
return
Err
(
Error
::
InvalidReadBufferLength
);
}
let
p
=
T
::
regs
();
let
mut
remaining
=
buffer
.len
();
let
mut
remaining_queue
=
buffer
.len
();
let
mut
abort_reason
=
Ok
(());
while
remaining
>
0
{
// Waggle SCK - basically the same as write
let
tx_fifo_space
=
Self
::
tx_fifo_capacity
();
let
mut
batch
=
0
;
debug_assert!
(
remaining_queue
>
0
);
for
_
in
0
..
remaining_queue
.min
(
tx_fifo_space
as
usize
)
{
remaining_queue
-=
1
;
let
last
=
remaining_queue
==
0
;
batch
+=
1
;
unsafe
{
p
.ic_data_cmd
()
.write
(|
w
|
{
w
.set_restart
(
restart
&&
remaining_queue
==
buffer
.len
()
-
1
);
w
.set_stop
(
last
&&
send_stop
);
w
.set_cmd
(
true
);
});
}
}
// We've either run out of txfifo or just plain finished setting up
// the clocks for the message - either way we need to wait for rx
// data.
debug_assert!
(
batch
>
0
);
let
res
=
self
.wait_on
(
|
me
|
{
let
rxfifo
=
Self
::
rx_fifo_len
();
if
let
Err
(
abort_reason
)
=
me
.read_and_clear_abort_reason
()
{
Poll
::
Ready
(
Err
(
abort_reason
))
}
else
if
rxfifo
>=
batch
{
Poll
::
Ready
(
Ok
(
rxfifo
))
}
else
{
Poll
::
Pending
}
},
|
_me
|
unsafe
{
// Set the read threshold to the number of bytes we're
// expecting so we don't get spurious interrupts.
p
.ic_rx_tl
()
.write
(|
w
|
w
.set_rx_tl
(
batch
-
1
));
p
.ic_intr_mask
()
.modify
(|
w
|
{
w
.set_m_rx_full
(
true
);
w
.set_m_tx_abrt
(
true
);
});
},
)
.await
;
match
res
{
Err
(
reason
)
=>
{
abort_reason
=
Err
(
reason
);
break
;
}
Ok
(
rxfifo
)
=>
{
// Fetch things from rx fifo. We're assuming we're the only
// rxfifo reader, so nothing else can take things from it.
let
rxbytes
=
(
rxfifo
as
usize
)
.min
(
remaining
);
let
received
=
buffer
.len
()
-
remaining
;
for
b
in
&
mut
buffer
[
received
..
received
+
rxbytes
]
{
*
b
=
unsafe
{
p
.ic_data_cmd
()
.read
()
.dat
()
};
}
remaining
-=
rxbytes
;
}
};
}
self
.wait_stop_det
(
abort_reason
,
send_stop
)
.await
}
async
fn
write_async_internal
(
&
mut
self
,
bytes
:
impl
IntoIterator
<
Item
=
u8
>
,
send_stop
:
bool
,
)
->
Result
<
(),
Error
>
{
let
p
=
T
::
regs
();
let
mut
bytes
=
bytes
.into_iter
()
.peekable
();
let
res
=
'xmit
:
loop
{
let
tx_fifo_space
=
Self
::
tx_fifo_capacity
();
for
_
in
0
..
tx_fifo_space
{
if
let
Some
(
byte
)
=
bytes
.next
()
{
let
last
=
bytes
.peek
()
.is_none
();
unsafe
{
p
.ic_data_cmd
()
.write
(|
w
|
{
w
.set_stop
(
last
&&
send_stop
);
w
.set_cmd
(
false
);
w
.set_dat
(
byte
);
});
}
}
else
{
break
'xmit
Ok
(());
}
}
let
res
=
self
.wait_on
(
|
me
|
{
if
let
abort_reason
@
Err
(
_
)
=
me
.read_and_clear_abort_reason
()
{
Poll
::
Ready
(
abort_reason
)
}
else
if
!
Self
::
tx_fifo_full
()
{
// resume if there's any space free in the tx fifo
Poll
::
Ready
(
Ok
(()))
}
else
{
Poll
::
Pending
}
},
|
_me
|
unsafe
{
// Set tx "free" threshold a little high so that we get
// woken before the fifo completely drains to minimize
// transfer stalls.
p
.ic_tx_tl
()
.write
(|
w
|
w
.set_tx_tl
(
1
));
p
.ic_intr_mask
()
.modify
(|
w
|
{
w
.set_m_tx_empty
(
true
);
w
.set_m_tx_abrt
(
true
);
})
},
)
.await
;
if
res
.is_err
()
{
break
res
;
}
};
self
.wait_stop_det
(
res
,
send_stop
)
.await
}
/// Helper to wait for a stop bit, for both tx and rx. If we had an abort,
/// then we'll get a hardware-generated stop, otherwise wait for a stop if
/// we're expecting it.
///
/// Also handles an abort which arises while processing the tx fifo.
async
fn
wait_stop_det
(
&
mut
self
,
had_abort
:
Result
<
(),
Error
>
,
do_stop
:
bool
)
->
Result
<
(),
Error
>
{
if
had_abort
.is_err
()
||
do_stop
{
let
p
=
T
::
regs
();
let
had_abort2
=
self
.wait_on
(
|
me
|
unsafe
{
// We could see an abort while processing fifo backlog,
// so handle it here.
let
abort
=
me
.read_and_clear_abort_reason
();
if
had_abort
.is_ok
()
&&
abort
.is_err
()
{
Poll
::
Ready
(
abort
)
}
else
if
p
.ic_raw_intr_stat
()
.read
()
.stop_det
()
{
Poll
::
Ready
(
Ok
(()))
}
else
{
Poll
::
Pending
}
},
|
_me
|
unsafe
{
p
.ic_intr_mask
()
.modify
(|
w
|
{
w
.set_m_stop_det
(
true
);
w
.set_m_tx_abrt
(
true
);
});
},
)
.await
;
unsafe
{
p
.ic_clr_stop_det
()
.read
();
}
had_abort
.and
(
had_abort2
)
}
else
{
had_abort
}
}
pub
async
fn
read_async
(
&
mut
self
,
addr
:
u16
,
buffer
:
&
mut
[
u8
])
->
Result
<
(),
Error
>
{
Self
::
setup
(
addr
)
?
;
self
.read_async_internal
(
buffer
,
false
,
true
)
.await
}
pub
async
fn
write_async
(
&
mut
self
,
addr
:
u16
,
bytes
:
impl
IntoIterator
<
Item
=
u8
>
)
->
Result
<
(),
Error
>
{
Self
::
setup
(
addr
)
?
;
self
.write_async_internal
(
bytes
,
true
)
.await
}
}
impl
<
'd
,
T
:
Instance
+
'd
,
M
:
Mode
>
I2c
<
'd
,
T
,
M
>
{
fn
new_inner
(
_peri
:
impl
Peripheral
<
P
=
T
>
+
'd
,
scl
:
PeripheralRef
<
'd
,
AnyPin
>
,
sda
:
PeripheralRef
<
'd
,
AnyPin
>
,
config
:
Config
,
)
->
Self
{
into_ref!
(
_peri
);
assert!
(
config
.frequency
<=
1_000_000
);
assert!
(
config
.frequency
>
0
);
let
p
=
T
::
regs
();
unsafe
{
let
reset
=
T
::
reset
();
crate
::
reset
::
reset
(
reset
);
crate
::
reset
::
unreset_wait
(
reset
);
p
.ic_enable
()
.write
(|
w
|
w
.set_enable
(
false
));
// Select controller mode & speed
p
.ic_con
()
.modify
(|
w
|
{
// Always use "fast" mode (<= 400 kHz, works fine for standard
// mode too)
w
.set_speed
(
i2c
::
vals
::
Speed
::
FAST
);
w
.set_master_mode
(
true
);
w
.set_ic_slave_disable
(
true
);
w
.set_ic_restart_en
(
true
);
w
.set_tx_empty_ctrl
(
true
);
});
// Set FIFO watermarks to 1 to make things simpler. This is encoded
// by a register value of 0.
p
.ic_tx_tl
()
.write
(|
w
|
w
.set_tx_tl
(
0
));
p
.ic_rx_tl
()
.write
(|
w
|
w
.set_rx_tl
(
0
));
// Configure SCL & SDA pins
scl
.io
()
.ctrl
()
.write
(|
w
|
w
.set_funcsel
(
3
));
sda
.io
()
.ctrl
()
.write
(|
w
|
w
.set_funcsel
(
3
));
scl
.pad_ctrl
()
.write
(|
w
|
{
w
.set_schmitt
(
true
);
w
.set_ie
(
true
);
w
.set_od
(
false
);
w
.set_pue
(
true
);
w
.set_pde
(
false
);
});
sda
.pad_ctrl
()
.write
(|
w
|
{
w
.set_schmitt
(
true
);
w
.set_ie
(
true
);
w
.set_od
(
false
);
w
.set_pue
(
true
);
w
.set_pde
(
false
);
});
// Configure baudrate
// There are some subtleties to I2C timing which we are completely
// ignoring here See:
// https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
let
clk_base
=
crate
::
clocks
::
clk_peri_freq
();
let
period
=
(
clk_base
+
config
.frequency
/
2
)
/
config
.frequency
;
let
lcnt
=
period
*
3
/
5
;
// spend 3/5 (60%) of the period low
let
hcnt
=
period
-
lcnt
;
// and 2/5 (40%) of the period high
// Check for out-of-range divisors:
assert!
(
hcnt
<=
0xffff
);
assert!
(
lcnt
<=
0xffff
);
assert!
(
hcnt
>=
8
);
assert!
(
lcnt
>=
8
);
// Per I2C-bus specification a device in standard or fast mode must
// internally provide a hold time of at least 300ns for the SDA
// signal to bridge the undefined region of the falling edge of SCL.
// A smaller hold time of 120ns is used for fast mode plus.
let
sda_tx_hold_count
=
if
config
.frequency
<
1_000_000
{
// sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
// 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
// fit in uint. Add 1 to avoid division truncation.
((
clk_base
*
3
)
/
10_000_000
)
+
1
}
else
{
// fast mode plus requires a clk_base > 32MHz
assert!
(
clk_base
>=
32_000_000
);
// sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
// 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
// fit in uint. Add 1 to avoid division truncation.
((
clk_base
*
3
)
/
25_000_000
)
+
1
};
assert!
(
sda_tx_hold_count
<=
lcnt
-
2
);
p
.ic_fs_scl_hcnt
()
.write
(|
w
|
w
.set_ic_fs_scl_hcnt
(
hcnt
as
u16
));
p
.ic_fs_scl_lcnt
()
.write
(|
w
|
w
.set_ic_fs_scl_lcnt
(
lcnt
as
u16
));
p
.ic_fs_spklen
()
.write
(|
w
|
w
.set_ic_fs_spklen
(
if
lcnt
<
16
{
1
}
else
{
(
lcnt
/
16
)
as
u8
}));
p
.ic_sda_hold
()
.modify
(|
w
|
w
.set_ic_sda_tx_hold
(
sda_tx_hold_count
as
u16
));
// Enable I2C block
p
.ic_enable
()
.write
(|
w
|
w
.set_enable
(
true
));
}
Self
{
phantom
:
PhantomData
}
}
fn
setup
(
addr
:
u16
)
->
Result
<
(),
Error
>
{
if
addr
>=
0x80
{
return
Err
(
Error
::
AddressOutOfRange
(
addr
));
}
if
i2c_reserved_addr
(
addr
)
{
return
Err
(
Error
::
AddressReserved
(
addr
));
}
let
p
=
T
::
regs
();
unsafe
{
p
.ic_enable
()
.write
(|
w
|
w
.set_enable
(
false
));
p
.ic_tar
()
.write
(|
w
|
w
.set_ic_tar
(
addr
));
p
.ic_enable
()
.write
(|
w
|
w
.set_enable
(
true
));
}
Ok
(())
}
#[inline]
fn
tx_fifo_full
()
->
bool
{
Self
::
tx_fifo_capacity
()
==
0
}
#[inline]
fn
tx_fifo_capacity
()
->
u8
{
let
p
=
T
::
regs
();
unsafe
{
FIFO_SIZE
-
p
.ic_txflr
()
.read
()
.txflr
()
}
}
#[inline]
fn
rx_fifo_len
()
->
u8
{
let
p
=
T
::
regs
();
unsafe
{
p
.ic_rxflr
()
.read
()
.rxflr
()
}
}
fn
read_and_clear_abort_reason
(
&
mut
self
)
->
Result
<
(),
Error
>
{
let
p
=
T
::
regs
();
unsafe
{
let
abort_reason
=
p
.ic_tx_abrt_source
()
.read
();
if
abort_reason
.0
!=
0
{
// Note clearing the abort flag also clears the reason, and this
// instance of flag is clear-on-read! Note also the
// IC_CLR_TX_ABRT register always reads as 0.
p
.ic_clr_tx_abrt
()
.read
();
let
reason
=
if
abort_reason
.abrt_7b_addr_noack
()
|
abort_reason
.abrt_10addr1_noack
()
|
abort_reason
.abrt_10addr2_noack
()
{
AbortReason
::
NoAcknowledge
}
else
if
abort_reason
.arb_lost
()
{
AbortReason
::
ArbitrationLoss
}
else
{
AbortReason
::
Other
(
abort_reason
.0
)
};
Err
(
Error
::
Abort
(
reason
))
}
else
{
Ok
(())
}
}
}
fn
read_blocking_internal
(
&
mut
self
,
read
:
&
mut
[
u8
],
restart
:
bool
,
send_stop
:
bool
)
->
Result
<
(),
Error
>
{
if
read
.is_empty
()
{
return
Err
(
Error
::
InvalidReadBufferLength
);
}
let
p
=
T
::
regs
();
let
lastindex
=
read
.len
()
-
1
;
for
(
i
,
byte
)
in
read
.iter_mut
()
.enumerate
()
{
let
first
=
i
==
0
;
let
last
=
i
==
lastindex
;
// NOTE(unsafe) We have &mut self
unsafe
{
// wait until there is space in the FIFO to write the next byte
while
Self
::
tx_fifo_full
()
{}
p
.ic_data_cmd
()
.write
(|
w
|
{
w
.set_restart
(
restart
&&
first
);
w
.set_stop
(
send_stop
&&
last
);
w
.set_cmd
(
true
);
});
while
Self
::
rx_fifo_len
()
==
0
{
self
.read_and_clear_abort_reason
()
?
;
}
*
byte
=
p
.ic_data_cmd
()
.read
()
.dat
();
}
}
Ok
(())
}
fn
write_blocking_internal
(
&
mut
self
,
write
:
&
[
u8
],
send_stop
:
bool
)
->
Result
<
(),
Error
>
{
if
write
.is_empty
()
{
return
Err
(
Error
::
InvalidWriteBufferLength
);
}
let
p
=
T
::
regs
();
for
(
i
,
byte
)
in
write
.iter
()
.enumerate
()
{
let
last
=
i
==
write
.len
()
-
1
;
// NOTE(unsafe) We have &mut self
unsafe
{
p
.ic_data_cmd
()
.write
(|
w
|
{
w
.set_stop
(
send_stop
&&
last
);
w
.set_dat
(
*
byte
);
});
// Wait until the transmission of the address/data from the
// internal shift register has completed. For this to function
// correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
// TX_EMPTY_CTRL flag was set in i2c_init.
while
!
p
.ic_raw_intr_stat
()
.read
()
.tx_empty
()
{}
let
abort_reason
=
self
.read_and_clear_abort_reason
();
if
abort_reason
.is_err
()
||
(
send_stop
&&
last
)
{
// If the transaction was aborted or if it completed
// successfully wait until the STOP condition has occurred.
while
!
p
.ic_raw_intr_stat
()
.read
()
.stop_det
()
{}
p
.ic_clr_stop_det
()
.read
()
.clr_stop_det
();
}
// Note the hardware issues a STOP automatically on an abort
// condition. Note also the hardware clears RX FIFO as well as
// TX on abort, ecause we set hwparam
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
abort_reason
?
;
}
}
Ok
(())
}
// =========================
// Blocking public API
// =========================
pub
fn
blocking_read
(
&
mut
self
,
address
:
u8
,
read
:
&
mut
[
u8
])
->
Result
<
(),
Error
>
{
Self
::
setup
(
address
.into
())
?
;
self
.read_blocking_internal
(
read
,
true
,
true
)
// Automatic Stop
}
pub
fn
blocking_write
(
&
mut
self
,
address
:
u8
,
write
:
&
[
u8
])
->
Result
<
(),
Error
>
{
Self
::
setup
(
address
.into
())
?
;
self
.write_blocking_internal
(
write
,
true
)
}
pub
fn
blocking_write_read
(
&
mut
self
,
address
:
u8
,
write
:
&
[
u8
],
read
:
&
mut
[
u8
])
->
Result
<
(),
Error
>
{
Self
::
setup
(
address
.into
())
?
;
self
.write_blocking_internal
(
write
,
false
)
?
;
self
.read_blocking_internal
(
read
,
true
,
true
)
// Automatic Stop
}
}
mod
eh02
{
use
super
::
*
;
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_02
::
blocking
::
i2c
::
Read
for
I2c
<
'd
,
T
,
M
>
{
type
Error
=
Error
;
fn
read
(
&
mut
self
,
address
:
u8
,
buffer
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_read
(
address
,
buffer
)
}
}
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_02
::
blocking
::
i2c
::
Write
for
I2c
<
'd
,
T
,
M
>
{
type
Error
=
Error
;
fn
write
(
&
mut
self
,
address
:
u8
,
bytes
:
&
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_write
(
address
,
bytes
)
}
}
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_02
::
blocking
::
i2c
::
WriteRead
for
I2c
<
'd
,
T
,
M
>
{
type
Error
=
Error
;
fn
write_read
(
&
mut
self
,
address
:
u8
,
bytes
:
&
[
u8
],
buffer
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_write_read
(
address
,
bytes
,
buffer
)
}
}
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_02
::
blocking
::
i2c
::
Transactional
for
I2c
<
'd
,
T
,
M
>
{
type
Error
=
Error
;
fn
exec
(
&
mut
self
,
address
:
u8
,
operations
:
&
mut
[
embedded_hal_02
::
blocking
::
i2c
::
Operation
<
'_
>
],
)
->
Result
<
(),
Self
::
Error
>
{
Self
::
setup
(
address
.into
())
?
;
for
i
in
0
..
operations
.len
()
{
let
last
=
i
==
operations
.len
()
-
1
;
match
&
mut
operations
[
i
]
{
embedded_hal_02
::
blocking
::
i2c
::
Operation
::
Read
(
buf
)
=>
{
self
.read_blocking_internal
(
buf
,
false
,
last
)
?
}
embedded_hal_02
::
blocking
::
i2c
::
Operation
::
Write
(
buf
)
=>
self
.write_blocking_internal
(
buf
,
last
)
?
,
}
}
Ok
(())
}
}
}
#[cfg(feature
=
"unstable-traits"
)]
mod
eh1
{
use
super
::
*
;
impl
embedded_hal_1
::
i2c
::
Error
for
Error
{
fn
kind
(
&
self
)
->
embedded_hal_1
::
i2c
::
ErrorKind
{
match
*
self
{
Self
::
Abort
(
AbortReason
::
ArbitrationLoss
)
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
ArbitrationLoss
,
Self
::
Abort
(
AbortReason
::
NoAcknowledge
)
=>
{
embedded_hal_1
::
i2c
::
ErrorKind
::
NoAcknowledge
(
embedded_hal_1
::
i2c
::
NoAcknowledgeSource
::
Address
)
}
Self
::
Abort
(
AbortReason
::
Other
(
_
))
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
Other
,
Self
::
InvalidReadBufferLength
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
Other
,
Self
::
InvalidWriteBufferLength
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
Other
,
Self
::
AddressOutOfRange
(
_
)
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
Other
,
Self
::
AddressReserved
(
_
)
=>
embedded_hal_1
::
i2c
::
ErrorKind
::
Other
,
}
}
}
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_1
::
i2c
::
ErrorType
for
I2c
<
'd
,
T
,
M
>
{
type
Error
=
Error
;
}
impl
<
'd
,
T
:
Instance
,
M
:
Mode
>
embedded_hal_1
::
i2c
::
I2c
for
I2c
<
'd
,
T
,
M
>
{
fn
read
(
&
mut
self
,
address
:
u8
,
read
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_read
(
address
,
read
)
}
fn
write
(
&
mut
self
,
address
:
u8
,
write
:
&
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_write
(
address
,
write
)
}
fn
write_read
(
&
mut
self
,
address
:
u8
,
write
:
&
[
u8
],
read
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
self
.blocking_write_read
(
address
,
write
,
read
)
}
fn
transaction
(
&
mut
self
,
address
:
u8
,
operations
:
&
mut
[
embedded_hal_1
::
i2c
::
Operation
<
'_
>
],
)
->
Result
<
(),
Self
::
Error
>
{
Self
::
setup
(
address
.into
())
?
;
for
i
in
0
..
operations
.len
()
{
let
last
=
i
==
operations
.len
()
-
1
;
match
&
mut
operations
[
i
]
{
embedded_hal_1
::
i2c
::
Operation
::
Read
(
buf
)
=>
self
.read_blocking_internal
(
buf
,
false
,
last
)
?
,
embedded_hal_1
::
i2c
::
Operation
::
Write
(
buf
)
=>
self
.write_blocking_internal
(
buf
,
last
)
?
,
}
}
Ok
(())
}
}
}
#[cfg(all(feature
=
"unstable-traits"
,
feature
=
"nightly"
))]
mod
nightly
{
use
embedded_hal_1
::
i2c
::
Operation
;
use
embedded_hal_async
::
i2c
::
AddressMode
;
use
super
::
*
;
impl
<
'd
,
A
,
T
>
embedded_hal_async
::
i2c
::
I2c
<
A
>
for
I2c
<
'd
,
T
,
Async
>
where
A
:
AddressMode
+
Into
<
u16
>
+
'static
,
T
:
Instance
+
'd
,
{
async
fn
read
(
&
mut
self
,
address
:
A
,
read
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
let
addr
:
u16
=
address
.into
();
Self
::
setup
(
addr
)
?
;
self
.read_async_internal
(
read
,
false
,
true
)
.await
}
async
fn
write
(
&
mut
self
,
address
:
A
,
write
:
&
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
let
addr
:
u16
=
address
.into
();
Self
::
setup
(
addr
)
?
;
self
.write_async_internal
(
write
.iter
()
.copied
(),
true
)
.await
}
async
fn
write_read
(
&
mut
self
,
address
:
A
,
write
:
&
[
u8
],
read
:
&
mut
[
u8
])
->
Result
<
(),
Self
::
Error
>
{
let
addr
:
u16
=
address
.into
();
Self
::
setup
(
addr
)
?
;
self
.write_async_internal
(
write
.iter
()
.cloned
(),
false
)
.await
?
;
self
.read_async_internal
(
read
,
false
,
true
)
.await
}
async
fn
transaction
(
&
mut
self
,
address
:
A
,
operations
:
&
mut
[
Operation
<
'_
>
])
->
Result
<
(),
Self
::
Error
>
{
let
addr
:
u16
=
address
.into
();
let
mut
iterator
=
operations
.iter_mut
();
while
let
Some
(
op
)
=
iterator
.next
()
{
let
last
=
iterator
.len
()
==
0
;
match
op
{
Operation
::
Read
(
buffer
)
=>
{
Self
::
setup
(
addr
)
?
;
self
.read_async_internal
(
buffer
,
false
,
last
)
.await
?
;
}
Operation
::
Write
(
buffer
)
=>
{
Self
::
setup
(
addr
)
?
;
self
.write_async_internal
(
buffer
.into_iter
()
.cloned
(),
last
)
.await
?
;
}
}
}
Ok
(())
}
}
}
fn
i2c_reserved_addr
(
addr
:
u16
)
->
bool
{
(
addr
&
0x78
)
==
0
||
(
addr
&
0x78
)
==
0x78
}
mod
sealed
{
use
embassy_cortex_m
::
interrupt
::
Interrupt
;
use
embassy_sync
::
waitqueue
::
AtomicWaker
;
pub
trait
Instance
{
const
TX_DREQ
:
u8
;
const
RX_DREQ
:
u8
;
type
Interrupt
:
Interrupt
;
fn
regs
()
->
crate
::
pac
::
i2c
::
I2c
;
fn
reset
()
->
crate
::
pac
::
resets
::
regs
::
Peripherals
;
fn
waker
()
->
&
'static
AtomicWaker
;
}
pub
trait
Mode
{}
pub
trait
SdaPin
<
T
:
Instance
>
{}
pub
trait
SclPin
<
T
:
Instance
>
{}
}
pub
trait
Mode
:
sealed
::
Mode
{}
macro_rules!
impl_mode
{
(
$name:ident
)
=>
{
impl
sealed
::
Mode
for
$name
{}
impl
Mode
for
$name
{}
};
}
pub
struct
Blocking
;
pub
struct
Async
;
impl_mode!
(
Blocking
);
impl_mode!
(
Async
);
pub
trait
Instance
:
sealed
::
Instance
{}
macro_rules!
impl_instance
{
(
$type:ident
,
$irq:ident
,
$reset:ident
,
$tx_dreq:expr
,
$rx_dreq:expr
)
=>
{
impl
sealed
::
Instance
for
peripherals
::
$type
{
const
TX_DREQ
:
u8
=
$tx_dreq
;
const
RX_DREQ
:
u8
=
$rx_dreq
;
type
Interrupt
=
crate
::
interrupt
::
$irq
;
#[inline]
fn
regs
()
->
pac
::
i2c
::
I2c
{
pac
::
$type
}
#[inline]
fn
reset
()
->
pac
::
resets
::
regs
::
Peripherals
{
let
mut
ret
=
pac
::
resets
::
regs
::
Peripherals
::
default
();
ret
.
$reset
(
true
);
ret
}
#[inline]
fn
waker
()
->
&
'static
AtomicWaker
{
static
WAKER
:
AtomicWaker
=
AtomicWaker
::
new
();
&
WAKER
}
}
impl
Instance
for
peripherals
::
$type
{}
};
}
impl_instance!
(
I2C0
,
I2C0_IRQ
,
set_i2c0
,
32
,
33
);
impl_instance!
(
I2C1
,
I2C1_IRQ
,
set_i2c1
,
34
,
35
);
pub
trait
SdaPin
<
T
:
Instance
>
:
sealed
::
SdaPin
<
T
>
+
crate
::
gpio
::
Pin
{}
pub
trait
SclPin
<
T
:
Instance
>
:
sealed
::
SclPin
<
T
>
+
crate
::
gpio
::
Pin
{}
macro_rules!
impl_pin
{
(
$pin:ident
,
$instance:ident
,
$function:ident
)
=>
{
impl
sealed
::
$function
<
peripherals
::
$instance
>
for
peripherals
::
$pin
{}
impl
$function
<
peripherals
::
$instance
>
for
peripherals
::
$pin
{}
};
}
impl_pin!
(
PIN_0
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_1
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_2
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_3
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_4
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_5
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_6
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_7
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_8
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_9
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_10
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_11
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_12
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_13
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_14
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_15
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_16
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_17
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_18
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_19
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_20
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_21
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_22
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_23
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_24
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_25
,
I2C0
,
SclPin
);
impl_pin!
(
PIN_26
,
I2C1
,
SdaPin
);
impl_pin!
(
PIN_27
,
I2C1
,
SclPin
);
impl_pin!
(
PIN_28
,
I2C0
,
SdaPin
);
impl_pin!
(
PIN_29
,
I2C0
,
SclPin
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment