Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAN training #2

Merged
merged 26 commits into from
Mar 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# braintrain
BRAINv3-based firmware training

Labs currently available:
- [Lab 1: Embedded Introduction](lab1.md)
- [Lab 2: CAN Bus and Multitasking](lab2.md)

Coming soon:
- Suggest something!
19 changes: 14 additions & 5 deletions SConscript
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os.path
import os, os.path

Import('env_lpc1549')

# Environment for building projects for labs
env = env_lpc1549.Clone()

env.Append(CCFLAGS=['-Wall', '-Werror'])
Expand All @@ -10,10 +11,10 @@ env.Append(CCFLAGS=['-Wall', '-Werror'])
# be shared with solution compilation
main_all = Glob('src/*.cpp')
main_srcs = [elt for elt in main_all if elt.name == 'main.cpp']
mainlibs_srcs = [elt for elt in main_all if elt not in main_srcs]
support_srcs = [elt for elt in main_all if elt not in main_srcs]

mainlibs = env.StaticLibrary('mainlibs', mainlibs_srcs)
env.Append(LIBS=mainlibs)
supportlib = env.StaticLibrary('mainlibs', support_srcs)
env.Append(LIBS=supportlib)

env.Default(env.CalSolFW('brain',
srcs=main_srcs,
Expand All @@ -28,7 +29,15 @@ for solution in solutions:
srcs=[solution],
includes=['src']
))


# Build the master node with SLCAN debugging
env.Default(
env.CalSolFW('util/lab2slcan',
srcs=Glob('util/*.cpp'),
includes=['util','src']
)
)

env.Alias('prog',
env.Command('openocd', 'brain.elf',
'openocd -f interface/cmsis-dap.cfg -f lpc1549_openocd.cfg -c init -c "reset halt" -c "flash erase_sector 0 0 last" -c "flash write_image $SOURCE" -c "reset run" -c "exit"'
Expand Down
49 changes: 46 additions & 3 deletions SConscript-env-lpc1549
Original file line number Diff line number Diff line change
@@ -1,26 +1,69 @@
# Modifies the environment to build mbed firmware for the LPC1549 using GCC-ARM
import os, os.path

Import('env')

env.ConfigureMbedTarget('LPC1549', File('mbed/targets/targets.json').srcnode())

# Build the mbed library as a static library
mbed_paths = env.GetMbedSourceDirectories('mbed')
env.Append(CPPPATH=[x.srcnode() for x in mbed_paths]) # this allows duplicate=0

rtos_paths = [
Dir('mbed/rtos'),
Dir('mbed/rtos/rtx/TARGET_CORTEX_M'),
Dir('mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_M3'),
Dir('mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_M3/TOOLCHAIN_GCC'),
]
env.Append(CPPPATH=[x.srcnode() for x in rtos_paths]) # this allows duplicate=0

env['MBED_LINKSCRIPT'] = env.GetMbedLinkscript(mbed_paths)
env.Append(CPPDEFINES=[
'MBED_CONF_PLATFORM_STDIO_BAUD_RATE=115200',
'MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE=115200',
'MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT==1',
'MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES=0'
'MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT=1',
'MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES=0',
'OS_CLOCK=12000000', # for RTOS
])


# Build the USBDevice library as a dependency
usb_class_dirs = [
'mbed/features/unsupported/USBDevice/USBAudio',
'mbed/features/unsupported/USBDevice/USBHID',
'mbed/features/unsupported/USBDevice/USBMIDI',
'mbed/features/unsupported/USBDevice/USBMSD',
'mbed/features/unsupported/USBDevice/USBSerial',
]

usb_device_dirs = [
'mbed/features/unsupported/USBDevice/USBDevice',
]

usb_srcs = [
'mbed/features/unsupported/USBDevice/USBDevice/USBDevice.cpp',
'mbed/features/unsupported/USBDevice/USBDevice/USBHAL_LPC11U.cpp',
]

for path in usb_class_dirs:
usb_srcs.extend(Glob(os.path.join(path,'*.cpp')))

usb_dirs = usb_class_dirs + usb_device_dirs
env.Append(CPPPATH=usb_dirs)

env_mbed = env.Clone()
env_mbed.Append(CCFLAGS='-w') # don't care about errors in dependencies
mbed_sources = env.GetMbedSources(mbed_paths)
mbed_sources.remove(File('mbed/targets/TARGET_NXP/TARGET_LPC15XX/device/system_LPC15xx.c'))
mbed_sources.append(File('common/lpc15xx_overrides/system_LPC15xx.c'))
mbed_lib = env_mbed.StaticLibrary('mbed', mbed_sources)

rtos_sources = env.GetMbedSources(rtos_paths)
rtos_lib = env_mbed.StaticLibrary('rtos', rtos_sources)
env.Prepend(LIBS=rtos_lib)

usb_lib = env_mbed.StaticLibrary('usbdevice', usb_srcs)
env.Append(LIBS=usb_lib)

env.Append(LINKFLAGS=[
'-Wl,--whole-archive', # used to compile mbed HAL, which uses funky weak symbols
mbed_lib,
Expand Down
Binary file added docs/usbtin-interface.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usbtin-monitor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/usbtin-trace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 21 additions & 19 deletions lab1.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Objectives
Target audience
- Anyone with no practical experience with Arduino-level embedded systems or with the mbed API.
- All electrical team members, whether focusing on software or hardware, should attend.
- All electrical team members, whether focusing on software or hardware, should attend.
- Anyone in general (even the mech people!) that is interested is also welcome to attend.

Assumptions:
Expand Down Expand Up @@ -37,7 +37,7 @@ This should fade the RGB LED through all the colors over a period of 3 seconds,

0. If doing this lab during one of the scheduled training sessions, consider pairing up.
0. Clone this repository. You may also set up this repository under Eclipse (similarly to [Zephyr-FW](https://github.com/CalSol/Zephyr-FW#project-configuration)), or use command-line scons and openocd.
0. Sanity check: build the code, either by running `scons` at the repository root, or in Eclipse.
0. Sanity check: build the code, either by running `scons` at the repository root, or in Eclipse.

## Lab 1.2: "Hello, world"
While the typical programming "Hello, world" is to print text on a screen, we don't have a screen on our BRAINs. Instead, we will do the typical embedded "hello, world": the blinking LED.
Expand All @@ -55,18 +55,18 @@ DigitalOut led1(P0_3);
DigitalOut led2(P0_9);

DigitalIn btn(P0_4);

RawSerial serial(P0_8, NC, 115200);
```
```

**Objective**: for this first part will be to alternate the left LED (`led1`, on `P0_3`) and the right LED (`led2`, on `P0_9`) on and off, at once full cycle (left on, then right on) per second.

> LEDs are electronic devices that emit light when current flows through them from anode (A) to cathode (K).
>
> The circuit on the BRAINv3.3 for the left and right LEDs is:
> The circuit on the BRAINv3.3 for the left and right LEDs is:
>
> ![Image](docs/led.png?raw=true)
>
>
> The LED turns on (emits light) when the pin voltage is high.

mbed's [DigitalOut](https://developer.mbed.org/handbook/DigitalOut) provides a way to control an IO pin as a digital output - the pin can be set low (0v in this case) or high (3.3v in this case). Note that from the [example and API docs](https://developer.mbed.org/handbook/DigitalOut), this can be done by assigning 0 or 1 to the object. For example,
Expand Down Expand Up @@ -97,15 +97,15 @@ Feel free to try playing with the LEDs by writing some code and deploying it.
> }
> ```
>
> This has been structured as typical embedded code: an (optional) initialization section, followed by code repeating forever in a main loop.
> This has been structured as typical embedded code: an (optional) initialization section, followed by code repeating forever in a main loop.

mbed also has basic timing functions, like [wait](https://developer.mbed.org/handbook/Wait), that waits for (approximately) some specified number of seconds regardless of the underlying hardware characteristics (like processor speed). For example,

```c++
wait(0.1)
```

will delay by 100ms. This may be useful for getting the (approximate) 1Hz blink rate.
will delay by 100ms. This may be useful for getting the (approximate) 1Hz blink rate.

Done? Compare against [the solution here](solutions/lab1.2.cpp).

Expand All @@ -120,7 +120,7 @@ Like DigitalOut, mbed also has a [DigitalIn](https://developer.mbed.org/handbook
if (!btn) {
/* do something if button is pressed */
}
```
```

> Switches are electronic devices that connect (or disconnect, in some cases) a circuit when pressed.
>
Expand All @@ -132,7 +132,7 @@ if (!btn) {

Done? Compare against [one possible solution here](solutions/lab1.3.cpp).

You may realize that while the high-level objective (pause blinking) might appear clear, there are many different implementations that could result in subtly different behaviors. For example, it's unspecified whether pressing the button only needs to stop toggling the LED (as in the example solution) or if it should pause the counter (for example, if you press the button 0.25s after the last toggle, it shouldn't toggle for 0.25s after you release the button). For a toy example and at these timescales for human reaction, it's inconsequential, but that won't be true for every system you work on...
You may realize that while the high-level objective (pause blinking) might appear clear, there are many different implementations that could result in subtly different behaviors. For example, it's unspecified whether pressing the button only needs to stop toggling the LED (as in the example solution) or if it should pause the counter (for example, if you press the button 0.25s after the last toggle, it shouldn't toggle for 0.25s after you release the button). For a toy example and at these timescales for human reaction, it's inconsequential, but that won't be true for every system you work on...

> Switches also suffer from mechanical bounce, where during press or release, the switch may jump between connected and disconnected several times before settling down. For applications which rely on edge detection (the high to low or low to high transition on the input) and sample fast enough, this may cause it to register false edges. Two common methods to "debounce" switches are either with a RC (resistor-capacitor) circuit or with filtering software.

Expand All @@ -145,18 +145,20 @@ mbed's [RawSerial](https://developer.mbed.org/users/mbed_official/code/mbed/docs

> [UART (universal asynchronous receiver transmitter)](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter) transmits a frame of data (typically a byte, or 8 bits) serially (that is, one at a time: each bit is placed on the digital line for some duration before the next bit is "shifted out"). Since there is no external clock (defining when bits transition), both the receiver and transmitter must agree on baud rate (bit rate).
>
> Here, we initialize the UART at 115200 baud, which is one of the faster but still common rates.
> Here, we initialize the UART at 115200 baud, which is one of the faster but still common rates.


> RawSerial vs. Serial: mbed also offers a [Serial](https://developer.mbed.org/handbook/Serial) interface, which provides an additional file-like abstraction. We don't need that, so we don't use it, preferring to use the more lightweight RawSerial directly.

<a name="serial-port"></a>

To connect to the serial terminal on your PC:
- For Windows:
- Open up the Device Manager and find the COM port (like COM4) for USB Serial Device.

![Image](docs/windows-device-manager.png?raw=true)
- Open up a serial terminal (like [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html), and connect to the COM port you found (above) at 115200 baud.

![Image](docs/windows-putty.png?raw=true)
- For Linux:
- You're a power user, you probably already know how. There's also way too many Linux distros out there with subtly different behaviors (like serial terminal permissions!).
Expand All @@ -171,7 +173,7 @@ in the initialization section of your code.

> `__FILE__` is replaced by the compiler with the filename of the source file containing it, and `__DATE__` and `__TIME__` are replaced by the compiler with the current time (which is the time of complication). Having version information readily available is helpful in many cases, such as when you don't know what's deployed, or to ensure that new code is actually being deployed.
>
> `\r` is a carriage return (move pointer to beginning of line) and `\n` is a newline (move pointer down one line).
> `\r` is a carriage return (move pointer to beginning of line) and `\n` is a newline (move pointer down one line).

RawSerial also offers [`printf`](https://en.wikipedia.org/wiki/Printf_format_string), which allows you to interpolate (splice) variable data into the string. The first argument to `printf` is the format string (containing optional specifiers, that define the type and interpretation of variables to be spliced), and subsequent arguments are the values to be spliced.

Expand All @@ -188,7 +190,7 @@ Now put all the pieces together and code up the full objective. The [solution is
## Lab 1.5: "Hello, world", _in color_
We've covered the basics, but that's still kind of boring. Especially since we have a RGB LED on each BRAIN - we might as well do something cool and fun with it!

**Objective**: Fade the RGB LED through the 6 hues (red - yellow - green - cyan - blue - purple) at one cycle per 3 seconds. Since we're bleeding edge (and 120 Hz displays are _so last year_), update the LED output at 1,200 Hz.
**Objective**: Fade the RGB LED through the 6 hues (red - yellow - green - cyan - blue - purple) at one cycle per 3 seconds. Since we're bleeding edge (and 120 Hz displays are _so last year_), update the LED output at 1,200 Hz.

Since this is a non-trivial task, we'll break it down into several parts:

Expand All @@ -198,14 +200,14 @@ Since this is a non-trivial task, we'll break it down into several parts:
> - Hue: the color, ranging between [0, 360�). For our purposes, 0� is red, 120� is green, and 240� is blue. Values inbetween are interpolated, so 60� is yellow, 180� is cyan, and 300� is purple.
> - Saturation: colorfulness of a color, normalized to [0, 1] here, with 1 being a pure color.
> - Value: brightness, normalized to [0, 1] here, with 0 being off and 1 being full brightness.

0. Set the saturation and value to a constant 1. Increment the hue slightly every tick.
0. Convert HSV representation to RGB representation, which corresponds to the raw red, green, and blue LED channels.
0. Square the RGB brightness, since [humans perceive brightness of a point source as the inverse square of actual intensity](https://en.wikipedia.org/wiki/Stevens%27_power_law).
0. Invert the RGB brightness. Unlike the single LEDs which connected the microcontroller to the LED anode (positive) pin, the RGB LED is a common anode LED and the microcontroller is connected to the cathode (negative) pin of each LED channel, so the LED only emits light when the pin is low.

![Image](docs/rgbled.png?raw=true)

0. Write the brightness to the output.

### Incrementing the hue
Expand Down Expand Up @@ -341,7 +343,7 @@ Instead, we will use PwmOut's `pulsewidth_us` function to set the on-time in mic
ledR.pulsewidth_us((uint32_t)r * 500 / 65535);
ledG.pulsewidth_us((uint32_t)g * 500 / 65535);
ledB.pulsewidth_us((uint32_t)b * 500 / 65535);
```
```

Once you've put together all the pieces, check out [the solution here](solutions/lab1.6.cpp).

Expand Down
Loading