Initial commit
Much of the content here is a direct port from https://github.com/japaric/discovery
This commit is contained in:
162
src/appendix/explore.md
Normal file
162
src/appendix/explore.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# What's left for you to explore
|
||||
|
||||
We have barely scratched the surface! There's lots of stuff left for you to explore:
|
||||
|
||||
## Multitasking
|
||||
|
||||
All our programs executed a single task. How could we achieve multitasking in a system with no OS,
|
||||
and thus no threads. There are two main approaches to multitasking: preemptive multitasking and
|
||||
cooperative multitasking.
|
||||
|
||||
In preemptive multitasking a task that's currently being executed can, at any point in time, be
|
||||
*preempted* (interrupted) by another task. On preemption, the first task will be suspended and the
|
||||
processor will instead execute the second task. At some point the first task will be resumed.
|
||||
Microcontrollers provide hardware support for preemption in the form of *interrupts*.
|
||||
|
||||
In cooperative multitasking a task that's being executed will run until it reaches a *suspension
|
||||
point*. When the processor reaches that suspension point it will stop executing the current task and
|
||||
instead go and execute a different task. At some point the first task will be resumed. The main
|
||||
difference between these two approaches to multitasking is that in cooperative multitasking *yields*
|
||||
execution control at *known* suspension points instead of being forcefully preempted at any point of
|
||||
its execution.
|
||||
|
||||
## Direct Memory Access (DMA).
|
||||
|
||||
This peripheral is a kind of *asynchronous* `memcpy`. So far our programs have
|
||||
been pumping data, byte by byte, into peripherals like UART and I2C. This DMA
|
||||
peripheral can be used to perform bulk transfers of data. Either from RAM to
|
||||
RAM, from a peripheral, like a UART, to RAM or from RAM to a peripheral. You can
|
||||
schedule a DMA transfer, like read 256 bytes from USART1 into this buffer, leave
|
||||
it running in the background and then poll some register to see if it has
|
||||
completed so you can do other stuff while the transfer is ongoing.
|
||||
|
||||
## Sleeping
|
||||
|
||||
All our programs have been continuously polling peripherals to see if there's
|
||||
anything that needs to be done. However, some times there's nothing to be done!
|
||||
At those times, the microcontroller should "sleep".
|
||||
|
||||
When the processor sleeps, it stops executing instructions and this saves power.
|
||||
It's almost always a good idea to save power so your microcontroller should be
|
||||
sleeping as much as possible. But, how does it know when it has to wake up to
|
||||
perform some action? "Interrupts" are one of the events that wake up the
|
||||
microcontroller but there are others and the `wfi` and `wfe` are the
|
||||
instructions that make the processor "sleep".
|
||||
|
||||
## Pulse Width Modulation (PWM)
|
||||
|
||||
In a nutshell, PWM is turning on something and then turning it off periodically
|
||||
while keeping some proportion ("duty cycle") between the "on time" and the "off
|
||||
time". When used on a LED with a sufficiently high frequency, this can be used
|
||||
to dim the LED. A low duty cycle, say 10% on time and 90% off time, will make
|
||||
the LED very dim wheres a high duty cycle, say 90% on time and 10% off time,
|
||||
will make the LED much brighter (almost as if it were fully powered).
|
||||
|
||||
In general, PWM can be used to control how much *power* is given to some
|
||||
electric device. With proper (power) electronics between a microcontroller and
|
||||
an electrical motor, PWM can be used to control how much power is given to the
|
||||
motor thus it can be used to control its torque and speed. Then you can add an
|
||||
angular position sensor and you got yourself a closed loop controller that can
|
||||
control the position of the motor at different loads.
|
||||
|
||||
## Digital input
|
||||
|
||||
We have used the microcontroller pins as digital outputs, to drive LEDs. But
|
||||
these pins can also be configured as digital inputs. As digital inputs, these
|
||||
pins can read the binary state of switches (on/off) or buttons (pressed/not
|
||||
pressed).
|
||||
|
||||
(*spoilers* reading the binary state of switches / buttons is not as
|
||||
straightforward as it sounds ;-)
|
||||
|
||||
## Sensor fusion
|
||||
|
||||
The STM32F3DISCOVERY contains three motion sensors: an accelerometer, a
|
||||
gyroscope and a magnetometer. On their own these measure: (proper) acceleration,
|
||||
angular speed and (the Earth's) magnetic field. But these magnitudes can be
|
||||
"fused" into something more useful: a "robust" measurement of the orientation of
|
||||
the board. Where robust means with less measurement error than a single sensor
|
||||
would be capable of.
|
||||
|
||||
This idea of deriving more reliable data from different sources is known as
|
||||
sensor fusion.
|
||||
|
||||
## Analog-to-Digital Converters (ADC)
|
||||
|
||||
There are a lots of digital sensors out there. You can use a protocol like I2C
|
||||
and SPI to read them. But analog sensors also exist! These sensors just output a
|
||||
voltage level that's proportional to the magnitude they are sensing.
|
||||
|
||||
The ADC peripheral can be use to convert that "analog" voltage level, say `1.25`
|
||||
Volts,into a "digital" number, say in the `[0, 65535]` range, that the processor
|
||||
can use in its calculations.
|
||||
|
||||
## Digital-to-Analog Converters (DAC)
|
||||
|
||||
As you might expect a DAC is exactly the opposite of ADC. You can write some
|
||||
digital value into a register to produce a voltage in the `[0, 3.3V]` range
|
||||
(assuming a `3.3V` power supply) on some "analog" pin. When this analog pin is
|
||||
connected to some appropriate electronics and the register is written to at some
|
||||
constant, fast rate (frequency) with the right values you can produce sounds or
|
||||
even music!
|
||||
|
||||
## Real Time Clock (RTC)
|
||||
|
||||
This peripheral can be used to track time in "human format". Seconds, minutes,
|
||||
hours, days, months and years. This peripheral handles the translation from
|
||||
"ticks" to these human friendly units of time. It even handles leap years and
|
||||
Daylight Save Time for you!
|
||||
|
||||
## Other communication protocols
|
||||
|
||||
SPI, I2S, SMBUS, CAN, IrDA, Ethernet, USB, Bluetooth, etc.
|
||||
|
||||
Different applications use different communication protocols. User facing
|
||||
applications usually have an USB connector because USB is an ubiquitous
|
||||
protocol in PCs and smartphones. Whereas inside cars you'll find plenty of CAN
|
||||
"buses". Some digital sensors use SPI, others use I2C and others, SMBUS.
|
||||
|
||||
---
|
||||
|
||||
So where to next? There are several options:
|
||||
|
||||
- You could check out the examples in the [`microbit`] board support crate repository. All those examples work for
|
||||
the micro:bit board you have.
|
||||
|
||||
[`f3`]: https://docs.rs/f3
|
||||
|
||||
- You could try out [this motion sensors demo][madgwick]. Details about the implementation and
|
||||
source code are available in [this blog post][wd-1-2].
|
||||
|
||||
[madgwick]: https://mobile.twitter.com/japaricious/status/962770003325005824
|
||||
[wd-1-2]: http://blog.japaric.io/wd-1-2-l3gd20-lsm303dlhc-madgwick/
|
||||
|
||||
- You could check out [Real Time for The Masses]. A very efficient preemptive multitasking framework
|
||||
that supports task prioritization and dead lock free execution.
|
||||
|
||||
[Real Time for The Masses]: https://docs.rs/cortex-m-rtfm
|
||||
|
||||
- You could try running Rust on a different development board. The easiest way to get started is to
|
||||
use the [`cortex-m-quickstart`] Cargo project template.
|
||||
|
||||
[`cortex-m-quickstart`]: https://docs.rs/cortex-m-quickstart/0.2.4/cortex_m_quickstart
|
||||
|
||||
- You could check out [this blog post][brave-new-io] which describes how Rust type system can
|
||||
prevent bugs in I/O configuration.
|
||||
|
||||
[brave-new-io]: http://blog.japaric.io/brave-new-io/
|
||||
|
||||
- You could check out my [blog] for miscellaneous topics about embedded development with Rust.
|
||||
|
||||
[blog]: http://blog.japaric.io
|
||||
|
||||
- You could check out the [`embedded-hal`] project which aims to build abstractions (traits) for all
|
||||
the embedded I/O functionality commonly found on microcontrollers.
|
||||
|
||||
[`embedded-hal`]: https://github.com/japaric/embedded-hal
|
||||
|
||||
- You could join the [Weekly driver initiative] and help us write generic drivers on top of the
|
||||
`embedded-hal` traits and that work for all sorts of platforms (ARM Cortex-M, AVR, MSP430, RISCV,
|
||||
etc.)
|
||||
|
||||
[Weekly driver initiative]: https://github.com/rust-lang-nursery/embedded-wg/issues/39
|
||||
170
src/appendix/troubleshooting.md
Normal file
170
src/appendix/troubleshooting.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# General troubleshooting
|
||||
|
||||
## OpenOCD problems
|
||||
|
||||
### can't connect to OpenOCD - "Error: open failed"
|
||||
|
||||
#### Symptoms
|
||||
|
||||
Upon trying to establish a *new connection* with the device you get an error
|
||||
that looks like this:
|
||||
|
||||
```
|
||||
$ openocd -f (..)
|
||||
(..)
|
||||
Error: open failed
|
||||
in procedure 'init'
|
||||
in procedure 'ocd_bouncer'
|
||||
```
|
||||
|
||||
#### Cause + Fix
|
||||
|
||||
- All: The device is not (properly) connected. Check the USB connection using
|
||||
`lsusb` or the Device Manager.
|
||||
- Linux: You may not have enough permission to open the device. Try again with
|
||||
`sudo`. If that works, you can use [these instructions] to make OpenOCD work
|
||||
without root privilege.
|
||||
- Windows: You are probably missing the ST-LINK USB driver. Installation
|
||||
instructions [here].
|
||||
|
||||
[these instructions]: 03-setup/linux.html#udev%20rules
|
||||
[here]: 03-setup/windows.html#ST-LINK%20USB%20driver
|
||||
|
||||
### can't connect to OpenOCD - "Polling again in X00ms"
|
||||
|
||||
#### Symptoms
|
||||
|
||||
Upon trying to establish a *new connection* with the device you get an error
|
||||
that looks like this:
|
||||
|
||||
```
|
||||
$ openocd -f (..)
|
||||
(..)
|
||||
Error: jtag status contains invalid mode value - communication failure
|
||||
Polling target stm32f3x.cpu failed, trying to reexamine
|
||||
Examination failed, GDB will be halted. Polling again in 100ms
|
||||
Info : Previous state query failed, trying to reconnect
|
||||
Error: jtag status contains invalid mode value - communication failure
|
||||
Polling target stm32f3x.cpu failed, trying to reexamine
|
||||
Examination failed, GDB will be halted. Polling again in 300ms
|
||||
Info : Previous state query failed, trying to reconnect
|
||||
```
|
||||
|
||||
#### Cause
|
||||
|
||||
The microcontroller may have get stuck in some tight infinite loop or it may be
|
||||
continuously raising an exception, e.g. the exception handler is raising an
|
||||
exception.
|
||||
|
||||
#### Fix
|
||||
|
||||
- Close OpenOCD, if running
|
||||
- Press and hold the reset (black) button
|
||||
- Launch the OpenOCD command
|
||||
- Now, release the reset button
|
||||
|
||||
|
||||
### OpenOCD connection lost - "Polling again in X00ms"
|
||||
|
||||
#### Symptoms
|
||||
|
||||
A *running* OpenOCD session suddenly errors with:
|
||||
|
||||
```
|
||||
# openocd -f (..)
|
||||
Error: jtag status contains invalid mode value - communication failure
|
||||
Polling target stm32f3x.cpu failed, trying to reexamine
|
||||
Examination failed, GDB will be halted. Polling again in 100ms
|
||||
Info : Previous state query failed, trying to reconnect
|
||||
Error: jtag status contains invalid mode value - communication failure
|
||||
Polling target stm32f3x.cpu failed, trying to reexamine
|
||||
Examination failed, GDB will be halted. Polling again in 300ms
|
||||
Info : Previous state query failed, trying to reconnect
|
||||
```
|
||||
|
||||
#### Cause
|
||||
|
||||
The USB connection was lost.
|
||||
|
||||
#### Fix
|
||||
|
||||
- Close OpenOCD
|
||||
- Disconnect and re-connect the USB cable.
|
||||
- Re-launch OpenOCD
|
||||
|
||||
### Can't flash the device - "Ignoring packet error, continuing..."
|
||||
|
||||
#### Symptoms
|
||||
|
||||
While flashing the device, you get:
|
||||
|
||||
```
|
||||
$ arm-none-eabi-gdb $file
|
||||
Start address 0x8000194, load size 31588
|
||||
Transfer rate: 22 KB/sec, 5264 bytes/write.
|
||||
Ignoring packet error, continuing...
|
||||
Ignoring packet error, continuing...
|
||||
```
|
||||
|
||||
#### Cause
|
||||
|
||||
Closed `itmdump` while a program that "printed" to the ITM was running. The
|
||||
current GDB session will appear to work normally, just without ITM output but
|
||||
the next GDB session will error with the message that was shown in the previous
|
||||
section.
|
||||
|
||||
Or, `itmdump` was called **after** the `monitor tpiu` was issued thus making
|
||||
`itmdump` delete the file / named-pipe that OpenOCD was writing to.
|
||||
|
||||
#### Fix
|
||||
|
||||
- Close/kill GDB, OpenOCD and `itmdump`
|
||||
- Remove the file / named-pipe that `itmdump` was using (for example,
|
||||
`itm.txt`).
|
||||
- Launch OpenOCD
|
||||
- Then, launch `itmdump`
|
||||
- Then, launch the GDB session that executes the `monitor tpiu` command.
|
||||
|
||||
## Cargo problems
|
||||
|
||||
### "can't find crate for `core`"
|
||||
|
||||
#### Symptoms
|
||||
|
||||
```
|
||||
Compiling volatile-register v0.1.2
|
||||
Compiling rlibc v1.0.0
|
||||
Compiling r0 v0.1.0
|
||||
error[E0463]: can't find crate for `core`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
error[E0463]: can't find crate for `core`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
error[E0463]: can't find crate for `core`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
Build failed, waiting for other jobs to finish...
|
||||
Build failed, waiting for other jobs to finish...
|
||||
error: Could not compile `r0`.
|
||||
|
||||
To learn more, run the command again with --verbose.
|
||||
```
|
||||
|
||||
#### Cause
|
||||
|
||||
You are using a toolchain older than `nightly-2018-04-08` and forgot to call `rustup target add
|
||||
thumbv7m-none-eabi`.
|
||||
|
||||
#### Fix
|
||||
|
||||
Update your nightly and install the `thumbv7em-none-eabihf` target.
|
||||
|
||||
``` console
|
||||
$ rustup update nightly
|
||||
|
||||
$ rustup target add thumbv7em-none-eabihf
|
||||
```
|
||||
Reference in New Issue
Block a user