Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
A
app
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
app
Commits
0deaa01f
Commit
0deaa01f
authored
6 years ago
by
Per Lindgren
Browse files
Options
Downloads
Patches
Plain Diff
bare4 and bare5
parent
acf1041f
No related branches found
No related tags found
No related merge requests found
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
.vscode/launch.json
+50
-2
50 additions, 2 deletions
.vscode/launch.json
.vscode/tasks.json
+36
-0
36 additions, 0 deletions
.vscode/tasks.json
examples/bare4.rs
+131
-0
131 additions, 0 deletions
examples/bare4.rs
examples/bare5.rs
+235
-0
235 additions, 0 deletions
examples/bare5.rs
with
452 additions
and
2 deletions
.vscode/launch.json
+
50
−
2
View file @
0deaa01f
...
@@ -288,7 +288,7 @@
...
@@ -288,7 +288,7 @@
"type"
:
"cortex-debug"
,
"type"
:
"cortex-debug"
,
"request"
:
"launch"
,
"request"
:
"launch"
,
"servertype"
:
"openocd"
,
"servertype"
:
"openocd"
,
"name"
:
"bare3 (d
u
bug)"
,
"name"
:
"bare3 (d
e
bug)"
,
"preLaunchTask"
:
"cargo build --example bare3"
,
"preLaunchTask"
:
"cargo build --example bare3"
,
"executable"
:
"./target/thumbv7em-none-eabihf/debug/examples/bare3"
,
"executable"
:
"./target/thumbv7em-none-eabihf/debug/examples/bare3"
,
"postLaunchCommands"
:
[
"postLaunchCommands"
:
[
...
@@ -300,6 +300,54 @@
...
@@ -300,6 +300,54 @@
],
],
"cwd"
:
"${workspaceRoot}"
"cwd"
:
"${workspaceRoot}"
},
},
{
"type"
:
"cortex-debug"
,
"request"
:
"launch"
,
"servertype"
:
"openocd"
,
"name"
:
"bare4 (debug)"
,
"preLaunchTask"
:
"cargo build --example bare4"
,
"executable"
:
"./target/thumbv7em-none-eabihf/debug/examples/bare4"
,
"postLaunchCommands"
:
[
"monitor arm semihosting enable"
],
"configFiles"
:
[
"interface/stlink.cfg"
,
"target/stm32f4x.cfg"
],
"cwd"
:
"${workspaceRoot}"
},
{
"type"
:
"cortex-debug"
,
"request"
:
"launch"
,
"servertype"
:
"openocd"
,
"name"
:
"bare5 (debug)"
,
"preLaunchTask"
:
"cargo build --example bare5"
,
"executable"
:
"./target/thumbv7em-none-eabihf/debug/examples/bare5"
,
"postLaunchCommands"
:
[
"monitor arm semihosting enable"
],
"configFiles"
:
[
"interface/stlink.cfg"
,
"target/stm32f4x.cfg"
],
"cwd"
:
"${workspaceRoot}"
},
{
"type"
:
"cortex-debug"
,
"request"
:
"launch"
,
"servertype"
:
"openocd"
,
"name"
:
"bare5 (release)"
,
"preLaunchTask"
:
"cargo build --example bare5 --release"
,
"executable"
:
"./target/thumbv7em-none-eabihf/release/examples/bare5"
,
"postLaunchCommands"
:
[
"monitor arm semihosting enable"
],
"configFiles"
:
[
"interface/stlink.cfg"
,
"target/stm32f4x.cfg"
],
"cwd"
:
"${workspaceRoot}"
},
{
{
"type"
:
"cortex-debug"
,
"type"
:
"cortex-debug"
,
"request"
:
"launch"
,
"request"
:
"launch"
,
...
@@ -377,6 +425,6 @@
...
@@ -377,6 +425,6 @@
]
]
},
},
"cwd"
:
"${workspaceRoot}"
"cwd"
:
"${workspaceRoot}"
}
}
,
]
]
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
.vscode/tasks.json
+
36
−
0
View file @
0deaa01f
...
@@ -147,5 +147,41 @@
...
@@ -147,5 +147,41 @@
"isDefault"
:
true
"isDefault"
:
true
}
}
},
},
{
"type"
:
"shell"
,
"label"
:
"cargo build --example bare4"
,
"command"
:
"cargo build --example bare4"
,
"problemMatcher"
:
[
"$rustc"
],
"group"
:
{
"kind"
:
"build"
,
"isDefault"
:
true
}
},
{
"type"
:
"shell"
,
"label"
:
"cargo build --example bare5"
,
"command"
:
"cargo build --example bare5"
,
"problemMatcher"
:
[
"$rustc"
],
"group"
:
{
"kind"
:
"build"
,
"isDefault"
:
true
}
},
{
"type"
:
"shell"
,
"label"
:
"cargo build --example bare5 --release"
,
"command"
:
"cargo build --example bare5 --release"
,
"problemMatcher"
:
[
"$rustc"
],
"group"
:
{
"kind"
:
"build"
,
"isDefault"
:
true
}
},
]
]
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
examples/bare4.rs
0 → 100644
+
131
−
0
View file @
0deaa01f
//! bare4.rs
//!
//! Access to Peripherals
//!
//! What it covers:
//! - raw pointers
//! - volatile read/write
//! - busses and clocking
//! - gpio
#![feature(uniform_paths)]
// requires nightly
#![no_std]
#![no_main]
extern
crate
panic_halt
;
extern
crate
cortex_m
;
use
cortex_m_rt
::
entry
;
// Peripheral addresses as constants
#[rustfmt::skip]
mod
address
{
pub
const
PERIPH_BASE
:
u32
=
0x40000000
;
pub
const
AHB1PERIPH_BASE
:
u32
=
PERIPH_BASE
+
0x00020000
;
pub
const
RCC_BASE
:
u32
=
AHB1PERIPH_BASE
+
0x3800
;
pub
const
RCC_AHB1ENR
:
u32
=
RCC_BASE
+
0x30
;
pub
const
GBPIA_BASE
:
u32
=
AHB1PERIPH_BASE
+
0x0000
;
pub
const
GPIOA_MODER
:
u32
=
GBPIA_BASE
+
0x00
;
pub
const
GPIOA_BSRR
:
u32
=
GBPIA_BASE
+
0x18
;
}
use
address
::
*
;
// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf)
// rcc, chapter 6
// gpio, chapter 8
#[inline(always)]
fn
read_u32
(
addr
:
u32
)
->
u32
{
unsafe
{
core
::
ptr
::
read_volatile
(
addr
as
*
const
_
)
}
//core::ptr::read_volatile(addr as *const _)
}
#[inline(always)]
fn
write_u32
(
addr
:
u32
,
val
:
u32
)
{
unsafe
{
core
::
ptr
::
write_volatile
(
addr
as
*
mut
_
,
val
);
}
}
fn
wait
(
i
:
u32
)
{
for
_
in
0
..
i
{
cortex_m
::
asm
::
nop
();
// no operation (cannot be optimized out)
}
}
#[entry]
fn
main
()
->
!
{
// power on GPIOA
let
r
=
read_u32
(
RCC_AHB1ENR
);
// read
write_u32
(
RCC_AHB1ENR
,
r
|
1
);
// set enable
// configure PA5 as output
let
r
=
read_u32
(
GPIOA_MODER
)
&
!
(
0b11
<<
(
5
*
2
));
// read and mask
write_u32
(
GPIOA_MODER
,
r
|
0b01
<<
(
5
*
2
));
// set output mode
// and alter the data output through the BSRR register
// this is more efficient as the read register is not needed.
loop
{
// set PA5 high
write_u32
(
GPIOA_BSRR
,
1
<<
5
);
// set bit, output hight (turn on led)
wait
(
10_000
);
// set PA5 low
write_u32
(
GPIOA_BSRR
,
1
<<
(
5
+
16
));
// clear bit, output low (turn off led)
wait
(
10_000
);
}
}
// 1. Build and run the application (debug build).
// Did you enjoy the blinking?
//
// ** your answer here **
//
// Now lookup the data-sheets, and read each section referred,
// 6.3.11, 8.4.1, 8.4.7
//
// Document each low level access *code* by the appropriate section in the
// data sheet
//
// commit your answers (bare4_1)
//
// 2. comment out line 40 and uncomment line 41 (essentially omitting the `unsafe`)
//
// //unsafe { core::ptr::read_volatile(addr as *const _) }
// core::ptr::read_volatile(addr as *const _)
//
// What was the error message and explain why.
//
// ** your answer here **
//
// Digging a bit deeper, why do you think `read_volatile` is declared `unsafe`.
// (https://doc.rust-lang.org/core/ptr/fn.read_volatile.html, for some food for thought )
//
// ** your answer here **
//
// commit your answers (bare4_2)
//
// 3. Volatile read/writes are explicit *volatile operations* in Rust, while in C they
// are declared at type level (i.e., access to varibles declared volatile amounts to
// volatile reads/and writes).
//
// Both C and Rust (even more) allows code optimization to re-order operations, as long
// as data dependencies are preserved.
//
// Why is it important that ordering of volatile operations are ensured by the compiler?
//
// ** your answer here **
//
// Give an example in the above code, where reordering might make things go horribly wrong
// (hint, accessing a peripheral not being powered...)
//
// ** your answer here **
//
// Without the non-reording proprety of `write_volatile/read_volatile` could that happen in theory
// (argue from the point of data dependencies).
//
// ** your answer here **
//
// commit your answers (bare4_3)
This diff is collapsed.
Click to expand it.
examples/bare5.rs
0 → 100644
+
235
−
0
View file @
0deaa01f
//! bare5.rs
//!
//! C Like Peripheral API
//!
//! What it covers:
//! - abstractions in Rust
//!
#![feature(uniform_paths)]
// requires nightly
#![no_std]
#![no_main]
extern
crate
panic_halt
;
extern
crate
cortex_m
;
use
cortex_m_rt
::
entry
;
// C like API...
mod
stm32f40x
{
#[allow(dead_code)]
use
core
::{
cell
,
ptr
};
#[rustfmt::skip]
mod
address
{
pub
const
PERIPH_BASE
:
u32
=
0x40000000
;
pub
const
AHB1PERIPH_BASE
:
u32
=
PERIPH_BASE
+
0x00020000
;
pub
const
RCC_BASE
:
u32
=
AHB1PERIPH_BASE
+
0x3800
;
pub
const
GPIOA_BASE
:
u32
=
AHB1PERIPH_BASE
+
0x0000
;
}
use
address
::
*
;
pub
struct
VolatileCell
<
T
>
{
value
:
cell
::
UnsafeCell
<
T
>
,
}
impl
<
T
>
VolatileCell
<
T
>
{
#[inline(always)]
pub
fn
read
(
&
self
)
->
T
where
T
:
Copy
,
{
unsafe
{
ptr
::
read_volatile
(
self
.value
.get
())
}
}
#[inline(always)]
pub
fn
write
(
&
self
,
value
:
T
)
where
T
:
Copy
,
{
unsafe
{
ptr
::
write_volatile
(
self
.value
.get
(),
value
)
}
}
}
// impl VolatileCell<u32> {
// #[inline(always)]
// pub fn modify(&self, offset: u8, width: u8, value: u32) {
// // your code here
// }
// }
#[repr(C)]
#[allow(non_snake_case)]
#[rustfmt::skip]
pub
struct
RCC
{
pub
CR
:
VolatileCell
<
u32
>
,
// < RCC clock control register, Address offset: 0x00
pub
PLLCFGR
:
VolatileCell
<
u32
>
,
// < RCC PLL configuration register, Address offset: 0x04
pub
CFGR
:
VolatileCell
<
u32
>
,
// < RCC clock configuration register, Address offset: 0x08
pub
CIR
:
VolatileCell
<
u32
>
,
// < RCC clock interrupt register, Address offset: 0x0C
pub
AHB1RSTR
:
VolatileCell
<
u32
>
,
// < RCC AHB1 peripheral reset register, Address offset: 0x10
pub
AHB2RSTR
:
VolatileCell
<
u32
>
,
// < RCC AHB2 peripheral reset register, Address offset: 0x14
pub
AHB3RSTR
:
VolatileCell
<
u32
>
,
// < RCC AHB3 peripheral reset register, Address offset: 0x18
pub
RESERVED0
:
VolatileCell
<
u32
>
,
// < Reserved, 0x1C
pub
APB1RSTR
:
VolatileCell
<
u32
>
,
// < RCC APB1 peripheral reset register, Address offset: 0x20
pub
APB2RSTR
:
VolatileCell
<
u32
>
,
// < RCC APB2 peripheral reset register, Address offset: 0x24
pub
RESERVED1
:
[
VolatileCell
<
u32
>
;
2
],
// < Reserved, 0x28-0x2C
pub
AHB1ENR
:
VolatileCell
<
u32
>
,
// < RCC AHB1 peripheral clock register, Address offset: 0x30
pub
AHB2ENR
:
VolatileCell
<
u32
>
,
// < RCC AHB2 peripheral clock register, Address offset: 0x34
pub
AHB3ENR
:
VolatileCell
<
u32
>
,
// < RCC AHB3 peripheral clock register, Address offset: 0x38
pub
RESERVED2
:
VolatileCell
<
u32
>
,
// < Reserved, 0x3C
pub
APB1ENR
:
VolatileCell
<
u32
>
,
// < RCC APB1 peripheral clock enable register, Address offset: 0x40
pub
APB2ENR
:
VolatileCell
<
u32
>
,
// < RCC APB2 peripheral clock enable register, Address offset: 0x44
pub
RESERVED3
:
[
VolatileCell
<
u32
>
;
2
],
// < Reserved, 0x48-0x4C
pub
AHB1LPENR
:
VolatileCell
<
u32
>
,
// < RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50
pub
AHB2LPENR
:
VolatileCell
<
u32
>
,
// < RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54
pub
AHB3LPENR
:
VolatileCell
<
u32
>
,
// < RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58
pub
RESERVED4
:
VolatileCell
<
u32
>
,
// < Reserved, 0x5C
pub
APB1LPENR
:
VolatileCell
<
u32
>
,
// < RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60
pub
APB2LPENR
:
VolatileCell
<
u32
>
,
// < RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64
pub
RESERVED5
:
[
VolatileCell
<
u32
>
;
2
],
// < Reserved, 0x68-0x6C
pub
BDCR
:
VolatileCell
<
u32
>
,
// < RCC Backup domain control register, Address offset: 0x70
pub
CSR
:
VolatileCell
<
u32
>
,
// < RCC clock control & status register, Address offset: 0x74
pub
RESERVED6
:
[
VolatileCell
<
u32
>
;
2
],
// < Reserved, 0x78-0x7C
pub
SSCGR
:
VolatileCell
<
u32
>
,
// < RCC spread spectrum clock generation register, Address offset: 0x80
pub
PLLI2SCFGR
:
VolatileCell
<
u32
>
,
// < RCC PLLI2S configuration register, Address offset: 0x84
}
impl
RCC
{
pub
fn
get
()
->
*
mut
RCC
{
address
::
RCC_BASE
as
*
mut
RCC
}
}
#[repr(C)]
#[allow(non_snake_case)]
#[rustfmt::skip]
pub
struct
GPIOA
{
pub
MODER
:
VolatileCell
<
u32
>
,
// < GPIO port mode register, Address offset: 0x00
pub
OTYPER
:
VolatileCell
<
u32
>
,
// < GPIO port output type register, Address offset: 0x04
pub
OSPEEDR
:
VolatileCell
<
u32
>
,
// < GPIO port output speed register, Address offset: 0x08
pub
PUPDR
:
VolatileCell
<
u32
>
,
// < GPIO port pull-up/pull-down register, Address offset: 0x0C
pub
IDR
:
VolatileCell
<
u32
>
,
// < GPIO port input data register, Address offset: 0x10
pub
ODR
:
VolatileCell
<
u32
>
,
// < GPIO port output data register, Address offset: 0x14
pub
BSRRL
:
VolatileCell
<
u16
>
,
// < GPIO port bit set/reset low register, Address offset: 0x18
pub
BSRRH
:
VolatileCell
<
u16
>
,
// < GPIO port bit set/reset high register, Address offset: 0x1A
pub
LCKR
:
VolatileCell
<
u32
>
,
// < GPIO port configuration lock register, Address offset: 0x1C
pub
AFR
:
[
VolatileCell
<
u32
>
;
2
],
// < GPIO alternate function registers, Address offset: 0x20-0x24
}
impl
GPIOA
{
pub
fn
get
()
->
*
mut
GPIOA
{
GPIOA_BASE
as
*
mut
GPIOA
}
}
}
use
stm32f40x
::
*
;
// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf)
// rcc, chapter 6
// gpio, chapter 8
fn
wait
(
i
:
u32
)
{
for
_
in
0
..
i
{
cortex_m
::
asm
::
nop
();
// no operation (cannot be optimized out)
}
}
// simple test of Your `modify`
//fn test() {
// let t:VolatileCell<u32> = unsafe { core::mem::uninitialized() };
// t.write(0);
// assert!(t.read() == 0);
// t.modify(3, 3, 0b10101);
// //
// // 10101
// // ..0111000
// // ---------
// // 000101000
// assert!(t.read() == 0b101 << 3);
// t.modify(4, 3, 0b10001);
// // 000101000
// // 111
// // 001
// // 000011000
// assert!(t.read() == 0b011 << 3);
// if << is used, your code will panic in dev, but not in release mode
// t.modify(32, 3, 1);
//}
// system startup, can be hidden from the user
#[entry]
fn
main
()
->
!
{
let
rcc
=
unsafe
{
&
mut
*
RCC
::
get
()
};
// get the reference to RCC in memory
let
gpioa
=
unsafe
{
&
mut
*
GPIOA
::
get
()
};
// get the reference to GPIOA in memory
// test(); // uncomment to run test
idle
(
rcc
,
gpioa
);
loop
{}
}
// user application
fn
idle
(
rcc
:
&
mut
RCC
,
gpioa
:
&
mut
GPIOA
)
{
// power on GPIOA
let
r
=
rcc
.AHB1ENR
.read
();
// read
rcc
.AHB1ENR
.write
(
r
|
1
<<
(
0
));
// set enable
// configure PA5 as output
let
r
=
gpioa
.MODER
.read
()
&
!
(
0b11
<<
(
5
*
2
));
// read and mask
gpioa
.MODER
.write
(
r
|
0b01
<<
(
5
*
2
));
// set output mode
// and alter the data output through the BSRR register
// this is more efficient as the read register is not needed.
loop
{
// set PA5 high
//gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led)
gpioa
.ODR
.write
(
gpioa
.ODR
.read
()
|
(
1
<<
5
));
wait
(
10_000
);
// set PA5 low
// gpioa.BSRRL.write(1 << 5); // clear bit, output low (turn off led)
gpioa
.ODR
.write
(
gpioa
.ODR
.read
()
&
!
(
1
<<
5
));
wait
(
10_000
);
}
}
// 1. C like API.
// In C the .h files are used for defining interfaces, like function signatures (prototypes),
// structs and macros (but usually not the functions themselves)
// here is a peripheral abstraction quite similar to what you would find in the .h files
// provided by ST (and other companies). Actually, the file presesnted here is mostly a
// cut/paste/replace of the stm32f40x.h, just Rustified.
//
// In this case we pass mutable pointers of the peripherals to the `idle`.
//
// Rewrite the accesses in the loop to use the data register directly (and make a read/modify/write).
//
// Run and see that the program behaves the same.
//
// commit your answers (bare5_1)
//
// 2. Extend the read/write API with a modify for u32, taking the
// - address (&mut u32),
// - field offset (in bits, u8),
// - field width (in bits, u8),
// - and value (u32).
//
// Implement and check that running `test` gives you expected behavior.
//
// Change the code into using your new API.
//
// Run and see that the program behaves the same.
//
// commit your answers (bare5_2)
//
// Discussion:
// As with algebraic operations, defalut semantics differ in between
// debug/dev and release builds. E.g., debug << rhs is checked, rhs must be less
// than 32 (for 32 bit datatypes).
//
// Notice, over-shifting (where bits are spilled) is always considered legal,
// its just the shift amuount that is checked.
// There are explicit unchecked versions available if so wanted.
\ No newline at end of file
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