SlideShare ist ein Scribd-Unternehmen logo
1 von 106
Downloaden Sie, um offline zu lesen
University of Technology, Sydney
Faculty of Engineering and Information Technology
DEVELOPMENT OF A MODERNISED SOFTWARE PLATFORM
FOR AN EDUCATIONAL ROBOT
Christopher James Kerr
Student Number: 10826598
Project Number: S13-123
Major: Electrical Engineering
Supervisor: Dr Peter McLean
A 12 Credit Point Project submitted in partial fulfilment of the requirements for
the Degree of Bachelor of Engineering
20 June 2014
Christopher Kerr
ii
STATEMENT OF ORIGINALITY
I, Christopher James Kerr, hereby declare that I am the sole author of this report.
I assert that:
 All work shown in the body of this report is my own
 All Appendices have been properly attributed to their original author
 All theories, ideas, and results of others have been correctly referenced
 All sources of assistance have been acknowledged by name in this report
Please be aware that some small samples of code have been reused from a
previous subject, 48434 Embedded Software. This code comprises an
insignificant portion of the finished project.
I must also acknowledge that this project is substantially based on the source
code of the original Maze Rover, developed and supplied by Dr Peter McLean.
Appendix B contains material created in collaboration with other students in
48580 Advanced Control, during the Autumn 2014 semester. They have been
acknowledged at the beginning of that chapter. However, I wish to clarify that the
related work presented in Chapter 7: “Control Implementation” is entirely mine.
Signed: __________________________________________
Christopher James Kerr
Date: 20 June 2014
Christopher Kerr
iii
ABSTRACT
In 48540 Signals and Systems, a robot platform, called the “Maze Rover”, is used
to teach signal and control theory concepts to Electrical Engineering students.
This robot is built upon obsolete technology, and a replacement is under
development.
The current Maze Rover platform is based upon the Freescale MC9S12A512, a 16-
bit fixed-point microcontroller. Whilst this chip is very capable, its current
application as the controller for the “Maze Rover” pushes its capabilities to the
limit, leaving no capacity for future expansion of features.
The new platform is built on a Freescale Kinetis 32-bit microcontroller, which
provides vastly improved performance and a number of additional capabilities.
This project demonstrates the reimplementation of the Maze Rover software on
this new platform, performed in C99 using the Freescale CodeWarrior toolchain.
A literature review of best practices in embedded development was conducted,
leading to the development of an Embedded Software Coding Standard. This
standard has been extensively documented and rigorously adhered to, to
demonstrate the development of high-reliability embedded software.
The core of the project is the development of a Hardware Abstraction Layer
(HAL) for this new platform. The HAL provides serial communications via UART
and SPI, data acquisition, analogue output, and EEPROM emulation. It
demonstrates the application of several interesting features of the new platform,
including the highly configurable hardware SPI implementation and use of the
Direct Memory Access peripheral.
The project also implements the original Maze Rover features, including
modulated wave synthesis, tone detection, and a phase locked loop. These
features have been tested to be functionally identical to the original platform.
Future development may extend this work by implementing a real-time
operating system. The new platform’s improved speed provides ample capacity
to run additional tasks, such as driving an LCD-based Human-Machine Interface
or performing network communications over TCP/IP.
Christopher Kerr
iv
ACKNOWLEDGEMENTS
I would like to acknowledge the support of Dr Peter McLean, whose excellent
teaching has kept me sane over the course of this degree. I must also acknowledge
that this project is substantially based on the source code of the original Maze
Rover, developed and supplied by Dr McLean, and I thank him for this resource.
My friends at UTS are owed thanks for putting up with me, far more than I
deserved! It’s been a long degree and I couldn’t have done it without you.
Finally, I express the utmost gratitude for my family, who have supported me in
more ways than I could possibly count.
ACKNOWLEDGEMENT OF PRIOR WORK
The Analog Interface board used in this project was designed during a previous
capstone project by Rosario Vambuca. Rosario provided the assembled board and
its design schematics for this project.
I must also acknowledge that this project is substantially based on the source
code of the original Maze Rover, developed and supplied by Dr Peter McLean.
Appendix B contains material created in collaboration with other students in
48580 Advanced Control, during the Autumn 2014 semester. They have been
acknowledged at the beginning of that chapter.
Christopher Kerr
v
TABLE OF CONTENTS
Statement of Originality...............................................................................................................ii
Abstract ............................................................................................................................................ iii
Acknowledgements.......................................................................................................................iv
List of figures...................................................................................................................................vi
1 Introduction ............................................................................................................................1
2 Embedded C Code Quality .................................................................................................5
3 Project Setup........................................................................................................................15
4 Hardware Abstraction Layer.........................................................................................25
5 High Level Functionality .................................................................................................43
6 Communication Lab Testing..........................................................................................49
7 Control Implementation..................................................................................................55
8 Conclusions...........................................................................................................................63
References......................................................................................................................................67
Table of Appendices ...................................................................................................................69
Christopher Kerr
vi
LIST OF FIGURES
Figure 1: The ModCon Board.....................................................................................................1
Figure 2: Freescale Tower System (Freescale, 2012) ......................................................2
Figure 3: New Project Options 1............................................................................................ 15
Figure 4: Language and Build Tools Options.................................................................... 16
Figure 5: Extract from CodeWarrior Edition Comparison Table.............................. 17
Figure 6: Download Size Limit Error (Styger, 2012)..................................................... 17
Figure 7: Librarian Model Setting for C99 ......................................................................... 18
Figure 8: Kinetis Clocking Overview (Freescale Semiconductor, 2011)................ 22
Figure 9: MCG State Diagram.................................................................................................. 23
Figure 10: PUSHR Register Layout....................................................................................... 28
Figure 11: Analog Interface Board Top Level Schematic (Vambuca, 2013)......... 29
Figure 12: ModCon Analog Interface Breakout Panel................................................... 30
Figure 13: AD7609 Serial Timing (Analog Devices, 2013, p. 10).............................. 31
Figure 14: AD7609 Acquisition Timing (Analog Devices, 2013, p. 9)..................... 33
Figure 15: AD5754R Serial and Load Timing................................................................... 34
Figure 16: DAC Input Register Layout (Analog Devices, 2011, p. 26)..................... 34
Figure 17: DAC Input Loading (Analog Devices, 2011, p. 22).................................... 35
Figure 18: Schematic Extract Showing Reset 0Ω Link (Freescale, 2011).............. 36
Figure 19: Major and Minor Loops in DMA Requests (Freescale, 2011)............... 37
Figure 20: Eeprom_Write Logic Flowchart ....................................................................... 41
Figure 21: Serial Protocol Packet Structure...................................................................... 43
Figure 22: Coherent Demodulation Scheme..................................................................... 47
Figure 23: SSB-Lower Time Domain.................................................................................... 49
Figure 24: SSB-Lower Frequency Domain......................................................................... 49
Figure 25: SSB-Upper Time Domain .................................................................................... 50
Figure 26: SSB-Upper Frequency Domain......................................................................... 50
Figure 27: SSB-HI Time Domain............................................................................................ 51
Figure 28: SSB-HI Frequency Domain................................................................................. 51
Figure 29: Voltage Controlled Oscillator Characteristic............................................... 52
Figure 30: Phase-Locked Loop Operation.......................................................................... 53
Figure 31: Demodulated Message Signal Time Domain............................................... 54
Figure 32: Demodulated Message Signal Frequency Domain.................................... 54
Figure 33: Quanser MAGLEV Apparatus ............................................................................ 55
Figure 34: Control Module Overview .................................................................................. 56
Figure 35: Non-Inverting Op-amp Buffer........................................................................... 58
Figure 36 : Controller Architecture...................................................................................... 59
Figure 37 : Feedforward Current Relationships.............................................................. 60
Figure 38 : Lab Response to Step Input.............................................................................. 61
Figure 39 : Lab Tracking of Triangle Wave Input ........................................................... 62
Figure 40 : Lab Rejection of External Disturbance......................................................... 62
Christopher Kerr
vii
NOMENCLATURE
ADC Analog to Digital Converter
DAC Digital to Analog Converter
DMA Direct Memory Access
EEPROM A type of Non-Volatile Memory
Flash NAND Flash, a type of Non-Volatile Memory
ISR Interrupt Service Routine
LSB Least Significant Bit/Byte
Maze Rover An educational robotics platform used at UTS
MCG Master Clock Generator
ModCon Modular Controller microcontroller board
MSB Most Significant Bit/Byte
NVM Non-Volatile Memory
PLL Phase-Locked Loop
RAM, SRAM Random Access Memory. Volatile memory type.
RX Receive
SPI Serial Peripheral Interface
TCD Transmission Control Descriptor (for DMA)
TX Transmit
UART Universal Asynchronous Reciever/Transmitter
UTS University of Technology, Sydney
VCO Voltage Controlled Oscillator
Table 1: Project Nomenclature
Chapter 1: Introduction Christopher Kerr
Background
1
1 INTRODUCTION
1.1 BACKGROUND
At the University of Technology, Sydney (UTS), engineering is taught with a
practice-based curriculum. Theoretical concepts learnt in lectures are reinforced
by application in the laboratory.
At present a robot platform, called the “Maze Rover”, is used in 48540 “Signals
and Systems” to teach signal theory concepts to Electrical Engineering students.
The core of this device is a microcontroller board called ModCon (MODular
CONtroller), a flexible platform deployed in laboratories for several subjects.
ModCon acts as the “brain” of the robot, controlling its functionality. Whilst in
other subjects ModCon is user-programmable, its use in the Maze Rover is strictly
as an embedded appliance running preloaded firmware.
1.2 PROJECT OVERVIEW
Figure 1: The ModCon Board
The microcontroller used on the ModCon (the large black microchip visible in
Figure 1) is obsolete, and a replacement microcontroller board (ModCon 2.0) has
been developed to modernise the platform. This has prompted the design of a
new revision of the Maze Rover robot (Maze Rover 2.0) built around ModCon 2.0.
This project involves the development of the control software for that
Chapter 1: Introduction Christopher Kerr
Technical Outline
2
replacement robot. The purpose of this project is replicate the capabilities of the
current Maze Rover using a development prototype of Maze Rover 2.0. During
this process a methodology for development of high-quality embedded software
will be developed and explored.
1.3 TECHNICAL OUTLINE
The current ModCon platform is based upon an obsolete device, the Freescale
MC9S12A512, a 16-bit fixed-point microcontroller with a 25MHz clock, 512KB of
non-volatile Flash storage, 14KB of RAM and many peripherals and interfaces.
Whilst this chip is very capable, its current application as the controller for the
Maze Rover pushes its capabilities to the limit.
ModCon 2.0 is based on a modern device, the Freescale MK50DX256CLL10. A
member of the Kinetis K50 family, this device uses a 32-bit ARM Cortex-M4 core
clocked at up to 100MHz. The specific model chosen provides 256KB of Flash
storage and 128KB of RAM.
At the commencement of this project, the final ModCon 2.0 hardware was not
available, so development was performed using a Freescale Kinetis
TWR-K70F120M development board. This development board is designed to
integrate into the Freescale Tower System (shown in Figure 2), which provides a
modular system for development of embedded projects. In this project, an Analog
Interface Board developed by a previous student is used as a tower peripheral.
Figure 2: Freescale Tower System (Freescale Semiconductor, 2012)
Chapter 1: Introduction Christopher Kerr
Project Goals
3
The TWR-K70F120M module is designed around the high-end Freescale
MK70FN1M0VMJ12. This model provides a number of additional capabilities
when compared to K50 family devices, including a hardware floating-point unit.
For the purposes of developing software for Maze Rover 2.0 the use of these
features has been restricted. Where the development of this project diverges
from the limitations imposed by a K50 family device, a note has been made to aid
future development.
1.4 PROJECT GOALS
The goal of this project is to completely re-implement the functionality of the
existing Maze Rover firmware on a prototype of the ModCon 2.0 platform. Major
functionality units of the Maze Rover firmware (as deployed in Signals and
Systems) to be re-implemented include:
 Hardware Abstraction Layer
o SPI and UART interface drivers
o Analogue Inputs and Outputs
o Periodic timers
o Low level functions such as clock generation
 Serial Communications Protocol
 Discrete Fourier Transform
 Phase Locked Loop, including
o Numerically controlled oscillator
 Generation of modulated waveforms
 Demodulation of acquired waveforms
It also features a Model Reference Adaptive Motor Controller. This advanced
controller is applied transparently, such that the complex transfer function of the
Maze Rover’s motor appears to be a simple first order system when measured
without an external controller. This allows for a relatively simple controller to be
developed by students in “Signals and Systems” using the first order model
developed from the observed system.
As finalised Maze Rover 2.0 hardware was not available during the development
of this project, an alternative control task was implemented on this platform
using Quanser MAGLEV apparatus, demonstrating the viability of ModCon 2.0 for
performing complex control tasks.
Chapter 1: Introduction Christopher Kerr
Document Outline
4
1.5 DOCUMENT OUTLINE
Chapter 2: Literature review – Embedded C Code Quality
An overview of research conducted prior to commencing software development
for this project, including a discussion of code quality and its applicability in an
embedded software project.
Chapter 3: Project Setup
Getting started with the Freescale Codewarrior toolchain and understanding the
fundamentals of the Freescale Kinetis architecture.
Chapter 4: Hardware Abstraction Layer
Understanding the hardware of the Maze Rover 2.0 platform, and implementing
drivers for its UART, Periodic Timers and Analog Input/Output systems.
Chapter 5: High Level Functionality
Design and implementation of the Maze Rover 2.0’s application-specific software,
including the ModCon serial protocol and the Signals and Systems
communication functions.
Chapter 6: Communication Lab Testing
Verification of the Maze Rover 2.0’s ability to replicate the communications
functions of the original Maze Rover.
Chapter 7: Control Implementation
Implementation details and test results for a control system implemented using
the prototype Maze Rover 2.0 platform.
Chapter 8: Conclusions
A discussion of the final status of the project. A subsection on further work gives
an outline of the work required to use this project’s results in the Signals and
Systems laboratory, and suggestions for potential future refinements.
Chapter 2: Embedded C Code Quality Christopher Kerr
Defining Quality Code
5
2 EMBEDDED C CODE QUALITY
2.1 DEFINING QUALITY CODE
For the purposes of this project, we shall consider quality code to be:
Stable: The software should have no known bugs, and all necessary
precautions must be taken to avoid introducing common errors.
Maintainable: The intent of code must be clear to the reader, and the
code’s purpose in the larger system must be thoroughly documented.
Portable: The code should not make unnecessary assumptions about
the underlying architecture or compiler, to permit porting between systems.
2.2 THE NEED FOR QUALITY CODE IN EMBEDDED SYSTEMS
The embedded environment is fundamentally different from the personal
workstation environment with which most programmers are familiar. The
operation of embedded systems is largely autonomous and unsupervised. In a
workstation environment some kinds of failure are annoying, but acceptable –
programs become unresponsive or crash, but the user is there to restart them.
This is not typically the case for an embedded system, where the user has little
awareness or control over the internal state of the system.
Furthermore, many embedded systems control safety-critical processes, such as
automobiles and industrial automatons. In this environment, unreliable software
can result in injury or death. Unfortunately, this is not hypothetical – in the 1980’s
at least three deaths were inflicted by Therac-25 radiation therapy machines,
which suffered from a race condition in a safety interlock. During the first Gulf
War, 28 US soldiers were killed when a Patriot Missile system failed to destroy a
SCUD missile because of a poorly designed timekeeping system which compared
incompatible data formats. More recently, it has been argued that some of the
“unintended acceleration” issues affecting the Toyota Camry may have been
caused by faulty software and inadequately designed fail-safes.
Chapter 2: Embedded C Code Quality Christopher Kerr
The C Programming Language
6
2.3 THE C PROGRAMMING LANGUAGE
The C programming language is a popular choice for embedded software
development. Firstly, and most prosaically, it is often the only high-level language
with a supported toolchain for the target microcontroller architecture.
Conversely, few (if any) architectures support another high-level language but do
not support C. This makes C the de facto choice when code portability is required
or desirable. Secondly, C provides an appropriately minimalist level of
abstraction. The higher level languages currently popular on desktop computers,
such as Java and Python, do not provide good support for fast hardware I/O
operations, whereas C's arrays, structs, and bitfields translate neatly to low-level
manipulation of hardware.
Unfortunately, as a language, the C standard tends towards permissiveness. It is
certainly possible to write code which will compile as valid C despite being
difficult to understand, perverse, or not correctly reflecting the intentions of the
programmer. For instance, C has a system of type promotions which, ultimately,
permits a floating point number to be assigned to a boolean variable.
Furthermore, many edge cases in the C standard are “implementation defined”,
resulting in unpredictable program operation across compilers and
architectures.
Other sections of the language are well defined but prone to programmer error.
A misplaced semicolon after the declaration of a for loop or the test in an if
statement can completely alter the intended logical flow without causing
compilation errors. It is very easy to mistype the assignment operator = in place
of the comparison operator == (or vice versa) and in most cases these
substitutions still produce valid C. The operator precedence rules in C are
particularly notorious for their illogical design – the bitwise operators | and &
have lower rank than the comparison operator ==. This results in errors when
evaluating simple expressions such as:
if (x & y == 0)
In this example, most readers would assume the intended logic to be:
if ((x & y) == 0)
Chapter 2: Embedded C Code Quality Christopher Kerr
The C Programming Language
7
However, C’s operator precedence rules have this result:
if (x & (y == 0))
Finally, we should consider that the same feature that originally made C
attractive, its minimal abstraction, can also be a hazard at runtime. C assumes that
programmers know what they are doing, and does not protect against run time
errors such as division by zero or dereferencing of invalid pointers.
Given these limitations of C, it is clear that the language must be applied carefully
when used for embedded systems. Used without restriction, C has features which
can negatively impact the stability, maintainability, and portability of code,
resulting in poor code quality.
A subtle but important consideration is the version of the C language used.
Modern compilers support two main options – ANSI C (commonly known as C89,
and published as ISO/IEC 9899:1990) and C99 (ISO/IEC 9899:1999). C99 was
recently withdrawn by the International Standards Organisation in favour of C11,
a new standard ratified in 2011, but compiler support for this standard is
essentially non-existent at this time.
Until relatively recently it was common to advise against the use of C99 (as of
2004, no commercial compiler supported C99), but it is now well supported by
most C compilers. C99 brings valuable features to the C language, such as:
 The ability to mix declarations and code, i.e. to declare a variable at any
point in a function,
 The first expression in a for loop may be a declaration, as in C++,
 The inline keyword, which hints to the compiler that a function should be
included inline rather than called
 Support for a Boolean type,
 C++ style // one line comments,
 More flexible initialisation of arrays and structs.
The utility of these features is seen as sufficient justification for the use of C99.
Chapter 2: Embedded C Code Quality Christopher Kerr
Best Practices in Embedded Development
8
2.4 BEST PRACTICES IN EMBEDDED DEVELOPMENT
2.4.1 LITERATURE REVIEW
In order to develop a suitable coding standard for this project, I conducted a
review of the existing literature on embedded development using the C
programming language.
The following titles should be considered representative rather than exhaustive.
Many alternative coding standards exist.
2.4.2 MISRA-C:2004 (MIRA LIMITED, 2004)
“MISRA-C:2004 – Guidelines for the use of the C language in critical systems” is
primarily interested in addressing the reliability of embedded systems. Published
by the Motor Industry Software Reliability Association for application in the
automotive industry, MISRA-C is a highly restrictive coding standard which
defines a “safe” subset of the C programming language.
MISRA-C recognises the utility of the C programming language, but seeks to
eliminate the insecurities inherent to the language by defining a rule set
amenable to enforcement by static analysis tools.
Rules in MISRA-C are classified as either “Required” or “Advisory”. In order to
claim to be compliant with MISRA-C, all required rules must be followed.
Advisory rules are considered to be less important – it is not necessary to follow
any advisory rule, but it is strongly recommended that they be considered.
Required rules largely deal with eliminating the use of language features whose
behaviour (under C89) is unspecified, undefined, or implementation defined. Use
of such features can result in unintended behaviour, especially when porting
between compilers or architectures. Note that several required rules also
explicitly ban the use of C99 features – these rules are known to be retracted in
MISRA-C:2012, but no copy of that document could be located for review.
Further rules aim to restrict cases where C is considered to be overly permissive.
For instance, it is permissible in C for the same identifier to be used for both a
typedef name and a variable name. This is potentially confusing, so reuse of a
typedef name is banned by Rule 5.3.
Chapter 2: Embedded C Code Quality Christopher Kerr
Best Practices in Embedded Development
9
Advisory rules are typically stricter cases of required rules. For instance, where
Rule 5.3 (required) bans the reuse of typedef names, and Rule 5.2 (required) bans
naming reusing a variable name such that a variable in the current scope hides a
variable in outer scope, Advisory Rule 5.7 issues a blanket ban on reuse of any
identifier regardless of namespace or scope.
The vast majority of the recommendations made by MISRA-C:2004 are sensible
and practical, but some specific Rules are considered to be too strict for
practicality in a typical embedded system. For example, Rule 14.7 requires that
functions have a single point of return. Such a rule can significantly complicate
the design of functions which should return early in case of error. Rule 17.1
forbids the use of pointer arithmetic outside of array addressing, a restriction
which is unhelpful when addressing hardware registers known to be at a
particular offset from a peripheral base address.
Portability is addressed by MISRA-C in an indirect but conclusive manner – by
banning the use of all non-standard language extensions and eliminating all
aspects of the language which are poorly defined, portability is guaranteed.
However, considering the thoroughly considered nature of the MISRA-C:2004
rule set, it shall be considered as a definitive reference – any explicit contradiction
of MISRA-C rules shall be documented in the developed coding standard.
2.4.3 BARR GROUP EMBEDDED C CODING STANDARD (BARR, 2013)
The Barr Group standard may be considered as a companion text to
MISRA-C:2004. Where the two documents overlap they are largely compatible –
the only significant difference is the adoption of C99 and its features. However,
the Barr Group standard moves beyond examining language features to concern
itself with style, and thus concerns itself largely with code maintainability.
The author’s hypothesis is that many bugs are introduced by maintenance
programmers, and that these bugs may be reduced by “the disciplined use of
consistent commenting and stylistic practices”. Style is a highly personal aspect
of coding, but I acknowledge that code does not belong to the original author, but
to those future programmers who will maintain it. As such, it follows that there
is value in a strictly codified style to maximise consistency.
Chapter 2: Embedded C Code Quality Christopher Kerr
Best Practices in Embedded Development
10
The Barr Group standard is exhaustive in its codification of style. It incorporates
all the usual features of a style guide – naming conventions, rules for the
placement of braces, guidelines for comments and so on – but goes much further,
rigorously defining the acceptable use of whitespace.
This document is much easier to follow than MISRA-C, taking a more colloquial
style. It uses a clear and logical structure, with chapters based on common
language features (Procedures, Variables, Expressions, and so on). It thus serves
as a useful model for this project’s coding standard. This is permitted by the legal
notices of the document, requiring only the inclusion of a particular paragraph
from that section.
I chose to adapt this standard, rather than adopting it wholesale, for three
reasons: firstly, much of the document is concerned with style, and style is highly
personal. I would prefer to enforce my own style, and thus will codify it using this
document as a template. Secondly, there are points of significant disagreement
between this document and the Embedded Software Style Guide discussed in
section 2.4.5, and I am aware that many of my own conventions were strongly
influenced by that document. Adaptation has permitted the reconciliation and
incorporation of useful material from the Embedded Software Style Guide.
Finally, I believe that rewriting the standard has provided a deep familiarity with
the details of the result, superior to that gained by simply examining a document
prepared by another person.
2.4.4 THE ART OF DESIGNING EMBEDDED SYSTEMS (GANSSLE, 2008)
The Art of Designing Embedded Systems concerns itself with the entire process
of embedded software development. It is largely unsuccessful – it covers a wide
variety of topics in scattershot fashion, with topics ranging from debouncing to
team management philosophies. However, it does contain a thorough discussion
of quality code that informed this project, and Appendix A presents a Firmware
Standard.
By comparison to the previous two documents, this standard is dreadful –
imprecise, incomplete, and laden with bizarrely specific advice. Much of it is
copied verbatim from the discussion of code quality in Chapter 3. Jack Ganssle is
Chapter 2: Embedded C Code Quality Christopher Kerr
Best Practices in Embedded Development
11
a highly respected embedded software engineer. The high quality of his published
articles and essays led me to review this text, but in review it is clear that this
book is largely assembled from summaries of Ganssle’s previous writing. The
longer form is used here merely to cover more topics rather than discuss topics
in greater depth.
The value in The Art of Designing Embedded Systems is not in its coding standard,
but in its discussions of code quality and particularly encapsulation. In this
context, encapsulation is taken to be the pattern of design which avoids global
variables by preferring C++-style Get and Set functions in the public interface of
a module. This pattern is useful, and not idiomatic in C.
The Art of Designing Embedded Systems is also notable for being the text that
originally drew my attention to the very useful MISRA-C standard reviewed in
section 2.4.2.
2.4.5 48434 EMBEDDED SOFTWARE: SOFTWARE STYLE GUIDE (MCLEAN, 2013)
Peter McLean’s Software Style Guide is included in this review for two reasons.
Firstly, it was my first exposure to a formalised coding standard, and has thus
influenced some of my most fundamental assumptions about coding style.
Secondly, it loosely describes the style used in the existing Maze Rover codebase.
The Software Style Guide was not written until several years after the Maze Rover
firmware, but the common ancestry of their respective styles is clearly apparent.
This style guide is concerned almost entirely with consistency, in the interest of
maintainability. It is less comprehensive than the Barr Group standard, giving
more general guidelines than specific rules. The Software Style Guide is a more
human document, giving guidance as to what a programmer “should” do rather
than forbidding the use of the incorrect version. This is because it is designed for
enforcement by a human reader, rather than a software static analysis tool.
From this document, I have adopted many of the naming convention and code
structure rules, and much of its advice on coding best practices such as scope
limitation (data hiding) and const correctness.
Chapter 2: Embedded C Code Quality Christopher Kerr
Best Practices in Embedded Development
12
One notable conflict relates to single-line conditional or loop constructs, such as:
if (y < z)
x = y;
The Software Style guide requires the format shown above, without braces, but
with the following line indented as if it were wrapped in braces. The Barr Group
argues against this style, on the basis that single-line conditional constructs are
often expanded into multi-line conditional blocks. This introduces the potential
for error – the braces may not be added, and the indenting may trick the reading
into believe the braces are present. Instead, they require the following style, in
which even single lines are wrapped with braces:
if (y < z)
{
x = y;
}
This has the potential to prevent error, but adds two lines of mostly empty space
to every such construct. It does however have a beneficial effect on
documentation, as it removes the pressure to force a comment to fit in the space
available to the right of the single line.
In the original draft of my coding standard, I had preferred the Software Style
Guide approach, as I believe the more concise form is easier to read. However,
during the development of this project, I became aware of a bug discovered in
Apple Inc.’s SSL implementation, which affected a range of platforms, including
arguably embedded devices such as their iPhone mobile phones.
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; // << duplicated line
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
The bug consists of a single duplicated line, which thanks to the omitted braces is
unconditionally executed unless the preceding test has failed. A goto sends
execution directly to a label named “fail”, bypassing several tests. Worse, the “fail”
label leads to logic which does not always signal failure - it is simply the function
Chapter 2: Embedded C Code Quality Christopher Kerr
The Maze Rover Embedded C Coding Standard
13
return, which returns the error code in the err variable. As no error has yet
occurred, this causes the function to prematurely return without error.
Reading about this error (“GotoFail”), and a similar error involving a case
statement found in the OpenSSL codebase (“Heartbleed”) has changed my
position on the inclusion of such braces, and the final revision of my coding
standard requires them unconditionally.
2.5 THE MAZE ROVER EMBEDDED C CODING STANDARD
The resulting document can be reviewed in Appendix A. It contains discussions
of the rationale behind interesting, complex, or unintuitive rules, and has been
footnoted with justifications for diverging from MISRA-C:2004 and the Barr
Group coding standard.
Chapter 3: Project Setup Christopher Kerr
Freescale CodeWarrior
15
3 PROJECT SETUP
3.1 FREESCALE CODEWARRIOR
Freescale CodeWarrior Development Studio is an Integrated Development
Environment (IDE) for Freescale microcontroller products. The latest major
version, CodeWarrior 10, takes the form of modular plugins running in the
popular open-source Eclipse IDE. The CodeWarrior IDE provides a complete
environment for development of Kinetis applications; including wizard-driven
project creation, a modern code editor, a Flash programmer, and a well-featured
debugger.
Development for this project was conducted using CodeWarrior 10.4 (later 10.5)
Special Edition, which is available at no cost but imposes a code size limit of
128KB for Kinetis K-series devices. This limit was not significant for this project
– the final optimised executable is well under 20KB, and this includes known
inefficiencies which were not addressed because they did not affect run-time
performance.
3.1.1 STARTING A CODEWARRIOR PROJECT
Starting a new project in CodeWarrior (File>New>Bareboard Project) firsts
prompts for a name and location, then for the target processor (MK70FN1M0 for
the TWR-K70F120M development board), then the programmer/debugger
connection to be used. The development board integrates a P&E USB Multilink
debugger. The next step gives our first meaningful choices – Figure 3 shows the
available options for Floating Point and I/O Support.
Figure 3: New Project Options 1
Chapter 3: Project Setup Christopher Kerr
Freescale CodeWarrior
16
The Kinetis K70 used on my development board includes a floating point unit,
but for comparability with the target K50 architecture I used software floating
point emulation in this project.
The I/O support option specifies which version of the Freescale Embedded
Warrior Library is linked into the project. Freescale supply versions of stdio.h
which include basic hardware drivers, permitting easy usage of printf() for
debugging using the UART or Debugger Console. The third option, “No I/O”, does
not link any such drivers. Including stdio.h introduces significant code
complexity and size to the project, and I do not consider it appropriate for an
embedded environment. As such, I did not make use of this feature and selected
the “No I/O” option.
3.1.2 LANGUAGE AND COMPILER – EXPLORING THE USE OF C++
There are two other options in this step of the wizard – Figure 4 shows the
Language and Built Tools options. The final project used the settings shown in
Figure 4 – the C language with the GCC-ARM toolchain – but this was not my
initially preferred configuration.
Figure 4: Language and Build Tools Options
My original project proposal revolved less around code quality and more around
applying modern programming paradigms to the embedded world. To this end, I
had proposed that I would undertake the project using C++ and thus explore the
applicability of Object Oriented Programming to embedded environment.
In the version that was current in July 2013, CodeWarrior 10.4, the Freescale
tools were the default. Thus my first attempt at creating the project used C++ with
Freescale’s own build tools, on the assumption that this would be the most
thoroughly supported configuration.
Chapter 3: Project Setup Christopher Kerr
Freescale CodeWarrior
17
Unfortunately, this configuration is not supported in CodeWarrior Special
Edition. Attempting to compile the created project gives the error “C++ is not
supported by the current set of licences and is disabled”. Examining Figure 5 it
can be seen that only the Professional Edition of CodeWarrior supports the use
of C++.
Figure 5: Extract from CodeWarrior Edition Comparison Table
However, the project creation wizard specifically presents GCC as an option, and
GCC is an open-source C++ compiler. Recreating the project using C++ with GCC
initially appeared successful – the project would compile without error. However,
trying to launch the project in the debugger would result in an error similar to
that shown in Figure 6 – “Download size limit has been exceeded. Please check
your license”. This was clearly nonsensical, as the empty application compiles to
less than 6KB.
Figure 6: Download Size Limit Error (Styger, 2012)
Investigation ultimately lead me to a blog entry by Erich Stryger (2012) which
confirmed that the debugger is capable of detecting the use of C++, resulting in
the error message shown when no C++ permitting license is found. I confirmed
this hypothesis by attempting debugging using the time-limited CodeWarrior
Professional Evaluation version. The only way to use C++ with CodeWarrior is to
purchase a licence for the professional edition. This option was discussed with
Dr Peter McLean and deemed unworkable due to the costs – Freescale does not
offer an academic discount (recommending the use of the free Special Edition).
and a one person-year license for CodeWarrior Professional costs US$1,995.00.
Chapter 3: Project Setup Christopher Kerr
Freescale CodeWarrior
18
Whilst attempting to work around this issue I had already begun to write code
using GCC conventions, thus ultimately resulting in my use of the GCC compiler
even after switching to the C language.
3.1.3 USING C99
As discussed in Chapter 2.3 (The C Programming Language), it is desirable to use
the latest supported version of ISO C. CodeWarrior, the Embedded Warrior
Library, and GCC support the use of C99, but it is not the default and no option is
given during project creation.
If I attempt to make use of a C99 construction on an unmodified project, errors
result – for instance, including stdbool.h and attempting to define a bool results
in the error “unknown type name ‘bool’” and the warning “EWL support for C99
is not enabled”. Examining stdbool.h shows this construction:
#if !_EWL_C99
#warning "EWL support for C99 is not enabled"
The obvious solution to this issue, and the one I used for most of the development,
is to simply redefine the _EWL_C99 symbol prior to the #include for any C99
headers, like so:
#if !(_EWL_C99)
#undef _EWL_C99
#define _EWL_C99 (1)
#endif
#include <stdbool.h>
However, late in development I learnt that there is a more correct method. In the
Project Properties -> C/C++ Build -> Settings pane, under the Tool Settings tab,
there is a folder in the navigation tree named “Librarian”. Changing the Model
setting from “ewl_noio” to “c9x_noio” results in the correct symbol definition,
thus compiling the included C99 headers in the correct mode.
Figure 7: Librarian Model Setting for C99
Chapter 3: Project Setup Christopher Kerr
Using the Kinetis Platform
19
3.2 USING THE KINETIS PLATFORM
3.2.1 DEVELOPMENT ON FREESCALE KINETIS
Freescale offer two options for rapid development on the Kinetis platform.
Processor Expert
Freescale Processor Expert is a GUI-driven automatic code generation tool which
is tightly integrated with Freescale CodeWarrior. Processor Expert hasa database
of all peripherals available on the target microprocessor. Users add “Embedded
Components” to their project. Components provide a modular object-oriented
approach to embedded development, with each Component encapsulating the
functionality of an on-chip peripheral, popular external peripheral (such as an
LCD display), or pure software algorithm.
The cost for this simplicity and modularity is reduced flexibility. Processor Expert
generates an event-driven application framework, and the user must adapt their
process to suit. As Processor Expert ultimately generates C code for compilation,
I also considered using Processor Expert to produce driver code for integration
into my own application. However, inspection of the generated code showed that
this was not feasible – the generated code was tightly coupled with the Processor
Expert environment, and would have required substantial rework to function
independently.
Bare-Metal Sample Code
Freescale provide a package of Bare-Metal sample code for the K70 platform.1
This package is interesting, because it contains a number of driver libraries for
K70 peripherals. However, no documentation (beyond the sample programs) is
supplied for these libraries, and I have been unable to locate a version-controlled
copy of this resource.
Ultimately I preferred to use these libraries as a reference source, alongside the
Kinetis Quick Reference User Guide (Freescale Semiconductor, 2012), to develop
my own drivers which meet my needs and conform to my own quality standards.
1 Download (Freescale login required) from
https://www.freescale.com/webapp/Download?colCode=KINETIS_120MHZ_SC
Chapter 3: Project Setup Christopher Kerr
Using the Kinetis Platform
20
3.2.2 INTERRUPTS
Kinetis microcontrollers are designed around an ARM Cortex-M4 CPU, which
provides very powerful and flexible interrupt management through its Nested
Vectored Interrupt Controller (NVIC). It has a number of interesting features,
including the ability to dynamically allocate interrupt priorities, and interrupt-
tail chaining, which permits the next pending interrupt to be rapidly entered
without performing a complete pop/push sequence on the stack.
The NVIC Vector Table
Unlike most other architectures, Interrupt Service Routines (ISRs) on ARM
Cortex-M based devices are not special. An ISR may be any function which takes
no parameters and has return type void.
On the MC9S12 microcontroller used by the original ModCon, interrupts are
defined using the non-ANSI keyword interrupt followed by the interrupt vector
number of the peripheral. This tells the compiler that the function is a special
interrupt service routine, and to place a call to this function in the corresponding
position of the vector table.
void interrupt 26 PeriodicTimer_ISR(void)
On a Kinetis microcontroller, the ISR function is not special. ISR’s are connected
to their respective vector by placing a function pointer in the vector table, which
is located at <projectDir>Project_SettingsStartup_Codekinetis_sysinit.c.
void (* const InterruptVector[])()
__attribute__ ((section(".vectortable"))) =
{
/* Processor exceptions */
(void(*)(void)) &_estack, // 0 Initial Stack Pointer
__thumb_startup, // 1 Initial Program Counter
/* and so on up to vector 15 */
/* Interrupts */
Analog_ADC_RxComplete_ISR,// 16 0 DMA Channel 0
Analog_DAC_TxComplete_ISR,// 17 1 DMA Channel 1
// and so on up to vector 121
}
The non-standard attribute __attribute__ ((section(".vectortable"))) directs
the linker to place this table at an address defined by the linker map. The
CodeWarrior-generated Kinetis boilerplate initialises the NVIC with this address.
Chapter 3: Project Setup Christopher Kerr
Using the Kinetis Platform
21
Interrupt Priority and the BASEPRI Register
The NVIC provides the capacity to set interrupt priorities, thus determining the
order in which interrupts are handled if they queue during the execution of
another ISR.
There are 16 possible priority levels, with 0 the highest priority, and 15 the
lowest. CPU_SetIrqPriority() exposes this functionality, taking as parameters an
IRQ number and a priority from 0-15. Note that Kinetis interrupts have both a
vector number and an IRQ. The first peripheral interrupt vector is 16,
corresponding to an IRQ of 0. Other IRQs may be calculated in this way by
subtracting 16 from the vector number.
The NVIC provides the capacity to “mask” execution of interrupts below a certain
priority level whilst preserving execution of higher priorities. This feature is
enabled by writing to the BASEPRI register. When BASEPRI is equal to 0, all
interrupts are executed. When BASEPRI is non-zero, interrupts with priorities
lower than or equal to BASEPRI are masked. Thus, when BASEPRI is equal to 1,
only interrupts of the highest priority will execute. Conversely, when BASEPRI is
equal to 15, all interrupts except the lowest priority will execute.
Enabling and Disabling Interrupts
Interrupts are enabled by writing a 1 to the relevant bit in the corresponding
NVIC Interrupt Set Enabled Register (NVICISER), and disabled by writing a 1 in
the corresponding NVIC Interrupt Clear Enabled Register (NVICICER). Before
enabling an interrupt, the pending flag for that interrupt should be cleared. This
can be achieved by writing 1 to the relevant bit of the corresponding NVIC
Interrupt Clear Pending Register (NVICICPR).
This functionality is handled by CPU_EnableIRQ() and CPU_DisableIRQ().
Critical Sections
Critical section inline-functions are defined which simply enable and disable
interrupts, because it is known that interrupts are never otherwise disabled in
this project. A more refined approach could make use of interrupt priorities and
the BASEPRI mask, but care must be taken to truly disable interrupts when it is
required (an example is seen in section 4.5.3).
Chapter 3: Project Setup Christopher Kerr
Using the Kinetis Platform
22
3.2.3 CLOCKING
Freescale Kinetis microcontrollers have an extremely complex clocking system,
an overview of which is shown in Figure 8 below.
Figure 8: Kinetis Clocking Overview (Freescale Semiconductor, 2011, p. 214)
The Master Clock Generator (MCG) module controls clock generation. The System
Integration Module (SIM) controls clock dividers and clock gating.
Main Clocks
Ultimately, there are four main output clocks, derived from MCGOUTCLK via the
dividers OUTDIV1 – OUTDIV4 respectively:
Core / System Clock: The ARM Cortex-M4 CPU core clock (max 150 MHz)
Bus Clock: The source of most peripheral clocks (max 75 MHz)
FlexBus Clock: Clock for the external FlexBus (max 50 MHz)
Flash Clock: Clock for the program flash memory (max 25 MHz)
An interface for setting these dividers is exposed by MCG_SetClockDividers().
Additionally, many peripherals can be clocked directly from the MCG – see the
outputs on the right hand side of Figure 8, which provide access to the output of
the Oscillators, PLLs, FLL, and the internal reference clocks.
Clock Gating
All module clocks are disabled after reset. Before any peripheral can be used, it is
necessary to enable the clock to its module by setting the appropriate bit in the
corresponding SCGCx register.
Chapter 3: Project Setup Christopher Kerr
Using the Kinetis Platform
23
Generating MCGOUTCLK
After reset, MCGOUTCLK is equal to 20.97MHz, sourced from a Frequency Locked
Loop driven by the internal 32.768 kHz clock (FEI mode). The maximum 2
supported clock speed for the microprocessor on the TWR-K70F120M is
120MHz. To achieve this frequency, it is necessary to transition the MCG to source
MCGOUTCLK from a Phase Locked Loop (PLL) driven by an external 50 MHz
oscillator (PEE mode).
Figure 9: MCG State Diagram
It can be seen in Figure 9 than in order to transition from FEI mode to PEE mode,
it is necessary to pass through a minimum of two intermediate states.
To enter FLL Bypassed External (FBE) mode, the MCG is configured to source
MCGOUTCLK directly, from either an external clock source or an internal
oscillator driven by an external crystal. The FLL remains locked, but neither the
FLL nor PLL output is used. This mode is used to transition the MCG from an
internal clock source to an external one.
To transition to PLL Bypassed External (PBE) mode, we configure and lock the
PLL, but leave its output unused. This involves configuring the appropriate
dividers, and this functionality is handled by MCG_calculatePLLDividers(). The
MCGOUTCLK is still sourced directly from the external reference.
Finally, the MCG is configured to use the now-configured PLL as the source for
MCGOUTCLK, transitioning the system to full-speed PLL Engaged External mode.
2 150 MHz core clock is unofficially supported within a reduced range of operating
temperatures, but the part used on the TWR-K70F120M is specified for use at 120 MHz.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Periodic Timers
25
4 HARDWARE ABSTRACTION LAYER
4.1 PERIODIC TIMERS
The Freescale Kinetis platform provides the Periodic Interrupt Timer (PIT)
module for implementing periodic timers. There are 4 independent PIT channels
available on the MK70FN1M0, each of which has its own interrupt vector.
The PIT channels are clocked from the Bus Clock. The value given by the LDVALn
register is loaded as the start value, then decremented by 1 on each clock tick
until it reaches 0. At zero, an interrupt is asserted and the value is reloaded.
To use the module, it must first be enabled. This involves enabling the clock to
the module by writing a 1 to the relevant bit in the SIM_SCGC6 register, then
clearing the Module Disabled flag in the PIT_MCR register. This functionality is
handled by PTimer_Setup().
Configuring a timer channel is then a three step process. First, the timer period is
set using PTimer_SetPeriod(). This function takes as input a timer channel and a
value to write to the register PIT_LDVALn. To minimise inter-module coupling,
calculating the required value is left to the user. To generate interrupts at a
frequency Fint Hz:
𝐿𝐷𝑉𝐴𝐿 =
𝐵𝑢𝑠 𝐶𝑙𝑜𝑐𝑘 (𝐻𝑧)
𝐹𝑖𝑛𝑡 (𝐻𝑧)
To perform this calculation at runtime, the current Bus Clock may be retrieved
using MCG_GetClocks().
Once the period is set, the PIT channel’s interrupt may optionally be enabled
using PTimer_InterruptSetup(). This step is not required if the PIT is being used
to trigger a DMA event.
Finally, the timer may be started with PTimer_Start(). A running timer may be
halted using PTimer_Halt(). Note that the downcounter is reset when the timer is
started, restarting the timer period. If the period is changed while the timer is
running, the new period will take effect in the next timer cycle.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Serial Communications Interface
26
4.2 SERIAL COMMUNICATIONS INTERFACE
4.2.1 UNIVERSAL ASYNCHRONOUS RECEIVER/TRANSMITTER (UART)
The UART peripheral is used to provide communications with a PC. UART2 on the
TWR-K70F120M is connected to the USB debugging interface, which enumerates
on the PC side as a USB Communications Device Class (CDC) device. This behaves
like a COM port in essentially all respects.
Setup of the UART peripheral is performed in UART_Init(). This driver exposes
only one parameter – the target baud rate. All other configurable settings remain
at the default configuration: 8 data bits, 1 stop bit, and no parity.
Baud Rate Calculation
In order to successfully communicate between a pair of asynchronous
receiver/transmitters, the baud clock on each device must match to a high degree
of accuracy. Any inaccuracy will result in the receiver sampling its input out of
synchronisation with the transmitter, resulting in framing errors.
In order to facilitate the required degree of accuracy whilst accommodating the
very flexible Kinetis clocking system, the UART peripheral uses a 13 bit modulus
counter (SBR) and 5 bit fractional counter (BRFD) to divide the incoming module
clock down to the desired baud rate:
𝐵𝑎𝑢𝑑 𝑅𝑎𝑡𝑒 =
𝑀𝑜𝑑𝑢𝑙𝑒 𝐶𝑙𝑜𝑐𝑘
(16 ∗ (𝑆𝐵𝑅 + 𝐵𝑅𝐹𝐷))
To implement this, UART_Init() first calculates SBR, the integer part of the divisor,
by dividing the module clock by 16 times the desired baud rate (the receiver is
run with 16 times oversampling).
uint16_t calcSbr = (uint16_t) ((moduleClkHz) /
(targetBaudRate * k_oversamplingRate));
As a 5-bit register, BRFD stores a value from 0-31, representing the numerator
of a fraction with denominator 32.
(moduleClkHz * 32) / (targetBaudRate * 16) gives an accurate total divisor for
32 times the required baud rate. Subtracting 32 times the calculated integer SBR
then leaves the required fractional numerator, BRFD.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Serial Communications Interface
27
4.2.2 INTERRUPT-DRIVEN SCI
The UART peripheral can generate interrupts upon completion of transmission
or reception of a byte. This permits the implementation of an interrupt-driven
Serial Communication Interface (SCI). Rather than polling the UART’s status flags,
transmission and reception can occur asynchronously in an interrupt service
routine.
Buffers: First-In, First-Out (FIFO)
Information needs to be sent and received by the Maze Rover asynchronously.
The simplest way to meet this requirement is the addition of send and receive
buffers. Simple First-In, First-Out (FIFO) buffers are implemented by fifo.c.
In this configuration, the reception of data by the UART triggers the UART ISR. If
the Received Data Ready flag is set, the data in the UART data register is stored in
the Receive FIFO. This data can later be retrieved by SCI0_InChar();
When data is ready for transmission, it is added to the Transmit FIFO. If no
transmission is already in progress, the UART’s Transmission Complete interrupt
is enabled. This will immediately trigger an interrupt, as the Transmit Data
Register Empty flag will test true. Data is retrieved from the Transmit FIFO and
placed in the UART’s data register, beginning a transmission. As each
transmission completes, the ISR will be triggered again. If data is successfully
retrieved from the Transmit FIFO, the cycle continues. When no data remains in
the Transmit FIFO, the Transmission Complete interrupt is disabled.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Serial Peripheral Interface (SPI)
28
4.3 SERIAL PERIPHERAL INTERFACE (SPI)
4.3.1 SPI BACKGROUND
Serial Peripheral Interface (SPI) is a full-duplex synchronous serial bus. In this
project, it is used to communicate with the external DAC and ADC peripherals
supplied by the Analog Interface Board.
The Freescale Kinetis DSPI peripheral is very configurable, and offers support
both interrupt-driven and Direct Memory Access usage models. These are
discussed further in Section 4.4: “Analog Interface Board”.
4.3.2 SPI IMPLEMENTATION
Because of the divergent protocol requirements of the DAC and ADC (see Section
4.4), no attempt was made to produce a generalised SPI driver. Instead, spi.c
provides support functions for managing SPI data frames.
The DSPI uses an interesting configuration scheme, in which many configuration
variables are duplicated between the CTARn (Clock and Transfer Attributes)
registers. This allows the module to be reconfigured on a frame by frame basis.
When queuing a frame for transmission, half of the 32-bit PUSHR register is
reserved for configuration bits, including which set of Clock and Transfer
Attributes is to be used for the transmission of that frame (see Figure 10).
Figure 10: PUSHR Register Layout
The function SPI_MakeTxFrame() has been written to assist in handling this data
structure. It has the definition:
uint32_t SPI_MakeTxFrame(uint16_t txData, tSPI_holdPCS holdPCS,
tSPI_CTAR transferSettings, tSPI_EOQ endOfQueue,
tSPI_clearCnt clearCnt, uint8_t assertPCS)
It takes data and configuration settings, and returns a uint32_t which is properly
formatted for assignment to the PUSHR register. This function is as generalised as
can be useful in this project, generating transmission frames which are applicable
to any implementation whether it uses flag polling, interrupts, or DMA.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
29
4.4 ANALOG INTERFACE BOARD
4.4.1 OVERVIEW
Figure 11: Analog Interface Board Top Level Schematic (Vambuca, 2013)
The ModCon 2.0 Analog Interface Board is a module for the Freescale Tower
System providing high-quality analog-to-digital (data acquisition) and digital-to-
analogue (data distribution) capabilities. It was designed during a previous
capstone project by Rosario Vambuca, who provided me with an assembled
prototype unit for use in this project.
Data Acquisition
Analog data acquisition is provided by an Analog Devices AD7609 ADC connected
to a SPI interface. This part has the following features:
 Eight simultaneously sampled true differential inputs
 18 bit resolution
 Acquisition rate up to 200,000 samples per second
Data Distribution
Analog data distribution is provided by an Analog Devices AD5754R DAC
connected to a SPI interface. This part has the following features:
 Four single-ended channels
 Programmable output range (+5V, +10V, +10.8V, ±5V, ±10V, ±10.8V)
 16 bit resolution (pin-compatible with 12 bit AD5724R and 14 bit AD5734R)
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
30
4.4.2 PHYSICAL INTERFACE
The ModCon 2.0 Analog Interface Board was designed to interface to the same
breakout panel as used with the original ModCon in Embedded Software and the
control laboratory. It connects via a 26 pin header cable, carrying signals for 8
differential inputs, 4 single-ended outputs, and ±12V power rails. The remaining
4 pins are connected to analog ground. The breakout panel permits connection of
these signals via standard 4mm banana jacks as seen in Figure 12.
Figure 12: ModCon Analog Interface Breakout Panel
The Analog Interface Board was supplied assembled. I assumed that it had been
demonstrated functional during Rosario’s capstone, but was later informed that
only the power supply had been tested. Initial tests of the Analog-to-Digital
converter revealed an issue – the signals I had connected at the breakout panel
were not present at the ADC input pins. Further investigation showed that the
pinout of the ribbon cable was flipped at the breakout panel. Rosario had copied
the PCB footprint used on the original ModCon Analog Interface, which has the
header soldered on the underside of the board, but populated his board with the
header on the upper side.
IDC header connectors are designed such that you cannot flip the pinout along
either axis by manipulating the connector’s orientation – it is possible to produce
a cable equivalent to having connected Pin 1 to Pin 26, Pin 2 to 25 (i.e. rotated
180 degrees) but not one where Pin 1 connects to Pin 2 and vice versa. The
problem was instead resolved by desoldering the header and installing a new
header on the underside of the board (thanks to Russell Nicholson for his
assistance with the desoldering process).
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
31
4.4.3 ANALOG TO DIGITAL CONVERTER
As discussed in Section 4.3.2, the DSPI peripheral duplicates the Clock and
Transfer Attributes register, providing CTAR0 and CTAR1. This is convenient,
because the Analog Interface Board has two SPI peripherals, each with its own
format and timing requirements. CTAR0 is configured for use with the AD7609
Analog to Digital Converter.
Handling the Frame Size
AD7609’s serial protocol uses an 18 bit SPI frame, but in master mode the Kinetis
DSPI peripheral only supports frames up to 16 bits. To accommodate this
requirement, I emulate an 18 bit frame by using two 9 bit “sub-frames”.
Figure 13: AD7609 Serial Timing (Analog Devices, 2013, p. 10)
The timing requirements of the AD7609 are shown in Figure 13. It can be seen
that /CS must remain low for the duration of the 18 bit transfer. This can be
achieved using the Continuous Peripheral Chip Select Enable (CONT) flag, which
is located in the PUSHR register and thus may be set independently for each
transmission.
On the first sub-frame, the CONT flag is set. This tells the DSPI to keep the chip
select signal asserted after the transfer completes. On the second sub-frame the
CONT flag is unset, and the chip select returns to the idle state once the transfer
completes.
Baud Rate
The AD7609 is specified for an SCLK frequency of 15MHz when configured with
Vdrive = 3.3V as on the Analog Interface Board.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
32
The DSPI peripheral is clocked from the Bus Clock3 (60 MHz). The DSPI baud rate
is set by:
𝑆𝐶𝐾 𝑏𝑎𝑢𝑑 𝑟𝑎𝑡𝑒 = (
𝑓𝑆 𝑌𝑆
𝑃𝐵𝑅
) ∗
1 + 𝐷𝐵𝑅
𝐵𝑅
Where:
 PBR is the baud rate prescaler.
Valid values correspond to dividers of
1
2
,
1
3
,
1
5
, and
1
7
 DBR is a flag which sets double baud rate mode
 BR is the baud rate scaler.
Valid values are
1
2 𝑛
from ½ through
1
65536
To achieve 15MHz, we need a total scaling factor of
15
60
=
1
4
, which can be
achieved by setting PBR to ½ and BR to ½, with double baud rate mode disabled.
However, in testing this configuration was found to be unreliable – the ADC
shifted data too slowly, resulting in only 17 bits of data being received. The next
fastest normal baud rate is 10Mhz (PBR =
1
3
, BR = ½), but it is possible to achieve
12MHz by enabling double baud rate mode (DBR = 1, PBR =
1
5
, BR = ½). This
configuration was reliable in testing.
Note that using double baud rate (DBR) mode can result in an asymmetric clock
waveform. This setup gives the worst-case result of 60% high, 40% low.
However, in this case the asymmetry is beneficial. The issue observed at higher
clock rates was that the clock high time was too short for the data to be shifted
out before the sample was taken on the falling edge of the clock. Using DBR gives
a high time roughly equivalent to a 10MHz clock whilst maintaining 12MBit/s
throughput, so transfer times are extended by only 25% compared to the 15MHz
theoretical maximum.
3 The reference manual claims that this module is clocked from the System Clock.
This is incorrect.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
33
Performing an Analog to Digital Conversion
Figure 14: AD7609 Acquisition Timing (Analog Devices, 2013, p. 9)
The timing of a data conversion is shown in Figure 14. To begin a conversion, the
CONVST4 pin is brought high until the BUSY pin is seen to go high in response.
The chip reacts only to the rising edge of CONVST, so it is permissible for CONVST
to remain high throughout the conversion process. The conversion is complete
on the falling edge of the BUSY line, and can now be read out by supplying up to
8 frames of 18 clock cycles on the SPI bus. Channels must be read sequentially,
but if less channels are required it is permissible to send only the required
number of frames – after a new conversion is performed, the first data shifted
onto the SPI bus is always channel 1.
Implementation Details
A periodic timer is set up to provide an interrupt at the desired sample rate. This
ISR calls Analog_AdcTrigger(), which takes CONVST low. The GPIO pin connected
to BUSY is configured to generate an interrupt on a falling edge, triggering the ISR
Analog_ADC_ConvComplete_ISR() when the falling edge of busy indicates the
conversion is complete. This function sets up the Direct Memory Access (DMA)
module, which reads the results from the SPI without further CPU intervention,
storing them in the array RawResults[]. When the DMA transfer is complete
(having read the requested number of channels) an ISR is triggered which sets
the boolean flag FreshData, which the application may poll to determine when
new data is available. The use of the DMA peripheral is discussed further in the
following section.
The function Analog_Get() takes a channel number as a parameter, and returns
the reassembled 18-bit sample as a signed 32-bit integer.
4 AD7609 provides two CONVST lines. CONVST A starts the acquisition process for the
lower four channels, and CONVST B the upper four. The Analog Interface Board ties
both pins together, so this document will refer only to CONVST in the singular.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
34
4.4.4 DIGITAL TO ANALOG CONVERTER
The AD5754R is part of the AD57x4R family of quad channel Digital to Analog
converters, all of which have a compatible pinout and interface. The cheapest
device, AD5724R, provides a 12-bit converter. The midrange AD5734R provides
a 14-bit converter, and the AD5754R provides a 16-bit converter. No changes to
the circuit or software are required when substituting these parts.
SPI Configuration
The DSPI’s CTAR1 register is configured for use with the AD5754R. Two 12-bit sub-
frames with continuous chip select are used to simulate the required 24-bit
frame. The AD5754R is specified for use with a 30MHz SCLK, and operates
correctly at that speed. See Section 4.4.3 for more details on CTAR configuration.
Figure 15: AD5754R Serial and Load Timing
Serial Protocol
Figure 16: DAC Input Register Layout (Analog Devices, 2011, p. 26)
The AD5754R uses a 24-bit SPI frame, as shown in Figure 16. The most significant
bit is used to indicate whether this is a read to or a write from the addressed
register. Bits REG2-REG0 specify which register is being addressed. Bits A2-A0,
and the data bits, vary in their function depending on which register is addressed.
If addressing the DAC register, A2-A0 specify which DAC channel is to be updated
with the following data. On AD5754R, all 16 bits of data are used for the DAC. On
the cheaper models, the least significant bits are treated as don’t-care values.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
35
Startup
When the DAC is reset, it must be initialised before use. Firstly, the output range
must be set in the Output Range Select Register. Both unipolar and bipolar ranges
can be selected, with symmetrical limits at 5V, 10V, or 10.8V.
Secondly, each DAC and the internal voltage reference must be powered up by
writing to the Power Control Register. The DAC’s require 10µs to power up, and
the DAC input register must not be loaded to the DAC during this time.
Optionally, the Control register may be written to disable Serial Data Output. This
feature, which echoes the previous input to the MISO line, is designed to permit
daisy-chaining of DAC’s, but it is not useful in this project.
Loading the DAC
Figure 17: DAC Input Loading (Analog Devices, 2011, p. 22)
After data has been loaded from the SPI input register to the DAC register, the
DAC’s may be updated in one of two modes. If /LDAC is held low whilst the data
transfer is ongoing, the DAC (and thus the output value) is immediately updated
on the rising edge of /SYNC. Alternatively, if /LDAC is high whilst data is loaded,
the update does not take effect until LDAC is held low for at least 20ns. This allows
for all the DAC’s to be updated simultaneously (see visualisation in Figure 15).
This is used in the Maze Rover 2.0 firmware to ensure that DAC updates occur
monotonically.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
36
Problems Solved During Testing
In early testing, no output was observed from the DAC. Observation on a mixed
signal oscilloscope showed that whenever /LDAC was high, so was the Analog
Interface Board’s RESET line. Probing with a multimeter confirmed that there
was an electrical connection between /LDAC and RESET, but only when the board
was assembled as part of the Tower System with the TWR-K70F120M.
On the Tower System Connectors, /LDAC is connected to pin B35. The
documentation for the TWR-K70F120M board shows that pin B35 is designated
GPIO4, and is connected to PTB 8 on the microcontroller. However, PTB 8 is also
seen to be used for “RSTOUT_b” on pin A63, which is connected to the RESET line
on the Analog Interface Board. Inspection of the TWR-K70F120M schematics
showed a 0Ω link (see R140 in Figure 18) connecting PTB 8 to the RESET line.
Removing this resistor corrected the behaviour.
Because this modification leaves the RESET line floating, I added a 10kΩ
pulldown resistor from RESET to ground on the Analog Interface board to ensure
RESET was in a known (logic low) state.
Figure 18: Schematic Extract Showing Reset 0Ω Link (Freescale Semiconductor, 2011, p. 8)
In subsequent tests, output from the DAC was erratic. Sometimes the intended
waveform could be seen, but at the wrong scale or offset. Inspecting the Analog
Interface Board schematic, I thought I had found the issue when I saw that the
REFIN pin was not connected to a 2.5V reference. Soldering a connection from
the ADC’s REFOUT pin to the DAC’s REFIN pin resolved the issue, seemingly
confirming my belief. However, it later came to my attention that I had been
reading the wrong datasheet – Analog Devices produce both an AD5754, which
requires an external reference, and an AD5754R. The –R suffixed model includes
an internal reference, but it is powered down by default. Adding the necessary
code to power up the internal reference allowed the DAC to operate correctly
without the additional wire.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
37
4.4.5 USING THE ENHANCED DIRECT MEMORY ACCESS PERIPHERAL
Benefits of DMA
The Enhanced Direct Memory Access (eDMA) permits data transfer operations to
be conducted without the intervention of the host CPU. It is capable of performing
its own source and destination offset calculations, permitting it to execute
complex data movements, such as reading incoming SPI values into a buffer. To
perform such operations using interrupts requires a lot of CPU time – every
received SPI frame triggers an interrupt, invoking a context switch every time.
This is particularly significant for the ADC, where transferring the conversion
results for eight channels results in the reception of 16 9-bit subframes.
Furthermore, because the host CPU is fast (clocked at 120MHz), even SPI
transfers are relatively slow – assuming the above transfer incurs no overhead
and takes exactly 144 cycles at 12MHz to complete, in the meantime 1440 cycles
have elapsed at the CPU. In reality, context switching overhead would slow this
further, and some of the remaining CPU time would be spent in the ISR
supervising the data transfer. By replacing such an interrupt-driven system with
DMA, the total transfer time is reduced and the CPU is free to do useful work.
Using DMA with the ADC
Transmission for the ADC is very simple – the MOSI line of the SPI bus is not even
connected to the ADC, so it doesn’t matter what you send provided you supply
the right clocks and framing as discussed in Section 4.4.2. As such, the TX data can
be pre-allocated to an array (AdcQueue[]).
Figure 19: Major and Minor Loops in DMA Requests (Freescale Semiconductor, 2011, p. 586)
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
38
The DMA Transmission Control Block (TCD) for the ADC TX is configured to move
4 bytes per minor loop (to understand major and minor loops, see Figure 19). The
destination is the SPI2 PUSHR register, and no offset is applied to the destination
address – the PUSHR register never moves. The source address is configured to be
the array of uint32_t AdcQueue[], advancing the source pointer by four bytes after
each transfer (to reach the next 32 bit entry). Only two channels need to be
fetched, so the major loop count is set to 4 (2 frames of 2 sub-frames each), and
the source address is moved back 16 bytes after the major loop is complete,
resetting to the start of the array. The TCD is configured to disable the DMA
request upon completion by setting the Disable Request (DREQ) bit.
For the ADC RX, the configuration is similar, but the source address remains
constant (the SPI2 POPR register) and the destination is the array RawResults[].
Upon completion of the major loop, the RX channel triggers an interrupt (to set
the boolean FreshData flag) and disables the DMA request.
Using DMA with the DAC
For the DAC, the TX configuration is slightly more complex. In order to permit
asynchronous queuing of DAC commands, the TX DMA TCD is configured to use
the DMA’s modulo feature to implement a FIFO circular buffer for the source. The
circular buffer contains 16 uint32_t entries, for a total of 64 bytes, addressed as
0 to 63. 63 is 26
− 1, or 1111112, so the DMA is configured for a 6 bit Source
Modulo (SMOD). Note that this requires that the array starts aligned with a 64
byte boundary. I initially overlooked this requirement, resulting in very
unpredictable behaviour as the SPI attempted to transmit based on an
uninitialized region of memory. This is fixed by using the proprietary GCC
attribute “aligned”, like so:
uint32_t TxBuffer[BUFFER_SIZE] __attribute__ ((aligned (64)));
This project does not make use of the DAC’s readback feature, so the DMA RX
channel is not configured when using the DAC. However, some code stubs are
included to make implementation of this feature simple if it is desired in the
future. Search for the symbol USE_DAC_RX_DMA.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Analog Interface Board
39
DMA Arbitration
During testing I discovered an issue wherein attempting to connect multiple DMA
channels to the same trigger (i.e. connecting the transmit DMA channels for both
the DAC and the ADC to the SPI2 transmission complete trigger) would result in
unreliable behaviour. Despite having only one channel enabled at a time,
sometimes a channel would simply fail to respond to a trigger.
To solve this issue, I redesigned the DMA system to use only one transmit channel
and one receive channel. This required adding a state machine to manage
arbitration of the DMA channels. In summary, it worked as follows:
At startup, the DMA channels are not configured, and the state machine is in
MODE_UNITIALISED.
When either the DAC or the ADC is used, it checks the current state to see if the
DMA is configured for the active peripheral. Let us assume, for example, that the
ADC is used first after startup. MODE_IDLE_ADC would indicate that the DMA
channels are already configured correctly, but we are in MODE_UNITIALISED, so
the DMA channels are reconfigured for ADC use. Whilst the transfer is ongoing,
the state is set to MODE_ACTIVE, preventing use by the other peripheral. When
the transfer is complete, the mode is set to MODE_IDLE_ADC. If no DAC operations
are performed before the next ADC operation, no reconfiguration will be
required. When a DAC operation is performed, MODE_IDLE_ADC will indicate
that reconfiguration is required, and when the operation is complete the DMA
arbitration state is MODE_IDLE DAC.
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Non-Volatile Memory (EEPROM Emulation)
40
4.5 NON-VOLATILE MEMORY (EEPROM EMULATION)
The original Maze Rover software stores many user-configurable constants in
non-volatile memory (NVM). The MC9S12A512 microcontroller at the heart of
the original ModCon provides 4KB of integrated EEPROM, which may be erased
in 4 byte sectors and written in 2 byte words.
The MK70FN1M0 microcontroller used on the TWR-K70F120M development
board does not offer true or emulated EEPROM. The N in the part number
indicates that this model has Program Flash only, whereas an X would indicate
the presence of Freescale’s FlexMemory feature. FlexMemory permits the
designer to partition the available flash between Program Flash and emulated
EEPROM. This feature is present on the MK50DX256 used on ModCon 2.0, but for
this project an alternative solution was required.
The TWR-K70F120M development board offers two external sources of non-
volatile memory – 256MB of NAND flash, and a Secure Digital (SD) card slot.
However, neither of these features is present on ModCon 2.0, so these solutions
would be non-portable. Furthermore, a cursory examination of the relevant
datasheet sections indicated that development of drivers would be non-trivial.
This leaves only the internal source of NVM, the microcontroller’s Program Flash.
Using the Program Flash has the advantage of being available on any Kinetis
derivative, but complicates write operations – writes can be as small as 8 bytes
(a “phrase”) but erases must be a whole 4KB sector. Since NVM is used in this
project to store 1, 2, and 4 byte values which may be updated at runtime, an
EEPROM emulation layer is required to give byte-level read/write access.
4.5.1 USING THE FREESCALE 90NM TFS FLASH DRIVER
Freescale has a driver for interacting with the Program Flash on Kinetis devices,
but it is strangely difficult to find. It can be located by searching for “C90TFS” on
the Freescale website, and locating the entry “TFS Flash Driver Software for
Kinetis and ColdFire+ Microcontrollers”5.
5 At the time of writing the package can be downloaded directly from:
http://cache.freescale.com/files/32bit/software/C90TFS_FLASH_DRIVER.exe
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Non-Volatile Memory (EEPROM Emulation)
41
The driver package includes a User Manual (Freescale Semiconductor, 2014) and
example projects for various derivatives of the Kinetis architecture including the
MK70FN1M0. Integrating the driver into my project was straightforward – the
driver source and include files were copied into the project tree, and the paths
repaired to correctly reflect the new file layout. The configuration files demo_cfg.h
and user_cfg.h were copied directly from the MK70FN1M0xxx12 demo provided
with the driver.
4.5.2 EEPROM EMULATION
The EEPROM emulation module (Eeprom.c) provides byte-level write access to
the Program Flash by buffering and modifying whole 4KB sectors. The core
functionality of the module is the function Eeprom_Write(), which takes as
parameters a pointer to the first byte of data, the data length in bytes, and a
pointer to the destination address in Flash memory.
Eeprom_Write() is responsible for determining which Flash sector a write affects,
buffering that sector, modifying the relevant part of the buffer, erasing the Flash
sector, and then writing the buffer to the Flash. This process is performed inside
a loop, so the write may cross sector boundaries. The logic is shown in Figure 20.
Figure 20: Eeprom_Write Logic Flowchart
Chapter 4: Hardware Abstraction Layer Christopher Kerr
Non-Volatile Memory (EEPROM Emulation)
42
4.5.3 IMPLEMENTATION DETAILS
Program Flash on Kinetis devices is divided into large regions named “blocks” –
on the MK70FN1M0 there are four program flash blocks, dividing the 1MB flash
into 256KB regions. Attempting to read from a block whilst a write is in progress
will result in an access violation error, and the result of the read is invalid. This is
important because program instructions and constant data are stored in the
program flash. Executing instructions or reading data from the same block as an
ongoing write will cause the program to behave unpredictably. This can be
avoided by placing simulated EEPROM variables in a different block to the
program instructions. CodeWarrior Special Edition imposes a 128KB limit on
program size, and the CodeWarrior new project wizard generates a linker map
which places the program at the start of the address space. Thus it may be
assumed, since 128KB is less than 256KB, that any block beyond the first is
available at any time.
However, I wished to provide a more generalised solution. This involves
executing the function which actually performs the Flash operations from RAM,
thus avoiding the need to read from Flash whilst the operation is ongoing. The
Freescale flash drivers provide a function designed for this purpose named
RelocateFunction(), and use of this function to store FlashCommandSequence() in
RAM was simple to integrate into Eeprom_Init().
However, during testing, writes to the first block still caused the program to
crash. I initially assumed the debugger was giving faulty data – it indicated that
execution had followed a function pointer to address 0x00000000. However,
debugging showed that this was exactly the case – an interrupt had caused a read
from the interrupt vector table, which returned invalid data resulting in an
invalid function pointer dereference. Interrupts must be completely disabled
around the write operation if it is to complete safely.
This functionality is not enabled by default, because it presents the risk of
overwriting the program data. The functionality permitting writing to the first
block may be configured by defining or undefining the symbol EEPROM_ANY_BLOCK.
The limits of the simulated EEPROM region are set by the pointers
k_EepromStartPtr and k_EepromEndPtr.
Chapter 5: High Level Functionality Christopher Kerr
Maze Rover to PC Communications
43
5 HIGH LEVEL FUNCTIONALITY
5.1 MAZE ROVER TO PC COMMUNICATIONS
The Maze Rover is configured using the Maze Rover PC Interface, an application
running on a Windows PC. The PC Interface communicates with the Rover via an
emulated UART, using a modified version of Dr McLean’s ModCon Serial Protocol.
5.1.1 MODCON SERIAL PROTOCOL
Structure
The ModCon Serial Protocol (McLean, 2013) defines a 5-byte packet structure as
shown in Figure 21 below.
Command Parameter 1 Parameter 2 Parameter 3 Checksum
Figure 21: Serial Protocol Packet Structure
The most significant bit of the command byte is reserved for packet
acknowledgement requests. The remaining 7 bits store the command number,
thus permitting 128 unique commands (0x00 – 0x7F).
The function of the three parameter bytes may vary depending on the command.
The final byte carries a checksum, which is simply the exclusive-or (XOR) of the
preceding four bytes. Whilst not very theoretically robust (compared to popular
checksum methods like Cyclic Redundancy Checking), this checksum is
computationally inexpensive and quite adequate in this application. The
emulated UART used to communicate with the Maze Rover is implemented using
the USB Communications Device Class, which includes its own robust methods
for ensuring data integrity.
Packet Acknowledgement
The sender requests acknowledgement from the receiver by setting the most
significant bit (the ACK bit) of the Command byte. The receiver first attempts to
complete the requested command. If successful (or if no action is required), it
returns a copy of the packet with the ACK bit set. If unsuccessful, the packet is
modified to unset the ACK bit before being returned, thus sending a NACK.
Chapter 5: High Level Functionality Christopher Kerr
Maze Rover to PC Communications
44
5.1.2 IMPLEMENTATION DETAILS
Most of the implementation is straightforward, and neither novel nor interesting.
packet.c contains functions for recognising valid received packets (Packet_Get())
and assembling packets for transmission (Packet_Put()). When a valid packet is
received, it is then passed to Protocol_HandlePacket(). This function handles
processing received packets, selecting the appropriate function based on the
received command. Implemented as a switch statement, it looks like this:
switch(maskedCommand)
{
case CMD_STARTUP:
retVal = Packet_HandleStartup();
break;
case CMD_TIME:
retVal = Packet_HandleTime();
break;
... // and so on, for many cases
Whilst this construct is simple and easily maintained at this size, the function may
potentially be required to scale to 128 entries. The resulting function would be
long and difficult to maintain. I prefer to address this problem with an array of
function pointers, and discuss the practicality of this solution below.
Function Pointers
In C, a pointer named funcPtr to a function which takes a Packet_t as a parameter,
and returns a bool, can be declared like so:
bool (*funcPtr)(Packet_t);
This syntax, which arises from C’s “declaration follows usage” design pattern, is
difficult for readers to parse. It is typically preferred to use a typedef to name
function pointers of a given signature (parameters and return type) as a type,
permitting a more typical declaration. The following extract creates a pointer
named funcPtr to a function Protocol_HandleStartup(), then dereferences that
pointer to call the function (note that in C, &fooFunc and fooFunc are equivalent –
either gives the address of the function fooFunc):
typedef bool(*Protocol_jumpPtr_t)(const Packet_t);
Protocol_jumpPtr_t funcPtr = Protocol_HandleStartup;
bool retVal = *funcPtr(fooPacket);
Chapter 5: High Level Functionality Christopher Kerr
Maze Rover to PC Communications
45
Switch Statements vs Function Pointer Arrays
An array of function pointers named jumpTable may be created like so:
typedef bool(*Protocol_jumpPtr_t)(const Packet_t);
static const Protocol_jumpPtr_t jumpTable[] =
{
Packet_HandleStartup, // 0x00
Packet_handleDefault, // 0x01 – Unused
Packet_HandleTime // 0x02
};
Now the appropriate function for handling the command stored in an
appropriately range-tested variable named maskedCommand can be called by:
bool retVal = *jumpTable[maskedcommand](fooPacket);
The advantages of using an array of function pointers are:
 Reduced logic complexity – new functionality can be added by altering only
the statically-allocated array, without need to modify the program logic
 Improved speed – each case in a switch statement is tested sequentially, and
conditional logic is slow. For switches with many cases, the time spent
processing the switch becomes significant, so such designs scale poorly.
However, there are also some disadvantages:
 C does not test if an array index actually lies within the bounds of the array,
so the index value must be correctly range limited before use.
 Unused cases must be handled – there is no safe way to skip inclusion of an
element in a function pointer array, so a dummy function must be inserted for
all unused indices. For Protocol_HandlePacket(), the dummy function simply
returns false without performing any other action.
As a result of this second drawback, the function pointer array must be at least as
large as the difference between the lowest expected index (which can be offset to
0 by a subtraction) and the highest. However, if the array is declared static const
it will be stored in Flash, where bytes are plentiful. Thus, I chose to include the
full range of possible values from 0x00 to 0x7F in my jump table, with each entry
commented as shown in the example above. This makes it easy to find the entry
for a given command code, and to visually distinguish unused codes.
Chapter 5: High Level Functionality Christopher Kerr
Maze Rover Communications Functions
46
5.2 MAZE ROVER COMMUNICATIONS FUNCTIONS
The communications functions are a direct port of those written by Dr McLean
for the original Maze Rover. I will briefly outline their function, and discuss the
adaptations required to have them function correctly in my project.
5.2.1 MODULATED WAVEFORM GENERATION
Comms_MakeWave() pre-calculates an amplitude modulated waveform, storing it in
the array WaveData[]. Interestingly, this function does not actually perform
amplitude modulation, but rather emulates it by adding sinusoidal components.
When considered in the frequency domain, it can be seen that this produces the
same output signal as amplitude modulation, but only if the message signals are
sinusoids.
The only significant changes made to this function were:
 Updating the cosine-wave table to provide full 16 bit resolution. This was not
strictly necessary, but seemed proper – the new platform uses a proper DAC
in place of the smoothed PWM of the original Maze Rover, making it capable
of much higher fidelity.
 Updated data types to ensure results would not be truncated as a result of the
16-bit cos wave input
A third change which was not made, but may be considered, relates to the divisor
used to scale the summed waveforms to an int16_t for output. I have kept the
same value as the original ModCon (21 * 2 = 42), but this results in an output
which is 10Vpp rather than the 5Vpp of the original system. It is my opinion that
the 5Vpp output used in the original Maze Rover was merely the result of its
technical limitations, and thus have made no deliberate effort to replicate this
characteristic.
5.2.2 VOLTAGE CONTROLLED OSCILLATOR
The function Comms_UpdateVCO() implements a numerically controlled sinusoidal
oscillator. When provided with ADC samples as input, it may be considered a
Voltage Controlled Oscillator. No modifications to this function were performed,
but it is necessary to modify the way in which it is called in order to preserve its
Chapter 5: High Level Functionality Christopher Kerr
Maze Rover Communications Functions
47
intended performance. When the numerical input is supplied by the Analog
Interface Board’s 18-bit ADC, it is necessary to divide by 64 to preserve the
intended voltage-to-frequency relationship. However, this change should not be
made internal to the function, as this would render it incompatible with the
Phase-Locked Loop.
5.2.3 PHASE LOCKED LOOP
No changes to the PLL were required, but during testing (see Section 0) it was
noted that the PLL performed well over only a very limited range of frequencies,
perhaps 250Hz either side of the VCO’s centre frequency. This may merit further
investigation, but I spent no further time on it given that the demodulator, which
relies upon the PLL to resynthesise the carrier wave, operates without issue.
5.2.4 DEMODULATION
Comms_DetectDemod() implements a coherent demodulation system as outlined in
Figure 22. The modulated waveform is multiplied by the oscillator recovered by
the phase-locked loop, then filtered by a comb-resonator cascade.
Figure 22: Coherent Demodulation Scheme
However, the resulting signal is not used as the output. Instead, a Sliding Discrete
Fourier Transform is used to determine the magnitudes of the expected message
frequencies, and these magnitudes are used by Comms_MakeDemod() to synthesise a
clean version of the demodulated signal.
5.2.5 TESTING
This project is focused on embedded software development, not signal theory. As
such, I have used the pre-solved “Automatic” coefficients for testing, rather than
presenting my own derivation.
Chapter 6: Communication Lab Testing Christopher Kerr
Modulated Wave Generation
49
6 COMMUNICATION LAB TESTING
6.1 MODULATED WAVE GENERATION
Single Sideband Lower
Figure 23: SSB-Lower Time Domain
Figure 24: SSB-Lower Frequency Domain
Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq.
Odd Autumn A 1050 Hz ☑ 375 Hz ☑ 425 Hz ☑
Chapter 6: Communication Lab Testing Christopher Kerr
Modulated Wave Generation
50
Single Sideband Upper
Figure 25: SSB-Upper Time Domain
Figure 26: SSB-Upper Frequency Domain
Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq.
Odd Autumn I 1100 Hz ☑ 75 Hz ☑ 125 Hz ☑
Chapter 6: Communication Lab Testing Christopher Kerr
Modulated Wave Generation
51
Double Sideband
Figure 27: SSB-HI Time Domain
Figure 28: SSB-HI Frequency Domain
Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq.
Odd Autumn E 700 Hz ☑ 425 Hz ☑ 375 Hz ☑
Chapter 6: Communication Lab Testing Christopher Kerr
Voltage-Controlled Oscillator
52
6.2 VOLTAGE-CONTROLLED OSCILLATOR
For this test I have used the configuration of Maze Rover B, Spring Semester 2013,
in order to permit comparison to the known results of an original Maze Rover.
The centre frequency for this configuration is 1100Hz.
Input Voltage Frequency (tested) Frequency (sample)
-2.5 1474.1 1497
-2.25 1436.7 1452
-2 1400.0 1417
-1.5 1324.2 1341
-1 1249.1 1267
-0.5 1174.2 1192
0 1099.6 1110
0.5 1024.5 1035
1 949.4 958
1.5 874.3 885.3
2 799.3 812.7
2.25 761.8 774
2.5 724.3 749.9
Notice that the tested values which are multiples of 0.5 volts give frequencies
which are very close to multiples of 25. In my opinion, this suggests that my
measurements are more accurate than those I am comparing against. This is
supported by the linear regression shown in Figure 29.
Figure 29: Voltage Controlled Oscillator Characteristic
Sample:
y = -150.77x + 1114.7
Tested:
y = -150x + 1099.3
600
700
800
900
1000
1100
1200
1300
1400
1500
1600
-2.5 -1.5 -0.5 0.5 1.5 2.5
OutputFrequency(Hz)
Input Voltage (V)
Frequency (sample)
Frequency (tested)
Chapter 6: Communication Lab Testing Christopher Kerr
Phase Locked Loop
53
A note on the testing procedure: It is typically difficult to measure the frequency
of unfiltered DAC-synthesised sine waves, since features are not typically placed
consistently between cycles. However, when using a digital storage oscilloscope
such as the Agilent DSO-X 2004A used in these tests, the Fast Fourier Transform
functionality provides a useful method for making accurate measurement
measurements of frequency. The high-order frequency components which make
up the “stair-step” characteristic are easily distinguished from the fundamental
when viewed in the frequency domain.
6.3 PHASE LOCKED LOOP
Figure 30: Phase-Locked Loop Operation
The Phase-Locked Loop works very well over a limited range of frequencies, but
performance rapidly degrades as the input frequency diverges from that shown
in Figure 30. Debugging did not reveal any obvious inconsistency in operation.
Both the Voltage Controlled Oscillator and the demodulator operate correctly,
and these components are closely related to the Phase Locked Loop.
Chapter 6: Communication Lab Testing Christopher Kerr
Demodulator
54
6.4 DEMODULATOR
For this test, the same configuration was used as in Section 6.2 (Rover B, Spring
Semester 2013). This configuration uses single-sideband upper modulation, with
messages frequencies 300Hz and 350Hz. These frequencies have been perfectly
reconstructed, as seen in Figure 32.
Figure 31: Demodulated Message Signal Time Domain
Figure 32: Demodulated Message Signal Frequency Domain
Chapter 7: Control Implementation Christopher Kerr
Controlled Plant: Quanser MAGLEV
55
7 CONTROL IMPLEMENTATION
Finalised Maze Rover 2.0 hardware was not available during the development of
this project, so implementation and testing of the Maze Rover’s Model Reference
Adaptive Controller could not be performed. Instead, an alternative control task
was implemented on this platform using the Quanser MAGLEV apparatus,
demonstrating the viability of ModCon 2.0 for performing complex control tasks.
7.1 CONTROLLED PLANT: QUANSER MAGLEV
Figure 33: Quanser MAGLEV Apparatus
The Quanser MAGLEV plant, seen in Figure 33, is an electromagnetic suspension
system. One pole of an electromagnet faces downward towards a post on which
a stainless steel ball sits when at rest. The pole contains a photo-transistor based
sensor which measures the distance from the top of the post to the surface of the
ball. A one Ohm current-sense resistor is provided, giving a 1 VA-1 response.
Using this apparatus, the goal of the controller is to modulate the input voltage of
the electromagnet such that ball tracks to a specified point in the vertical axis.
The derivation of a system model and LQR controller for this plant can be found
in Appendix B.
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report
Capstone Report

Weitere ähnliche Inhalte

Ähnlich wie Capstone Report

CV of Douglas Wendelboe
CV of Douglas WendelboeCV of Douglas Wendelboe
CV of Douglas Wendelboedwendelboe
 
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...Wolfgang Gentzsch
 
UberCloud - From Project to Product
UberCloud - From Project to ProductUberCloud - From Project to Product
UberCloud - From Project to ProductThe UberCloud
 
Thesis Report - Gaurav Raina MSc ES - v2
Thesis Report - Gaurav Raina MSc ES - v2Thesis Report - Gaurav Raina MSc ES - v2
Thesis Report - Gaurav Raina MSc ES - v2Gaurav Raina
 
Deep Convolutional Neural Network acceleration on the Intel Xeon Phi
Deep Convolutional Neural Network acceleration on the Intel Xeon PhiDeep Convolutional Neural Network acceleration on the Intel Xeon Phi
Deep Convolutional Neural Network acceleration on the Intel Xeon PhiGaurav Raina
 
Deep Convolutional Network evaluation on the Intel Xeon Phi
Deep Convolutional Network evaluation on the Intel Xeon PhiDeep Convolutional Network evaluation on the Intel Xeon Phi
Deep Convolutional Network evaluation on the Intel Xeon PhiGaurav Raina
 
Docker up &amp; running
Docker   up &amp; runningDocker   up &amp; running
Docker up &amp; runningLe Thi
 
Introducation of CPLDS and Design of Combinational circuit using CPLD
Introducation of CPLDS and Design of Combinational circuit using CPLDIntroducation of CPLDS and Design of Combinational circuit using CPLD
Introducation of CPLDS and Design of Combinational circuit using CPLDHemantChaurasia8
 
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...Boston Data Engineering
 
MCHE 484 Senior Design Final Report Rev_8
MCHE 484 Senior Design Final Report Rev_8MCHE 484 Senior Design Final Report Rev_8
MCHE 484 Senior Design Final Report Rev_8Daniel Newman
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...Henning Jacobs
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...Henning Jacobs
 
Seminar Report - Managing the Cloud with Open Source Tools
Seminar Report - Managing the Cloud with Open Source ToolsSeminar Report - Managing the Cloud with Open Source Tools
Seminar Report - Managing the Cloud with Open Source ToolsNakul Ezhuthupally
 
Programming the world with Docker
Programming the world with DockerProgramming the world with Docker
Programming the world with DockerPatrick Chanezon
 
OpenACC Monthly Highlights September 2019
OpenACC Monthly Highlights September 2019OpenACC Monthly Highlights September 2019
OpenACC Monthly Highlights September 2019OpenACC
 

Ähnlich wie Capstone Report (20)

CV of Douglas Wendelboe
CV of Douglas WendelboeCV of Douglas Wendelboe
CV of Douglas Wendelboe
 
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...
The UberCloud - From Project to Product - From HPC Experiment to HPC Marketpl...
 
UberCloud - From Project to Product
UberCloud - From Project to ProductUberCloud - From Project to Product
UberCloud - From Project to Product
 
Thesis Report - Gaurav Raina MSc ES - v2
Thesis Report - Gaurav Raina MSc ES - v2Thesis Report - Gaurav Raina MSc ES - v2
Thesis Report - Gaurav Raina MSc ES - v2
 
Deep Convolutional Neural Network acceleration on the Intel Xeon Phi
Deep Convolutional Neural Network acceleration on the Intel Xeon PhiDeep Convolutional Neural Network acceleration on the Intel Xeon Phi
Deep Convolutional Neural Network acceleration on the Intel Xeon Phi
 
Deep Convolutional Network evaluation on the Intel Xeon Phi
Deep Convolutional Network evaluation on the Intel Xeon PhiDeep Convolutional Network evaluation on the Intel Xeon Phi
Deep Convolutional Network evaluation on the Intel Xeon Phi
 
Docker up &amp; running
Docker   up &amp; runningDocker   up &amp; running
Docker up &amp; running
 
Introducation of CPLDS and Design of Combinational circuit using CPLD
Introducation of CPLDS and Design of Combinational circuit using CPLDIntroducation of CPLDS and Design of Combinational circuit using CPLD
Introducation of CPLDS and Design of Combinational circuit using CPLD
 
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...
Boston Data Engineering: Kedro Python Framework for Data Science: Overview an...
 
RESUME ROHIT LATEST
RESUME ROHIT LATESTRESUME ROHIT LATEST
RESUME ROHIT LATEST
 
MCHE 484 Senior Design Final Report Rev_8
MCHE 484 Senior Design Final Report Rev_8MCHE 484 Senior Design Final Report Rev_8
MCHE 484 Senior Design Final Report Rev_8
 
resumelrs_jan_2017
resumelrs_jan_2017resumelrs_jan_2017
resumelrs_jan_2017
 
Anup Rungta
Anup RungtaAnup Rungta
Anup Rungta
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
 
Masters_Thesis_FINAL_COPY
Masters_Thesis_FINAL_COPYMasters_Thesis_FINAL_COPY
Masters_Thesis_FINAL_COPY
 
UDP Report
UDP ReportUDP Report
UDP Report
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - Enterprise...
 
Seminar Report - Managing the Cloud with Open Source Tools
Seminar Report - Managing the Cloud with Open Source ToolsSeminar Report - Managing the Cloud with Open Source Tools
Seminar Report - Managing the Cloud with Open Source Tools
 
Programming the world with Docker
Programming the world with DockerProgramming the world with Docker
Programming the world with Docker
 
OpenACC Monthly Highlights September 2019
OpenACC Monthly Highlights September 2019OpenACC Monthly Highlights September 2019
OpenACC Monthly Highlights September 2019
 

Capstone Report

  • 1. University of Technology, Sydney Faculty of Engineering and Information Technology DEVELOPMENT OF A MODERNISED SOFTWARE PLATFORM FOR AN EDUCATIONAL ROBOT Christopher James Kerr Student Number: 10826598 Project Number: S13-123 Major: Electrical Engineering Supervisor: Dr Peter McLean A 12 Credit Point Project submitted in partial fulfilment of the requirements for the Degree of Bachelor of Engineering 20 June 2014
  • 2. Christopher Kerr ii STATEMENT OF ORIGINALITY I, Christopher James Kerr, hereby declare that I am the sole author of this report. I assert that:  All work shown in the body of this report is my own  All Appendices have been properly attributed to their original author  All theories, ideas, and results of others have been correctly referenced  All sources of assistance have been acknowledged by name in this report Please be aware that some small samples of code have been reused from a previous subject, 48434 Embedded Software. This code comprises an insignificant portion of the finished project. I must also acknowledge that this project is substantially based on the source code of the original Maze Rover, developed and supplied by Dr Peter McLean. Appendix B contains material created in collaboration with other students in 48580 Advanced Control, during the Autumn 2014 semester. They have been acknowledged at the beginning of that chapter. However, I wish to clarify that the related work presented in Chapter 7: “Control Implementation” is entirely mine. Signed: __________________________________________ Christopher James Kerr Date: 20 June 2014
  • 3. Christopher Kerr iii ABSTRACT In 48540 Signals and Systems, a robot platform, called the “Maze Rover”, is used to teach signal and control theory concepts to Electrical Engineering students. This robot is built upon obsolete technology, and a replacement is under development. The current Maze Rover platform is based upon the Freescale MC9S12A512, a 16- bit fixed-point microcontroller. Whilst this chip is very capable, its current application as the controller for the “Maze Rover” pushes its capabilities to the limit, leaving no capacity for future expansion of features. The new platform is built on a Freescale Kinetis 32-bit microcontroller, which provides vastly improved performance and a number of additional capabilities. This project demonstrates the reimplementation of the Maze Rover software on this new platform, performed in C99 using the Freescale CodeWarrior toolchain. A literature review of best practices in embedded development was conducted, leading to the development of an Embedded Software Coding Standard. This standard has been extensively documented and rigorously adhered to, to demonstrate the development of high-reliability embedded software. The core of the project is the development of a Hardware Abstraction Layer (HAL) for this new platform. The HAL provides serial communications via UART and SPI, data acquisition, analogue output, and EEPROM emulation. It demonstrates the application of several interesting features of the new platform, including the highly configurable hardware SPI implementation and use of the Direct Memory Access peripheral. The project also implements the original Maze Rover features, including modulated wave synthesis, tone detection, and a phase locked loop. These features have been tested to be functionally identical to the original platform. Future development may extend this work by implementing a real-time operating system. The new platform’s improved speed provides ample capacity to run additional tasks, such as driving an LCD-based Human-Machine Interface or performing network communications over TCP/IP.
  • 4. Christopher Kerr iv ACKNOWLEDGEMENTS I would like to acknowledge the support of Dr Peter McLean, whose excellent teaching has kept me sane over the course of this degree. I must also acknowledge that this project is substantially based on the source code of the original Maze Rover, developed and supplied by Dr McLean, and I thank him for this resource. My friends at UTS are owed thanks for putting up with me, far more than I deserved! It’s been a long degree and I couldn’t have done it without you. Finally, I express the utmost gratitude for my family, who have supported me in more ways than I could possibly count. ACKNOWLEDGEMENT OF PRIOR WORK The Analog Interface board used in this project was designed during a previous capstone project by Rosario Vambuca. Rosario provided the assembled board and its design schematics for this project. I must also acknowledge that this project is substantially based on the source code of the original Maze Rover, developed and supplied by Dr Peter McLean. Appendix B contains material created in collaboration with other students in 48580 Advanced Control, during the Autumn 2014 semester. They have been acknowledged at the beginning of that chapter.
  • 5. Christopher Kerr v TABLE OF CONTENTS Statement of Originality...............................................................................................................ii Abstract ............................................................................................................................................ iii Acknowledgements.......................................................................................................................iv List of figures...................................................................................................................................vi 1 Introduction ............................................................................................................................1 2 Embedded C Code Quality .................................................................................................5 3 Project Setup........................................................................................................................15 4 Hardware Abstraction Layer.........................................................................................25 5 High Level Functionality .................................................................................................43 6 Communication Lab Testing..........................................................................................49 7 Control Implementation..................................................................................................55 8 Conclusions...........................................................................................................................63 References......................................................................................................................................67 Table of Appendices ...................................................................................................................69
  • 6. Christopher Kerr vi LIST OF FIGURES Figure 1: The ModCon Board.....................................................................................................1 Figure 2: Freescale Tower System (Freescale, 2012) ......................................................2 Figure 3: New Project Options 1............................................................................................ 15 Figure 4: Language and Build Tools Options.................................................................... 16 Figure 5: Extract from CodeWarrior Edition Comparison Table.............................. 17 Figure 6: Download Size Limit Error (Styger, 2012)..................................................... 17 Figure 7: Librarian Model Setting for C99 ......................................................................... 18 Figure 8: Kinetis Clocking Overview (Freescale Semiconductor, 2011)................ 22 Figure 9: MCG State Diagram.................................................................................................. 23 Figure 10: PUSHR Register Layout....................................................................................... 28 Figure 11: Analog Interface Board Top Level Schematic (Vambuca, 2013)......... 29 Figure 12: ModCon Analog Interface Breakout Panel................................................... 30 Figure 13: AD7609 Serial Timing (Analog Devices, 2013, p. 10).............................. 31 Figure 14: AD7609 Acquisition Timing (Analog Devices, 2013, p. 9)..................... 33 Figure 15: AD5754R Serial and Load Timing................................................................... 34 Figure 16: DAC Input Register Layout (Analog Devices, 2011, p. 26)..................... 34 Figure 17: DAC Input Loading (Analog Devices, 2011, p. 22).................................... 35 Figure 18: Schematic Extract Showing Reset 0Ω Link (Freescale, 2011).............. 36 Figure 19: Major and Minor Loops in DMA Requests (Freescale, 2011)............... 37 Figure 20: Eeprom_Write Logic Flowchart ....................................................................... 41 Figure 21: Serial Protocol Packet Structure...................................................................... 43 Figure 22: Coherent Demodulation Scheme..................................................................... 47 Figure 23: SSB-Lower Time Domain.................................................................................... 49 Figure 24: SSB-Lower Frequency Domain......................................................................... 49 Figure 25: SSB-Upper Time Domain .................................................................................... 50 Figure 26: SSB-Upper Frequency Domain......................................................................... 50 Figure 27: SSB-HI Time Domain............................................................................................ 51 Figure 28: SSB-HI Frequency Domain................................................................................. 51 Figure 29: Voltage Controlled Oscillator Characteristic............................................... 52 Figure 30: Phase-Locked Loop Operation.......................................................................... 53 Figure 31: Demodulated Message Signal Time Domain............................................... 54 Figure 32: Demodulated Message Signal Frequency Domain.................................... 54 Figure 33: Quanser MAGLEV Apparatus ............................................................................ 55 Figure 34: Control Module Overview .................................................................................. 56 Figure 35: Non-Inverting Op-amp Buffer........................................................................... 58 Figure 36 : Controller Architecture...................................................................................... 59 Figure 37 : Feedforward Current Relationships.............................................................. 60 Figure 38 : Lab Response to Step Input.............................................................................. 61 Figure 39 : Lab Tracking of Triangle Wave Input ........................................................... 62 Figure 40 : Lab Rejection of External Disturbance......................................................... 62
  • 7. Christopher Kerr vii NOMENCLATURE ADC Analog to Digital Converter DAC Digital to Analog Converter DMA Direct Memory Access EEPROM A type of Non-Volatile Memory Flash NAND Flash, a type of Non-Volatile Memory ISR Interrupt Service Routine LSB Least Significant Bit/Byte Maze Rover An educational robotics platform used at UTS MCG Master Clock Generator ModCon Modular Controller microcontroller board MSB Most Significant Bit/Byte NVM Non-Volatile Memory PLL Phase-Locked Loop RAM, SRAM Random Access Memory. Volatile memory type. RX Receive SPI Serial Peripheral Interface TCD Transmission Control Descriptor (for DMA) TX Transmit UART Universal Asynchronous Reciever/Transmitter UTS University of Technology, Sydney VCO Voltage Controlled Oscillator Table 1: Project Nomenclature
  • 8.
  • 9. Chapter 1: Introduction Christopher Kerr Background 1 1 INTRODUCTION 1.1 BACKGROUND At the University of Technology, Sydney (UTS), engineering is taught with a practice-based curriculum. Theoretical concepts learnt in lectures are reinforced by application in the laboratory. At present a robot platform, called the “Maze Rover”, is used in 48540 “Signals and Systems” to teach signal theory concepts to Electrical Engineering students. The core of this device is a microcontroller board called ModCon (MODular CONtroller), a flexible platform deployed in laboratories for several subjects. ModCon acts as the “brain” of the robot, controlling its functionality. Whilst in other subjects ModCon is user-programmable, its use in the Maze Rover is strictly as an embedded appliance running preloaded firmware. 1.2 PROJECT OVERVIEW Figure 1: The ModCon Board The microcontroller used on the ModCon (the large black microchip visible in Figure 1) is obsolete, and a replacement microcontroller board (ModCon 2.0) has been developed to modernise the platform. This has prompted the design of a new revision of the Maze Rover robot (Maze Rover 2.0) built around ModCon 2.0. This project involves the development of the control software for that
  • 10. Chapter 1: Introduction Christopher Kerr Technical Outline 2 replacement robot. The purpose of this project is replicate the capabilities of the current Maze Rover using a development prototype of Maze Rover 2.0. During this process a methodology for development of high-quality embedded software will be developed and explored. 1.3 TECHNICAL OUTLINE The current ModCon platform is based upon an obsolete device, the Freescale MC9S12A512, a 16-bit fixed-point microcontroller with a 25MHz clock, 512KB of non-volatile Flash storage, 14KB of RAM and many peripherals and interfaces. Whilst this chip is very capable, its current application as the controller for the Maze Rover pushes its capabilities to the limit. ModCon 2.0 is based on a modern device, the Freescale MK50DX256CLL10. A member of the Kinetis K50 family, this device uses a 32-bit ARM Cortex-M4 core clocked at up to 100MHz. The specific model chosen provides 256KB of Flash storage and 128KB of RAM. At the commencement of this project, the final ModCon 2.0 hardware was not available, so development was performed using a Freescale Kinetis TWR-K70F120M development board. This development board is designed to integrate into the Freescale Tower System (shown in Figure 2), which provides a modular system for development of embedded projects. In this project, an Analog Interface Board developed by a previous student is used as a tower peripheral. Figure 2: Freescale Tower System (Freescale Semiconductor, 2012)
  • 11. Chapter 1: Introduction Christopher Kerr Project Goals 3 The TWR-K70F120M module is designed around the high-end Freescale MK70FN1M0VMJ12. This model provides a number of additional capabilities when compared to K50 family devices, including a hardware floating-point unit. For the purposes of developing software for Maze Rover 2.0 the use of these features has been restricted. Where the development of this project diverges from the limitations imposed by a K50 family device, a note has been made to aid future development. 1.4 PROJECT GOALS The goal of this project is to completely re-implement the functionality of the existing Maze Rover firmware on a prototype of the ModCon 2.0 platform. Major functionality units of the Maze Rover firmware (as deployed in Signals and Systems) to be re-implemented include:  Hardware Abstraction Layer o SPI and UART interface drivers o Analogue Inputs and Outputs o Periodic timers o Low level functions such as clock generation  Serial Communications Protocol  Discrete Fourier Transform  Phase Locked Loop, including o Numerically controlled oscillator  Generation of modulated waveforms  Demodulation of acquired waveforms It also features a Model Reference Adaptive Motor Controller. This advanced controller is applied transparently, such that the complex transfer function of the Maze Rover’s motor appears to be a simple first order system when measured without an external controller. This allows for a relatively simple controller to be developed by students in “Signals and Systems” using the first order model developed from the observed system. As finalised Maze Rover 2.0 hardware was not available during the development of this project, an alternative control task was implemented on this platform using Quanser MAGLEV apparatus, demonstrating the viability of ModCon 2.0 for performing complex control tasks.
  • 12. Chapter 1: Introduction Christopher Kerr Document Outline 4 1.5 DOCUMENT OUTLINE Chapter 2: Literature review – Embedded C Code Quality An overview of research conducted prior to commencing software development for this project, including a discussion of code quality and its applicability in an embedded software project. Chapter 3: Project Setup Getting started with the Freescale Codewarrior toolchain and understanding the fundamentals of the Freescale Kinetis architecture. Chapter 4: Hardware Abstraction Layer Understanding the hardware of the Maze Rover 2.0 platform, and implementing drivers for its UART, Periodic Timers and Analog Input/Output systems. Chapter 5: High Level Functionality Design and implementation of the Maze Rover 2.0’s application-specific software, including the ModCon serial protocol and the Signals and Systems communication functions. Chapter 6: Communication Lab Testing Verification of the Maze Rover 2.0’s ability to replicate the communications functions of the original Maze Rover. Chapter 7: Control Implementation Implementation details and test results for a control system implemented using the prototype Maze Rover 2.0 platform. Chapter 8: Conclusions A discussion of the final status of the project. A subsection on further work gives an outline of the work required to use this project’s results in the Signals and Systems laboratory, and suggestions for potential future refinements.
  • 13. Chapter 2: Embedded C Code Quality Christopher Kerr Defining Quality Code 5 2 EMBEDDED C CODE QUALITY 2.1 DEFINING QUALITY CODE For the purposes of this project, we shall consider quality code to be: Stable: The software should have no known bugs, and all necessary precautions must be taken to avoid introducing common errors. Maintainable: The intent of code must be clear to the reader, and the code’s purpose in the larger system must be thoroughly documented. Portable: The code should not make unnecessary assumptions about the underlying architecture or compiler, to permit porting between systems. 2.2 THE NEED FOR QUALITY CODE IN EMBEDDED SYSTEMS The embedded environment is fundamentally different from the personal workstation environment with which most programmers are familiar. The operation of embedded systems is largely autonomous and unsupervised. In a workstation environment some kinds of failure are annoying, but acceptable – programs become unresponsive or crash, but the user is there to restart them. This is not typically the case for an embedded system, where the user has little awareness or control over the internal state of the system. Furthermore, many embedded systems control safety-critical processes, such as automobiles and industrial automatons. In this environment, unreliable software can result in injury or death. Unfortunately, this is not hypothetical – in the 1980’s at least three deaths were inflicted by Therac-25 radiation therapy machines, which suffered from a race condition in a safety interlock. During the first Gulf War, 28 US soldiers were killed when a Patriot Missile system failed to destroy a SCUD missile because of a poorly designed timekeeping system which compared incompatible data formats. More recently, it has been argued that some of the “unintended acceleration” issues affecting the Toyota Camry may have been caused by faulty software and inadequately designed fail-safes.
  • 14. Chapter 2: Embedded C Code Quality Christopher Kerr The C Programming Language 6 2.3 THE C PROGRAMMING LANGUAGE The C programming language is a popular choice for embedded software development. Firstly, and most prosaically, it is often the only high-level language with a supported toolchain for the target microcontroller architecture. Conversely, few (if any) architectures support another high-level language but do not support C. This makes C the de facto choice when code portability is required or desirable. Secondly, C provides an appropriately minimalist level of abstraction. The higher level languages currently popular on desktop computers, such as Java and Python, do not provide good support for fast hardware I/O operations, whereas C's arrays, structs, and bitfields translate neatly to low-level manipulation of hardware. Unfortunately, as a language, the C standard tends towards permissiveness. It is certainly possible to write code which will compile as valid C despite being difficult to understand, perverse, or not correctly reflecting the intentions of the programmer. For instance, C has a system of type promotions which, ultimately, permits a floating point number to be assigned to a boolean variable. Furthermore, many edge cases in the C standard are “implementation defined”, resulting in unpredictable program operation across compilers and architectures. Other sections of the language are well defined but prone to programmer error. A misplaced semicolon after the declaration of a for loop or the test in an if statement can completely alter the intended logical flow without causing compilation errors. It is very easy to mistype the assignment operator = in place of the comparison operator == (or vice versa) and in most cases these substitutions still produce valid C. The operator precedence rules in C are particularly notorious for their illogical design – the bitwise operators | and & have lower rank than the comparison operator ==. This results in errors when evaluating simple expressions such as: if (x & y == 0) In this example, most readers would assume the intended logic to be: if ((x & y) == 0)
  • 15. Chapter 2: Embedded C Code Quality Christopher Kerr The C Programming Language 7 However, C’s operator precedence rules have this result: if (x & (y == 0)) Finally, we should consider that the same feature that originally made C attractive, its minimal abstraction, can also be a hazard at runtime. C assumes that programmers know what they are doing, and does not protect against run time errors such as division by zero or dereferencing of invalid pointers. Given these limitations of C, it is clear that the language must be applied carefully when used for embedded systems. Used without restriction, C has features which can negatively impact the stability, maintainability, and portability of code, resulting in poor code quality. A subtle but important consideration is the version of the C language used. Modern compilers support two main options – ANSI C (commonly known as C89, and published as ISO/IEC 9899:1990) and C99 (ISO/IEC 9899:1999). C99 was recently withdrawn by the International Standards Organisation in favour of C11, a new standard ratified in 2011, but compiler support for this standard is essentially non-existent at this time. Until relatively recently it was common to advise against the use of C99 (as of 2004, no commercial compiler supported C99), but it is now well supported by most C compilers. C99 brings valuable features to the C language, such as:  The ability to mix declarations and code, i.e. to declare a variable at any point in a function,  The first expression in a for loop may be a declaration, as in C++,  The inline keyword, which hints to the compiler that a function should be included inline rather than called  Support for a Boolean type,  C++ style // one line comments,  More flexible initialisation of arrays and structs. The utility of these features is seen as sufficient justification for the use of C99.
  • 16. Chapter 2: Embedded C Code Quality Christopher Kerr Best Practices in Embedded Development 8 2.4 BEST PRACTICES IN EMBEDDED DEVELOPMENT 2.4.1 LITERATURE REVIEW In order to develop a suitable coding standard for this project, I conducted a review of the existing literature on embedded development using the C programming language. The following titles should be considered representative rather than exhaustive. Many alternative coding standards exist. 2.4.2 MISRA-C:2004 (MIRA LIMITED, 2004) “MISRA-C:2004 – Guidelines for the use of the C language in critical systems” is primarily interested in addressing the reliability of embedded systems. Published by the Motor Industry Software Reliability Association for application in the automotive industry, MISRA-C is a highly restrictive coding standard which defines a “safe” subset of the C programming language. MISRA-C recognises the utility of the C programming language, but seeks to eliminate the insecurities inherent to the language by defining a rule set amenable to enforcement by static analysis tools. Rules in MISRA-C are classified as either “Required” or “Advisory”. In order to claim to be compliant with MISRA-C, all required rules must be followed. Advisory rules are considered to be less important – it is not necessary to follow any advisory rule, but it is strongly recommended that they be considered. Required rules largely deal with eliminating the use of language features whose behaviour (under C89) is unspecified, undefined, or implementation defined. Use of such features can result in unintended behaviour, especially when porting between compilers or architectures. Note that several required rules also explicitly ban the use of C99 features – these rules are known to be retracted in MISRA-C:2012, but no copy of that document could be located for review. Further rules aim to restrict cases where C is considered to be overly permissive. For instance, it is permissible in C for the same identifier to be used for both a typedef name and a variable name. This is potentially confusing, so reuse of a typedef name is banned by Rule 5.3.
  • 17. Chapter 2: Embedded C Code Quality Christopher Kerr Best Practices in Embedded Development 9 Advisory rules are typically stricter cases of required rules. For instance, where Rule 5.3 (required) bans the reuse of typedef names, and Rule 5.2 (required) bans naming reusing a variable name such that a variable in the current scope hides a variable in outer scope, Advisory Rule 5.7 issues a blanket ban on reuse of any identifier regardless of namespace or scope. The vast majority of the recommendations made by MISRA-C:2004 are sensible and practical, but some specific Rules are considered to be too strict for practicality in a typical embedded system. For example, Rule 14.7 requires that functions have a single point of return. Such a rule can significantly complicate the design of functions which should return early in case of error. Rule 17.1 forbids the use of pointer arithmetic outside of array addressing, a restriction which is unhelpful when addressing hardware registers known to be at a particular offset from a peripheral base address. Portability is addressed by MISRA-C in an indirect but conclusive manner – by banning the use of all non-standard language extensions and eliminating all aspects of the language which are poorly defined, portability is guaranteed. However, considering the thoroughly considered nature of the MISRA-C:2004 rule set, it shall be considered as a definitive reference – any explicit contradiction of MISRA-C rules shall be documented in the developed coding standard. 2.4.3 BARR GROUP EMBEDDED C CODING STANDARD (BARR, 2013) The Barr Group standard may be considered as a companion text to MISRA-C:2004. Where the two documents overlap they are largely compatible – the only significant difference is the adoption of C99 and its features. However, the Barr Group standard moves beyond examining language features to concern itself with style, and thus concerns itself largely with code maintainability. The author’s hypothesis is that many bugs are introduced by maintenance programmers, and that these bugs may be reduced by “the disciplined use of consistent commenting and stylistic practices”. Style is a highly personal aspect of coding, but I acknowledge that code does not belong to the original author, but to those future programmers who will maintain it. As such, it follows that there is value in a strictly codified style to maximise consistency.
  • 18. Chapter 2: Embedded C Code Quality Christopher Kerr Best Practices in Embedded Development 10 The Barr Group standard is exhaustive in its codification of style. It incorporates all the usual features of a style guide – naming conventions, rules for the placement of braces, guidelines for comments and so on – but goes much further, rigorously defining the acceptable use of whitespace. This document is much easier to follow than MISRA-C, taking a more colloquial style. It uses a clear and logical structure, with chapters based on common language features (Procedures, Variables, Expressions, and so on). It thus serves as a useful model for this project’s coding standard. This is permitted by the legal notices of the document, requiring only the inclusion of a particular paragraph from that section. I chose to adapt this standard, rather than adopting it wholesale, for three reasons: firstly, much of the document is concerned with style, and style is highly personal. I would prefer to enforce my own style, and thus will codify it using this document as a template. Secondly, there are points of significant disagreement between this document and the Embedded Software Style Guide discussed in section 2.4.5, and I am aware that many of my own conventions were strongly influenced by that document. Adaptation has permitted the reconciliation and incorporation of useful material from the Embedded Software Style Guide. Finally, I believe that rewriting the standard has provided a deep familiarity with the details of the result, superior to that gained by simply examining a document prepared by another person. 2.4.4 THE ART OF DESIGNING EMBEDDED SYSTEMS (GANSSLE, 2008) The Art of Designing Embedded Systems concerns itself with the entire process of embedded software development. It is largely unsuccessful – it covers a wide variety of topics in scattershot fashion, with topics ranging from debouncing to team management philosophies. However, it does contain a thorough discussion of quality code that informed this project, and Appendix A presents a Firmware Standard. By comparison to the previous two documents, this standard is dreadful – imprecise, incomplete, and laden with bizarrely specific advice. Much of it is copied verbatim from the discussion of code quality in Chapter 3. Jack Ganssle is
  • 19. Chapter 2: Embedded C Code Quality Christopher Kerr Best Practices in Embedded Development 11 a highly respected embedded software engineer. The high quality of his published articles and essays led me to review this text, but in review it is clear that this book is largely assembled from summaries of Ganssle’s previous writing. The longer form is used here merely to cover more topics rather than discuss topics in greater depth. The value in The Art of Designing Embedded Systems is not in its coding standard, but in its discussions of code quality and particularly encapsulation. In this context, encapsulation is taken to be the pattern of design which avoids global variables by preferring C++-style Get and Set functions in the public interface of a module. This pattern is useful, and not idiomatic in C. The Art of Designing Embedded Systems is also notable for being the text that originally drew my attention to the very useful MISRA-C standard reviewed in section 2.4.2. 2.4.5 48434 EMBEDDED SOFTWARE: SOFTWARE STYLE GUIDE (MCLEAN, 2013) Peter McLean’s Software Style Guide is included in this review for two reasons. Firstly, it was my first exposure to a formalised coding standard, and has thus influenced some of my most fundamental assumptions about coding style. Secondly, it loosely describes the style used in the existing Maze Rover codebase. The Software Style Guide was not written until several years after the Maze Rover firmware, but the common ancestry of their respective styles is clearly apparent. This style guide is concerned almost entirely with consistency, in the interest of maintainability. It is less comprehensive than the Barr Group standard, giving more general guidelines than specific rules. The Software Style Guide is a more human document, giving guidance as to what a programmer “should” do rather than forbidding the use of the incorrect version. This is because it is designed for enforcement by a human reader, rather than a software static analysis tool. From this document, I have adopted many of the naming convention and code structure rules, and much of its advice on coding best practices such as scope limitation (data hiding) and const correctness.
  • 20. Chapter 2: Embedded C Code Quality Christopher Kerr Best Practices in Embedded Development 12 One notable conflict relates to single-line conditional or loop constructs, such as: if (y < z) x = y; The Software Style guide requires the format shown above, without braces, but with the following line indented as if it were wrapped in braces. The Barr Group argues against this style, on the basis that single-line conditional constructs are often expanded into multi-line conditional blocks. This introduces the potential for error – the braces may not be added, and the indenting may trick the reading into believe the braces are present. Instead, they require the following style, in which even single lines are wrapped with braces: if (y < z) { x = y; } This has the potential to prevent error, but adds two lines of mostly empty space to every such construct. It does however have a beneficial effect on documentation, as it removes the pressure to force a comment to fit in the space available to the right of the single line. In the original draft of my coding standard, I had preferred the Software Style Guide approach, as I believe the more concise form is easier to read. However, during the development of this project, I became aware of a bug discovered in Apple Inc.’s SSL implementation, which affected a range of platforms, including arguably embedded devices such as their iPhone mobile phones. if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; // << duplicated line if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; The bug consists of a single duplicated line, which thanks to the omitted braces is unconditionally executed unless the preceding test has failed. A goto sends execution directly to a label named “fail”, bypassing several tests. Worse, the “fail” label leads to logic which does not always signal failure - it is simply the function
  • 21. Chapter 2: Embedded C Code Quality Christopher Kerr The Maze Rover Embedded C Coding Standard 13 return, which returns the error code in the err variable. As no error has yet occurred, this causes the function to prematurely return without error. Reading about this error (“GotoFail”), and a similar error involving a case statement found in the OpenSSL codebase (“Heartbleed”) has changed my position on the inclusion of such braces, and the final revision of my coding standard requires them unconditionally. 2.5 THE MAZE ROVER EMBEDDED C CODING STANDARD The resulting document can be reviewed in Appendix A. It contains discussions of the rationale behind interesting, complex, or unintuitive rules, and has been footnoted with justifications for diverging from MISRA-C:2004 and the Barr Group coding standard.
  • 22.
  • 23. Chapter 3: Project Setup Christopher Kerr Freescale CodeWarrior 15 3 PROJECT SETUP 3.1 FREESCALE CODEWARRIOR Freescale CodeWarrior Development Studio is an Integrated Development Environment (IDE) for Freescale microcontroller products. The latest major version, CodeWarrior 10, takes the form of modular plugins running in the popular open-source Eclipse IDE. The CodeWarrior IDE provides a complete environment for development of Kinetis applications; including wizard-driven project creation, a modern code editor, a Flash programmer, and a well-featured debugger. Development for this project was conducted using CodeWarrior 10.4 (later 10.5) Special Edition, which is available at no cost but imposes a code size limit of 128KB for Kinetis K-series devices. This limit was not significant for this project – the final optimised executable is well under 20KB, and this includes known inefficiencies which were not addressed because they did not affect run-time performance. 3.1.1 STARTING A CODEWARRIOR PROJECT Starting a new project in CodeWarrior (File>New>Bareboard Project) firsts prompts for a name and location, then for the target processor (MK70FN1M0 for the TWR-K70F120M development board), then the programmer/debugger connection to be used. The development board integrates a P&E USB Multilink debugger. The next step gives our first meaningful choices – Figure 3 shows the available options for Floating Point and I/O Support. Figure 3: New Project Options 1
  • 24. Chapter 3: Project Setup Christopher Kerr Freescale CodeWarrior 16 The Kinetis K70 used on my development board includes a floating point unit, but for comparability with the target K50 architecture I used software floating point emulation in this project. The I/O support option specifies which version of the Freescale Embedded Warrior Library is linked into the project. Freescale supply versions of stdio.h which include basic hardware drivers, permitting easy usage of printf() for debugging using the UART or Debugger Console. The third option, “No I/O”, does not link any such drivers. Including stdio.h introduces significant code complexity and size to the project, and I do not consider it appropriate for an embedded environment. As such, I did not make use of this feature and selected the “No I/O” option. 3.1.2 LANGUAGE AND COMPILER – EXPLORING THE USE OF C++ There are two other options in this step of the wizard – Figure 4 shows the Language and Built Tools options. The final project used the settings shown in Figure 4 – the C language with the GCC-ARM toolchain – but this was not my initially preferred configuration. Figure 4: Language and Build Tools Options My original project proposal revolved less around code quality and more around applying modern programming paradigms to the embedded world. To this end, I had proposed that I would undertake the project using C++ and thus explore the applicability of Object Oriented Programming to embedded environment. In the version that was current in July 2013, CodeWarrior 10.4, the Freescale tools were the default. Thus my first attempt at creating the project used C++ with Freescale’s own build tools, on the assumption that this would be the most thoroughly supported configuration.
  • 25. Chapter 3: Project Setup Christopher Kerr Freescale CodeWarrior 17 Unfortunately, this configuration is not supported in CodeWarrior Special Edition. Attempting to compile the created project gives the error “C++ is not supported by the current set of licences and is disabled”. Examining Figure 5 it can be seen that only the Professional Edition of CodeWarrior supports the use of C++. Figure 5: Extract from CodeWarrior Edition Comparison Table However, the project creation wizard specifically presents GCC as an option, and GCC is an open-source C++ compiler. Recreating the project using C++ with GCC initially appeared successful – the project would compile without error. However, trying to launch the project in the debugger would result in an error similar to that shown in Figure 6 – “Download size limit has been exceeded. Please check your license”. This was clearly nonsensical, as the empty application compiles to less than 6KB. Figure 6: Download Size Limit Error (Styger, 2012) Investigation ultimately lead me to a blog entry by Erich Stryger (2012) which confirmed that the debugger is capable of detecting the use of C++, resulting in the error message shown when no C++ permitting license is found. I confirmed this hypothesis by attempting debugging using the time-limited CodeWarrior Professional Evaluation version. The only way to use C++ with CodeWarrior is to purchase a licence for the professional edition. This option was discussed with Dr Peter McLean and deemed unworkable due to the costs – Freescale does not offer an academic discount (recommending the use of the free Special Edition). and a one person-year license for CodeWarrior Professional costs US$1,995.00.
  • 26. Chapter 3: Project Setup Christopher Kerr Freescale CodeWarrior 18 Whilst attempting to work around this issue I had already begun to write code using GCC conventions, thus ultimately resulting in my use of the GCC compiler even after switching to the C language. 3.1.3 USING C99 As discussed in Chapter 2.3 (The C Programming Language), it is desirable to use the latest supported version of ISO C. CodeWarrior, the Embedded Warrior Library, and GCC support the use of C99, but it is not the default and no option is given during project creation. If I attempt to make use of a C99 construction on an unmodified project, errors result – for instance, including stdbool.h and attempting to define a bool results in the error “unknown type name ‘bool’” and the warning “EWL support for C99 is not enabled”. Examining stdbool.h shows this construction: #if !_EWL_C99 #warning "EWL support for C99 is not enabled" The obvious solution to this issue, and the one I used for most of the development, is to simply redefine the _EWL_C99 symbol prior to the #include for any C99 headers, like so: #if !(_EWL_C99) #undef _EWL_C99 #define _EWL_C99 (1) #endif #include <stdbool.h> However, late in development I learnt that there is a more correct method. In the Project Properties -> C/C++ Build -> Settings pane, under the Tool Settings tab, there is a folder in the navigation tree named “Librarian”. Changing the Model setting from “ewl_noio” to “c9x_noio” results in the correct symbol definition, thus compiling the included C99 headers in the correct mode. Figure 7: Librarian Model Setting for C99
  • 27. Chapter 3: Project Setup Christopher Kerr Using the Kinetis Platform 19 3.2 USING THE KINETIS PLATFORM 3.2.1 DEVELOPMENT ON FREESCALE KINETIS Freescale offer two options for rapid development on the Kinetis platform. Processor Expert Freescale Processor Expert is a GUI-driven automatic code generation tool which is tightly integrated with Freescale CodeWarrior. Processor Expert hasa database of all peripherals available on the target microprocessor. Users add “Embedded Components” to their project. Components provide a modular object-oriented approach to embedded development, with each Component encapsulating the functionality of an on-chip peripheral, popular external peripheral (such as an LCD display), or pure software algorithm. The cost for this simplicity and modularity is reduced flexibility. Processor Expert generates an event-driven application framework, and the user must adapt their process to suit. As Processor Expert ultimately generates C code for compilation, I also considered using Processor Expert to produce driver code for integration into my own application. However, inspection of the generated code showed that this was not feasible – the generated code was tightly coupled with the Processor Expert environment, and would have required substantial rework to function independently. Bare-Metal Sample Code Freescale provide a package of Bare-Metal sample code for the K70 platform.1 This package is interesting, because it contains a number of driver libraries for K70 peripherals. However, no documentation (beyond the sample programs) is supplied for these libraries, and I have been unable to locate a version-controlled copy of this resource. Ultimately I preferred to use these libraries as a reference source, alongside the Kinetis Quick Reference User Guide (Freescale Semiconductor, 2012), to develop my own drivers which meet my needs and conform to my own quality standards. 1 Download (Freescale login required) from https://www.freescale.com/webapp/Download?colCode=KINETIS_120MHZ_SC
  • 28. Chapter 3: Project Setup Christopher Kerr Using the Kinetis Platform 20 3.2.2 INTERRUPTS Kinetis microcontrollers are designed around an ARM Cortex-M4 CPU, which provides very powerful and flexible interrupt management through its Nested Vectored Interrupt Controller (NVIC). It has a number of interesting features, including the ability to dynamically allocate interrupt priorities, and interrupt- tail chaining, which permits the next pending interrupt to be rapidly entered without performing a complete pop/push sequence on the stack. The NVIC Vector Table Unlike most other architectures, Interrupt Service Routines (ISRs) on ARM Cortex-M based devices are not special. An ISR may be any function which takes no parameters and has return type void. On the MC9S12 microcontroller used by the original ModCon, interrupts are defined using the non-ANSI keyword interrupt followed by the interrupt vector number of the peripheral. This tells the compiler that the function is a special interrupt service routine, and to place a call to this function in the corresponding position of the vector table. void interrupt 26 PeriodicTimer_ISR(void) On a Kinetis microcontroller, the ISR function is not special. ISR’s are connected to their respective vector by placing a function pointer in the vector table, which is located at <projectDir>Project_SettingsStartup_Codekinetis_sysinit.c. void (* const InterruptVector[])() __attribute__ ((section(".vectortable"))) = { /* Processor exceptions */ (void(*)(void)) &_estack, // 0 Initial Stack Pointer __thumb_startup, // 1 Initial Program Counter /* and so on up to vector 15 */ /* Interrupts */ Analog_ADC_RxComplete_ISR,// 16 0 DMA Channel 0 Analog_DAC_TxComplete_ISR,// 17 1 DMA Channel 1 // and so on up to vector 121 } The non-standard attribute __attribute__ ((section(".vectortable"))) directs the linker to place this table at an address defined by the linker map. The CodeWarrior-generated Kinetis boilerplate initialises the NVIC with this address.
  • 29. Chapter 3: Project Setup Christopher Kerr Using the Kinetis Platform 21 Interrupt Priority and the BASEPRI Register The NVIC provides the capacity to set interrupt priorities, thus determining the order in which interrupts are handled if they queue during the execution of another ISR. There are 16 possible priority levels, with 0 the highest priority, and 15 the lowest. CPU_SetIrqPriority() exposes this functionality, taking as parameters an IRQ number and a priority from 0-15. Note that Kinetis interrupts have both a vector number and an IRQ. The first peripheral interrupt vector is 16, corresponding to an IRQ of 0. Other IRQs may be calculated in this way by subtracting 16 from the vector number. The NVIC provides the capacity to “mask” execution of interrupts below a certain priority level whilst preserving execution of higher priorities. This feature is enabled by writing to the BASEPRI register. When BASEPRI is equal to 0, all interrupts are executed. When BASEPRI is non-zero, interrupts with priorities lower than or equal to BASEPRI are masked. Thus, when BASEPRI is equal to 1, only interrupts of the highest priority will execute. Conversely, when BASEPRI is equal to 15, all interrupts except the lowest priority will execute. Enabling and Disabling Interrupts Interrupts are enabled by writing a 1 to the relevant bit in the corresponding NVIC Interrupt Set Enabled Register (NVICISER), and disabled by writing a 1 in the corresponding NVIC Interrupt Clear Enabled Register (NVICICER). Before enabling an interrupt, the pending flag for that interrupt should be cleared. This can be achieved by writing 1 to the relevant bit of the corresponding NVIC Interrupt Clear Pending Register (NVICICPR). This functionality is handled by CPU_EnableIRQ() and CPU_DisableIRQ(). Critical Sections Critical section inline-functions are defined which simply enable and disable interrupts, because it is known that interrupts are never otherwise disabled in this project. A more refined approach could make use of interrupt priorities and the BASEPRI mask, but care must be taken to truly disable interrupts when it is required (an example is seen in section 4.5.3).
  • 30. Chapter 3: Project Setup Christopher Kerr Using the Kinetis Platform 22 3.2.3 CLOCKING Freescale Kinetis microcontrollers have an extremely complex clocking system, an overview of which is shown in Figure 8 below. Figure 8: Kinetis Clocking Overview (Freescale Semiconductor, 2011, p. 214) The Master Clock Generator (MCG) module controls clock generation. The System Integration Module (SIM) controls clock dividers and clock gating. Main Clocks Ultimately, there are four main output clocks, derived from MCGOUTCLK via the dividers OUTDIV1 – OUTDIV4 respectively: Core / System Clock: The ARM Cortex-M4 CPU core clock (max 150 MHz) Bus Clock: The source of most peripheral clocks (max 75 MHz) FlexBus Clock: Clock for the external FlexBus (max 50 MHz) Flash Clock: Clock for the program flash memory (max 25 MHz) An interface for setting these dividers is exposed by MCG_SetClockDividers(). Additionally, many peripherals can be clocked directly from the MCG – see the outputs on the right hand side of Figure 8, which provide access to the output of the Oscillators, PLLs, FLL, and the internal reference clocks. Clock Gating All module clocks are disabled after reset. Before any peripheral can be used, it is necessary to enable the clock to its module by setting the appropriate bit in the corresponding SCGCx register.
  • 31. Chapter 3: Project Setup Christopher Kerr Using the Kinetis Platform 23 Generating MCGOUTCLK After reset, MCGOUTCLK is equal to 20.97MHz, sourced from a Frequency Locked Loop driven by the internal 32.768 kHz clock (FEI mode). The maximum 2 supported clock speed for the microprocessor on the TWR-K70F120M is 120MHz. To achieve this frequency, it is necessary to transition the MCG to source MCGOUTCLK from a Phase Locked Loop (PLL) driven by an external 50 MHz oscillator (PEE mode). Figure 9: MCG State Diagram It can be seen in Figure 9 than in order to transition from FEI mode to PEE mode, it is necessary to pass through a minimum of two intermediate states. To enter FLL Bypassed External (FBE) mode, the MCG is configured to source MCGOUTCLK directly, from either an external clock source or an internal oscillator driven by an external crystal. The FLL remains locked, but neither the FLL nor PLL output is used. This mode is used to transition the MCG from an internal clock source to an external one. To transition to PLL Bypassed External (PBE) mode, we configure and lock the PLL, but leave its output unused. This involves configuring the appropriate dividers, and this functionality is handled by MCG_calculatePLLDividers(). The MCGOUTCLK is still sourced directly from the external reference. Finally, the MCG is configured to use the now-configured PLL as the source for MCGOUTCLK, transitioning the system to full-speed PLL Engaged External mode. 2 150 MHz core clock is unofficially supported within a reduced range of operating temperatures, but the part used on the TWR-K70F120M is specified for use at 120 MHz.
  • 32.
  • 33. Chapter 4: Hardware Abstraction Layer Christopher Kerr Periodic Timers 25 4 HARDWARE ABSTRACTION LAYER 4.1 PERIODIC TIMERS The Freescale Kinetis platform provides the Periodic Interrupt Timer (PIT) module for implementing periodic timers. There are 4 independent PIT channels available on the MK70FN1M0, each of which has its own interrupt vector. The PIT channels are clocked from the Bus Clock. The value given by the LDVALn register is loaded as the start value, then decremented by 1 on each clock tick until it reaches 0. At zero, an interrupt is asserted and the value is reloaded. To use the module, it must first be enabled. This involves enabling the clock to the module by writing a 1 to the relevant bit in the SIM_SCGC6 register, then clearing the Module Disabled flag in the PIT_MCR register. This functionality is handled by PTimer_Setup(). Configuring a timer channel is then a three step process. First, the timer period is set using PTimer_SetPeriod(). This function takes as input a timer channel and a value to write to the register PIT_LDVALn. To minimise inter-module coupling, calculating the required value is left to the user. To generate interrupts at a frequency Fint Hz: 𝐿𝐷𝑉𝐴𝐿 = 𝐵𝑢𝑠 𝐶𝑙𝑜𝑐𝑘 (𝐻𝑧) 𝐹𝑖𝑛𝑡 (𝐻𝑧) To perform this calculation at runtime, the current Bus Clock may be retrieved using MCG_GetClocks(). Once the period is set, the PIT channel’s interrupt may optionally be enabled using PTimer_InterruptSetup(). This step is not required if the PIT is being used to trigger a DMA event. Finally, the timer may be started with PTimer_Start(). A running timer may be halted using PTimer_Halt(). Note that the downcounter is reset when the timer is started, restarting the timer period. If the period is changed while the timer is running, the new period will take effect in the next timer cycle.
  • 34. Chapter 4: Hardware Abstraction Layer Christopher Kerr Serial Communications Interface 26 4.2 SERIAL COMMUNICATIONS INTERFACE 4.2.1 UNIVERSAL ASYNCHRONOUS RECEIVER/TRANSMITTER (UART) The UART peripheral is used to provide communications with a PC. UART2 on the TWR-K70F120M is connected to the USB debugging interface, which enumerates on the PC side as a USB Communications Device Class (CDC) device. This behaves like a COM port in essentially all respects. Setup of the UART peripheral is performed in UART_Init(). This driver exposes only one parameter – the target baud rate. All other configurable settings remain at the default configuration: 8 data bits, 1 stop bit, and no parity. Baud Rate Calculation In order to successfully communicate between a pair of asynchronous receiver/transmitters, the baud clock on each device must match to a high degree of accuracy. Any inaccuracy will result in the receiver sampling its input out of synchronisation with the transmitter, resulting in framing errors. In order to facilitate the required degree of accuracy whilst accommodating the very flexible Kinetis clocking system, the UART peripheral uses a 13 bit modulus counter (SBR) and 5 bit fractional counter (BRFD) to divide the incoming module clock down to the desired baud rate: 𝐵𝑎𝑢𝑑 𝑅𝑎𝑡𝑒 = 𝑀𝑜𝑑𝑢𝑙𝑒 𝐶𝑙𝑜𝑐𝑘 (16 ∗ (𝑆𝐵𝑅 + 𝐵𝑅𝐹𝐷)) To implement this, UART_Init() first calculates SBR, the integer part of the divisor, by dividing the module clock by 16 times the desired baud rate (the receiver is run with 16 times oversampling). uint16_t calcSbr = (uint16_t) ((moduleClkHz) / (targetBaudRate * k_oversamplingRate)); As a 5-bit register, BRFD stores a value from 0-31, representing the numerator of a fraction with denominator 32. (moduleClkHz * 32) / (targetBaudRate * 16) gives an accurate total divisor for 32 times the required baud rate. Subtracting 32 times the calculated integer SBR then leaves the required fractional numerator, BRFD.
  • 35. Chapter 4: Hardware Abstraction Layer Christopher Kerr Serial Communications Interface 27 4.2.2 INTERRUPT-DRIVEN SCI The UART peripheral can generate interrupts upon completion of transmission or reception of a byte. This permits the implementation of an interrupt-driven Serial Communication Interface (SCI). Rather than polling the UART’s status flags, transmission and reception can occur asynchronously in an interrupt service routine. Buffers: First-In, First-Out (FIFO) Information needs to be sent and received by the Maze Rover asynchronously. The simplest way to meet this requirement is the addition of send and receive buffers. Simple First-In, First-Out (FIFO) buffers are implemented by fifo.c. In this configuration, the reception of data by the UART triggers the UART ISR. If the Received Data Ready flag is set, the data in the UART data register is stored in the Receive FIFO. This data can later be retrieved by SCI0_InChar(); When data is ready for transmission, it is added to the Transmit FIFO. If no transmission is already in progress, the UART’s Transmission Complete interrupt is enabled. This will immediately trigger an interrupt, as the Transmit Data Register Empty flag will test true. Data is retrieved from the Transmit FIFO and placed in the UART’s data register, beginning a transmission. As each transmission completes, the ISR will be triggered again. If data is successfully retrieved from the Transmit FIFO, the cycle continues. When no data remains in the Transmit FIFO, the Transmission Complete interrupt is disabled.
  • 36. Chapter 4: Hardware Abstraction Layer Christopher Kerr Serial Peripheral Interface (SPI) 28 4.3 SERIAL PERIPHERAL INTERFACE (SPI) 4.3.1 SPI BACKGROUND Serial Peripheral Interface (SPI) is a full-duplex synchronous serial bus. In this project, it is used to communicate with the external DAC and ADC peripherals supplied by the Analog Interface Board. The Freescale Kinetis DSPI peripheral is very configurable, and offers support both interrupt-driven and Direct Memory Access usage models. These are discussed further in Section 4.4: “Analog Interface Board”. 4.3.2 SPI IMPLEMENTATION Because of the divergent protocol requirements of the DAC and ADC (see Section 4.4), no attempt was made to produce a generalised SPI driver. Instead, spi.c provides support functions for managing SPI data frames. The DSPI uses an interesting configuration scheme, in which many configuration variables are duplicated between the CTARn (Clock and Transfer Attributes) registers. This allows the module to be reconfigured on a frame by frame basis. When queuing a frame for transmission, half of the 32-bit PUSHR register is reserved for configuration bits, including which set of Clock and Transfer Attributes is to be used for the transmission of that frame (see Figure 10). Figure 10: PUSHR Register Layout The function SPI_MakeTxFrame() has been written to assist in handling this data structure. It has the definition: uint32_t SPI_MakeTxFrame(uint16_t txData, tSPI_holdPCS holdPCS, tSPI_CTAR transferSettings, tSPI_EOQ endOfQueue, tSPI_clearCnt clearCnt, uint8_t assertPCS) It takes data and configuration settings, and returns a uint32_t which is properly formatted for assignment to the PUSHR register. This function is as generalised as can be useful in this project, generating transmission frames which are applicable to any implementation whether it uses flag polling, interrupts, or DMA.
  • 37. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 29 4.4 ANALOG INTERFACE BOARD 4.4.1 OVERVIEW Figure 11: Analog Interface Board Top Level Schematic (Vambuca, 2013) The ModCon 2.0 Analog Interface Board is a module for the Freescale Tower System providing high-quality analog-to-digital (data acquisition) and digital-to- analogue (data distribution) capabilities. It was designed during a previous capstone project by Rosario Vambuca, who provided me with an assembled prototype unit for use in this project. Data Acquisition Analog data acquisition is provided by an Analog Devices AD7609 ADC connected to a SPI interface. This part has the following features:  Eight simultaneously sampled true differential inputs  18 bit resolution  Acquisition rate up to 200,000 samples per second Data Distribution Analog data distribution is provided by an Analog Devices AD5754R DAC connected to a SPI interface. This part has the following features:  Four single-ended channels  Programmable output range (+5V, +10V, +10.8V, ±5V, ±10V, ±10.8V)  16 bit resolution (pin-compatible with 12 bit AD5724R and 14 bit AD5734R)
  • 38. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 30 4.4.2 PHYSICAL INTERFACE The ModCon 2.0 Analog Interface Board was designed to interface to the same breakout panel as used with the original ModCon in Embedded Software and the control laboratory. It connects via a 26 pin header cable, carrying signals for 8 differential inputs, 4 single-ended outputs, and ±12V power rails. The remaining 4 pins are connected to analog ground. The breakout panel permits connection of these signals via standard 4mm banana jacks as seen in Figure 12. Figure 12: ModCon Analog Interface Breakout Panel The Analog Interface Board was supplied assembled. I assumed that it had been demonstrated functional during Rosario’s capstone, but was later informed that only the power supply had been tested. Initial tests of the Analog-to-Digital converter revealed an issue – the signals I had connected at the breakout panel were not present at the ADC input pins. Further investigation showed that the pinout of the ribbon cable was flipped at the breakout panel. Rosario had copied the PCB footprint used on the original ModCon Analog Interface, which has the header soldered on the underside of the board, but populated his board with the header on the upper side. IDC header connectors are designed such that you cannot flip the pinout along either axis by manipulating the connector’s orientation – it is possible to produce a cable equivalent to having connected Pin 1 to Pin 26, Pin 2 to 25 (i.e. rotated 180 degrees) but not one where Pin 1 connects to Pin 2 and vice versa. The problem was instead resolved by desoldering the header and installing a new header on the underside of the board (thanks to Russell Nicholson for his assistance with the desoldering process).
  • 39. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 31 4.4.3 ANALOG TO DIGITAL CONVERTER As discussed in Section 4.3.2, the DSPI peripheral duplicates the Clock and Transfer Attributes register, providing CTAR0 and CTAR1. This is convenient, because the Analog Interface Board has two SPI peripherals, each with its own format and timing requirements. CTAR0 is configured for use with the AD7609 Analog to Digital Converter. Handling the Frame Size AD7609’s serial protocol uses an 18 bit SPI frame, but in master mode the Kinetis DSPI peripheral only supports frames up to 16 bits. To accommodate this requirement, I emulate an 18 bit frame by using two 9 bit “sub-frames”. Figure 13: AD7609 Serial Timing (Analog Devices, 2013, p. 10) The timing requirements of the AD7609 are shown in Figure 13. It can be seen that /CS must remain low for the duration of the 18 bit transfer. This can be achieved using the Continuous Peripheral Chip Select Enable (CONT) flag, which is located in the PUSHR register and thus may be set independently for each transmission. On the first sub-frame, the CONT flag is set. This tells the DSPI to keep the chip select signal asserted after the transfer completes. On the second sub-frame the CONT flag is unset, and the chip select returns to the idle state once the transfer completes. Baud Rate The AD7609 is specified for an SCLK frequency of 15MHz when configured with Vdrive = 3.3V as on the Analog Interface Board.
  • 40. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 32 The DSPI peripheral is clocked from the Bus Clock3 (60 MHz). The DSPI baud rate is set by: 𝑆𝐶𝐾 𝑏𝑎𝑢𝑑 𝑟𝑎𝑡𝑒 = ( 𝑓𝑆 𝑌𝑆 𝑃𝐵𝑅 ) ∗ 1 + 𝐷𝐵𝑅 𝐵𝑅 Where:  PBR is the baud rate prescaler. Valid values correspond to dividers of 1 2 , 1 3 , 1 5 , and 1 7  DBR is a flag which sets double baud rate mode  BR is the baud rate scaler. Valid values are 1 2 𝑛 from ½ through 1 65536 To achieve 15MHz, we need a total scaling factor of 15 60 = 1 4 , which can be achieved by setting PBR to ½ and BR to ½, with double baud rate mode disabled. However, in testing this configuration was found to be unreliable – the ADC shifted data too slowly, resulting in only 17 bits of data being received. The next fastest normal baud rate is 10Mhz (PBR = 1 3 , BR = ½), but it is possible to achieve 12MHz by enabling double baud rate mode (DBR = 1, PBR = 1 5 , BR = ½). This configuration was reliable in testing. Note that using double baud rate (DBR) mode can result in an asymmetric clock waveform. This setup gives the worst-case result of 60% high, 40% low. However, in this case the asymmetry is beneficial. The issue observed at higher clock rates was that the clock high time was too short for the data to be shifted out before the sample was taken on the falling edge of the clock. Using DBR gives a high time roughly equivalent to a 10MHz clock whilst maintaining 12MBit/s throughput, so transfer times are extended by only 25% compared to the 15MHz theoretical maximum. 3 The reference manual claims that this module is clocked from the System Clock. This is incorrect.
  • 41. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 33 Performing an Analog to Digital Conversion Figure 14: AD7609 Acquisition Timing (Analog Devices, 2013, p. 9) The timing of a data conversion is shown in Figure 14. To begin a conversion, the CONVST4 pin is brought high until the BUSY pin is seen to go high in response. The chip reacts only to the rising edge of CONVST, so it is permissible for CONVST to remain high throughout the conversion process. The conversion is complete on the falling edge of the BUSY line, and can now be read out by supplying up to 8 frames of 18 clock cycles on the SPI bus. Channels must be read sequentially, but if less channels are required it is permissible to send only the required number of frames – after a new conversion is performed, the first data shifted onto the SPI bus is always channel 1. Implementation Details A periodic timer is set up to provide an interrupt at the desired sample rate. This ISR calls Analog_AdcTrigger(), which takes CONVST low. The GPIO pin connected to BUSY is configured to generate an interrupt on a falling edge, triggering the ISR Analog_ADC_ConvComplete_ISR() when the falling edge of busy indicates the conversion is complete. This function sets up the Direct Memory Access (DMA) module, which reads the results from the SPI without further CPU intervention, storing them in the array RawResults[]. When the DMA transfer is complete (having read the requested number of channels) an ISR is triggered which sets the boolean flag FreshData, which the application may poll to determine when new data is available. The use of the DMA peripheral is discussed further in the following section. The function Analog_Get() takes a channel number as a parameter, and returns the reassembled 18-bit sample as a signed 32-bit integer. 4 AD7609 provides two CONVST lines. CONVST A starts the acquisition process for the lower four channels, and CONVST B the upper four. The Analog Interface Board ties both pins together, so this document will refer only to CONVST in the singular.
  • 42. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 34 4.4.4 DIGITAL TO ANALOG CONVERTER The AD5754R is part of the AD57x4R family of quad channel Digital to Analog converters, all of which have a compatible pinout and interface. The cheapest device, AD5724R, provides a 12-bit converter. The midrange AD5734R provides a 14-bit converter, and the AD5754R provides a 16-bit converter. No changes to the circuit or software are required when substituting these parts. SPI Configuration The DSPI’s CTAR1 register is configured for use with the AD5754R. Two 12-bit sub- frames with continuous chip select are used to simulate the required 24-bit frame. The AD5754R is specified for use with a 30MHz SCLK, and operates correctly at that speed. See Section 4.4.3 for more details on CTAR configuration. Figure 15: AD5754R Serial and Load Timing Serial Protocol Figure 16: DAC Input Register Layout (Analog Devices, 2011, p. 26) The AD5754R uses a 24-bit SPI frame, as shown in Figure 16. The most significant bit is used to indicate whether this is a read to or a write from the addressed register. Bits REG2-REG0 specify which register is being addressed. Bits A2-A0, and the data bits, vary in their function depending on which register is addressed. If addressing the DAC register, A2-A0 specify which DAC channel is to be updated with the following data. On AD5754R, all 16 bits of data are used for the DAC. On the cheaper models, the least significant bits are treated as don’t-care values.
  • 43. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 35 Startup When the DAC is reset, it must be initialised before use. Firstly, the output range must be set in the Output Range Select Register. Both unipolar and bipolar ranges can be selected, with symmetrical limits at 5V, 10V, or 10.8V. Secondly, each DAC and the internal voltage reference must be powered up by writing to the Power Control Register. The DAC’s require 10µs to power up, and the DAC input register must not be loaded to the DAC during this time. Optionally, the Control register may be written to disable Serial Data Output. This feature, which echoes the previous input to the MISO line, is designed to permit daisy-chaining of DAC’s, but it is not useful in this project. Loading the DAC Figure 17: DAC Input Loading (Analog Devices, 2011, p. 22) After data has been loaded from the SPI input register to the DAC register, the DAC’s may be updated in one of two modes. If /LDAC is held low whilst the data transfer is ongoing, the DAC (and thus the output value) is immediately updated on the rising edge of /SYNC. Alternatively, if /LDAC is high whilst data is loaded, the update does not take effect until LDAC is held low for at least 20ns. This allows for all the DAC’s to be updated simultaneously (see visualisation in Figure 15). This is used in the Maze Rover 2.0 firmware to ensure that DAC updates occur monotonically.
  • 44. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 36 Problems Solved During Testing In early testing, no output was observed from the DAC. Observation on a mixed signal oscilloscope showed that whenever /LDAC was high, so was the Analog Interface Board’s RESET line. Probing with a multimeter confirmed that there was an electrical connection between /LDAC and RESET, but only when the board was assembled as part of the Tower System with the TWR-K70F120M. On the Tower System Connectors, /LDAC is connected to pin B35. The documentation for the TWR-K70F120M board shows that pin B35 is designated GPIO4, and is connected to PTB 8 on the microcontroller. However, PTB 8 is also seen to be used for “RSTOUT_b” on pin A63, which is connected to the RESET line on the Analog Interface Board. Inspection of the TWR-K70F120M schematics showed a 0Ω link (see R140 in Figure 18) connecting PTB 8 to the RESET line. Removing this resistor corrected the behaviour. Because this modification leaves the RESET line floating, I added a 10kΩ pulldown resistor from RESET to ground on the Analog Interface board to ensure RESET was in a known (logic low) state. Figure 18: Schematic Extract Showing Reset 0Ω Link (Freescale Semiconductor, 2011, p. 8) In subsequent tests, output from the DAC was erratic. Sometimes the intended waveform could be seen, but at the wrong scale or offset. Inspecting the Analog Interface Board schematic, I thought I had found the issue when I saw that the REFIN pin was not connected to a 2.5V reference. Soldering a connection from the ADC’s REFOUT pin to the DAC’s REFIN pin resolved the issue, seemingly confirming my belief. However, it later came to my attention that I had been reading the wrong datasheet – Analog Devices produce both an AD5754, which requires an external reference, and an AD5754R. The –R suffixed model includes an internal reference, but it is powered down by default. Adding the necessary code to power up the internal reference allowed the DAC to operate correctly without the additional wire.
  • 45. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 37 4.4.5 USING THE ENHANCED DIRECT MEMORY ACCESS PERIPHERAL Benefits of DMA The Enhanced Direct Memory Access (eDMA) permits data transfer operations to be conducted without the intervention of the host CPU. It is capable of performing its own source and destination offset calculations, permitting it to execute complex data movements, such as reading incoming SPI values into a buffer. To perform such operations using interrupts requires a lot of CPU time – every received SPI frame triggers an interrupt, invoking a context switch every time. This is particularly significant for the ADC, where transferring the conversion results for eight channels results in the reception of 16 9-bit subframes. Furthermore, because the host CPU is fast (clocked at 120MHz), even SPI transfers are relatively slow – assuming the above transfer incurs no overhead and takes exactly 144 cycles at 12MHz to complete, in the meantime 1440 cycles have elapsed at the CPU. In reality, context switching overhead would slow this further, and some of the remaining CPU time would be spent in the ISR supervising the data transfer. By replacing such an interrupt-driven system with DMA, the total transfer time is reduced and the CPU is free to do useful work. Using DMA with the ADC Transmission for the ADC is very simple – the MOSI line of the SPI bus is not even connected to the ADC, so it doesn’t matter what you send provided you supply the right clocks and framing as discussed in Section 4.4.2. As such, the TX data can be pre-allocated to an array (AdcQueue[]). Figure 19: Major and Minor Loops in DMA Requests (Freescale Semiconductor, 2011, p. 586)
  • 46. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 38 The DMA Transmission Control Block (TCD) for the ADC TX is configured to move 4 bytes per minor loop (to understand major and minor loops, see Figure 19). The destination is the SPI2 PUSHR register, and no offset is applied to the destination address – the PUSHR register never moves. The source address is configured to be the array of uint32_t AdcQueue[], advancing the source pointer by four bytes after each transfer (to reach the next 32 bit entry). Only two channels need to be fetched, so the major loop count is set to 4 (2 frames of 2 sub-frames each), and the source address is moved back 16 bytes after the major loop is complete, resetting to the start of the array. The TCD is configured to disable the DMA request upon completion by setting the Disable Request (DREQ) bit. For the ADC RX, the configuration is similar, but the source address remains constant (the SPI2 POPR register) and the destination is the array RawResults[]. Upon completion of the major loop, the RX channel triggers an interrupt (to set the boolean FreshData flag) and disables the DMA request. Using DMA with the DAC For the DAC, the TX configuration is slightly more complex. In order to permit asynchronous queuing of DAC commands, the TX DMA TCD is configured to use the DMA’s modulo feature to implement a FIFO circular buffer for the source. The circular buffer contains 16 uint32_t entries, for a total of 64 bytes, addressed as 0 to 63. 63 is 26 − 1, or 1111112, so the DMA is configured for a 6 bit Source Modulo (SMOD). Note that this requires that the array starts aligned with a 64 byte boundary. I initially overlooked this requirement, resulting in very unpredictable behaviour as the SPI attempted to transmit based on an uninitialized region of memory. This is fixed by using the proprietary GCC attribute “aligned”, like so: uint32_t TxBuffer[BUFFER_SIZE] __attribute__ ((aligned (64))); This project does not make use of the DAC’s readback feature, so the DMA RX channel is not configured when using the DAC. However, some code stubs are included to make implementation of this feature simple if it is desired in the future. Search for the symbol USE_DAC_RX_DMA.
  • 47. Chapter 4: Hardware Abstraction Layer Christopher Kerr Analog Interface Board 39 DMA Arbitration During testing I discovered an issue wherein attempting to connect multiple DMA channels to the same trigger (i.e. connecting the transmit DMA channels for both the DAC and the ADC to the SPI2 transmission complete trigger) would result in unreliable behaviour. Despite having only one channel enabled at a time, sometimes a channel would simply fail to respond to a trigger. To solve this issue, I redesigned the DMA system to use only one transmit channel and one receive channel. This required adding a state machine to manage arbitration of the DMA channels. In summary, it worked as follows: At startup, the DMA channels are not configured, and the state machine is in MODE_UNITIALISED. When either the DAC or the ADC is used, it checks the current state to see if the DMA is configured for the active peripheral. Let us assume, for example, that the ADC is used first after startup. MODE_IDLE_ADC would indicate that the DMA channels are already configured correctly, but we are in MODE_UNITIALISED, so the DMA channels are reconfigured for ADC use. Whilst the transfer is ongoing, the state is set to MODE_ACTIVE, preventing use by the other peripheral. When the transfer is complete, the mode is set to MODE_IDLE_ADC. If no DAC operations are performed before the next ADC operation, no reconfiguration will be required. When a DAC operation is performed, MODE_IDLE_ADC will indicate that reconfiguration is required, and when the operation is complete the DMA arbitration state is MODE_IDLE DAC.
  • 48. Chapter 4: Hardware Abstraction Layer Christopher Kerr Non-Volatile Memory (EEPROM Emulation) 40 4.5 NON-VOLATILE MEMORY (EEPROM EMULATION) The original Maze Rover software stores many user-configurable constants in non-volatile memory (NVM). The MC9S12A512 microcontroller at the heart of the original ModCon provides 4KB of integrated EEPROM, which may be erased in 4 byte sectors and written in 2 byte words. The MK70FN1M0 microcontroller used on the TWR-K70F120M development board does not offer true or emulated EEPROM. The N in the part number indicates that this model has Program Flash only, whereas an X would indicate the presence of Freescale’s FlexMemory feature. FlexMemory permits the designer to partition the available flash between Program Flash and emulated EEPROM. This feature is present on the MK50DX256 used on ModCon 2.0, but for this project an alternative solution was required. The TWR-K70F120M development board offers two external sources of non- volatile memory – 256MB of NAND flash, and a Secure Digital (SD) card slot. However, neither of these features is present on ModCon 2.0, so these solutions would be non-portable. Furthermore, a cursory examination of the relevant datasheet sections indicated that development of drivers would be non-trivial. This leaves only the internal source of NVM, the microcontroller’s Program Flash. Using the Program Flash has the advantage of being available on any Kinetis derivative, but complicates write operations – writes can be as small as 8 bytes (a “phrase”) but erases must be a whole 4KB sector. Since NVM is used in this project to store 1, 2, and 4 byte values which may be updated at runtime, an EEPROM emulation layer is required to give byte-level read/write access. 4.5.1 USING THE FREESCALE 90NM TFS FLASH DRIVER Freescale has a driver for interacting with the Program Flash on Kinetis devices, but it is strangely difficult to find. It can be located by searching for “C90TFS” on the Freescale website, and locating the entry “TFS Flash Driver Software for Kinetis and ColdFire+ Microcontrollers”5. 5 At the time of writing the package can be downloaded directly from: http://cache.freescale.com/files/32bit/software/C90TFS_FLASH_DRIVER.exe
  • 49. Chapter 4: Hardware Abstraction Layer Christopher Kerr Non-Volatile Memory (EEPROM Emulation) 41 The driver package includes a User Manual (Freescale Semiconductor, 2014) and example projects for various derivatives of the Kinetis architecture including the MK70FN1M0. Integrating the driver into my project was straightforward – the driver source and include files were copied into the project tree, and the paths repaired to correctly reflect the new file layout. The configuration files demo_cfg.h and user_cfg.h were copied directly from the MK70FN1M0xxx12 demo provided with the driver. 4.5.2 EEPROM EMULATION The EEPROM emulation module (Eeprom.c) provides byte-level write access to the Program Flash by buffering and modifying whole 4KB sectors. The core functionality of the module is the function Eeprom_Write(), which takes as parameters a pointer to the first byte of data, the data length in bytes, and a pointer to the destination address in Flash memory. Eeprom_Write() is responsible for determining which Flash sector a write affects, buffering that sector, modifying the relevant part of the buffer, erasing the Flash sector, and then writing the buffer to the Flash. This process is performed inside a loop, so the write may cross sector boundaries. The logic is shown in Figure 20. Figure 20: Eeprom_Write Logic Flowchart
  • 50. Chapter 4: Hardware Abstraction Layer Christopher Kerr Non-Volatile Memory (EEPROM Emulation) 42 4.5.3 IMPLEMENTATION DETAILS Program Flash on Kinetis devices is divided into large regions named “blocks” – on the MK70FN1M0 there are four program flash blocks, dividing the 1MB flash into 256KB regions. Attempting to read from a block whilst a write is in progress will result in an access violation error, and the result of the read is invalid. This is important because program instructions and constant data are stored in the program flash. Executing instructions or reading data from the same block as an ongoing write will cause the program to behave unpredictably. This can be avoided by placing simulated EEPROM variables in a different block to the program instructions. CodeWarrior Special Edition imposes a 128KB limit on program size, and the CodeWarrior new project wizard generates a linker map which places the program at the start of the address space. Thus it may be assumed, since 128KB is less than 256KB, that any block beyond the first is available at any time. However, I wished to provide a more generalised solution. This involves executing the function which actually performs the Flash operations from RAM, thus avoiding the need to read from Flash whilst the operation is ongoing. The Freescale flash drivers provide a function designed for this purpose named RelocateFunction(), and use of this function to store FlashCommandSequence() in RAM was simple to integrate into Eeprom_Init(). However, during testing, writes to the first block still caused the program to crash. I initially assumed the debugger was giving faulty data – it indicated that execution had followed a function pointer to address 0x00000000. However, debugging showed that this was exactly the case – an interrupt had caused a read from the interrupt vector table, which returned invalid data resulting in an invalid function pointer dereference. Interrupts must be completely disabled around the write operation if it is to complete safely. This functionality is not enabled by default, because it presents the risk of overwriting the program data. The functionality permitting writing to the first block may be configured by defining or undefining the symbol EEPROM_ANY_BLOCK. The limits of the simulated EEPROM region are set by the pointers k_EepromStartPtr and k_EepromEndPtr.
  • 51. Chapter 5: High Level Functionality Christopher Kerr Maze Rover to PC Communications 43 5 HIGH LEVEL FUNCTIONALITY 5.1 MAZE ROVER TO PC COMMUNICATIONS The Maze Rover is configured using the Maze Rover PC Interface, an application running on a Windows PC. The PC Interface communicates with the Rover via an emulated UART, using a modified version of Dr McLean’s ModCon Serial Protocol. 5.1.1 MODCON SERIAL PROTOCOL Structure The ModCon Serial Protocol (McLean, 2013) defines a 5-byte packet structure as shown in Figure 21 below. Command Parameter 1 Parameter 2 Parameter 3 Checksum Figure 21: Serial Protocol Packet Structure The most significant bit of the command byte is reserved for packet acknowledgement requests. The remaining 7 bits store the command number, thus permitting 128 unique commands (0x00 – 0x7F). The function of the three parameter bytes may vary depending on the command. The final byte carries a checksum, which is simply the exclusive-or (XOR) of the preceding four bytes. Whilst not very theoretically robust (compared to popular checksum methods like Cyclic Redundancy Checking), this checksum is computationally inexpensive and quite adequate in this application. The emulated UART used to communicate with the Maze Rover is implemented using the USB Communications Device Class, which includes its own robust methods for ensuring data integrity. Packet Acknowledgement The sender requests acknowledgement from the receiver by setting the most significant bit (the ACK bit) of the Command byte. The receiver first attempts to complete the requested command. If successful (or if no action is required), it returns a copy of the packet with the ACK bit set. If unsuccessful, the packet is modified to unset the ACK bit before being returned, thus sending a NACK.
  • 52. Chapter 5: High Level Functionality Christopher Kerr Maze Rover to PC Communications 44 5.1.2 IMPLEMENTATION DETAILS Most of the implementation is straightforward, and neither novel nor interesting. packet.c contains functions for recognising valid received packets (Packet_Get()) and assembling packets for transmission (Packet_Put()). When a valid packet is received, it is then passed to Protocol_HandlePacket(). This function handles processing received packets, selecting the appropriate function based on the received command. Implemented as a switch statement, it looks like this: switch(maskedCommand) { case CMD_STARTUP: retVal = Packet_HandleStartup(); break; case CMD_TIME: retVal = Packet_HandleTime(); break; ... // and so on, for many cases Whilst this construct is simple and easily maintained at this size, the function may potentially be required to scale to 128 entries. The resulting function would be long and difficult to maintain. I prefer to address this problem with an array of function pointers, and discuss the practicality of this solution below. Function Pointers In C, a pointer named funcPtr to a function which takes a Packet_t as a parameter, and returns a bool, can be declared like so: bool (*funcPtr)(Packet_t); This syntax, which arises from C’s “declaration follows usage” design pattern, is difficult for readers to parse. It is typically preferred to use a typedef to name function pointers of a given signature (parameters and return type) as a type, permitting a more typical declaration. The following extract creates a pointer named funcPtr to a function Protocol_HandleStartup(), then dereferences that pointer to call the function (note that in C, &fooFunc and fooFunc are equivalent – either gives the address of the function fooFunc): typedef bool(*Protocol_jumpPtr_t)(const Packet_t); Protocol_jumpPtr_t funcPtr = Protocol_HandleStartup; bool retVal = *funcPtr(fooPacket);
  • 53. Chapter 5: High Level Functionality Christopher Kerr Maze Rover to PC Communications 45 Switch Statements vs Function Pointer Arrays An array of function pointers named jumpTable may be created like so: typedef bool(*Protocol_jumpPtr_t)(const Packet_t); static const Protocol_jumpPtr_t jumpTable[] = { Packet_HandleStartup, // 0x00 Packet_handleDefault, // 0x01 – Unused Packet_HandleTime // 0x02 }; Now the appropriate function for handling the command stored in an appropriately range-tested variable named maskedCommand can be called by: bool retVal = *jumpTable[maskedcommand](fooPacket); The advantages of using an array of function pointers are:  Reduced logic complexity – new functionality can be added by altering only the statically-allocated array, without need to modify the program logic  Improved speed – each case in a switch statement is tested sequentially, and conditional logic is slow. For switches with many cases, the time spent processing the switch becomes significant, so such designs scale poorly. However, there are also some disadvantages:  C does not test if an array index actually lies within the bounds of the array, so the index value must be correctly range limited before use.  Unused cases must be handled – there is no safe way to skip inclusion of an element in a function pointer array, so a dummy function must be inserted for all unused indices. For Protocol_HandlePacket(), the dummy function simply returns false without performing any other action. As a result of this second drawback, the function pointer array must be at least as large as the difference between the lowest expected index (which can be offset to 0 by a subtraction) and the highest. However, if the array is declared static const it will be stored in Flash, where bytes are plentiful. Thus, I chose to include the full range of possible values from 0x00 to 0x7F in my jump table, with each entry commented as shown in the example above. This makes it easy to find the entry for a given command code, and to visually distinguish unused codes.
  • 54. Chapter 5: High Level Functionality Christopher Kerr Maze Rover Communications Functions 46 5.2 MAZE ROVER COMMUNICATIONS FUNCTIONS The communications functions are a direct port of those written by Dr McLean for the original Maze Rover. I will briefly outline their function, and discuss the adaptations required to have them function correctly in my project. 5.2.1 MODULATED WAVEFORM GENERATION Comms_MakeWave() pre-calculates an amplitude modulated waveform, storing it in the array WaveData[]. Interestingly, this function does not actually perform amplitude modulation, but rather emulates it by adding sinusoidal components. When considered in the frequency domain, it can be seen that this produces the same output signal as amplitude modulation, but only if the message signals are sinusoids. The only significant changes made to this function were:  Updating the cosine-wave table to provide full 16 bit resolution. This was not strictly necessary, but seemed proper – the new platform uses a proper DAC in place of the smoothed PWM of the original Maze Rover, making it capable of much higher fidelity.  Updated data types to ensure results would not be truncated as a result of the 16-bit cos wave input A third change which was not made, but may be considered, relates to the divisor used to scale the summed waveforms to an int16_t for output. I have kept the same value as the original ModCon (21 * 2 = 42), but this results in an output which is 10Vpp rather than the 5Vpp of the original system. It is my opinion that the 5Vpp output used in the original Maze Rover was merely the result of its technical limitations, and thus have made no deliberate effort to replicate this characteristic. 5.2.2 VOLTAGE CONTROLLED OSCILLATOR The function Comms_UpdateVCO() implements a numerically controlled sinusoidal oscillator. When provided with ADC samples as input, it may be considered a Voltage Controlled Oscillator. No modifications to this function were performed, but it is necessary to modify the way in which it is called in order to preserve its
  • 55. Chapter 5: High Level Functionality Christopher Kerr Maze Rover Communications Functions 47 intended performance. When the numerical input is supplied by the Analog Interface Board’s 18-bit ADC, it is necessary to divide by 64 to preserve the intended voltage-to-frequency relationship. However, this change should not be made internal to the function, as this would render it incompatible with the Phase-Locked Loop. 5.2.3 PHASE LOCKED LOOP No changes to the PLL were required, but during testing (see Section 0) it was noted that the PLL performed well over only a very limited range of frequencies, perhaps 250Hz either side of the VCO’s centre frequency. This may merit further investigation, but I spent no further time on it given that the demodulator, which relies upon the PLL to resynthesise the carrier wave, operates without issue. 5.2.4 DEMODULATION Comms_DetectDemod() implements a coherent demodulation system as outlined in Figure 22. The modulated waveform is multiplied by the oscillator recovered by the phase-locked loop, then filtered by a comb-resonator cascade. Figure 22: Coherent Demodulation Scheme However, the resulting signal is not used as the output. Instead, a Sliding Discrete Fourier Transform is used to determine the magnitudes of the expected message frequencies, and these magnitudes are used by Comms_MakeDemod() to synthesise a clean version of the demodulated signal. 5.2.5 TESTING This project is focused on embedded software development, not signal theory. As such, I have used the pre-solved “Automatic” coefficients for testing, rather than presenting my own derivation.
  • 56.
  • 57. Chapter 6: Communication Lab Testing Christopher Kerr Modulated Wave Generation 49 6 COMMUNICATION LAB TESTING 6.1 MODULATED WAVE GENERATION Single Sideband Lower Figure 23: SSB-Lower Time Domain Figure 24: SSB-Lower Frequency Domain Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq. Odd Autumn A 1050 Hz ☑ 375 Hz ☑ 425 Hz ☑
  • 58. Chapter 6: Communication Lab Testing Christopher Kerr Modulated Wave Generation 50 Single Sideband Upper Figure 25: SSB-Upper Time Domain Figure 26: SSB-Upper Frequency Domain Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq. Odd Autumn I 1100 Hz ☑ 75 Hz ☑ 125 Hz ☑
  • 59. Chapter 6: Communication Lab Testing Christopher Kerr Modulated Wave Generation 51 Double Sideband Figure 27: SSB-HI Time Domain Figure 28: SSB-HI Frequency Domain Rover Spec Carrier Freq. Msg 1 Freq. Msg 2 Freq. Odd Autumn E 700 Hz ☑ 425 Hz ☑ 375 Hz ☑
  • 60. Chapter 6: Communication Lab Testing Christopher Kerr Voltage-Controlled Oscillator 52 6.2 VOLTAGE-CONTROLLED OSCILLATOR For this test I have used the configuration of Maze Rover B, Spring Semester 2013, in order to permit comparison to the known results of an original Maze Rover. The centre frequency for this configuration is 1100Hz. Input Voltage Frequency (tested) Frequency (sample) -2.5 1474.1 1497 -2.25 1436.7 1452 -2 1400.0 1417 -1.5 1324.2 1341 -1 1249.1 1267 -0.5 1174.2 1192 0 1099.6 1110 0.5 1024.5 1035 1 949.4 958 1.5 874.3 885.3 2 799.3 812.7 2.25 761.8 774 2.5 724.3 749.9 Notice that the tested values which are multiples of 0.5 volts give frequencies which are very close to multiples of 25. In my opinion, this suggests that my measurements are more accurate than those I am comparing against. This is supported by the linear regression shown in Figure 29. Figure 29: Voltage Controlled Oscillator Characteristic Sample: y = -150.77x + 1114.7 Tested: y = -150x + 1099.3 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 -2.5 -1.5 -0.5 0.5 1.5 2.5 OutputFrequency(Hz) Input Voltage (V) Frequency (sample) Frequency (tested)
  • 61. Chapter 6: Communication Lab Testing Christopher Kerr Phase Locked Loop 53 A note on the testing procedure: It is typically difficult to measure the frequency of unfiltered DAC-synthesised sine waves, since features are not typically placed consistently between cycles. However, when using a digital storage oscilloscope such as the Agilent DSO-X 2004A used in these tests, the Fast Fourier Transform functionality provides a useful method for making accurate measurement measurements of frequency. The high-order frequency components which make up the “stair-step” characteristic are easily distinguished from the fundamental when viewed in the frequency domain. 6.3 PHASE LOCKED LOOP Figure 30: Phase-Locked Loop Operation The Phase-Locked Loop works very well over a limited range of frequencies, but performance rapidly degrades as the input frequency diverges from that shown in Figure 30. Debugging did not reveal any obvious inconsistency in operation. Both the Voltage Controlled Oscillator and the demodulator operate correctly, and these components are closely related to the Phase Locked Loop.
  • 62. Chapter 6: Communication Lab Testing Christopher Kerr Demodulator 54 6.4 DEMODULATOR For this test, the same configuration was used as in Section 6.2 (Rover B, Spring Semester 2013). This configuration uses single-sideband upper modulation, with messages frequencies 300Hz and 350Hz. These frequencies have been perfectly reconstructed, as seen in Figure 32. Figure 31: Demodulated Message Signal Time Domain Figure 32: Demodulated Message Signal Frequency Domain
  • 63. Chapter 7: Control Implementation Christopher Kerr Controlled Plant: Quanser MAGLEV 55 7 CONTROL IMPLEMENTATION Finalised Maze Rover 2.0 hardware was not available during the development of this project, so implementation and testing of the Maze Rover’s Model Reference Adaptive Controller could not be performed. Instead, an alternative control task was implemented on this platform using the Quanser MAGLEV apparatus, demonstrating the viability of ModCon 2.0 for performing complex control tasks. 7.1 CONTROLLED PLANT: QUANSER MAGLEV Figure 33: Quanser MAGLEV Apparatus The Quanser MAGLEV plant, seen in Figure 33, is an electromagnetic suspension system. One pole of an electromagnet faces downward towards a post on which a stainless steel ball sits when at rest. The pole contains a photo-transistor based sensor which measures the distance from the top of the post to the surface of the ball. A one Ohm current-sense resistor is provided, giving a 1 VA-1 response. Using this apparatus, the goal of the controller is to modulate the input voltage of the electromagnet such that ball tracks to a specified point in the vertical axis. The derivation of a system model and LQR controller for this plant can be found in Appendix B.