Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Commit 71f1201

Browse files
committed
Copy working I2C implementation from reitermarkus' template
1 parent aee09af commit 71f1201

File tree

2 files changed

+117
-132
lines changed

2 files changed

+117
-132
lines changed

examples/ssd1306-i2c.rs

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use {
1212
dprintln, i2c,
1313
prelude::*,
1414
serial::{config::Config as SerialConfig, NoRx, NoTx, Serial},
15+
target,
1516
},
1617
ssd1306::{prelude::*, Builder},
1718
xtensa_lx6_rt::get_cycle_count,
@@ -43,27 +44,58 @@ fn main() -> ! {
4344
)
4445
.unwrap();
4546

46-
// set desired clock frequencies
47-
clkcntrl
48-
.set_cpu_frequencies(
49-
CPUSource::Xtal,
50-
CORE_HZ.Hz(),
51-
CPUSource::PLL,
52-
240.MHz(),
53-
CPUSource::PLL,
54-
80.MHz(),
55-
)
56-
.unwrap();
57-
5847
let (clkcntrl_config, mut watchdog) = clkcntrl.freeze().unwrap();
5948
watchdog.disable();
6049

6150
let pins = dp.GPIO.split();
6251

6352
let mut rst = pins.gpio16.into_push_pull_output();
53+
54+
//i2c_set_pin(0, 4, 15, true, true, i2c_mode_t::I2C_MODE_MASTER);
55+
let gpio = unsafe { &*target::GPIO::ptr() };
56+
let iomux = unsafe { &*target::IO_MUX::ptr() };
57+
6458
let sda = pins.gpio4.into_alternate_3();
6559
let scl = pins.gpio15.into_alternate_3();
6660

61+
// sda
62+
{
63+
// gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL);
64+
gpio.pin4.write(|w| unsafe { w.bits(1 << 4) });
65+
66+
// PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
67+
iomux.gpio4.modify(|_, w| unsafe { w.mcu_sel().bits(2) });
68+
69+
// gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
70+
iomux
71+
.gpio4
72+
.modify(|_, w| w.fun_ie().set_bit().mcu_oe().set_bit());
73+
74+
// gpio_set_pull_mode(sda_io_num, GPIO_PULLUP_ONLY);
75+
iomux
76+
.gpio4
77+
.modify(|_, w| w.fun_wpd().clear_bit().fun_wpu().set_bit());
78+
}
79+
80+
// scl
81+
{
82+
// gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL);
83+
gpio.pin15.write(|w| unsafe { w.bits(1 << 15) });
84+
85+
// PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
86+
iomux.mtdo.modify(|_, w| unsafe { w.mcu_sel().bits(2) });
87+
88+
// gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
89+
iomux
90+
.mtdo
91+
.modify(|_, w| w.fun_ie().set_bit().mcu_oe().set_bit());
92+
93+
// gpio_set_pull_mode(scl_io_num, GPIO_PULLUP_ONLY);
94+
iomux
95+
.mtdo
96+
.modify(|_, w| w.fun_wpd().clear_bit().fun_wpu().set_bit());
97+
}
98+
6799
let mut serial = Serial::uart0(
68100
dp.UART0,
69101
(NoTx, NoRx),
@@ -76,7 +108,19 @@ fn main() -> ! {
76108
writeln!(serial, "\n\n\nserial initialized").unwrap();
77109

78110
let mut disp: GraphicsMode<_> = {
79-
let i2c = i2c::I2C::new(dp.I2C0, i2c::Pins { sda, scl }, &mut dport);
111+
let i2c = i2c::I2C::new(
112+
dp.I2C0,
113+
i2c::PinConfig {
114+
pin_num: 4,
115+
pullup: true,
116+
},
117+
i2c::PinConfig {
118+
pin_num: 15,
119+
pullup: true,
120+
},
121+
400_000,
122+
&mut dport,
123+
);
80124
Builder::new().connect_i2c(i2c).into()
81125
};
82126
writeln!(serial, "display built").unwrap();

src/i2c.rs

Lines changed: 60 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
use {
2-
crate::{
3-
dprintln,
4-
target::{self, i2c, GPIO, I2C0, I2C1, IO_MUX},
5-
},
6-
core::{fmt::Write, ops::Deref},
7-
};
1+
use core::ops::Deref;
2+
3+
use crate::target::{self, i2c, I2C0, I2C1};
4+
5+
#[derive(Clone, Copy, Debug)]
6+
pub struct PinConfig {
7+
pub pin_num: u32,
8+
pub pullup: bool,
9+
}
810

911
unsafe fn gpio_matrix_out(gpio: u32, signal_idx: u32, out_inverted: bool, oen_inverted: bool) {
1012
let base_address = 0x3FF44530; // GPIO_FUNC0_OUT_SEL_CFG_REG
@@ -13,31 +15,31 @@ unsafe fn gpio_matrix_out(gpio: u32, signal_idx: u32, out_inverted: bool, oen_in
1315
let mut value = signal_idx;
1416

1517
if out_inverted {
16-
value = value | 0b100_0000_0000;
18+
value |= 1 << 9;
1719
}
1820

1921
if oen_inverted {
20-
value = value | 0b1_0000_0000_0000;
22+
value |= 1 << 11;
2123
}
2224

23-
*store_address = value;
25+
core::ptr::write_volatile(store_address, value);
2426
}
2527

2628
unsafe fn gpio_matrix_in(gpio: u32, signal_idx: u32, inverted: bool) {
2729
let base_address = 0x3FF44130; // GPIO_FUNC0_IN_SEL_CFG_REG
28-
let store_address = (base_address + 4 * gpio) as *mut u32;
30+
let store_address = (base_address + 4 * signal_idx) as *mut u32;
2931

30-
let mut value = signal_idx;
32+
let mut value = gpio;
3133

3234
if inverted {
33-
value = value | 64;
35+
value |= 1 << 6;
3436
}
3537

3638
if gpio != 52 {
37-
value = value | 128;
39+
value |= 1 << 7;
3840
}
3941

40-
*store_address = value;
42+
core::ptr::write_volatile(store_address, value);
4143
}
4244

4345
pub struct I2C<T>(T);
@@ -46,78 +48,35 @@ impl<T> I2C<T>
4648
where
4749
T: Instance,
4850
{
49-
pub fn new<SDA, SCL>(i2c: T, _pins: Pins<SDA, SCL>, dport: &mut target::DPORT) -> Self {
51+
pub fn new(
52+
i2c: T,
53+
sda: PinConfig,
54+
scl: PinConfig,
55+
clk_speed: u32,
56+
dport: &mut target::DPORT,
57+
) -> Self {
5058
let mut i2c = Self(i2c);
5159

52-
// i2c_set_pin
53-
// TEMPORARY UNTIL I CORRECTLY IMPLEMENT PINS
54-
// manually set sda to gpio4 and scl to gpio15
55-
unsafe {
56-
let gpio = &*GPIO::ptr();
57-
let iomux = &*IO_MUX::ptr();
58-
59-
// sda
60-
{
61-
// gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL);
62-
gpio.pin4.write(|w| w.bits(1 << 4));
63-
64-
// PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
65-
iomux.gpio4.modify(|_, w| w.mcu_sel().bits(2));
66-
67-
// gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
68-
iomux
69-
.gpio4
70-
.modify(|_, w| w.fun_ie().set_bit().mcu_oe().set_bit());
71-
72-
// gpio_set_pull_mode(sda_io_num, GPIO_PULLUP_ONLY);
73-
iomux
74-
.gpio4
75-
.modify(|_, w| w.fun_wpd().clear_bit().fun_wpu().set_bit());
76-
77-
// gpio_matrix_out(sda_io_num, sda_out_sig, 0, 0);
78-
gpio_matrix_out(4, 30, false, false);
79-
// gpio_matrix_in(sda_io_num, sda_in_sig, 0);
80-
gpio_matrix_in(4, 30, false);
81-
}
82-
83-
// scl
84-
{
85-
// gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL);
86-
gpio.pin15.write(|w| w.bits(1 << 15));
87-
88-
// PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
89-
iomux.mtdo.modify(|_, w| w.mcu_sel().bits(2));
60+
// i2c_config_t documentation says that clock speed must be no higher than 1 MHz
61+
assert!(clk_speed <= 1_000_000);
9062

91-
// gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD);
92-
iomux
93-
.mtdo
94-
.modify(|_, w| w.fun_ie().set_bit().mcu_oe().set_bit());
63+
// sda
64+
unsafe { gpio_matrix_out(sda.pin_num, 30, false, false) };
65+
unsafe { gpio_matrix_in(sda.pin_num, 30, false) };
9566

96-
// gpio_matrix_out(scl_io_num, scl_out_sig, 0, 0);
97-
gpio_matrix_out(15, 29, false, false);
67+
// scl
68+
unsafe { gpio_matrix_out(scl.pin_num, 29, false, false) };
69+
unsafe { gpio_matrix_in(scl.pin_num, 29, false) };
9870

99-
// gpio_matrix_in(scl_io_num, scl_in_sig, 0);
100-
gpio_matrix_in(15, 29, false);
101-
102-
// gpio_set_pull_mode(scl_io_num, GPIO_PULLUP_ONLY);
103-
iomux
104-
.mtdo
105-
.modify(|_, w| w.fun_wpd().clear_bit().fun_wpu().set_bit());
106-
}
107-
}
108-
109-
// i2c_hw_enable(i2c_num);
71+
// i2c_hw_enable
11072
i2c.reset(dport);
11173
i2c.enable(dport);
11274

113-
// i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), 0x3FFF);
114-
i2c.0.int_ena.write(|w| unsafe { w.bits(0) });
115-
// i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), 0x3FFF);
116-
i2c.0.int_clr.write(|w| unsafe { w.bits(0x3FFF) });
75+
// i2c_hal_disable_intr_mask
76+
i2c.0.int_ena.modify(|_, w| unsafe { w.bits(0) });
77+
// i2c_hal_clr_intsts_mask
78+
i2c.0.int_clr.modify(|_, w| unsafe { w.bits(0x3FFF) });
11779

118-
//i2c_ll_master_init(hal->dev);
119-
//MSB
120-
//i2c_ll_set_data_mode(hal->dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST);
12180
i2c.0.ctr.modify(|_, w| unsafe {
12281
w.bits(0)
12382
.ms_mode()
@@ -132,14 +91,11 @@ where
13291
.clear_bit()
13392
});
13493

135-
//i2c_ll_set_fifo_mode(hal->dev, true);
136-
i2c.0.fifo_conf.modify(|_, w| w.nonfifo_en().clear_bit());
137-
13894
i2c.reset_fifo();
13995

14096
i2c.set_filter(Some(7), Some(7));
14197

142-
i2c.set_frequency(200_000);
98+
i2c.set_frequency(clk_speed);
14399

144100
i2c.0.ctr.modify(|_, w| w.clk_en().set_bit());
145101

@@ -170,8 +126,6 @@ where
170126

171127
/// Sets the filter with a supplied threshold in clock cycles for which a pulse must be present to pass the filter
172128
fn set_filter(&mut self, sda_threshold: Option<u8>, scl_threshold: Option<u8>) {
173-
// i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 7);
174-
175129
match sda_threshold {
176130
Some(threshold) => {
177131
self.0
@@ -239,65 +193,61 @@ where
239193
}
240194
}
241195

196+
/// Write `bytes` to an I2C device at address `addr`
242197
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
243-
dprintln!("addr: {:?}, bytes: {:?}", addr, &bytes);
244-
245-
// TODO: Use bytes.chunk(255) to remove this limitation
246-
assert!(bytes.len() < 255);
198+
//TODO: Confirm this hardware limit
199+
if bytes.len() > 254 {
200+
return Err(Error::Transmit);
201+
}
247202

248203
// Address for I2C0 (obviously this shouldn't make it into the HAL)
249204
let fifo_addr = 0x6001301c as *mut u8;
250205

251-
// Clear FIFO
252-
self.0.fifo_conf.modify(|_, w| w.tx_fifo_rst().set_bit());
253-
self.0.fifo_conf.modify(|_, w| w.tx_fifo_rst().clear_bit());
254-
self.0.fifo_conf.modify(|_, w| w.rx_fifo_rst().set_bit());
255-
self.0.fifo_conf.modify(|_, w| w.rx_fifo_rst().clear_bit());
206+
// Reset FIFO
207+
self.reset_fifo();
256208

257209
// RSTART command
258210
self.0.comd0.write(|w| unsafe { w.command0().bits(0) });
259211

260-
// Address byte
212+
// Load data into hardware FIFO buffer
261213
unsafe {
262-
*(fifo_addr) = addr << 1 | 0;
263-
}
264-
// Data bytes
265-
for byte in bytes {
266-
unsafe {
267-
*(fifo_addr) = *byte;
214+
// Address byte
215+
*fifo_addr = addr << 1 | 0;
216+
217+
// Data bytes
218+
for byte in bytes {
219+
*fifo_addr = *byte;
268220
}
269221
}
270222

271223
// WRITE command
272-
self.0.comd1.write(|w| unsafe {
273-
w.command1()
274-
.bits(0b00_1100_0000_0000 | (1 + bytes.len() as u8) as u16)
275-
});
224+
let length = (1 + bytes.len() as u8) as u16;
225+
self.0
226+
.comd1
227+
.write(|w| unsafe { w.command1().bits(0b00_1100_0000_0000 | length) });
276228

277229
// STOP command
278230
self.0
279231
.comd2
280232
.write(|w| unsafe { w.command2().bits(0b01_1000_0000_0000) });
281233

282-
dprintln!("txfifo_cnt: {:?}", self.0.sr.read().txfifo_cnt().bits());
283-
284234
// Start transmission
285235
self.0.ctr.modify(|_, w| w.trans_start().set_bit());
286236

237+
// Wait for commands to complete
287238
while self.0.comd0.read().command0_done().bit() != true {}
288-
dprintln!("start");
289239
while self.0.comd1.read().command1_done().bit() != true {}
290-
dprintln!("write");
291240
while self.0.comd2.read().command2_done().bit() != true {}
292-
dprintln!("stop");
293241

294242
Ok(())
295243
}
296244

297-
pub fn read(&mut self, _addr: u8, _bytes: &mut [u8]) -> Result<(), Error> {
245+
/// Read into `buffer` from an I2C device at address `addr`
246+
pub fn read(&mut self, _addr: u8, _buffer: &mut [u8]) -> Result<(), Error> {
298247
unimplemented!()
299248
}
300249

250+
/// Write `bytes` to an I2C device at address `addr` whilst reading received data into `buffer` without triggering a STOP condition
301251
pub fn write_then_read(
302252
&mut self,
303253
_addr: u8,
@@ -353,15 +303,6 @@ where
353303
}
354304
}
355305

356-
/// Pins used by the I2C interface
357-
///
358-
/// Note that any two pins may be used
359-
/// TODO: enforce this in the type system
360-
pub struct Pins<SDA, SCL> {
361-
pub sda: SDA,
362-
pub scl: SCL,
363-
}
364-
365306
#[derive(Debug)]
366307
pub enum Error {
367308
Transmit,

0 commit comments

Comments
 (0)