1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-23 00:05:33 +03:00

CF - restore docs folder from master_v1.x

This commit is contained in:
Hydra 2017-02-25 17:49:42 +00:00
parent 6a869f05f6
commit f9f41530bf
143 changed files with 9321 additions and 0 deletions

View file

@ -0,0 +1,92 @@
# Atomic Barrier implementation
```
static int markme_bar = 0;
static int markme = 0;
markme++;
// (1) markme is read into register, but not changed
markme_bar++;
// markme_bar is read from memory and incremented
ATOMIC_BLOCK_NB(NVIC_PRIO_TIMER) {
ATOMIC_BARRIER(markme_bar);
// start of ATOMIC_BLOCK_NB scope:
// markme_bar is stored into memory (it is input/output - "+m" output operand - of asm volatile)
// BASEPRI is saved into temporary variable
// BASEPRI_MAX is decremented to NVIC_PRIO_TIMER (if it is higher than NVIC_PRIO_TIMER or zero; lower number means higher priority on ARM)
markme++;
// nothing happens, markme value is not needed yet
markme_bar++;
// (2) markme_bar re-read from memory (ATOMIC_BARRIER marked it as modified - "+m" output operand of asm volatile)
// and incremented
// end of ATOMIC_BLOCK_NB scope:
// markme_bar is stored into memory (cleanup function from ATOMIC_BARRIER) / input "m" operand), but kept for later use in register
// (actually markme_bar+1 is stored and pre-increment value kept in register)
// BASEPRI value is restored
};
markme++;
// register value read in (1) is incremented by 3
markme_bar++;
// register value read in (2) is incremented (actually +=2, because register contains pre-increment value)
// markme and markme_bar are stored into memory
```
# Atomic Barrier Warning
The ATOMIC_BLOCK/ATOMIC_BARRIER construction is dependent on gcc extensions. I relies on gcc cleanup function (`attribute ((cleanup))`) and assumes that cleanup handler is called, when leaving block, even when associated variable is eliminated.
There is (a bit paranoid) safeguard warning to make sure that generated assembly is hand-checked on new gcc version. It is assumed that only major gcc version versions need to be checked.
If GCC is upgraded and a warning appears when compiling then the generated asm source must be verified.
e.g.
```
%% serial_softserial.c
warning "Please verify that ATOMIC_BARRIER works as intended"
```
To perform the verification, proceed as per discusson on issue #167 which reads:
I hope it's enough to check that optimized-away variable still has cleanup code at end of scope.
```
static int markme=0;
markme++;
ATOMIC_BLOCK_NB(0xff) {
ATOMIC_BARRIER(markme);
markme++;
};
markme++;
```
pass `-save-temps=obj` (or `-save-temps=cwd`, but lots of files will end up in same directory as makefile) to gcc link step (LTO is in use), find resulting `*.ltrans*.ltrans.s` (grep for `markme`, on linux it ends up in `/tmp`) and check that generated assembly sequence is:
```
MSR basepri_max, r3
# (possibly markme address load)
# barier (markme) start
# (increment markme, load and store to memory)
ldr r2, [r3]
adds r0, r2, #1
str r0, [r3]
# barier(markme) end
MSR basepri, r3
# (markme value should be cached in register on next increment)
```
The # barrier(markme) must surround access code and must be inside MSR basepri instructions .
Similar approach is used for ATOMIC_BLOCK in avr libraries, so gcc should not break this behavior.
IMO attribute(cleanup) and asm volatile is defined in a way that should guarantee this.
attribute(cleanup) is probably safer way to implement atomic sections - another possibility is to explicitly place barriers in code, but that can (and will eventually) lead to missed barrier/basepri restore on same path creating very hard to find bug.
The 'MEMORY_BARRIER()' code can be omitted when 'ATOMIC_BLOCK' (with full memory barriers) is used, but it is better to explicitly state what memory is protected by barrier. gcc 5 can use this knowledge to greatly improve generated code.

View file

@ -0,0 +1,674 @@
# Blackbox logging internals
The Blackbox is designed to record the raw internal state of the flight controller at near-maximum rate. By logging the
raw inputs and outputs of key flight systems, the Blackbox log aims to allow the offline bench-top simulation, debugging,
and testing of flight control algorithms using data collected from real flights.
A typical logging regime might capture 30 different state variables (for an average of 28 bytes per frame) at a sample
rate of 900Hz. That's about 25,000 bytes per second, which is 250,000 baud with a typical 8-N-1 serial encoding.
## References
Please refer to the source code to clarify anything this document leaves unclear:
* Cleanflight's Blackbox logger: [blackbox.c](https://github.com/cleanflight/cleanflight/blob/master/src/main/blackbox/blackbox.c),
[blackbox_io.c](https://github.com/cleanflight/cleanflight/blob/master/src/main/blackbox/blackbox_io.c),
[blackbox_fielddefs.h](https://github.com/cleanflight/cleanflight/blob/master/src/main/blackbox/blackbox_fielddefs.h)
* [C implementation of the Blackbox log decoder](https://github.com/cleanflight/blackbox-tools/blob/master/src/parser.c)
* [JavaScript implementation of the Blackbox log decoder](https://github.com/cleanflight/blackbox-log-viewer/blob/master/js/flightlog_parser.js)
## Logging cycle
Blackbox is designed for flight controllers that are based around the concept of a "main loop". During each main loop
iteration, the flight controller will read some state from sensors, run some flight control algorithms, and produce some
outputs. For each of these loop iterations, a Blackbox "logging iteration" will be executed. This will read data that
was stored during the execution of the main loop and log this data to an attached logging device. The data will include
algorithm inputs such as sensor and RC data, intermediate results from flight control algorithms, and algorithm outputs
such as motor commands.
## Log frame types
Each event which is recorded to the log is packaged as a "log frame". Blackbox only uses a handful of different types of
log frames. Each frame type is identified by a single capital letter.
### Main frames: I, P
The most basic kind of logged frames are the "main frames". These record the primary state of the flight controller (RC
input, gyroscopes, flight control algorithm intermediates, motor outputs), and are logged during every logging
iteration.
Each main frame must contain at least two fields, "loopIteration" which records the index of the current main loop
iteration (starting at zero for the first logged iteration), and "time" which records the timestamp of the beginning of
the main loop in microseconds (this needn't start at zero, on Cleanflight it represents the system uptime).
There are two kinds of main frames, "I" and "P". "I", or "intra" frames are like video keyframes. They can be decoded
without reference to any previous frame, so they allow log decoding to be resynchronized in the event of log damage. "P"
or "inter" frames use an encoding which references previously logged frames in order to reduce the required datarate.
When one interframe fails to decode, all following interframes will be undecodable up until the next intraframe.
### GPS frames: G, H
Because the GPS is updated so infrequently, GPS data is logged in its own dedicated frames. These are recorded whenever
the GPS data changes (not necessarily alongside every main frame). Like the main frames, the GPS frames have their own
intra/inter encoding system.
The "H" or "home" frame records the lat/lon of a reference point. The "G" or "GPS" frame records the current state of
the GPS system (current position, altitude etc.) based on the reference point. The reference point can be updated
(infrequently) during the flight, and is logged whenever it changes.
To allow "G" frames to continue be decoded in the event that an "H" update is dropped from the log, the "H" frame is
logged periodically even if it has not changed (say, every 10 seconds). This caps the duration of unreadble "G" frames
that will result from a single missed "H" change.
### Slow frames: S
Some flight controller state is updated very infrequently (on the order of once or twice a minute). Logging the fact
that this data had not been updated during every single logging iteration would be a waste of bandwidth, so these frames
are only logged when the "slow" state actually changes.
All Slow frames are logged as intraframes. An interframe encoding scheme can't be used for Slow frames, because one
damaged frame causes all subsequent interframes to be undecodable. Because Slow frames are written so infrequently, one
missing Slow frame could invalidate minutes worth of Slow state.
On Cleanflight, Slow frames are currently used to log data like the user-chosen flight mode and the current failsafe
state.
### Event frames: E
Some flight controller data is updated so infrequently or exists so transiently that we do not log it as a flight
controller "state". Instead, we log it as a state *transition* . This data is logged in "E" or "event" frames. Each event
frame payload begins with a single byte "event type" field. The format of the rest of the payload is not encoded in the
flight log, so its interpretation is left up to an agreement of the writer and the decoder.
For example, one event that Cleanflight logs is that the user has adjusted a system setting (such as a PID setting)
using Cleanflight's inflight adjustments feature. The event payload notes which setting was adjusted and the new value
for the setting.
Because these setting updates are so rare, it would be wasteful to treat the settings as "state" and log the fact that
the setting had not been changed during every logging iteration. It would be infeasible to periodically log the system
settings using an intra/interframe scheme, because the intraframes would be so large. Instead we only log the
transitions as events, accept the small probability that any one of those events will be damaged/absent in the log, and
leave it up to log readers to decide the extent to which they are willing to assume that the state of the setting
between successfully-decoded transition events was truly unchanged.
## Log field format
For every field in a given frame type, there is an associated name, predictor, and encoding.
When a field is written, the chosen predictor is computed for the field, then this predictor value is subtracted from
the raw field value. Finally, the encoder is used to transform the value into bytes to be written to the logging device.
### Field predictors
The job of the predictor is to bring the value to be encoded as close to zero as possible. The predictor may be based
on the values seen for the field in a previous frame, or some other value such as a fixed value or a value recorded in
the log headers. For example, the battery voltage values in "I" intraframes in Cleanflight use a reference voltage that
is logged as part of the headers as a predictor. This assumes that battery voltages will be broadly similar to the
initial pack voltage of the flight (e.g. 4S battery voltages are likely to lie within a small range for the whole
flight). In "P" interframes, the battery voltage will instead use the previously-logged voltage as a predictor, because
the correlation between successive voltage readings is high.
These predictors are presently available:
#### Predict zero (0)
This predictor is the null-predictor which doesn't modify the field value at all. It is a common choice for fields
which are already close to zero, or where no better history is available (e.g. in intraframes which may not rely on the
previous value of fields).
#### Predict last value (1)
This is the most common predictor in interframes. The last-logged value of the field will be used as the predictor, and
subtracted from the raw field value. For fields which don't change very often, this will make their encoded value be
normally zero. Most fields have some time-correlation, so this predictor should reduce the magnitude of all but the
noisiest fields.
#### Predict straight line (2)
This predictor assumes that the slope between the current measurement and the previous one will be similar to the
slope between the previous measurement and the one before that. This is common for fields which increase at a steady rate,
such as the "time" field. The predictor is `history_age_2 - 2 * history_age_1`.
#### Predict average 2 (3)
This predictor is the average of the two previously logged values of the field (i.e. `(history_age_1 + history_age_2) / 2`
). It is used when there is significant random noise involved in the field, which means that the average of the recent
history is a better predictor of the next value than the previous value on its own would be (for example, in gyroscope
or motor measurements).
#### Predict minthrottle (4)
This predictor subtracts the value of "minthrottle" which is included in the log header. In Cleanflight, motors always
lie in the range of `[minthrottle ... maxthrottle]` when the craft is armed, so this predictor is used for the first
motor value in intraframes.
#### Predict motor[0] (5)
This predictor is set to the value of `motor[0]` which was decoded earlier within the current frame. It is used in
intraframes for every motor after the first one, because the motor commands typically lie in a tight grouping.
#### Predict increment (6)
This predictor assumes that the field will be incremented by 1 unit for every main loop iteration. This is used to
predict the `loopIteration` field, which increases by 1 for every loop iteration.
#### Predict home-coord (7)
This predictor is set to the corresponding latitude or longitude field from the GPS home coordinate (which was logged in
a preceding "H" frame). If no preceding "H" frame exists, the value is marked as invalid.
#### Predict 1500 (8)
This predictor is set to a fixed value of 1500. It is preferred for logging servo values in intraframes, since these
typically lie close to the midpoint of 1500us.
#### Predict vbatref (9)
This predictor is set to the "vbatref" field written in the log header. It is used when logging intraframe battery
voltages in Cleanflight, since these are expected to be broadly similar to the first battery voltage seen during
arming.
#### Predict last main-frame time (10)
This predictor is set to the last logged `time` field from the main frame. This is used when predicting timestamps of
non-main frames (e.g. that might be logging the timing of an event that happened during the main loop cycle, like a GPS
reading).
### Field encoders
The field encoder's job is to use fewer bits to represent values which are closer to zero than for values that are
further from zero. Blackbox supports a range of different encoders, which should be chosen on a per-field basis in order
to minimize the encoded data size. The choice of best encoder is based on the probability distribution of the values
which are to be encoded. For example, if a field is almost always zero, then an encoding should be chosen for it which
can encode that case into a very small number of bits, such as one. Conversely, if a field is normally 8-16 bits large,
it would be wasteful to use an encoder which provided a special short encoded representation for zero values, because
this will increase the encoded length of larger values.
These encoders are presently available:
#### Unsigned variable byte (1)
This is the most straightforward encoding. This encoding uses the lower 7 bits of an encoded byte to store the lower 7
bits of the field's value. The high bit of that encoded byte is set to one if more than 7 bits are required to store the
value. If the value did exceed 7 bits, the lower 7 bits of the value (which were written to the log) are removed from
the value (by right shift), and the encoding process begins again with the new value.
This can be represented by the following algorithm:
```c
while (value > 127) {
writeByte((uint8_t) (value | 0x80)); // Set the high bit to mean "more bytes follow"
value >>= 7;
}
writeByte(value);
```
Here are some example values encoded using variable-byte encoding:
| Input value | Output encoding |
| ----------- | --------------- |
| 1 | 0x01 |
| 42 | 0x2A |
| 127 | 0x7F |
| 128 | 0x80 0x01 |
| 129 | 0x81 0x01 |
| 23456 | 0xA0 0xB7 0x01 |
#### Signed variable byte (0)
This encoding applies a pre-processing step to fold negative values into positive ones, then the resulting unsigned
number is encoded using unsigned variable byte encoding. The folding is accomplished by "ZigZag" encoding, which is
represented by:
```c
unsigned32 = (signed32 << 1) ^ (signed32 >> 31)
```
ZigZag encoding is preferred against simply casting the signed integer to unsigned, because casting would cause small
negative quantities to appear to be very large unsigned integers, causing the encoded length to be similarly large.
ZigZag encoding ensures that values near zero are still near zero after encoding.
Here are some example integers encoded using ZigZag encoding:
| Input value | ZigZag encoding |
| ----------- | --------------- |
| 0 | 0 |
| -1 | 1 |
| 1 | 2 |
| -2 | 3 |
| 2147483647 | 4294967294 |
| -2147483648 | 4294967295 |
#### Neg 14-bit (3)
The value is negated, treated as an unsigned 14 bit integer, then encoded using unsigned variable byte encoding. This
bizarre encoding is used in Cleanflight for battery pack voltages. This is because battery voltages are measured using a
14-bit ADC, with a predictor which is set to the battery voltage during arming, which is expected to be higher than any
voltage experienced during flight. After the predictor is subtracted, the battery voltage will almost certainly be below
zero.
This results in small encoded values when the voltage is closely below the initial one, at the expense of very large
encoded values if the voltage rises higher than the initial one.
#### Elias delta unsigned 32-bit (4)
Because this encoding produces a bitstream, this is the only encoding for which the encoded value might not be a whole
number of bytes. If the bitstream isn't aligned on a byte boundary by the time the next non-Elias Delta field arrives,
or the end of the frame is reached, the final byte is padded with zeros byte-align the stream. This encoding requires
more CPU time than the other encodings because of the bit juggling involved in writing the bitstream.
When this encoder is chosen to encode all of the values in Cleanflight interframes, it saves about 10% bandwidth
compared to using a mixture of the other encodings, but uses too much CPU time to be practical.
[The basic encoding algorithm is defined on Wikipedia](https://en.wikipedia.org/wiki/Elias_delta_coding). Given these
utility functions:
```c
/* Write `bitCount` bits from the least-significant end of the `bits` integer to the bitstream. The most-significant bit
* will be written first
*/
void writeBits(uint32_t bits, unsigned int bitCount);
/* Returns the number of bits needed to hold the top-most 1-bit of the integer 'i'. 'i' must not be zero. */
unsigned int numBitsToStoreInteger(uint32_t i);
```
This is our reference implementation of Elias Delta:
```c
// Value must be more than zero
void writeU32EliasDeltaInternal(uint32_t value)
{
unsigned int valueLen, lengthOfValueLen;
valueLen = numBitsToStoreInteger(value);
lengthOfValueLen = numBitsToStoreInteger(valueLen);
// Use unary to encode the number of bits we'll need to write the length of the value
writeBits(0, lengthOfValueLen - 1);
// Now write the length of the value
writeBits(valueLen, lengthOfValueLen);
// Having now encoded the position of the top bit of value, write its remaining bits
writeBits(value, valueLen - 1);
}
```
To this we add a wrapper which allows encoding both the value zero and MAXINT:
```c
void writeU32EliasDelta(uint32_t value)
{
/* We can't encode value==0, so we need to add 1 to the value before encoding
*
* That would make it impossible to encode MAXINT, so use 0xFFFFFFFF as an escape
* code with an additional bit to choose between MAXINT-1 or MAXINT.
*/
if (value >= 0xFFFFFFFE) {
// Write the escape code
writeU32EliasDeltaInternal(0xFFFFFFFF);
// Add a one bit after the escape code if we wanted "MAXINT", or a zero if we wanted "MAXINT - 1"
writeBits(value - 0xFFFFFFFE, 1);
} else {
writeU32EliasDeltaInternal(value + 1);
}
}
```
Here are some reference encoded bit patterns produced by writeU32EliasDelta:
| Input value | Encoded bit string |
| ----------- | ------------------ |
| 0 | 1 |
| 1 | 0100 |
| 2 | 0101 |
| 3 | 01100 |
| 4 | 01101 |
| 5 | 01110 |
| 6 | 01111 |
| 7 | 00100000 |
| 8 | 00100001 |
| 9 | 00100010 |
| 10 | 00100011 |
| 11 | 00100100 |
| 12 | 00100101 |
| 13 | 00100110 |
| 14 | 00100111 |
| 15 | 001010000 |
| 225 | 00010001100010 |
| 4294967292 | 000001000001111111111111111111111111111101 |
| 4294967293 | 000001000001111111111111111111111111111110 |
| 4294967294 | 0000010000011111111111111111111111111111110 |
| 4294967295 | 0000010000011111111111111111111111111111111 |
Note that the very common value of zero encodes to a single bit, medium-sized values like 225 encode to 14 bits (an
overhead of 4 bits over writing a plain 8 bit value), and typical 32-bit values like 4294967293 encode into 42 bits, an
overhead of 10 bits.
#### Elias delta signed 32-bit (5)
The value is first converted to unsigned using ZigZag encoding, then unsigned Elias-delta encoding is applied.
#### TAG8_8SVB (6)
First, an 8-bit (one byte) header is written. This header has its bits set to zero when the corresponding field (from a
maximum of 8 fields) is set to zero, otherwise the bit is set to one. The least-signficant bit in the header corresponds
to the first field to be written. This header is followed by the values of only the fields which are non-zero, written
using signed variable byte encoding.
This encoding is preferred for groups of fields in interframes which are infrequently updated by the flight controller.
This will mean that their predictions are usually perfect, and so the value to be encoded for each field will normally
be zero. This is common for values like RC inputs and barometer readings, which are updated in only a fraction of main
loop iterations.
For example, given these field values to encode:
```
0, 0, 4, 0, 8
```
This would be encoded:
```
0b00010100, 0x04, 0x08
```
#### TAG2_3S32 (7)
A 2-bit header is written, followed by 3 signed field values of up to 32 bits each. The header value is based on the
maximum size in bits of the three values to be encoded as follows:
| Header value | Maximum field value size | Field range |
| ------------ | ------------------------ | -------------------------- |
| 0 | 2 bits | [-2...1] |
| 1 | 4 bits | [-8...7] |
| 2 | 6 bits | [-32...31] |
| 3 | Up to 32 bits | [-2147483648...2147483647] |
If any of the three values requires more than 6 bits to encode, a second, 6-bit header value is written in the lower
bits of the initial header byte. This second header has 2 bits for each of the encoded values which represents how many
bytes are required to encode that value. The least-significant bits of the header represent the first field which is
encoded. The values for each possibility are as follows:
| Header value | Field size | Field range |
| ------------ | ---------- | -------------------------- |
| 0 | 1 byte | [-127...128] |
| 1 | 2 bytes | [-32768...32767] |
| 2 | 3 bytes | [-8388608...8388607] |
| 3 | 4 bytes | [-2147483648...2147483647] |
This header is followed by the actual field values in order, written least-significant byte first, using the byte
lengths specified in the header.
So bringing it all together, these encoded bit patterns are possible, where "0" and "1" mean bits fixed to be those
values, "A", "B", and "C" represent the first, second and third fields, and "s" represents the bits of the secondary
header in the case that any field is larger than 6 bits:
```
00AA BBCC,
0100 AAAA BBBB CCCC
10AA AAAA 00BB BBBB 00CC CCCC
11ss ssss (followed by fields of byte lengths specified in the "s" header)
```
This encoding is useful for fields like 3-axis gyroscopes, which are frequently small and typically have similar
magnitudes.
#### TAG8_4S16 (8)
An 8-bit header is written, followed by 4 signed field values of up to 16 bits each. The 8-bit header value has 2 bits
for each of the encoded fields (the least-significant bits represent the first field) which represent the
number of bits required to encode that field as follows:
| Header value | Field value size | Field range |
| ------------ | ---------------- | ---------------- |
| 0 | 0 bits | [0...0] |
| 1 | 4 bits | [-8...7] |
| 2 | 8 bits | [-128...127] |
| 3 | 16 bits | [-32768...32767] |
This header is followed by the actual field values in order, written as if the output stream was a bit-stream, with the
most-significant bit of the first field ending up in the most-significant bits of the first written byte. If the number
of nibbles written is odd, the final byte has its least-significant nibble set to zero.
For example, given these field values:
```
13, 0, 4, 2
```
Choosing from the allowable field value sizes, they may be encoded using this many bits each:
```
8, 0, 4, 4
```
The corresponding header values for these lengths would be:
```
2, 0, 1, 1
```
So the header and fields would be encoded together as:
```
0b01010010, 0x0D, 0x42
```
#### NULL (9)
This encoding does not write any bytes to the file. It is used when the predictor will always perfectly predict the
value of the field, so the remainder is always zero. In practice this is only used for the "loopIteration" field in
interframes, which is always perfectly predictable based on the logged frame's position in the sequence of frames and
the "P interval" setting from the header.
## Log file structure
A logging session begins with a log start marker, then a header section which describes the format of the log, then the
log payload data, and finally an optional "log end" event ("E" frame).
A single log file can be comprised of one or more logging sessions. Each session may be preceded and followed by any
amount of non-Blackbox data. This data is ignored by the Blackbox log decoding tools. This allows for the logging device
to be alternately used by the Blackbox and some other system (such as MSP) without requiring the ability to begin a
separate log file for each separate activity.
### Log start marker
The log start marker is "H Product:Blackbox flight data recorder by Nicholas Sherlock\n". This marker is
used to discover the beginning of the flight log if the log begins partway through a file. Because it is such a long
string, it is not expected to occur by accident in any sequence of random bytes from other log device users.
### Log header
The header is comprised of a sequence of lines of plain ASCII text. Each header line has the format `H fieldname:value`
and ends with a '\n'. The overall header does not have a terminator to separate it from the log payload
(the header implicitly ends when a line does not begin with an 'H' character).
The header can contain some of these fields:
#### Data version (required)
When the interpretation of the Blackbox header changes due to Blackbox specification updates, the log version is
incremented to allow backwards-compatibility in the decoder:
```
H Data version:2
```
#### Logging interval
Not every main loop iteration needs to result in a Blackbox logging iteration. When a loop iteration is not logged,
Blackbox is not called, no state is read from the flight controller, and nothing is written to the log. Two header lines
are included to note which main loop iterations will be logged:
##### I interval
This header notes which of the main loop iterations will record an "I" intraframe to the log. If main loop iterations
with indexes divisible by 32 will be logged as "I" frames, the header will be:
```
H I interval: 32
```
The first main loop iteration seen by Blackbox will be numbered with index 0, so the first main loop iteration will
always be logged as an intraframe.
##### P interval
Not every "P" interframe needs to be logged. Blackbox will log a portion of iterations in order to bring the total
portion of logged main frames to a user-chosen fraction. This fraction is called the logging rate. The smallest possible
logging rate is `(1/I interval)` which corresponds to logging only "I" frames at the "I" interval and discarding all
other loop iterations. The maximum logging rate is `1/1`, where every main loop iteration that is not an "I" frame is
logged as a "P" frame. The header records the logging rate fraction in `numerator/denominator` format like so:
```
H P interval:1/2
```
The logging fraction given by `num/denom` should be simplified (i.e. rather than 2/6, a logging rate of 1/3 should
be used).
Given a logging rate of `num/denom` and an I-frame interval of `I_INTERVAL`, the frame type to log for an iteration
of index `iteration` is given by:
```c
if (iteration % I_INTERVAL == 0)
return 'I';
if ((iteration % I_INTERVAL + num - 1) % denom < num)
return 'P';
return '.'; // i.e. don't log this iteration
```
For an I-interval of 32, these are the resulting logging patterns at some different P logging rates.
| Logging rate | Main frame pattern | Actual portion logged |
| ------------ | ----------------------------------------------------------------- | --------------------- |
| 1 / 32 | I...............................I...............................I | 0.03 |
| 1 / 6 | I.....P.....P.....P.....P.....P.I.....P.....P.....P.....P.....P.I | 0.19 |
| 1 / 3 | I..P..P..P..P..P..P..P..P..P..P.I..P..P..P..P..P..P..P..P..P..P.I | 0.34 |
| 1 / 2 | I.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.I.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.I | 0.50 |
| 2 / 3 | I.PP.PP.PP.PP.PP.PP.PP.PP.PP.PP.I.PP.PP.PP.PP.PP.PP.PP.PP.PP.PP.I | 0.66 |
| 5 / 6 | I.PPPPP.PPPPP.PPPPP.PPPPP.PPPPP.I.PPPPP.PPPPP.PPPPP.PPPPP.PPPPP.I | 0.81 |
| 1 / 1 | IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPIPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPI | 1.00 |
#### Firmware type (optional)
Because Blackbox records the internal flight controller state, the interpretation of the logged data will depend
on knowing which flight controller recorded it. To accomodate this, the name of the flight controller should be recorded:
```
H Firmware type:Cleanflight
```
More details should be included to help narrow down the precise flight-controller version (but these are not required):
```
H Firmware revision:c49bd40
H Firmware date:Aug 28 2015 16:49:11
```
#### Field X name (required)
This header is a comma-separated list of the names for the fields in the 'X' frame type:
```
H Field I name:loopIteration,time,axisP[0],axisP[1]...
```
The decoder assumes that the fields in the 'P' frame type will all have the same names as those in the 'I' frame, so
a "Field P name" header does not need to be supplied.
#### Field X signed (optional)
This is a comma-separated list of integers which are set to '1' when their corresponding field's value should be
interpreted as signed after decoding, or '0' otherwise:
```
H Field I signed:0,0,1,1...
```
#### Field X predictor (required)
This is a comma-separated list of integers which specify the predictors for each field in the specified frame type:
```
H Field I predictor:0,0,0,0...
```
#### Field X encoding (required)
This is a comma-separated list of integers which specify the encoding used for each field in the specified frame type:
```
H Field X encoding:1,1,0,0...
```
#### vbatref
This header provides the reference voltage that will be used by predictor #9.
#### minthrottle
This header provides the minimum value sent by Cleanflight to the ESCs when armed, it is used by predictor #4.
#### Additional headers
The decoder ignores headers that it does not understand, so you can freely add any headers that you require in order to
properly interpret the meaning of the logged values.
For example, to create a graphical displays of RC sticks and motor percentages, the Blackbox rendering tool requires
the additional headers "rcRate" and "maxthrottle". In order to convert raw gyroscope, accelerometer and voltage readings
into real-world units, the Blackbox decoder requires the calibration constants "gyro.scale", "acc_1G" and "vbatscale".
These headers might look like:
```
H rcRate:100
H maxthrottle:1980
H gyro.scale:0x3d79c190
H acc_1G:4096
H vbatscale:110
```
### Log payload
The log payload is a concatenated sequence of logged frames. Each frame type which is present in the log payload must
have been previously described in the log header (with Frame X name, etc. headers). Each frame begins with a single
capital letter to specify the type of frame (I, P, etc), which is immediately followed by the frame's field data. There
is no frame length field, checksum, or trailer.
The field data is encoded by taking an array of raw field data, computing the predictor for each field, subtrating this
predictor from the field, then applying the field encoders to each field in sequence to serialize them to the log.
For example, imagine that we are encoding three fields in an intraframe, are using zero-predictors for each field (#0),
and are encoding the values using the unsigned variable byte encoding (#1). For these field values:
```
1, 2, 3
```
We would encode a frame:
```
'I', 0x01, 0x02, 0x03
```
Imagine that we are encoding an array of motor commands in an interframe. We will use the previous motor commands as a
predictor, and encode the resulting values using signed variable byte encoding. The motor command values seen in the
previous logged iteration were:
```
1430, 1500, 1470, 1490
```
And the motor commands to be logged in this iteration are:
```
1635, 1501, 1469, 1532
```
After subtracting the predictors for each field, we will be left with:
```
205, 1, -1, 42
```
We will apply ZigZag encoding to each field, which will give us:
```
410, 2, 1, 84
```
We will use unsigned variable byte encoding to write the resulting values to the log, which will give us:
```
'P', 0x9A, 0x03, 0x02, 0x01, 0x54
```
### Log end marker
The log end marker is an optional Event ("E") frame of type 0xFF whose payload is the string "End of log\0". The
payload ensures that random data does not look like an end-of-log marker by chance. This event signals the tidy ending
of the log. All following bytes until the next log-begin marker (or end of file) should be ignored by the log
decoder.
```
'E', 0xFF, "End of log", 0x00
```
## Log validation
Any damage experienced to the log during recording is overwhelmingly due to subsequences of bytes being dropped by the
logging device due to overflowing buffers. Accordingly, Blackbox logs do not bother to include any checksums (bytes are
not expected to be damaged by the logging device without changing the length of the message). Because of the tight
bandwidth requirements of logging, neither a frame length field nor frame trailer is recorded that would allow for the
detection of missing bytes.
Instead, the decoder uses a heuristic in order to detect damaged frames. The decoder reads an entire frame from the log
(using the decoder for each field which is the counterpart of the encoder specified in the header), then it checks to
see if the byte immediately following the frame, which should be the beginning of a next frame, is a recognized
frame-type byte (e.g. 'I', 'P', 'E', etc). If that following byte represents a valid frame type, it is assumed that the
decoded frame was the correct length (so was unlikely to have had random ranges of bytes removed from it, which would
have likely altered the frame length). Otherwise, the frame is rejected, and a valid frame-type byte is looked for
immediately after the frame-start byte of the frame that was rejected. A rejected frame causes all subsequent
interframes to be rejected as well, up until the next intraframe.
A frame is also rejected if the "loopIteration" or "time" fields have made unreasonable leaps forward, or moved at
all backwards. This suffices to detect almost all log corruption.

View file

@ -0,0 +1,20 @@
#Building Manual.
The manual PDF file is generated by concatenating relevant markdown files and by transforming the result using Gimli to obtain the final PDF file. This steps are handled automatically by the ```build_docs.sh``` script located in the root of the repository next to the Makefile.
##Requirements & Installation
The PDF manual generation uses the Gimli for the conversion. It can be installed via ruby gems. On Debian based systems the installation steps are:
```bash
sudo apt-get install ruby1.9.1 ruby1.9.1-dev rubygems zlib1g-dev wkhtmltopdf libxml2-dev libxslt-dev
sudo gem1.9.1 install gimli
```
##Configuration
All markdown files need to be registered in the ```build_manual.sh``` file individually by modifying the ```doc_files``` variable / array:
```bash
doc_files=( 'Configuration.md'
'Board - CC3D.md'
'...'
'...'
)
```

View file

@ -0,0 +1,131 @@
# Building in Eclipse
How to build, test & debug Cleanflight in Eclipse on Linux, Windows & MacOS.
## Checklist
Use this checklist to make sure you didn't miss a step. Versions mandated below are current and correct as of January 2016.
- [ ] [Download and Install](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) the latest (currently 1.8) 64bit Oracle JDK [read more](#install-the-jdk)
- [ ] [Download and Install](https://eclipse.org/downloads/packages/eclipse-ide-cc-developers/lunasr2) Eclipse Luna (4.4) 64bit CDT edition, **NB:** not Mars or Neon [read more](#install-eclipse)
- [ ] [Download and Install](https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q3-update) the GCC ARM Embedded toolchain 4.9-2015-q3-update [read more](#install-arm-toolchain)
- [ ] *Windows platform only:* [Download and Install](https://github.com/gnuarmeclipse/windows-build-tools/releases) the latest GNU ARM Eclipse Windows Build Tools
- [ ] *Windows platform only:* Download and Install either [Cygwin](http://cygwin.com/install.html) or [MinGW MSYS](http://sourceforge.net/projects/mingw/files/latest/download)
- [ ] Optionally [Download and Install](https://github.com/gnuarmeclipse/openocd/releases) the latest GNU ARM Eclipse OpenOCD [read more](#install-openocd)
- [ ] *Linux platform only:* [Configure UDEV](http://gnuarmeclipse.github.io/openocd/install/#udev) to recognise USB JTAG probes
- [ ] *Windows platform only:* [Download and Install](http://www.st.com/web/en/catalog/tools/FM147/SC1887/PF260219) the ST-Link / ST-LinkV2 drivers. These drivers do work on Windows 10 even if not yet mentioned by ST.
- [ ] Optionally [Download and Install](https://github.com/gnuarmeclipse/qemu/releases) the latest GNU ARM Eclipse QEMU [read more](#install-qemu)
- [ ] Add a new update site to Eclipse named "GNU ARM Eclipse Plugins" with the URL "http://gnuarmeclipse.sourceforge.net/updates" and install all the features offered
- [ ] Configure [the recommended workspace settings](http://gnuarmeclipse.github.io/eclipse/workspace/preferences/)
- [ ] Checkout the cleanflight source code [read more](#checkout-cleanflight)
- [ ] *Windows platform only:* Add the msys or cygwin bin directory to the project path
- [ ] Build the code by going to *Project menu -> Build All* [read more](#build)
- [ ] Run the tests by creating and running a make target named "test"
- [ ] Configure debugging [read more](#configure-debugging)
## Extended Notes
### Install the JDK
The [minimum JDK version](http://gnuarmeclipse.github.io/plugins/install/#java) supported by GNU Arm Eclipse is 1.7 but the current latest, 1.8, is recommended instead. While Oracle JDK is the recommended version, [they do also support](http://gnuarmeclipse.github.io/plugins/install/#java) the OpenJDK.
### Install Eclipse
Eclipse Luna v4.4 is the preferred version for GNU Arm Tools currently. The minimum Eclipse version is Kepler 4.3. The maximum is Mars 4.5 although it is not tested by GNU Arm Eclipse and some things are [known to be broken](http://gnuarmeclipse.github.io/plugins/install/#eclipse--cdt). Eclipse Neon is currently not released.
CDT v8.6.0, as shipped in the Eclipse Luna CDT download, is recommended. The minimum CDT version is 8.3.
The 64bit Eclipse is preferred but a 32bit Eclipse can be used; ensure you run it on a 32bit JDK.
### Install ARM Toolchain
The minimum version is 4.8-2014-q2. The maximum, and currently recommended version, is 4_9-2015q3.
GNU ARM Tools recommends that you don't add the toolchain to your path environment variable. This means you can install multiple versions of the toolchain without conflict. If you'll install only one version, it can make life easier when working outside Eclipse to add it to your path.
Retain the default installation directories so that the GNU ARM Plugins can locate the toolchain.
### Install OpenOCD
You should install OpenOCD If you will be debugging on real hardware, such as the STM32F3DISCOVERY dev board. It is not required to simply build Cleanflight or run the tests.
### Install QEMU
No tests currently run on the QEMU emulator therefore this install is entirely optional. It is useful to test your installation, since you can compile and run a blinky demo.
### Checkout Cleanflight
If you'll be submitting changes to cleanflight, [fork the repository](https://help.github.com/articles/fork-a-repo/) on GitHub and checkout your copy.
In Eclipse go to *File -> Import* choose *Git -> Projects from Git*
![projects from git](assets/building-in-eclipse/checkout-cleanflight-001.PNG)
Choose *Clone URI*
![clone uri](assets/building-in-eclipse/checkout-cleanflight-002.PNG)
Enter the URI https://github.com/cleanflight/cleanflight or if you've forked the repo, enter your URI instead. With a fork, you will need to specify your authentication details
![enter uri](assets/building-in-eclipse/checkout-cleanflight-003.PNG)
On the branch selection dialog, de-select all branches and select only *master*
![choose branches to clone](assets/building-in-eclipse/checkout-cleanflight-004.PNG)
Select the default destination directory
![destination](assets/building-in-eclipse/checkout-cleanflight-005.PNG)
When the download completes, choose *Use the New Project wizard* and click Finish
![finish](assets/building-in-eclipse/checkout-cleanflight-006.PNG)
Choose *C/C++ -> Makefile Project with Existing Code*
![makefile project](assets/building-in-eclipse/checkout-cleanflight-007.PNG)
Enter cleanflight as the project name and browse to your home directory -> git -> cleanflight for the existing code location. Ensure the C (cleanflight) and C++ (tests) languages are checked. Choose the Cross ARM GCC toolchain for the Indexer Settings. Click finish.
![finish checkout](assets/building-in-eclipse/checkout-cleanflight-008.PNG)
Set your build and debug targets by going to project properties -> C/C++ Build and choose the Behaviour tab. Replace "all" in the build box with "TARGET=xxx DEBUG=GDB" where xxx is your platform such as NAZE
![build](assets/building-in-eclipse/checkout-cleanflight-012.PNG)
On Windows only, add msys or cygwin bin directory to the project's path by right clicking the project and choosing properties
![properties](assets/building-in-eclipse/checkout-cleanflight-009.PNG)
Edit the path variable in *C/C++ Build -> Environment*
![edit path](assets/building-in-eclipse/checkout-cleanflight-010.PNG)
Append the full path to the relevant bin dir
![append bin dir](assets/building-in-eclipse/checkout-cleanflight-011.PNG)
### Build
Choose project -> build all
![build all](assets/building-in-eclipse/checkout-cleanflight-013.PNG)
### Configure Debugging
Choose debug -> debug configurations
![debug configurations](assets/building-in-eclipse/checkout-cleanflight-014.PNG)
Create a new OpenOCD configuration for the obj\main\cleanflight_XXX.elf application (this file is generated by the build step above)
![debug configurations](assets/building-in-eclipse/checkout-cleanflight-015.PNG)
Add the appropriate openocd board configuration parameter for your dev platform
![openocd target](assets/building-in-eclipse/checkout-cleanflight-016.PNG)
Add the target to your debug menu favourites
![debug favs](assets/building-in-eclipse/checkout-cleanflight-017.PNG)

View file

@ -0,0 +1,16 @@
# Building in Fedora
Assuming you already have wget and git available, you should be able to build Cleanflight on a fresh install of Fedora with the following commands (tested on F18, F20 and Ubuntu 14.04):
```
wget http://distribute.atmel.no/tools/opensource/Atmel-ARM-GNU-Toolchain/4.8.4/arm-gnu-toolchain-4.8.4.371-linux.any.x86_64.tar.gz
tar xf arm-gnu-toolchain-4.8.4.371-linux.any.x86_64.tar.gz
export PATH=$PATH:$PWD/arm-none-eabi/bin
git clone https://github.com/cleanflight/cleanflight.git
cd cleanflight
TARGET=NAZE make
```
This will create cleanflight_NAZE.hex in the obj folder.

View file

@ -0,0 +1,107 @@
# Building in Mac OS X
Building in Mac OS X can be accomplished in just a few steps:
* Install general development tools (clang, make, git)
* Install ARM GCC 4.9 series compiler
* Checkout Cleanflight sourcecode through git
* Build the code
## Install general development tools (clang, make, git)
Open up a terminal and run `make`. If it is installed already, you should see a message like this, which means that you
already have the required development tools installed:
```
make: *** No targets specified and no makefile found. Stop.
```
If it isn't installed yet, you might get a popup like this. If so, click the "install" button to install the commandline
developer tools:
![Prompt to install developer tools](assets/mac-prompt-tools-install.png)
If you just get an error like this instead of a helpful popup prompt:
```
-bash: make: command not found
```
Try running `xcode-select --install` instead to trigger the popup.
If that doesn't work, you'll need to install the XCode development environment [from the App Store][]. After
installation, open up XCode and enter its preferences menu. Go to the "downloads" tab and install the
"command line tools" package.
[from the App Store]: https://itunes.apple.com/us/app/xcode/id497799835
## Install ARM GCC 4.9 series compiler
Cleanflight is built using the 4.9 series GCC compiler provided by the [GNU Tools for ARM Embedded Processors project][].
Hit the "all downloads" link on the right side of the GNU Tools for ARM page to view [the older releases][]. Grab the
Mac installation tarball for the latest version in the 4.9 series (e.g. 4.9-2015q2). Move it somewhere useful
such as a `~/development` folder (in your home directory) and double click it to unpack it. You should end up with a
folder called `~/development/gcc-arm-none-eabi-4_9-2015q2/`.
Now you just need to add the `bin/` directory from inside the GCC directory to your system's path. Run `nano ~/.profile`. Add a
new line at the end of the file which adds the path for the `bin/` folder to your path, like so:
```
export PATH=$PATH:~/development/gcc-arm-none-eabi-4_9-2015q2/bin
```
Press CTRL+X to exit nano, and answer "y" when prompted to save your changes.
Now *close this terminal window* and open a new one. Try running:
```
arm-none-eabi-gcc --version
```
You should get output similar to:
```
arm-none-eabi-gcc.exe (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288]
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
If `arm-none-eabi-gcc` couldn't be found, go back and check that you entered the correct path in your `~/.profile` file.
[GNU Tools for ARM Embedded Processors project]: https://launchpad.net/gcc-arm-embedded
[the older releases]: https://launchpad.net/gcc-arm-embedded/+download
## Checkout CleanFlight sourcecode through git
Enter your development directory and clone the [Cleanflight repository][] using the "HTTPS clone URL" which is shown on
the right side of the Cleanflight GitHub page, like so:
```
git clone https://github.com/cleanflight/cleanflight.git
```
This will download the entire Cleanflight repository for you into a new folder called "cleanflight".
[CleanFlight repository]: https://github.com/cleanflight/cleanflight
## Build the code
Enter the cleanflight directory and run `make TARGET=NAZE` to build firmware for the Naze32. When the build completes,
the .hex firmware should be available as `obj/cleanflight_NAZE.hex` for you to flash using the Cleanflight
Configurator.
## Updating to the latest source
If you want to erase your local changes and update to the latest version of the Cleanflight source, enter your
cleanflight directory and run these commands to first erase your local changes, fetch and merge the latest
changes from the repository, then rebuild the firmware:
```
git reset --hard
git pull
make clean TARGET=NAZE
make TARGET=NAZE
```

View file

@ -0,0 +1,89 @@
# Building in Ubuntu
Building for Ubuntu platform is remarkably easy. The only trick to understand is that the Ubuntu toolchain,
which they are downstreaming from Debian, is not compatible with Cleanflight. We suggest that you take an
alternative PPA from Terry Guo, found here:
https://launchpad.net/~terry.guo/+archive/ubuntu/gcc-arm-embedded
This PPA has several compiler versions and platforms available. For many hardware platforms (notably Naze)
the 4.9.3 compiler will work fine. For some, older compiler 4.8 (notably Sparky) is more appropriate. We
suggest you build with 4.9.3 first, and try to see if you can connect to the CLI or run the Configurator.
If you cannot, please see the section below for further hints on what you might do.
## Setup GNU ARM Toolchain
Note specifically the last paragraph of Terry's PPA documentation -- Ubuntu carries its own package for
`gcc-arm-none-eabi`, so you'll have to remove it, and then pin the one from the PPA.
For your release, you should first remove any older pacakges (from Debian or Ubuntu directly), introduce
Terry's PPA, and update:
```
sudo apt-get remove binutils-arm-none-eabi gcc-arm-none-eabi
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
```
For Ubuntu 14.10 (current release, called Utopic Unicorn), you should pin:
```
sudo apt-get install gcc-arm-none-eabi=4.9.3.2014q4-0utopic12
```
For Ubuntu 14.04 (an LTS as of Q1'2015, called Trusty Tahr), you should pin:
```
sudo apt-get install gcc-arm-none-eabi=4.9.3.2014q4-0trusty12
```
For Ubuntu 12.04 (previous LTS, called Precise Penguin), you should pin:
```
sudo apt-get install gcc-arm-none-eabi=4.9.3.2014q4-0precise12
```
## Building on Ubuntu
After the ARM toolchain from Terry is installed, you should be able to build from source.
```
cd src
git clone git@github.com:cleanflight/cleanflight.git
cd cleanflight
make TARGET=NAZE
```
You'll see a set of files being compiled, and finally linked, yielding both an ELF and then a HEX:
```
...
arm-none-eabi-size ./obj/main/cleanflight_NAZE.elf
text data bss dec hex filename
97164 320 11080 108564 1a814 ./obj/main/cleanflight_NAZE.elf
arm-none-eabi-objcopy -O ihex --set-start 0x8000000 obj/main/cleanflight_NAZE.elf obj/cleanflight_NAZE.hex
$ ls -la obj/cleanflight_NAZE.hex
-rw-rw-r-- 1 pim pim 274258 Jan 12 21:45 obj/cleanflight_NAZE.hex
```
You can use the Cleanflight-Configurator to flash the ```obj/cleanflight_NAZE.hex``` file.
## Bricked/Bad build?
Users have reported that the 4.9.3 compiler for ARM produces bad builds, for example on the Sparky hardware platform.
It is very likely that using an older compiler would be fine -- Terry happens to have also a 4.8 2014q2 build in his
PPA - to install this, you can fetch the `.deb` directly:
http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu/pool/main/g/gcc-arm-none-eabi/
and use `dpkg` to install:
```
sudo dpkg -i gcc-arm-none-eabi_4-8-2014q2-0saucy9_amd64.deb
```
Make sure to remove `obj/` and `make clean`, before building again.
## Updating and rebuilding
Navigate to the local cleanflight repository and use the following steps to pull the latest changes and rebuild your version of cleanflight:
```
cd src/cleanflight
git reset --hard
git pull
make clean TARGET=NAZE
make
```
Credit goes to K.C. Budd, AKfreak for testing, and pulsar for doing the long legwork that yielded this very short document.

View file

@ -0,0 +1,112 @@
# Building in windows
## Bash On Windows 10
A new feature in Windows 10 allows any developer to quickly and easily run an entire linux subsystem in windows and access it via a bash terminal. This gives developers full use of the entire linux OS and all of the great existing linux tools and programs. When Bash for Windows is up and running it feels like you sshed into a full linux box, except the linux distro is actually running alongside windows locally.
If you use Bash on Windows you can easily build cleanflight exactly as you would for Ubuntu. (the linux distro running on Windows is Ubuntu Trusty)
Setup for Bash on Windows is very easy and takes less than 5 minutes. [For instructions follow the official guide here.](https://msdn.microsoft.com/commandline/wsl/install_guide)
Once you have Bash On Windows running you can follow the "Building in Ubuntu" instructions for building cleanfight.
##Setup Cygwin
download the Setup*.exe from https://www.cygwin.com/
![Cygwin Installation](assets/001.cygwin_dl.png)
Execute the download Setup and step through the installation wizard (no need to customize the settings here). Stop at the "Select Packages" Screen and select the following Packages
for Installation:
- Devel/git
- Devel/bash-completion (was git-completion, Optional)
- Devel/make
- Devel/binutils
- Editors/vim
- Editors/vim-common (Optional)
- Shells/mintty (should be already selected)
![Cygwin Installation](assets/002.cygwin_setup.png)
![Cygwin Installation](assets/003.cygwin_setup.png)
![Cygwin Installation](assets/004.cygwin_setup.png)
![Cygwin Installation](assets/005.cygwin_setup.png)
![Cygwin Installation](assets/006.cygwin_setup.png)
Continue with the Installation and accept all autodetected dependencies.
![Cygwin Installation](assets/007.cygwin_setup.png)
##Setup GNU ARM Toolchain
----------
versions do matter, 5.4 is known to work well. Download this version from https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-win32.zip
Extract the contents of this archive to any folder of your choice, for instance ```C:\dev\gcc-arm```.
![GNU ARM Toolchain Setup](assets/008.toolchain.png)
add the "bin" subdirectory to the PATH Windows environment variable: ```%PATH%;C:\dev\gcc-arm\bin```
![GNU ARM Toolchain Setup](assets/009.toolchain_path.png)
![GNU ARM Toolchain Setup](assets/010.toolchain_path.png)
## Checkout and compile Cleanflight
Head over to the Cleanflight Github page and grab the URL of the GIT Repository: "https://github.com/cleanflight/cleanflight.git"
Open the Cygwin-Terminal, navigate to your development folder and use the git commandline to checkout the repository:
```bash
cd /cygdrive/c/dev
git clone https://github.com/cleanflight/cleanflight.git
```
![GIT Checkout](assets/011.git_checkout.png)
![GIT Checkout](assets/012.git_checkout.png)
To compile your Cleanflight binaries, enter the cleanflight directory and build the project using the make command. You can append TARGET=[HARDWARE] if you want to build anything other than the default NAZE target:
```bash
cd cleanflight
make TARGET=NAZE
```
![GIT Checkout](assets/013.compile.png)
within few moments you should have your binary ready:
```bash
(...)
arm-none-eabi-size ./obj/main/cleanflight_NAZE.elf
text data bss dec hex filename
95388 308 10980 106676 1a0b4 ./obj/main/cleanflight_NAZE.elf
arm-none-eabi-objcopy -O ihex --set-start 0x8000000 obj/main/cleanflight_NAZE.elf obj/cleanflight_NAZE.hex
```
You can use the Cleanflight-Configurator to flash the ```obj/cleanflight_NAZE.hex``` file.
## Updating and rebuilding
Navigate to the local cleanflight repository and use the following steps to pull the latest changes and rebuild your version of cleanflight:
```bash
cd /cygdrive/c/dev/cleanflight
git reset --hard
git pull
make clean TARGET=NAZE -j16 -l
make
```
You may want to remove -j16 -l if your having a hard time narrowing down errors. It does multithreaded make, however it makes it harder to know which warning or error comes from which file.

View file

@ -0,0 +1,259 @@
#General
This document overrides the original Baseflight style that was referenced before.
This document has taken inspiration from that style, from Eclipse defaults and from Linux, as well as from some Cleanflight developers and existing code.
There are not so many changes from the old style, if you managed to find it.
#Formatting style
##Indentation
K&R indent style with 4 space indent, NO hard tabs (all tabs replaced by spaces).
##Tool support
Any of these tools can get you pretty close:
Eclipse built in "K&R" style, after changing the indent to 4 spaces and change Braces after function declarations to Next line.
```
astyle --style=kr --indent=spaces=4 --min-conditional-indent=0 --max-instatement-indent=80 --pad-header --pad-oper --align-pointer=name --align-reference=name --max-code-length=120 --convert-tabs --preserve-date --suffix=none --mode=c
```
```
indent -kr -i4 -nut
```
(the options for these commands can be tuned more to comply even better)
Note: These tools are not authorative.
Sometimes, for example, you may want other columns and line breaks so it looks like a matrix.
Note2: The Astyle settings have been tested and will produce a nice result. Many files will be changed, mostly to the better but maybe not always, so use with care.
##Curly Braces
Functions shall have the opening brace at the beginning of the next line.
All non-function statement blocks (if, switch, for) shall have the opening brace last on the same line, with the following statement on the next line.
Closing braces shall be but on the line after the last statement in the block.
If it is followed by an `else` or `else if` that shall be on the same line, again with the opening brace on the same line.
A single statement after an `if` or an `else` may omit the "unnecessary" braces only when ALL conditional branches have single statements AND you have strong reason to know it will always be that way.
If in doubt, do not omit such "unnecessary" braces.
(Adding a statement to a branch will break the logic if the braces are forgotten and otherwise make the PR longer).
##Spaces
Use a space after (most) keywords. The notable exceptions are sizeof, typeof, alignof, and __attribute__, which look somewhat like functions (and are usually used with parentheses).
So use a space after these keywords:
```
if, switch, case, for, do, while
```
but not with sizeof, typeof, alignof, or __attribute__. E.g.,
```
s = sizeof(struct file);
```
When declaring pointer data or a function that returns a pointer type, the preferred use of '*' is adjacent to the data name or function name and not adjacent to the type name. Examples:
```
char *linux_banner;
memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
```
Use one space around (on each side of) most binary and ternary operators, such as any of these:
```
= + - < > * / % | & ^ <= >= == != ? :
```
but no space after unary operators:
```
& * + - ~ ! sizeof typeof alignof __attribute__ defined
```
no space before the postfix increment & decrement unary operators:
```
++ --
```
no space after the prefix increment & decrement unary operators:
```
++ --
```
and no space around the '.' and "->" structure member operators.
'*' and '&', when used for pointer and reference, shall have no space between it and the following variable name.
#typedef
enums with a count should have that count declared as the last item in the enumeration list,
so that it is automatically maintained, e.g.:
```
typedef enum {
PID_CONTROLLER_MW23 = 0,
PID_CONTROLLER_MWREWRITE,
PID_CONTROLLER_LUX_FLOAT,
PID_COUNT
} pidControllerType_e;
```
It shall not be calculated afterwards, e.g. using PID_CONTROLLER_LUX_FLOAT + 1;
typedef struct definitions should include the struct name, so that the type can be forward referenced, that is in:
```
typedef struct motorMixer_s {
float throttle;
...
float yaw;
} motorMixer_t;
```
the motorMixer_s name is required.
#Variables
##Naming
Generally, descriptive lowerCamelCase names are preferred for function names, variables, arguments, etc.
For configuration variables that are user accessible via CLI or similar, all_lowercase with underscore is preferred.
Variable names should be nouns.
Simple temporary variables with a very small scope may be short where it aligns with common practice.
Such as "i" as a temporary counter in a `for` loop, like `for (int i = 0; i < 4; i++)`.
Using "temporaryCounter" in that case would not improve readability.
##Declarations
Avoid global variables.
Variables should be declared at the top of the smallest scope where the variable is used.
Variable re-use should be avoided - use distinct variabes when their use is unrelated.
One blank line should follow the declaration(s).
Hint: Sometimes you can create a block, i.e. add curly braces, to reduce the scope further.
For example to limit variable scope to a single `case` branch.
Variables with limited use may be declared at the point of first use. It makes PR-review easier (but that point is lost if the variable is used everywhere anyway).
##Initialisation
The pattern with "lazy initialisation" may be advantageous in the Configurator to speed up the start when the initialisation is "expensive" in some way.
In the FC, however, its always better to use some milliseconds extra before take-off than to use them while flying.
So don't use "lazy initialisation".
An explicit "init" function, is preferred.
##Data types
Be aware of the data types you use and do not trust implicit type casting to be correct.
Angles are sometimes represented as degrees in a float. Sometimes as decidegrees in a uint8_t.
You have been warned.
Avoid implicit double conversions and only use float-argument functions.
Check .map file to make sure no conversions sneak in, and use -Wdouble-promotion warning for the compiler
Instead of sin() and cos(), use sin_approx() and cos_approx() from common/math.h.
Float constants should be defined with "f" suffix, like 1.0f and 3.1415926f, otherwise double conversion might occur.
#Functions
##Naming
Methods that return a boolean should be named as a question, and should not change any state. e.g. 'isOkToArm()'.
Methods should have verb or verb-phrase names, like deletePage or save. Tell the system to 'do' something 'with' something. e.g. deleteAllPages(pageList).
Non-static functions should be prefixed by their class. Eg baroUpdate and not updateCompass .
Groups of functions acting on an 'object' should share the same prefix, e.g.
```
float biQuadFilterApply(...);
void biQuadFilterInit(...);
boolean biQuadIsReady();
```
rather than
```
float applyBiQuadFilter(...);
void newBiQuadLpf(...);
boolean isBiQuadReady();
```
##Parameter order
Data should move from right to left, as in memcpy(void *dst, const void *src, size_t size).
This also mimics the assignment operator (e.g. dst = src;)
When a group of functions act on an 'object' then that object should be the first parameter for all the functions, e.g.:
```
float biQuadFilterApply(biquad_t *state, float sample);
void biQuadNewLpf(biquad_t *state, float filterCutFreq, uint32_t refreshRate);
```
rather than
```
float biQuadFilterApply(float sample, biquad_t *state);
void biQuadNewLpf(float filterCutFreq, biquad_t *state, uint32_t refreshRate);
```
##Declarations
Functions not used outside their containing .c file should be declared static (or STATIC_UNIT_TESTED so they can be used in unit tests).
Non-static functions should have their declaration in a single .h file.
Don't make more than necessary visible for other modules, not even types. Pre-processor macros may be used to declare module internal things that must be shared with the modules test code but otherwise hidden.
In the .h file:
```
#ifdef MODULENAME_INTERNALS_
… declarations …
#endif
```
In the module .c file, and in the test file but nowhere else, put `#define MODULENAME_INTERNALS_` just before including the .h file.
Note: You can get the same effect by putting the internals in a separate .h file.
##Implementation
Keep functions short and distinctive.
Think about unit test when you define your functions. Ideally you should implement the test cases before implementing the function.
Never put multiple statements on a single line.
Never put multiple assignments on a single line.
Never put multiple assignments in a single statement.
Defining constants using pre-processor macros is not preferred.
Const-correctness should be enforced.
This allows some errors to be picked up at compile time (for example getting the order of the parameters wrong in a call to memcpy).
A function should only read data from the HW once in each call, and preferably all at one place.
For example, if gyro angle or time is needed multiple times, read once and store in a local variable.
Use `for` loops (rather than `do` or `while` loops) for iteration.
The use of `continue` or `goto` should be avoided.
Same for multiple `return` from a function and multiple `break` inside a `case`.
In general, they reduce readability and maintainability.
In rare cases such constructs can be justified but only when you have considered and understood the alternatives and still have a strong reason.
Use parentheses around each group in logical and mathematical statements,
rather than relying on the implicit logic and operator priority.
The compiler knows what its doing but it should be easy for people too.
#Includes
All files must include their own dependencies and not rely on includes from the included files or that some other file was included first.
Do not include things you are not using.
"[#pragma once](https://en.wikipedia.org/wiki/Pragma_once)" is preferred over "#include guards" to avoid multiple includes.
#Other details
No trailing whitespace at the end of lines or at blank lines.
Stay within 120 columns, unless exceeding 120 columns significantly increases readability and does not hide information.
(Less is acceptable. More than 140 makes it difficult to read on Github so that shall never be exceeded.)
Take maximum possible advantage of compile time checking, so generally warnings should be as strict as possible.
Don't call or reference "upwards". That is don't call or use anything in a software layer that is above the current layer. The software layers are not that obvious in Cleanflight, but we can certainly say that device drivers are the bottom layer and so should not call or use anything outside the device drivers.
Target specific code (e.g. #ifdef CC3D) should be absolutely minimised.
`typedef void handlerFunc(void);` is easier to read than `typedef void (*handlerFuncPtr)(void);`.
Code should be spherical.
That is its surface area (public interfaces) relative to its functionality should be minimised.
Which is another way of saying that the public interfaces shall be easy to use,
do something essential and all implementation should be hidden and unimportant to the user
Code should work in theory as well as in practice.
It should be based on sound mathematical, physical or computer science principles rather than just heuristics.
This is important for test code too. Tests shall be based on such principles and real-world properties so they don't just test the current implementation as it happens to be.
Guidelines not tramlines: guidelines are not totally rigid - they can be broken when there is good reason.

View file

@ -0,0 +1,70 @@
# Configuration Format
The configuration format and external protocol use some of the same concepts
as SAE J1939. A parameter group (PG) is a set of parameters belonging
to the same topic and are stored and sent together. A parameter group
instance has a unique parameter group number (PGN). Each parameter
also has a suspect parameter number (SPN) which can be used to get or
set a parameter directly.
When used as on-wire formats structures should be packed to give the
same in storage, in memory, and on-wire format. However care must be taken
over memory alignment issues when packing structures.
The PGs can be defined on a system-wide basis on a profile specific basis.
profiles can be activated on the fly.
The storage consists of a header, zero or more PGs, a footer and a checksum.
To keep the RAM usage low, the parameters are written directly to flash
which means that things that are only known at the end, such as the
size are stored in the footer. The checksum is written after the footer.
The header holds:
* The format number. This is bumped on incompatible changes.
Each stored PG holds:
* The size of this record
* The PGN
* Version number
* Profile number
* Flags
* The record format. This is bumped on incompatible changes.
* The PG data
The footer holds:
* A zero to mark the end of data
The checksum is based on the header, PGs, and footer.
The PG registrations hold similar but not identical information (e.g. the profile
number is not known until it is stored).
## Initialiion function.
All fields are reset to 0 upon initialisation and then if a reset function is
defined for the group then initial settings can be defined by the system.
## Upgrading
Upgrades are done at the PG level and are detected by a difference in
size or version. New fields can be added to the end of the parameter group.
The reset and initialisation function is called before upgrading so new
fields will first be reset to 0 and then initialised by the system if defined.
Note: Currently the code does not check the version field.
## Downgrading
Downgrades are done at the PG level. Any trailing, unrecognised
fields will be silently dropped on load. Saving the config back to
flash will discard these unrecognised fields.
## Incompatible changes
An incompatible change is where a field is inserted, deleted from the
middle, reordered, resized (including changing the size of a contained array),
or has the meaning changed. Such changes should be handled by bumping the
PG version field or allocating a new PGN.

View file

@ -0,0 +1,101 @@
# Configuration
The configuration in cleanflight is stored at the end of the flash ram, currently it uses 2-4KB of flash depending on the target.
Sometimes it's necessary to erase this during development.
## Erasing
Generate a 2-4kb blank file.
2kb:
```
dd if=/dev/zero of=obj/blankconfig.bin bs=1024 count=2
```
4kb:
```
dd if=/dev/zero of=obj/blankconfig.bin bs=1024 count=4
```
Overwrite configuration using JLink
Run JLink (OSX: `/Applications/SEGGER/JLink/JLinkExe`)
Execute commands
`device <your device>`, e.g. `STM32F303CB`
`r`
`h`
`loadbin obj/blankconfig.bin, <address>`
`r` to Reboot FC.
`q` to quit
the address is the address of the end of the flash ram minus the size of the configuration.
example addresses:
```
64k device/2kb config = 0x800F800
128k device/2kb config = 0x801F800
128k device/4kb config = 0x801F000
256k device/2kb config = 0x803f800
256k device/4kb config = 0x803f000
```
Example session
```
$ /Applications/SEGGER/JLink/JLinkExe
SEGGER J-Link Commander V4.90c ('?' for help)
Compiled Aug 29 2014 09:52:38
DLL version V4.90c, compiled Aug 29 2014 09:52:33
Firmware: J-Link ARM-OB STM32 compiled Aug 22 2012 19:52:04
Hardware: V7.00
S/N: -1
Feature(s): RDI,FlashDL,FlashBP,JFlash,GDBFull
VTarget = 3.300V
Info: Could not measure total IR len. TDO is constant high.
Info: Could not measure total IR len. TDO is constant high.
No devices found on JTAG chain. Trying to find device on SWD.
Info: Found SWD-DP with ID 0x2BA01477
Info: Found Cortex-M4 r0p1, Little endian.
Info: FPUnit: 6 code (BP) slots and 2 literal slots
Info: TPIU fitted.
Info: ETM fitted.
Cortex-M4 identified.
Target interface speed: 100 kHz
J-Link>device STM32F303CC
Info: Device "STM32F303CC" selected (256 KB flash, 32 KB RAM).
Reconnecting to target...
Info: Found SWD-DP with ID 0x2BA01477
Info: Found SWD-DP with ID 0x2BA01477
Info: Found Cortex-M4 r0p1, Little endian.
Info: FPUnit: 6 code (BP) slots and 2 literal slots
Info: TPIU fitted.
Info: ETM fitted.
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link>h
PC = 08001154, CycleCnt = 00000000
R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
R12= 00000000
SP(R13)= 2000A000, MSP= 2000A000, PSP= 00000000, R14(LR) = FFFFFFFF
XPSR = 01000000: APSR = nzcvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00
FPU regs: FPU not enabled / not implemented on connected CPU.
J-Link>loadbin obj/blankconfig.bin, 0x803f800
Downloading file [obj/blankconfig.bin]...
WARNING: CPU is running at low speed (7989 kHz).
Info: J-Link: Flash download: Flash programming performed for 1 range (2048 bytes)
Info: J-Link: Flash download: Total time needed: 1.254s (Prepare: 0.698s, Compare: 0.009s, Erase: 0.075s, Program: 0.405s, Verify: 0.005s, Restore: 0.059s)
O.K.
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link>q
```

137
docs/development/Development.md Executable file
View file

@ -0,0 +1,137 @@
# Development
This document is primarily for developers only.
## General principals
1. Name everything well.
2. Strike a balance between simplicity and not-repeating code.
3. Methods that start with the word 'find' can return a null, methods that start with 'get' should not.
4. Keep methods short - it makes it easier to test.
5. Don't be afraid of moving code to a new file - it helps to reduce test dependencies.
6. Avoid noise-words in variable names, like 'data' or 'info'. Think about what you're naming and name it well. Don't be afraid to rename anything.
7. Avoid comments that describe what the code is doing, the code should describe itself. Comments are useful however for big-picture purposes and to document content of variables.
8. If you need to document a variable do it at the declaration, don't copy the comment to the `extern` usage since it will lead to comment rot.
9. Seek advice from other developers - know you can always learn more.
10. Be professional - attempts at humor or slating existing code in the codebase itself is not helpful when you have to change/fix it.
11. Know that there's always more than one way to do something and that code is never final - but it does have to work.
Before making any code contributions, try to comply with the [coding style](CodingStyle.md). It has a lot of sound advice.
It is also advised to read about clean code, here are some useful links:
* http://cleancoders.com/
* http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29
* http://en.wikipedia.org/wiki/Code_smell
* http://en.wikipedia.org/wiki/Code_refactoring
* http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
## Unit testing
Ideally, there should be tests for any new code. However, since this is a legacy codebase which was not designed to be tested this might be a bit difficult.
If you want to make changes and want to make sure it's tested then focus on the minimal set of changes required to add a test.
Tests currently live in the `test` folder and they use the google test framework.
The tests are compiled and run natively on your development machine and not on the target platform.
This allows you to develop tests and code and actually execute it to make sure it works without needing a development board or simulator.
This project could really do with some functional tests which test the behaviour of the application.
All pull requests to add/improve the testability of the code or testing methods are highly sought!
Note: Tests are written in C++ and linked with with firmware's C code. All code is also instrumented using gcov to make test coverage analysis possible.
### Running the tests.
The tests and test build system is very simple and based off the googletest example files, it will be improved in due course. From the root folder of the project simply do:
```
make test
```
You can also do:
```
make junittest
```
This will build a set of executable files in the `obj/test` folder, one for each `*_unittest.cc` file.
It will stop after first compile/build error. If you want it to continue with the next test module you can use `make -k test`.
After they have been executed by the make invocation, you can still run them on the command line to execute the tests and to see the test report. Test reports will also be produced in form of junit XML files, if tests are built and run with the "junittest" goal. Junit report files are saved in obj/test directory and has the following naming pattern test_name_results.xml, for example: obj/test/battery_unittest_results.xml
You can also step-debug the tests in eclipse and you can use the GoogleTest test runner to make building and re-running the tests simple.
The tests are currently always compiled with debugging information enabled, there may be additional warnings, if you see any warnings please attempt to fix them and submit pull requests with the fixes.
Tests are verified and working with GCC 4.9.3
## Test coverage analysis
There are a number of possibilities to analyse test coverage and produce various reports. There are guides available from many sources, a good overview and link collection to more info can be found on Wikipedia:
https://en.wikipedia.org/wiki/Gcov
A simple report for a single test can for example be made using this command:
```
gcov -s src/main/sensors -o obj/test/ battery_unittest.cc
```
To produce an coverage report in xml format usable by the Cobertura plugin in Jenkins requires installation of a Python script called "gcovr" from github:
https://github.com/gcovr/gcovr/tree/dev
Example usage in Jenkins:
```
/gcovr-install-path/gcovr/scripts/gcovr obj/test --root=src/main -x > coverage.xml
```
There are many other ways to prodice test coverage reports in other formats, like html etc etc.
## Using git and github
Ensure you understand the github workflow: https://guides.github.com/introduction/flow/index.html
Please keep pull requests focused on one thing only, since this makes it easier to merge and test in a timely manner.
If you need help with pull requests there are guides on github here:
https://help.github.com/articles/creating-a-pull-request/
The main flow for a contributing is as follows:
1. Login to github, go to the cleanflight repository and press `fork`.
2. Then using the command line/terminal on your computer: `git clone <url to YOUR fork>`
3. `cd cleanflight`
4. `git checkout master`
5. `git checkout -b my-new-code`
6. Make changes
7. `git add <files that have changed>`
8. `git commit`
9. `git push origin my-new-code`
10. Create pull request using github UI to merge your changes from your new branch into `cleanflight/master`
11. Repeat from step 4 for new other changes.
The primary thing to remember is that separate pull requests should be created for separate branches. Never create a pull request from your `master` branch.
Once you have created the PR,
every new commit/push in your branch will propagate from your fork into the PR in the main github/cleanflight repo.
Checkout another branch first if you want something else.
Push will often fail if you edit or squash commits in a branch already pushed. Never do such things after creating the PR.
Later, you can get the changes from the cleanflight repo into your `master` branch by adding cleanflight as a git remote and merging from it as follows:
1. `git remote add cleanflight https://github.com/cleanflight/cleanflight.git`
2. `git checkout master`
3. `git fetch cleanflight`
4. `git merge cleanflight/master`
5. `git push origin master` is an optional step that will update your fork on github
You can also perform the git commands using the git client inside Eclipse. Refer to the Eclipse git manual.

View file

@ -0,0 +1,121 @@
# Hardware Debugging In Eclipse
Build a binary with debugging information using command line or via Eclipse make target.
Example Eclipse make target
![](assets/eclipse-gdb-debugging/make 1 - OLIMEXINO GDB.PNG)
# GDB and OpenOCD
start openocd
Create a new debug configuration in eclipse :
![connect to openocd](http://i.imgur.com/somJLnq.png)
![use workspace default](http://i.imgur.com/LTtioaF.png)
you can control openocd with a telnet connection:
telnet localhost 4444
stop the board, flash the firmware, restart:
reset halt
wait_halt
sleep 100
poll
flash probe 0
flash write_image erase /home/user/git/cleanflight/obj/cleanflight_NAZE.hex 0x08000000
sleep 200
soft_reset_halt
wait_halt
poll
reset halt
A this point you can launch the debug in Eclispe.
![](http://i.imgur.com/u7wDgxv.png)
# GDB and J Link
Here are some screenshots showing Hydra's configuration of Eclipse (Kepler)
If you use cygwin to build the binaries then be sure to have configured your common `Source Lookup Path`, `Path Mappings` first, like this:
![](assets/eclipse-gdb-debugging/config 7.PNG)
Create a new `GDB Hardware Debugging` launch configuration from the `Run` menu
It's important to have build the executable compiled with GDB debugging information first.
Select the appropriate .elf file (not hex file) - In these examples the target platform is an OLIMEXINO.
DISABLE auto-build
![](assets/eclipse-gdb-debugging/config 1.PNG)
Choose the appropriate gdb executable - ideally from the same toolchain that you use to build the executable.
![](assets/eclipse-gdb-debugging/config 2.PNG)
Configure Startup as follows
Initialization commands
```
target remote localhost:2331
monitor interface SWD
monitor speed 2000
monitor flash device = STM32F103RB
monitor flash download = 1
monitor flash breakpoints = 1
monitor endian little
monitor reset
```
![](assets/eclipse-gdb-debugging/config 3.PNG)
![](assets/eclipse-gdb-debugging/config 4.PNG)
It may be useful to specify run commands too:
```
monitor reg r13 = (0x00000000)
monitor reg pc = (0x00000004)
continue
```
![](assets/eclipse-gdb-debugging/config 13.PNG)
If you use cygwin an additional entry should be shown on the Source tab (not present in this screenshot)
![](assets/eclipse-gdb-debugging/config 5.PNG)
Nothing to change from the defaults on the Common tab
![](assets/eclipse-gdb-debugging/config 6.PNG)
Start up the J-Link server in USB mode
![](assets/eclipse-gdb-debugging/config 9.PNG)
If it connects to your target device it should look like this
![](assets/eclipse-gdb-debugging/config 10.PNG)
From Eclipse launch the application using the Run/Debug Configurations..., Eclipse should upload the compiled file to the target device which looks like this
![](assets/eclipse-gdb-debugging/config 11.PNG)
When it's running the J-Link server should look like this.
![](assets/eclipse-gdb-debugging/config 12.PNG)
Then finally you can use Eclipse debug features to inspect variables, memory, stacktrace, set breakpoints, step over code, etc.
![](assets/eclipse-gdb-debugging/debugging.PNG)
If Eclipse can't find your breakpoints and they are ignored then check your path mappings (if using cygwin) or use the other debugging launcher as follows. Note the 'Select other...' at the bottom of the configuration window.
![](assets/eclipse-gdb-debugging/config 8 - If breakpoints do not work.PNG)

View file

@ -0,0 +1,106 @@
# Hardware debugging
The code can be compiled with debugging information, you can then upload a debug version to a board via a JLink/St-Link debug adapter and step through the code in your IDE.
More information about the necessary hardware and setting up the eclipse IDE can be found [here](Hardware Debugging in Eclipse.md)
A guide for visual studio can be found here:
http://visualgdb.com/tutorials/arm/st-link/
This video is also helpful in understanding the proces:
https://www.youtube.com/watch?v=kjvqySyNw20
## Hardware
Various debugging hardware solutions exist, the Segger J-Link clones are cheap and are known to work on Windows with both the Naze and Olimexino platforms.
### J-Link devices
Segger make excellent debuggers and debug software.
The Segger J-Link GDB server can be obtained from here.
http://www.segger.com/jlink-software.html
#### Segger J-Link EDU EDU version, for hobbyists and educational use.
![Segger J-Link EDU](assets/hardware/j-link-edu.jpg)
https://www.segger.com/j-link-edu.html
#### USB-MiniJTAG J-Link JTAG/SWD Debugger/Emulator
http://www.hotmcu.com/usbminijtag-jlink-jtagswd-debuggeremula%E2%80%8Btor-p-29.html?cPath=3_25&zenid=fdefvpnod186umrhsek225dc10
![THAOYU USB-MiniJTAG](assets/hardware/THAOYU-USB-MiniJTAG.jpg)
##### ARM-JTAG-20-10 adapter
https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-20-10/
http://uk.farnell.com/jsp/search/productdetail.jsp?sku=2144328
![OLIMEX ARM JTAG ADAPTER](assets/hardware/OLIMEX-ARM-JTAG-ADAPTER-2144328-40.jpg)
#### CJMCU-STM32 Singlechip Development Board Jlink Downloader Jlink ARM Programmer
![CJMCU-STM32 Jlink ARM Programmer Front](assets/hardware/cjmcu-jlink-front.jpg)
![CJMCU-STM32 Jlink ARM Programmer Back](assets/hardware/cjmcu-jlink-back.jpg)
http://www.goodluckbuy.com/cjmcu-stm32-singlechip-development-board-jlink-downloader-jlink-arm-programmer.html
### STLink V2 devices
STLink V2 devices can be used too, via OpenOCD.
#### CEPark STLink V2
![CEPark STLink V2](assets/hardware/cepark-stlink-v2-front.jpg)
http://www.goodluckbuy.com/cepark-stlink-st-link-v2-emulator-programmer-stm8-stm32-downloader.html
## Compilation options
use `DEBUG=GDB` make argument.
You may find that if you compile all the files with debug information on that the program is too big to fit on the target device. If this happens you have some options:
* Compile all files without debug information (`make clean`, `make ...`), then re-save or `touch` the files you want to be able to step though and then run `make DEBUG=GDB`. This will then re-compile the files you're interested in debugging with debugging symbols and you will get a smaller binary file which should then fit on the device.
* You could use a development board such as an PORT103R, development boards often have more flash rom.
## OSX
### Install OpenOCD via Brew
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install openocd
### GDB debug server
#### J-Link
##### Windows
Run the Launch the J-Link GDB Server program and configure using UI.
#### OpenOCD
##### Windows
STM32F103 targets
"C:\Program Files (x86)\UTILS\openocd-0.8.0\bin-x64\openocd-x64-0.8.0.exe" -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg
STM32F30x targets
"C:\Program Files (x86)\UTILS\openocd-0.8.0\bin-x64\openocd-x64-0.8.0.exe" -f scripts\board\stm32f3discovery.cfg
##### OSX/Linux
STM32F30x targets
openocd -f /usr/share/openocd/scripts/board/stm32vldiscovery.cfg

View file

@ -0,0 +1,63 @@
### IO variables
`gyroADC/8192*2000 = deg/s`
`gyroADC/4 ~ deg/s`
`rcCommand` - `<-500 - 500>` nominal, but is scaled with `rcRate/100`, max +-1250
`inclination` - in 0.1 degree, roll and pitch deviation from horizontal position
`max_angle_inclination` - in 0.1 degree, default 50 degrees (500)
`axisPID` - output to mixer, will be added to throttle(`<1000-2000>`), output range is `<minthrottle, maxthrottle>` (default `<1150 - 1850>`)
### PID controller 0, "MultiWii" (default)
#### Leveling term
```
error = constrain(2*rcCommand[axis], limit +- max_angle_inclination) - inclination[axis]
Pacc = constrain(P8[PIDLEVEL]/100 * error, limit +- 5 * D8[PIDLEVEL])
Iacc = intergrate(error, limit +-10000) * I8[PIDLEVEL] / 4096
```
#### Gyro term
```
Pgyro = rcCommand[axis];
error = rcCommand[axis] * 10 * 8 / pidProfile->P8[axis] - gyroADC[axis] / 4; (conversion so that error is in deg/s ?)
Igyro = integrate(error, limit +-16000) / 10 / 8 * I8[axis] / 100 (conversion back to mixer units ?)
```
reset I term if
- axis rotation rate > +-64deg/s
- axis is YAW and rcCommand>+-100
##### Mode dependent mix(yaw is always from gyro)
- HORIZON - proportionally according to max deflection
```
deflection = MAX(ABS(rcCommand[PITCH]), ABS(rcCommand[ROLL])) / 500 ; limit to 0.0 .. 1.0
P = Pacc * (1-deflection) + Pgyro * deflection
I = Iacc * (1-deflection) + Igyro * deflection
```
- gyro
```
P = Pgyro
I = Igyro
```
- ANGLE
```
P = Pacc
I = Iacc
```
#### Gyro stabilization
```
P -= gyroADC[axis] / 4 * dynP8 / 10 / 8
D = -mean(diff(gyroADC[axis] / 4), over 3 samples) * 3 * dynD8 / 32
[equivalent to :]
D = - (gyroADC[axis]/4 - (<3 loops old>gyroADC[axis]/4)) * dynD8 / 32
```
This can be seen as sum of
- PI controller (handles rcCommand, HORIZON/ANGLE); `Igyro` is only output based on gyroADC
- PD controller(parameters dynP8/dynD8) with zero setpoint acting on gyroADC

View file

@ -0,0 +1,11 @@
#Travis
Cleanflight provides Travis build and config files in the repository root.
## Pushing builds to a remote server
```.travis.sh``` script can upload build artifacts to a remote server. This feature is controlled by the
```PUBLISH_URL``` environment variable. If set, the build script will use the cURL binary and simulate
a file upload post to the configured server.
Pleas check the ```notifications``` section in the ```.travis.yml``` file and adjust the irc notifications if you plan on using Travis on your Cleanflight fork

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB