Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
F
f4
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
Model registry
Operate
Environments
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
Per Lindgren
f4
Commits
1ce91397
Commit
1ce91397
authored
7 years ago
by
Johannes Sjölund
Browse files
Options
Downloads
Patches
Plain Diff
SPI support, add LSM9DS1 example
parent
127ae7b5
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
examples/spi1.rs
+132
-0
132 additions, 0 deletions
examples/spi1.rs
src/lib.rs
+2
-0
2 additions, 0 deletions
src/lib.rs
src/spi.rs
+301
-0
301 additions, 0 deletions
src/spi.rs
with
435 additions
and
0 deletions
examples/spi1.rs
0 → 100644
+
132
−
0
View file @
1ce91397
//! Interfacing the LSM9DS1 3D accelerometer, gyroscope, and magnetometer
//! using SPI3.
//!
//! Using the SparkFun LSM9DS1 breakout board, connect:
//! PA_8 -> CS_AG (Chip Select for accelerometer/gyro)
//! PA_9 -> CS_M (Chip Select for magnetometer)
//! PB_3 -> SCL (SPI clock)
//! PB_4 -> SDO_M and SDO_AG (Combined SPI MISO)
//! PB_5 -> SDA (SPI MOSI)
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
extern
crate
cortex_m
;
extern
crate
cortex_m_rtfm
as
rtfm
;
extern
crate
f4
;
extern
crate
stm32f40x
;
use
f4
::
Spi
;
use
f4
::
prelude
::
*
;
use
rtfm
::{
app
,
Threshold
};
use
stm32f40x
::
GPIOA
;
app!
{
device
:
f4
::
stm32f40x
,
idle
:
{
resources
:
[
SPI3
,
GPIOA
],
},
}
fn
init
(
p
:
init
::
Peripherals
)
{
// Setup CS pins
{
// Power on GPIOA
p
.RCC.ahb1enr
.modify
(|
_
,
w
|
w
.gpioaen
()
.set_bit
());
// Set PA_8 and PA_9 as outputs
p
.GPIOA
.moder
.modify
(|
_
,
w
|
w
.moder8
()
.bits
(
1
)
.moder9
()
.bits
(
1
));
// Use pull-ups
p
.GPIOA
.pupdr
.modify
(|
_
,
w
|
unsafe
{
w
.pupdr8
()
.bits
(
1
)
.pupdr9
()
.bits
(
1
)
});
// Highest output speed
p
.GPIOA
.ospeedr
.modify
(|
_
,
w
|
w
.ospeedr8
()
.bits
(
3
)
.ospeedr9
()
.bits
(
3
));
// Default to high (CS disabled)
p
.GPIOA
.odr
.modify
(|
_
,
w
|
w
.odr8
()
.bit
(
true
)
.odr9
()
.bit
(
true
));
}
// Init the SPI peripheral
let
spi
=
Spi
(
p
.SPI3
);
spi
.init
(
p
.GPIOA
,
p
.GPIOB
,
p
.RCC
);
// For the LSM9DS1, the second clock transition is
// the first data capture edge
// RM0368 20.5.1
p
.SPI3.cr1
.modify
(|
_
,
w
|
w
.cpha
()
.set_bit
());
}
fn
enable_m
(
gpioa
:
&
mut
GPIOA
)
{
gpioa
.odr
.modify
(|
_
,
w
|
w
.odr9
()
.bit
(
false
));
}
fn
disable_m
(
gpioa
:
&
mut
GPIOA
)
{
gpioa
.odr
.modify
(|
_
,
w
|
w
.odr9
()
.bit
(
true
));
}
fn
enable_ag
(
gpioa
:
&
mut
GPIOA
)
{
gpioa
.odr
.modify
(|
_
,
w
|
w
.odr8
()
.bit
(
false
));
}
fn
disable_ag
(
gpioa
:
&
mut
GPIOA
)
{
gpioa
.odr
.modify
(|
_
,
w
|
w
.odr8
()
.bit
(
true
));
}
fn
send_receive
(
spi
:
&
f4
::
Spi
<
f4
::
stm32f40x
::
SPI3
>
,
addr
:
u8
)
->
u8
{
// Send and receive using the hal crate
while
spi
.send
(
addr
)
.is_err
()
{}
loop
{
if
let
Ok
(
_
)
=
spi
.read
()
{
break
;
}
}
while
spi
.send
(
0
)
.is_err
()
{}
loop
{
if
let
Ok
(
byte
)
=
spi
.read
()
{
break
byte
;
}
}
}
fn
to_read_address
(
sub_address
:
u8
)
->
u8
{
0x80
|
(
sub_address
&
0x3F
)
}
fn
idle
(
_t
:
&
mut
Threshold
,
r
:
idle
::
Resources
)
->
!
{
// Registers to read
const
WHO_AM_I_AG
:
u8
=
0x0F
;
const
WHO_AM_I_M
:
u8
=
0x0F
;
// Expected answers
const
ANS_AG
:
u8
=
0x68
;
const
ANS_M
:
u8
=
0x3D
;
let
spi
=
Spi
(
&*
r
.SPI3
);
spi
.enable
();
// Read accelerometer/gyro identity
enable_ag
(
r
.GPIOA
);
let
ans_ag
=
send_receive
(
&
spi
,
to_read_address
(
WHO_AM_I_AG
));
disable_ag
(
r
.GPIOA
);
// Read magnetometer identity
enable_m
(
r
.GPIOA
);
let
ans_m
=
send_receive
(
&
spi
,
to_read_address
(
WHO_AM_I_M
));
disable_m
(
r
.GPIOA
);
spi
.disable
();
// Program will panic if these are incorrect
assert_eq!
(
ans_ag
,
ANS_AG
);
assert_eq!
(
ans_m
,
ANS_M
);
loop
{
rtfm
::
wfi
();
}
}
This diff is collapsed.
Click to expand it.
src/lib.rs
+
2
−
0
View file @
1ce91397
...
@@ -44,6 +44,7 @@ pub mod time;
...
@@ -44,6 +44,7 @@ pub mod time;
pub
mod
pwm
;
pub
mod
pwm
;
pub
mod
capture
;
pub
mod
capture
;
pub
mod
clock
;
pub
mod
clock
;
pub
mod
spi
;
pub
mod
frequency
;
pub
mod
frequency
;
use
frequency
::
*
;
use
frequency
::
*
;
...
@@ -54,6 +55,7 @@ pub use serial::U8Writer;
...
@@ -54,6 +55,7 @@ pub use serial::U8Writer;
pub
use
timer
::{
Channel
,
Timer
};
pub
use
timer
::{
Channel
,
Timer
};
pub
use
pwm
::
Pwm
;
pub
use
pwm
::
Pwm
;
pub
use
capture
::
Capture
;
pub
use
capture
::
Capture
;
pub
use
spi
::
Spi
;
/// println over semihosting
/// println over semihosting
#[macro_export]
#[macro_export]
...
...
This diff is collapsed.
Click to expand it.
src/spi.rs
0 → 100644
+
301
−
0
View file @
1ce91397
//! Serial Peripheral Interface
//!
//! You can use the `Spi` interface with these SPI instances
//!
//! # SPI1
//!
//! - NSS = PA4
//! - SCK = PA5
//! - MISO = PA6
//! - MOSI = PA7
//!
//! # SPI2
//!
//! - NSS = PB12
//! - SCK = PB13
//! - MISO = PB14
//! - MOSI = PB15
//!
//! # SPI3
//!
//! - NSS = PA15
//! - SCK = PB3
//! - MISO = PB4
//! - MOSI = PB5
//!
use
core
::
any
::{
Any
,
TypeId
};
use
core
::
ptr
;
use
hal
;
use
nb
;
use
stm32f40x
::{
SPI1
,
SPI2
,
SPI3
,
GPIOA
,
GPIOB
,
RCC
};
/// SPI result
pub
type
Result
<
T
>
=
::
core
::
result
::
Result
<
T
,
nb
::
Error
<
Error
>>
;
/// SPI error
#[derive(Debug)]
pub
enum
Error
{
/// Overrun occurred
Overrun
,
/// Mode fault occurred
ModeFault
,
/// CRC error
Crc
,
#[doc(hidden)]
_Extensible
,
}
/// Serial Peripheral Interface
pub
struct
Spi
<
'a
,
T
>
(
pub
&
'a
T
)
where
T
:
'a
;
/// Serial Peripheral Interface
macro_rules!
impl_Spi
{
(
$S:ident
)
=>
{
impl
<
'a
>
Spi
<
'a
,
$S
>
{
/// Initializes the SPI
pub
fn
init
(
&
self
,
gpioa
:
&
GPIOA
,
// TODO: Make these optional/implement custom init for each SPI
gpiob
:
&
GPIOB
,
rcc
:
&
RCC
)
{
let
spi
=
self
.0
;
if
spi
.get_type_id
()
==
TypeId
::
of
::
<
SPI1
>
()
{
// enable SPI1, GPIOA
rcc
.apb2enr
.modify
(|
_
,
w
|
{
w
.spi1en
()
.set_bit
()
});
rcc
.ahb1enr
.modify
(|
_
,
w
|
{
w
.gpioaen
()
.set_bit
()
});
// NSS = PA4 = Alternate function push pull
// SCK = PA5 = Alternate function push pull
// MISO = PA6 = Alternate function open drain
// MOSI = PA7 = Alternate function push pull
// DM00102166 - Alternate function AF5, Table 9
gpioa
.afrl
.modify
(|
_
,
w
|
w
.afrl4
()
.bits
(
5
)
.afrl5
()
.bits
(
5
)
.afrl6
()
.bits
(
5
)
.afrl7
()
.bits
(
5
));
// RM0368 8.3 Table 23
// Highest output speed
gpioa
.ospeedr
.modify
(|
_
,
w
|
w
.ospeedr4
()
.bits
(
0b11
)
.ospeedr5
()
.bits
(
0b11
)
.ospeedr6
()
.bits
(
0b11
)
.ospeedr7
()
.bits
(
0b11
));
// Alternate function mode
gpioa
.moder
.modify
(|
_
,
w
|
w
.moder4
()
.bits
(
2
)
.moder5
()
.bits
(
2
)
.moder6
()
.bits
(
2
)
.moder7
()
.bits
(
2
));
// Push pull, MISO open drain
gpioa
.otyper
.modify
(|
_
,
w
|
w
.ot4
()
.clear_bit
()
.ot5
()
.clear_bit
()
.ot6
()
.set_bit
()
.ot7
()
.clear_bit
()
);
// No pull up/down except MISO
gpioa
.pupdr
.modify
(|
_
,
w
|
unsafe
{
w
.pupdr4
()
.bits
(
0
)
.pupdr5
()
.bits
(
0
)
.pupdr6
()
.bits
(
1
)
.pupdr7
()
.bits
(
0
)
});
}
else
if
spi
.get_type_id
()
==
TypeId
::
of
::
<
SPI2
>
()
{
// enable SPI2, GPIOB
rcc
.apb1enr
.modify
(|
_
,
w
|
{
w
.spi2en
()
.set_bit
()
});
rcc
.ahb1enr
.modify
(|
_
,
w
|
{
w
.gpioben
()
.set_bit
()
});
// NSS = PB12 = Alternate function push pull
// SCK = PB13 = Alternate function push pull
// MISO = PB14 = Alternate function open drain
// MOSI = PB15 = Alternate function push pull
// DM00102166 - Alternate function AF5, Table 9
gpiob
.afrh
.modify
(|
_
,
w
|
unsafe
{
w
.afrh12
()
.bits
(
5
)
.afrh13
()
.bits
(
5
)
.afrh14
()
.bits
(
5
)
.afrh15
()
.bits
(
5
)
});
// RM0368 8.3 Table 23
// Highest output speed
gpiob
.ospeedr
.modify
(|
_
,
w
|
unsafe
{
w
.ospeedr12
()
.bits
(
0b11
)
.ospeedr13
()
.bits
(
0b11
)
.ospeedr14
()
.bits
(
0b11
)
.ospeedr15
()
.bits
(
0b11
)
});
// Alternate function mode
gpiob
.moder
.modify
(|
_
,
w
|
unsafe
{
w
.moder12
()
.bits
(
2
)
.moder13
()
.bits
(
2
)
.moder14
()
.bits
(
2
)
.moder15
()
.bits
(
2
)
});
// Push pull, MISO open drain
gpiob
.otyper
.modify
(|
_
,
w
|
w
.ot12
()
.clear_bit
()
.ot13
()
.clear_bit
()
.ot14
()
.set_bit
()
.ot15
()
.clear_bit
()
);
// No pull up/down except MISO
gpiob
.pupdr
.modify
(|
_
,
w
|
unsafe
{
w
.pupdr12
()
.bits
(
0
)
.pupdr13
()
.bits
(
0
)
.pupdr14
()
.bits
(
1
)
.pupdr15
()
.bits
(
0
)
});
}
else
if
spi
.get_type_id
()
==
TypeId
::
of
::
<
SPI3
>
()
{
// enable SPI3, GPIOA/B
rcc
.apb1enr
.modify
(|
_
,
w
|
{
w
.spi3en
()
.set_bit
()
});
rcc
.ahb1enr
.modify
(|
_
,
w
|
{
w
.gpioaen
()
.set_bit
()
});
rcc
.ahb1enr
.modify
(|
_
,
w
|
{
w
.gpioben
()
.set_bit
()
});
// NSS = PA15 = Alternate function push pull
// SCK = PB3 = Alternate function push pull
// MISO = PB4 = Alternate function open drain
// MOSI = PB5 = Alternate function push pull
// DM00102166 - Alternate function AF6, Table 9
gpioa
.afrh
.modify
(|
_
,
w
|
w
.afrh15
()
.bits
(
5
));
gpiob
.afrl
.modify
(|
_
,
w
|
unsafe
{
w
.afrl3
()
.bits
(
6
)
.afrl4
()
.bits
(
6
)
.afrl5
()
.bits
(
6
)
});
// RM0368 8.3 Table 23
// Highest output speed
gpioa
.ospeedr
.modify
(|
_
,
w
|
w
.ospeedr15
()
.bits
(
0b11
));
gpiob
.ospeedr
.modify
(|
_
,
w
|
unsafe
{
w
.ospeedr3
()
.bits
(
0b11
)
.ospeedr4
()
.bits
(
0b11
)
.ospeedr5
()
.bits
(
0b11
)
});
// Alternate function mode
gpioa
.moder
.modify
(|
_
,
w
|
w
.moder15
()
.bits
(
2
));
gpiob
.moder
.modify
(|
_
,
w
|
unsafe
{
w
.moder3
()
.bits
(
2
)
.moder4
()
.bits
(
2
)
.moder5
()
.bits
(
2
)
});
// Push pull, MISO open drain
gpioa
.otyper
.modify
(|
_
,
w
|
w
.ot15
()
.clear_bit
());
gpiob
.otyper
.modify
(|
_
,
w
|
w
.ot3
()
.clear_bit
()
.ot4
()
.set_bit
()
.ot5
()
.clear_bit
());
// No pull up/down except MISO
gpioa
.pupdr
.modify
(|
_
,
w
|
unsafe
{
w
.pupdr15
()
.bits
(
0
)});
gpiob
.pupdr
.modify
(|
_
,
w
|
unsafe
{
w
.pupdr3
()
.bits
(
0
)
.pupdr4
()
.bits
(
1
)
.pupdr5
()
.bits
(
0
)
});
}
// enable SS output
spi
.cr2
.write
(|
w
|
w
.ssoe
()
.set_bit
());
// RM0368 20.5.1 SPI control register 1
spi
.cr1
.write
(|
w
|
unsafe
{
w
.br
()
.bits
(
0b100
)
// CLK / 32 prescaler
.ssi
()
.set_bit
()
// NSS
.ssm
()
.set_bit
()
// Software chip select
.mstr
()
.set_bit
()
// Master SPI mode
.cpol
()
.set_bit
()
// CK to 1 when idle
.lsbfirst
()
.clear_bit
()
// MSB first
.dff
()
.clear_bit
()
// 8 bit frames
.bidimode
()
.clear_bit
()
// 2-line unidirectional mode
});
}
/// Disables the SPI bus
///
/// **NOTE** This drives the NSS pin high
pub
fn
disable
(
&
self
)
{
self
.0
.cr1
.modify
(|
_
,
w
|
w
.spe
()
.clear_bit
())
}
/// Enables the SPI bus
///
/// **NOTE** This drives the NSS pin low
pub
fn
enable
(
&
self
)
{
self
.0
.cr1
.modify
(|
_
,
w
|
w
.spe
()
.set_bit
())
}
}
impl
<
'a
>
hal
::
Spi
<
u8
>
for
Spi
<
'a
,
$S
>
{
type
Error
=
Error
;
fn
read
(
&
self
)
->
Result
<
u8
>
{
let
spi1
=
self
.0
;
let
sr
=
spi1
.sr
.read
();
if
sr
.ovr
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
Overrun
))
}
else
if
sr
.modf
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
ModeFault
))
}
else
if
sr
.crcerr
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
Crc
))
}
else
if
sr
.rxne
()
.bit_is_set
()
{
Ok
(
unsafe
{
ptr
::
read_volatile
(
&
spi1
.dr
as
*
const
_
as
*
const
u8
)
})
}
else
{
Err
(
nb
::
Error
::
WouldBlock
)
}
}
fn
send
(
&
self
,
byte
:
u8
)
->
Result
<
()
>
{
let
spi1
=
self
.0
;
let
sr
=
spi1
.sr
.read
();
if
sr
.ovr
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
Overrun
))
}
else
if
sr
.modf
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
ModeFault
))
}
else
if
sr
.crcerr
()
.bit_is_set
()
{
Err
(
nb
::
Error
::
Other
(
Error
::
Crc
))
}
else
if
sr
.txe
()
.bit_is_set
()
{
// NOTE(write_volatile) see note above
unsafe
{
ptr
::
write_volatile
(
&
spi1
.dr
as
*
const
_
as
*
mut
u8
,
byte
)
}
Ok
(())
}
else
{
Err
(
nb
::
Error
::
WouldBlock
)
}
}
}
}
}
impl_Spi!
(
SPI1
);
impl_Spi!
(
SPI2
);
impl_Spi!
(
SPI3
);
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