aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-05-26 23:52:15 +0200
committerGitHub <[email protected]>2021-05-26 23:52:15 +0200
commitb515170e0a1f5a5c79401cd6508b9638232302b3 (patch)
tree083769e7b4751b3ebc36adfba2e155afc5d9e714
parenta126e17fb2d5544f1506aec860cc1b218008e9fd (diff)
parent565c606ff8b216689df6551808ee57038b8939cd (diff)
Merge pull request #208 from embassy-rs/deconfigure-pins
nRF lowpower improvements
-rw-r--r--embassy-nrf-examples/src/bin/qspi.rs2
-rw-r--r--embassy-nrf-examples/src/bin/qspi_lowpower.rs81
-rw-r--r--embassy-nrf-examples/src/bin/twim.rs35
-rw-r--r--embassy-nrf-examples/src/bin/twim_lowpower.rs54
-rw-r--r--embassy-nrf/src/gpio.rs13
-rw-r--r--embassy-nrf/src/qspi.rs140
-rw-r--r--embassy-nrf/src/spim.rs19
-rw-r--r--embassy-nrf/src/twim.rs19
-rw-r--r--embassy-nrf/src/uarte.rs9
9 files changed, 310 insertions, 62 deletions
diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs
index 14f215187..1f33192e9 100644
--- a/embassy-nrf-examples/src/bin/qspi.rs
+++ b/embassy-nrf-examples/src/bin/qspi.rs
@@ -33,7 +33,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
33 33
34 let config = qspi::Config::default(); 34 let config = qspi::Config::default();
35 let irq = interrupt::take!(QSPI); 35 let irq = interrupt::take!(QSPI);
36 let mut q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config); 36 let mut q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config).await;
37 37
38 let mut id = [1; 3]; 38 let mut id = [1; 3];
39 q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); 39 q.custom_instruction(0x9F, &[], &mut id).await.unwrap();
diff --git a/embassy-nrf-examples/src/bin/qspi_lowpower.rs b/embassy-nrf-examples/src/bin/qspi_lowpower.rs
new file mode 100644
index 000000000..9bbc87caa
--- /dev/null
+++ b/embassy-nrf-examples/src/bin/qspi_lowpower.rs
@@ -0,0 +1,81 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use core::mem;
12use defmt::panic;
13use embassy::executor::Spawner;
14use embassy::time::{Duration, Timer};
15use embassy::traits::flash::Flash;
16use embassy_nrf::Peripherals;
17use embassy_nrf::{interrupt, qspi};
18use example_common::*;
19
20// Workaround for alignment requirements.
21// Nicer API will probably come in the future.
22#[repr(C, align(4))]
23struct AlignedBuf([u8; 64]);
24
25#[embassy::main]
26async fn main(_spawner: Spawner, mut p: Peripherals) {
27 let mut irq = interrupt::take!(QSPI);
28
29 loop {
30 let mut config = qspi::Config::default();
31 config.deep_power_down = Some(qspi::DeepPowerDownConfig {
32 enter_time: 3, // tDP = 30uS
33 exit_time: 3, // tRDP = 35uS
34 });
35
36 let mut q = qspi::Qspi::new(
37 &mut p.QSPI,
38 &mut irq,
39 &mut p.P0_19,
40 &mut p.P0_17,
41 &mut p.P0_20,
42 &mut p.P0_21,
43 &mut p.P0_22,
44 &mut p.P0_23,
45 config,
46 )
47 .await;
48
49 let mut id = [1; 3];
50 q.custom_instruction(0x9F, &[], &mut id).await.unwrap();
51 info!("id: {}", id);
52
53 // Read status register
54 let mut status = [4; 1];
55 q.custom_instruction(0x05, &[], &mut status).await.unwrap();
56
57 info!("status: {:?}", status[0]);
58
59 if status[0] & 0x40 == 0 {
60 status[0] |= 0x40;
61
62 q.custom_instruction(0x01, &status, &mut []).await.unwrap();
63
64 info!("enabled quad in status");
65 }
66
67 let mut buf = AlignedBuf([0u8; 64]);
68
69 info!("reading...");
70 q.read(0, &mut buf.0).await.unwrap();
71 info!("read: {=[u8]:x}", buf.0);
72
73 // Drop the QSPI instance. This disables the peripehral and deconfigures the pins.
74 // This clears the borrow on the singletons, so they can now be used again.
75 mem::drop(q);
76
77 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
78 // During this sleep, the nRF chip should only use ~3uA
79 Timer::after(Duration::from_secs(1)).await;
80 }
81}
diff --git a/embassy-nrf-examples/src/bin/twim.rs b/embassy-nrf-examples/src/bin/twim.rs
new file mode 100644
index 000000000..537cea160
--- /dev/null
+++ b/embassy-nrf-examples/src/bin/twim.rs
@@ -0,0 +1,35 @@
1//! Example on how to read a 24C/24LC i2c eeprom.
2//!
3//! Connect SDA to P0.03, SCL to P0.04
4
5#![no_std]
6#![no_main]
7#![feature(min_type_alias_impl_trait)]
8#![feature(impl_trait_in_bindings)]
9#![feature(type_alias_impl_trait)]
10#![allow(incomplete_features)]
11
12#[path = "../example_common.rs"]
13mod example_common;
14
15use defmt::{panic, *};
16use embassy::executor::Spawner;
17use embassy_nrf::twim::{self, Twim};
18use embassy_nrf::{interrupt, Peripherals};
19
20const ADDRESS: u8 = 0x50;
21
22#[embassy::main]
23async fn main(_spawner: Spawner, p: Peripherals) {
24 info!("Initializing TWI...");
25 let config = twim::Config::default();
26 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
27 let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
28
29 info!("Reading...");
30
31 let mut buf = [0u8; 16];
32 twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap();
33
34 info!("Read: {=[u8]:x}", buf);
35}
diff --git a/embassy-nrf-examples/src/bin/twim_lowpower.rs b/embassy-nrf-examples/src/bin/twim_lowpower.rs
new file mode 100644
index 000000000..1cd66a18e
--- /dev/null
+++ b/embassy-nrf-examples/src/bin/twim_lowpower.rs
@@ -0,0 +1,54 @@
1//! Example on how to read a 24C/24LC i2c eeprom with low power consumption.
2//! The eeprom is read every 1 second, while ensuring lowest possible power while
3//! sleeping between reads.
4//!
5//! Connect SDA to P0.03, SCL to P0.04
6
7#![no_std]
8#![no_main]
9#![feature(min_type_alias_impl_trait)]
10#![feature(impl_trait_in_bindings)]
11#![feature(type_alias_impl_trait)]
12#![allow(incomplete_features)]
13
14#[path = "../example_common.rs"]
15mod example_common;
16
17use core::mem;
18
19use defmt::{panic, *};
20use embassy::executor::Spawner;
21use embassy::time::{Duration, Timer};
22use embassy_nrf::twim::{self, Twim};
23use embassy_nrf::{interrupt, Peripherals};
24
25const ADDRESS: u8 = 0x50;
26
27#[embassy::main]
28async fn main(_spawner: Spawner, mut p: Peripherals) {
29 info!("Started!");
30 let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
31
32 loop {
33 info!("Initializing TWI...");
34 let config = twim::Config::default();
35
36 // Create the TWIM instance with borrowed singletons, so they're not consumed.
37 let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
38
39 info!("Reading...");
40
41 let mut buf = [0u8; 16];
42 twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap();
43
44 info!("Read: {=[u8]:x}", buf);
45
46 // Drop the TWIM instance. This disables the peripehral and deconfigures the pins.
47 // This clears the borrow on the singletons, so they can now be used again.
48 mem::drop(twi);
49
50 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
51 // During this sleep, the nRF chip should only use ~3uA
52 Timer::after(Duration::from_secs(1)).await;
53 }
54}
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 3ae160ca8..b02e77874 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -12,6 +12,8 @@ use gpio::pin_cnf::DRIVE_A;
12use crate::pac; 12use crate::pac;
13use crate::pac::p0 as gpio; 13use crate::pac::p0 as gpio;
14 14
15use self::sealed::Pin as _;
16
15/// A GPIO port with up to 32 pins. 17/// A GPIO port with up to 32 pins.
16#[derive(Debug, Eq, PartialEq)] 18#[derive(Debug, Eq, PartialEq)]
17pub enum Port { 19pub enum Port {
@@ -487,6 +489,17 @@ impl OptionalPin for NoPin {
487 489
488// ==================== 490// ====================
489 491
492pub(crate) fn deconfigure_pin(psel_bits: u32) {
493 if psel_bits & 0x8000_0000 != 0 {
494 return;
495 }
496 unsafe {
497 AnyPin::steal(psel_bits as _).conf().reset();
498 }
499}
500
501// ====================
502
490macro_rules! impl_pin { 503macro_rules! impl_pin {
491 ($type:ident, $port_num:expr, $pin_num:expr) => { 504 ($type:ident, $port_num:expr, $pin_num:expr) => {
492 impl crate::gpio::Pin for peripherals::$type {} 505 impl crate::gpio::Pin for peripherals::$type {}
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index e5d21ceaf..6cabe1168 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -2,6 +2,7 @@
2 2
3use core::future::Future; 3use core::future::Future;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::ptr;
5use core::task::Poll; 6use core::task::Poll;
6use embassy::interrupt::{Interrupt, InterruptExt}; 7use embassy::interrupt::{Interrupt, InterruptExt};
7use embassy::traits::flash::{Error, Flash}; 8use embassy::traits::flash::{Error, Flash};
@@ -10,7 +11,8 @@ use embassy_extras::unborrow;
10use futures::future::poll_fn; 11use futures::future::poll_fn;
11 12
12use crate::fmt::{assert, assert_eq, *}; 13use crate::fmt::{assert, assert_eq, *};
13use crate::gpio::Pin as GpioPin; 14use crate::gpio::sealed::Pin as _;
15use crate::gpio::{self, Pin as GpioPin};
14use crate::pac; 16use crate::pac;
15 17
16pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode; 18pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode;
@@ -29,7 +31,9 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
29// - set gpio in high drive 31// - set gpio in high drive
30 32
31pub struct DeepPowerDownConfig { 33pub struct DeepPowerDownConfig {
34 /// Time required for entering DPM, in units of 16us
32 pub enter_time: u16, 35 pub enter_time: u16,
36 /// Time required for exiting DPM, in units of 16us
33 pub exit_time: u16, 37 pub exit_time: u16,
34} 38}
35 39
@@ -55,11 +59,12 @@ impl Default for Config {
55} 59}
56 60
57pub struct Qspi<'d, T: Instance> { 61pub struct Qspi<'d, T: Instance> {
62 dpm_enabled: bool,
58 phantom: PhantomData<&'d mut T>, 63 phantom: PhantomData<&'d mut T>,
59} 64}
60 65
61impl<'d, T: Instance> Qspi<'d, T> { 66impl<'d, T: Instance> Qspi<'d, T> {
62 pub fn new( 67 pub async fn new(
63 _qspi: impl Unborrow<Target = T> + 'd, 68 _qspi: impl Unborrow<Target = T> + 'd,
64 irq: impl Unborrow<Target = T::Interrupt> + 'd, 69 irq: impl Unborrow<Target = T::Interrupt> + 'd,
65 sck: impl Unborrow<Target = impl GpioPin> + 'd, 70 sck: impl Unborrow<Target = impl GpioPin> + 'd,
@@ -69,20 +74,21 @@ impl<'d, T: Instance> Qspi<'d, T> {
69 io2: impl Unborrow<Target = impl GpioPin> + 'd, 74 io2: impl Unborrow<Target = impl GpioPin> + 'd,
70 io3: impl Unborrow<Target = impl GpioPin> + 'd, 75 io3: impl Unborrow<Target = impl GpioPin> + 'd,
71 config: Config, 76 config: Config,
72 ) -> Self { 77 ) -> Qspi<'d, T> {
73 unborrow!(irq, sck, csn, io0, io1, io2, io3); 78 unborrow!(irq, sck, csn, io0, io1, io2, io3);
74 79
75 let r = T::regs(); 80 let r = T::regs();
76 81
77 for cnf in &[ 82 let sck = sck.degrade();
78 sck.conf(), 83 let csn = csn.degrade();
79 csn.conf(), 84 let io0 = io0.degrade();
80 io0.conf(), 85 let io1 = io1.degrade();
81 io1.conf(), 86 let io2 = io2.degrade();
82 io2.conf(), 87 let io3 = io3.degrade();
83 io3.conf(), 88
84 ] { 89 for pin in [&sck, &csn, &io0, &io1, &io2, &io3] {
85 cnf.write(|w| w.dir().output().drive().h0h1()); 90 pin.set_high();
91 pin.conf().write(|w| w.dir().output().drive().h0h1());
86 } 92 }
87 93
88 r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); 94 r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
@@ -92,53 +98,56 @@ impl<'d, T: Instance> Qspi<'d, T> {
92 r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) }); 98 r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) });
93 r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) }); 99 r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) });
94 100
95 r.ifconfig0.write(|mut w| { 101 r.ifconfig0.write(|w| {
96 w = w.addrmode().variant(AddressMode::_24BIT); 102 w.addrmode().variant(AddressMode::_24BIT);
97 if config.deep_power_down.is_some() { 103 w.dpmenable().bit(config.deep_power_down.is_some());
98 w = w.dpmenable().enable(); 104 w.ppsize().variant(config.write_page_size);
99 } else { 105 w.readoc().variant(config.read_opcode);
100 w = w.dpmenable().disable(); 106 w.writeoc().variant(config.write_opcode);
101 }
102 w = w.ppsize().variant(config.write_page_size);
103 w = w.readoc().variant(config.read_opcode);
104 w = w.writeoc().variant(config.write_opcode);
105 w 107 w
106 }); 108 });
107 109
108 if let Some(dpd) = &config.deep_power_down { 110 if let Some(dpd) = &config.deep_power_down {
109 r.dpmdur.write(|mut w| unsafe { 111 r.dpmdur.write(|w| unsafe {
110 w = w.enter().bits(dpd.enter_time); 112 w.enter().bits(dpd.enter_time);
111 w = w.exit().bits(dpd.exit_time); 113 w.exit().bits(dpd.exit_time);
112 w 114 w
113 }) 115 })
114 } 116 }
115 117
116 r.ifconfig1.write(|w| { 118 r.ifconfig1.write(|w| unsafe {
117 let w = unsafe { w.sckdelay().bits(80) }; 119 w.sckdelay().bits(80);
118 let w = w.dpmen().exit(); 120 w.dpmen().exit();
119 let w = w.spimode().mode0(); 121 w.spimode().mode0();
120 let w = unsafe { w.sckfreq().bits(3) }; 122 w.sckfreq().bits(3);
123 w
124 });
125
126 r.xipoffset.write(|w| unsafe {
127 w.xipoffset().bits(config.xip_offset);
121 w 128 w
122 }); 129 });
123 130
124 r.xipoffset 131 irq.set_handler(Self::on_interrupt);
125 .write(|w| unsafe { w.xipoffset().bits(config.xip_offset) }); 132 irq.unpend();
133 irq.enable();
126 134
127 // Enable it 135 // Enable it
128 r.enable.write(|w| w.enable().enabled()); 136 r.enable.write(|w| w.enable().enabled());
129 137
138 let mut res = Self {
139 dpm_enabled: config.deep_power_down.is_some(),
140 phantom: PhantomData,
141 };
142
130 r.events_ready.reset(); 143 r.events_ready.reset();
144 r.intenset.write(|w| w.ready().set());
145
131 r.tasks_activate.write(|w| w.tasks_activate().bit(true)); 146 r.tasks_activate.write(|w| w.tasks_activate().bit(true));
132 while r.events_ready.read().bits() == 0 {}
133 r.events_ready.reset();
134 147
135 irq.set_handler(Self::on_interrupt); 148 res.wait_ready().await;
136 irq.unpend();
137 irq.enable();
138 149
139 Self { 150 res
140 phantom: PhantomData,
141 }
142 } 151 }
143 152
144 fn on_interrupt(_: *mut ()) { 153 fn on_interrupt(_: *mut ()) {
@@ -151,19 +160,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
151 } 160 }
152 } 161 }
153 162
154 pub fn sleep(&mut self) {
155 let r = T::regs();
156
157 info!("flash: sleeping");
158 info!("flash: state = {:?}", r.status.read().bits());
159 r.ifconfig1.modify(|_, w| w.dpmen().enter());
160 info!("flash: state = {:?}", r.status.read().bits());
161 cortex_m::asm::delay(1000000);
162 info!("flash: state = {:?}", r.status.read().bits());
163
164 r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
165 }
166
167 pub async fn custom_instruction( 163 pub async fn custom_instruction(
168 &mut self, 164 &mut self,
169 opcode: u8, 165 opcode: u8,
@@ -246,6 +242,44 @@ impl<'d, T: Instance> Qspi<'d, T> {
246 } 242 }
247} 243}
248 244
245impl<'d, T: Instance> Drop for Qspi<'d, T> {
246 fn drop(&mut self) {
247 let r = T::regs();
248
249 if self.dpm_enabled {
250 info!("qspi: doing deep powerdown...");
251
252 r.ifconfig1.modify(|_, w| w.dpmen().enter());
253
254 // Wait for DPM enter.
255 // Unfortunately we must spin. There's no way to do this interrupt-driven.
256 // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:)
257 while r.status.read().dpm().is_disabled() {}
258 }
259
260 // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it.
261 r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
262
263 // Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7
264 // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate,
265 // so we only do the second one here.
266 unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) }
267
268 r.enable.write(|w| w.enable().disabled());
269
270 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
271 // leaving it floating, the flash chip might read it as zero which would cause it to
272 // spuriously exit DPM.
273 gpio::deconfigure_pin(r.psel.sck.read().bits());
274 gpio::deconfigure_pin(r.psel.io0.read().bits());
275 gpio::deconfigure_pin(r.psel.io1.read().bits());
276 gpio::deconfigure_pin(r.psel.io2.read().bits());
277 gpio::deconfigure_pin(r.psel.io3.read().bits());
278
279 info!("qspi: dropped");
280 }
281}
282
249impl<'d, T: Instance> Flash for Qspi<'d, T> { 283impl<'d, T: Instance> Flash for Qspi<'d, T> {
250 #[rustfmt::skip] 284 #[rustfmt::skip]
251 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; 285 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index bb43b7c7c..a29c1a3ee 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -14,6 +14,7 @@ use traits::spi::FullDuplex;
14use crate::gpio::sealed::Pin as _; 14use crate::gpio::sealed::Pin as _;
15use crate::gpio::{OptionalPin, Pin as GpioPin}; 15use crate::gpio::{OptionalPin, Pin as GpioPin};
16use crate::interrupt::Interrupt; 16use crate::interrupt::Interrupt;
17use crate::{fmt::*, gpio};
17use crate::{pac, util::slice_in_ram_or}; 18use crate::{pac, util::slice_in_ram_or};
18 19
19pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 20pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
@@ -153,6 +154,24 @@ impl<'d, T: Instance> Spim<'d, T> {
153 } 154 }
154} 155}
155 156
157impl<'d, T: Instance> Drop for Spim<'d, T> {
158 fn drop(&mut self) {
159 info!("spim drop");
160
161 // TODO check for abort, wait for xxxstopped
162
163 // disable!
164 let r = T::regs();
165 r.enable.write(|w| w.enable().disabled());
166
167 gpio::deconfigure_pin(r.psel.sck.read().bits());
168 gpio::deconfigure_pin(r.psel.miso.read().bits());
169 gpio::deconfigure_pin(r.psel.mosi.read().bits());
170
171 info!("spim drop: done");
172 }
173}
174
156impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> { 175impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
157 type Error = Error; 176 type Error = Error;
158 177
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 05c4c260f..ea3ac7553 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -13,10 +13,10 @@ use embassy::util::{AtomicWaker, Unborrow};
13use embassy_extras::unborrow; 13use embassy_extras::unborrow;
14 14
15use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 15use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
16use crate::fmt::*;
17use crate::gpio::Pin as GpioPin; 16use crate::gpio::Pin as GpioPin;
18use crate::pac; 17use crate::pac;
19use crate::util::{slice_in_ram, slice_in_ram_or}; 18use crate::util::{slice_in_ram, slice_in_ram_or};
19use crate::{fmt::*, gpio};
20 20
21pub enum Frequency { 21pub enum Frequency {
22 #[doc = "26738688: 100 kbps"] 22 #[doc = "26738688: 100 kbps"]
@@ -30,12 +30,16 @@ pub enum Frequency {
30#[non_exhaustive] 30#[non_exhaustive]
31pub struct Config { 31pub struct Config {
32 pub frequency: Frequency, 32 pub frequency: Frequency,
33 pub sda_pullup: bool,
34 pub scl_pullup: bool,
33} 35}
34 36
35impl Default for Config { 37impl Default for Config {
36 fn default() -> Self { 38 fn default() -> Self {
37 Self { 39 Self {
38 frequency: Frequency::K100, 40 frequency: Frequency::K100,
41 sda_pullup: false,
42 scl_pullup: false,
39 } 43 }
40 } 44 }
41} 45}
@@ -61,15 +65,19 @@ impl<'d, T: Instance> Twim<'d, T> {
61 sda.conf().write(|w| { 65 sda.conf().write(|w| {
62 w.dir().input(); 66 w.dir().input();
63 w.input().connect(); 67 w.input().connect();
64 w.pull().pullup();
65 w.drive().s0d1(); 68 w.drive().s0d1();
69 if config.sda_pullup {
70 w.pull().pullup();
71 }
66 w 72 w
67 }); 73 });
68 scl.conf().write(|w| { 74 scl.conf().write(|w| {
69 w.dir().input(); 75 w.dir().input();
70 w.input().connect(); 76 w.input().connect();
71 w.pull().pullup();
72 w.drive().s0d1(); 77 w.drive().s0d1();
78 if config.scl_pullup {
79 w.pull().pullup();
80 }
73 w 81 w
74 }); 82 });
75 83
@@ -422,9 +430,10 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
422 let r = T::regs(); 430 let r = T::regs();
423 r.enable.write(|w| w.enable().disabled()); 431 r.enable.write(|w| w.enable().disabled());
424 432
425 info!("uarte drop: done"); 433 gpio::deconfigure_pin(r.psel.sda.read().bits());
434 gpio::deconfigure_pin(r.psel.scl.read().bits());
426 435
427 // TODO: disable pins 436 info!("twim drop: done");
428 } 437 }
429} 438}
430 439
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 3ad7a787d..2f6d1a391 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -15,7 +15,7 @@ use futures::future::poll_fn;
15use crate::chip::EASY_DMA_SIZE; 15use crate::chip::EASY_DMA_SIZE;
16use crate::fmt::{assert, panic, *}; 16use crate::fmt::{assert, panic, *};
17use crate::gpio::sealed::Pin as _; 17use crate::gpio::sealed::Pin as _;
18use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; 18use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin};
19use crate::interrupt::Interrupt; 19use crate::interrupt::Interrupt;
20use crate::pac; 20use crate::pac;
21use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 21use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
@@ -166,9 +166,12 @@ impl<'a, T: Instance> Drop for Uarte<'a, T> {
166 // Finally we can disable! 166 // Finally we can disable!
167 r.enable.write(|w| w.enable().disabled()); 167 r.enable.write(|w| w.enable().disabled());
168 168
169 info!("uarte drop: done"); 169 gpio::deconfigure_pin(r.psel.rxd.read().bits());
170 gpio::deconfigure_pin(r.psel.txd.read().bits());
171 gpio::deconfigure_pin(r.psel.rts.read().bits());
172 gpio::deconfigure_pin(r.psel.cts.read().bits());
170 173
171 // TODO: disable pins 174 info!("uarte drop: done");
172 } 175 }
173} 176}
174 177