· 6 years ago · Sep 12, 2019, 03:22 PM
1Discovering the STM32 Microcontroller
2Geoffrey Brown
3©2012
4June 5, 2016
5This work is covered by the Creative Commons Attibution-NonCommercialShareAlike 3.0 Unported (CC BY-NC-SA 3.0) license.
6http://creativecommons.org/licenses/by-nc-sa/3.0/
7Revision: 14c8a1e (2016-06-05) 1
8Contents
9List of Exercises 7
10Foreword 11
111 Getting Started 13
121.1 Required Hardware . . . . . . . . . . . . . . . . . . . . . . . . . 16
13STM32 VL Discovery . . . . . . . . . . . . . . . . . . . . . . . 16
14Asynchronous Serial . . . . . . . . . . . . . . . . . . . . . . . . 19
15SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
16I2C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
17Time Based . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
18Analog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
19Power Supply . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
20Prototyping Materials . . . . . . . . . . . . . . . . . . . . . . . 25
21Test Equipment . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
221.2 Software Installation . . . . . . . . . . . . . . . . . . . . . . . . 26
23GNU Tool chain . . . . . . . . . . . . . . . . . . . . . . . . . . 27
24STM32 Firmware Library . . . . . . . . . . . . . . . . . . . . . 27
25Code Template . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
26GDB Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
271.3 Key References . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
282 Introduction to the STM32 F1 31
292.1 Cortex-M3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
302.2 STM32 F1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
313 Skeleton Program 47
32Demo Program . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
33Make Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
34STM32 Memory Model and Boot Sequence . . . . . . . . . . . 52
352 Revision: 14c8a1e (2016-06-05)
36CONTENTS
374 STM32 Configuration 57
384.1 Clock Distribution . . . . . . . . . . . . . . . . . . . . . . . . . 61
394.2 I/O Pins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
404.3 Alternative Functions . . . . . . . . . . . . . . . . . . . . . . . 65
414.4 Remapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
424.5 Pin Assignments For Examples and Exercises . . . . . . . . . . 66
434.6 Peripheral Configuration . . . . . . . . . . . . . . . . . . . . . . 68
445 Asynchronous Serial Communication 71
455.1 STM32 Polling Implementation . . . . . . . . . . . . . . . . . . 76
465.2 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
476 SPI 85
486.1 Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
496.2 STM32 SPI Peripheral . . . . . . . . . . . . . . . . . . . . . . . 87
506.3 Testing the SPI Interface . . . . . . . . . . . . . . . . . . . . . 90
516.4 EEPROM Interface . . . . . . . . . . . . . . . . . . . . . . . . . 92
527 SPI : LCD Display 97
537.1 Color LCD Module . . . . . . . . . . . . . . . . . . . . . . . . . 97
547.2 Copyright Information . . . . . . . . . . . . . . . . . . . . . . . 108
557.3 Initialization Commands (Remainder) . . . . . . . . . . . . . . 108
568 SD Memory Cards 111
578.1 FatFs Organization . . . . . . . . . . . . . . . . . . . . . . . . . 114
588.2 SD Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
598.3 FatFs Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . 122
609 I2C – Wii Nunchuk 123
619.1 I2C Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
629.2 Wii Nunchuk . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
639.3 STM32 I2C Interface . . . . . . . . . . . . . . . . . . . . . . . . 131
6410 Timers 139
6510.1 PWM Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
667735 Backlight . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
6710.2 Input Capture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
6811 Interrupts 151
6911.1 Cortex-M3 Exception Model . . . . . . . . . . . . . . . . . . . . 155
7011.2 Enabling Interrupts and Setting Their Priority . . . . . . . . . 159
71Revision: 14c8a1e (2016-06-05) 3
72CONTENTS
7311.3 NVIC Configuration . . . . . . . . . . . . . . . . . . . . . . . . 159
7411.4 Example: Timer Interrupts . . . . . . . . . . . . . . . . . . . . 160
7511.5 Example: Interrupt Driven Serial Communications . . . . . . . 161
76Interrupt-Safe Queues . . . . . . . . . . . . . . . . . . . . . . . 165
77Hardware Flow Control . . . . . . . . . . . . . . . . . . . . . . 167
7811.6 External Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . 171
7912 DMA: Direct Memory Access 179
8012.1 STM32 DMA Architecture . . . . . . . . . . . . . . . . . . . . . 181
8112.2 SPI DMA Support . . . . . . . . . . . . . . . . . . . . . . . . . 182
8213 DAC : Digital Analog Converter 189
83Warning: . . . . . . . . . . . . . . . . . . . . . . 190
8413.1 Example DMA Driven DAC . . . . . . . . . . . . . . . . . . . . 194
8514 ADC : Analog Digital Converter 201
8614.1 About Successive Approximation ADCs . . . . . . . . . . . . . 202
8715 NewLib 209
8815.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
8915.2 Building newlib . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
9016 Real-Time Operating Systems 217
9116.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
9216.2 FreeRTOS Configuration . . . . . . . . . . . . . . . . . . . . . . 224
9316.3 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
9416.4 Interrupt Handlers . . . . . . . . . . . . . . . . . . . . . . . . . 227
9516.5 SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
9616.6 FatFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
9716.7 FreeRTOS API . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
9816.8 Discusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9917 Next Steps 235
10017.1 Processors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
10117.2 Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
102Position/Inertial Measurement . . . . . . . . . . . . . . . . . . 238
103Environmental Sensors . . . . . . . . . . . . . . . . . . . . . . . 238
104Motion and Force Sensors . . . . . . . . . . . . . . . . . . . . . 239
105ID – Barcode/RFID . . . . . . . . . . . . . . . . . . . . . . . . 239
106Proximity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
10717.3 Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
1084 Revision: 14c8a1e (2016-06-05)
109CONTENTS
11017.4 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
111Attributions 242
112Bibliography 243
113Revision: 14c8a1e (2016-06-05) 5
114CONTENTS
115List of exercises
116Exercise 3.1 GDB on STM32 . . . . . . . . . . . . . . . . . . . . . 50
117Exercise 4.1 Blinking Lights . . . . . . . . . . . . . . . . . . . . . . 60
118Exercise 4.2 Blinking Lights with Pushbutton . . . . . . . . . . . . . 65
119Exercise 4.3 Configuration without Standard Peripheral Library . . 68
120Exercise 5.1 Testing the USB/UART Interface . . . . . . . . . . . . 73
121Exercise 5.2 Hello World! . . . . . . . . . . . . . . . . . . . . . . . 80
122Exercise 5.3 Echo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
123Exercise 6.1 SPI Loopback . . . . . . . . . . . . . . . . . . . . . . . 91
124Exercise 6.2 Write and Test an EEPROM Module . . . . . . . . . . 96
125Exercise 7.1 Complete Interface Code . . . . . . . . . . . . . . . . . 101
126Exercise 7.2 Display Text . . . . . . . . . . . . . . . . . . . . . . . . 102
127Exercise 7.3 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . 103
128Exercise 8.1 FAT File System . . . . . . . . . . . . . . . . . . . . . 118
129Exercise 9.1 Reading Wii Nunchuk . . . . . . . . . . . . . . . . . . 130
130Exercise 10.1 Ramping LED . . . . . . . . . . . . . . . . . . . . . . 144
131Exercise 10.2 Hobby Servo Control . . . . . . . . . . . . . . . . . . 144
132Exercise 10.3 Ultrasonic Sensor . . . . . . . . . . . . . . . . . . . . 149
133Exercise 11.1 Timer Interrupt – Blinking LED . . . . . . . . . . . . 161
134Exercise 11.2 Interrupt Driven Serial Communciations . . . . . . . 170
135Exercise 11.3 External Interrupt . . . . . . . . . . . . . . . . . . . . 173
136Exercise 12.1 SPI DMA module . . . . . . . . . . . . . . . . . . . . 185
137Exercise 12.2 Display BMP Images from Fat File System . . . . . . 185
138Exercise 13.1 Waveform Generator . . . . . . . . . . . . . . . . . . 190
139Exercise 13.2 Application Software Driven Conversion . . . . . . . 191
140Exercise 13.3 Interrupt Driven Conversion . . . . . . . . . . . . . . 192
141Exercise 13.4 Audio Player . . . . . . . . . . . . . . . . . . . . . . . 195
142Exercise 14.1 Continuous Sampling . . . . . . . . . . . . . . . . . . 205
143Exercise 14.2 Timer Driven Conversion . . . . . . . . . . . . . . . 207
144Exercise 14.3 Voice Recorder . . . . . . . . . . . . . . . . . . . . . . 208
1456 Revision: 14c8a1e (2016-06-05)
146CONTENTS
147Exercise 15.1 Hello World . . . . . . . . . . . . . . . . . . . . . . . 213
148Exercise 16.1 RTOS – Blinking Lights . . . . . . . . . . . . . . . . 225
149Exercise 16.2 Multiple Threads . . . . . . . . . . . . . . . . . . . . 227
150Exercise 16.3 Multithreaded Queues . . . . . . . . . . . . . . . . . . 228
151Exercise 16.4 Multithreaded SPI . . . . . . . . . . . . . . . . . . . . 232
152Exercise 16.5 Multithreaded FatFS . . . . . . . . . . . . . . . . . . . 232
153Revision: 14c8a1e (2016-06-05) 7
154
155Acknowledgment
156I have had a lot of help from various people in the Indiana University
157School of Informatics in developing these materials. Most notably, Caleb Hess
158developed the protoboard that we use in our lab, and he, along with Bryce
159Himebaugh made significant contributions to the development of the various
160experiments. Tracey Theriault provided many of the photographs.
161I am grateful to ST Microelectronics for the many donations that allowed us to develop this laboratory. I particularly wish to thank Andrew
162Dostie who always responded quickly to any request that I made.
163STM32 F1, STM32 F2, STM32 F3, STM32 F4, STM32 L1, Discovery
164Kit, Cortex, ARM and others are trademarks and are the property of their
165owners.
166Revision: 14c8a1e (2016-06-05) 9
167
168Foreword
169This book is intended as a hands-on manual for learning how to design systems using the STM32 F1 family of micro-controllers. It was written
170to support a junior-level computer science course at Indiana University. The
171focus of this book is on developing code to utilize the various peripherals available in STM32 F1 micro-controllers and in particular the STM32VL Discovery
172board. Because there are other fine sources of information on the Cortex-M3,
173which is the core processor for the STM32 F1 micro-controllers, we do not
174examine this core in detail; an excellent reference is “The Definitive Guide to
175the ARM CORTEX-M3.” [5]
176This book is not exhaustive, but rather provides a single “trail” to
177learning about programming STM32 micro controller built around a series of
178laboratory exercises. A key design decision was to utilize readily available
179off-the-shelf hardware models for all the experiments discussed.
180I would be happy to make available to any instructor the other materials developed for teaching C335 (Computer Structures) at Indiana University;
181however, copyright restrictions limit my ability to make them broadly available.
182Geoffrey Brown
183Indiana University
184Revision: 14c8a1e (2016-06-05) 11
185
186Chapter 1
187Getting Started
188The last few years has seen a renaissance of hobbyists and inventors
189building custom electronic devices. These systems utilize off-the-shelf components and modules whose development has been fueled by a technological
190explosion of integrated sensors and actuators that incorporate much of the
191analog electronics which previously presented a barrier to system development by non-engineers. Micro-controllers with custom firmware provide the
192glue to bind sophisticated off-the-shelf modules into complex custom systems.
193This book provides a series of tutorials aimed at teaching the embedded programming and hardware interfacing skills needed to use the STM32 family of
194micro-controllers in developing electronic devices. The book is aimed at readers with ’C’ programming experience, but no prior experience with embedded
195systems.
196The STM32 family of micro-controllers, based upon the ARM CortexM3 core, provides a foundation for building a vast range of embedded systems
197from simple battery powered dongles to complex real-time systems such as
198helicopter autopilots. This component family includes dozens of distinct configurations providing wide-ranging choices in memory sizes, available peripherals, performance, and power. The components are sufficiently inexpensive
199in small quantities – a few dollars for the least complex devices – to justify
200their use for most low-volume applications. Indeed, the low-end “Value Line”
201components are comparable in cost to the ATmega parts which are used for
202the popular Arduino development boards yet offer significantly greater performance and more powerful peripherals. Furthermore, the peripherals used are
203shared across many family members (for example, the USART modules are
204common to all STM32 F1 components) and are supported by a single firmware
205library. Thus, learning how to program one member of the STM32 F1 family
206Revision: 14c8a1e (2016-06-05) 13
207CHAPTER 1. GETTING STARTED
208enables programming them all. 1
209Unfortunately, power and flexibility are achieved at a cost – software
210development for the STM32 family can be extremely challenging for the uninitiated with a vast array of documentation and software libraries to wade
211through. For example, RM0041, the reference manual for large value-line
212STM32 F1 devices, is 675 pages and does not even cover the Cortex-M3 processor core ! Fortunately, it is not necessary to read this book to get started
213with developing software for the STM32, although it is an important reference. In addition, a beginner is faced with many tool-chain choices. 2
214In
215contrast, the Arduino platform offers a simple application library and a single
216tool-chain which is accessible to relatively inexperienced programmers. For
217many simple systems this offers a quick path to prototype. However, simplicity has its own costs – the Arduino software platform isn’t well suited to
218managing concurrent activities in a complex real-time system and, for software interacting with external devices, is dependent upon libraries developed
219outside the Arduino programming model using tools and techniques similar
220to those required for the STM32. Furthermore, the Arduino platform doesn’t
221provide debugging capability which severely limits the development of more
222complex systems. Again, debugging requires breaking outside the confines of
223the Arduino platform. Finally, the Arduino environment does not support
224a real-time operating system (RTOS), which is essential when building more
225complex embedded systems.
226For readers with prior ’C’ programming experience, the STM32 family
227is a far better platform than the Arduino upon which to build micro-controller
228powered systems if the barriers to entry can be reduced. The objective of this
229book is to help embedded systems beginners get jump started with programming the STM32 family. I do assume basic competence with C programming
230in a Linux environment – readers with no programming experience are better
231served by starting with a platform like Arduino. I assume familiarity with
232a text editor; and experience writing, compiling, and debugging C programs.
233I do not assume significant familiarity with hardware – the small amount of
234“wiring” required in this book can easily be accomplished by a rank beginner.
235The projects I describe in this book utilize a small number of read1There are currently five families of STM32 MCUs – STM32 F0, STM32 F1, STM32
236L1, STM32 F2, and STM32 F4 supported by different, but structurally similar, firmware
237libraries. While these families share many peripherals, some care is needed when moving
238projects between these families. [18, 17, 16]
2392A tool-chain includes a compiler, assembler, linker, debugger, and various tools for
240processing binary files.
24114 Revision: 14c8a1e (2016-06-05)
242ily available, inexpensive, off-the-shelf modules. These include the amazing
243STM32 VL Discovery board (a $10 board that includes both an STM32 F100
244processor and a hardware debugger link), a small LCD display, a USB/UART
245bridge, a Wii Nunchuk, and speaker and microphone modules. With this
246small set of components we can explore three of the most important hardware
247interfaces – serial, SPI, and I2C – analog input and output interfaces, and
248the development of firmware utilizing both interrupts and DMA. All of the
249required building blocks are readily available through domestic suppliers as
250well as ebay vendors. I have chosen not to utilize a single, comprehensive,
251“evaluation board” as is commonly done with tutorials because I hope that
252the readers of this book will see that this basic collection of components along
253with the software techniques introduced provides the concepts necessary to
254adapt many other off-the-self components. Along the way I suggest other
255such modules and describe how to adapt the techniques introduced in this
256book to their use.
257The development software used in this book is all open-source. Our
258primary resource is the GNU software development tool-chain including gcc,
259gas, objcopy, objdump, and the debugger gdb. I do not use an IDE such
260as eclipse. I find that most IDEs have a high startup cost although they
261can ultimately streamline the development process for large systems. IDEs
262also obscure the compilation process in a manner that makes it difficult to
263determine what is really happening, when my objective here is to lay bare the
264development process. While the reader is welcome to use an IDE, I offer no
265guidance on setting one up. One should not assume that open-source means
266lower quality – many commercial tool-chains for embedded systems utilize
267GNU software and a significant fraction of commercial software development is
268accomplished with GNU software. Finally, virtually every embedded processor
269is supported by the GNU software tool-chain. Learning to use this toolchain on one processor literally opens wide the doors to embedded software
270development.
271Firmware development differs significantly from application development because it is often exceedingly difficult to determine what is actually
272happening in code that interacts with a hardware peripheral simply through
273examining program state. Furthermore, in many situations it is impractical
274to halt program execution (e.g., through a debugger) because doing so would
275invalidate real-time behavior. For example, in developing code to interface
276with a Wii Nunchuk (one of the projects described in this book) I had difficulty tracking down a timing bug which related to how fast data was being
277“clocked” across the hardware interface. No amount of software debugging
278Revision: 14c8a1e (2016-06-05) 15
279CHAPTER 1. GETTING STARTED
280could have helped isolate this problem – I had to have a way to see the hardware behavior. Similarly, when developing code to provide flow-control for a
281serial interface, I found my assumptions about how the specific USB/UART
282bridge I was communicating with were wrong. It was only through observing
283the hardware interface that I found this problem.
284In this book I introduce a firmware development process that combines
285traditional software debugging (with GDB), with the use of a low-cost “logic
286analyzer” to allow the capture of real-time behavior at hardware interfaces.
2871.1 Required Hardware
288A list of the hardware required for the tutorials in this book is provided
289in Figure 1.1. The component list is organized by categories corresponding
290to the various interfaces covered by this book followed by the required prototyping materials and test equipment. In the remainder of this section, I
291describe each of these components and, where some options exist, key properties that must be satisfied. A few of these components require header pins
292to be soldered on. This is a fairly simple task that can be accomplished with
293even a very low cost pencil soldering iron. The amount of soldering required
294is minimal and I recommend borrowing the necessary equipment if possible.
295There are many soldering tutorials on the web.
296The most expensive component required is a logic analyzer. While I
297use the Saleae Logic it may be too expensive for casual hobbyists ($150).3 An
298alternative, OpenBench Logic Sniffer, is considerably cheaper ($50) and probably adequate. My choice was dictated by the needs of a teaching laboratory
299where equipment takes a terrific beating – the exposed electronics and pins of
300the Logic Sniffer are too vulnerable for such an environment. An Oscilloscope
301might be helpful for the audio interfaces, but is far from essential.
302STM32 VL Discovery
303The key component used in the tutorials is the STM32 VL discovery
304board produced by STMicroelectronics (ST) and available from many electronics distributors for approximately $10. 4 This board, illustrated in Figure 1.2
305includes a user configurable STM32 F100 micro-controller with 128 KB flash
306and 8 KB ram as well as an integrated hardware debugger interface based
307upon a dedicated USB connected STM32 F103. With appropriate software
3083At the time of writing Saleae offers a discount to students and professors.
3094http://www.st.com/internet/evalboard/product/250863.jsp
31016 Revision: 14c8a1e (2016-06-05)
3111.1. REQUIRED HARDWARE
312Component Supplier cost
313Processor
314STM32 VL discovery Mouser, Digikey, Future Electronics
315$10
316Asynchronous Serial
317USB/UART breakout Sparkfun, Pololu, ebay $7-$15
318SPI
319EEPROM (25LC160) Digikey, Mouser, others $0.75
320LCD (ST7735) ebay and adafruit $16-$25
321Micro SD card (1-2G) Various $5
322I2C
323Wii Nunchuk ebay (clones), Amazon $6-$12
324Nunchuk Adaptor Sparkfun, Adafruit $3
325Time Based
326Hobby Servo (HS-55 micro) ebay $5
327Ultrasonic range finder (HC-SR04) ebay $4
328Analog
329Potentiometer Digikey, Mouser, ebay $1
330Audio amplifier Sparkfun (TPA2005D1) $8
331Speaker Sparkfun COM-10722 $1
332Microphone Module Sparkfun (BOB-09868 or
333BOB-09964)
334$8-$10
335Power Supply (optional)
336Step Down Regulator (2110) Pololu $15
3379V Battery Holder
3389V Battery
339Prototyping Materials
340Solderless 700 point breadboard (2) ebay $6
341Jumper wires ebay $5-$10
342Test Equipment
343Saleae Logic or Saleae $150
344Oscilloscope optional for testing analog
345output
346Figure 1.1: Required Prototype Hardware and Suppliers
347running on the host it is possible to connect to the STM32 F100 processor to
348download, execute, and debug user code. Furthermore, the hardware debugRevision: 14c8a1e (2016-06-05) 17
349CHAPTER 1. GETTING STARTED
350Figure 1.2: STM32 VL Discovery Board
351ger interface is accessible through pin headers and can be used to debug any
352member of the STM32 family – effectively, ST are giving away a hardware
353debugger interface with a basic prototyping board. The STM32 VL Discovery
354board is distributed with complete documentation including schematics. [14].
355In the photograph, there is a vertical white line slightly to the left of
356the midpoint. To the right of the line are the STM32 F100, crystal oscillators,
357two user accessible LEDs, a user accessible push-button and a reset push
358button. To the left is the hardware debugger interface including an STM32
359F103, voltage regulator, and other components. The regulator converts the 5V
360supplied by the USB connection to 3.3V for the processors and also available
361at the board edge connectors. This regulator is capable of sourcing sufficient
362current to support the additional hardware used for the tutorials.
363All of the pins of the STM32 F100 are brought out to well labeled
364headers – as we shall see the pin labels directly correspond to the logical names
365used throughout the STM32 documentation rather than the physical pins
366associated with the particular part/package used. This use of logical names
367is consistent across the family and greatly simplifies the task of designing
368portable software.
369The STM32 F100 is a member of the value line STM32 processors and
370executes are a relatively slow (for Cortex-M3 processors) 24Mhz, yet provides
371far more computation and I/O horsepower than is required for the tutorials
372described in this book. Furthermore, all of the peripherals provided by the
373STM32 F100 are common to the other members of the STM32 family and,
374the code developed on this component is completely portable across the micro18 Revision: 14c8a1e (2016-06-05)
3751.1. REQUIRED HARDWARE
376controller family.
377Asynchronous Serial
378One of the most useful techniques for debugging software is to print
379messages to a terminal. The STM32 micro-controllers provide the necessary
380capability for serial communications through USART (universal synchronous
381asynchronous receiver transmitter) devices, but not the physical connection
382necessary to communicate with a host computer. For the tutorials we utilize
383a common USB/UART bridge. The most common of these are meant as serial port replacements for PCs and are unsuitable for our purposes because
384they include voltage level converters to satisfy the RS-232 specification. Instead we require a device which provides more direct access to the pins of the
385USB/UART bridge device.
386Figure 1.3: Pololu CP2102 Breakout Board
387An example of such a device, shown in Figure 1.3 is the Pololu cp2102
388breakout board. An alternative is the Sparkfun FT232RL breakout board
389(BOB-00718) which utilizes the FTDI FT232RL bridge chip. I purchased a
390cp2102 board on ebay which was cheap and works well. While a board with
391either bridge device will be fine, it is important to note that not all such boards
392are suitable. The most common cp2102 boards, which have a six pin header,
393do not provide access the the hardware flow control pins that are essential
394for reliable high speed connection. An important tutorial in this book covers
395the implementation of a reliable high-speed serial interface. You should look
396at the pin-out for any such board to ensure at least the following signals are
397available – rx, tx, rts, cts.
398Asynchronous serial interfaces are used on many commonly available
399modules including GPS (global positioning system) receivers, GSM cellular
400modems, and bluetooth wireless interfaces.
401Revision: 14c8a1e (2016-06-05) 19
402CHAPTER 1. GETTING STARTED
403Figure 1.4: EEPROM in PDIP Package
404SPI
405The simplest of the two synchronous serial interfaces that we examine
406in this book is SPI. The key modules we consider are a color LCD display
407and an SD flash memory card. As these represent relatively complex uses
408of the SPI interface, we first discuss a simpler device – a serial EEPROM
409(electrically erasable programmable memory). Many embedded systems use
410these for persistent storage and it is relatively simple to develop the code
411necessary to access them.
412There are many EEPROMs available with similar, although not identical interfaces. I recommend beginning with the Microchip 25LC160 in a
413PDIP package (see Figure 1.4). Other packages can be challenging to use in
414a basic prototyping environment. EEPROMs with different storage densities
415frequently require slightly different communications protocols.
416The second SPI device we consider is a display – we use an inexpensive color TFT (thin film transistor) module that includes a micro SD card
417adaptor slot. While I used the one illustrated in Figure 1.1, an equivalent
418module is available from Adafruit. The most important constraint is that the
419examples in this book assume that the display controller is an ST7735 with a
420SPI interface. We do use the SD card adaptor, although it is possible to find
421alternative adaptors from Sparkfun and others.
422The display is 128x160 pixel full color display similar to those used
423on devices like ipods and digital cameras. The colors are quite bright and
424can easily display images with good fidelity. One significant limitation to SPI
425based displays is communication bandwidth – for high speed graphics it would
426be advisable to use a display with a parallel interface. Although the value line
427component on the discovery board does not provide a built-in peripheral to
428support parallel interfaces, many other STM32 components do.
429Finally you will need an SD memory card in the range 1G-2G along
430with an adaptor to program the card with a desktop computer. The speed
43120 Revision: 14c8a1e (2016-06-05)
4321.1. REQUIRED HARDWARE
433Figure 1.5: Color Display Module
434and brand are not critical. The recommended TFT module includes an SD
435flash memory card slot.
436I2C
437Figure 1.6: Wii Nunchuk
438The second synchronous serial interface we study is I2C. To illustrate the
439use of the I2C bus we use the Wii Nunchuk (Figure 1.6). This was developed
440and used for the Wii video console, but has been re-purposed by hobbyists.
441It contains an ST LIS3L02AL 3-axis accelerometer, a 2-axis analog joy-stick,
442Revision: 14c8a1e (2016-06-05) 21
443CHAPTER 1. GETTING STARTED
444and two buttons all of which can be polled over the I2C bus. These are widely
445available in both genuine and clone form. I should note that there appear to be
446some subtle differences between the various clones that may impact software
447development. The specific problem is a difference in initialization sequences
448and data encoding.
449Figure 1.7: Wii Nunchuk Adaptor
450The connector on the Nunchuk is proprietary to Wii and I have not
451found a source for the mating connector. There are simple adaptor boards
452available that work well for the purposes of these tutorials. These are available
453from several sources; the Sparkfun version is illustrated in Figure 1.7.
454Time Based
455Hardware timers are key components of most micro-controllers. In addition to being used to measure the passage of time – for example, providing an
456alarm at regular intervals – timers are used to both generate and decode complex pulse trains. A common use is the generation of a pulse-width modulated
457signal for motor speed control. The STM32 timers are quite sophisticated and
458support complex time generation and measurement. We demonstrate how
459timers can be used to set the position of common hobby servos (Figure 1.8)
460and to measure time-of-flight for an ultrasonic range sensor (Figure 1.9). The
461ultrasonic range sensor we use is known generically as an HC-SR04 and is available from multiple suppliers – I obtained one from an ebay vendor. Virtually
462any small hobby servo will work, however, because of the power limitations
46322 Revision: 14c8a1e (2016-06-05)
4641.1. REQUIRED HARDWARE
465of USB it is desirable to use a “micro” servo for the experiments described in
466this book.
467Figure 1.8: Servo
468Figure 1.9: Ultrasonic Sensor
469Analog
470The final interface that we consider is analog – both in (analog to digital)
471and out (digital to analog). A digital to analog converter (DAC) translates a
472digital value into a voltage. To illustrate this capability we use a DAC to drive
473a small speaker through an amplifier (Figure 1.11). The particular experiment,
474reading audio files off an SD memory card and playing then through a speaker,
475requires the use of multiple interfaces as well as timers and DMA.
476To illustrate the use of analog to digital conversion, we use a small potentiometer (Figure 1.10) to provide a variable input voltage and a microphone
477(Figure 1.12) to provide an analog signal.
478Revision: 14c8a1e (2016-06-05) 23
479CHAPTER 1. GETTING STARTED
480Figure 1.10: Common Potentiometer
481Figure 1.11: Speaker and Amplifier
482Figure 1.12: Microphone
483Power Supply
484In our laboratory we utilize USB power for most experiments. However,
485if it is necessary to build a battery powered project then all that is needed is
486a voltage regulator (converter) between the desired battery voltage and 5V.
487The STM32 VL Discovery includes a linear regulator to convert 5V to 3.3V.
488I have used a simple step-down converter step-down converter – Figure 1.13
489illustrates one available from Pololu – to convert the output of a 9V battery
490to 5V. With such a converter and battery, all of the experiments described in
491this book can be made portable.
49224 Revision: 14c8a1e (2016-06-05)
4931.1. REQUIRED HARDWARE
494Figure 1.13: Power Supply
495Prototyping Materials
496Need pictures
497In order to provide a platform for wiring the various components together, I recommend purchasing two 700-tie solder less bread boards along
498with a number of breadboard jumper wires in both female-female and malemale configuration. All of these are available on ebay at extremely competitive
499prices.
500Test Equipment
501The Saleae Logic logic analyzer is illustrated in Figure 1.14. This device
502provides a simple 8-channel logic analyzer capable of capturing digital data at
50310-20 MHz which is sufficiently fast to debug the basic serial protocols utilized
504by these tutorials. While the hardware itself is quite simple – even primitive
505– the software provided is very sophisticated. Most importantly, it has the
506capability of analyzing several communication protocols and displaying the
507resulting data in a meaningful manner. Figure 1.15 demonstrates the display
508of serial data – in this case “hello world” (you may need to zoom in your pdf
509viewer to see the details).
510When developing software in an embedded environment, the most likely
511scenario when testing a new hardware interface is ... nothing happens. Unless
512things work perfectly, it is difficult to know where to begin looking for problems. With a logic analyzer, one can capture and visualize any data that is
513being transmitted. For example, when working on software to drive a serial
514port, it is possible to determine whether anything is being transmitted, and if
515so, what. This becomes especially important where the embedded processor
516is communicating with an external device (e.g. a Wii Nunchuk) – where every
517command requires a transmitting and receiving a specific binary sequence. A
518logic analyzer provides the key to observing the actual communication events
519(if any !).
520Revision: 14c8a1e (2016-06-05) 25
521CHAPTER 1. GETTING STARTED
522Figure 1.14: Saleae Logic
523Figure 1.15: Saleae Logic Software
5241.2 Software Installation
525The software development process described in this book utilizes the
526firmware libraries distributed by STMicroelectronics, which provide low-level
52726 Revision: 14c8a1e (2016-06-05)
5281.2. SOFTWARE INSTALLATION
529access to all of the peripherals of the STM32 family. While these libraries are
530relatively complicated, this book will provide a road map to their use as well
531some initial shortcuts. The advantages to the using these firmware libraries
532are that they abstract much of the bit-level detail required to program the
533STM32, they are relatively mature and have been thoroughly tested, and
534they enable the development of application code that is portable across the
535STM32 family. In contrast, we have examined the sample code distributed
536with the NXP LPC13xx Cortex-M3 processors and found it to be incomplete
537and in a relatively immature state.
538GNU Tool chain
539The software development for this book was performed using the GNU
540embedded development tools including gcc, gas, gdb, and gld. We have successfully used two different distributions of these tools. In a linux environment
541we use the Sourcery (a subsidiary of Mentor Graphics) CodeBench Lite Edition for ARM (EABI). These may be obtained at https://sourcery.mentor.
542com/sgpp/lite/arm/portal/subscription?@template=lite. I recommend
543using the GNU/Linux installer. The site includes PDF documentation for the
544GNU tool chain along with a “getting started” document providing detailed
545installation instructions.
546Adding the following to your Linux bash initialization will make access
547simpler
548export PATH=path-to/codesourcery/bin:$PATH
549On OS X systems (Macs) we use the yagarto (www.yagarto.de) distribution of the GNU toolchain. There is a simple installer available for download.
550STM32 Firmware Library
551The STM32 parts are well supported by a the ST Standard Peripheral
552Library 5 which provides firmware to support all of the peripherals on the various STM32 parts. This library, while easy to install, can be quite challenging
553to use. There are many separate modules (one for each peripheral) as well
554as large numbers of definitions and functions for each module. Furthermore,
555compiling with these modules requires appropriate compiler flags as well as
5565
557http://www.st.com/web/en/catalog/tools/PF257890
558Revision: 14c8a1e (2016-06-05) 27
559CHAPTER 1. GETTING STARTED
560a few external files (a configuration file, and a small amount of code). The
561approach taken in this documentation is to provide a basic build environment
562(makefiles, configuration file, etc.) which can be easily extended as we explore
563the various peripherals. Rather than attempt to fully describe this peripheral
564library, I present modules as needed and then only the functions/definitions
565we require.
566Code Template
567While the firmware provided by STMicroelectronics provides a solid
568foundation for software development with the STM32 family, it can be difficult
569to get started. Unfortunately, the examples distributed with the STM32 VL
570Discovery board are deeply interwoven with the commercial windows-based
571IDEs available for STM32 code development and are challenging to extract
572and use in a Linux environment. I have created a small template example
573which uses standard Linux make files and in which all aspects of the build
574process are exposed to the user.
575STM32-Template/
576BlinkLight.elf
577Demo/
578main.c
579Makefile
580Library/
581· · ·
582Makefile.common
583README.md
584startup_STM32F10x.c
585STM32F100.ld
586STM32F10x_conf.h
587Figure 1.16: STM32VL Template
588This template can be downloaded as follows:
589git clone git://github.com/geoffreymbrown/STM32-Template.git
590The template directory (illustrated in Figure 1.16) consists of part specific startup code, a part specific linker script, a common makefile, and a
59128 Revision: 14c8a1e (2016-06-05)
5921.2. SOFTWARE INSTALLATION
593header file required by the standard peripheral library. A subdirectory contains the code and example specific makefile. The directory includes a working
594binary for the STM32 VL Discovery. The Demo program is discussed further
595in Chapter 3.
596GDB Server
597In order to download and debug code on the STM32 VL Discovery board
598we can exploit the built-in USB debugger interface called stlink which communicates with the STM32 on-chip debug module. The stlink interface can
599be used both for the processor on the Discovery board and, by setting jumper
600appropriately, for off-board processors. ST also sells a stand-alone version
601of this debugger interface. Sadly, the stlink interface is only supported on
602Windows and ST has not publicly released the interface specification. It is
603widely known that the stlink interface is implemented using the USB Mass
604Storage device class and it is further known that this particular implementation is incompatible with the OS X and Linux kernel drivers. Nevertheless,
605the interface has been sufficiently reverse-engineered that a very usable gdb
606server running on Linux or OS X is available for download:
607git clone git://github.com/texane/stlink.git
608The README file describes the installation process. The STM32VL
609Discovery board utilizes the STLINKv1 protocol which is somewhat problematic in either case because of the manner in which it interacts with the OS
610Kernel. Because of the kernel issues, it is important to follow the directions
611provided. In the case of OS X, there is also a “mac os x driver” which must
612be built and installed.
613To execute the gdb server, plug in an STM32 VL discovery board. Check
614to see if “/dev/stlink” exists and then execute:
615st-util -1
616Note: earlier versions of st-util need a different startup sequence
617st-util 4242 /dev/stlink
618To download the blinking light example, start an instance of arm-noneeabi-gdb in a separate window and execute the following
619Revision: 14c8a1e (2016-06-05) 29
620CHAPTER 1. GETTING STARTED
621arm-none-eabi-gdb BlinkingLights.elf
622(gdb) target extended-remote :4242
623(gdb) load
624(gdb) continue
625This will download the program to flash and begin execution.
626GDB can also be used to set breakpoints and watchpoints.
6271.3 Key References
628There are an overwhelming number of documents pertaining the the
629STM32 family of Cortex-M3 MCUs. The following list includes the key documents referred to in this book. Most of these are available on-line from www.
630st.com. The Cortex-M3 technical reference is available from www.arm.com.
631RM0041 Reference manual for STM32F100x Advanced ARM-based 32-bit
632MCUs [20]. This document provides reference information on all of
633the peripheral used in the STM32 value line processors including the
634processor used on the STM32 VL Discovery board.
635PM0056 STM32F10xx/20xx/21xx/L1xxx [19]. ST reference for programming the Cortex-M3 core. Include the execution model and instruction
636set, and core peripherals (e.g. the interrupt controller).
637Cortex-M3 ARM Cortex-M3 (revision r1p1) Technical Reference Manual.
638The definitive source for information pertaining to the Cortex-M3 [1].
639Data Sheet Low & Medium-density Value Line STM32 data sheet [15]. Provides pin information – especially the mapping between GPIO names
640and alternative functions. There are data sheets for a number of STM32
641family MCUs – this one applies to the MCU on the STM32 VL discovery
642board.
643UM0919 User Manual STM32 Value Line Discovery [14]. Provides detailed
644information, including circuit diagrams, for the STM32 VL Discovery
645board.
64630 Revision: 14c8a1e (2016-06-05)
647Chapter 2
648Introduction to the STM32
649F1
650The STM32 F1xx micro-controllers are based upon the ARM CortexM3 core. The Cortex-M3 is also the basis for micro-controllers from a number
651of other manufacturers including TI, NXP, Toshiba, and Atmel. Sharing
652a common core means that the software development tools including compiler and debugger are common across a wide range of micro-controllers. The
653Cortex-M3 differs from previous generations of ARM processors by defining a
654number of key peripherals as part of the core architecture including interrupt
655controller, system timer, and debug and trace hardware (including external
656interfaces). This additional level of integration means that system software
657such as real-time operating systems and hardware development tools such as
658debugger interfaces can be common across the family of processors. The various Cortex-M3 based micro-controller families differ significantly in terms of
659hardware peripherals and memory – the STM32 family peripherals are completely different architecturally from the NXP family peripherals even where
660they have similar functionality. In this chapter we introduce key aspects of
661the Cortex-M3 core and of the STM32 F1xx micro-controllers.
662A block diagram of the STM32F100 processor used on the value line
663discovery board is illustrated in Figure 2.1. The Cortex-M3 CPU is shown in
664the upper left corner. The value line components have a maximum frequency
665of 24 MHz – other STM32 processors can support a 72 MHz clock. The
666bulk of the figure illustrates the peripherals and their interconnection. The
667discovery processor has 8K bytes of SRAM and 128K bytes of flash. There are
668two peripheral communication buses – APB2 and APB1 supporting a wide
669variety of peripherals.
670Revision: 14c8a1e (2016-06-05) 31
671CHAPTER 2. INTRODUCTION TO THE STM32 F1
672USART1
673SPI1
674TIM1
675TIM17
676TIM16
677TIM15
678GPIOE
679GPIOD
680GPIOC
681GPIOB
682GPIOA
68312-bit ADC1
684EXTIT
685I2C2
686I2C1
687HDMI CEC
688SPI2
689USART3
690USART2
691TIM4
692TIM3
693TIM2
694DAC1
695DAC2
696WWDG
697TIM8
698TIM7
699APB2
700APB1
701Bus Matrix
702Cortex-M3
703DMA
704Flash (128KB)
705SRAM (8KB)
706AHB2
707APB2
708AHB1
709APB1
710STM32F100
711(simplified)
712Figure 2.1: STM32 F100 Architecture
713The Cortex-M3 core architecture consists of a 32-bit processor (CM3)
714with a small set of key peripherals – a simplified version of this core is illustrated in Figure 2.2. The CM3 core has a Harvard architecture meaning that
715it uses separate interfaces to fetch instructions (Inst) and (Data). This helps
716ensure the processor is not memory starved as it permits accessing data and
717instruction memories simultaneously. From the perspective of the CM3, everything looks like memory – it only differentiates between instruction fetches
718and data accesses. The interface between the Cortex-M3 and manufacturer
71932 Revision: 14c8a1e (2016-06-05)
720specific hardware is through three memory buses – ICode, DCode, and System
721– which are defined to access different regions of memory.
722Cortex-M3
723Bus Matrix
724ICode
725DCode
726System
727NVIC
728SysTick
729Interrupts CM3 Core
730Inst Data
731Figure 2.2: Simplified Cortex-M3 Core Architecture
732The STM32, illustrated in Figure 2.3 connects the three buses defined
733by the Cortex-M3 through a micro-controller level bus matrix. In the STM32,
734the ICode bus connects the CM3 instruction interface to Flash Memory, the
735DCode bus connects to Flash memory for data fetch and the System bus provides read/write access to SRAM and the STM32 peripherals. The peripheral
736sub-system is supported by the AHB bus which is further divided into two
737sub-bus regions AHB1 and AHB2. The STM32 provides a sophisticated direct memory access (DMA) controller that supports direct transfer of data
738between peripherals and memory.
739Revision: 14c8a1e (2016-06-05) 33
740CHAPTER 2. INTRODUCTION TO THE STM32 F1
741DMA
742Cortex-M3
743Bus Matrix
744Flash
745Memory
746ICode
747DCode
748System
749DMA
750SRAM
751Bridge 1
752Bridge 2
753AHB Bus
754ADC1
755AFIO
756GPIOx
757SPI1
758TIM1
759TIM15
760TIM16
761TIM17
762USART1
763APB2
764BKP
765CEC
766DAC
767I2C1
768I2C2
769SPI2
770TIM2
771TIM3
772TIM4
773TIM6
774TIM7
775USART2
776USART3
777WWDG
778APB1
779Figure 2.3: STM32 Medium Density Value-Line Bus Architecture
7802.1 Cortex-M3
781The CM3 processor implements the Thumb-2 instruction set which provides a large set of 16-bit instructions, enabling 2 instructions per memory
782fetch, along with a small set of 32-bit instructions to support more complex
783operations. The specific details of this instruction set are largely irrelevant for
784this book as we will be performing all our programming in C. However, there
785are a few key ideas which we discuss in the following.
786As with all RISC processors, the Cortex-M3 is a load/store architecture with three basic types of instructions – register-to-register operations for
787processing data, memory operations which move data between memory and
788registers, and control flow operations enabling programming language control
789flow such as if and while statements and procedure calls. For example, suppose
790we define the following rather trivial C-procedure:
79134 Revision: 14c8a1e (2016-06-05)
7922.1. CORTEX-M3
793int counter;
794int counterInc(void){
795return counter++;
796}
797The resulting (annotated) assembly language with corresponding machine code follows:
798counterInc:
7990: f240 0300 movw r3, #:lower16:counter // r3 = &counter
8004: f2c0 0300 movt r3, #:upper16:counter
8018: 6818 ldr r0, [r3, #0] // r0 = *r3
802a: 1c42 adds r2, r0, #1 // r2 = r0 + 1
803c: 601a str r2, [r3, #0] // *r3 = r2
804e: 4740 bx lr // return r0
805Two 32-bit instructions (movw, movt) are used to load the lower/upper
806halves of the address of counter (known at link time, and hence 0 in the
807code listing). Then three 16-bit instructions load (ldr) the value of counter,
808increment (adds) the value, and write back (str) the updated value. Finally,
809the procedure returns the original counter.
810It is not expected that the reader of this book understand the Cortex-M3
811instruction set, or even this example in great detail. The key points are that
812the Cortex-M3 utilizes a mixture of 32-bit and 16-bit instructions (mostly the
813latter) and that the core interacts with memory solely through load and store
814instructions. While there are instructions that load/store groups of registers
815(in multiple cycles) there are no instructions that directly operate on memory
816locations.
817The Cortex-M3 core has 16 user-visible registers (illustrated in Figure 2.4) – all processing takes place in these registers. Three of these registers
818have dedicated functions including the program counter (PC), which holds the
819address of the next instruction to execute, the link register (LR), which holds
820the address from which the current procedure was called, and “the” stack
821pointer (SP) which holds the address of the current stack top (as we shall
822discuss in Chapter 11, the CM3 supports multiple execution modes, each with
823their own private stack pointer). Separately illustrated is a processor status
824register (PSR) which is implicitly accessed by many instructions.
825The Cortex-M3, like other ARM processors was designed to be programmed (almost) entirely in higher-level language such as C. One consequence is a well developed “procedure call standard” (often called an ABI or
826Revision: 14c8a1e (2016-06-05) 35
827CHAPTER 2. INTRODUCTION TO THE STM32 F1
828r0
829r1
830r2
831r3
832r4
833r5
834r6
835r7
836r8
837r9
838r10
839r11
840r12
841r13 (SP) PSP MSP
842r14 (LR)
843r15 (PC)
844PSR
845Figure 2.4: Processor Register Set
846application binary interface) which dictates how registers are used. [2] This
847model explicitly assumes that the RAM for an executing program is divided
848into three regions as illustrated in Figure 2.5. The data in RAM are allocated
849during the link process and initialized by startup code at reset (see Chapter 3).
850The (optional) heap is managed at runtime by library code implementing functions such as the malloc and free which are part of the standard C library.
851The stack is managed at runtime by compiler generated code which generates
852per-procedure-call stack frames containing local variables and saved registers.
853The Cortex-M3 has a “physical” address space of 2
85432 bytes. The ARM
855Cortex-M3 Technical Reference Manual defines how this address space is to be
856used. [1] This is (partially) illustrated in Figure 2.6. As mentioned, the “Code”
857region is accessed through the ICode (instructions) and DCode (constant data)
858buses. The SRAM and Peripheral areas are accessed through the System bus.
859The physical population of these regions is implementation dependent. For
860example, the STM32 processors have 8K–1M flash memory based at address
861(0x08000000). 1 The STM32F100 processor on the Discovery board has 8K of
862SRAM based at address 0x20000000. Not shown on this address map are the
863internal Cortex-M3 peripherals such as the NVIC which is located starting at
8641This memory is “aliased” to 0x00000000 at boot time.
86536 Revision: 14c8a1e (2016-06-05)
8662.1. CORTEX-M3
867Data
868Heap End
869Main Stack SP
870RAM Start (low)
871RAM End (high)
872Heap Start
873Figure 2.5: Program Memory Model
874address 0xE000E000; these are defined in the Cortex-M3 reference manual.
875[1] We discuss the NVIC further in Chapter 11.
876Code
8770.5GB
8780x00000000
8790x1FFFFFFF
880SRAM
8810.5GB
8820x20000000
8830x3FFFFFFF
884Peripheral
8850.5GB
8860x40000000
8870x5FFFFFFF
8880x60000000
8890xFFFFFFFF
890Figure 2.6: Cortex-M3 Memory Address Space
891Revision: 14c8a1e (2016-06-05) 37
892CHAPTER 2. INTRODUCTION TO THE STM32 F1
893As mentioned, the Cortex-M3 core includes a vectored interrupt controller (NVIC) (see Chapter 11 for more details). The NVIC is a programmable
894device that sits between the CM3 core and the micro-controller. The CortexM3 uses a prioritized vectored interrupt model – the vector table is defined to
895reside starting at memory location 0. The first 16 entries in this table are defined for all Cortex-M3 implementations while the remainder, up to 240, are
896implementation specific; for example the STM32F100 devices define 60 additional vectors. The NVIC supports dynamic redefinition of priorities with
897up to 256 priority levels – the STM32 supports only 16 priority levels. Two
898entries in the vector table are especially important: address 0 contains the
899address of the initial stack pointer and address 4 contains the address of the
900“reset handler” to be executed at boot time.
901The NVIC also provides key system control registers including the System Timer (SysTick) that provides a regular timer interrupt. Provision for
902a built-in timer across the Cortex-M3 family has the significant advantage of
903making operating system code highly portable – all operating systems need at
904least one core timer for time-slicing. The registers used to control the NVIC
905are defined to reside at address 0xE000E000 and are defined by the Cortex-M3
906specification. These registers are accessed with the system bus.
9072.2 STM32 F1
908The STM32 is a family of micro-controllers. The STM32 F1xx microcontrollers are based upon the Cortex-M3 and include the STM32F100 valueline micro-controller used on the discovery board considered in this book. The
909STM32 L1 series is derived from the STM32 F1 series but with reduced power
910consumption. The STM32 F2 series is also based upon the Cortex-M3 but
911has an enhanced set of peripherals and a faster processor core. Many of the
912peripherals of the STM32 F1 series are forward compatible, but not all. The
913STM32 F4 series of processors use the Cortex-M4 core which is a significant
914enhancement of the Cortex-M3. Finally, there is a new STM32 family – the
915STM32 F0 based upon the Cortex-M0. Each of these families – STM32F0,
916STM32 F1, STM32 L1. STM32 F2, and STM32 F4 are supported by different
917firmware libraries. While there is significant overlap between the families and
918their peripherals, there are also important differences. In this book we focus
919on the STM32 F1 family.
920As illustrated in Figure 2.3, the STM32 F1 micro-controllers are based
921upon the Cortex-M3 core with a set of peripherals distributed across three
922buses – AHB and its two sub-buses APB1 and APB2. These peripherals are
92338 Revision: 14c8a1e (2016-06-05)
9242.2. STM32 F1
925controlled by the core with load and store instructions that access memorymapped registers. The peripherals can “interrupt” the core to request attention through peripheral specific interrupt requests routed through the NVIC.
926Finally, data transfers between peripherals and memory can be automated
927using DMA. In Chapter 4 we discuss basic peripheral configuration, in Chapter 11 we show how interrupts can be used to build effective software, and
928in Chapter 12 we show how to use DMA to improve performance and allow
929processing to proceed in parallel with data transfer.
930Throughout this book we utilize the ST Standard Peripheral Library for
931the STM32 F10xx processors. It is helpful to understand the layout of this software library. Figure 2.7 provides a simplified view of the directory structure.
932The library consists of two major sub-directories – STM32F10x_StdPeriph_Driver
933and CMSIS. CMSIS stands for “Cortex Micro-controller Software Interface
934Standard” and provides the common low-level software required for all ARM
935Cortex parts. For example, the core_cm3.* files provide access to the interrupt controller, the system tick timer, and the debug and trace modules. The
936STM32F10x_StdPeriph_Driver directory provides roughly one module (23 in
937all) for each of the peripherals available in the STM32 F10x family. In the
938figure, I have included modules for general purpose I/O (GPIO), I2C, SPI,
939and serial IO (USART). Throughout this book I will introduce the modules
940as necessary.
941There are additional directories distributed with the firmware libraries
942that provide sample code which are not illustrated. The supplied figure provides the paths to all of the key components required to build the tutorials in
943this book.
944The STM32 F1 has a sophisticated clock system. There are two primary
945external sources of timing – HSE and LSE. The HSE signal is derived from an
9468MHz crystal or other resonator, and the LSE signal is derived from a 32.768
947kHz crystal. Internally, the HSE is multiplied in frequency through the use of
948a PLL; the output of this, SYSCLK is used to derive (by division) various onchip time sources include clocks for the ABP1 and APB2 peripherals as well as
949for the various programmable timers. The LSE is used to manage a low-power
950real-time clock. The STM32F100 micro-controllers can support a maximum
951SYSCLK frequency of 24MHz while the other STM32 F1xx micro-controllers
952support a SYSCLK frequency of 72MHz. Fortunately, most of the code required to manage these clocks is provided in the standard peripheral library
953module (system_stm32f10x.[ch]) which provides an initialization function
954– SystemInit(void) to be called at startup. This module also exports a variable SystenCoreClock which contains the SYSCLK frequency; this simplifies
955Revision: 14c8a1e (2016-06-05) 39
956CHAPTER 2. INTRODUCTION TO THE STM32 F1
957STM32F10x_StdPeriph_Lib_V3.5.0/Libraries/
958CMSIS
959CM3
960CoreSupport
961core_cm3.c
962core_cm3.h
963DeviceSupport
964ST
965STM32F10x
966…
967stm32f10x.h
968system_stm32f10x.c
969system_stm32f10x.h
970…
971STM32F10x_StdPeriph_Driver
972inc
973misc.h
974…
975stm32f10x_gpio.h
976stm32f10x_i2c.h
977stm32f10x_spi.h
978stm32f10x_usart.h
979…
980src
981misc.c
982…
983stm32f10x_gpio.c
984stm32f10x_i2c.c
985stm32f10x_spi.c
986stm32f10x_usart.c
987…
988Figure 2.7: ST Standard Peripheral Library
989the task of developing code that is portable across the STM32F1 family.
990The STM32 F1 micro-controllers a variety of peripherals – not all of
991which are supported by the STM32F100 parts. The following peripherals are
992considered extensively in this book.
99340 Revision: 14c8a1e (2016-06-05)
9942.2. STM32 F1
995ADC Analog to digital converter – Chapter 14.
996DAC Digital to analog converter – Chapter 13.
997GPIO General Purpose I/O – Chapter 4.
998I2C I2C bus – Chapter 9.
999SPI SPI bus – Chapter 6.
1000TIM Timers (various) – Chapter 10.
1001USART Universal synchronous asynchronous receiver transmitter – Chapter 5.
1002The following peripherals are not considered in this book.
1003CAN Controller area network. Not supported by STM32F100
1004CEC Consumer electronics control.
1005CRC Cyclic redundancy check calculation unit.
1006ETH Ethernet interface. Not supported by the STM32F100
1007FSMC Flexible static memory controller. Not supported by medium density
1008STMF100.
1009PWR Power control (sleep and low power mode).
1010RTC Real time clock.
1011IWDG Independent watchdog.
1012USB Universal serial bus. Not supported by the STM32F100
1013WWDG Windowing watchdog
1014As mentioned previously all of the peripherals are “memory-mapped”
1015which means that the core interacts with the peripheral hardware by reading
1016and writing peripheral “registers” using load and store instructions. 2 All of
10172The terminology can be confusing – from the perspective of the CM3 core, peripheral
1018registers are just dedicated memory locations.
1019Revision: 14c8a1e (2016-06-05) 41
1020CHAPTER 2. INTRODUCTION TO THE STM32 F1
1021the various peripheral registers are documented in the various STM32 reference manuals ([20, 21]). The documentation include bit-level definitions of
1022the various registers and text to help interpret those bits. The actual physical
1023addresses are also found in the reference manuals.
1024The following table provides the address for a subset of the peripherals
1025that we consider in this book. Notice that all of these fall in the area of the
1026Cortex-M3 address space defined for peripherals.
10270x40013800 - 0x40013BFF USART1
10280x40013000 - 0x400133FF SPI1
10290x40012C00 - 0x40012FFF TIM1 timer
10300x40012400 - 0x400127FF ADC1
1031... ...
1032Fortunately, it is not necessary for a programmer to look up all these
1033values as they are defined in the library file stm32f10x.h as USART1_BASE,
1034SPI1_BASE, TIM1_BASE ADC1_BASE, etc.
1035Typically, each peripheral will have control registers to configure the
1036peripheral, status registers to determine the current peripheral status, and
1037data registers to read data from and write data to the peripheral. Each GPIO
1038port (GPIOA, GPIOB, etc.) has seven registers. Two are used to configure
1039the sixteen port bits individually, two are used to read/write the sixteen port
1040bits in parallel, two are used to set/reset the sixteen port bits individually,
1041and one is used to implement a “locking sequence” that is intended to prevent
1042rogue code from accidentally modifying the port configuration. This final
1043feature can help minimize the possibility that software bugs lead to hardware
1044failures; e.g, accidentally causing a short circuit.
1045In addition to providing the addresses of the peripherals, stm32f10x.h
1046also provides C language level structures that can be used to access each
1047peripherals. For example, the GPIO ports are defined by the following register
1048structure.
1049typedef struct
1050{
1051volatile uint32_t CRL;
1052volatile uint32_t CRH;
1053volatile uint32_t IDR;
1054volatile uint32_t ODR;
1055volatile uint32_t BSRR;
1056volatile uint32_t BRR;
1057volatile uint32_t LCKR;
1058} GPIO_TypeDef;
105942 Revision: 14c8a1e (2016-06-05)
10602.2. STM32 F1
1061The register addresses of the various ports are defined in the library as
1062(the following defines are from stm32f10x.h)
1063#define PERIPH_BASE ((uint32_t)0x40000000)
1064#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
1065#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
1066#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
1067To read the 16 bits of GPIOA in parallel we might use the following
1068code:
1069uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx) {
1070return ((uint16_t)GPIOx ->IDR);
1071}
1072The preceding example is somewhat misleading in its simplicity. Consider that to configure a GPIO pin requires writing two 2-bit fields at the
1073correct location in correct configuration register. In general, the detail required can be excruciating.
1074Fortunately, the standard peripheral library provides modules for each
1075peripheral that can greatly simplify this task. For example, the following is a
1076subset of the procedures available for managing GPIO ports:
1077void GPIO_Init(GPIO_TypeDef* GPIOx ,
1078GPIO_InitTypeDef* GPIO_InitStruct);
1079uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx ,
1080uint16_t GPIO_Pin);
1081uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
1082uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx ,
1083uint16_t GPIO_Pin);
1084uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
1085void GPIO_SetBits(GPIO_TypeDef* GPIOx , uint16_t GPIO_Pin);
1086void GPIO_ResetBits(GPIO_TypeDef* GPIOx , uint16_t GPIO_Pin);
1087void GPIO_WriteBit(GPIO_TypeDef* GPIOx , uint16_t GPIO_Pin ,
1088BitAction BitVal);
1089void GPIO_Write(GPIO_TypeDef* GPIOx , uint16_t PortVal);
1090The initialization function (GPIO_Init) provides an interface for configuring individual port bits. The remaining functions provide interfaces for
1091reading and writing (also setting and resetting) both individual bits and the
109216 port bits in parallel.
1093We use the standard peripheral library functions throughout this book.
1094There is a significant downside to using this library – the modules are
1095huge. The GPIO module stm32f10x_gpio.o when compiled with parameter
1096checking is 4K where a simple application might use a few 100 bytes of custom
1097Revision: 14c8a1e (2016-06-05) 43
1098CHAPTER 2. INTRODUCTION TO THE STM32 F1
1099code. Furthermore, the code can be slow – often multiple procedure calls are
1100used by the library where none would be required by custom code. Nevertheless, the library offers a much faster path to correct prototype code. For
1101prototype work, it’s probably better to throw extra hardware (memory, clock
1102rate) at a problem than sweat the details. For serious product development
1103it may be wise to refine a design to reduce dependence on these libraries.
1104To get a sense of the cost of using the library consider the code in
1105Figure 2.1 which configures PC8 and PC9 as outputs (to drive LEDs) and
1106PA0 as an input (to read the push button). 3
1107. Similar library based code
1108is presented as an exercise in Chapter 4. In Table 2.1 I compare the space
1109requirements of two versions of this program with and without the use of the
1110standard peripheral library. The first column (text) provides the size of “text
1111segment” (code and data initializers), the data allocated in ram at startup is
1112the sum of data (initialized data) and bss (zeroed data). The total memory
1113requirements are provided in column text. The .elf files are the complete
1114binaries. Excluding 256 bytes of preallocated runtime stack (bss), the library
1115version is nearly 3 times as large. Unlike the original which did minimum
1116system initialization, I included two common startup files for both versions.
1117Also, the standard peripheral library has extensive parameter checking which
1118I disabled for this comparison.
1119Code With Libraries
1120text data bss dec filename
1121200 0 0 200 main.o
1122576 0 0 576 startup_stm32f10x.o
1123832 0 0 832 stm32f10x_gpio.o
11241112 20 0 1132 stm32f10x_rcc.o
1125484 20 0 504 system_stm32f10x.o
11263204 40 256 3500 blinky2-lib.elf
1127Code Without Libraries
1128text data bss dec filename
1129136 0 0 136 main.o
1130576 0 0 576 startup_stm32f10x.o
1131484 20 0 504 system_stm32f10x.o
11321196 20 256 1472 blinky2.elf
1133Table 2.1: Code Size With and Without Standard Libraries
11343This is an excerpt of blinky.c by Paul Robson
113544 Revision: 14c8a1e (2016-06-05)
11362.2. STM32 F1
1137#include <stm32f10x.h>
1138int main(void){
1139int n = 0;
1140int button;
1141/* Enable the GPIOA (bit 2) and GPIOC (bit 4) */
1142/* See 6.3.7 in stm32f100x reference manual */
1143RCC->APB2ENR |= 0x10 | 0x04;
1144/* Set GPIOC Pin 8 and Pin 9 to outputs */
1145/* 7.2.2 in stm32f100x reference manual */
1146GPIOC ->CRH = 0x11;
1147/* Set GPIOA Pin 0 to input floating */
1148/* 7.2.1 in stm32f100x reference manual */
1149GPIOA ->CRL = 0x04;
1150while(1){
1151delay();
1152// Read the button - the button pulls down PA0 to logic 0
1153button = ((GPIOA ->IDR & 0x1) == 0);
1154n++;
1155/* see 7.2.5 in stm32f100x reference manual */
1156if (n & 1) {
1157GPIOC ->BSRR = 1<<8 ;
1158} else {
1159GPIOC ->BSRR = 1<<24;
1160}
1161if ((n & 4) && button) {
1162GPIOC ->BSRR = 1<<9 ;
1163} else {
1164GPIOC ->BSRR = 1<<25;
1165}
1166}
1167}
1168void delay(void){
1169int i = 100000;/* About 1/4 second delay */
1170while (i-- > 0)
1171asm("nop");
1172}
1173Listing 2.1: Programming without Standard Peripheral Library
1174Revision: 14c8a1e (2016-06-05) 45
1175
1176Chapter 3
1177Skeleton Program
1178In this chapter I discuss the process of creating, compiling, loading,
1179executing, and debugging a program with the STM32 VL Discovery board
1180and Sourcery tools. For desktop machines, the standard first example is the
1181“hello world” program:
1182#include <stdio.h>
1183main() {
1184printf("hello world\n");
1185}
1186which can be compiled and executed in a single step
1187$ gcc -o hello hello.c ; ./hello
1188hello world
1189This simple program hides an enormous amount of complexity ranging from
1190the automatic inclusion of the standard libraries, to linking in startup code,
1191to interacting with the world through the shell. In the embedded world, much
1192of that complexity is visible to the programmer and hence it is necessary to
1193understand quite a bit more about the execution environment for even the
1194simplest program (and “hello world” is not a simple program).
1195In the embedded world, the simplest C program is one which does not
1196require any standard libraries and does not interact with the world:
1197main {
1198}
1199Revision: 14c8a1e (2016-06-05) 47
1200CHAPTER 3. SKELETON PROGRAM
1201However, this is a little too pared down for our purposes. Instead, we
1202structure this chapter around a program that has some data and which runs
1203forever:
1204int i;
1205int off = 5;
1206void inc(void){
1207i += off;
1208}
1209int main(void){
1210while (1) {
1211inc();
1212}
1213}
1214While we cannot directly observe this program when it executes, we can
1215attach a debugger and control its execution through breakpoints and watchpoints. Notice that this program has two global variables (i and off) one of
1216which is initialized to zero and the other has a non-zero initizializer. Furthermore the program has a single procedure other than main and repeatedly calls
1217this procedure.
1218Before we can execute the program there are a number of hurdles we
1219must overcome. First, we must compile the program into a binary format
1220suitable for loading onto the discovery board. Second, we must load this
1221binary into the flash memory. Finally, in order to observe the program, we
1222must intereact with the discovery board through a debugger (GDB). While
1223we use GDB as a loader as well as a debugger, in general the last two steps
1224may involve separate tools.
1225Demo Program
1226The process of compiling a program for embedded processors such as the
1227STM32 can involve quite a few details such as processor specific compilation
1228flags, paths to the compilation tools, etc. Generally the best approach is
1229to build a “make” script to guide the process. Rather than diving in at this
1230level, you should download the code template as described in Section 1.2 which
1231contains the necessary scripts. The layout of this directory is illustrated in
1232Figure 1.16.
1233In order to build this example on your system, you will need to modify
1234two constants in the file Makefile.common – TOOLROOT which should point
123548 Revision: 14c8a1e (2016-06-05)
1236to the bin directory of your Sourcery installation and LIBROOT which should
1237point to your installation of the STM32 standard periperal library.
1238To compile this program, change directories to the Demo directory and
1239execute “make”. This should create a file called Demo.ELF which contains the
1240compiled binary.
1241To download and execute this binary we will need two programs – gdb
1242(arm-none-eabi-gdb), which is part of the Sourcery distribution, and st-util,
1243which provides a gdb server that communicates with the stlink debugging
1244stub on the discovery board through a USB connection. We described how to
1245install st-util in Section 1.2. I will assume you have installed and tested the
1246connection. You should open two terminal windows. In one, execute:
1247st-util -1
1248Note: earlier versions of st-util need a different startup sequence
1249st-util 4242 /dev/stlink
1250which starts a gdb server listening at port 4242. You should see an output
1251such as the following:
1252Chip ID is 00000420, Core ID is 1ba01477.
1253KARL - should read back as 0x03, not 60 02 00 00
1254Listening at *:4242...
1255In the other terminal window, execute (lines starting “(gdb)” are within the
1256debugger):
1257arm-none-eabi-gdb Demo.elf
1258(gdb) target extended -remote :4242
1259(gdb) load
1260(gdb) break main
1261(gdb) break inc
1262(gdb) continue
1263The “target” command should connect to the gdb server at port 4242;
1264the load command downloads the executable to the STM32 flash memory.
1265The next two commands set breakpoints at main and inc procedures, and the
1266continue command executes until the next breakpoint occurs. You can then
1267repeatedly execute and examine the value of i:
1268Revision: 14c8a1e (2016-06-05) 49
1269CHAPTER 3. SKELETON PROGRAM
1270(gdb) print i
1271(gdb) continue
1272...
1273Exercise 3.1 GDB on STM32
1274Experiment with GDB to test various commands such as the following:
12751. Print current register values (e.g. print /x $sp displays the stack
1276pointer in hex.
12772. Try setting a watchpoint on i.
12783. Try using a breakpoint command that prints i and continues just before
1279main calls inc
1280Make Scripts
1281While downloading and executing a binary is comparatively easy, the
1282process of building a binary is not. The compilation tools require non-obvious
1283options, the STM32 firmware libraries require various definitions, and the
1284generation of an executable from binaries requires a dedicated “linker script”.
1285Furthermore, “main.c” is not in itself a complete program – there are always
1286steps necessary to initialize variables and set up the execution environment.
1287In the Unix world, every C program is linked with “crt0.o” to perform this
1288initialization. In the embedded world, additional initialization is necessary
1289to set up hardware environment. In this section I discuss the build process
1290and in the next, the function performed by the STM32 startup code (which
1291is included with the firmware libraries).
1292The make files included with the demo program are split into two parts
1293– Makefile.common does the heavy lifting and is reusable for other projects
1294while Demo/Makefile is project specific. Indeed the only function of the
1295project specific makefile is to define the required object files and their dependencies. The Makefile for the demo project is illustrated in Listing 3.1.
1296This can be modified for other projects by adding additional objects and modifying compilation flags. The variable TEMPLATEROOT should be modified to
1297point to the template directory.
129850 Revision: 14c8a1e (2016-06-05)
1299TEMPLATEROOT = ..
1300# compilation flags for gdb
1301CFLAGS = -O1 -g
1302ASFLAGS = -g
1303# object files
1304OBJS= $(STARTUP) main.o
1305# include common make file
1306include $(TEMPLATEROOT)/Makefile.common
1307Listing 3.1: Demo Makefile
1308Most of Makefile.common defines paths to the tools and libraries. The
1309only notable parts of this file are the processor specific defines and the compilation flags. The processor specific definitions include the linker script LDSCRIPT
1310that informs the linker of the correct linking script to use – we will discuss
1311this file briefly in the next section. A processor type define PTYPE that controls conditional compilation of the firmware libraries, and two startup files
1312– one generic (system_stm32f10x.o) and one specific to the STM32 Value
1313Line processors (startup_stm32f10x.o). The STM32 libraries are designed
1314to support multiple members of the STM32 family by requiring various compile time switches. The processor on the STM32 VL Discovery board is
1315“medium density value line” part – this is reflected in the compile-time definition STM32F10X_MD_VL.
1316PTYPE = STM32F10X_MD_VL
1317LDSCRIPT = $(TEMPLATEROOT)/stm32f100.ld
1318STARTUP= startup_stm32f10x.o system_stm32f10x.o
1319# Compilation Flags
1320FULLASSERT = -DUSE_FULL_ASSERT
1321LDFLAGS+= -T$(LDSCRIPT) -mthumb -mcpu=cortex -m3
1322CFLAGS+= -mcpu=cortex -m3 -mthumb
1323CFLAGS+= -I$(TEMPLATEROOT) -I$(DEVICE) -I$(CORE) -I$(PERIPH)/inc -I.
1324CFLAGS+= -D$(PTYPE) -DUSE_STDPERIPH_DRIVER $(FULLASSERT)
1325The flags -mcpu=cortex-m3 -mthumb inform gcc about the core procesRevision: 14c8a1e (2016-06-05) 51
1326CHAPTER 3. SKELETON PROGRAM
1327sor. -DUSE_STDPERIPH_DRIVER -DUSE_FULL_ASSERT affect the compilation of
1328firmware library code.
1329STM32 Memory Model and Boot Sequence
1330The memory of the STM32 processors consists of two major areas – flash
1331memory (effectively read-only) begins at address 0x08000000 while static ram
1332(read/write) memory begins at address 0x20000000. The size of these areas is
1333processor specific. When a program is executing, the machine code (generally)
1334resides in flash and the mutable state (variables and the run-time stack) resides
1335in static ram (SRAM). In addition, the first portion of flash memory, starting
1336at 0x08000000, contains a vector table consisting of pointers to the various
1337exception handlers. The most important of these are the address of the reset
1338handler (stored at 0x08000004) which is executed whenever the processor is
1339reset, and the initial stack pointer value (stored at 0x08000000).
1340This memory structure is reflected in the linker script fragment illustrated in Figure 3. The script begins by defining the code entry point
1341(Reset_Handler) and the two memory regions – flash and ram. It then places
1342the named sections from the object files being linked into appropriate locations
1343in these two memory regions. From the perspective of an executable, there
1344are three relevant sections – “.text” which is always placed in flash, “.data”
1345and “.bss” which are always allocated space in the ram region. The constants
1346required to initialize .data at runtime are placed in flash as well for the startup
1347code to copy. Notice further that the linker script defines key labels _etext,
1348_sidata, ... that are referenced by the startup code in order to initialize
1349the ram.
1350The GNU linker is instructed to place the data section in FLASH –
1351specifically “at” the location of _sidata, but links data references to locations
1352in RAM by the following code fragment:
1353.data : AT ( _sidata )
1354{
1355...
1356} >RAM
1357The key idea is that the GNU linker distinguishes between virtual
1358(VMA) and load addresses (LMA). The VMA is the address a section has
1359when the program is executed, the LMA is the address at which the section is
1360loaded. For data, our linker script places the LMA of the data section within
1361FLASH and the VMA within RAM – notice that _sidata = _etext.
136252 Revision: 14c8a1e (2016-06-05)
1363ENTRY(Reset_Handler)
1364MEMORY
1365{
1366RAM (rwx) : ORIGIN = 0x20000000 , LENGTH = 8K
1367FLASH (rx) : ORIGIN = 0x08000000 , LENGTH = 128K
1368}
1369SECTIONS
1370{
1371.text :
1372{
1373KEEP(*(.isr_vector)) /* vector table */
1374*(.text) /* code */
1375*(.text.*) /* remaining code */
1376*(.rodata) /* read-only data (constants) */
1377...
1378} >FLASH
1379...
1380_etext = .;
1381_sidata = _etext;
1382/* Init data goes in RAM, but is copied after code as well */
1383.data : AT ( _sidata )
1384{
1385...
1386_sdata = .;
1387*(.data)
1388...
1389_edata = . ; /* used to init data section */
1390} >RAM
1391.bss :
1392{
1393...
1394_sbss = .; /* used to init bss */
1395__bss_start__ = _sbss;
1396*(.bss)
1397...
1398. = ALIGN(4);
1399_ebss = . ; /* used to init bss */
1400__bss_end__ = _ebss;
1401} >RAM
1402Figure 3.1: Linker Script Fragment
1403The first portion of the .text section is loaded with the exception vectors (.isr_vector) which are later defined in the startup code. These excepRevision: 14c8a1e (2016-06-05) 53
1404CHAPTER 3. SKELETON PROGRAM
1405tion vectors start at 0x08000000, as is required when the STM32 boots from
1406flash.
1407There are a number of details elided that ensure the creation of labels
1408assumed by the compiler and standard libraries as well as handling debugging
1409sections of the binary.
1410The linker script and the startup code collaborate to create a meaningful executable environment. The linker script is responsible for ensuring
1411that the various portions of the executable (e.g. the exception vectors) are
1412in their proper place and for associating meaningful labels with specific regions of memory used by the start up code. At reset, the reset handler is
1413called. The reset handler (defined in startup_stm32f10x.c) copies the initial values for variables from flash (where the linker places them) to SRAM
1414and zeros the so-called uninitialized data portion of SRAM. (see Listing 3.2).
1415These steps are necessary whenever the processor resets in order to initialize
1416the “C” environment. The reset handler then calls SystemInit (defined in
1417system_stm32f10x.c from the firmware library) which initializes the clocking system, disables and clears interrupts. The compile flag STM32F10X_MD_VL
1418defined in our makefile is crucial to this code because the clock initialization
1419code is processor specific. Finally, the reset handler calls the main function
1420defined in user code. The external variables required by the reset handler to
1421initialize memory (e.g. _sidata, _sdata...) are defined by the linker script.
1422Another important function of the startup code is to define the default
1423interrupt vector table (Listing 3.3). In order to allow application code to
1424conveniently redefine the various interrupt handler, every required interrupt
1425vector is assigned an overideable (weak) alias to a default hander (which loops
1426forever). To create a custom interrupt handler in application code, it is sufficient to define a procedure with the appropriate handler name. One word of
1427caution – you must be careful to use exactly then names defined in the vector
1428table for your handler or else it will not be linked into the loaded vector table
1429!
143054 Revision: 14c8a1e (2016-06-05)
1431// Linker supplied pointers
1432extern unsigned long _sidata;
1433extern unsigned long _sdata;
1434extern unsigned long _edata;
1435extern unsigned long _sbss;
1436extern unsigned long _ebss;
1437extern int main(void);
1438void Reset_Handler(void) {
1439unsigned long *src, *dst;
1440src = &_sidata;
1441dst = &_sdata;
1442// Copy data initializers
1443while (dst < &_edata)
1444*(dst++) = *(src++);
1445// Zero bss
1446dst = &_sbss;
1447while (dst < &_ebss)
1448*(dst++) = 0;
1449SystemInit();
1450__libc_init_array();
1451main();
1452while(1) {}
1453}
1454Listing 3.2: Reset Handler in startup_stm32f10x.c
1455Revision: 14c8a1e (2016-06-05) 55
1456CHAPTER 3. SKELETON PROGRAM
1457static void default_handler (void) { while(1); }
1458void NMI_Handler (void) __attribute__ ((weak, alias
1459,→(``default_handler'')));
1460void HardFault_Handler (void) __attribute__ ((weak, alias
1461,→(``default_handler'')));
1462void MemMange_Handler (void) __attribute__ ((weak, alias
1463,→(``default_handler'')));
1464void BusFault_Handler (void) __attribute__ ((weak, alias
1465,→(``default_handler'')));
1466...
1467__attribute__ ((section(``.isr_vector'')))
1468void (* const g_pfnVectors[])(void) = {
1469_estack ,
1470Reset_Handler ,
1471NMI_Handler ,
1472HardFault_Handler ,
1473...
1474Listing 3.3: Interrupt Vectors
147556 Revision: 14c8a1e (2016-06-05)
1476Chapter 4
1477STM32 Configuration
1478The STM32 processors are complex systems with many peripherals. Before any of these peripherals can be used they must be configured. Some of
1479this configuration is generic – for example clock distribution and pin configuration – while the rest is peripheral specific. Throughout this chapter, we
1480utilize a simple “blinking lights” program as a guiding example.
1481The fundamental initialization steps required to utilize any of the STM32
1482peripherals are:
14831. Enable clocks to the peripheral
14842. Configure pins required by the peripheral
14853. Configure peripheral hardware
1486The STM32 processors, as members of the Cortex-M3 family, all have
1487a core system timer which can be used to provide a regular timing “tick.” We
1488utilize this timer to provide a constant blink rate for our example. The overall
1489structure of this program is illustrated in Figure 4. The program begins by
1490including the relevant firmware library headers – in this case for clock and
1491pin configuration. The main routine follows the initialization steps described
1492above and then enters a loop in which it toggles an LED and waits for 250ms.
1493Procedure main is followed by code implementing the delay function which
1494utilizes the system timer. Finally, a helper function is provided to handle
1495assertion violations in the firmware library (required if USE_FULL_ASSERT is
1496defined when compiling firmware library modules). While the assert_failed
1497handler does nothing, it is very useful when debugging new projects as the
1498Revision: 14c8a1e (2016-06-05) 57
1499CHAPTER 4. STM32 CONFIGURATION
1500firmware library will perform extensive parameter checking. In the event of
1501an assertion violation, GDB can be used to examine the parameters of this
1502routine to determine the point of failure.
1503#include <stm32f10x.h>
1504#include <stm32f10x_rcc.h>
1505#include <stm32f10x_gpio.h>
1506void Delay(uint32_t nTime);
1507int main(void)
1508{
1509GPIO_InitTypeDef GPIO_InitStructure;
1510// Enable Peripheral Clocks
1511... (1) ...
1512// Configure Pins
1513... (2) ...
1514// Configure SysTick Timer
1515... (3) ...
1516while (1) {
1517static int ledval = 0;
1518// toggle led
1519... (4) ...
1520Delay(250); // wait 250ms
1521}
1522}
1523// Timer code
1524... (5) ...
1525#ifdef USE_FULL_ASSERT
1526void assert_failed(uint8_t* file, uint32_t line)
1527{
1528/* Infinite loop */
1529/* Use GDB to find out why we're here */
1530while (1);
1531}
1532#endif
1533Figure 4.1: Blinking Lights
1534The STM32 VL discovery board has an LED driven by I/O pin PC9.
1535[14] In order to configure this pin, clocks must first be enabled for GPIO
153658 Revision: 14c8a1e (2016-06-05)
1537Port C with the following library command (described in greater detail in
1538Section 4.1).
1539RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); // (1)
1540After enabling the clocks, it is necessary to configure any required pins.
1541In this case, a single pin (PC9) must be configured as an output (described in
1542greater detail in Section 4.2).
1543/* (2) */
1544GPIO_StructInit(&GPIO_InitStructure);
1545GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
1546GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
1547GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
1548GPIO_Init(GPIOC , &GPIO_InitStructure);
1549Once configuration is complete, the pin can be set or reset with the
1550following code:
1551/* (4) */
1552GPIO_WriteBit(GPIOC , GPIO_Pin_9 , (ledval) ? Bit_SET : Bit_RESET);
1553ledval = 1 - ledval;
1554The blinking light demo also utilizes a “timer tick” to measure the
1555passage of time. While this timer tick utilizes interrupts, which we will not
1556be discussing until Chapter 11, the actual use here can be treated simply as
1557an idiom. The Cortex-M3 core used in the STM32 processors has a dedicated
1558timer for this function. The timer as a multiple of the system clock (which
1559is defined in ticks/second) – here we configure it for 1 msec interrupts (the
1560constant SystemCoreClock is defined in the firmware library to be the number
1561of system clock cycles per second):
1562/* (3) */
1563if (SysTick_Config(SystemCoreClock / 1000))
1564while (1);
1565Every 1 msec, the timer triggers a call to the SysTick_Handler. For
1566the blinking light demo, we simply decrement a shared counter – declared as
1567__IO to ensure that the compiler doesn’t perform undesired optimization.
1568Revision: 14c8a1e (2016-06-05) 59
1569CHAPTER 4. STM32 CONFIGURATION
1570/* (5) */
1571static __IO uint32_t TimingDelay;
1572void Delay(uint32_t nTime){
1573TimingDelay = nTime;
1574while(TimingDelay != 0);
1575}
1576void SysTick_Handler(void){
1577if (TimingDelay != 0x00)
1578TimingDelay --;
1579}
1580This simple blinking lights program requires support from two library
1581modules (stm32_gpio.c, stm32_rcc.c). To include these in the project, we
1582have to slightly modify the Makefile provided with the demo project.
1583TEMPLATEROOT = ../../stm32vl_template
1584# additional compilation flags
1585CFLAGS += -O0 -g
1586ASFLAGS += -g
1587# project files
1588OBJS= $(STARTUP) main.o
1589OBJS+= stm32f10x_gpio.o stm32f10x_rcc.o
1590# include common make file
1591include $(TEMPLATEROOT)/Makefile.common
1592In the remainder of this chapter we examine clock and pin configuration
1593in greater detail.
1594Exercise 4.1 Blinking Lights
1595Complete the Blinking lights main.c and create a project using the demo
1596program described in Chapter 3 as an example. You should compile and run
1597your program.
1598Modify your program to cause an assertion violation – for example replacing GPIOC with 66 when initializing the pin – and use GDB to find the
1599place in the library source code where an assertion failed.
160060 Revision: 14c8a1e (2016-06-05)
16014.1. CLOCK DISTRIBUTION
16024.1 Clock Distribution
1603In the world of embedded processors, power consumption is critical;
1604hence, most sophisticated embedded processors provide mechanisms to power
1605down any resources that are not required for a particular application. The
1606STM32 has a complex clock distribution network which ensures that only
1607those peripherals that are actually needed are powered. This system, called
1608Reset and Clock Control (RCC) is supported by the firmware module
1609stm32f10x_rcc.[ch]. While this module can be used to control the main
1610system clocks and PLLs, any required configuration of those is handled by the
1611startup code provided with the examples in this book. Our concern here is
1612simply with enabling the peripheral clocks.
1613The STM32 peripherals are organized into three distinct groups called
1614APB1, APB2, and AHB. APB1 peripherals include the I2C devices, USARTs
16152-5, and SPI devices; APB2 devices include the GPIO ports, ADC controllers
1616and USART 1. AHB devices are primarily memory oriented including the
1617DMA controllers and external memory interfaces (for some devices)
1618Clocks to the various peripherals can be controlled with three firmware
1619routines:
1620RCC_APB1PeriphClockCmd(uint32_t RCC_APB1PERIPH ,
1621FunctionalState NewState)
1622RCC_APB2PeriphClockCmd(uint32_t RCC_APB2PERIPH ,
1623FunctionalState NewState)
1624RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPERIPH ,
1625FunctionalState NewState)
1626Each routine takes two parameters – a bit-vector of peripherals whose
1627state should be modified, and an action – ENABLE or DISABLE. For example,
1628GPIO ports A and B can be enabled with the following call:
1629RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
1630RCC_APB2Periph_GPIOB , ENABLE);
1631The appropriate constants are defined in stm32f10x_rcc.h; the constant names, shown in Table 4.1, are relatively self-explanatory and correspond to the device names utilized in the various STM32 reference manuals
1632([20, 21]), limited to those that are present in the STM32 MCU on the discovery board. It is a testament to the STM32 family design that the same
1633constants and core library applies across a broad family of devices. (Note the
1634stm32f2xx and stm32f4xx components have different, although similar standard peripheral libraries)
1635Revision: 14c8a1e (2016-06-05) 61
1636CHAPTER 4. STM32 CONFIGURATION
1637APB1 Devices APB2 Devices
1638RCC_APB1Periph_BKP RCC_APB2Periph_ADC1
1639RCC_APB1Periph_CEC RCC_APB2Periph_AFIO
1640RCC_APB1Periph_DAC RCC_APB2Periph_GPIOA
1641RCC_APB1Periph_I2C1 RCC_APB2Periph_GPIOB
1642RCC_APB1Periph_I2C2 RCC_APB2Periph_GPIOC
1643RCC_APB1Periph_PWR RCC_APB2Periph_GPIOD
1644RCC_APB1Periph_SPI2 RCC_APB2Periph_GPIOE
1645RCC_APB1Periph_TIM2 RCC_APB2Periph_SPI1
1646RCC_APB1Periph_TIM3 RCC_APB2Periph_TIM1
1647RCC_APB1Periph_TIM4 RCC_APB2Periph_TIM15
1648RCC_APB1Periph_TIM5 RCC_APB2Periph_TIM16
1649RCC_APB1Periph_TIM6 RCC_APB2Periph_TIM17
1650RCC_APB1Periph_TIM7 RCC_APB2Periph_USART1
1651RCC_APB1Periph_USART2
1652RCC_APB1Periph_USART3
1653RCC_APB1Periph_WWDG
1654AHB Devices
1655RCC_AHBPeriph_CRC RCC_AHBPeriph_DMA
1656Table 4.1: Clock Distribution Constant Names (stm32f10x_rcc.h)
1657The standard peripheral library code to enable clocks doesn’t perform
1658any “magic”, but rather releases the programmer from the need to be intimately familiar with the micro-controller registers. For example, the APB2
1659peripherals are enabled through a single register (RCC_APB2ENR) (illustrated in Figure 4.2)
16601
1661.); each peripheral is enabled (or disabled) by the state
1662of a single bit. For example, Bit 2 determines whether GPIOA is enabled (1) or
1663disabled (0). Applying the structure and register definitions in <stm32f10x.h>
1664we can enable GPIOA and GPIOB as follows:
1665ABP2ENR |= 0x0C;
16661The various control registers are fully documented in [20]
166762 Revision: 14c8a1e (2016-06-05)
16684.2. I/O PINS
166931 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
1670Reserved TIM17TIM16TIM15
167115 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1672Res. URT1 Res. SPI1 TIM1 Res. ADC1 IOPG IOPF IOPE IOPD IOPC IOPB IOPA Res. AFIO
1673Figure 4.2: APB2 Peripheral Clock Enable Register
16744.2 I/O Pins
1675Most of the pins of the STM32 can be configured as input or output
1676and may be connected to either the GPIO ports or “alternative functions”
1677(other peripherals). As a standard naming convention, the pins are called by
1678their GPIO function – for example PA0 (bit 0 of port A) or PB9 (bit 9 of
1679port B). Indeed, the labeling of the discovery board follows this convention.
1680Subject to specific hardware constraints, each pin can be configured in the
1681modes illustrated in Figure 4.2.
1682Function Library Constant
1683Alternate function open-drain GPIO_Mode_AF_OD
1684Alternate function push-pull GPIO_Mode_AF_PP
1685Analog GPIO_Mode_AIN
1686Input floating GPIO_Mode_IN_FLOATING
1687Input pull-down GPIO_Mode_IPD
1688Input pull-up GPIO_Mode_IPU
1689Output open-drain GPIO_Mode_Out_OD
1690Output push-pull GPIO_Mode_Out_PP
1691Table 4.2: Pin Modes (stm32f10x_gpio.h)
1692By default, most pins are reset to “Input Floating” – this ensures that
1693no hardware conflicts will occur when the system is powering up. The firmware
1694library provides an initialization routine in stm32f10x_gpio.[ch] which may
1695be used to reconfigure the pins. For example, for the blinking lights we configured PC9 as a (slow) output as illustrated in Listing 4.1.
1696When configuring an output as shown above, we have three choices of
1697output “speed” – 50 MHz, 10 MHz, and 2 MHz. In general, for reasons of
1698power consumption and noise, it is desirable to use the lowest speed consistent
1699Revision: 14c8a1e (2016-06-05) 63
1700CHAPTER 4. STM32 CONFIGURATION
1701// see stm32f10x_gpio.h
1702GPIO_InitTypeDef GPIO_InitStructure;
1703GPIO_StructInit(&GPIO_InitStructure);
1704GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
1705GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
1706GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
1707GPIO_Init(GPIOC , &GPIO_InitStructure);
1708Listing 4.1: PC9 Configuration
1709with the I/O requirements. The field GPIO_Pin is a bit vector and it is possible
1710to configure multiple pins associated with a single port in a single step.
1711Note: The pin-outs for specific parts (including the assignment of peripherals to pins) are defined in their respective data sheets (e.g. [15]) and
1712NOT in the programming manual ! The pin assignments for the Discovery
1713board are documented in the user’s manual [14].
1714As we have seen, we can write a value to the pin controlling the LED
1715with the following procedures:
1716GPIO_WriteBit(GPIOC , GPIO_Pin_9 , x); // x is Bit_SET or Bit_RESET
1717The gpio library module provides procedures to read and write both
1718individual pins and entire ports – the later is especially helpful when capturing
1719parallel data. It is instructive to read stm32f10x_gpio.h.
1720To (re-)configure the pin associated with the discovery board push button, we can use the following code (after configuring the clock for Port A
1721!):
1722GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
1723GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
1724GPIO_Init(GPIOA , &GPIO_InitStructure);
1725To read the current value of the pushbutton we can execute:
1726GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_0)
1727Recall from Chapter 2 that each GPIO port is controlled by 7 registers:
1728typedef struct
1729{
173064 Revision: 14c8a1e (2016-06-05)
17314.3. ALTERNATIVE FUNCTIONS
1732volatile uint32_t CRL;
1733volatile uint32_t CRH;
1734volatile uint32_t IDR;
1735volatile uint32_t ODR;
1736volatile uint32_t BSRR;
1737volatile uint32_t BRR;
1738volatile uint32_t LCKR;
1739} GPIO_TypeDef;
1740The 16 bits of each port are configured with CRL (bits 0-7) and CHR (pins
17418-15). To support the various I/O modes, 4 configuration bits are required for
1742each GPIO bit. The 16 GPIO bits can be read in parallel (IDR) and written in
1743parallel (ODR). As a convenience, registers BSRR and BRR provide a mechanism
1744to set and reset individual bits. The lock register LCKR provides a mechanism
1745to “lock” the configuration of individual bits against software reconfiguration
1746and hence protect hardware from software bugs.
1747Exercise 4.2 Blinking Lights with Pushbutton
1748Modify the blinking lights program to additionally track the state of
1749the user pushbutton (PA0) on the blue LED (PC8). See if you can figure out
1750how to configure both LEDs with a single call to GPIO_Init.
17514.3 Alternative Functions
1752Peripherals such as the USARTs share pins with the GPIO devices.
1753Before these peripherals can be utilized, any outputs required by the peripheral
1754must be configured to an “alternative mode”. For example, the Tx pin (data
1755out) for USART1 is configured as follows:
1756GPIO_InitStruct.GPIO_PIN = GPIO_Pin_9;
1757GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
1758GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
1759GPIO_Init(GPIOA , &GPIO_InitStruct);
1760The specific configuration required for each peripheral is described in
1761section 7.1.11 of the stm32f10xx reference manual RM0041 [20] (section 9.1.11
1762for stm32f103xx reference manual RM0008 [21]).
17634.4 Remapping
1764It is also possible to “remap” pins so that non-default pins are used for
1765various peripherals in order to minimize conflicts. These re-mappings, which
1766Revision: 14c8a1e (2016-06-05) 65
1767CHAPTER 4. STM32 CONFIGURATION
1768are beyond the scope of this book, are described in the appropriate STM32
1769reference manual ([20, 21])
17704.5 Pin Assignments For Examples and Exercises
1771In this book we develop a series of examples and exercises based upon
1772the STM32VL Discovery board. Ensuring that these examples can work together required some care in the selection of STM32 devices and GPIO pins
1773– for example we used the SPI2 device rather than the SPI1 device due to a
1774resource conflict. In Table 4.5 we enumerate all the pin assignments used in
1775this book along with the configurations required for these uses.
177666 Revision: 14c8a1e (2016-06-05)
17774.5. PIN ASSIGNMENTS FOR EXAMPLES AND EXERCISES
1778Device Pin Function Configuration
1779User Button PA0 Input floating
1780LCD Backlight PA1 Backlight Output/Alternative function push-pull
1781DAC1 PA4 DAC Output Analog
1782ADC PA6 IN6 Input floating
1783PA7 IN7 Input floating
1784Timer 1 PA8 Channel 1 Input floating
1785USART 1
1786PA9 TX Alternative function push-pull
1787PA10 RX Input Pull-up
1788PA11 nCTS Input Pull-up
1789PA12 nRTS Alternative function push-pull
1790Timer 3 PB0 Channel 3 Alternative function push-pull
1791PB1 Channel 4 Alternative function push-pull
1792I2C1 PB6 SCK Alternative function open-drain
1793PB7 SDA Alternative function open-drain
1794Timer 4 PB9 Channel 4 Alternative function push-pull
1795I2C2 PB10 SCK Alternative function open-drain
1796PB11 SDA Alternative function open-drain
1797SPI2
1798PB13 CLK Alternative function push-pull
1799PB14 MISO Input pull-up
1800PB15 MOSI Alternative function push-pull
1801LCD
1802control
1803PC0 LCD Select Output push-pull
1804PC1 Reset Output push-pull
1805PC2 Data/Control Output push-pull
1806SD Card PC6 Select Output push-pull
1807Blue LED PC8 Output push-pull
1808Green LED PC9 Output push-pull
1809SPI EEPROM CS PC10 Output push-pull
1810Table 4.3: Pin Assignments for Exercises
1811Revision: 14c8a1e (2016-06-05) 67
1812CHAPTER 4. STM32 CONFIGURATION
18134.6 Peripheral Configuration
1814As mentioned the third configuration stage, after clock distribution and
1815pin configuration, is peripheral configuration. While we defer the discussion of
1816peripheral specific configuration, the standard firmware library offers a standard pattern for the configuration process. We’ve see a bit of this already with
1817GPIO configuration where a device specific structure was populated with a
1818set of parameters and one or more pins for a given port were initialized:
1819GPIO_StructInit(&GPIO_InitStructure);
1820... fill in structure ...
1821GPIO_Init(GPIOx , &GPIO_InitStructure);
1822It is also possible to “de-initialize” a port, returning all of its pin configuration to the hardware reset state with a call to
1823GPIO_DeInit(GPIOx)
1824The DeInit function resets the peripheral registers, but it does not disable the peripheral clock – that requires a separate call to the clock command
1825(with DISABLE replacing ENABLE).
1826This pattern – an initialization structure, an init function, and a de-init
1827function is repeated throughout the standard peripheral library. The basic
1828naming convention for peripheral “ppp” is:
1829Files stm32f10x_ppp.[c|h]
1830Init Structure ppp_InitTypeDef
1831Zero Structure ppp_StructInit(ppp_InitTypeDef*)
1832Initialize Peripheral ppp_Init([sub-device,] ppp_InitTypeDef*)
1833De-initialize Peripheral ppp_DeInit([sub-device])
1834Examples of devices with the optional “sub device” are USART, SPI,
1835I2C. Timers are a somewhat complicated case because each timer is typically
1836multiple devices – a “time base”, zero or more output compares, zero or more
1837input captures. There are other exceptions, but mostly for peripherals that
1838are not supported on the medium density value-line parts.
1839Exercise 4.3 Configuration without Standard Peripheral Library
1840Write a program using only the constants defined in the programmer
1841reference manual ([20]) that: configures the pins for the user push-button and
1842blue LED, and, in an infinite loop, displays the button state on the LED.
1843Your code should look like
184468 Revision: 14c8a1e (2016-06-05)
18454.6. PERIPHERAL CONFIGURATION
1846main()
1847{
1848// configure button
1849// configure led
1850while (1)
1851{
1852if (read(button))
1853led = on;
1854else
1855led = off;
1856}
1857}
1858Revision: 14c8a1e (2016-06-05) 69
1859
1860Chapter 5
1861Asynchronous Serial
1862Communication
1863After LEDs and pushbuttons, the most basic method for communication with an embedded processor is asynchronous serial. Asynchronous serial
1864communication in its most primitive form is implemented over a symmetric
1865pair of wires connecting two devices – here I’ll refer to them as the host and
1866target, although those terms are arbitrary. Whenever the host has data to
1867send to the target, it does so by sending an encoded bit stream over its transmit (TX) wire; this data is received by the target over its receive (RX) wire.
1868Similarly, when the target has data to send to the host it transmits the encoded bit stream over its TX wire and this data is received by the host over its
1869RX wire. This arrangement is illustrated in Figure 5. This mode of communications is called “asynchronous” because the host and target share no time
1870reference. Instead, temporal properties are encoded in the bit stream by the
1871transmitter and must be decoded by the receiver.
1872Host Target
1873TX RX
1874RX TX
1875Figure 5.1: Basic Serial Communications Topology
1876Revision: 14c8a1e (2016-06-05) 71
1877CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
1878A commonly used device for encoding and decoding such asynchronous
1879bit streams is a Universal Asynchronous Receiver/Transmitter (UART) which
1880converts data bytes provided by software into a sequence of individual bits and,
1881conversely, converts such a sequence of bits into data bytes to be passed off to
1882software. The STM32 processors include (up to) five such devices called USARTs (for universal synchronous/asynchronous receiver/transmitter) because
1883they support additional communication modes beyond basic asynchronous
1884communications. In this Chapter we will explore serial communication between the (target) STM32 USART and a USB/UART bridge connected to a
1885host PC.
1886UARTs can also be used to interface to a wide variety of other peripherals. For example, widely available GSM/GPRS cell phone modems and
1887Bluetooth modems can be interfaced to a micro-controller UART. Similarly
1888GPS receivers frequently support UART interfaces. As with the other interfaces we’ll consider in future chapters, the serial protocol provides access to a
1889wide variety of devices.
1890frame
1891start stop
1892TX 0 1 2 3 4 5 6 7
1893Figure 5.2: Serial Communications Protocol
1894One of the basic encodings used for asynchronous serial communications
1895is illustrated in Figure 5. Every character is transmitted in a “frame” which
1896begins with a (low) start bit followed by eight data bits and ends with a (high)
1897stop bit. The data bits are encoded as high or low signals for (1) and (0),
1898respectively. Between frames, an idle condition is signaled by transmitting a
1899continuous high signal. Thus, every frame is guaranteed to begin with a highlow transition and to contain at least one low-high transition. Alternatives
1900to this basic frame structure include different numbers of data bits (e.g. 9),
1901a parity bit following the last data bit to enable error detection, and longer
1902stop conditions.
1903There is no clock directly encoded in the signal (in contrast with signaling protocols such as Manchester encoding) – the start transition provides the
1904only temporal information in the data stream. The transmitter and receiver
190572 Revision: 14c8a1e (2016-06-05)
1906each independently maintain clocks running at (a multiple of) an agreed frequency – commonly, and inaccurately, called the baud rate. These two clocks
1907are not synchronized and are not guaranteed to be exactly the same frequency,
1908but they must be close enough in frequency (better than 2%) to recover the
1909data.
1910Sample
1911clock (16x)
191224 16
1913idle start
1914TX 0 1
1915Figure 5.3: UART Signal Decoding
1916To understand how the receiver extracts encoded data, assume it has a
1917clock running at a multiple of the baud rate (e.g. 16x) starting from an idle
1918state as illustrated in Figure 5. The receiver “samples” its RX signal until it
1919detects a high-low transition. It then waits 1.5 bit periods (24 clock periods)
1920to sample its RX signal at what it estimates to be the center of data bit 0.
1921The receiver then samples RX at bit-period intervals (16 clock periods) until
1922it has read the remaining 7 data bits and the stop bit. From that point the
1923process repeats. Successful extraction of the data from a frame requires that,
1924over 10.5 bit periods, the drift of the receiver clock relative to the transmitter
1925clock be less that 0.5 periods in order to correctly detect the stop bit.
1926Exercise 5.1 Testing the USB/UART Interface
1927Before we discuss the implementation of UART communications with
1928the STM32, it may be helpful to use the Saleae Logic to “see” the asynchronous
1929signals. We will use the USB-UART bridge to generate signals that we will
1930then capture with logic analyzer. Later, this will be an essential tool for
1931debugging your code executing on the STM32.
1932It is extremely difficult to debug hardware device drivers using only a
1933software debugger such as GDB because these debuggers provide no visibility
1934into what the hardware is actually doing. For example, if one neglects to
1935configure the clocks to a specific hardware peripheral, that peripheral will do
1936nothing in response to software commands even if all the peripheral specific
1937software is completely correct. Perhaps even more vexing is when the hardware interface almost works. For example, in developing the I2C examples
1938Revision: 14c8a1e (2016-06-05) 73
1939CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
1940Figure 5.4: Adding A Protocol Analyzer
1941Figure 5.5: Configuring Capture Rate and Trigger
1942using the Wii Nunchuk, I found that while the STM32 and Nunchuk were
1943communicating, the data exchanged was incorrect – ultimately, I tracked this
1944to an incorrect clock rate. In this case GDB was slightly helpful it isolating
1945but not diagnosing the problem.
1946For developing embedded systems with communicating hardware, a
1947logic analyzer provides the capability of observing the actual communication
1948events between two hardware components. Essentially, a logic analyzer “listens” to a set of digital signals until a trigger event occurs and then captures a
1949window of data around the trigger event. The software associated with a logic
1950analyzer allows us to interpret the captured data. In the simplest case a trigger event might be a the occurrence of a transition on a signal – in the case of
1951USART communication, every transmission event begins with a falling transition. Throughout this book we use the Saleae Logic analyzer. Professional
195274 Revision: 14c8a1e (2016-06-05)
1953logic analyzers can watch for complex sequences of events to form a trigger
1954condition, but the Saleae analyzer is limited to simple events. Furthermore,
1955the Saleae can only capture signals at a modest sample rate. However, it is
1956more than sufficient for the examples we present.
1957Early logic analyzers were relatively limited in the display of captured
1958information as a simple time sequence of signals. More modern systems, including the Saleae Logic, provide protocol analysis capabilities which overlay
1959the time sequences with interpretations. For example, with serial protocol
1960analyzers, the actual characters transmitted are displayed superimposed over
1961the time sequence.
1962The Saleae Logic software provides a simulation mode which is useful for
1963learning how the system works. We will begin by using the simulation mode to
1964evaluate serial protocol. You will need to download and install the Saleae logic
1965software appropriate for your system http://www.saleae.com/downloads/.
1966Launch the Logic software. On the right side of the screen “add” an
1967“Async Serial” analyzer – the default options are fine – and rename the channel
19680 to “Serial Out.” This is illustrated in Figure 5.4.
1969Set the capture rate to 100 Khz, the number of samples to 1 M, and the
1970trigger condition on Serial Out to the falling arrow (a transition from ’1’ to
1971’0’) as illustrated in Figure 5.5. When configuring Saleae for other protocols,
1972you will need to select a capture rate that is a multiple (ideally 10 or more) of
1973the data rate. You will find that the Saleae logic is somewhat limiting in this
1974regard. For example, I have found it necessary to debug the SPI protocol at
1975a somewhat reduced rate in order to ensure that the Saleae logic is capable of
1976buffering the data. Ultimately, it may be necessary to debug at a modest rate
1977and, when confident everything is working, increase the underlying protocol
1978speed.
1979Finally, start the simulation. After the simulation is complete zoom in
1980on the data (by clicking with the mouse pointer) until individual serial frames
1981are visible. You may wish to read the Saleae Logic User’s Guide to learn how
1982to navigate the displayed data.
1983Once you understand the basic interface, connect the ground and TX
1984pins of a USB/UART adaptor to the gray and black (channel 0) wires of the
1985logic. Connect the USB/UART adaptor and Saleae Logic module to your
1986computer. We will use the Unix “screen” program as an interface to the
1987USB-UART bridge.
1988First you need to determine the device name for the UART-USB bridge.
1989List the contents of /dev/tty* to find all the tty devices. You are looking for a
1990Revision: 14c8a1e (2016-06-05) 75
1991CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
1992device with USB in its name (e.g. in OS X, tty.SLAB_USBtoUART, or ttyUSB0
1993in Linux).
1994Once you’ve found the device (e.g. /dev/ttyXXX), it’s important to
1995make sure that it is correctly configured. To determine the current configuration execute
1996stty -f /dev/ttyXXX
1997On Linux -f should be replaced by -F. This will list the current configuration. If the baud rate is other than 9600, you have two choices – change the
1998baud rate in your program, or modify the device baud rate (see the man page
1999for stty to learn how to do this.). Once the configuration of your program
2000and device match, execute the following in the screen terminal.
2001screen /dev/ttyXXX
2002Now, anything you type in the screen program will be transmitted by
2003the USB/UART adaptor. In the logic program, “start” a capture – you should
2004see a window that says “waiting for a trigger”. Then, in the screen window
2005type the alphabet as quickly as you can. Once the capture is complete, zoom
2006in and examine the captured data – you should see the characters you typed.
2007If the data is marked with framing errors, then it is likely that the USB/UART
2008is transmitting at a baud rate that is different than the Saleae Logic expects.
2009Correct this (either by reconfiguring Logic, or the USB/UART) before proceeding.
2010To exit from screen type C-a k\ (“control a k’́).
20115.1 STM32 Polling Implementation
2012The simplest form of USART communication is based upon polling the
2013state of the USART device. Each STM32 USART has 6 registers – 4 of which
2014are used for configuration through the initialization routines provided by the
2015driver library as shown in Section 5.2. The remaining 2 registers are the
2016“data register” and the “status register”. While the data register occupies a
2017single memory word, it is really two separate locations; when the data register
2018is written, the written character is transmitted by the USART. When the
2019data register is read, the character most recently received by the USART is
2020returned. The status register contains a number of flags to determine the
2021current USART state. The most important of these are:
202276 Revision: 14c8a1e (2016-06-05)
20235.1. STM32 POLLING IMPLEMENTATION
2024USART_FLAG_TXE -- Transmit data register empty
2025USART_FLAG_RXNE -- Receive data register not empty
2026Other flags provide error information include parity, framing, and overrun errors which should be checked in a robust implementation.
2027In order to transmit a character, the application software must wait for
2028the transmit data register to be empty and then write the character to be
2029transmitted to that register. The state of the transmit data register is determined by checking the USART_FLAG_TXE flag of the USART status register.
2030The following code implements a basic putchar procedure utilizing USART1.
2031int putchar(int c){
2032while (USART_GetFlagStatus(USART1 , USART_FLAG_TXE) == RESET);
2033USART1 ->DR = (c & 0xff);
2034return 0;
2035}
2036With a single transmit data register, this implementation is only as fast
2037as the underlying baud rate and must wait (by “polling” the flag status) between characters. For simple programs this may be acceptable, but in general
2038a non-block implementation such as the one we will describe in Section 11.5
2039is preferred. The dual of putchar is getchar.
2040int getchar(void){
2041while (USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == RESET);
2042return USART1 ->DR & 0xff;
2043}
2044Notice the use of the status flag USART_IT_RXNE to determine when
2045there is a character to receive (“receive data not empty”). Also, notice the
2046use of a mask to select the lower 8 bits returned by USART_ReceiveData –
2047this library procedure returns 9 bits by default because configuration of the
2048USART permits 9-bit data. For example, the 9th bit might contain parity
2049information which could be used to check the validity of the received character.
2050While the polling implementation of putchar has the deficiency of being
2051slow, the polling implementation of getchar has a fatal flaw – if the application
2052code does not receive characters as they arrive, but the host continues to send
2053characters, an “overrun” will occur that results in lost characters. The STM32
2054is has only a single receive data buffer while many micro-controllers have 8
2055or 16 character buffers. This provides very little room for timing variation in
2056the application code that is responsible for monitoring the USART receiver.
2057Revision: 14c8a1e (2016-06-05) 77
2058CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
2059In the Chapter 11 we discuss the use of interrupt driven code to alleviate this
2060deficiency.
20615.2 Initialization
2062As with all STM32 peripherals, the USARTs must be initialized before
2063they can be used. This initialization includes pin configuration, clock distribution, and device initialization. Initialization is handled most conveniently
2064with the Standard Peripheral Driver library – in the following we assume version 3.5.0. The stm32f100 component in the discovery board has 3 USARTs
2065called USART1 – USART3 throughout the documentation and driver library.
2066In the following we will be utilizing USART1, but the principles for the other
2067USARTs are the same.
2068There are three modules (in addition to the general header) that are
2069part of the driver library which are required for USART applications (you will
2070need to include the associated object files in your make file).
2071#include <stm32f10x.h>
2072#include <stm32f10x_gpio.h>
2073#include <stm32f10x_rcc.h>
2074#include <stm32f10x_usart.h>
2075The first initialization step is to enable the RCC (reset and clock control) signals to the various functional blocks required for utilizing the USART
2076– these include GPIO ports (port A for USART1), the USART component
2077and the AF (alternative function) module. For USART1, the necessary RCC
2078configuration step is:
2079RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 |
2080RCC_APB2Periph_AFIO |
2081RCC_APB2Periph_GPIOA , ENABLE);
2082USART2 and USART3 are “APB1” peripherals, hence their RCC initialization differs slightly. Notice the that various APB2 flags are or’d together; it is also acceptable to enable the clocks in separate steps.
2083Once clocks are enabled, it is necessary to configure the USART pins –
2084the default pins for all three USARTs are provided in Table 5.1.
2085The STM32 reference manuals provide key information for configuring
2086the GPIO pins for the various devices. For the USARTs, this information is
2087reproduced here as Table 5.2. More complete pin configuration information is
2088available from the device data sheet [15].
208978 Revision: 14c8a1e (2016-06-05)
20905.2. INITIALIZATION
2091Function Pin
2092x=1 x=2 x=3
2093USARTx_TX PA9 PA2 PB10
2094USARTx_RX PA10 PA3 PB11
2095USARTx_CK PA8 PA4 PB12
2096USARTx_RTS PA12 PA1 PB14
2097USARTx_CTS PA11 PA0 PB13
2098Table 5.1: USART Pins
2099USART pinout Configuration GPIO Configuration
2100USARTx_TX Full Duplex Alternate function push-pull
2101Half duplex Synchronous
2102mode
2103Alternate function push-pull
2104USARTx_RX Full Duplex Input floating/Input Pull-up
2105Half duplex Synchronous
2106mode
2107Not used. Can be used as General IO
2108USARTx_CK Synchronous mode Alternate function push-pull
2109USARTx_RTS Hardware flow control Alternate function push-pull
2110USARTx_CTS Hardware flow control Input floating/Input pull-up
2111Table 5.2: USART Pin Configuration
2112As mentioned previously, the USARTs in the STM32 are capable of
2113supporting an additional operational mode – synchronous serial – that requires
2114an separate clock signal (USARTx_CK) which we will not be using. In addition,
2115the USARTs have the capability to support “hardware flow control” (signals
2116USARTx_RTS and USARTx_CTS) which we will discuss in Section 11.5. For
2117basic serial communications we must configure two pins – USART1_Tx and
2118USART1_Rx. The former is an output “driven” by the USART component
2119(an “alternative function” in the STM32 documentation) while the later is an
2120input which may be configured as floating or pulled up. Pin configuration is
2121performed with functions and constants defined in stm32f10x_gpio.h.
2122Revision: 14c8a1e (2016-06-05) 79
2123CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
2124GPIO_InitTypeDef GPIO_InitStruct;
2125GPIO_StructInit(&GPIO_InitStruct);
2126// Initialize USART1_Tx
2127GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
2128GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
2129GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
2130GPIO_Init(GPIOA , &GPIO_InitStruct);
2131// Initialize USART1_RX
2132GPIO_InitStruct.GPIO_PIN = GPIO_Pin_10;
2133GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
2134GPIO_Init(GPIOA , &GPIO_InitStruct);
2135The final initialization step is to configure the USART. We use the
2136default USART initialization of 9600 “baud”, 8 data bits, 1 stop bit, no parity,
2137and no flow control provided by the library procedure USART_StructInit.
2138Changes to the default initialization are made by modifying specific fields of
2139the USART_InitStructure.
21401
2141// see stm32f10x_usart.h
2142USART_InitTypeDef USART_InitStructure;
2143// Initialize USART structure
2144USART_StructInit(&USART_InitStructure);
2145// Modify USART_InitStructure for non-default values , e.g.
2146// USART_InitStructure.USART_BaudRate = 38400;
2147USART_InitStructure.USART_BaudRate = 9600;
2148USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
2149USART_Init(USART1 ,&USART_InitStructure);
2150USART_Cmd(USART1 , ENABLE);
2151Exercise 5.2 Hello World!
2152The code in the preceding sections provide all of the basic functionality
2153required to successfully use an STM32 USART. In this section, I will guide you
21541As with many of the library procedures, it can be illuminating to read the source code
2155– in this case the module stm32f10x_usart.c.
215680 Revision: 14c8a1e (2016-06-05)
21575.2. INITIALIZATION
2158.../
2159STM32-Template/
2160HelloWorld/
2161main.c
2162Makefile
2163uart.c
2164uart.h
2165Figure 5.6: Hello World Project
2166int uart_open(USART_TypeDef* USARTx , uint32_t baud, uint32_t flags);
2167int uart_close(USART_TypeDef* USARTx);
2168int uart_putc(int c, USART_TypeDef* USARTx);
2169int uart_getc(USART_TypeDef* USARTx);
2170Listing 5.1: Uart Interface
2171through the process of developing a simple application that repeatedly sends
2172the string “hello world” from the STM32 to a host computer. This is the first
2173application that requires actually wiring hardware components together, so I
2174will walk you through that process. In the following I assume you have access
2175to a USB/UART bridge as described in Section 1.1.
2176You will be developing a program using the build environment provided
2177with the blinking light example. The directory structure for the (complete)
2178project is illustrated in Figure 5.6
2179The uart.[ch] files provide the basic software interface to the stm32
2180USART1. Your first task is to implement the functions specified by the uart.h
2181file (Listing 5.1).
2182The function uart_open should
21831. Initialize usart/gpio clocks.
21842. Configure usart pins
21853. Configure and enable the usart1
2186Revision: 14c8a1e (2016-06-05) 81
2187CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
2188GND
2189PB2
2190PB1
2191PB0
2192PC5
2193PC4
2194PA7
2195PA6
2196PA5
2197PA4
2198PA3
2199PA2
2200PA1
2201PA0
2202PC3
2203PC2
2204PC1
2205PC0
2206RST
2207PD1
2208PD0
2209PC15
2210PC14
2211PC13
2212VBAT
22133V3
2214NC
2215GND
2216PB10
2217PB11
2218PB12
2219PB13
2220PB14
2221PB15
2222GND
2223PC6
2224PC7
2225PC8
2226PC9
2227PA8
2228PA9
2229PA10
2230PA11
2231PA12
2232PA13
2233PA14
2234PA15
2235PC10
2236PC11
2237PC12
2238PD2
2239PB3
2240PB4
2241PB5
2242PB6
2243PB7
2244Boot
2245PB8
2246PB9
22475V
2248NC
2249GND
2250stm32-discovery
2251Susp
2252RST
2253RI
22543.3V
2255RTS
2256DSR
2257DTR
2258DCD
2259Susp
2260RX
22615V
2262TX
2263GND
2264CTS
2265Figure 5.7: Wiring Uart Polling
2266You will need the following “include” directives in your uart.c file:
2267#include <stm32f10x.h>
2268#include <stm32f10x_rcc.h>
2269#include <stm32f10x_gpio.h>
2270#include <stm32f10x_usart.h>
2271#include "uart.h"
2272Functions uart_putc and uart_getc should read or write individual
2273characters, respectively. They should behave like the standard Linux getc
2274and putc. Your main.c file should:
22751. Initialize the timer tick.
22762. Initialize the uart.
22773. Write Hello World!\n\r'' every 250 msec.
227882 Revision: 14c8a1e (2016-06-05)
22795.2. INITIALIZATION
2280You will need to include stm32f10x.h, stm32f10x_usart.h, and uart.h
2281in your main.c file
2282You should copy and modify the Makefile from the BlinkingLight
2283directory. You should add uart.o and stm32f10x_usart.o to the OBJS list
2284of project files. You may need to modify the variable TEMPLATEROOT to point
2285to the directory containing the Demo program.
2286At this point you should make sure your project compiles correctly (type
2287make !). If compilation succeeded, you should have an executable named
2288“HelloWorld.elf”.
2289There are only three wires that need to be connected as illustrated in
2290Figure 5.7. The ground signals of the discovery board and uart bridge need
2291to be connected (these are labeled gnd) – there are multiple ground pins on
2292the discovery board all of which are electrically connected by the PCB. Thus,
2293only a single wire (black is traditional) is needed to tie the ground signals
2294together. You will need to connect the rx (tx) pin of USART1 to the tx (rx)
2295pin of the USB/uart.
2296To test your program, open three terminal windows. One will be used to
2297communicate with the USB/UART adaptor, a second will be used to execute
2298the gdb server, and the third to execute gdb.
2299Start the screen program to communicate with the USB/UART adaptor. In the gdbserver window, execute
2300st-util -1
2301Finally, in the gdb terminal, navigate to the directory with your program and execute
2302arm-none-eabi-gdb HelloWorld.elf
2303(gdb) target extended -remote :4242
2304(gdb) load
2305(gdb) continue
2306With some luck you will be rewarded with “hello world” in the screen
2307window. If not, it’s time for some serious debugging.
2308Even if you do not encounter problems, it will be instructive to use
2309the Saleae Logic to observe the low-level behavior of the STM32 UART. To
2310capture data from the lab board it is necessary to connect two wires from
2311the Saleae Logic to your circuit – ground (gray) and channel 0 (black). The
2312ground wire should be connected to one of the GND pins and channel 0 to the
2313Revision: 14c8a1e (2016-06-05) 83
2314CHAPTER 5. ASYNCHRONOUS SERIAL COMMUNICATION
2315USART1 tx (PA9) pin. Connect the Saleae logic analyzer to your computer
2316and configure the software for Async serial on channel 0.
2317Compile your project and download your executable (follow the directions in Section 1.2). Start the capture process on the Saleae logic, and run
2318your program. With luck, you will be rewarded with a capture of
2319Hello World\n\r being transmitted. If no data is captured, carefully check
2320that your software correctly configures the necessary peripherals and then,
2321using GDB, try to determine if your code is actually attempting to transmit
2322the string.
2323Exercise 5.3 Echo
2324Modify your program to receive and echo input from the host. There
2325are two ways to do this – line at a time and character at a time (try both !).
2326Try testing your code using cat to send an entire file to your program at once
2327while capturing the output in another file. You can check your output using
2328“diff.” It is likely that the input and output don’t match (especially if you
2329perform the echo on a line at a time basis). We will return to this problem in
2330Chapter 11.
233184 Revision: 14c8a1e (2016-06-05)
2332Chapter 6
2333SPI
2334The SPI bus is widely used serial interface for communicating with many
2335common hardware devices including displays, memory cards, and sensors. The
2336STM32 processors have multiple SPI interfaces and each of these interfaces
2337can communicate with multiple devices. In this chapter we show how to use
2338the SPI bus to interface to widely available EEPROM memory chips. These
2339chips provide non-volatile storage for embedded systems and are frequently
2340used to store key parameter and state data. In Chapter 7 we show how to use
2341the SPI bus to interface with a color LCD display module and in Chapter 8 we
2342will use the same interface to communicate with a commodity flash memory
2343card.
23446.1 Protocol
2345SCK
2346MOSI
2347MISO
2348SS
2349SCK
2350MOSI
2351MISO
2352SS
2353SPI
2354Master
2355SPI
2356Slave
2357Figure 6.1: SPI Protocol Block Diagram
2358The basic SPI interface is illustrated in Figure 6.1. Every instance of a
2359SPI bus has a single master and one or more slaves. While the STM32 can be
2360configured in either role, here we consider only the case where it is configured
2361as a master. In the figure there are four single-wire signals – three from the
2362Revision: 14c8a1e (2016-06-05) 85
2363CHAPTER 6. SPI
2364master and one from the slave. One of these signals, SS (for “slave select”)
2365must be replicated for every slave connected to the bus. All communication is
2366controlled by the master, which selects the slave it wishes to communicate with
2367by lowering the appropriate SS line, and then causes a single word (commonly
2368one byte) to be transferred serially to the slave over the signal MOSI (“master
2369out, slave in”) and simultaneously accepts a single byte from the slave over the
2370signal MISO (“master in, slave out”). This transfer is realized by generating 8
2371clock pulses on the signal SCK (“serial clock”).
23720 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
2373MOSI
2374MISO
2375SCK
2376SPI Master SPI Slave
2377Figure 6.2: Logical Behavior of SPI Bus
2378The basic data transfer mechanism can be visualized as a pair of linked
2379shift registers as illustrated in Figure 6.2. In this illustration, data are shifted
2380out (in) starting with most significant bit.
2381The actual protocol behavior is illustrated by the timing diagram in
2382Figure 6.3. In this figure, the master initiates communication with a slave
2383by lowering SS. Notice that the MISO signal moves from a high-impedance
2384(tri-state) state once the slave is selected. The master controls the transfer
2385with 8 pulses on SCLK. In this illustration, data are “clocked” in to the master/slave shift registers on rising clock edges and new data are driven on falling
2386clock edges. Unfortunately, the specific relationship between the clock edges
2387and data is configuration dependent – there are four possible clock modes;
2388however, the LCD requires the illustrated mode (commonly referred to as
2389CPOL=0,CPHA=0).
239086 Revision: 14c8a1e (2016-06-05)
23916.2. STM32 SPI PERIPHERAL
2392SCK
2393MOSI MSB LSB
2394MISO MSB LSB
2395SS
2396Cycle 1 2 3 4 5 6 7 8
2397CPOL=0, CPHA=0
2398Figure 6.3: SPI Protocol Timing
23996.2 STM32 SPI Peripheral
2400enum spiSpeed { SPI_SLOW , SPI_MEDIUM , SPI_FAST };
2401void spiInit(SPI_TypeDef* SPIx);
2402int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
2403const uint8_t *tbuf, int cnt,
2404enum spiSpeed speed);
2405int spiReadWrite16(SPI_TypeDef* SPIx, uint16_t *rbuf,
2406const uint16_t *tbuf, int cnt,
2407enum spiSpeed speed);
2408Listing 6.1: SPI Module Interface
2409In this chapter we will develop and test a SPI driver with the simple
2410interface illustrated in Listing 6.1. The standard peripheral library defines
2411three SPI devices (SPI1, SPI2, and SPI3) and 8 possible clock prescalers in
2412stm32f10x_spi.h – for the 24MHz part on the Discovery board, a prescaler
2413of 8 results in a 3MHz SPI clock (24/8). We use prescalers of 64, 8, and 2
2414for slow, medium, and fast speeds, respectively. This interface provides for
2415initializing any of these three devices with a relatively generic configuration.
2416There is one data transfer operation which allows exchanging buffers of data
2417with a SPI device. Technically, every data transfer is bidirectional, but many
2418devices do not utilize this capability. Thus, the read/write operations accept
2419null pointers for either send or receive buffers. The SPI device also supports
2420Revision: 14c8a1e (2016-06-05) 87
2421CHAPTER 6. SPI
242216-bit transfers, hence our interface provides a 16-bit read/write function.
2423Finally, the interface allows on-the-fly changes of transmission speed. Such a
2424change may be necessary if a bus has two slaves with differing speeds. 1
2425Initialization for the SPI module follows the same general sequence required for any peripheral –
24261. Enable clocks to peripheral and associated GPIO ports.
24272. Configure GPIO pins.
24283. Configure the device.
2429Function SPI1 SPI2 GPIO configuration
2430SCK PA5 PB13 Alternate function push-pull (50MHz)
2431MISO PA6 PB14 Input pull-up
2432MOSI PA7 PB15 Alternate function push-pull (50MHz)
2433Table 6.1: SPI Pin Configuration
2434The configuration of the pins required are illustrated in Table 6.1. Not
2435shown are the pins available for hardware control of the slave select line because we implement this through software control. The initialization process
2436is illustrated in Listing 6.2. We are only interested in one mode of operation – the STM32 acting as a master. In more complex systems it may
2437be necessary to significantly modify this procedure, for example passing in a
2438SPI_InitStructure. The initialization routine follows the sequence shown
2439above and is easily extended to support additional SPI peripherals.
24401We use this capability in Chapter 8 where initialization and block transfer speeds differ.
244188 Revision: 14c8a1e (2016-06-05)
24426.2. STM32 SPI PERIPHERAL
2443static const uint16_t speeds[] = {
2444[SPI_SLOW] = SPI_BaudRatePrescaler_64 ,
2445[SPI_MEDIUM] = SPI_BaudRatePrescaler_8 ,
2446[SPI_FAST] = SPI_BaudRatePrescaler_2};
2447void spiInit(SPI_TypeDef *SPIx)
2448{
2449SPI_InitTypeDef SPI_InitStructure;
2450GPIO_InitTypeDef GPIO_InitStructure;
2451GPIO_StructInit(&GPIO_InitStructure);
2452SPI_StructInit(&SPI_InitStructure);
2453if (SPIx == SPI2) {
2454/* Enable clocks , configure pins
2455...
2456*/
2457} else {
2458return;
2459}
2460SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
2461SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
2462SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
2463SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
2464SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
2465SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
2466SPI_InitStructure.SPI_BaudRatePrescaler = speeds[SPI_SLOW];
2467SPI_InitStructure.SPI_CRCPolynomial = 7;
2468SPI_Init(SPIx, &SPI_InitStructure);
2469SPI_Cmd(SPIx, ENABLE);
2470}
2471Listing 6.2: SPI Initialization
2472Our basic SPI module supports a single transaction types – read/write
2473which is illustrated in Listing 6.3. The read/write routine iterates over the
2474number of data bytes to be exchanged. Each iteration consists of sending
2475a byte, waiting for the receiver to complete, and then receiving a byte. In
2476the case of the write-only routine, an internal buffer is used to catch and
2477discard a received byte. Similarly, the read-only routine transmits a sequence
2478of 0xff (effectively idle) bytes while receiving. The 16-bit routines work by
2479temporarily modifying the configuration to support 16-bit transfers using the
2480following system calls:
2481Revision: 14c8a1e (2016-06-05) 89
2482CHAPTER 6. SPI
2483SPI_DataSizeConfig(SPIx, SPI_DataSize_16b);
2484SPI_DataSizeConfig(SPIx, SPI_DataSize_8b);
2485int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
2486const uint8_t *tbuf, int cnt, enum spiSpeed speed)
2487{
2488int i;
2489SPIx->CR1 = (SPIx->CR1 & ~SPI_BaudRatePrescaler_256) |
2490speeds[speed];
2491for (i = 0; i < cnt; i++){
2492if (tbuf) {
2493SPI_I2S_SendData(SPIx, *tbuf++);
2494} else {
2495SPI_I2S_SendData(SPIx, 0xff);
2496}
2497while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
2498if (rbuf) {
2499*rbuf++ = SPI_I2S_ReceiveData(SPIx);
2500} else {
2501SPI_I2S_ReceiveData(SPIx);
2502}
2503}
2504return i;
2505}
2506Listing 6.3: SPI Read/Write
25076.3 Testing the SPI Interface
2508The easiest way to test this SPI interface is by wiring it in “loop-back”
2509mode with MISO directly connected to MOSI and watching data transmissions
2510with the Saleae Logic. Because the Logic expects a select signal (SS) the
2511test program must explicitly configure and control a select signal. In the
2512following section, we will show how to use the SPI interface to control an
2513external EEPROM; for that example we will use PC10 as the select pin (for
2514this loopback example we are using PC3), therefore it is convenient to use the
2515same pin here.
2516The main routine of a simple test program is illustrated in Listing 6.4.
2517Notice that it tests both 8-bit and 16-bit modes. An fragment of the Logic
2518output for this program is illustrated in Figure 6.4.
251990 Revision: 14c8a1e (2016-06-05)
25206.3. TESTING THE SPI INTERFACE
2521uint8_t txbuf[4], rxbuf[4];
2522uint16_t txbuf16[4], rxbuf16[4];
2523void main()
2524{
2525int i, j;
2526csInit(); // Initialize chip select PC03
2527spiInit(SPI2);
2528for (i = 0; i < 8; i++) {
2529for (j = 0; j < 4; j++)
2530txbuf[j] = i*4 + j;
2531GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 0);
2532spiReadWrite(SPI2, rxbuf , txbuf , 4, SPI_SLOW);
2533GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 1);
2534for (j = 0; j < 4; j++)
2535if (rxbuf[j] != txbuf[j])
2536assert_failed(__FILE__ , __LINE__);
2537}
2538for (i = 0; i < 8; i++) {
2539for (j = 0; j < 4; j++)
2540txbuf16[j] = i*4 + j + (i << 8);
2541GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 0);
2542spiReadWrite16(SPI2, rxbuf16 , txbuf16 , 4, SPI_SLOW);
2543GPIO_WriteBit(GPIOC , GPIO_Pin_3 , 1);
2544for (j = 0; j < 4; j++)
2545if (rxbuf16[j] != txbuf16[j])
2546assert_failed(__FILE__ , __LINE__);
2547}
2548}
2549Listing 6.4: SPI Loopback Test
2550Exercise 6.1 SPI Loopback
2551Complete the loop back test and capture the resulting output with
2552Saleae. Pay special attention to the “byte order” for 16-bit transfers. Compare
2553this to the byte order for 8-bit transfers. You should use SPI2 and PC3 as the
2554select pin. A template for this project is illustrated in Figure 6.5
2555Revision: 14c8a1e (2016-06-05) 91
2556CHAPTER 6. SPI
2557Figure 6.4: SPI Loopback Test Output
2558.../
2559SPIloopback/
2560main.c
2561Makefile
2562spi.c
2563spi.h
2564Figure 6.5: SPI Loopback Project
25656.4 EEPROM Interface
2566One of the simplest and most useful SPI devices is a serial EEPROM
2567(electrically erasable programmable memory) which is often used in embedded devices as a small non-volatile store for configuration parameters and
2568persistent state (e.g. high scores in a game). Data retention for EEPROMs is
2569measured in decades. One limitation is that they can survive only a limited
2570number of write cycles (perhaps a million) and hence should be used for relatively slowly changing information. SPI EEPROMs are available from many
2571manufacturers with common interfaces. The capacities vary from < 1K bit
2572to > 1M bit.
2573Our choice of an EEPROM for the first SPI example application was
2574dictated by one consideration – the basic operation is intuitive (read/write)
2575and hence it is relatively easy to determine if interface code is working correctly. In the preceding section we used data loop back and the Saleae Logic
2576to ensure that our SPI interface code was operating as expected. It’s time to
257792 Revision: 14c8a1e (2016-06-05)
25786.4. EEPROM INTERFACE
2579use that code to build a simple application.
2580In the following discussion we use a member of the Microchip 25LC160
2581which is part of a series of devices ranging from 1Kbit for $0.50 (25x010) to
25821Mbit for $3.50 (25x1024). For this example, the actual size is irrelevant. We
2583use the common PDIP package illustrated in Figure 6.6.
2584CS 1
2585SO 2
2586W P 3
2587Vss(GND) 4
25888 Vcc
25897 HOLD
25906 SCK
25915 SI
2592Figure 6.6: PDIP Pinout
2593The 25xxxx devices implement a simple message protocol over the SPI
2594bus where every transaction consists of one or more instruction bytes sent to
2595the device followed by one or more data bytes either to or from the device. [6]
2596For example, The EEPROM contains a status register which can be used to
2597set various protection modes as well as determine whether the device is busy –
2598EEPROM devices take a long time to complete write operations ! The status
2599read transaction is illustrated in Figure 6.7 – not shown is the SPI clock which
2600completes 16 cycles during this transaction. The master (STM32) selects the
2601EEPROM by lowering SS, it then transmits the 8-bit RDSR code (0x05) and
2602receives the 8-bit status value.
2603MOSI RDSR
2604MISO status
2605SS
2606Figure 6.7: Read Status
2607A command to implement status read is easily implemented:
2608Revision: 14c8a1e (2016-06-05) 93
2609CHAPTER 6. SPI
2610uint8_t eepromReadStatus() {
2611uint8_t cmd[] = {cmdRDSR , 0xff};
2612uint8_t res[2];
2613GPIO_WriteBit(EEPROM_PORT , EEPROM_CS , 0);
2614spiReadWrite(EEPROM_SPI , res, cmd, 2, EEPROM_SPEED);
2615GPIO_WriteBit(EEPROM_PORT , EEPROM_CS , 1);
2616return res[1];
2617}
2618The status register format is illustrated in Figure 6.8. There are only
2619two bits that concern us at present – WIP (write in progress) and WEL (write
2620enable latch). BP[1:0] are block protect bits which, if set, protect portions of
2621the EEPROM from writes. The WIP bit is especially important – if it is set,
2622then a write is in progress and all commands other than RDSR will fail. As
2623we’ll see, it is essential to wait for this bit to be cleared before attempting any
2624other action. The WEL bit must be set in order to perform a data write and
2625it is automatically reset by any write – later we’ll see how to set this bit.
26267 6 5 4 3 2 1 0
26270 0 0 0 BP1 BP0 WEL WIP
2628Figure 6.8: EEPROM Status Register
2629Instruction Description Code
2630WRSR Write Status Register 0x01
2631WRITE Data Write 0x02
2632READ Data Read 0x03
2633WRDI Write Disable 0x04
2634RDSR Read Status Register 0x05
2635WREN Write Enable 0x06
2636Table 6.2: EEPROM Instructions
2637.
2638The full set of available commands are illustrated in Table 6.2. Which
2639we encode as:
2640enum eepromCMD { cmdREAD = 0x03, cmdWRITE = 0x02
2641cmdWREN = 0x06, cmdWRDI = 0x04,
2642cmdRDSR = 0x05, cmdWRSR = 0x01 };
2643The simplest commands are WRDI (Write disable) and WREN (Write
2644enable) which clear and set the WEL bit of the status register respectively.
264594 Revision: 14c8a1e (2016-06-05)
26466.4. EEPROM INTERFACE
2647Each is implemented by writing a single byte – the command – to the EEPROM. No data is returned. Remember, both of these commands will fail if
2648the EEPROM is busy. For example, we implement the an EEPROM enable
2649as follows (notice the status register polling !):
2650#define WIP(x) ((x) & 1)
2651void eepromWriteEnable(){
2652uint8_t cmd = cmdWREN;
2653while (WIP(eepromReadStatus()));
2654GPIO_WriteBit(EEPROM_PORT , EEPROM_CS , 0);
2655spiReadWrite(EEPROM_SPI , 0, &cmd, 1, EEPROM_SPEED);
2656GPIO_WriteBit(EEPROM_PORT , EEPROM_CS , 1);
2657}
2658The most difficult instructions to implement are read and write – both
2659can read or write multiple bytes. It is important to note that these operations
2660must behave differently for various size EEPROMS. For the larger EEPROMS,
2661such as the 25LC160, the address is transmitted as a pair of successive bytes,
2662while for the 25AA040, the most significant address bit (8) is encoded with
2663the command. Here we assume a 16-bit address as illustrated by the read
2664operation in Figure 6.9. A read operation can access any number of bytes
2665– including the entire EEPROM. The operation begins with the instruction
2666code, two address bytes (most significant byte first !) and then 1 or more read
2667operations. The address transmission is most conveniently treated as a 16-bit
2668transfer – if performed with two 8-bit transfers the address will need to have
2669its bytes swapped.
2670MOSI READ A[15:8] A[7:0]
2671MISO D0 Dn
2672SS
2673Figure 6.9: EEPROM Read
2674The write operation is more complicated because of the architecture of
2675an EEPROM. The memory array is organized into “pages” and it is possible
2676to write any or all bytes in a page in a single operation (it is way more efficient
2677to write whole pages simultaneously). The page size is device specific – the
2678Revision: 14c8a1e (2016-06-05) 95
2679CHAPTER 6. SPI
268025LC160 has 16 byte pages while larger ones may have 64 byte pages. It is not
2681possible to write bytes in more than one page in a single operation. In practice
2682any bytes written beyond the page selected by the address bits A[16:5] will
2683wrap around within the page. Thus, the eeprom write code must check for
2684page boundaries. The easiest implementation is to return a count of bytes
2685written and limit those bytes to a single page. Some devices limit reads to
2686page boundaries as well – it’s important to read the data sheet for the device
2687you plan to use !
2688void eepromInit();
2689void eepromWriteEnable();
2690void eepromWriteDisable();
2691uint8_t eepromReadStatus();
2692void eepromWriteStatus(uint8_t status);
2693int eepromWrite(uint8_t *buf, uint8_t cnt, uint16_t offset);
2694int eepromRead(uint8_t *buf, uint8_t cnt, uint16_t offset);
2695Listing 6.5: EEPROM Module
2696Exercise 6.2 Write and Test an EEPROM Module
2697Implement an eeprom module with the interface illustrated in Listing 6.5. The connection for the eeprom chip are given in Table 6.3. You
2698should use SPI2 at the slow speed (most EEPROMS are fairly slow). The use
2699of a logic analyzer will be essential to debug any issues that arise.
2700Write a program to perform a test of reading/writing individual locations as well as block read/write.
2701EEPROM Pin EEPROM Signal STM32 Pin
27021 CS PC10
27032 SO PB14
27043 W P 3V3
27054 V SS GND
27065 SI PB15
27076 SCK PB13
27087 HOLD 3V3
27098 V CC 3V3
2710Table 6.3: EEPROM Connections
271196 Revision: 14c8a1e (2016-06-05)
2712Chapter 7
2713SPI : LCD Display
2714In this chapter we consider the use of the STM32 SPI interface to communicate with an LCD display module. The LCD is a 1.8” TFT display with
2715128x160 18-bit color pixels supported by a common (ST7735R) driver chip.
27167.1 Color LCD Module
2717The LCD module we consider uses the ST7735R controller.1
2718. We refer to
2719the display as a 7735 LCD. The 7735 LCD is a pixel addressable display; every
2720pixel requires multiple bytes to define color – the internal display memory uses
272118-bits/pixel (6 bits each for red, blue, and green). We will use this display
2722in a 16-bit mode with 5 bits defining red, 6 bits defining green, and 5 bits
2723defining blue. The display controller automatically extrapolates from 16 bits
2724to 18 bits when pixels are written to the display. This color model is illustrated
2725in Figure 7.1. There are two parts to this figure, the layout of the separate
2726colors within a 16-bit word, and colors resulting from various 16-bit constants.
2727To understand the required interface to the 7735 LCD, consider the
2728model in Figure 7.1. There are three major components to consider – the
2729controller, the LCD panel, and the display RAM. The display ram contains
273018 bits of color information for each of the (128 x 160) pixels in the panel.
27312 The data in the display RAM is continuously transferred to the panel –
2732we configure the device to sweep from bottom to top. The model for writing
2733pixel (color) data is somewhat indirect. First, using a separate “control”
27341There are two variants of the ST7735 – when initializing the controller it is important
2735to do this for the correct variant !
27362Actually 132x162, but we configure the controller for the smaller number.
2737Revision: 14c8a1e (2016-06-05) 97
2738CHAPTER 7. SPI : LCD DISPLAY
273915 11 10 5 4 0
2740Bit assignment
27410x0000
27420x001F
27430x07E0
27440x07FF
27450xF800
27460xF81F
27470xFFE0
27480xFFFF
2749Sample Colors
2750Figure 7.1: Color Encoding
2751interface, a drawing rectangle is configured. Then, pixel (color) data are
2752written. The location to which the data are written is determined by a pair
2753internal address counters RAC (for row address counter) and CAC (for column
2754address counter). Each successive pixel write causes these address counters
2755to be updated. The 7735 can be configured to “sweep” this rectangle an
2756any left/right top/down order. There are three internal control bits (which
2757we expose in the interface described subsequently). In addition to sweep
2758order, it is possible to “exchange” row and column address and thus support
2759a “landscape” mode. By default we use the mode 0x6 (MY = 1, MX = 1, MV
2760= 0). These are described fully in the ST7735 data manual. [11]
2761MY Row address order: 1 (bottom to top), 0 (top to bottom)
2762MX Column address order: 1 (right to left), 0 (left to right)
2763MV Column/row exchange: 1 (landscape mode), 0 (portrait mode)
2764As mentioned previously, we configure the panel to accept 16-bit color,
2765so each data write consists of a pair of bytes sent of the SPI interface. These
276616-bit color data are automatically translated to 18-bits through an internal
2767lookup table (LUT); the actual display ram pixels are 18-bits.
2768The 7735 has a separate control signal to differentiate “control” information from “data”. Control information (to be discussed subsequently) is
276998 Revision: 14c8a1e (2016-06-05)
27707.1. COLOR LCD MODULE
2771Display RAM
2772LCD Panel
2773 Controller
2774SPI
2775RAC
2776CAC
27770xF800 LUT
2778(0,0)
2779(127,159)
2780current
2781drawing
2782rectangle
2783Figure 7.2: Model of 7735 Display
2784used to configure the display and to set a current drawing rectangle. The advantage to this approach is that once a drawing rectangle is configured, data
2785can be sent in a burst without any additional control information.
2786A simple “driver” for the 7735 LCD requires only three routines – one
2787to initialize the controller, one to set the drawing rectangle, and one to write
2788color data to the current rectangle. Notice that this interface sets the drawing
2789direction when setting the rectangle (as described above, the madctl value
2790of 0x6 corresponds to a top-down/left-right sweep of the drawing rectangle.
2791A madctl value of 0x02 corresponds to a bottom-up/left-right sweep and is
2792useful for displaying BMP image files where the data are stored in bottom-up
2793order. A separate routine can be added to control the brightness of the backlight – for now we implement this as on/off. Later, in Chapter 10 we show
2794how to control the brightness with a PWM signal.
2795Revision: 14c8a1e (2016-06-05) 99
2796CHAPTER 7. SPI : LCD DISPLAY
2797#define MADCTLGRAPHICS 0x6
2798#define MADCTLBMP 0x2
2799#define ST7735_width 128
2800#define ST7735_height 160
2801void ST7735_setAddrWindow(uint16_t x0, uint16_t y0,
2802uint16_t x1, uint16_t y1, uint8_t madctl);
2803void ST7735_pushColor(uint16_t *color , int cnt);
2804void ST7735_init();
2805void ST7735_backLight(uint8_t on);
2806The following example fills the 7735 screen with a single background
2807color.
2808void fillScreen(uint16_t color)
2809{
2810uint8_t x,y;
2811ST7735_setAddrWindow(0, 0, ST7735_width -1, ST7735_height -1,
2812,→MADCTLGRAPHICS);
2813for (x=0; x < ST7735_width; x++) {
2814for (y=0; y < ST7735_height; y++) {
2815ST7735_pushColor(&color ,1);
2816}
2817}
2818}
2819While this interface can be made more sophisticated, it is sufficient to
2820display text, images, and graphics with sufficient programmer ingenuity.
2821One complication that must be dealt with is endianess. The STM32
2822memory is little-endian meaning that a 16-bit quantity is stored in successive
2823memory locations with the low-order byte (bits 0-7) at the lower memory
2824address. In contrast, the 7735 interface assumes that data are received in bigendian order (high-order byte first). Therefore, it is essential that color data
2825are transmitted using 16-bit transfer functions; transferring blocks of color
2826data with 8-bit transfers will result in the high and low order bytes being
2827swapped !
2828Implementation of basic functionality for the ST7735 relies upon a small
2829set of internal primitives to provide access to the SPI interface and handle
2830“chip select” control. These are illustrated in Listing 7.1. There are two
2831data commands for 8-bit and 16-bit transfers, and a control command. The
2832public interface commands are illustrated in Listing 7.2. Constants such as
2833ST7735_CASET (column address set) and ST7735_RASET (row address set) are
2834100 Revision: 14c8a1e (2016-06-05)
28357.1. COLOR LCD MODULE
2836defined in the ST7735 datasheet [11], although our code is derived from code
2837available at https://github.com/adafruit/Adafruit-ST7735-Library.git.
2838static void LcdWrite(char dc, const char *data, int nbytes)
2839{
2840GPIO_WriteBit(LCD_PORT ,GPIO_PIN_DC , dc); // dc 1 = data, 0 =
2841,→control
2842GPIO_ResetBits(LCD_PORT ,GPIO_PIN_SCE);
2843spiReadWrite(SPILCD , 0, data, nbytes , LCDSPEED);
2844GPIO_SetBits(LCD_PORT ,GPIO_PIN_SCE);
2845}
2846static void LcdWrite16(char dc, const uint16_t *data, int cnt)
2847{
2848GPIO_WriteBit(LCD_PORT ,GPIO_PIN_DC , dc); // dc 1 = data, 0 =
2849,→control
2850GPIO_ResetBits(LCD_PORT ,GPIO_PIN_SCE);
2851spiReadWrite16(SPILCD , 0, data, cnt, LCDSPEED);
2852GPIO_SetBits(LCD_PORT ,GPIO_PIN_SCE);
2853}
2854static void ST7735_writeCmd(uint8_t c)
2855{
2856LcdWrite(LCD_C , &c, 1);
2857}
2858Listing 7.1: ST7735 Internal Primitives
2859Initialization of the ST7735 is somewhat complex because of the need
2860to initialize internal registers in addition to pins and clock sources. The sequence of initialization commands is best copied from existing software (be
2861careful to use ST7735R initialization code !). The basic initialization process
2862requires sending a series of commands interspersed with delays. We defined
2863a data structure to hold these initialization steps (illustrated in Listing 7.3).
2864The actual initialization code is shown in Listing 7.4. Missing details can be
2865gleaned from the library code from which our code is derived – the elided
2866initialization commands are shown in Listing 7.5.
2867Wiring for the LCD module is relatively simple as illustrated in Figure 7.1 – the chip select signal for the SD card is left disconnected at this
2868time. Table 7.1 summarizes the necessary connections (constant names used
2869in the example code are shown in parenthesis).
2870Exercise 7.1 Complete Interface Code
2871Revision: 14c8a1e (2016-06-05) 101
2872CHAPTER 7. SPI : LCD DISPLAY
2873TFT Pin STM32 Pin Function
2874VCC 5V Power – 5 Volts
2875BKL PA1 Backlight control (GPIO_PIN_BKL)
2876RESET PC1 LCD Reset (GPIO_PIN_RST)
2877RS PC2 Data/Control (GPIO_PIN_DC)
2878MISO PB14 SPI2 MISO
2879MOSI PB15 SPI2 MOSI
2880SCLK PB13 SPI2 CLK
2881LCD CS PC0 LCD select (GPIO_PIN_SCE)
2882SD_CS PC6 SD card select
2883GND GND Ground
2884Figure 7.3: TFT Pin Assignment
2885Complete the code for the ST7335 driver by examining the reference
2886code at
2887https://github.com/adafruit/Adafruit-ST7735-Library. You’ll need to
2888complete the initialization code data structure. To test your code, write a
2889program that displays the three primary colors in a cycle, with an appropriate
2890delay.
2891Exercise 7.2 Display Text
2892An important use for an LCD is to display log messages from your
2893code. The first requirement is to display characters. The reference code cited
2894above includes a simple bit-mapped font glcdfont.c which defines the ASCII
2895characters as 5x7 bit maps (each character is placed in a 6x10 rectangle leaving
2896space between lines (3 pixels) and characters (1 pixel). A fragment of this
2897font is illustrated in Figure 7.1. ASCII 0 is a NULL character and hence not
2898displayed. Many of the low-numbered ASCII characters are unprintable and
2899hence either left blank or filled with a default glyph. Consider the character
2900for ’A’ (ASCII 65) also illustrated.
2901Write a routine to display a single character at a specific location defined by the upper left corner of the character – remember that (0,0) is the
2902upper left corner of the display and (127,159) is the lower right corner. Writing a character requires writing a foreground color to each “on” pixel and a
2903background color to each “off” pixel. Each character should occupy a 6x10
2904region. It is much faster to write a block to the LCD than one pixel at a time
2905(especially when we introduce DMA.
2906102 Revision: 14c8a1e (2016-06-05)
29077.1. COLOR LCD MODULE
2908GND
2909PB2
2910PB1
2911PB0
2912PC5
2913PC4
2914PA7
2915PA6
2916PA5
2917PA4
2918PA3
2919PA2
2920PA1
2921PA0
2922PC3
2923PC2
2924PC1
2925PC0
2926RST
2927PD1
2928PD0
2929PC15
2930PC14
2931PC13
2932VBAT
29333V3
2934NC
2935GND
2936PB10
2937PB11
2938PB12
2939PB13
2940PB14
2941PB15
2942GND
2943PC6
2944PC7
2945PC8
2946PC9
2947PA8
2948PA9
2949PA10
2950PA11
2951PA12
2952PA13
2953PA14
2954PA15
2955PC10
2956PC11
2957PC12
2958PD2
2959PB3
2960PB4
2961PB5
2962PB6
2963PB7
2964Boot
2965PB8
2966PB9
29675V
2968NC
2969GND
2970stm32-discovery
2971GND
2972SD CS
2973LCD CS
2974SCLK
2975MOSI
2976MISO
2977RS
2978RESET
2979BKL
2980VCC
29811.8 inch TFT LCD Module
2982Figure 7.4: Wiring for TFT Module
2983Extend your routine to support writing lines of text to the screen -
2984consider how you might handle wrap.
2985Exercise 7.3 Graphics
2986Write routines to draw lines and circles of various sizes and colors.
2987Revision: 14c8a1e (2016-06-05) 103
2988CHAPTER 7. SPI : LCD DISPLAY
2989#include <stdint.h>
2990const uint8_t ASCII[] = {
29910x00, 0x00, 0x00, 0x00, 0x00, // 0
29920x3E, 0x5B, 0x4F, 0x5B, 0x3E, // 1
2993...
29940x7C, 0x12, 0x11, 0x12, 0x7C, // 65 A
29950x7F, 0x49, 0x49, 0x49, 0x36, // 66 B
29960x3E, 0x41, 0x41, 0x41, 0x22, // 67 C
2997...
2998lsb
2999msb
30000x7C
30010x12
30020x11
30030x12
30040x7C
300501234
3006Figure 7.5: Font Fragment
3007104 Revision: 14c8a1e (2016-06-05)
30087.1. COLOR LCD MODULE
3009#define LOW 0
3010#define HIGH 1
3011#define LCD_C LOW
3012#define LCD_D HIGH
3013#define ST7735_CASET 0x2A
3014#define ST7735_RASET 0x2B
3015#define ST7735_MADCTL 0x36
3016#define ST7735_RAMWR 0x2C
3017#define ST7735_RAMRD 0x2E
3018#define ST7735_COLMOD 0x3A
3019#define MADVAL(x) (((x) << 5) | 8)
3020static uint8_t madctlcurrent = MADVAL(MADCTLGRAPHICS);
3021void ST7735_setAddrWindow(uint16_t x0, uint16_t y0,
3022uint16_t x1, uint16_t y1, uint8_t madctl)
3023{
3024madctl = MADVAL(madctl);
3025if (madctl != madctlcurrent){
3026ST7735_writeCmd(ST7735_MADCTL);
3027LcdWrite(LCD_D , &madctl , 1);
3028madctlcurrent = madctl;
3029}
3030ST7735_writeCmd(ST7735_CASET);
3031LcdWrite16(LCD_D , &x0, 1);
3032LcdWrite16(LCD_D , &x1, 1);
3033ST7735_writeCmd(ST7735_RASET);
3034LcdWrite16(LCD_D , &y0, 1);
3035LcdWrite16(LCD_D , &y1, 1);
3036ST7735_writeCmd(ST7735_RAMWR);
3037}
3038void ST7735_pushColor(uint16_t *color , int cnt)
3039{
3040LcdWrite16(LCD_D , color , cnt);
3041}
3042void ST7735_backLight(uint8_t on)
3043{
3044if (on)
3045GPIO_WriteBit(LCD_PORT_BKL ,GPIO_PIN_BKL , LOW);
3046else
3047GPIO_WriteBit(LCD_PORT_BKL ,GPIO_PIN_BKL , HIGH);
3048}
3049Listing 7.2: ST7735 Interface
3050Revision: 14c8a1e (2016-06-05) 105
3051CHAPTER 7. SPI : LCD DISPLAY
3052struct ST7735_cmdBuf {
3053uint8_t command; // ST7735 command byte
3054uint8_t delay; // ms delay after
3055uint8_t len; // length of parameter data
3056uint8_t data[16]; // parameter data
3057};
3058static const struct ST7735_cmdBuf initializers[] = {
3059// SWRESET Software reset
3060{ 0x01, 150, 0, 0},
3061// SLPOUT Leave sleep mode
3062{ 0x11, 150, 0, 0},
3063// FRMCTR1 , FRMCTR2 Frame Rate configuration -- Normal mode, idle
3064// frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D)
3065{ 0xB1, 0, 3, { 0x01, 0x2C, 0x2D }},
3066{ 0xB2, 0, 3, { 0x01, 0x2C, 0x2D }},
3067// FRMCTR3 Frame Rate configureation -- partial mode
3068{ 0xB3, 0, 6, { 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D }},
3069// INVCTR Display inversion (no inversion)
3070{ 0xB4, 0, 1, { 0x07 }},
3071/* ... */
3072Listing 7.3: ST7735 Initialization Commands (Abbreviated)
3073106 Revision: 14c8a1e (2016-06-05)
30747.1. COLOR LCD MODULE
3075void ST7735_init()
3076{
3077GPIO_InitTypeDef GPIO_InitStructure;
3078const struct ST7735_cmdBuf *cmd;
3079// set up pins
3080/* ... */
3081// set cs, reset low
3082GPIO_WriteBit(LCD_PORT ,GPIO_PIN_SCE , HIGH);
3083GPIO_WriteBit(LCD_PORT ,GPIO_PIN_RST , HIGH);
3084Delay(10);
3085GPIO_WriteBit(LCD_PORT ,GPIO_PIN_RST , LOW);
3086Delay(10);
3087GPIO_WriteBit(LCD_PORT ,GPIO_PIN_RST , HIGH);
3088Delay(10);
3089// Send initialization commands to ST7735
3090for (cmd = initializers; cmd->command; cmd++)
3091{
3092LcdWrite(LCD_C , &(cmd->command), 1);
3093if (cmd->len)
3094LcdWrite(LCD_D , cmd->data, cmd->len);
3095if (cmd->delay)
3096Delay(cmd->delay);
3097}
3098}
3099Listing 7.4: ST7735 Initialization
3100Revision: 14c8a1e (2016-06-05) 107
3101CHAPTER 7. SPI : LCD DISPLAY
31027.2 Copyright Information
3103Our code for the ST7335 is derived from a module available from https:
3104//github.com/adafruit/Adafruit-ST7735-Library.git
3105The following copyright applies to that code:
3106/***************************************************
3107This is a library for the Adafruit 1.8" SPI display.
3108This library works with the Adafruit 1.8" TFT Breakout w/SD card
3109----> http://www.adafruit.com/products/358
3110as well as Adafruit raw 1.8" TFT display
3111----> http://www.adafruit.com/products/618
3112Check out the links above for our tutorials and wiring diagrams
3113These displays use SPI to communicate, 4 or 5 pins are required to
3114interface (RST is optional)
3115Adafruit invests time and resources providing this open source code,
3116please support Adafruit and open-source hardware by purchasing
3117products from Adafruit!
3118Written by Limor Fried/Ladyada for Adafruit Industries.
3119MIT license, all text above must be included in any redistribution
3120****************************************************/
31217.3 Initialization Commands (Remainder)
3122108 Revision: 14c8a1e (2016-06-05)
31237.3. INITIALIZATION COMMANDS (REMAINDER)
3124// PWCTR1 Power control -4.6V, Auto mode
3125{ 0xC0, 0, 3, { 0xA2, 0x02, 0x84}},
3126// PWCTR2 Power control VGH25 2.4C, VGSEL -10, VGH = 3 * AVDD
3127{ 0xC1, 0, 1, { 0xC5}},
3128// PWCTR3 Power control , opamp current smal, boost frequency
3129{ 0xC2, 0, 2, { 0x0A, 0x00 }},
3130// PWCTR4 Power control , BLK/2, opamp current small and medium low
3131{ 0xC3, 0, 2, { 0x8A, 0x2A}},
3132// PWRCTR5 , VMCTR1 Power control
3133{ 0xC4, 0, 2, { 0x8A, 0xEE}},
3134{ 0xC5, 0, 1, { 0x0E }},
3135// INVOFF Don't invert display
3136{ 0x20, 0, 0, 0},
3137// Memory access directions. row address/col address , bottom to
3138,→top refesh (10.1.27)
3139{ ST7735_MADCTL , 0, 1, {MADVAL(MADCTLGRAPHICS)}},
3140// Color mode 16 bit (10.1.30
3141{ ST7735_COLMOD , 0, 1, {0x05}},
3142// Column address set 0..127
3143{ ST7735_CASET , 0, 4, {0x00, 0x00, 0x00, 0x7F }},
3144// Row address set 0..159
3145{ ST7735_RASET , 0, 4, {0x00, 0x00, 0x00, 0x9F }},
3146// GMCTRP1 Gamma correction
3147{ 0xE0, 0, 16, {0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D,
31480x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10 }},
3149// GMCTRP2 Gamma Polarity corrction
3150{ 0xE1, 0, 16, {0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D,
31510x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10 }},
3152// DISPON Display on
3153{ 0x29, 100, 0, 0},
3154// NORON Normal on
3155{ 0x13, 10, 0, 0},
3156// End
3157{ 0, 0, 0, 0}
3158};
3159Listing 7.5: ST7735 Initialization Commands (Remainder)
3160Revision: 14c8a1e (2016-06-05) 109
3161
3162Chapter 8
3163SD Memory Cards
3164In this chapter we show how to interface a commodity SD memory card
3165to the STM32 VL Discovery board using the SPI peripheral discussed in Chapter 6. While communicating with an SD memory card is a simple extension of
3166the previously presented work, controlling the card and interpreting the data
3167communicated requires a significant additional software. Fortunately, much
3168of the required software is available in the widely used FatFs module [3]. Only
3169a modest amount of porting is required to utilize this module with our SPI
3170driver.
3171The STM32 processors on the VL discovery board are relatively memory
3172constrained – 128K bytes flash and 8K bytes ram – which limits the ability to
3173store large quantities of data either as inputs to or outputs from an embedded
3174program. For example, in a game application it might be desirable to access
3175sound and graphic files or in a data logging application, to store extended
3176amounts of data. Furthermore, accessing the contents of the STM32 flash
3177requires a special interface and software. In such applications it is desirable to
3178provide external storage which the STM32 can access while running and the
3179user/programmer can easily access at other times. Commodity flash memory
3180cards (in particular SD cards) provide a cost effective solution which can
3181reasonably easily be accessed by both the processor and user. In practice,
3182these cards have file systems (typically FAT) and can be inserted in commonly
3183available adaptors to be accessed by a desktop machine. Furthermore, the
3184physical interface has a SPI mode which is accessible using the code described
3185in Chapter 6.
3186Physically, SD memory cards consist of a flash memory array and a
3187control processor which communicates with a host over either the SD bus (a
3188parallel bus) or the SPI bus. Communication is transaction based – the host
3189Revision: 14c8a1e (2016-06-05) 111
3190CHAPTER 8. SD MEMORY CARDS
3191sends a command message to the SD card and receives a response. Access to
3192the flash memory of an SD card is performed through fixed-sized block reads
3193and writes which are also implemented with the command protocol. A basic
3194overview is provided in [4].
3195The data on an SD card is organized as a file system – cards below 2GB
3196are typically formatted as FAT16 file systems. In a FAT file system, the first
3197several storage blocks are used to maintain data about the file system – for
3198example allocation tables – while the remaining blocks are used to store the
3199contents of files and directories.
3200Fat
3201Driver
3202SD
3203Driver
3204SPI
3205Driver
3206Application
3207SD
3208Card
3209SPI BUS
3210STM32
3211Figure 8.1: SD Card Software Stack
3212Although we have previously developed a SPI bus driver that is capable
3213of communicating with an SD card, we are missing several key software components. Consider Figure 8 which illustrates the necessary software stack. An
3214application, which wishes to access data stored on an SD Card, utilizes file
3215112 Revision: 14c8a1e (2016-06-05)
3216level commands such as open, read, and write to access specific files within
3217the SD card file system. These commands are provided by a FAT file system driver. The FAT file system issues commands at the level of block reads
3218and writes without any knowledge of how these commands are implemented.
3219A separate SD driver implements these commands. Finally, the SD driver
3220utilizes the SPI interface to communicate with the SD Card.
3221Fortunately, it is not necessary to write all of this software. In this
3222chapter we will describe the use of the FatFs generic file system. [3] This
3223open source package provides most of the components required including a
3224“generic” SD driver that is relatively easily modified to utilize the SPI driver
3225presented in Chapter 6.
3226To understand how an application interacts with FatFs, consider the
3227example derived from the FatFs sample distribution illustrated in Listing 8.1.
3228This example fragment assumes it is communicating with an SD card formatted with a fat file system which contains file in the root directory called
3229MESSAGE.TXT. The program reads this file, and creates another called HELLO.TXT.
3230Notice the use of relatively standard file system commands.
3231Revision: 14c8a1e (2016-06-05) 113
3232CHAPTER 8. SD MEMORY CARDS
3233f_mount(0, &Fatfs);/* Register volume work area */
3234xprintf("\nOpen an existing file (message.txt).\n");
3235rc = f_open(&Fil, "MESSAGE.TXT", FA_READ);
3236if (!rc) {
3237xprintf("\nType the file content.\n");
3238for (;;) {
3239/* Read a chunk of file */
3240rc = f_read(&Fil, Buff, sizeof Buff, &br);
3241if (rc || !br) break;/* Error or end of file */
3242for (i = 0; i < br; i++)/* Type the data */
3243myputchar(Buff[i]);
3244}
3245if (rc) die(rc);
3246xprintf("\nClose the file.\n");
3247rc = f_close(&Fil);
3248if (rc) die(rc);
3249}
3250xprintf("\nCreate a new file (hello.txt).\n");
3251rc = f_open(&Fil, "HELLO.TXT", FA_WRITE | FA_CREATE_ALWAYS);
3252if (rc) die(rc);
3253xprintf("\nWrite a text data. (Hello world!)\n");
3254rc = f_write(&Fil, "Hello world!\r\n", 14, &bw);
3255if (rc) die(rc);
3256xprintf("%u bytes written.\n", bw);
3257Listing 8.1: FatFs Example
32588.1 FatFs Organization
3259The following discussion refers to the current (0.9) version of FatFs.
3260The code distribution is organized as illustrated in Figure 8.2
3261The interface between the fat file system driver and the SD driver is
3262defined in the module diskio.h illustrated in Listing 8.2. We have modified
3263the default distribution to include meaningful parameter names. An initialized
3264disk can be read, written, and controlled (ioctl). The read/write commands
3265are restricted to the block level (the size of blocks depends upon the SD card).
3266The ioctl function provides a means to determine the SD card “geometry”
3267(e.g. number and size of blocks), and may provide additionally functionality
3268to enable power control. The low level implementation described in the sequel
3269only supports ioctl functions to determine the disk “geometry” and to force
3270114 Revision: 14c8a1e (2016-06-05)
32718.2. SD DRIVER
3272ff9/
3273doc/
3274src/
327500readme.txt
3276diskio.h
3277ff.c
3278ff.h
3279ffconf.h
3280integer.h
3281option/
3282Figure 8.2: FatFs Distribution Organization
3283completion of pending writes.
3284/*---------------------------------------*/
3285/* Prototypes for disk control functions */
3286int assign_drives (int, int);
3287DSTATUS disk_initialize (BYTE drv);
3288DSTATUS disk_status (BYTE drv);
3289DRESULT disk_read (BYTE drv, BYTE* buff, DWORD sector , BYTE count);
3290#if _READONLY == 0
3291DRESULT disk_write (BYTE drv, const BYTE* buff, DWORD sector , BYTE
3292,→count);
3293#endif
3294DRESULT disk_ioctl (BYTE drv, BYTE ctl, void* buff);
3295Listing 8.2: Low Level Driver Interface
32968.2 SD Driver
3297As described previously, the SD driver implements five functions to
3298support the FatFs and uses the SPI driver to communicate with the SDCard.
3299The SDCard communication protocol is transaction based. Each transaction
3300begins with a one-byte command code, optionally followed by parameters, and
3301then a data transfer (read or write). The SDCard protocol is well documented.
3302[9]. In the following we present a few examples to illustrated the basic concepts. Fortunately, it is not necessary to create this module from scratch.
3303There is a distribution of sample projects http://elm-chan.org/fsw/ff/
3304Revision: 14c8a1e (2016-06-05) 115
3305CHAPTER 8. SD MEMORY CARDS
3306ffsample.zip – we use the generic example. Alternatively, there is a more sophisticated port to the STM32 (http://www.siwawi.arubi.uni-kl.de/avr_
3307projects/arm_projects/arm_memcards/index.html#stm32_memcard). The
3308sample code is organized as illustrated in Figure 8.3.
3309ffsample/
331000readme.txt
3311lpc17xx/
3312xprintf.h
3313xprintf.c
3314...
3315...
3316generic/ .3 main.c
3317mmcbb.c
3318...
3319Figure 8.3: FatFs Sample Code Organization
3320Command
3321Response
3322From host (STM32)
3323From SD Card
3324Data Block
3325Command
3326Response
3327From host (STM32)
3328From SD Card
3329Command
3330Response
3331From host (STM32)
3332From SD Card Data Block
3333Write Transaction
3334Read Transaction
3335Control Transaction
3336Figure 8.4: SD Transactions
3337The three basic transaction types that concern us are illustrated in
3338Figure 8.2. Every transaction begins with a command issued by the host
3339116 Revision: 14c8a1e (2016-06-05)
33408.2. SD DRIVER
3341(in this case the STM32) followed by a response from the SD card. For
3342pure control operations (e.g querying the card status or configuration, the
3343SD card response terminates the transactions. For read or write transactions,
3344the response is followed by the transmission of a data block from (write) or to
3345the host (read). There are other cases including multi-block data transactions
3346and error conditions which are not illustrated. It should be clear that these
3347transaction types are sufficient to implement the functionality required by the
3348FatFs.
3349We will not delve deeply into the format of the information transferred
3350during transactions except to enumerate a few of the commands defined by
3351the SD Card specifications and to point out that all of the fields of a transaction may optionally be protected by CRC codes. A subset of the SD card
3352commands are illustrated in Table 8.2. Notice that there are commands to
3353reset and initialize the card, read/write parameters (e.g. block length), and
3354read/write data blocks. These commands are supported by multiple response
3355formats with lengths that vary from 1-5.
3356Command Description
3357CMD0 Reset the SD Card
3358CMD1 Initialize card
3359CMD8 Write voltage level
3360CMD9 Request card-specific data (CSD)
3361CMD10 Request card identification (CID)
3362CMD12 Stop transmission
3363CMD13 Request card status
3364CMD16 Set transfer block length
3365CMD17 Read single block
3366CMD18 Read multiple blocks
3367CMD24 Write single block
3368CMD25 Write multiple blocks
3369CMD58 Read OCR register
3370ACMD23 Number of blocks to erase
3371ACMD41 Initialize card
3372Table 8.1: Some SD Card Commands
3373Our implementation of the SD driver is a simple port of generic/mmbc.c
3374(see Figure 8.3). There are only a small number of routines that must be modified in order to utilize this module. These are presented in Listings 8.3 and 8.4.
3375Additionally, the sample code utilizes a wait function (DLY_US) that counts
3376Revision: 14c8a1e (2016-06-05) 117
3377CHAPTER 8. SD MEMORY CARDS
3378microseconds while our delay counts milliseconds. It is necessary to make appropriate modifications throughout the code. There is nothing fundamental
3379about most of the delay periods, but any changes should attempt a similar
3380total delay. Finally, we modified the disk_initialize routine to set the SPI
3381speed to a slow rate during initialization and a fast rate after initialization is
3382successfully completed.
3383Exercise 8.1 FAT File System
3384Port the generic FatFs driver and example program to the Discovery
3385board. You may use the xprintf functions distributed with the sample code.
3386FatFs is a highly configurable system. The configuration is controlled through
3387ffconf.h. For this exercise you should use the default settings. Once your
3388code is working, you may wish to try some of the available options. The basic
3389steps follow – an example Makefile is given in Listing 8.5
33901. modify mmcbb.c from the generic example
33912. create a project which includes ff.c from the fat file system, mmcbb.c,
3392your spi driver, and the required STM32 library files.
33933. format your SD card and create a file “MESSAGE.TXT”
3394In order to use xprintf you will need to include some code in your
3395main
3396#include "xprintf.h"
3397void myputchar(unsigned char c)
3398{
3399uart_putc(c, USART1);
3400}
3401unsigned char mygetchar()
3402{
3403return uart_getc(USART1);
3404}
3405int main(void)
3406{
3407...
3408xfunc_in = mygetchar;
3409xfunc_out = myputchar;
3410...
3411}
3412118 Revision: 14c8a1e (2016-06-05)
34138.2. SD DRIVER
3414#include <stm32f10x.h>
3415#include <stm32f10x_spi.h>
3416#include <stm32f10x_rcc.h>
3417#include <stm32f10x_gpio.h>
3418#include "spi.h"
3419#define GPIO_Pin_CS GPIO_Pin_6
3420#define GPIO_CS GPIOC
3421#define RCC_APB2Periph_GPIO_CS RCC_APB2Periph_GPIOC
3422#define SD_SPI SPI2
3423enum spiSpeed Speed = SPI_SLOW;
3424void Delay(uint32_t);
3425/* ... */
3426/*----------------------------*/
3427/* Transmit bytes to the card */
3428/*----------------------------*/
3429static
3430void xmit_mmc (
3431const BYTE* buff, /* Data to be sent */
3432UINT bc /* Number of bytes to send */
3433)
3434{
3435spiReadWrite(SD_SPI , 0, buff, bc, Speed);
3436}
3437/*-----------------------------*/
3438/* Receive bytes from the card */
3439/*-----------------------------*/
3440static
3441void rcvr_mmc (
3442BYTE *buff, /* Pointer to read buffer */
3443UINT bc /* Number of bytes to receive */
3444)
3445{
3446spiReadWrite(SD_SPI , buff, 0, bc, Speed);
3447}
3448Listing 8.3: SD Driver Routines
3449Revision: 14c8a1e (2016-06-05) 119
3450CHAPTER 8. SD MEMORY CARDS
3451/*-----------------------*/
3452/* Deselect the card */
3453/*-----------------------*/
3454static
3455void deselect (void)
3456{
3457BYTE d;
3458GPIO_SetBits(GPIO_CS , GPIO_Pin_CS);
3459rcvr_mmc(&d, 1); /* Dummy clock (force DO hi-z for multiple
3460,→slave SPI) */
3461}
3462/*-------------------*/
3463/* Select the card */
3464/*-------------------*/
3465static
3466int select (void) /* 1:OK, 0:Timeout */
3467{
3468BYTE d;
3469GPIO_ResetBits(GPIO_CS , GPIO_Pin_CS);
3470rcvr_mmc(&d, 1); /* Dummy clock (force DO enabled) */
3471if (wait_ready()) return 1; /* OK */
3472deselect();
3473return 0; /* Failed */
3474}
3475INIT_PORT()
3476{
3477GPIO_InitTypeDef GPIO_InitStructure;
3478RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_CS , ENABLE);
3479/* Configure I/O for Flash Chip select */
3480GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CS;
3481GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
3482GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
3483GPIO_Init(GPIO_CS , &GPIO_InitStructure);
3484deselect();
3485}
3486Listing 8.4: SD Driver Routines (cont.)
3487120 Revision: 14c8a1e (2016-06-05)
34888.2. SD DRIVER
3489TEMPLATEROOT = path_to_template_root
3490# additional compilation flags
3491CFLAGS += -g -Ipath_to_ff9/src
3492ASFLAGS += -g
3493LDLIBS += -lm
3494# project files
3495vpath %.c path_to_ff9/src
3496vpath %.c path_to_ff9/src/option
3497# ccsbcs.o
3498OBJS= $(STARTUP) main.o
3499OBJS+= ff.o spi.o uart.o xprintf.o mmcbb.o
3500OBJS+= stm32f10x_gpio.o stm32f10x_rcc.o stm32f10x_usart.o misc.o
3501OBJS+= stm32f10x_spi.o core_cm3.o
3502include $(TEMPLATEROOT)/Makefile.common
3503Listing 8.5: Makefile for SD Card Project
3504Revision: 14c8a1e (2016-06-05) 121
3505CHAPTER 8. SD MEMORY CARDS
35068.3 FatFs Copyright
3507FatFs module is an open source software to implement FAT file
3508,→system to
3509small embedded systems. This is a free software and is opened for
3510,→education ,
3511research and commercial developments under license policy of
3512,→following terms.
3513Copyright (C) 2011, ChaN, all right reserved.
3514* The FatFs module is a free software and there is NO WARRANTY.
3515* No restriction on use. You can use, modify and redistribute it
3516,→for
3517personal , non-profit or commercial product UNDER YOUR
3518* RESPONSIBILITY.
3519* Redistributions of source code must retain the above copyright
3520,→notice.
3521122 Revision: 14c8a1e (2016-06-05)
3522Chapter 9
3523I
35242C – Wii Nunchuk
3525In this chapter we introduce I2C, the third major protocol we use to
3526interface with external modules. I2C is a two wire protocol used to connect
3527one or more “masters” with one or more “slaves”, although we only discuss
3528the case of a single master (the STM32) communicating with slave devices.
3529An example configuration is illustrated in Figure 9.1. In this configuration, a
3530single master communicates with several slaves over the pair of signal wires SDA
3531and SCL. Example slave devices include temperature, humidity, and motion
3532sensors as well as serial EEPROMs.
3533As we shall see, the software required to interface with I2C devices is
3534considerably more complicated than with SPI. For example, I2C has multiple
3535error conditions that must be handled, SPI has no error conditions at the
3536physical level. Similarly, I2C has multiple transaction types, while SPI has a
3537single basic transaction type. Furthermore, SPI is generally a much faster bus
3538(1-3Mbit/sec vs 100-400Kbit/sec). The greatest advantage of I2C over SPI
3539ist that the number of wires required by I2C is constant (2) regardless of the
3540number of connected devices whereas SPI requires a separate select line for
3541each device. In place of select lines, I2C devices have internal addresses and
3542are selected by a master through the transmission of this address over the bus.
3543This difference makes I2C a good choice where a large number of devices must
3544be connected. Finally, I2C is a symmetric bus which can support multiple
3545masters whereas SPI is completely asymmetric.
3546The remainder of this chapter is organized as follows. We begin with
3547an introduction to the I2C protocol in Section 9.1. We then discuss the use of
3548I
35492C to communicate with a Wii Nunchuk. The Wii Nunchuk is an inexpensive
3550input device that includes a joystick, two buttons, and a three axis acceleromRevision: 14c8a1e (2016-06-05) 123
3551CHAPTER 9. I2C – WII NUNCHUK
3552eter (reported to be an LIS302 from ST Microelectronics [24]). Finally, we
3553present basic I2C communication module.
35549.1 I2C Protocol
3555In this Section we present a concise overview of the I2C bus protocol
3556which covers only those aspects of the protocol necessary to understand this
3557chapter. For a more complete description see the I2C specification manual [7].
3558Electrically, I2C is a “wired-or” bus – the value of the two signal wires
3559is “high” unless one of the connected devices pulls the signal low. On the left
3560side of Figure 9.1 are two resistors that force (“pull up”) the default value
3561of the two bus wires to VCC (typically 3.3V). Any device on the bus may
3562safely force either wire low (to GND) at any time because the resistors limit
3563the current draw; however, the communication protocol constrains when this
3564should occur. The two wires are called SCL (serial clock line) and SDA (serial
3565data/address). To communicate, a master drives a clock signal on SCL while
3566driving, or allowing a slave to drive SDA. Thus, the bit-rate of a transfer is
3567determined by the master.
3568Master Slave Slave
3569VCC
3570SDA
3571SCL
3572Figure 9.1: Typical I2C Configuration
3573SDA MSB LSB ACK
3574SCL
3575S P
3576Figure 9.2: I
35772C Physical Protocol
3578Communication between a master and a slave consists of a sequence
3579of transactions where the master utilizes the SCL as a clock for serial data
3580124 Revision: 14c8a1e (2016-06-05)
35819.1. I2C PROTOCOL
3582S Slave Address R/W= 0 A Data A Data A/A P
3583←−data transferred −→
3584(n bytes + acknowledge)
3585Write Transaction
3586S Slave Address R/W= 1 A Data A Data A P
3587←−data transferred −→
3588(n bytes + acknowledge)
3589Read Transaction
3590From master to slave
3591From slave to master
3592A = Acknowledge
3593A = Not Acknowledge
3594S = Start condition
3595P = Stop Condition
3596Figure 9.3: I
35972C Write and Read Transactions
3598driven by the master or a slave on SDA as illustrated in Figure 9.2. Every
3599transaction begins with a Start condition (S) and ends with Stop condition
3600(P). A transaction consists of a sequence of bytes, delivered most significant
3601bit (MSB) first, each of which is terminated by an Acknowledge (ACK), such
3602as illustrated here, or Not Acknowledge (NACK). The data may be sent by
3603either the slave or the master, as the protocol dictates, and the ACK or NACK
3604is generated by the receiver of the data. Start (S) and Stop (P) conditions are
3605always generated by the master. A high to low transition on SDA while SCL
3606is high defines a Start. A low to high transition on SDA while SCL is high
3607defines a Stop.
3608There are three types of transactions on the I2C bus, all of which are
3609initiated by the master. These are write, read, and combined transactions,
3610where a combined transaction concatenates a write and read transaction. The
3611first two of these are illustrated in Figure 9.3 – combined transactions are not
3612discussed in this book. Furthermore, there are two addressing modes: 7-bit
3613Revision: 14c8a1e (2016-06-05) 125
3614CHAPTER 9. I2C – WII NUNCHUK
3615addressing, as used in the transactions described in this book, and 10-bit
3616addressing which supports more devices on a single bus at the expensive a
3617more complex transaction format.
3618All 7-bit address transactions begin with a start event, the transmission
3619of a slave address and a bit which indicates whether this is a write or read
3620transaction by the master. The address phase it terminated by an ACK (0)
3621provided by the slave or NACK (1). Notice that in the event there is no
3622matching slave the electrical properties of the bus guarantee that a NACK is
3623received by the master. In the event that address transmission is followed by
3624a NACK, the master is obliged to generate a stop condition to terminate the
3625transaction thus returning the bus to an idle state – i.e. both signals high.
3626In a write transaction, the address phase if followed by a series of data
3627bytes (MSB first) transmitted by the master each of which is followed by
3628an ACK or NACK by the slave. The transaction is terminated with a Stop
3629condition after the master has sent as much data as it wishes or the slave has
3630responded with a NACK.
3631A read transaction differs from a write transaction in that the data
3632are provided by the slave and the ACK/NACK by the master. In a read
3633transaction, the master responds to the last byte it wishes to receive with a
3634NACK. The transaction is terminated with a Stop condition.
3635The protocol specification describes combined transactions, 10-bit addressing, multi-master buses, as well as details of the physical bus.
36369.2 Wii Nunchuk
3637Wii Nunchuks are inexpensive input devices with a joystick, two buttons, and a three-axis accelerometer as illustrated in Figure 9.4. Notice particularly the three axes X, Y, and Z which correspond to the data produced by
3638the accelerometer, joystick . X is right/left, Y is forward/backwards, and Z is
3639up/down (accelerometer only). The I2C bus is used to initialize the Nunchuk
3640to a known state and then to regularly “poll” its state. There is extensive
3641documentation on the web from which this chapter is drawn (e.g. [8]).
3642The data are read from the Nun chuck in a six-byte read transaction.
3643These data are formatted as illustrated in Figure 9.5 and are read beginning
3644with byte 0x0 (little-endian). The only complication with this format is that
3645the 10-bit/axis accelerometer data are split.
3646Communication with the Nunchuk consists of two phases – an initialization phase (executed once) in which specific data are written to to Nunchuk
3647126 Revision: 14c8a1e (2016-06-05)
36489.2. WII NUNCHUK
3649Y Z
3650X Z button
3651C button
3652Analog joystick
3653Figure 9.4: Wii Nunchuk
36547 6 5 4 3 2 1 0
36550x00 Joystick JX
36560x01 Joystick JY
36570x02 Accelerometer AX[9:2]
36580x03 Accelerometer AY[9:2]
36590x04 Accelerometer AZ[9:2]
36600x05 AZ[1:0] AY[1:0] AX[1:0] C Z
3661Figure 9.5: Nunchuk Data
3662and a repeated read phase in which the six data bytes are read. Each read
3663phase consists of two transactions – a write transaction which sets the read address to zero, and a read transaction. The following code fragments illustrates
3664the initialization phase. The initialization process is described in [23]. Essentially initialization consists of two write transactions, each of which writes a
3665single byte to a register internal to the I2C slave ( reg[0xf0] = 0x55, reg[0xfb]
3666= 0x00 ). The write routine takes three parameters, the I2C interface to use
3667Revision: 14c8a1e (2016-06-05) 127
3668CHAPTER 9. I2C – WII NUNCHUK
3669(I2C1 or I2C2), a buffer of data, the buffer length, and the slave address.
3670The I2C transaction routines, discussed in Section 9.3, return error conditions
3671which are ignored in this fragment.
3672128 Revision: 14c8a1e (2016-06-05)
36739.2. WII NUNCHUK
3674// Init
3675#define NUNCHUK_ADDRESS 0xA4
3676const uint8_t buf[] = {0xf0, 0x55};
3677const uint8_t buf2[] = {0xfb, 0x00};
3678I2C_Write(I2C1, buf, 2, NUNCHUK_ADDRESS);
3679I2C_Write(I2C1, buf2, 2, NUNCHUK_ADDRESS);
3680The Nunchuk read process consists of writing a 0 and then reading 6
3681bytes of data (as described above). Again, we have ignored any error return.
3682// Read
3683uint8_t data[6];
3684const uint8_t buf[] = {0};
3685I2C_Write(I2C1, buf, 1, NUNCHUK_ADDRESS);
3686I2C_Read(I2C1, data, 6, NUNCHUK_ADDRESS);
3687Reassembly of the data is rather simple; interpretation may be another
3688matter. The joystick data are in the range 0..255 roughly centered at 128
3689– we found it necessary to calibrate this based upon the value at startup.
3690Furthermore, the dynamic range was somewhat less than the full range (approximately 30-220).
3691The accelerometer data are in the range 0..1023 where 0 corresponds
3692to -2g and 1023 corresponds to +2g. The accelerometer can be used both
3693to detect motion (acceleration), but also as a “tilt sensor” when it is not in
3694motion because we can use the earth’s gravitational field as a reference. [10]
3695Suppose we have measured values of gravity in three dimensions – Gx, Gy, Gz
3696– we know that
3697G
36982
3699x + G
37002
3701y + G
37022
3703z = 1g
37042
3705From this, it is possible to compute “pitch” (rotation around the X axis),
3706“roll” (rotation around the Y axis) and “yaw” (rotation around the Z axis).
3707For joystick replacement, it is sufficient to compute (after range conversion to
3708-512..511).
3709pitch = atan (
3710AX
3711√
3712AY 2 + AZ2
3713)
3714Revision: 14c8a1e (2016-06-05) 129
3715CHAPTER 9. I2C – WII NUNCHUK
3716and
3717roll = atan (
3718AY
3719√
3720AX2 + AZ2
3721)
3722Keep in mind that this is for 360 degrees and a reasonable of motion to
3723measure is perhaps 90 degrees.
3724Exercise 9.1 Reading Wii Nunchuk
3725Using the I2C interface code described in Section 9.3 write a program to
3726track the state of the two joystick interface (one based on the accelerometer)
3727of a Wii Nunchuk and display this on the 5110 LCD. Your program should
3728use two letters, x and c, as cursors. When the c (x) button is pressed, the c
3729(x) cursor should be displayed as an upper case letter, otherwise is should be
3730displayed as a lower case letter. You should probably start with an I2C speed
3731of 10000 – the various Nunchuk clones appear to be unreliable at speeds in
3732the range of 100,000.
3733This is a challenging program to write. You will need to first learn
3734how to communicate with the Nunchuk. Your code will have to appropriately
3735scale the cursor position information to display each cursor in an appropriate
3736location. When working correctly, it should be possible to move each cursor
3737to all for corners of the screen with reasonable motion.
3738You will need to modify your Makefile to include the standard math
3739libraries by adding the following definition (assuming you are modifying the
3740demo template).
3741LDLIBS += -lm
3742In order to debug your I2C communications it is recommended that
3743you use the Saleae logic to capture any communication events. An example is
3744shown in Figure 9.6. This example illustrates the first phase of reading data
3745from the Nunchuk – writing a 0 to the Nunchuk address. Notice that the start
3746condition is indicated by a green dot and the stop condition is indicated by a
3747red square. Setting up the Saleae logic for the I2C protocol is similar to the
3748serial protocol, but with a different protocol analyzer.
3749The hardware configuration required is relatively simple. You will need
3750a Nunchuk adaptor as illustrated in Figure 1.7. There are four signals to
3751connect as shown in Table 9.1.
3752130 Revision: 14c8a1e (2016-06-05)
37539.3. STM32 I2C INTERFACE
3754Figure 9.6: Sample Logic Capture for I2C
3755STM32 Interface
3756I2C1 I2C2
3757+ 3V3 3V3
3758- GND GND
3759c PB6 PB10
3760d PB7 PB11
3761Table 9.1: Connection to Nunchuk Adaptor
37629.3 STM32 I2C Interface
3763The STM32 I2C device is extremely complicated. For example, read
3764transactions with 1, 2, and more than 2 bytes are handled in a significantly
3765different manner. The best references are the programmer’s manual ([21, 20])
3766and ST application note AN2824 [13]. The later describes examples for polling,
3767interrupt-driven, and DMA-driven interfaces. Unfortunately, the example
3768code weaves these three cases together and further does not make use of the
3769standard peripheral library. We have rewritten a polling-based solution using
3770the peripheral library.
3771As with all STM32 devices, the first task is to properly initialize the
3772device including clocks and pins. Our initialization code is illustrated in Listing 9.1.
3773The write transaction implementation is the simplest of the two transaction types with few special cases. This is illustrated in Listing 9.2. This
3774follows Figure 3 from AN2824. Comments of the form EVn (e.g. EV5) refer to
3775states as described in the programmers manual. The code provided does not
3776attempt to recover from I2C interface errors. Indeed, an interrupt handler is
3777required even to detect all possible errors.
3778Revision: 14c8a1e (2016-06-05) 131
3779CHAPTER 9. I2C – WII NUNCHUK
3780The final transaction we consider is the Read Transaction. As noted
3781in AN2824, there are separate cases required for 1 byte, 2 byte, and greater
3782than 2 byte reads. Furthermore, there are some time critical sections of code
3783which must be executed without interruption ! The shared code is illustrated
3784in Listing 9.3 with the 1, 2, and more than 2 byte cases illustrated in Listings
37859.4, 9.5, and 9.6, respectively.
3786132 Revision: 14c8a1e (2016-06-05)
37879.3. STM32 I2C INTERFACE
3788void I2C_LowLevel_Init(I2C_TypeDef* I2Cx, int ClockSpeed , int
3789OwnAddress)
3790{
3791GPIO_InitTypeDef GPIO_InitStructure;
3792I2C_InitTypeDef I2C_InitStructure;
3793// Enable GPIOB clocks
3794RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
3795// Configure I2C clock and GPIO
3796GPIO_StructInit(&GPIO_InitStructure);
3797if (I2Cx == I2C1){
3798/* I2C1 clock enable */
3799RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
3800/* I2C1 SDA and SCL configuration */
3801GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
3802GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
3803GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
3804GPIO_Init(GPIOB , &GPIO_InitStructure);
3805/* I2C1 Reset */
3806RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1 , ENABLE);
3807RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1 , DISABLE);
3808}
3809else { // I2C2 ...}
3810/* Configure I2Cx */
3811I2C_StructInit(&I2C_InitStructure);
3812I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
3813I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
3814I2C_InitStructure.I2C_OwnAddress1 = OwnAddress;
3815I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
3816I2C_InitStructure.I2C_AcknowledgedAddress =
3817I2C_AcknowledgedAddress_7bit;
3818I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
3819I2C_Init(I2Cx, &I2C_InitStructure);
3820I2C_Cmd(I2Cx, ENABLE);
3821}
3822Listing 9.1: Initializing I2C Device
3823Revision: 14c8a1e (2016-06-05) 133
3824CHAPTER 9. I2C – WII NUNCHUK
3825#define Timed(x) Timeout = 0xFFFF; while (x) \
3826{ if (Timeout -- == 0) goto errReturn;}
3827Status I2C_Write(I2C_TypeDef* I2Cx, const uint8_t* buf,
3828uint32_t nbyte , uint8_t SlaveAddress) {
3829__IO uint32_t Timeout = 0;
3830if (nbyte)
3831{
3832Timed(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
3833// Intiate Start Sequence
3834I2C_GenerateSTART(I2Cx, ENABLE);
3835Timed(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
3836// Send Address EV5
3837I2C_Send7bitAddress(I2Cx, SlaveAddress ,
3838I2C_Direction_Transmitter);
3839Timed(!I2C_CheckEvent(I2Cx,
3840I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
3841// EV6 Write first byte EV8_1
3842I2C_SendData(I2Cx, *buf++);
3843while (--nbyte) {
3844// wait on BTF
3845Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF));
3846I2C_SendData(I2Cx, *buf++);
3847}
3848Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF));
3849I2C_GenerateSTOP(I2Cx, ENABLE);
3850Timed(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF));
3851}
3852return Success;
3853errReturn:
3854return Error;
3855}
3856Listing 9.2: I2C Write Transaction
3857134 Revision: 14c8a1e (2016-06-05)
38589.3. STM32 I2C INTERFACE
3859Status I2C_Read(I2C_TypeDef* I2Cx, uint8_t *buf,
3860uint32_t nbyte , uint8_t SlaveAddress) {
3861__IO uint32_t Timeout = 0;
3862if (!nbyte)
3863return Success;
3864// Wait for idle I2C interface
3865Timed(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
3866// Enable Acknowledgment , clear POS flag
3867I2C_AcknowledgeConfig(I2Cx, ENABLE);
3868I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
3869// Intiate Start Sequence (wait for EV5)
3870I2C_GenerateSTART(I2Cx, ENABLE);
3871Timed(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
3872// Send Address
3873I2C_Send7bitAddress(I2Cx, SlaveAddress , I2C_Direction_Receiver);
3874// EV6
3875Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR));
3876if (nbyte == 1) { /* read 1 byte */ ... }
3877else if (nbyte == 2) { /* read 2 bytes */ ... }
3878else { /* read 3 or more bytes */ ... }
3879// Wait for stop
3880Timed(I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF));
3881return Success;
3882errReturn:
3883return Error;
3884}
3885Listing 9.3: I2C Read Transaction
3886Revision: 14c8a1e (2016-06-05) 135
3887CHAPTER 9. I2C – WII NUNCHUK
3888if (nbyte == 1) {
3889// Clear Ack bit
3890I2C_AcknowledgeConfig(I2Cx, DISABLE);
3891// EV6_1 -- must be atomic -- Clear ADDR, generate STOP
3892__disable_irq();
3893(void) I2Cx->SR2;
3894I2C_GenerateSTOP(I2Cx,ENABLE);
3895__enable_irq();
3896// Receive data EV7
3897Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE));
3898*buf++ = I2C_ReceiveData(I2Cx);
3899}
3900Listing 9.4: I2C Read 1 Byte
3901else if (nbyte == 2) {
3902// Set POS flag
3903I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Next);
3904// EV6_1 -- must be atomic and in this order
3905__disable_irq();
3906(void) I2Cx->SR2; // Clear ADDR flag
3907I2C_AcknowledgeConfig(I2Cx, DISABLE); // Clear Ack bit
3908__enable_irq();
3909// EV7_3 -- Wait for BTF, program stop, read data twice
3910Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF));
3911__disable_irq();
3912I2C_GenerateSTOP(I2Cx,ENABLE);
3913*buf++ = I2Cx->DR;
3914__enable_irq();
3915*buf++ = I2Cx->DR;
3916}
3917Listing 9.5: I2C Read 2 Bytes
3918136 Revision: 14c8a1e (2016-06-05)
39199.3. STM32 I2C INTERFACE
3920else {
3921(void) I2Cx->SR2; // Clear ADDR flag
3922while (nbyte -- != 3)
3923{
3924// EV7 -- cannot guarantee 1 transfer completion time,
3925// wait for BTF instead of RXNE
3926Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF));
3927*buf++ = I2C_ReceiveData(I2Cx);
3928}
3929Timed(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF));
3930// EV7_2 -- Figure 1 has an error , doesn't read N-2 !
3931I2C_AcknowledgeConfig(I2Cx, DISABLE); // clear ack bit
3932__disable_irq();
3933*buf++ = I2C_ReceiveData(I2Cx); // receive byte N-2
3934I2C_GenerateSTOP(I2Cx,ENABLE); // program stop
3935__enable_irq();
3936*buf++ = I2C_ReceiveData(I2Cx); // receive byte N-1
3937// wait for byte N
3938Timed(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));
3939*buf++ = I2C_ReceiveData(I2Cx);
3940nbyte = 0;
3941}
3942Listing 9.6: I2C Read 3 or More Bytes
3943Revision: 14c8a1e (2016-06-05) 137
3944
3945Chapter 10
3946Timers
3947Micro-controllers, such as the STM32 utilize hardware timers to generate signals of various frequencies, generate pulse-width-modulated (PWM)
3948outputs, measure input pulses, and trigger events at known frequencies or
3949delays. The STM32 parts have several different types of timer peripherals
3950which vary in their configurability. The simplest timers (TIM6 and TIM7)
3951are primarily limited to generating signals of a known frequency or pulses of
3952fixed width. While more sophisticated timers add additional hardware to utilize such a generated frequency to independently generate signals with specific
3953pulse widths or measure such signals. In this chapter we show how timers can
3954be used to control the intensity of the ST7735 backlight (by modulating its
3955enable signal) and to control common hobby servos.
3956An example of a basic timer is illustrated in Figure 10.1. This timer has
3957four components – a controller, a prescaler (PSC), an “auto-reload” register
3958(ARR) and a counter (CNT). The function of the prescaler is to divide a
3959reference clock to lower frequency. The STM32 timers have 16-bit prescaler
3960registers and can divide the reference clock by any value 1..65535. For example,
3961the 24Mhz system clock of the STM32 VL Discovery could be used to generate
3962a 1 Mhz count frequency with a prescaler of 23 (0..23 == 24 values). The
3963counter register can be configured to count up, down, or up/down and to be
3964reloaded from the auto reload register whenever it wraps around (an “update
3965event”) or to stop when it wraps around. The basic timer generates an output
3966event (TGRO) which can be configured to occur on an update event or when
3967the counter is enabled (for example on a GPIO input).
3968To understand the three counter modes consider Figure 10.2. In these
3969examples, we assume a prescaler of 1 (counter clock is half the internal clock),
3970and a auto reload value of 3. Notice that in “Up” mode, the counter increments
3971Revision: 14c8a1e (2016-06-05) 139
3972CHAPTER 10. TIMERS
3973Trigger
3974Controller
3975TRGO TIMxCLK
3976(RCC)
3977PSC
3978Prescaler
3979ARR
3980Auto Reload
3981CNT
3982Counter
3983CK_PSK
3984CK_INT
3985CK_CNT
3986Figure 10.1: Basic Timer
3987from 0 to 3 (ARR) and then is reset to 0. When the reset occurs, an “update
3988event” is generated. This update event may be tied to TRGO, or in more
3989complex timers with capture/compare channels it may have additional effects
3990(described below). Similarly, in “Down” mode, the counter decrements from 3
3991to 0 and then is reset to 3 (ARR). In Down mode, an update “event” (UEV)
3992is generated when the counter is reset to ARR. Finally, in Up/Down mode,
3993the counter increments to ARR, then decrements to 0, and repeats. A UEV
3994is generated before each reversal with the effect that the period in Up/Down
3995mode is one shorter than in either Up or Down mode.
3996Many timers extend this basic module with the addition of counter
3997channels such as the one illustrated in Figure 10.3. The “x” refers to the
3998channel number – frequently, timers support multiple channels. With this
3999modest additional hardware, an output can be generated whenever the count
4000register reaches a specific value or the counter register can be captured when
4001a specific input event occurs (possibly a prescaled input clock).
4002An important use of counter channels is the generation of precisely
4003timed pulses. There are two variations of this use – “one-pulse” pulses, in
4004which a single pulse is generated, and pulse width modulation, in which a
4005140 Revision: 14c8a1e (2016-06-05)
4006CNT 0 1 2 3 0 1 2 3 0
4007UEV
4008CNT 3 2 1 0 3 2 1 0 3
4009UEV
4010CNT 2 3 2 1 0 1 2 3 2
4011UEV
4012CK CNT
4013CK INT
4014Up
4015Down
4016Up/Down
4017Figure 10.2: Counter Modes (ARR=3, PSC=1)
4018series of pulses is generated with the counter UEV period. The pulse width is
4019controlled by the Capture/Compare Register (CCR). For example, the channel
4020output (OCxREF) may tied to whether the CNT register is greater (or less)
4021than the Compare register. In Figure 10.4 we illustrate the use of two channels
4022for one-pulse and PWM outputs. Here we assume that the ARR is 7 and the
4023CCR is 3. In PWM mode, ARR controls the period, and CCR controls the
4024pulse width (and hence the duty cycle). In one-pulse mode, the pulse begins
4025CCR cycles after an initial trigger event, and has a width of ARR-CRR. It
4026is possible to use multiple channels to create a set of synchronized, pulses
4027beginning at precise delays from each other.
4028A timer channel may also be used to measure pulse widths – in effect
4029decoding pwm signals. There are many other configuration options for the
4030STM32 timers including mechanisms to synchronize multiple timers both to
4031each other and to external signals.
4032In the remainder of this chapter we consider two timer applications including PWM output (Section 10.1), input pulse measurement (Section 10.2).
4033In Chapter 13 we show how to use a timer to control DMA transfers for an
4034audio player and in Chapter 14 we use a timer to sample and analog input at
4035regular intervals.
4036Revision: 14c8a1e (2016-06-05) 141
4037CHAPTER 10. TIMERS
4038CNT
4039Counter
4040Capture/Compare
4041Register x
4042external Prescaler OCxREF
4043evant
4044Figure 10.3: Timer Channel
4045OCxREF
4046OCyREF
4047CNT 7 0 1 2 3 4 5 6 7 0 1 2 3
4048One-Pulse
4049PWM
4050Figure 10.4: Pulse Width Modulation (PWM)
405110.1 PWM Output
4052In this section we consider two examples utilizing pulse-width-modulated
4053output – a backlight control for the 7735 LCD and a hobby servo control.
40547735 Backlight
4055The 7735 backlight consists of a number of LEDs which are turned on
4056by pulling the 7735 backlight control pin (PA1) low and off by pulling it high.
4057It is possible to “dim” LEDs by applying a PWM signal which modulates
4058their duty cycle. In this section, we show how to configure a timer to allow
4059the intensity of the 7735 backlight to be modified under program control. The
4060library code to configure timers is in stm32f10x_tim.[ch].
4061By consulting the STM32 VL Discovery User Manual [14] we find that
4062PA1 is “conveniently” associated with TIM2_CH2 – that is, channel 2 of timer
4063142 Revision: 14c8a1e (2016-06-05)
406410.1. PWM OUTPUT
4065TIM2 can drive the pin. 1
4066TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
4067TIM_OCInitTypeDef TIM_OCInitStructure;
4068// enable timer clock
4069RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
4070// configure timer
4071// PWM frequency = 100 hz with 24,000,000 hz system clock
4072// 24,000,000/240 = 100,000
4073// 100,000/1000 = 100
4074TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
4075TIM_TimeBaseStructure.TIM_Prescaler
4076= SystemCoreClock/100000 - 1; // 0..239
4077TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 0..999
4078TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
4079TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
4080// PWM1 Mode configuration: Channel2
4081// Edge-aligned; not single pulse mode
4082TIM_OCStructInit(&TIM_OCInitStructure);
4083TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
4084TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
4085TIM_OC2Init(TIM2, &TIM_OCInitStructure);
4086// Enable Timer
4087TIM_Cmd(TIM2, ENABLE);
4088Listing 10.1: Timer Configuration for PWM
4089Listing 10.1 illustrates the steps necessary to configure timer 2 to operate with a period of 100 Hz and 1000 steps of the timer clock. This allows
4090us to define a pulse width output from 0-100% with a precision of 0.1%. The
4091major configuration parameters are the prescaler, period, and count mode (up
4092!). The output channel is configured in PWM (repetitive) mode (there are
4093actually two variations – edge-aligned and center-aligned – here we choose
4094edge-aligned. Not shown is the code to reconfigure PA1 for “alternative func1One of the hardest optimization problems when designing a micro-controller based
4095system is to choose pins in a manner that enables access to all the necessary hardware
4096peripherals. Careful advance planning can save a lot of grief !
4097Revision: 14c8a1e (2016-06-05) 143
4098CHAPTER 10. TIMERS
4099tion push-pull” mode. Note, the when configuring the output channel, the
4100“number” is embedded in the name of the call – in this case TIM_OC2Init
4101initializes channel 2, similarly TIM_OC4Init initializes channel 4. The pulsewidth pw (0..999) can be set with the following command. (Again, the channel
4102number is embedded in the procedure name – TIM_SetCompare2.)
4103TIM_SetCompare2(TIM2, pw);
4104Exercise 10.1 Ramping LED
4105Write an application that displays a single color on the 7735 LCD and
4106repeatedly “ramps” the backlight up and down (fades in and out) at a rate of
41072 ms per step (2 seconds to fade in, 2 seconds to fade out).
4108Figure 10.5: Typical Hobby Servo
4109Exercise 10.2 Hobby Servo Control
4110The servos commonly used in radio controlled vehicles are easily controlled using the STM32 timers. A typical servo is illustrated in Figure 10.5.
4111The servo consists of a geared motor with a moving lever arm (or wheel) and
4112a simple electronic control used to set the lever angle. These servos typically
4113have three connections – power (4-6 volts) (usually the middle wire), ground
4114(brown or black), and a control signal. Servos are available in a wide range
4115of sizes from a few grams to more than 20 grams depending upon the power
4116requirements. However, the all work in a similar fashion.
4117The control protocol is very simple – every 20ms a pulse is sent to the
4118servo. The width of the pulse determines the servo position. This is illustrated
4119in Figure 10.6. A 1.5ms pulse corresponds to “center” (45◦
4120), 1ms corresponds
4121144 Revision: 14c8a1e (2016-06-05)
412210.1. PWM OUTPUT
4123to “full left” (0
4124◦
4125) and 2ms corresponds to “full right” (90◦
4126). Pulses between
41271ms and 2ms can be used to set any angle between 0
4128◦ and 90◦
4129.
4130Servos have a particularly simple electrical configuration – ground, power,
4131and signal. While textemmost servos use the center of three connectors for
4132power, it is important to check this for any servo you use. There are many
4133references on the web. The signal wire can be connected directly to the timer
4134output channel pin. The power signal should be 5V or less.
4135Configure a timer to control a pair of hobby servos using two timer
4136channels (pins PB8 and PB9 are good choices !). Use the Nunchuk joystick
4137to control their position. For this exercise it is OK to use USB power if the
4138servos are quite small and you use a flyback diode to protect the discovery
4139board. However, it would be better to use a separate power supply (a 3-cell
4140battery pack would be fine). Just remember to connect the battery ground to
4141the STM32 ground.
41421.0ms
41431.5ms
41442ms
414520ms
41460
4147◦
414845◦
414990◦
4150Figure 10.6: Servo Control Pulses
4151Revision: 14c8a1e (2016-06-05) 145
4152CHAPTER 10. TIMERS
415310.2 Input Capture
4154In generating PWM output signals we use the “compare” feature of the
4155capture/compare register. In this section we discuss “capture”. The capture
4156registers provide a mechanism to monitor an input pin and, based upon a programmed edge, capture the current value of the corresponding timer counter.
4157The main purpose of the capture registers is to enable measuring, relative to
4158a time reference, when events happen. It is possible to tie multiple capture
4159registers to a single input, capturing the times of both rising and falling edges,
4160to measure pulse widths. It is possible to use input events to reset the timer
4161counter, to use input values to enable a timer counter, and to synchronize
4162multiple timers. In this section we will show how input capture can be used
4163in conjunction with PWM output to control commonly available ultrasonic
4164ranging devices such as that illustrated in Figure 10.7.
4165Figure 10.7: Ultrasonic Sensor
4166The HC-SR04 ultrasonic ranging module is capable of 3mm resolution
4167in the range 20-500mm. It requires a 5V supply. In operation, the module
4168is triggered by delivering it a 10µs pulse. Some time later an “echo” pulse is
4169generated whose length is proportional to the measured distance as illustrated
4170in Figure 10.8 and defined by the following formula where pw is the echo pulse.
4171distance = pw ∗
4172cm
417358µs
4174If the distance is less than 20mm or greater than 500 mm, a 38ms pulse is
4175returned. Internally, the ultrasonic controller circuit generates an 8 pulse 40
4176kHz signal which drives the transducer.
4177In the remainder of this section we will describe to use two timers – one
4178for output and one for input to control such an ultrasonic ranger completely
4179autonomously. Meaning that after setting up the timers, an application need
4180146 Revision: 14c8a1e (2016-06-05)
418110.2. INPUT CAPTURE
418210µs
4183Trigger
4184Echo
4185150 − 2500µs
4186Figure 10.8: Ultrasonic Sensor Protocol
4187only read a capture register to learn the most recent distance measurement.
4188With the addition of interrupts (see Chapter 11, it is possible to notify the
4189application whenever a new measurement is available. Here we use a continuous measurement process. Note that when using multiple ranger modules,
4190it is advisable that they not be active continuously. With a small amount of
4191external hardware and a few GPIO pins, it is possible to multiplex the timing
4192hardware to control an arbitrary number of ranging modules with a just two
4193timers.
4194As mentioned, we use two timers – one to generate the trigger pulse and
4195one to measure the echo pulse. We discussed how to generate a pwm output
4196in Section 10.1 and now we leave it as an exercise to the reader to utilize timer
4197TIM4 and Pin PB9 to generate trigger pulses at a 10Hz rate.
4198To measure the echo pulse, we will use timer TIM1 connected to PA8.
4199The architecture of the various timers is quite complex. We exploit two key
4200concepts:
42011. Pairs of capture registers (1,2) and (3,4) can be “coupled” to enable
4202capture at opposite edges of a single input.
42032. Timer counters can be configured as slaves to capture inputs 1 and 2,
4204for example, to reset the counter on a specified input event.
4205Revision: 14c8a1e (2016-06-05) 147
4206CHAPTER 10. TIMERS
4207The details of setting up capture registers can be quite complex, in the
4208following, we refer to the simplified model illustrated in Figure 10.9. In this
4209figure two capture registers are illustrated along with the functional path from
4210inputs (t1 and t2). The inputs are (optionally) filtered and signals generated
4211on rising and falling edges. Any of the four edge signals can be selected and,
4212after (optionally) dividing, used to trigger the capture event. Thus, capture
4213register (channel) 1 or 2 can be loaded on rising or falling edges on either input
4214t1 or t2. In addition two signals TI1FP1 and TI2FP2 can be used to control
4215the timer counter, for example, causing it to be reset on the select input edge.
4216filter t1 edge
4217detector
4218TI1F Rising
4219TI1F Falling
4220TI1FP1
4221filter t2 edge
4222detector
4223TI2F Rising
4224TI2F Falling
4225TI2FP2
4226÷ capture 1
4227÷ capture 2
4228Figure 10.9: Capture Circuit
4229To configure a TIM1 to measure the ultrasonic echo pulse we must do
4230the following (in addition to pin and configuration and clock distribution !):
42311. Configure TIM1 prescaler and period.
42322. Configure channel 1 to latch the timer on a rising input on t1.
42333. Configure channel 2 to latch the timer on a falling input on t2.
42344. Configure TIM1 in slave mode to reset on the capture 1 event.
4235Task (1) is identical to that for the trigger generation; although you
4236may wish to use a longer period. Configuration for channel 1 follows:
4237TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
4238TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
4239148 Revision: 14c8a1e (2016-06-05)
424010.2. INPUT CAPTURE
4241TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
4242TIM_ICInitStructure.TIM_ICPrescaler = 0;
4243TIM_ICInitStructure.TIM_ICFilter = 0;
4244TIM_ICInit(TIM1, &TIM_ICInitStructure);
4245We require no filtering or prescaling (dividing) of the input signal. We
4246want to capture on rising edges, using the T1 input. Configuring channel 2
4247has the following differences:
4248TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
4249TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
4250Finally we must configure the timer slave mode with TI1FP1 as reset
4251signal:
4252TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
4253TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
4254TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
4255Exercise 10.3 Ultrasonic Sensor
4256Write an application which tracks, by printing over the USART, the
4257distance, in centimeters, measured by an ultrasonic sensor every 100ms.
4258Revision: 14c8a1e (2016-06-05) 149
4259
4260Chapter 11
4261Interrupts
4262Interrupts are a fundamental hardware mechanism to enable peripherals
4263to notify software of critical events. 1 For example, we may wish to generate
4264an analog output signal at precise intervals in order to play an audio file. One
4265way to achieve this is to configure a timer to generate interrupts at precise
4266intervals. When the configured interrupt occurs, the processor switches execution from the application program to a special interrupt handler which can
4267then “service” the interrupt event by transferring a data sample to the analog output. Once the interrupt handler has completed its task, the processor
4268resumes execution of the application program. Interrupts are also important
4269in communication – for example, notifying the processor when a character
4270has arrived at a UART. In this chapter we discuss how interrupts work in the
4271STM32 (more generally in the Cortex-M3) micro-controller family and present
4272several concrete examples to demonstrate their use.
4273We’ve actually been using interrupts throughout this book to implement
4274our delay function as illustrated by the code fragment in Listing 11.1. Within
4275main, we configure the Cortex-M3 “SysTick” to trigger an interrupt every
4276milli-second. Furthermore, we define an interrupt handler,
4277SysTick_Handler, to be executed when the SysTick interrupt occurs. This
4278handler decrements the variable TimingDelay and then returns control to the
4279application program. The application program may wait for a precise period
4280by calling the procedure Delay with an interval and then waiting for this
4281interval to elapse (literally be counted down by the handler).
4282Interrupts may be triggered by many possible events including the sys1
4283Interrupts are a special case of exceptions, which may include internal events such as
4284access violations.
4285Revision: 14c8a1e (2016-06-05) 151
4286CHAPTER 11. INTERRUPTS
4287main(){
4288...
4289if (SysTick_Config(SystemCoreClock / 1000))
4290while (1);
4291...
4292}
4293static __IO uint32_t TimingDelay;
4294void Delay(uint32_t nTime){
4295TimingDelay = nTime;
4296while(TimingDelay != 0);
4297}
4298void SysTick_Handler(void){
4299if (TimingDelay != 0x00)
4300TimingDelay --;
4301}
4302Listing 11.1: SysTick Interrupt
4303tem timer, memory access faults, external resets, and by all of the various
4304peripherals provided on the STM32 processor. It is easiest to view each possible interrupt source as a separate signal that is monitored by the processor
4305core during program execution. If the core detects a valid interrupt signal and
4306is configured to accept interrupt requests, it reacts by saving the state of the
4307currently executing program on the program stack and executing a handler
4308(sometimes called an interrupt service routine) corresponding to the accepted
4309interrupt. When the handler terminates, the saved program state is restored
4310and normal program execution is resumed.
4311The concept of interrupts, and more generally, exceptions can be relatively difficult to grasp. Recall that programs in a language such as C are
4312compiled into assembly code (the symbolic representation of machine instructions) from which machine code is generated. In the STM32, this machine
4313code is copied into flash memory when programming the device (we do this
4314through gdb) and executed when the processor is reset. The basic execution
4315model is:
4316while (1){
4317inst = *pc++;
4318eval(inst);
4319}
4320152 Revision: 14c8a1e (2016-06-0
4321The processor can be viewed as a machine code interpreter which reads
4322instructions from memory and evaluates them. The program counter, pc,
4323holds the address of the next instruction to execute. Consider the following
4324’C’ statement from the SysTick handler:
4325TimingDelay --;
4326The compiler translates this statement into three assembly language
4327steps which load (ldr) the value of TimingDelay, decrement the value (subs)
4328and write the decremented value back (str). This listing includes the 6 bytes
4329of machine code (0x68a1, 0x3a01, 0x601a) generated by the assembler. While
4330outside the scope of this book, it’s important to realize that assembly language
4331is fundamentally a human readable form of the binary machine code. The
4332process of linking assigns these instructions to fixed memory addresses.
4333681a ldr r2, [r3, #0]
43343a01 subs r2, #1
4335601a str r2, [r3, #0]
4336Implementing interrupts in the processor requires extending this model
4337slightly:
4338while (1) {
4339if (interrupt_pending()) {
4340save_state();
4341pc = find_handler();
4342} else {
4343inst = *pc++;
4344eval(inst);
4345}
4346}
4347On every “cycle” a test is made to determine if an interrupt is pending
4348– this literally corresponds to checking if a hardware input is 1 or 0. If so, the
4349current program state (including the program counter) is saved, an interrupt
4350handler address is found, and execution continues with the handler. When the
4351handler completes execution, the preempted state is restored and execution
4352of the application continues from the point of interruption. Note for example, that interrupts occur at machine instruction boundaries and not a “C”
4353statement boundaries. As we shall see, understanding this is fundamental to
4354writing reliable interrupt code.
4355In the case of the SysTick notice that the handler only modifies the
4356shared data (TimingDelay) when it is non-zero and the application only modifies the shared data when it is zero. Guarantees like this are important because
4357Revision: 14c8a1e (2016-06-05) 153
4358CHAPTER 11. INTERRUPTS
4359interrupt handlers cause application code to be suspended at unpredictable
4360locations and therefore the data structures that are used to communicate between handlers and application code must be very carefully constructed to
4361ensure that they work correctly. Consider the chaos that might result if an
4362application program and interrupt handler both access a linked list – interrupt
4363handlers had better not access links that are in the process of being moved
4364by the application code. This kind of conflict is called a “race condition.” We
4365present an example of using an interrupt handler to service a UART where the
4366application and handler share two data queues – the code is carefully crafted
4367to avoid potential data races.
4368The SysTick example demonstrates some typical interactions between
4369interrupt handlers and applications. The handler executes very briefly – just
4370a few machine instructions – in order to update some information shared with
4371the application program. To achieve reliability interrupt handlers must satisfy
4372three properties:
43731. They must execute briefly.
43742. Their execution time must be predictable (e.g. they must never wait)
43753. Their use of “shared data” must be carefully managed.
4376This model is of course an over-simplification. However, for the subsequent discussion of interrupts, it is a sufficient model. Key questions that
4377we will address are – how do we enable peripherals to generate pending interrupts, how do we ensure that our handlers are executed, and how do we write
4378reliable handlers ? Not illustrated in this model is the concept of interrupt
4379priority – when more than two interrupts are requested, how is the selection
4380made. Neither is interrupt preemption addressed – if an interrupt handler is
4381executing, is it possible for other handlers to be called recursively ?
4382The remainder of this chapter is organized as follows. We begin with a
4383discussion of the Cortex-M3 interrupt (exception) model including the various
4384exception types, stacks, and privileges. We then discuss the interrupt vector
4385table – the mechanism by which the Cortex-M3 core associates handlers with
4386specific interrupt causes, and the Nested Vector Interrupt Controller (NVIC)
4387which the Cortex-M3 uses to select among competing interrupt requests.
4388154 Revision: 14c8a1e (2016-06-05)
438911.1. CORTEX-M3 EXCEPTION MODEL
439011.1 Cortex-M3 Exception Model
4391The Cortex-M3 processors support two modes of operation, Thread
4392mode and Handler mode. Thread mode is entered on Reset, and can be
4393entered through an exception return. Handler mode is entered as a result
4394of an exception being taken. The Cortex-M3 processors support two distinct
4395stack pointers – as illustrated in Figure 11.1. Out of reset, all code utilizes
4396the main stack; however, the processor can be configured so that application
4397code utilizes a separate “process stack.” Whenever the processor invokes an
4398exception, the handler executes using the main stack, and when execution
4399returns from an exception, the processor resumes using the stack used prior to
4400the exception. When invoking an exception, the state of the currently executing code must be saved on the main stack to be restored when the exception
4401handler terminates. With single threaded applications, such as the examples
4402we have considered thus far, there is no significant advantage to utilizing separate stacks; however, when using an operating system supporting threads, it
4403is generally considered desirable to use a separate stack for exception handling
4404and execution within the OS kernel.
4405Low registers
4406
4407
4408
4409r0
4410r1
4411r2
4412r3
4413r4
4414r5
4415r6
4416r7
4417High registers
4418
4419
4420
4421r8
4422r9
4423r10
4424r11
4425r12
4426r13 (SP) PSP MSP
4427r14 (LR)
4428r15 (PC)
4429Program Status Register xPSR
4430Figure 11.1: Processor Register Set
4431State saving and restoring is a collaboration between the processor hardware and the exception handlers. The Cortex-M3 architecture assumes that
4432the exception handler code will obey the Arm Architecture Procedure Call
4433Revision: 14c8a1e (2016-06-05) 155
4434CHAPTER 11. INTERRUPTS
4435Standard [2] which dictates that all procedures (exception handlers included)
4436save and restore specific registers if they are modified. The Cortex-M3 exception hardware takes responsibility for saving any other registers. Specifically,
4437when an exception is taken, the processor pushes eight registers – xPSR, PC,
4438LR, r12, r3, r2, r1, and r0 – onto the main stack as illustrated in Figure 11.1.
4439When returning from an exception handler, the processor automatically pops
4440these off the main stack. Upon entry to the exception handler, the link register
4441(LR) contains a special value which controls the exception return.
4442Old SP → <previous>
4443xPSR
4444PC
4445LR
4446r12
4447r3
4448r2
4449r1
4450SP → r0
4451Figure 11.2: Main Stack Contents After Preemption
4452The Cortex-M3 processor supports multiple exception priorities. Even
4453if an exception handler is currently executing, a higher-priority exception can
4454be invoked preempting the current handler (priorities are defined as integers
4455with smaller integers having higher priorities). It this case, the state of the
4456preempted handler will be pushed on the main stack prior to executing the
4457new handler. The highest priority exception is Reset (-3), which can preempt
4458all others. The priority of most exceptions can be set under program control.
4459The Cortex-M3 processor core locates the interrupt (exception) handlers
4460through a vector table. Each entry in the table consists of the address of
4461an interrupt handler. The table is indexed by the unique number of each
4462interrupt source. The format of the STM32 vector table is defined both by
4463the Cortex-M3 reference manual [1] and by the appropriate STM32 reference
4464manual [21, 20]. A fragment of this table for the STM32 F100xx devices is
4465illustrated in Table 11.1.
4466The first 16 entries (through SysTick_Handler) are defined by the CortexM3 specification and the remainder are processor specific. The first entry
4467in the table is not the address of an interrupt handler, but rather the address
4468of the initial stack. At reset, the core loads the stack pointer from memory
4469location 0x0000_0000 and begins execution at the the Reset_Handler loca156 Revision: 14c8a1e (2016-06-05)
447011.1. CORTEX-M3 EXCEPTION MODEL
4471Name Description Address
4472- Initial Stack Pointer 0x0000_0000
4473Reset_Handler Executed at reset 0x0000_0004
4474NMI_Handler Non-maskable interrupt 0x0000_0008
4475· · ·
4476SysTick_Handler System Tick Timer 0x0000_0010
4477· · ·
4478EXTI0_ISRHandler External interrupt line 0 0x0000_0058
4479· · ·
4480TIM3_ISRHandler Timer 3 interrupt 0x0000_00B4
4481· · ·
4482USART1_ISRHandler USART1 global interrupt 0x0000_00D4
4483Table 11.1: STM32 F100xx Interrupt Vector Table
4484tion stored at memory location 0x0000_0004. This fragment also includes the
4485entries for TIM3, USART1 and EXTI0, which we will be considering in this
4486chapter.
4487The Cortex-M3 specifies that the vector table is located beginning at
4488memory location 0x0000_0000. There are a couple of important exceptions.
4489The STM32, when booting from flash, “aliases” the flash memory, which starts
4490at location 0x0800_0000 to 0x0000_0000 – thus memory reads from location
44910x0000_0000 actually return the value stored at 0x0800_0000 (this and other
4492aliases are described in in Section 2.4 of [20]). It is also possible to move the
4493location of the active vector table at runtime (see [19]) – an important feature
4494for supporting fixed bootloaders which may place application vector tables
4495in other locations. The interrupt vector table is defined in the startup code
4496and its location defined by the linker script both of which are described in
4497Chapter 3.
4498The startup code discussed in Chapter 3 is designed to simplify modification of the vector table. Every interrupt vector is provided with an initial
4499“weak” definition. To override this definition, it is sufficient to define a procedure with the correct name. For example, we previously defined a system
4500timer handler:
4501void SysTick_Handler(void){
4502if (TimingDelay != 0x00)
4503TimingDelay --;
4504}
4505Revision: 14c8a1e (2016-06-05) 157
4506CHAPTER 11. INTERRUPTS
4507Reset_Handler DMA1_Channel6_IRQHandler
4508NMI_Handler DMA1_Channel7_IRQHandler
4509HardFault_Handler ADC1_IRQHandler
4510MemManage_Handler EXTI9_5_IRQHandler
4511BusFault_Handler TIM1_BRK_TIM15_IRQHandler
4512UsageFault_Handler TIM1_UP_TIM16_IRQHandler
4513SVC_Handler TIM1_TRG_COM_TIM17_IRQHandler
4514DebugMon_Handler TIM1_CC_IRQHandler
4515PendSV_Handler TIM2_IRQHandler
4516SysTick_Handler TIM3_IRQHandler
4517WWDG_IRQHandler TIM4_IRQHandler
4518PVD_IRQHandler I2C1_EV_IRQHandler
4519TAMPER_IRQHandler I2C1_ER_IRQHandler
4520RTC_IRQHandler I2C2_EV_IRQHandler
4521FLASH_IRQHandler I2C2_ER_IRQHandler
4522RCC_IRQHandler SPI1_IRQHandler
4523EXTI0_IRQHandler SPI2_IRQHandler
4524EXTI1_IRQHandler USART1_IRQHandler
4525EXTI2_IRQHandler USART2_IRQHandler
4526EXTI3_IRQHandler USART3_IRQHandler
4527EXTI4_IRQHandler EXTI15_10_IRQHandler
4528DMA1_Channel1_IRQHandler RTCAlarm_IRQHandler
4529DMA1_Channel2_IRQHandler CEC_IRQHandler
4530DMA1_Channel3_IRQHandler TIM6_DAC_IRQHandler
4531DMA1_Channel4_IRQHandler TIM7_IRQHandler
4532DMA1_Channel5_IRQHandler
4533Figure 11.3: Vector Names Defined for the Medium Density Value Line Parts
4534Similarly, we will define a handler for USART1 as
4535void USART1_IRQHandler(void) {
4536// Check interrupt cause
4537...
4538// Clear interrupt cause
4539}
4540Notice, that in contrast with the SysTick handler, most handlers must,
4541at the very least, determine the cause of the interrupt – with the USART
4542this might be an empty transmit buffer or a full receive buffer – and clear
4543the interrupt cause. Determining the cause is generally performed by reading
4544a peripheral specific status register. Clearing the interrupt is accomplished
4545by performing a necessary action (e.g. reading a data register) or directly
4546resetting the corresponding status bit.
4547158 Revision: 14c8a1e (2016-06-05)
454811.2. ENABLING INTERRUPTS AND SETTING THEIR PRIORITY
4549The required handler names defined in the startup code are shown in
4550Figure 11.1. Note that different members of the STM32 family support different peripherals and hence have varying sets of handler names. Furthermore,
4551these names are defined in the startup code and not by library functions. If
4552in doubt, you must look at the startup sources ! Also, be careful of typos in
4553vector names which may be challenging to diagnose.
455411.2 Enabling Interrupts and Setting Their
4555Priority
4556The Cortex-M3 core defines a sophisticated priority mechanism that
4557allows interrupt sources to be assigned both a priority and a sub-priority. At
4558a given priority level, two interrupt sources are serviced in order of their subpriority (lower number takes precedence). If an interrupt handler is active
4559and another interrupt arrives with a lower priority number, the the active
4560handler will be preempted. The Cortex-M3 defines up to 8 priority level bits
4561that may be split among the priority and sub-priority fields. The STM32
4562processor implements only 4 of these bits. Throughout this book we utilize a
4563configuration where 0 bits are allocated to priority and 4 bits are allocated to
4564sub-priority. In other words, we choose not to enable interrupt preemption.
4565The interrupt priority mechanism is managed through the NVIC (Nested
4566Vectored Interrupt Controller) that is a standard peripheral for all CortexM3 based processors. The NVIC provides the following functions for every
4567interrupt source:
4568• Priority and sub-priority configuration.
4569• Enable (disable) interrupt.
4570• Set/Clear interrupt pending bit.
457111.3 NVIC Configuration
4572The STM32 NVIC supports 16 distinct priority and sub-priority levels
4573supported by 4 bits which are partitioned between these two functions. Interrupts with different priorities can preempt each other (lower number priorities
4574have precedence) while sub-priorities within a single priority only affect the
4575choice of interrupt taken when two or more are pending. For the examples in
4576Revision: 14c8a1e (2016-06-05) 159
4577CHAPTER 11. INTERRUPTS
4578this chapter we use 0 bits for priority. In Chapter 16 we will discuss FreeRTOS, a real-time operating system, that requires using 4 bits for priority.
4579#include <misc.h>
4580/*
4581* NVIC_PriorityGroup_0 0 bits priority , 4 bits subgroup
4582* NVIC_PriorityGroup_1 1 bits priority , 3 bits subgroup
4583* NVIC_PriorityGroup_2 2 bits priority , 2 bits subgroup
4584* NVIC_PriorityGroup_3 3 bits priority , 1 bits subgroup
4585* NVIC_PriorityGroup_4 4 bits priority , 0 bits subgroup
4586*/
4587NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
4588The following code fragment configures and enables the TIM2 interrupt.
4589Note that this should follow any device configuration !!!
4590NVIC_InitTypeDef NVIC_InitStructure;
4591// No StructInit call in API
4592NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
4593NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
4594NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
4595NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
4596NVIC_Init(&NVIC_InitStructure);
4597The IRQChannel number may be device specific. These are defined in
4598stm32f10x.h which you may consult for the correct constant name – do not
4599copy the constant value into your code ! Notice that this header file depends
4600upon device specific definitions – in our make file we define STM32F10X_MD_VL
4601in our compilation flags as discussed in Chapter 3.
460211.4 Example: Timer Interrupts
4603In Section 10.1 we showed how to configure timer TIM2 to control the
4604LCD back light. In this example, we show how to enable the TIM2 interrupt.
4605Since this builds upon work you have seen before, we present a basic outline in
4606Listing 11.2. In addition to configuring the timer, it is necessary to configure
4607the NVIC for the appropriate interrupt vector and to enable the timer to
4608generate interrupts. Timers can generate interrupts on multiple conditions –
4609here we choose to trigger interrupts whenever the counter is updated. Finally,
4610we need a handler which, at a minimum, clears the pending interrupt.
4611160 Revision: 14c8a1e (2016-06-05)
461211.5. EXAMPLE: INTERRUPT DRIVEN SERIAL COMMUNICATIONS
4613Exercise 11.1 Timer Interrupt – Blinking LED
4614Complete the timer interrupt program so that it blinks the green LED
4615(PA9) at a 1hz rate (half-second on/ half-second off).
4616// Configure clocks for GPIOA and TIM2
4617...
4618// Configure NVIC -- see preceding section
4619...
4620// Configure Timer
4621...
4622// Enable Timer Interrupt , enable timer
4623TIM_ITConfig(TIM2, TIM_IT_Update , ENABLE);
4624TIM_Cmd(TIM2, ENABLE);
4625while(1) { /* do nothing */ }
4626}
4627void TIM2_IRQHandler(void)
4628{
4629/* do something */
4630TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
4631}
4632Listing 11.2: Timer Tick Interrupt
463311.5 Example: Interrupt Driven Serial
4634Communications
4635The fundamental weakness of the serial communication code presented
4636in Chapter 5 is that unless the user code is constantly polling the USART
4637and is prepared to receive characters as soon as they arrive, there is a high
4638probability that the (single) receive buffer will overflow and characters will
4639be lost. Ideally, we want a solution that does not require such a high degree
4640of attention from the user code and which also can guarantee that characters
4641are not lost. Similarly, when the user code wishes to transmit a string it must
4642wait for the transmit buffer to empty after each character sent.
4643A partial solution is to create larger transmit and receive buffers in
4644software and utilize an interrupt handler to manage the details of receiving and
4645transmitting characters. The interrupt handler is a user supplied routine that
4646is executed, asynchronously to the user code, whenever the USART transmit
4647Revision: 14c8a1e (2016-06-05) 161
4648CHAPTER 11. INTERRUPTS
4649buffer becomes empty or the USART receive buffer becomes full. This relieves
4650the user program of the burden of monitoring the USART buffers and, by
4651providing additional buffer space, helps decouple the user program from the
4652communication process. It is only a partial solution because once the larger
4653software receive buffer is full, any additional characters received will be lost. A
4654complete solution, described in Section 11.5, utilizes additional USART flow
4655control signals to block communication when no future space exists.
4656As discussed in Chapter 5, polling based implementations of getchar
4657and putchar suffer significant performance issues. In the case of putchar, the
4658application code is slowed to the USART baud rate whenever it attempts to
4659transmit back-to-back characters. The situation for getchar is even more dire
4660– if the application code doesn’t constantly monitor the USART receive data
4661register there is a significant risk of lost data. In this section we show how
4662interrupts in conjunction with software buffers can be used to alleviate, but
4663not eliminate, the problem. A complete solution, as discussed in Section 11.5
4664requires the use of hardware flow control in conjunction with interrupts.
4665In an interrupt-driven USART responsibility for reception and transmission of data is split between the application code and interrupt code. The
4666interrupt code is called whenever configured events occur; for example, when
4667the transmit data register is empty or the receive data register is full. The interrupt code is responsible for removing the interrupt condition. In the case of
4668a full receive data register, the interrupt handler removes the interrupt condition by reading the received data. The application code and interrupt handler
4669communicate through a pair of software buffers implemented as queues as
4670illustrated in Figure 11.4.
4671putchar
4672getchar
4673USART1_IRQHandler
4674TX queue
4675RX queue
4676Figure 11.4: Interrupt Driven USART Software
4677162 Revision: 14c8a1e (2016-06-05)
467811.5. EXAMPLE: INTERRUPT DRIVEN SERIAL COMMUNICATIONS
4679The basic idea is simple. Whenever the application code executes
4680putchar, a character is added to the TX queue and whenever the application
4681code executes getchar, a character is removed from the RX queue. Similarly,
4682whenever the interrupt handler, USART1_IRQHandler, is called, the handler
4683removes the interrupting condition by moving a character from the TX queue
4684to the transmit data register or by moving a character from the receive data
4685register to the RX queue. All of the implementation difficulties arise from
4686handling the edge cases where the two queues are either empty or full.
4687The design decisions for the edge cases differ for the application and
4688interrupt code. The most important requirement for interrupt code is that
4689it may never block. For example, if the receive data register is full and the
4690RX queue is also full, the only way to remove the interrupt condition is to
4691read the receive data register and discard the data. Thus, an interrupt driven
4692USART cannot completely eliminate the lost data problem of the polling based
4693solution – that will come with the addition of flow control. In contrast, the
4694application code may block. For example, if the application executes putchar
4695and the TX queue is full, then it may “poll” to wait for the full condition
4696to be removed (by the interrupt handler). In this case, the application code
4697is again slowed to the transmit rate, but only after the TX queue is filled.
4698An important implementation decision is how large the queues should be to
4699prevent application stalling.
4700Let us assume a queue data structure with two operations
4701struct Queue;
4702struct Queue UART1_TXq , UART1_RXq;
4703int Enqueue(struct Queue *q, uint8_t data);
4704int Dequeue(struct Queue *q, uint8_t *data);
4705The Enqueue operation takes as parameters a queue and a data byte;
4706its function is to add the data to the queue. If the queue is full then Enqueue
4707should return an error (0). Thus, reliable use of the Enqueue operation may
4708require repeated calls. The Dequeue operation is similar but the operation
4709removes a data byte from the queue. As with Enqueue, Dequeue returns an
4710indicator of success and reliable operation may require multiple calls.
4711We further assume that the necessary interrupt hardware is enabled for
4712two conditions – the receive data register is not empty and the transmit data
4713register is empty. The interrupt handler code must then cope with these two
4714possible conditions:
4715Revision: 14c8a1e (2016-06-05) 163
4716CHAPTER 11. INTERRUPTS
4717static int TxPrimed = 0;
4718int RxOverflow = 0;
4719void USART1_IRQHandler(void)
4720{
4721if(USART_GetITStatus(USART1 , USART_IT_RXNE) != RESET)
4722{
4723uint8_t data;
4724// buffer the data (or toss it if there's no room
4725// Flow control will prevent this
4726data = USART_ReceiveData(USART1) & 0xff;
4727if (!Enqueue(&UART1_RXq , data))
4728RxOverflow = 1;
4729}
4730if(USART_GetITStatus(USART1 , USART_IT_TXE) != RESET)
4731{
4732uint8_t data;
4733/* Write one byte to the transmit data register */
4734if (Dequeue(&UART1_TXq , &data)){
4735USART_SendData(USART1 , data);
4736} else {
4737// if we have nothing to send, disable the interrupt
4738// and wait for a kick
4739USART_ITConfig(USART1 , USART_IT_TXE , DISABLE);
4740TxPrimed = 0;
4741}
4742}
4743}
4744Notice that the receive and transmit code both contain the essential
4745elements of the polling implementations of putchar and getchar, they handle
4746corner cases differently. If there is no room in the RX queue, the interrupt
4747handler receives, but discards any data in the receive register. Whenever the
4748interrupt handler discards data, it sets a global variable, RxOverflow to 1; it is
4749up to the application code to monitor this variable and decide how to handle
4750lost data. If the TX queue is empty, the interrupt handler cannot resolve
4751the interrupt condition (since it has nothing to write to the transmit data
4752register), so it disables the USART_IT_TXE condition. The variable TxPrimed
4753is used to communicate to the application (specifically putchar) that the
4754interrupt needs to be re-enabled when data is added to the TX queue.
4755164 Revision: 14c8a1e (2016-06-05)
475611.5. EXAMPLE: INTERRUPT DRIVEN SERIAL COMMUNICATIONS
4757The new implementation for getchar is quite simple (this can be generalized to replace the uart_getc implementation you developed in Exercise 5.2).
4758int getchar(void)
4759{
4760uint8_t data;
4761while (!Dequeue(&UART1_RXq , &data));
4762return data;
4763}
4764The new implementation for putchar requires an extra test to determine
4765if re-enabling the transmit interrupt condition is necessary:
4766int putchar(int c)
4767{
4768while (!Enqueue(&UART1_TXq , c));
4769if (!TxPrimed) {
4770TxPrimed = 1;
4771USART_ITConfig(USART1 , USART_IT_TXE , ENABLE);
4772}
4773}
4774The asynchronous interaction between interrupt handler code and application code can be quite subtle. Notice that we set TxPrimed before reenabling the interrupt. If the order were reversed it would be possible for
4775the newly enabled interrupt handler to empty the transmit queue and clear
4776TxPrimed before the application set TxPrimed, thus losing the signal from
4777the handler to the application code. Admittedly, the USART is sufficiently
4778slow that this scenario is unlikely, but with interrupt code it pays to program
4779defensively.
4780There remain two tasks – implementing the required queue data structure and enabling interrupts.
4781Interrupt-Safe Queues
4782The final piece of our interrupt driven USART code is a queue implementation. The most common approach is to provide a fixed sized circular
4783buffer with separate read and write pointers. This is illustrated in Figure 11.5.
4784There are several key ideas behind a circular buffer. The read pointer
4785“chases” the write pointer around the buffer; thus, the increment functions
4786must wrap around. Furthermore, the write pointer always references an
4787Revision: 14c8a1e (2016-06-05) 165
4788CHAPTER 11. INTERRUPTS
47890
47901
47912
47923
47934
47945
4795pWR
4796N
4797N-1
4798N-2
4799N-3
4800pRD
4801N-4
48026
4803Figure 11.5: Circular Buffer
4804“empty” location. Thus a buffer with N+1 locations can hold at most N
4805data elements. Thus we define the basic data structure as follows:
4806struct Queue {
4807uint16_t pRD, pWR;
4808uint8_t q[QUEUE_SIZE];
4809};
4810static int QueueFull(struct Queue *q)
4811{
4812return (((q->pWR + 1) % QUEUE_SIZE) == q->pRD);
4813}
4814static int QueueEmpty(struct Queue *q)
4815{
4816return (q->pWR == q->pRD);
4817}
4818static int Enqueue(struct Queue *q, uint8_t data)
4819{
4820if (QueueFull(q))
4821return 0;
4822166 Revision: 14c8a1e (2016-06-05)
482311.5. EXAMPLE: INTERRUPT DRIVEN SERIAL COMMUNICATIONS
4824else {
4825q->q[q->pWR] = data;
4826q->pWR = ((q->pWR + 1) == QUEUE_SIZE) ? 0 : q->pWR + 1;
4827}
4828return 1;
4829}
4830static int Dequeue(struct Queue *q, uint8_t *data)
4831{
4832if (QueueEmpty(q))
4833return 0;
4834else {
4835*data = q->q[q->pRD];
4836q->pRD = ((q->pRD + 1) == QUEUE_SIZE) ? 0 : q->pRD + 1;
4837}
4838return 1;
4839}
4840In spite of its simplicity, a shared data structure such as this offers ample
4841opportunity for data race conditions. Notice that the Enqueue (Dequeue)
4842operation writes (reads) the referenced queue location before updating the
4843qWR (qRD) pointer. The order of operations is important ! As presented,
4844the implementation assumes a single reader and a single writer. In a multireader or multi-writer situation (e.g. with multiple threads) a lock variable
4845is required to prevent data races. In such a situation, the interrupt handler
4846may not utilize a lock and hence must have exclusive access to one end of the
4847queue.
4848Hardware Flow Control
4849While adding interrupt driven buffers improves both the performance
4850and reliability of data transmission, it is not sufficient to prevent buffer overrun
4851and hence loss of data. In this section we discuss the use of two additional
4852signals RTS (request to send) and CTS (clear to send) which may be used to
4853enable “hardware flow” control. These signals are present on both the usb-uart
4854bridge (assuming you are using one that exposes them) and the STM32. In
4855practice nRTS (nCTS) from the STM32 is connected to nCTS (nRTS) of the
4856usb-usrt bridge. 2 When the STM32 is prepared to receive data it activates
4857(makes zero) nRTS and when it wants to stop receiving data it raises nRTS.
4858Similarly, the usb-uart bridge will use its nRTS (connected to the STM32
48592We use nRTS to indicate that the signal RTS is “active low”.
4860Revision: 14c8a1e (2016-06-05) 167
4861CHAPTER 11. INTERRUPTS
4862nCTS) signal to indicate its readiness to receive data. These two pins are
4863described in the STM32 documentation [20] as follows:
4864If the RTS flow control is enabled .., then nRTS is asserted (tied
4865low) as long as the USART receiver is ready to receive new data.
4866When the receive register is full, nRTS is de-asserted, indicating
4867that the transmission is expected to stop at the end of the current
4868frame ...
4869If the CTS flow control is enabled .., then the transmitter checks
4870the nCTS input before transmitting the next frame. If nCTS is
4871asserted (tied low), then the next data is transmitted (assuming
4872that a data is to be transmitted ..), else the transmission does
4873not occur. When nCTS is de-asserted during a transmission, the
4874current transmission is completed before the transmitter stops.
4875This approach is called hardware flow control because the signaling is
4876performed in hardware as opposed to software mechanisms that rely upon
4877inserting special control characters into the data stream. The solution we
4878present is not entirely hardware driven – we drive the nRTS pin through
4879software (e.g. the interrupt handler) to indicate to the remote device that it
4880should stop transmitting and let the USART hardware stop the transmitter
4881whenever the remote device de-asserts nCTS.
4882Unfortunately, the fully automated approach is doomed to failure. To
4883understand, consider this statement from the FTDI faq (FTDI is a prominent
4884producer of usb-uart bridge chips:
4885If [nCTS] is logic 1 it is indicating the external device cannot
4886accept more data. the FTxxx will stop transmitting within 0-3
4887characters, depending on what is in the buffer.
4888This potential 3 character overrun does occasionally present
4889problems. Customers should be made aware the FTxxx is a USB
4890device and not a “normal” RS232 device as seen on a PC. As such
4891the device operates on a packet basis as opposed to a byte basis.
4892Thus, the behavior of real devices does not always conform to the expectations of the STM32. The only viable solution is for software to de-assert
4893nRTS while it is still capable of receiving additional input data !. The problem
4894is fundamentally unsolvable as there does not appear to be a clear specification
4895that defines the amount of allowed character overrun.
4896168 Revision: 14c8a1e (2016-06-05)
489711.5. EXAMPLE: INTERRUPT DRIVEN SERIAL COMMUNICATIONS
4898The actual changes required to the code presented in Section 11.5 are
4899modest. We must configure two additional pins for nCTS and nRTS, modify
4900the initialization of the USART to allow nCTS to halt the transmitter, and
4901modify both the interrupt handler and getchar routines. Our strategy is to
4902define a “high water” mark in the input buffer below which the software asserts
4903nRTS and above which it de-asserts nRTS. The high water mark provides room
4904for additional characters to arrive after nRTS is de-asserted.
4905Table 5.2 provides the pin definitions for USART1. In addition to tx
4906and rx which we previously configured we must configure nRTS (PA12) and
4907nCTS (PA11):
4908// Configure CTS pin
4909GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
4910GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
4911GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
4912GPIO_Init(GPIOA , &GPIO_InitStructure);
4913// Configure RTS pin -- software controlled
4914GPIO_WriteBit(GPIOA , GPIO_Pin_12 , 1); // nRTS disabled
4915GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
4916GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
4917GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
4918GPIO_Init(GPIOA , &GPIO_InitStructure);
4919We modify slightly the USART configuration:
4920USART_InitStructure.USART_HardwareFlowControl =
4921USART_HardwareFlowControl_CTS;
4922and enable nRTS
4923// nRTS enabled
4924GPIO_WriteBit(GPIOA , GPIO_Pin_12 , 0);
4925As discussed above we add code to the getchar routine
4926Revision: 14c8a1e (2016-06-05) 169
4927CHAPTER 11. INTERRUPTS
4928char getchar (void)
4929{
4930uint8_t data;
4931while (Dequeue(&UART1_RXq , &data, 1) != 1);
4932// If the queue has fallen below high water mark, enable nRTS
4933if (QueueAvail(&UART1_RXq) <= HIGH_WATER)
4934GPIO_WriteBit(GPIOA , GPIO_Pin_12 , 0);
4935return data;
4936}
4937and the receive portion of the interrupt handler:
4938if(USART_GetITStatus(USART1 , USART_IT_RXNE) != RESET)
4939{
4940uint8_t data;
4941// clear the interrupt
4942USART_ClearITPendingBit(USART1 , USART_IT_RXNE);
4943// buffer the data (or toss it if there's no room
4944// Flow control is supposed to prevent this
4945data = USART_ReceiveData(USART1) & 0xff;
4946if (!Enqueue(&UART1_RXq , &data, 1))
4947RxOverflow = 1;
4948// If queue is above high water mark, disable nRTS
4949if (QueueAvail(&UART1_RXq) > HIGH_WATER)
4950GPIO_WriteBit(GPIOA , GPIO_Pin_12 , 1);
4951}
4952Finally, we define the high water mark in uart.h
4953#define HIGH_WATER (QUEUE_SIZE - 6)
4954Exercise 11.2 Interrupt Driven Serial Communciations
4955• Complete the implementation of an interrupt driven UART with flow
4956control.
4957170 Revision: 14c8a1e (2016-06-05)
495811.6. EXTERNAL INTERRUPTS
4959• Write a simple application that reads characters and echoes them.
4960You should test this by piping a large file through the serialT, capturing
4961the results and diffing the input and output files.
4962• Rewrite your echo program so that it reads/writes entire lines (up to
4963the limit of an 80-character buffer)
4964• Try the same tests with your polling based uart.
4965By now your Library of modules should look like:
4966Library
4967ff/
4968i2c.c
4969i2c.h
4970lcd.c
4971lcd.h
4972mmcbb.c
4973spi.c
4974spi.c
4975uart.c
4976uart.h
4977uart-fc.c
4978xprintf.c
4979xprintf.h
498011.6 External Interrupts
4981The STM32 F1xx micro-controller provide up to 20 possible EXTI (external interrupt) sources; although in many cases the various sources share a
4982single interrupt vector. The possible sources and their corresponding event/vector (for the STM32 F100) are:
4983Revision: 14c8a1e (2016-06-05) 171
4984CHAPTER 11. INTERRUPTS
4985Event Source Vector
4986EXT0 PA0-PG0 EXT0_IRQHandler
4987EXT1 PA1-PG1 EXT1_IRQHandler
4988EXT2 PA2-PG2 EXT2_IRQHandler
4989EXT3 PA3-PG3 EXT3_IRQHandler
4990EXT4 PA4-PG4 EXT4_IRQHandler
4991EXT5 PA5-PG5 EXT9_5_IRQHandler
4992… … …
4993EXT15 PA15-PG15 EXT1_10_IRQHander
4994EXT16 PVD PVD_IRQHandler
4995EXT17 RTC Alarm RTC_WKUP
4996EXT18 USB Wakeup not on STM32 F100
4997EXT19 Ethernet Wakeup not on STM32 F100
4998Notice that only one of PAx-PGx, where x is one of 1-15, can be configured for as an EXTI source at any moment. In the event that multiple EXTI
4999sources share a handler, pending interrupts can be determined from reading
5000the pending register EXTI_PR. Also, any EXTI source can be “triggered”
5001through software by setting the appropriate bit in the “software interrupt
5002event register” EXTI_SWIER.
5003Configuring an external interrupt consists of several steps:
50041. Configure the NVIC for the corresponding vector.
50052. For GPIO pins, configure the appropriate AFIO_EXTICRx register to
5006select the correct pin (e.g. PA0).
50073. Set the trigger condition (falling/rising or both).
50084. Set the appropriate bit in the event mask register.
5009This can all be accomplished using the standard peripheral library modules stm32f10x_nvic.[ch] and stm32f10x_exti.[ch]. For example, to configure
5010PA0 (connected to the “user push button” on the discovery board) to trigger
5011an interrupt on a rising edge:
5012// Connect EXTI0 to PA0
5013GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource0);
5014// Configure EXTI0 line // see stm32f10x_exti.h
5015EXTI_InitStructure.EXTI_Line = EXTI_Line0;
5016172 Revision: 14c8a1e (2016-06-05)
501711.6. EXTERNAL INTERRUPTS
5018EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
5019EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
5020EXTI_InitStructure.EXTI_LineCmd = ENABLE;
5021EXTI_Init(&EXTI_InitStructure);
5022// Configure NVIC EXTI0_IRQn ...
5023A basic handler should check the interrupt status and clear any pending
5024bit;
5025void EXTI0_IRQHandler(void){ if (EXTI_GetITStatus(EXTI_Line0) !=
5026RESET){ ... EXTI_ClearITPendingBit(EXTI_Line0); } }
5027EXTI sources can also be configured in “event mode”. In this mode, they
5028do not generate an interrupt, but rather, generate an internal event that can
5029be used to wake the processor from sleep. For example, the WFE instruction
5030can be used by software to enter Sleep mode which may be exited by an event
5031on any EXTI line in event mode.
5032Exercise 11.3 External Interrupt
5033Using the code fragments presented, write a simple program that responds to rising edges (button release) events on PA0 by toggling a led3.
5034In writing this application, you will probably notice that depending
5035upon how you release the button, it will often not behave as expected.
5036The following quotation from the reference manual is a clue to understanding what is going on:
5037Note: The external wakeup lines are edge triggered, no glitches
5038must be generated on these lines. If a falling edge on external
5039interrupt line occurs during writing of EXTI_FTSR register, the
5040pending bit will not be set.
5041Buttons and switches are notorious for “bounce” – when a button is
5042pressed, the contacts do not separate cleanly leading to multiple spikes. This
5043can be seen in Figure 11.6 which illustrates the actual behavior as captured on
5044an oscilloscope – the top trace shows the voltage at the PA0 when the button
5045is pressed and the lower trace when the button is released.
5046The solution is to add a de-bouncing circuit which serves as a “low-pass”
5047filter to remove fast changing signals (glitches). A simple de-bounce circuit
5048is illustrated in Figure 11.6 consisting of a resistor and capacitor. Because
5049Revision: 14c8a1e (2016-06-05) 173
5050CHAPTER 11. INTERRUPTS
5051the Discovery board has a pull-down resistor connected to the button, the
5052suggested circuit is sub-optimal, but will eliminate the glitches as illustrated
5053in Figure 11.6.
5054Try your code with the de-bounce circuit added to PA0.
5055174 Revision: 14c8a1e (2016-06-05)
505611.6. EXTERNAL INTERRUPTS
5057Figure 11.6: Button press/release
5058Revision: 14c8a1e (2016-06-05) 175
5059CHAPTER 11. INTERRUPTS
5060GND
5061PB2
5062PB1
5063PB0
5064PC5
5065PC4
5066PA7
5067PA6
5068PA5
5069PA4
5070PA3
5071PA2
5072PA1
5073PA0
5074PC3
5075PC2
5076PC1
5077PC0
5078RST
5079PD1
5080PD0
5081PC15
5082PC14
5083PC13
5084VBAT
50853V3
5086NC
5087GND
5088PB10
5089PB11
5090PB12
5091PB13
5092PB14
5093PB15
5094GND
5095PC6
5096PC7
5097PC8
5098PC9
5099PA8
5100PA9
5101PA10
5102PA11
5103PA12
5104PA13
5105PA14
5106PA15
5107PC10
5108PC11
5109PC12
5110PD2
5111PB3
5112PB4
5113PB5
5114PB6
5115PB7
5116Boot
5117PB8
5118PB9
51195V
5120NC
5121GND
5122stm32-discovery
51230.001µF
5124100Ω
5125Figure 11.7: De-bounce Circuit
5126176 Revision: 14c8a1e (2016-06-05)
512711.6. EXTERNAL INTERRUPTS
5128Figure 11.8: Button press/release (filtered)
5129Revision: 14c8a1e (2016-06-05) 177
5130
5131Chapter 12
5132DMA: Direct Memory Access
5133In this chapter we discuss the use of direct memory access (DMA) to
5134relieve the processor of the costs of transferring blocks of data between memory
5135and peripherals. Consider the following idiom where a block data is read from
5136a peripheral by repeatedly waiting for a status flag and then reading an item
5137from the peripheral.
5138for (i = 0; i < N; i++) {
5139while(flagBusy);
5140buf[i] = peripheralRegister;
5141}
5142We have seen this with serial communication (Section 5.1), SPI communication (Listing 6.3), and will see it again with I2C communication (Figure 9.3). This approach, called software polling, has three limitations. First,
5143the processor is tied up during the transfer and cannot perform other tasks;
5144ideally with a large data transfer (consider reading a data sector from an SD
5145card), the transfer could be kicked off and the processor freed to perform other
5146work while the transfer is realized. Second, the actual transfer rate is lower
5147than the underlying hardware might permit. Finally, it is difficult to achieve
5148tight timing bounds, for example, audio streaming depends upon the data
5149samples to be transferred at a constant rate.
5150To see rather dramatically the differences in performance, consider
5151the two Logic screen captures showing the SPI transfers when filling and
51527735 LCD with a solid color shown in Figure 12. The upper capture measures the time for transferring 2 pixels, while the lower capture measures
5153the time for transferring 128 pixels. The theoretical peak is 12x106/16 =
5154750, 000pixels/second for a 12 MHz SPI clock. Without DMA, our transRevision: 14c8a1e (2016-06-05) 179
5155CHAPTER 12. DMA: DIRECT MEMORY ACCESS
5156fer rate is 1/20x10−6 = 50, 000pixels/second, while with DMA, our transfer
5157rate is 128/17x10−4 = 735, 000pixels/second. Of course, with DMA, there
5158is unavoidable overhead between blocks. Thus, there is a tradeoff between
5159throughput and memory space (larger blocks yield higher throughput).
5160Figure 12.1: Color Fill with (lower) and without (upper) DMA
5161DMA is implemented in processors with dedicated hardware devices.
5162These devices share the memory bus and peripheral buses with the processor
5163(CPU) as illustrated in Figure 12. In this diagram, the DMA device reads from
5164memory over the memory bus and writes to a peripheral over the peripheral
5165bus. The situation with the STM32 is somewhat more complicated because
5166there are multiple peripheral buses, but the principle is the same.
5167Only one device can use a bus at any moment, so DMA transfers do
5168impact the CPU. However, consider that the peak rate for the SPI device
5169180 Revision: 14c8a1e (2016-06-05)
517012.1. STM32 DMA ARCHITECTURE
5171DMA CPU
5172Peripheral Memory
5173Memory Bus
5174Peripheral Bus
5175Figure 12.2: DMA Transfer
5176is 750,000 transfers/second while the memory bus of the STM32 Value line
5177device can support 24,000,000/5 RAM transfers/second (each transfer takes
51785 bus cycles). Thus, our block transfer consumes roughly 15% of the memory
5179bus cycles. The STM32 architecture guarantees that the CPU will not be
5180starved. Furthermore, only a fraction of STM32 instructions directly access
5181RAM memory – the rest simply pull instructions from FLASH which uses a
5182different bus.
518312.1 STM32 DMA Architecture
5184The STM32 has two DMA peripherals each of which has multiple independently configurable “channels” (7 for DMA1 and 5 for DMA2). A channel
5185is roughly the hardware realization of a transaction. To initialize DMA between a peripheral and memory it is necessary to configure the appropriate
5186channel. For example, DMA1 channel 2 (3) can be used to receive (transmit)
5187data from (to) SPI1.
5188Prior to utilizing the DMA peripherals, remember to enable their clocks
5189! For example,
5190RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);+
5191Configuring a channel consists of setting appropriate parameters through
5192a DMA_InitTypeDef structure:
5193typedef struct
5194{
5195uint32_t DMA_PeripheralBaseAddr
5196uint32_t DMA_MemoryBaseAddr;
5197Revision: 14c8a1e (2016-06-05) 181
5198CHAPTER 12. DMA: DIRECT MEMORY ACCESS
5199uint32_t DMA_DIR;
5200uint32_t DMA_BufferSize;
5201uint32_t DMA_PeripheralInc;
5202uint32_t DMA_MemoryInc;
5203uint32_t DMA_PeripheralDataSize;
5204uint32_t DMA_MemoryDataSize;
5205uint32_t DMA_Mode;
5206uint32_t DMA_Priority;
5207uint32_t DMA_M2M;
5208}DMA_InitTypeDef;
5209The parameters include the peripheral base address (e.g. SPI1->DR),
5210the memory address buffer, the transfer direction, the buffer size, etc. Once
5211the DMA channel is initialized, it must be enabled. The STM32 firmware
5212provides peripheral specific commands to enable a DMA transaction. The
5213following code fragment illustrates this for transmitting data via SPI utilizing
5214DMA.
5215DMA_Init(txChan , &DMA_InitStructure);
5216DMA_Cmd(txChan , ENABLE);
5217SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx , ENABLE);
5218Multiple DMA channels can be initialized simultaneously. Indeed, for
5219SPI the natural configuration utilizes DMA for both transmission and reception simultaneously. Completion of a DMA request is detected through an
5220appropriate flag. We will examine these details more in Section 12.2.
5221The DMA channels provided by the STM32 are each associated with
5222specific peripherals (See [20] for complete documentation). For example DMA1
5223channel 1 supports ADC1, TIM2_CH3, and TIM4_CH1. In designing a system with the STM32, it is important to be cognizant of potential resource
5224conflicts. For example DAC_Channel1 (digital analog converter) requires access to DMA1 Channel 3 which is also used for SPI1_TX. Thus it is not
5225possible to simultaneously transmit on SPI1 and output on DAC_Channel1
5226using DMA. I had initially developed the SPI examples using SPI1; however,
5227later I found that I needed to utilize the DAC for audio output which prompted
5228a switch to SPI2.
522912.2 SPI DMA Support
5230A complete SPI 8-bit data receive routine utilizing DMA is illustrated
5231in Listings 12.1 and 12.2. The DMA initialization structure is configured as
5232follows.
5233182 Revision: 14c8a1e (2016-06-05)
523412.2. SPI DMA SUPPORT
5235static int dmaRcvBytes(void *rbuf, unsigned count)
5236{
5237DMA_InitTypeDef DMA_InitStructure;
5238uint16_t dummy[] = {0xffff};
5239DMA_DeInit(DMA1_Channel2);
5240DMA_DeInit(DMA1_CHannel3);
5241// Common to both channels
5242DMA_InitStructure.DMA_PeripheralBaseAddr =
5243,→(uint32_t)(&(SPI1->DR));
5244DMA_InitStructure.DMA_PeripheralDataSize =
5245,→DMA_PeripheralDataSize_Byte;
5246DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
5247DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
5248DMA_InitStructure.DMA_BufferSize = count;
5249DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
5250DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
5251DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
5252// Rx Channel
5253DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rbuf;
5254DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
5255DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
5256DMA_Init(DMA1_Channel2 , &DMA_InitStructure);
5257// Tx channel
5258DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) dummy;
5259DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
5260DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
5261DMA_Init(DMA1_channel3 , &DMA_InitStructure);
5262/* ... */
5263Listing 12.1: SPI DMA Receive (Part 1)
5264• Peripheral base address set to SPI data register.
5265• Peripheral and memory data size set to 8 bits (byte).
5266• Peripheral increment disabled – all data read/written from a single DR
5267register.
5268Revision: 14c8a1e (2016-06-05) 183
5269CHAPTER 12. DMA: DIRECT MEMORY ACCESS
5270// Enable channels
5271DMA_Cmd(rxChan , ENABLE);
5272DMA_Cmd(txChan , ENABLE);
5273// Enable SPI TX/RX request
5274SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx ,
5275,→ENABLE);
5276// Wait for completion
5277while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);
5278// Disable channels
5279DMA_Cmd(rxChan , DISABLE);
5280DMA_Cmd(txChan , DISABLE);
5281SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx ,
5282,→DISABLE);
5283return count;
5284}
5285Listing 12.2: SPI DMA Receive (Part 2)
5286• Buffer size set to number of data to be transferred (count).
5287• Normal DMA mode
5288• High priority
5289The code then configures the memory side and initializes the receive
5290channel followed by reconfiguring the memory side and configuring the transmit channel. For uni-directional read operations, transmit data are provided via a “dummy” buffer which is read repeatedly during the transfer
5291(DMA_MemoryInc_Disable).
5292Once both channels are configured, they are enabled, a SPI DMA request is made, and finally the code waits for a completion flag. Notice that
5293in this implementation, the processor sets up the transfer and then waits for
5294completion, but this still involves busy waiting. An alternative approach (not
5295184 Revision: 14c8a1e (2016-06-05)
529612.2. SPI DMA SUPPORT
5297considered here) is to enable a DMA interrupt and define an appropriate handler (e.g. DM1_Channel1_IRQHandler). The main code could then return
5298and await an appropriate completion event. I postpone discussion of such an
5299architecture until I have the opportunity to introduce an RTOS.
5300Exercise 12.1 SPI DMA module
5301Implement a generic SPI exchange routine:
5302static int xchng_datablock(SPI_TypeDef *SPIx, int half, const void
5303,→*tbuf, void *rbuf, unsigned count)
5304Your configuration should utilize the DMA channels for either SPI1 or
5305SPI2 as defined at call time. The transfer size should be configured as 8-bits
5306or 16-bits as defined by the parameter half. It should be possible to utilize
5307this routine as read/write/exchange as needed.
5308You should then create a new SPI module (call it spidma.c) which implements the interface in Figure 6.1 and utilizes DMA for all transfers longer
5309than 4 data items (shorter transfers should be performed without DMA). This
5310module should be derived your polling-based spi.c module.
5311Exercise 12.2 Display BMP Images from Fat File System
5312Write an application that reads BMP images (see http://en.wikipedia.
5313org/wiki/BMP_file_format) from an SD card and displays them on the 7735
5314screen. Note that BMP images are usually stored from bottom to top so you
5315will need to appropriately set the direction when using the 7735 interface.
5316To help you get started, a simple Linux program that parses BMP files is
5317illustrated in Listings 12.3 and 12.4. You can manipulate images in various
5318formats (e.g. resize, rotate) with the Linux program convert. Your program
5319should probably check the size of BMP images it attempts to display and reject those which are not 128x160 and 24bit color. You program will have to
5320convert from 24 bit color to 16-bit color. The conversion is relatively easy –
5321for each RGB byte, select the lower 5 or 6 bits (RGB = 565) and pack into a
5322single 16-bit color byte. Finally, your program should cycle through the set of
5323BMP files in the root directory of an SD card. Note – remember that FAT16
5324file systems use 8.3 naming – that is 8 characters followed by a 3 character
5325previx !
5326To obtain the benefits of DMA you should read a block of pixels into
5327a buffer, convert them and pack in second buffer, and then write them out.
5328Experiment with different block sizes 16,32,64,128 pixels and measure how
5329Revision: 14c8a1e (2016-06-05) 185
5330CHAPTER 12. DMA: DIRECT MEMORY ACCESS
5331long it takes to load and display a file. You can easily utilize the system timer
5332interrupt to measure delays. For example, add a variable that is incremented
5333on every interrupt; clear this variable before reading and writing an image.
5334Compare your results with and without DMA.
5335Linux provides several tools for manipulating images. To resize a JPEG
5336image to the 128x160 geometry of the lcd:
5337convert -resize 128x160! input.jpg output.jpg
5338Conversion to a BMP file is accomplished with a pair of tools
5339jpegtopnm output.jpg |ppmtobmp > output.bmp
5340186 Revision: 14c8a1e (2016-06-05)
534112.2. SPI DMA SUPPORT
5342#include <stdint.h>
5343struct bmpfile_magic {
5344unsigned char magic[2];
5345};
5346struct bmpfile_header {
5347uint32_t filesz;
5348uint16_t creator1;
5349uint16_t creator2;
5350uint32_t bmp_offset;
5351};
5352typedef struct {
5353uint32_t header_sz;
5354int32_t width;
5355int32_t height;
5356uint16_t nplanes;
5357uint16_t bitspp;
5358uint32_t compress_type;
5359uint32_t bmp_bytesz;
5360int32_t hres;
5361int32_t vres;
5362uint32_t ncolors;
5363uint32_t nimpcolors;
5364} BITMAPINFOHEADER;
5365struct bmppixel { // little endian byte order
5366uint8_t b;
5367uint8_t g;
5368uint8_t r;
5369};
5370Listing 12.3: BMP File Structures
5371Revision: 14c8a1e (2016-06-05) 187
5372CHAPTER 12. DMA: DIRECT MEMORY ACCESS
5373#include <fcntl.h>
5374#include <stdio.h>
5375#include ``bmp.h''
5376struct bmpfile_magic magic;
5377struct bmpfile_header header;
5378BITMAPINFOHEADER info;
5379main(int argc, char *argv[])
5380{
5381int f;
5382if (argc > 1){
5383if ((f = open(argv[1], O_RDONLY)) == -1)
5384{
5385perror(``problem opening file'');
5386return 1;
5387}
5388read(f, (void *) &magic , 2);
5389printf(``Magic %c%c\n'', magic.magic[0], magic.magic[1]);
5390read(f, (void *) &header , sizeof(header));
5391printf(``file size %d offset %d\n'', header.filesz ,
5392,→header.bmp_offset);
5393read(f, (void *) &info, sizeof(info));
5394printf(``Width %d Height %d, bitspp %d\n'', info.width ,
5395info.height , info.bitspp);
5396close(f);
5397}
5398}
5399Listing 12.4: Parsing BMP Files
5400188 Revision: 14c8a1e (2016-06-05)
5401Chapter 13
5402DAC : Digital Analog
5403Converter
5404The STM32 F1xx parts have a 12-bit digital-analog-converter (DAC)
5405module with two independent output channels – DAC1 (pin PA4) and DAC2
5406(pin PA5). The channels can be configured in 8-bit mode or 12-bit mode and
5407the conversions can be done independently or simultaneously. Simultaneous
5408mode can be used where two independent but synchronized signals must be
5409generated – for example, the left and right channels of stereo audio. It is often
5410important that the analog output is update at precise instants, sometimes
5411controlled by external hardware – thus the conversion process can be triggered
5412by timers or external signals. Finally, a common use for DAC hardware is to
5413generate a time varying signal. Where the sample rate is high, it is impractical
5414to control the conversion process entirely through application software or even
5415interrupt handlers. Thus, each DAC channel has DMA capability which can
5416be controlled by the trigger signal.
5417In this chapter we will explore the use of a single DAC channel. We will
5418start with the simplest case – direct software control of a analog output – which
5419is useful for creating slow moving signals that do not have to be synchronized
5420in time. We will then explore the generation of time-synchronized signals;
5421first with DAC module provided triangle wave generator, and then interrupt
5422driven code to produce a sine wave. Interrupt driven operation does not scale
5423well to high update rates – eventually, all of the processor cycles are required
5424just to service the interrupt. Thus, we will examine the use of DMA to “feed”
5425the DAC, with a lower frequency interrupt used to update the DMA buffer.
5426Finally, we will define an exercise to read audio files from an SD card and play
5427them, via DMA, to an external audio amplifier driven by the DAC.
5428Revision: 14c8a1e (2016-06-05) 189
5429CHAPTER 13. DAC : DIGITAL ANALOG CONVERTER
5430Warning: The preliminary exercises in this chapter cannot easily be completed without access to an oscilloscope to display waveforms. The final exercise, an audio player, can be completed without an oscilloscope but may be
5431harder to debug without one.
5432Control
5433Logic DORx DACx
5434DHRx
5435DAC
5436Output Triggers
5437CR
5438Figure 13.1: DAC Channel x
5439A simplified block diagram of one DAC channel is illustrated in Figure 13. Each channel has separate control logic which is configured through
5440a single control register (CR). Data to be converted by channel x are written
5441to data holding register (DHRx). In response to a trigger event, DHRx is
5442transferred to the data output register (DORx) and, after a settling time, the
5443corresponding analog value appears at the output. The DAC output voltage
5444is linear between 0 and VREF + (3.3V on the discovery board) and is defined
5445by the following equation:
5446DACoutput = VREF + ×
5447DOR
54484095
5449Trigger events can include the trigger signals from various timers (TIM2-
5450TIM7, TIM15), an external interrupt (EXTI line 9), and software. It is also
5451possible to configure the DAC without a trigger in which case DHRx is automatically copied to the DORx after a single clock cycle delay.
5452Exercise 13.1 Waveform Generator
5453Write a C program to generate a sine wave with minimum and maximum
5454values of 512 and 1536 where a full cycle consists of 100 samples. The output
5455of your program should have the form:
5456190 Revision: 14c8a1e (2016-06-05)
5457int16_t a441[] = {
5458...
5459};
5460In order to simplify data alignment and synchronous output, the software interface for the two data holding registers is through a set of registers
5461each of which addresses a specific alignment issue. The various cases are illustrated in Figure 13. For each of the two DAC channels there are registers
5462for left and right-aligned 12-bit data as well as 8-bit data. Writing to these
5463registers affects the appropriate DHRx register as illustrated. To enable synchronous output, there are three interface registers (DHR12RD, DHR12LD,
5464and DHR8RD) for each of the three data alignment cases. Notice that for the
5465case of 8-bit data, the data fill bits 11..4 of the DHR (the high order bits)
5466which preserves the full 0..VREF range of the analog output.
5467In addition to converting user supplied data, the DAC channels each independently support noise-wave and triangle-wave generation. In these modes,
5468data to be converted are generated in response to the trigger event. The output waveforms can be useful both for testing the DAC and for testing external
5469hardware.
547031 1615 0
5471DHR12Rx DHRx[11:0]
5472DHR12Lx DHRx[11:0]
5473DHR8Rx DHRx[11:4]
5474DHR12RD DHR2[11:0] DHR1[11:0]
5475DHR12LD DHR2[11:0] DHR1[11:0]
5476DHR8RD DHR2[11:4] DHR1[11:4]
5477Figure 13.2: Data Holding Registers
5478Exercise 13.2 Application Software Driven Conversion
5479A common use for DAC hardware is to generate an analog output which
5480changes infrequently and which does not need to be synchronized to any signal.
5481Configuration follows the pattern for all previous devices – enable clocks,
5482configure pins, configure device, enable device. In the basic use, the default
5483configuration for the DAC is adequate, although we choose to enable an output
5484Revision: 14c8a1e (2016-06-05) 191
5485CHAPTER 13. DAC : DIGITAL ANALOG CONVERTER
5486buffer which provides a bit more electrical drive at the expense of speed as
5487illustrated in Listing 13.1.
5488Somewhat confusingly, the pin is configured as “analog in”. The name
5489is a bit misleading because the DAC module drives the pin when configured.
5490However, this configuration does perform the important function of disconnecting any digital input buffer ! Once a DAC is initialized, data may be
5491written using the following commands (defined in stm32f10x_dac.[ch] where
5492align is one of DAC_Align_12b_R, DAC_Align_12b_L, DAC_Align_8b_R.
5493DAC_SetChannel1Data(align ,value);
5494DAC_SetChannel2Data(align ,value);
5495Now write a program that, on a 1ms interval, output the 12-bit values
5496corresponding to the sin wave you created above (a full cycle consists of 100
5497samples). Test the output by examining on an oscilloscope.
5498GPIO_InitTypeDef GPIO_InitStructure;
5499DAC_InitTypeDef DAC_InitStructure;
5500RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
5501RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC , ENABLE);
5502GPIO_StructInit(&GPIO_InitStructure);
5503GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
5504GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
5505GPIO_Init(GPIOA , &GPIO_InitStructure);
5506// DAC channel1 Configuration
5507DAC_StructInit(&DAC_InitStructure);
5508DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
5509DAC_Init(DAC_Channel_1 , &DAC_InitStructure);
5510// Enable DAC
5511DAC_Cmd(DAC_Channel_1 , ENABLE);
5512Listing 13.1: DAC Initialization
5513Exercise 13.3 Interrupt Driven Conversion
5514Forcing the main application program to maintain precise timing is not
5515a robust solution. First, it ties the application program to a tight inner loop,
5516192 Revision: 14c8a1e (2016-06-05)
5517and second, in the presence of interrupts, we cannot guarantee that the data
5518are output precisely a the desired delay. The timing “jitter” introduced can
5519be a serious problem in some applications. For example, with audio, jitter can
5520be heard in the form of distortion.
5521An alternative approach is to configure a timer to generate interrupts at
5522the desired conversion frequency and using an interrupt handler to write the
5523DHR register. Once a timer is introduced into the solution, we can also use
5524the timer interrupt to trigger the transfer from the DHR to the DOR. This
5525insulates the DAC timing from any possible delays due to other interrupts.
5526As long as the interrupt handler is allowed to execute before the next timer
5527“tick” there will be no jitter in the output signal.
5528In this exercise we will utilize TIM3 both to trigger the DAC transfer
5529and to call an interrupt handler that will be responsible for reloading the
5530DHR. You may modify the previous exercise as follows.
5531• Configure TIM3 to update at 44.1 kHz – see Chapter 10 to review how
5532this is done.
5533• Configure the TIM3 output trigger so that it occurs on update events:
5534TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
5535• Configure the NVIC to enable interrupt channel TIM3_IRQn with the
5536highest priority (0 for both sub-priority and preemption priority) – see
5537Chapter 11 to see how this is done.
5538• Change the trigger in the DAC initialization code:
5539DAC_InitStructure.DAC_Trigger = DAC_Trigger_T3_TRGO;
5540• Write a suitable interrupt handler.
5541void TIM3_IRQHandler(void){
5542}
5543Test your program first using an oscilloscope and then connect it to
5544the external speaker module. You should hear an “A” (actually, 441Hz) if
5545everything is working properly.
5546Note that when configuring the timer, you do not need to set the
5547prescaler to ensure that the timer period is a particular number of cycles
5548as we did for the PWM. In this example, we are only concerned with the
5549frequency of the update events – not how many clock ticks occurred between
5550update events.
5551Revision: 14c8a1e (2016-06-05) 193
5552CHAPTER 13. DAC : DIGITAL ANALOG CONVERTER
555313.1 Example DMA Driven DAC
5554While an interrupt driven DAC has fewer jitter issues, ultimately, the
5555interrupt handler will consume all the available cycles. With the use of DMA
5556we can reduce the software overhead by a factor proportional to the buffer
5557size that we are willing to allocate. The DMA hardware handles the details
5558of writing individual samples to the DAC at the timer rate while an interrupt
5559handler is responsible for refreshing the buffer. As we shall see, with a N-item
5560buffer, we can reduce our interrupt rate by a factor of N/2.
5561This example builds upon Exercise 13.3. The major changes are:
5562• Initialize a DMA channel (DMA1 Channel 3)
5563• Initialize the NVIC for an interrupt handler
5564• Create an interrupt handler
5565We continue to use TIM3 to drive the conversion process; however,
5566rather than calling an interrupt handler to generate the next datum, the DMA
5567device provides this datum. We assume that you have generated a 100 item
5568array with the A440 tone. For this example, we will create a buffer of the
5569same size – initially a perfect clone.
5570for (i = 0; i < A440LEN; i++)
5571outbuf[i] = a440[i];
5572The DAC interrupt handler is responsible for refilling this buffer in
5573alternating halves (Listing 13.2). In this example, the refilling action is not
5574particularly interesting since we are simply re-copying the A440 tone into our
5575output buffer. However, the key idea is that the interrupt handler is called
5576with the DMA transfer is completed (DMA1_IT_TC3) and “half completed”
5577(DMA_IT_HC3) – each case fills a different half of the buffer. This approach
5578provides the greatest resilience to potential timing issues.
5579Configuration is somewhat more complicated because of the need to
5580initialize a DMA channel (Listing 13.3). Notice that the peripheral register
5581is for DHR12R1, and that the DMA is operating in “circular mode” which
5582means that it continuously pulls from a single memory buffer. The DMA
5583channel is configured to generate interrupts at the half and full completion
5584marks. Another notable configuration step is the configuration of the DAC to
5585utilize DMA DAC_DMACmd(DAC_Channel_1, ENABLE).
5586194 Revision: 14c8a1e (2016-06-05)
558713.1. EXAMPLE DMA DRIVEN DAC
5588int completed; // count cycles
5589void DMA1_Channel3_IRQHandler(void)
5590{
5591int i;
5592if (DMA_GetITStatus(DMA1_IT_TC3)){ // Transfer complete
5593for (i = A440LEN/2; i < A440LEN; i++)
5594outbuf[i] = a440[i];
5595completed++;
5596DMA_ClearITPendingBit(DMA1_IT_TC3);
5597}
5598else if (DMA_GetITStatus(DMA1_IT_HT3)){ // Half Transfer complete
5599for (i = 0; i < A440LEN/2; i++)
5600outbuf[i] = a440[i];
5601DMA_ClearITPendingBit(DMA1_IT_HT3);
5602}
5603}
5604Listing 13.2: DMA Interrupt Handler
5605Exercise 13.4 Audio Player
5606Create an audio player with the interface illustrated in Listing 13.4. The
5607player should be based on your previous code and the example in Section 13.1,
5608but with the following differences: the data size should be 8-bits, the data rate
5609should be configurable and the interrupt handler should simply set two the
5610two flags audioplayerHalf and audioplayWhole when the DMA half and
5611whole transfers, respectively, are complete. The job of keeping the audio
5612buffer Audiobuf full is pushed to the application which must poll these two
5613flags, refill the bottom or top half of the buffer as appropriate, and reset the
5614flag; later, when we examine a real-time operating system, this interface will
5615adapt easily to a thread based system. The “init” function should configure
5616the timer, DMA channel, DAC, and interrupt; but it should not enable the
5617hardware. The “start” function should enable the hardware – before calling
5618start, the application must first fill the data buffer. The “stop” function should
5619disable the hardware. Once a sound is completely played the application needs
5620to stop the player. Test this interface with a sine wave. Next, we’ll want to
5621read audio files from an SD Card.
5622An audio player is much more interesting if it can read “standard” audio
5623files. In the following we will describe a subset of the WAV file format which
5624can be generated by most audio software. We only consider the case for PCM
5625encoding with a single audio channel (mono). If you have stereo audio files
5626Revision: 14c8a1e (2016-06-05) 195
5627CHAPTER 13. DAC : DIGITAL ANALOG CONVERTER
5628// DMA Channel 3 Configuration
5629RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
5630DMA_DeInit(DMA1_Channel3);
5631DMA_StructInit(&DMA_InitStructure);
5632DMA_InitStructure.DMA_PeripheralBaseAddr = &DAC->DHR12R1;
5633DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
5634DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
5635DMA_InitStructure.DMA_PeripheralDataSize =
5636,→DMA_PeripheralDataSize_HalfWord;
5637DMA_InitStructure.DMA_BufferSize = A440LEN;
5638DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) outbuf;
5639DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
5640DMA_InitStructure.DMA_MemoryDataSize =
5641,→DMA_MemoryDataSize_HalfWord;
5642DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
5643DMA_InitStructure.DMA_Priority = DMA_Priority_High;
5644DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
5645DMA_Init(DMA1_Channel3 , &DMA_InitStructure);
5646// Enable Interrupts for complete and half transfers
5647DMA_ITConfig(DMA1_Channel3 , DMA_IT_TC | DMA_IT_HT , ENABLE);
5648NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
5649NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
5650NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
5651,→//HIGHEST_PRIORITY;
5652NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
5653NVIC_Init(&NVIC_InitStructure);
5654// Enable everything
5655DMA_Cmd(DMA1_Channel3 , ENABLE);
5656DAC_Cmd(DAC_Channel_1 , ENABLE);
5657DAC_DMACmd(DAC_Channel_1 , ENABLE);
5658TIM_Cmd(TIM3, ENABLE);
5659Listing 13.3: DMA Configuration
5660or files in other formats or with different encodings, the Linux program “sox”
5661provides a powerful conversion utility. You should write a parser for this
5662subset of WAV to test on a desktop machine – it is sufficient to print out the
5663key fields when parsing a file.
5664196 Revision: 14c8a1e (2016-06-05)
566513.1. EXAMPLE DMA DRIVEN DAC
5666#ifndef PLAYER_H
5667#define PLAYER_H
5668#define AUDIOBUFSIZE 128
5669extern uint8_t Audiobuf[];
5670extern int audioplayerHalf;
5671extern int audioplayerWhole;
5672audioplayerInit(unsigned int sampleRate);
5673audioplayerStart();
5674audioplayerStop();
5675#endif
5676Listing 13.4: Audio Player Interface
5677There are many references to WAV files available on the WWW. A
5678good one can be found at http://www-mmsp.ece.mcgill.ca/documents/
5679audioformats/wave/wave.html. A WAV file consists of a (recursive) sequence of chunks. Every chunk except the first has the following form:
5680Field Length (bytes) Content
5681ckID 4 Chunk ID (e.g. “RIFF”)
5682cksize 4 Chunk size n
5683body n Chunk contents
5684With the exception of the ckID field, which is a sequence of four characters in big-endian order, all other fields are in little-endian order. The WAV
5685files we consider have the following sequence: Master (RIFF) chunk, format
5686chunk, 0 or more other chunks, data chunk.
5687To parse WAV files we need to be able to read chunk headers, parse
5688the three chuck types of interest, and skip uninteresting chunks. The master
5689RIFF chunk has the following form:
5690Field Length (bytes) Content
5691ckID 4 Chunk ID: “RIFF”
5692cksize 4 Chunk size 4+n
5693WAVEID 4 WAVE ID: “WAVE”
5694WAVE chunks n Chunk contents
5695The Format chunk has the following form. There are three variations
5696for this, but we only need to parse the common portion; however, your code
5697Revision: 14c8a1e (2016-06-05) 197
5698CHAPTER 13. DAC : DIGITAL ANALOG CONVERTER
5699should skip any ignored bytes !
5700Field Length (bytes) Content
5701ckID 4 Chunk ID: “fmt ”
5702cksize 4 Chunk size 16 or 18 or 40
5703wFormatTag 2 0x0001 for PCM data
5704nChannels 2 Number of channels – 1 for mono
5705nSamplesPerSec 4 Sampling rate (per second)
5706nAvgBytesPerSec 4 Data rate
5707nBlockAlign 2 Data block size (bytes)
5708wBitsPerSample 2 Bits per sample – 8
57090-24 ignore
5710The key pieces of information are the format (must be 1 for PCM),
5711number of channels (must be 1 for mono), sampling rate (to be configured in
5712the player), bits per sample (must be 8).
5713The Format chunk may be followed by 0 or more non-data chunks which
5714your parser should skip. The final chunk we consider is the data chunk:
5715Field Length (bytes) Content
5716ckID 4 Chunk ID: “data”
5717cksize 4 n
5718sampled data n Samples
5719pad byte 0 or 1 Pad if n is odd
5720To write your parser here are some helpful data structures:
5721#define RIFF 'FFIR'
5722#define WAVE 'EVAW'
5723#define fmt ' tmf'
5724#define data 'atad'
5725struct ckhd {
5726uint32_t ckID;
5727uint32_t cksize;
5728};
5729struct fmtck {
5730uint16_t wFormatTag;
5731uint16_t nChannels;
5732uint32_t nSamplesPerSec;
5733uint32_t nAvgBytesPerSec;
5734uint16_t nBlockAlign;
5735uint16_t wBitsPerSample;
5736};
5737198 Revision: 14c8a1e (2016-06-05)
573813.1. EXAMPLE DMA DRIVEN DAC
5739It is convenient to compare the chunk IDs against strings; however, the
5740conventional C string has a null termination byte. An alternative, shown in
5741this preceding code fragment is a multi-byte character (defined in reverse order
5742to handle endianess !).
5743Your parser should take a WAV file name as argument, open and parse
5744the file. As mentioned, when parsing the file, your parser should print out the
5745relevant field. If you use the “open”, “close”, and “read” system commands,
5746then skipping over uninteresting chunks is easily accomplished:
5747lseek(fid, skip_amount , SEEK_CUR);
5748Once your parser is working, it’s time to create an audio player that
5749can read a WAV file off an SD card and play it. The fat file system described
5750in Chapter 8 has read (f_read), and lseek (f_lseek) commands with slightly
5751different interfaces than the Linux equivalent. You should modify your audio
5752player to open a particular WAV file (you’ll need to copy a suitable file to an
5753SD card) from an SD card, parse the header, initialize the player, and then
5754“play” the file – here’s an example of how I handled the audioplayerHalf
5755event (next is the number of bytes to be copied which is generally half the
5756buffer size except at the file end).
5757if (audioplayerHalf) {
5758if (next < AUDIOBUFSIZE/2)
5759bzero(Audiobuf , AUDIOBUFSIZE/2);
5760f_read(&fid, Audiobuf , next, &ret);
5761hd.cksize -= ret;
5762audioplayerHalf = 0;
5763}
5764Revision: 14c8a1e (2016-06-05) 199
5765
5766Chapter 14
5767ADC : Analog Digital
5768Converter
5769The dual of a DAC is an ADC (analog digital converter) which converts analog signals to digital values. The STM32 processors include one or
5770more ADC peripherals – there is one on the medium density value line parts.
5771The STM32 ADC uses successive approximation – the ADC has the ability
5772to generate a discrete set of voltages and to compare these against a sampled
5773input voltage; it essentially performs binary search to find the best approximation. For 12 bits of accuracy, the STM32 takes at least 14 cycles of the
5774ADC clock (a multiple of the system clock) – the extra 2 cycles are overhead
5775due to sampling. Thus, With a 12 MHz ADC clock, the STM32 ADC can
5776perform a sample in slightly more than 1µsec.
5777Although the STM32 VL component has a single ADC, it can support
5778multiple analog inputs. The basic architecture is illustrated in Figure 14.
5779On the discovery board, PA0-PA7, PB0-PB1, and PC0-PC5 may all be used
5780as analog inputs which can be multiplexed to the ADC. The ADC may be
5781configured to sample any subset of these inputs in succession. There are
5782two basic modes of operation – single and continuous conversion. With single
5783conversion, once the ADC is triggered, it converts a single input and stores the
5784result in its data register (DR). The trigger may either come from software or
5785signal such as a timer. In continuous mode, the ADC starts another conversion
5786as soon as it finishes one. The ADC may also operate in scan mode where
5787a set of inputs to be scanned is configured. A single conversion is performed
5788for each configured input in succession. Scans may also be continuous in the
5789sense that a new scan begins as soon as one is completed.
5790Revision: 14c8a1e (2016-06-05) 201
5791CHAPTER 14. ADC : ANALOG DIGITAL CONVERTER
5792GPIO
5793Port ADC DR
5794ADC_IN0
5795ADC_IN1
5796ADC_IN15
5797TIM1_CH1
5798TIM1_CH2
5799TIM3_TRG0
5800...
5801...
5802Figure 14.1: Analog Digital Converter
5803The ADC has a single data register, so when scanning multiple analog
5804inputs, it is essential that the data be read between samples. This can be
5805accomplished through polling – software can monitor a flag, interrupts, or
5806DMA. Interrupts and DMA may be triggered at the end of each conversion.
5807In this chapter we show how to use the ADC to continuously sample a single
5808input, to use a timer to trigger conversion of a single channel and an ADC
5809interrupt to read the result, and how to use DMA to handle conversions in
5810the time triggered case. We also present an exercise to create a voice recorder
5811that saves the resulting WAV files on an SD card.
5812It is important to note that our presentation ignores several additional
5813features of the STM32 ADC (for example “injected channels”) that are best
5814understood by reading the reference manual.
581514.1 About Successive Approximation ADCs
5816To fully understand the STM32 ADC it is helpful to have some background in how successive approximation ADCs operate. Consider Figure 14.1
5817which illustrates a typical ADC. At its heart is a digital analog converter
5818(DAC). To begin a conversion, a hardware control “captures” a sample of
5819input voltage (Vain) – shown here with some external resistance Rain to be
5820discussed in the sequel. Once the input (Vsamp) is captured, the controller
5821generates a sequence of digital approximations D(vest) and checks each by
5822converting the approximation to an analog signal which is then compared
5823against the sampled input. The sequence of approximations corresponds to
5824202 Revision: 14c8a1e (2016-06-05)
582514.1. ABOUT SUCCESSIVE APPROXIMATION ADCS
5826a binary search – MSB to LSB. Once the best approximation is found, the
5827digital value is loaded into a data register (DR). For a N-bit approximation,
5828the approximation process requires N iterations.
5829S&H
5830Control DAC
5831DR
5832−
5833+
5834vsamp
5835vest
5836vsamp > vest
5837Capture
5838vain
5839Rain
5840ld D(vest)
5841Figure 14.2: Successive Approximation ADC
5842Radc
5843Cadc
5844vsamp
5845Capture
5846vain
5847Rain
5848Figure 14.3: Sample and Hold
5849The sample and hold circuit operates by charging an internal capacitor
5850as illustrated in Figure 14.1. During the capture phase, a switch (transistor)
5851is closed and the internal capacitor Cadc is allowed to charge/discharge to
5852voltage vain. This is where the external resistance comes into play. If the
5853external voltage source has “high-impedance”, it cannot produce a large current and hence charging the capacitor may take a long time. In contrast, a
5854Revision: 14c8a1e (2016-06-05) 203
5855CHAPTER 14. ADC : ANALOG DIGITAL CONVERTER
5856low-impedance source can charge the capacitor quickly. Thus, the time required to capture an input voltage is dependent on the external circuit; in
5857the STM32, the capture time is configurable from 1.5 cycles to 239.5 cycles
5858to accommodate differences in inputs. For high speed conversion, it may be
5859necessary to use an external op-amp to buffer an input in order to convert a
5860high-impedance source into a low-impedance input. Where speed is not an
5861issue, it is best to choose the longest sample time that is feasible.
5862To understand the impact of sample time on accuracy, consider the
5863graph in Figure 14.1. The time required to charge the internal capacitor Cadc
5864is dependent upon the internal and external impedances –
5865tc = Cadc ∗ (Radc + Rain)
5866with the capacitor voltage at time t equal to
5867vsamp = vain × (1 − e
5868−t/tc
5869)
5870In general, it is necessary to wait a multiple of tc to achieve reasonable accuracy. For example given tc we can compute the sample time required to
5871achieve 12 bits of accuracy:
5872vsamp
5873vain
5874> 1 −
58751
58762
587712
58781 − e
5879−t/tc > 1 − 2
5880−12
5881e
5882−t/tc ≤ 2
5883−12
5884−t
5885tc
5886≤ ln(2−12)
5887−t
5888tc
5889≤ −12 × ln(2)
5890t > 8.32 × tc
5891The model presented is fairly simplistic, but illustrates some of the key
5892ideas. Other factors to be considered are board layout (stray capacitance)
5893reference voltages, signal noise, etc. All this is described in detail in [12]. It
5894is sufficient to conclude by saying that achieving fast and precise analog to
5895digital conversion is complex; however, many applications to not require either
5896high speed or high precision. In such applications, only modest attention to
5897detail is required.
5898204 Revision: 14c8a1e (2016-06-05)
589914.1. ABOUT SUCCESSIVE APPROXIMATION ADCS
5900vain × (1 − e
5901−t/tc )
5902t
5903vsamp
5904vain
5905tc
5906(0.63 × vain)
5907Figure 14.4: Impact of Sample Time on Accuracy
59083.3 V
5909gnd
5910ADC_IN6 3.3 V
5911gnd
5912ADC_IN6
5913Figure 14.5: Simple Analog Input
5914Exercise 14.1 Continuous Sampling
5915In this example a simple analog source – a potentiometer will be connected to PA6 (ADC_IN6). As illustrated in Figure 14.1 two terminals of the
5916potentiometer should be connected to 3.3 V and GND while the center tap is
5917connected to ADC_IN6. On the left side of the figure is the electrical symbol
5918for a potentiometer and on the right a photograph of a typical potentiometer.
5919A potentiometer is a variable resistor; in this application we use it a voltage
5920divider which can produce any input between 0 and 3.3 V.
5921The application will continuously read the analog input and, if it is
5922Revision: 14c8a1e (2016-06-05) 205
5923CHAPTER 14. ADC : ANALOG DIGITAL CONVERTER
5924above 3.3/2 Volts, light the green LED, or turn the LED off otherwise. By
5925now you should know how to do the following:
5926• Configure the clocks for GPIOA, GPIOC, and the ADC.
5927• Configure port PA6 as analog input.
5928• Configure port PC9 as push/pull output.
5929Configuring the ADC follows a familiar pattern:
5930ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
5931ADC_InitStructure.ADC_ScanConvMode = DISABLE;
5932ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
5933ADC_InitStructure.ADC_ExternalTrigConv =
5934,→ADC_ExternalTrigConv_None;
5935ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
5936ADC_InitStructure.ADC_NbrOfChannel = 1;
5937ADC_Init(ADC1, &ADC_InitStructure);
5938// Configure ADC_IN6
5939ADC_RegularChannelConfig(ADC1, ADC_Channel_6 , 1,
5940,→ADC_SampleTime_55Cycles5);
5941// Enable ADC
5942ADC_Cmd(ADC1, ENABLE);
5943Notice that when configuring the channel, we have to select a “sampling
5944time.” The minimum for 12 bits of accuracy is a 13.5 cycle sampling time.
5945Choosing the “right” sampling time can be complicated if it is desirable to
5946combine speed and accuracy. Our requirements for this example are pretty
5947loose.
5948Unlike other peripherals, the ADC needs to be calibrated. The hardware
5949supports automated calibration as the following code illustrates. Again for this
5950example, we can probably dispense with calibration.
5951206 Revision: 14c8a1e (2016-06-05)
595214.1. ABOUT SUCCESSIVE APPROXIMATION ADCS
5953// Check the end of ADC1 reset calibration register
5954while(ADC_GetResetCalibrationStatus(ADC1));
5955// Start ADC1 calibration
5956ADC_StartCalibration(ADC1);
5957// Check the end of ADC1 calibration
5958while(ADC_GetCalibrationStatus(ADC1));
5959The only remaining issue is reading the conversion result:
5960ain = ADC_GetConversionValue(ADC1);
5961It remains to create a working application.
5962Exercise 14.2 Timer Driven Conversion
5963In this exercise we will convert the preceding exercise to be timer driven
5964with an interrupt handler to execute whenever the conversion is complete. We
5965will need to slightly alter the ADC initialization code, configure a timer, and
5966configure the NVIC.
5967You should configure the NVIC to enable ADC1_IRQn – the specific priority is relatively unimportant. Configure TIM3 to generate a TRG0 event
5968every 1ms. Configure the ADC as follows:
5969Revision: 14c8a1e (2016-06-05) 207
5970CHAPTER 14. ADC : ANALOG DIGITAL CONVERTER
5971ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
5972ADC_InitStructure.ADC_ScanConvMode = DISABLE;
5973ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
5974ADC_InitStructure.ADC_ExternalTrigConv =
5975ADC_ExternalTrigConv_T3_TRGO;
5976ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
5977ADC_InitStructure.ADC_NbrOfChannel = 1;
5978ADC_Init(ADC1, &ADC_InitStructure);
5979ADC_RegularChannelConfig(ADC1, ADC_Channel_6 , 1,
5980ADC_SampleTime_55Cycles5);
5981ADC_ITConfig(ADC1, ADC_IT_EOC , ENABLE);
5982ADC_ExternalTrigConvCmd(ADC1, ENABLE);
5983ADC_Cmd(ADC1, ENABLE);
5984Move your code that toggles the LED to an interrupt handler with the
5985following structure:
5986void ADC1_IRQHandler(void)
5987{
5988// read ADC DR and set LED accordingly
5989ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
5990}
5991Exercise 14.3 Voice Recorder
5992TBD
5993208 Revision: 14c8a1e (2016-06-05)
5994Chapter 15
5995NewLib
5996Throughout this book we’ve lived without the standard C libraries
5997(libc) even though an implementation is distributed with the Sourcery tools
5998that we use for building projects. The primary reason we have avoided libc
5999thus far is to maintain clarity about what code is actually executing – as we’ll
6000see, introducing libc can quickly lead to obfuscation. A second reason is that
6001libc is a memory hog – with only 8k SRAM available on the discovery board
6002processor, there isn’t much room to spare. However, the first consideration is
6003now moot – you’ve had a pretty complete introduction to writing code for the
6004STM32, and the second consideration is much less important if you move on
6005to larger members of the STM32 family. There are many advantages to using
6006libc including access to the standard library functions.
6007The implementation of libc distributed with the Sourcery tools and
6008widely used for embedded systems is “newlib.” newlib includes the stdlib
6009functions (e.g. abs, atoi, atoll, malloc, and unicode support), stdio (printf,
6010sprintf, scanf, ...), string support, and many others. newlib also includes
6011an implementation of the standard math libraries libm. Unfortunately, the
6012stdio functions are particular memory hogs as they allocate rather large memory buffers to support I/O. Furthermore, by default (for example, the Sourcery
6013distribution) newlib is not configured to minimize memory use. Thus, we will
6014also show how to compile newlib from sources to optimize memory use.
6015The architecture of newlib requires an external implementation of key
6016system functions including – open, close, read, write, and sbrk – the last of
6017these is the building block upon which malloc is built. In order to use libc,
6018it is necessary to provide at least stubs for these and other functions. We will
6019show how to design these stubs to support standard I/O using the STM32
6020USART
6021Revision: 14c8a1e (2016-06-05) 209
6022CHAPTER 15. NEWLIB
6023This chapter is organized as follows. We will begin with a simple example – “hello world” (surprise !) to illustrate the issues we must resolve
6024in order to use newlib, and the memory issues that it raises. Recall that in
6025Chapter 3 we pointed out that “hello world” is actually a complex program,
6026although most of the complexity is “under the hood.” Finally, we will show
6027how to compile libc in a manner that minimizes the memory requirements
6028(especially SRAM). If you’re going to use libc on an STM32 variant with
6029substantial SRAM (at least 20k) this step is unnecessary – you may use the
6030libraries distributed with the Sourcery tools.
603115.1 Hello World
6032“Hello World” is the most famous programming example in the C universe. As we pointed out in Chapter 3, it’s actually pretty complex. Consider
6033the program:
6034#include <stdio.h>
6035main() {
6036printf("hello world\n");
6037}
6038printf is a library function which takes a format string and an optional
6039list of parameters. It must stringify these parameters, merge them with the
6040format string, and write the resulting string to stdout. What is stdout ?
6041It’s a buffered stream – the stdio libraries manage buffered streams. Data
6042are buffered as they are written, and then the buffered data are written to a
6043file or device. In this case, our intuition is that this stream should somehow
6044be connected to a UART to print to a screen somewhere. While our use of
6045printf is trivial, more complex invocations allocate memory in order to have
6046space for performing any conversions.
6047If we attempt to compile “hello world” (create a project and try this !),
6048we immediately learn that there are a number of undefined functions (Listing 15.1).
6049In a desktop environment, these all correspond to operating system calls
6050– libc is just a code library, ultimately it needs access to an operating system
6051API. In order to use newlib, we must provide the missing functionality in the
6052form of procedures. Some of these we will replace with simple stubs, others
6053(read and write) with code that accesses a uart.
6054As we mentioned, libc allocates memory – a lot of it – from the “heap.”
6055libc provides functions to manage the heap (malloc and free), but it de210 Revision: 14c8a1e (2016-06-05)
605615.1. HELLO WORLD
6057undefined reference to `_sbrk'
6058undefined reference to `_write'
6059undefined reference to `_close'
6060undefined reference to `_fstat'
6061undefined reference to `_isatty'
6062undefined reference to `_lseek'
6063undefined reference to `_read'
6064Listing 15.1: Undefined Functions in newlib
6065pends upon a system function _sbrk to allocate the memory that it manages.
6066Consider Figure 15.1 repeated from Chapter 2 which illustrates the use of
6067RAM by an executing program. The heap grows upward from the compiler
6068allocated data towards the stack which grows downwards. Within the heap,
6069memory is allocated by malloc and deallocated by free; however, whenever
6070malloc has insufficient free space it asks for more memory via _sbrk, which
6071has the effect of moving the heap end up (or down for a negative request).
6072In a desktop system, this is implemented by allocated more memory pages,
6073indeed malloc generally asks for memory blocks that are integral numbers of
6074pages (e.g. 4096 bytes), which is a problem in a memory constrained system
6075such as the discovery board.
6076Data
6077Heap End
6078Main Stack SP
6079RAM Start (low)
6080RAM End (high)
6081Heap Start
6082Figure 15.1: Program Memory Model
6083In order to implement _sbrk we need to know where the heap starts
6084(i.e. the end of compiler/linker allocated memory) and what its physical limit
6085is (i.e the maximum value for heap end). In the linker script, we define two
6086values _end – the end of the data segment – and _stackend which is the limit
6087Revision: 14c8a1e (2016-06-05) 211
6088CHAPTER 15. NEWLIB
6089of the space reserved for the stack. 1
6090Before providing an implementation of _sbrk, it is enlightening to read
6091the Linux man page for sbrk (which calls the system function _sbrk).
6092void *sbrk(intptr_t increment);
6093...
6094brk() and sbrk() change the location of the program break,
6095which defines the end of the process’s data segment (i.e., the program break is the first location after the end of the uninitialized
6096data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates
6097memory.
6098A few other key points are in order. _sbrk(0) returns the current
6099“program break.” If the call cannot be satisfied, _sbrk returns -1 and sets
6100the current errno to an appropriate error code. In newlib, errno is part of a
6101structure used to make the library reentrant – this “reent” structure is another
6102large source of memory usage which must be replicated in a multi-threaded
6103environment. An implementation of _sbrk is shown in Listing 15.2
6104The remaining stubs are provided in Listing 15.3. The read and write
6105operations utilize the putc and getc interface described in Chapter 5; in both
6106cases we restrict our transfers to a single character. Notice that most of the
6107remaining stubs simply return an error code; an exception is _isatty which
6108returns 1 since we’re using the uart as a terminal. _fstat which provides
6109meta data for open files always sets the file mode to S_IFCHR which denotes
6110a character oriented device.
6111There is one final detail required to use newlib. The startup code must
6112call _libc_init_array(void) before main. This ensures that any required
6113data structures are correctly initialized. In our startup code, we provide a
6114“weak” default implementation for the case where we compile without libc.
6115void __attribute__ ((weak)) __libc_init_array (void){}
6116void Reset_Handler(void) {
6117...
6118__libc_init_array();
6119main();
6120...
6121}
6122212 Revision: 14c8a1e (2016-06-05)
612315.1. HELLO WORLD
6124#include <errno.h>
6125// defined in linker script
6126extern caddr_t _end, _stackend;
6127caddr_t _sbrk(int nbytes){
6128static caddr_t heap_ptr = NULL;
6129caddr_t base;
6130if (heap_ptr == NULL) {
6131heap_ptr = (caddr_t)&_end;
6132}
6133if ((caddr_t) &_stackend > heap_ptr + nbytes) {
6134base = heap_ptr;
6135heap_ptr += nbytes;
6136return (base);
6137} else {
6138errno = ENOMEM;
6139return ((caddr_t)-1);
6140}
6141}
6142Listing 15.2: _sbrk Implementation
6143Exercise 15.1 Hello World
6144Complete and test the hello world example. You should put all the stub
6145code in a single file – syscalls.c and compile this with your code.
61461Calculating stack sizes can be challenging – especially in the presence of library code.
6147It’s best to relatively conservative !
6148Revision: 14c8a1e (2016-06-05) 213
6149CHAPTER 15. NEWLIB
6150int _close(int file) {
6151errno = ENOTSUP;
6152return -1;
6153}
6154int _fstat(int file, struct stat *st) {
6155st->st_mode = S_IFCHR; // character device
6156return 0;
6157}
6158int _isatty(int file) {
6159return 1;
6160}
6161int _link(char *old, char *new) {
6162errno = EMLINK;
6163return -1;
6164}
6165int _lseek(int file, int ptr, int dir) {
6166errno = ENOTSUP;
6167return -1;
6168}
6169int _open(const char *name, int flags , int mode) {
6170errno = ENOTSUP;
6171return -1;
6172}
6173int _read(int file, char *ptr, int len) {
6174if (len){
6175*ptr = (char) uart_getc(USART1);
6176return 1;
6177}
6178return 0;
6179}
6180int _unlink(char *name) {
6181errno = ENOENT;
6182return -1;
6183}
6184int _write(int file, char *ptr, int len) {
6185if (len) {
6186uart_putc(*ptr, USART1);
6187return 1;
6188}
6189return 0;
6190}
6191Listing 15.3: Basic Syscall stubs 214 Revision: 14c8a1e (2016-06-05)
619215.2. BUILDING NEWLIB
619315.2 Building newlib
6194The distribution of newlib with the Sourcery tool was not compiled for
6195minimum memory usage. You can build your own version by downloading the
6196newlib sources and using the following build process:
6197mkdir newlib -build
6198cd newlib -build
6199export CFLAGS_FOR_TARGET=''-g -O2 -DSMALL_MEMORY''
6200/path_to_newlib_source/configure --target=arm-none-eabi
6201,→--prefix=/target -directory --disable -newlib -supplied -syscalls
6202,→--disable -libgloss --disable -nls
6203Revision: 14c8a1e (2016-06-05) 215
6204
6205Chapter 16
6206Real-Time Operating Systems
6207The STM32 hardware is capable of simultaneously performing actions
6208on all its various communication buses – for example reading audio files from
6209an SD card on the SPI bus, playing these audio files through the DAC, monitoring Nunchuks over the I2C bus and logging messages through the UART.
6210However, coordinating these parallel activities through software can be a real
6211challenge – especially where hard timing constraints must be satisfied. One
6212common strategy is to partition responsibility for multiple activities among
6213separate threads – each of which acts autonomously – which are scheduled
6214based upon priorities. For example, threads with tight timing constraints are
6215given higher priorities than other threads.
6216Threads provide a way to partition the logic of a program into separate
6217tasks. Each thread has its own state and appears to execute as an autonomous
6218program while sharing data with other threads. In a uni-processor such as the
6219STM32, threads are executed in an interleaved manner with access to the
6220processor controlled by a scheduler. Whenever an interrupt occurs, there is
6221an opportunity to suspend the current thread and resume a blocked thread. A
6222timer interrupt provides the mechanism to “time-slice” the processor allowing
6223each ready thread the opportunity to make forward progress.
6224Coordination of hardware tasks by multiple threads is enabled through
6225synchronization objects. For example, a thread which is attempting to transmit a stream of data through a UART cannot make forward progress when
6226the output buffer is full. In this case, the thread should “wait” allowing other
6227threads to execute. Later when space is freed in the transmit buffer, for example by an interrupt handler, the waiting thread can be “signaled” to resume.
6228This wait/signal pattern is implemented using a synchronization object called
6229a “semaphore.”
6230Revision: 14c8a1e (2016-06-05) 217
6231CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6232The decision to structure a program around threads should not be taken
6233lightly because there are many potential pitfalls Threads require additional
6234RAM memory because each thread requires a separate stack; in memory constrained devices such as the processor on the discovery board this can be a
6235real problem. Threads can overflow their stacks if insufficient space is allocated – it can be difficult to accurately estimate the space required. Threads
6236offer ample opportunity for subtle bugs in the form of race conditions wherever threads share data. Finally, threads are extremely difficult to debug.
6237While one would like to trace the execution of a single thread, breakpoints are
6238typically at the instruction level and, with shared code, halt any thread executing the instruction. Furthermore, GDB is not integrated with most thread
6239packages and hence it is not easy to see the state of threads other than the
6240currently halted one.
6241There are many real-time operating systems available for the STM32.
6242In this chapter we use FreeRTOS because it is relatively simple and is available
6243in source code form. FreeRTOS provides a basic kernel with a small set of
6244synchronization primitives. In contrast, Chibios provides a complete hardware
6245abstraction layer with drivers for many of the STM32 devices. FreeRTOS
6246serves our pedagogical purposes better because it is easier to “look under the
6247hood”, but Chibios provides a significantly richer foundation for building large
6248projects. The choice to utilize FreeRTOS has two negative consequences – key
6249documents are available only by purchase, and the kernel requires dynamic
6250memory allocation which is not desirable in memory constrained situations.
6251In contrast, the Chibios kernel is statically allocated and all documents are
6252freely available.
6253The remainder of this chapter is organized as follows. We begin with a
6254discussion of threads, their implementation, and the FreeRTOS API for thread
6255management. We then discuss key synchronization primitives and show how
6256they can be used to control access to shared hardware, shared data (e.g. a
6257FatFS file system) and coordinate scheduling with interrupt handlers (UART
6258receive and send queues).
6259Note the stm32vl discovery board doesn’t really have sufficient memory
6260to support both libc (newlib) and FreeRTOS simultaneously. Thus, we do not
6261address additional issues that arise when combining the two (the FreeRTOS
6262distribution provides further information on this topic).
6263218 Revision: 14c8a1e (2016-06-05)
626416.1. THREADS
626516.1 Threads
6266The single threaded programs which we have developed throughout this
6267book organize RAM with all statically defined data allocated space in the low
6268address portion of RAM and the program stack initialized at the top (highest
6269address) in RAM. As the program executes, the stack grows downward on
6270entry to procedures and shrinks upward on procedure exit. When interrupts
6271occur, key portions of the execution context are pushed onto the main stack –
6272see Chapter 11 for further explanation. In a multi-threaded environment, the
6273main stack is used during initialization and then, primarily as an interrupt
6274stack. Each active thread is allocated its own stack within RAM as illustrated
6275in Figure 16.1.
6276Data
6277Heap End
6278Main Stack SP
6279Thread 1 SP thread 1
6280Thread 2 SP thread 2
6281RAM Start (low)
6282RAM End (high)
6283Heap Start
6284Figure 16.1: RAM Layout with Executing Threads
6285The data area is allocated statically at link time and includes all global
6286and static variables both initialized and uninitialized. The area above the
6287data is used for dynamic memory allocation (e.g. malloc). This area, called
6288the heap, is expanded by the memory allocator as required. The main stack
6289is placed at the high end of RAM by the linker and grows downward. In
6290FreeRTOS, the thread stacks are allocated blocks within the heap. Space is
6291Revision: 14c8a1e (2016-06-05) 219
6292CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6293allocated within each stack by executing code (e.g. at procedure entry). Correct program execution requires that no stack ever grow beyond its allocated
6294region. While there are runtime tests that can help detect such an unhappy
6295event, it is difficult to guarantee that an overflow will never occur.
6296FreeRTOS supports threads (called “tasks” in FreeRTOS) with a prioritized pre-emptive kernel – at any moment, the thread with the highest priority
6297is allowed to run. Threads with identical priorities are “time-sliced” with each
6298being allowed to run for a fixed period before being pre-empted. To understand the key ideas of the kernel, consider the thread states in Figure 16.1.
6299Every thread (task) is in one of four states – Ready, Running, Blocked, or
6300suspended. When a thread is created (0) it is put into the Ready state. The
6301(single) running thread is in the Running state. A running thread may be
6302pre-empted and returned to the Ready state (1) in which case a ready thread
6303is moved to the Running state (2). A running thread may also be blocked
6304(3) by calling a blocking API function (such as waiting on a semaphore). A
6305blocked thread may be made ready (4) when un-blocked by the actions of
6306another thread or interrupt handler. FreeRTOS has an additional Suspended
6307state which we ignore for now.
6308Ready
6309Blocked
6310Running
6311Suspended
63123
63130
63144
63152
63161
6317Figure 16.2: Thread (Task) States in FreeRTOS
6318The code for a thread (task) is defined by a C function that never
6319returns as in:
6320void threadFunction(void *params){
6321while(1) {
6322// do something
6323}
6324}
6325When “created” a thread is passed a pointer to a parameter structure
6326– many threads may share a single function, but can be specialized through
6327220 Revision: 14c8a1e (2016-06-05)
632816.1. THREADS
6329the parameters. A thread is created with a function, a name, a stack size,
6330optional parameter pointer, a priority, and (optionally) a location to store a
6331unique “handle” to the thread.
6332portBASE_TYPE xTaskCreate(
6333pdTASK_CODE pvTaskCode ,
6334const portCHAR * const pcName ,
6335unsigned portSHORT usStackDepth ,
6336void *pvParameters ,
6337unsigned portBASE_TYPE uxPriority ,
6338xTaskHandle *pvCreatedTask
6339);
6340The FreeRTOS kernel allocates memory for the stack and creates the
6341necessary thread data structure. 1
6342The stack size is a key parameter – too small and the thread will overflow its stack and corrupt memory, too large and memory is wasted. Since
6343FreeRTOS uses the stack to hold the context for non-running tasks (68 bytes
6344for 17 registers !) the minimum stack size is actually relatively large. Furthermore, if the task code calls any library functions, the stack will need to be big
6345enough to hold any data allocated on the stack and any registers saved. Most
6346threads will need 128-256 bytes.
6347The FreeRTOS kernel also creates an “idle thread” which has the lowest
6348priority and runs whenever no other thread can run. (The idle thread has a
6349stack too !). The basic flow of a multi-threaded program follows:
6350main() {
6351// include misc.h
6352NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
6353// Initialize hardware
6354...
6355// Create tasks
6356xTaskCreate( ... );
6357...
6358// Start Scheduler
6359vTaskStartScheduler();
6360}
63611FreeRTOS requires a memory allocator to dynamically allocate key data structures.
6362Revision: 14c8a1e (2016-06-05) 221
6363CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6364As with all the programs considered this far, code begins with hardware
6365initialization. One hardware initialization that we call out is the NVIC configuration. FreeRTOS requires preemptive thread priorities; here we enable
6366the NVIC to support 16 priorities (and no sub-priorities). This is the configuration assumed by the STM32 port of FreeRTOS. Once hardware has been
6367initialized, initial set of threads are created. While FreeRTOS allows dynamic
6368thread allocation, the limited RAM (8K) available on the Discovery board
6369virtually requires that we create all threads initially. The scheduler never
6370returns (there is an API call to exit the scheduler, but that isn’t particularly
6371useful for our applications). A more complete example, with two threads that
6372blink two LEDs is illustrated in Listing 16.1. Notice that the threads utilize
6373vTaskDelay to sleep.
6374222 Revision: 14c8a1e (2016-06-05)
637516.1. THREADS
6376static void Thread1(void *arg) {
6377int dir = 0;
6378while (1) {
6379vTaskDelay(300/portTICK_RATE_MS);
6380GPIO_WriteBit(GPIOC , GPIO_Pin_9 , dir ? Bit_SET : Bit_RESET);
6381dir = 1 - dir;
6382}
6383}
6384static void Thread2(void *arg) {
6385int dir = 0;
6386while (1) {
6387vTaskDelay(500/portTICK_RATE_MS);
6388GPIO_WriteBit(GPIOC , GPIO_Pin_8 , dir ? Bit_SET : Bit_RESET);
6389dir = 1 - dir;
6390}
6391}
6392int main(void)
6393{
6394// set up interrupt priorities for FreeRTOS !!
6395NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
6396// initialize hardware
6397init_hardware();
6398// Create tasks
6399xTaskCreate(Thread1 , // Function to execute
6400"Thread 1", // Name
6401128, // Stack size
6402NULL, // Parameter (none)
6403tskIDLE_PRIORITY + 1 , // Scheduling priority
6404NULL // Storage for handle (none)
6405);
6406xTaskCreate(Thread2 , "Thread 2", 128,
6407NULL, tskIDLE_PRIORITY + 1 , NULL);
6408// Start scheduler
6409vTaskStartScheduler();
6410// Schedule never ends
6411}
6412Listing 16.1: FreeRTOS Example
6413Revision: 14c8a1e (2016-06-05) 223
6414CHAPTER 16. REAL-TIME OPERATING SYSTEMS
641516.2 FreeRTOS Configuration
6416FreeRTOS/
6417Demo/CORTEX_STM32F100_Atollic/Simple_Demo_Source/
6418FreeRTOSConfig.h
6419Source/
6420include/
6421list.c
6422portable/
6423MemMang/
6424heap_1.c
6425GCC/ARM_CM3/
6426port.c
6427portmacro.h
6428queue.c
6429tasks.c
6430timers.c
6431Figure 16.3: Key Parts of FreeRTOS Distribution
6432The FreeRTOS source code is freely available from http://sourceforge.
6433net/projects/freertos/files/. The distribution can be a little overwhelming. The key files which we use are illustrated in Figure 16.3. In creating a
6434sample application, it will be necessary to augment your makefile to include
6435the necessary paths, as illustrated in Listing 16.2.
6436FreeRTOS = ... path_to_FreeRTOS ...
6437CFLAGS += -I$(FreeRTOS)/include -DGCC_ARMCM3
6438...
6439vpath %.c $(FreeRTOS)/
6440vpath %.c $(FreeRTOS)/portable/MemMang
6441vpath %.c $(FreeRTOS)/portable/GCC/ARM_CM3
6442...
6443OBJS+= tasks.o queue.o list.o timers.o heap_1.o port.o
6444Listing 16.2: Build Paths for FreeRTOS
6445Every FreeRTOS project requires a configuration file. This is used to
6446set key parameters of the project; for example, enabling or disabling kernel
6447features – FreeRTOSConfig.h. We based our projects on the configuration file
6448shown in Figure 16.3. The configuration file serves several purposes. First, it
6449224 Revision: 14c8a1e (2016-06-05)
645016.3. SYNCHRONIZATION
6451defines key parameters – for example clock rate, heap size, number of priorities,
6452etc. Second, it defines features to be enabled in a given build – features are
6453enabled (1) or disabled (0) by defines of the following form:
6454#define INCLUDE_xxx 0+
6455Examples of key features include
6456#define configUSE_MUTEXES 1
6457#define configCHECK_FOR_STACK_OVERFLOW 1
6458#define configUSE_RECURSIVE_MUTEXES 0
6459#define configUSE_COUNTING_SEMAPHORES 0
6460Finally, FreeRTOS also provides the opportunity for user code to “hook”
6461into the kernal at key places:
6462#define configUSE_MALLOC_FAILED_HOOK 0
6463#define configUSE_IDLE_HOOK 0
6464#define configUSE_TICK_HOOK 0
6465If you compile a project with FreeRTOS and have linker errors for missing functions then you should check to see if a corresponding hook was defined.
6466You then have the option to either provide the required function or disable
6467the hook.
6468Exercise 16.1 RTOS – Blinking Lights
6469Complete the blinking lights demo. You should disable any features
6470which your project does not need by making a local copy of the configuration
6471file. You will find it necessary to reduce the heap size (from 7k to 5k) in order
6472for your project to build.
647316.3 Synchronization
6474Threads cannot safely share either data structures or hardware without
6475some synchronization mechanisms. Consider the following getchar implementation discussed in Chapter 5:
6476int getchar(void){
6477while (USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == RESET);
6478return USARTx ->DR & 0xff;
6479}
6480Revision: 14c8a1e (2016-06-05) 225
6481CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6482Recall that this works by reading the UART status register until the
6483receive data resister is “not empty” and then reading the register. Suppose
6484that two threads access the UART – if thread 1 reads the status register
6485and finds the data register “not empty”, but is then preempted by thread 2
6486which also tests the status and reads the data register, then when thread 1 is
6487resumed, its knowlege of the status register will be incorrect and it may read
6488garbage from the data register.
6489The key idea to making this work is finding a method to ensure exclusive
6490access by thread 1 to the UART receive register. One approach is to prevent
6491pre-emption by disablng interrupts; however, consider what would happen
6492if no character arrived or simply arrived after a substantial delay. What is
6493needed is a mechanism to block only those threads which are competing for
6494access to the UART receive hardware. The solution is to use a semphore:
6495xSemaphoreHandle uartRcvMutex;
6496uart_init(...){
6497...
6498uartRcvMutex = xSemaphoreCreateMutex();
6499}
6500int getchar(void){
6501int c;
6502if (xSemaphoreTake(uartRcvMutex , portMAX_DELAY) == pdTRUE)
6503{
6504while (USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == RESET);
6505c = USARTx ->DR & 0xff;
6506xSemaphoreGive(uartRcvMutex);
6507}
6508return c;
6509}
6510A semaphore is a standard sychronization primitive (indeed the first one
6511described for structuring operating system code. The idea is provide a thread
6512safe interface to manage shared resources. A thread requesting a resource
6513is either granted the resource or blocked by the scheduler until the resource
6514becomes available. A thread releasing a resource may, as a side effect, un-block
6515a waiting thread.
6516FreeRTOS supports three types of semaphores – binary semaphores,
6517mutexes, and counting semaphores. Mutexes and binary semaphores are similar, but behave differently with respect to thread priority. Here we use a
6518Mutex. There are two operations of note – take and give. When the mutex
6519is initialized it has a single “token”. Take removes the token if available, or
6520226 Revision: 14c8a1e (2016-06-05)
652116.4. INTERRUPT HANDLERS
6522blocks the calling thread and places it on a list associated with the Mutex if
6523no token is available. Give restores the token. The major difference between
6524mutexes (binary semaphores) and counting semephores is that the latter may
6525have multiple tokens.
6526Another Mutex can be added to similarly protect putchar. Protecting
6527getchar and putchar with Mutexes will prevent data races such as the one
6528above; however, this may not yield the expected behavior. Suppose multiple
6529threads call putchar through a procedure putstring:
6530void putstring(char *s){
6531while (s && *s)
6532putchar(*s++);
6533}
6534In this case, the output of two threads simultaneously writing strings
6535may be interleaved !
6536Exercise 16.2 Multiple Threads
6537Write a program with two threads continuously printing strings to
6538UART1. A third thread should blink one of the leds at 2Hz. You should
6539use thread parameters to specialize a common thread function for the two
6540printing threads. Try your code first using just a Mutex on putchar. Then
6541come up with a solution that prevents interleaving of strings.
654216.4 Interrupt Handlers
6543The getchar code above has a major flaw – the thread holding the
6544mutex will continue to spin on the flag test until it succeeds. Ideally, we
6545need a mechanism to allow the waiting thread to sleep until space is available.
6546With peripherals such as UARTs we have already seen that interrupt code can
6547handle the actual changes in hardware status. In Section 11.5 we showed how
6548this might work. The remaining issue is how to communicate these hardware
6549events with interrupt handlers. As we showed previously, we would like to
6550associate a pair of queues with the transmit and receive interfaces of the
6551UART. Where previously our putchar code failed when the trasmit queue
6552was empty and our getchar code failed when the receive queue was empty,
6553in a multi-threaded environment we would like to block a thread in either of
6554these cases and have the interrupt handler wake the thread.
6555FreeRTOS provides its own blocking queue primitives (indeed, semaphores
6556and mutexes are special cases of queues):
6557Revision: 14c8a1e (2016-06-05) 227
6558CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6559xQueueHandle xQueueCreate(
6560unsigned portBASE_TYPE uxQueueLength ,
6561unsigned portBASE_TYPE uxItemSize);
6562A queue is created with both a length and data size. Items are queued
6563by copying them rather than by reference (one can always queue a pointer,
6564but think carefully before doing this !). The two interface procedures that we
6565require are “send” and “receive”. Notice that each has a “timeout” which may
6566range from 0 (don’t wait if the operation would fail to portMAX_DELAY to wait
6567forever.
6568portBASE_TYPE xQueueSend( xQueueHandle xQueue ,
6569const void * pvItemToQueue ,
6570portTickType xTicksToWait );
6571portBASE_TYPE xQueueReceive(xQueueHandle xQueue ,
6572void *pvBuffer ,
6573portTickType xTicksToWait );
6574Both of these interfaces may be used by threads, but not interrupt
6575handlers, which must use special versions of these:
6576portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue ,
6577const void *pvItemToQueue ,
6578portBASE_TYPE *pxHigherPriorityTaskWoken);
6579portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue ,
6580void *pvBuffer ,
6581portBASE_TYPE *pxTaskWoken);
6582Notice, these “ISR” (interrupt service routine) interfaces have a different
6583third parameter – a flag is returned if a task has been “woken” by the call.
6584In this situation, the interrupt handler should notify the kernel as we shall
6585demonstrate in a moment.
6586Note: It is very important that interrupt handlers accessing the FreeRTOS API have lower priorities (higher numbers) than the value
6587LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY defined in the FreeRTOS configuration file.
6588We now build an interrupt driven version of the uart as shown in Listings
658916.3 and 16.4
6590Exercise 16.3 Multithreaded Queues
6591228 Revision: 14c8a1e (2016-06-05)
659216.4. INTERRUPT HANDLERS
6593int uart_putc(int c){
6594xQueueSend(UART1_TXq , &c, portMAX_DELAY);
6595// kick the transmitter interrupt
6596USART_ITConfig(USART1 , USART_IT_TXE , ENABLE);
6597return 0;
6598}
6599int uart_getc (){
6600int8_t buf;
6601xQueueReceive(UART1_RXq , &buf, portMAX_DELAY);
6602return buf;
6603}
6604Listing 16.3: Interrupt Driven UART
6605Complete an interrupt driven UART with flow control using queues
6606along with a multi-threaded program that exercises both send and receive.
6607Revision: 14c8a1e (2016-06-05) 229
6608CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6609void USART1_IRQHandler(void)
6610{
6611portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
6612if(USART_GetITStatus(USART1 , USART_IT_RXNE) != RESET){
6613uint8_t data;
6614USART_ClearITPendingBit(USART1 , USART_IT_RXNE);
6615data = USART_ReceiveData(USART1) & 0xff;
6616if (xQueueSendFromISR(UART1_RXq , &data,
6617,→&xHigherPriorityTaskWoken) != pdTRUE)
6618RxOverflow = 1;
6619}
6620if(USART_GetITStatus(USART1 , USART_IT_TXE) != RESET) {
6621uint8_t data;
6622if (xQueueReceiveFromISR(UART1_TXq , &data,
6623,→&xHigherPriorityTaskWoken) == pdTRUE){
6624USART_SendData(USART1 , data);
6625}
6626else {
6627// turn off interrupt
6628USART_ITConfig(USART1 , USART_IT_TXE , DISABLE);
6629}
6630}
6631// Cause a scheduling operation if necessary
6632portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
6633}
6634Listing 16.4: Interrupt Driven UART (Handler)
663516.5 SPI
6636The other communication interfaces we have introduced in this book
6637also need to be reconsidered in the face of multi-threading. The I2C interface
6638is much like the Uart interface in that a semaphore can be added directly to
6639the interface code to protect the read/write interfaces (only one semaphore
6640is needed). SPI is somewhat different – whereas the I2C protocol includes
6641device addressing in the transmitted data, SPI uses separate select lines for
6642230 Revision: 14c8a1e (2016-06-05)
664316.5. SPI
6644each device. Our use of the SPI interface looks something like:
6645select();
6646spi_operation();
6647deselect();
6648where select and deselect are device specific. If we followed the UART pattern
6649of accessing a single semaphore inside the SPI operations then it would be
6650possible have one thread interfere with another. We have a couple of design
6651options. We could simply make the semaphore for the SPI interface into a
6652global object an require all users of the interface to first request the sempahore.
6653This has the significant disadvantage of requiring application code writers to
6654be too familar with the low-level synchronization assumptions for the interface
6655and runs a significant risk of leading to flawed code. We could add the select
6656GPIO pin as a (pair) of parameters to the SPI interface as in:
6657void spiReadWrite(SPI_TypeDef* SPIx, uint8_t *buf, uint8_t * buf,
6658,→int cnt,
6659uint16_t pin, GPIO_TypeDef* GPIOx);
6660Or, we could pass a callback function in which the SPI interface could
6661use to select/deselect the device after taking the semaphore
6662typedef void selectCB_t(int sel);
6663void spiReadWrite(SPI_TypeDef* SPIx, uint8_t *buf, uint8_t *buf,
6664,→int cnt,
6665selectCB_t selectCB);
6666This final approach seems preferable as it doesn’t burden the SPI interface with detailed knowledge of how the select/deselect operates.
6667The SPI interface is also used for rather long data transfers utilizing
6668DMA. For example, we use it to transfer blocks of data for the FatFS. In a
6669multi-threaded environment, it is desirable that DMA proceed in the background. In our current implementation we use busy waiting for DMA to
6670complete
6671while (DMA_GetFlagStatus(dmaflag) == RESET) { ; }
6672As with the UART code, this busy waiting can be replaced by blocking
6673the thread initiating the DMA operation on a synchronization object (in this
6674case a binary semaphore is appropriate) and utilizing an interrupt handler to
6675unblock the thread (as illustrated below).
6676Revision: 14c8a1e (2016-06-05) 231
6677CHAPTER 16. REAL-TIME OPERATING SYSTEMS
6678static void vExampleInterruptHandler( void )
6679{
6680portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
6681// handle interrupt
6682...
6683// release semaphore
6684xSemaphoreGiveFromISR( xBinarySemaphore ,
6685,→&xHigherPriorityTaskWoken);
6686portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
6687}
6688In Chapter 13 we showed how to create DMA interrupt handlers. For
6689the SPI interface we need to enable interrupts for the “transfer complete” case.
6690Exercise 16.4 Multithreaded SPI
6691Create a SPI interface supporting multi-threading and DMA. You should
6692use callbacks for device selection. Test your interface with the LCD with two
6693threads competing to use the interface for drawing colored rectangles at random locations (different colors for the two threads).
669416.6 FatFS
6695The FatFS code has some builtin support for multi-threading which
6696must be enabled in the ffconf.h.
6697#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
6698#define _FS_TIMEOUT 1000 /* Timeout period in unit of ticks */
6699#define _SYNC_t HANDLE /* O/S dependent type of sync object */
6700It is up to the user to define an appropriate _SYNC_t type and to
6701provide implementations for ff_req_grant, ff_rel_grant, ff_del_syncobj
6702and ff_cre_syncobj. It is also necessary to modify the low-level device interface to utilize a modified SPI interface and to replace busy waiting with
6703appropriate RTOS delay functions.
6704Exercise 16.5 Multithreaded FatFS
6705Rewrite the low-level interface for the FatFS to use the new SPI interface and to remove busy waiting – your changes should work either in a single
6706232 Revision: 14c8a1e (2016-06-05)
670716.7. FREERTOS API
6708threaded or multi-threaded environment (use the _FS_REENTRANT flag appropriately !. Test your code with a multi-threaded program that plays audio
6709files and displays images from an SD card. One thread should play an audio
6710file while another displays an image.
671116.7 FreeRTOS API
6712The FreeRTOS API is documented at www.freertos.org. Here we
6713identify the key API functions used throughout this chapter.
6714Task Creation
6715xTaskCreate() Create task
6716xTaskDelete() Delete task
6717Task Utilities
6718vTaskDelay() Delay from now
6719vTaskDelayUntil() Delay from previous wake time
6720Kernel Utilities
6721taskYIELD() Force a context switch
6722vTaskSuspendAll() Prevent current task from being preempted
6723vTaskResumeAll() Resume normal scheduling
6724Queues
6725uxQueueMessagesWaiting() Number of messages in queue
6726xQueueCreate() Create queue
6727xQueueDelete() Create queue
6728xQueueSend() Send to queue
6729xQueueReceive() Receive from queue
6730xQueueSendFromISR() ISR send to queue
6731xQueueReceiveFromISR() ISR Receive from queue
6732Sempahore
6733vSemephoreCreateBinary() Create a binary semaphore
6734vSemephoreCreateCounting() Create a counting semaphore
6735vSemephoreCreateMutex() Create a mutex
6736vSemephoreCreateTake() Take from semaphore
6737vSemephoreCreateGive() Give to semaphore
6738vSemephoreCreateGiveFromISR() Give from ISR to semaphore
6739Table 16.1: FreeRTOS API – Key Calls
6740Revision: 14c8a1e (2016-06-05) 233
6741CHAPTER 16. REAL-TIME OPERATING SYSTEMS
674216.8 Discusion
6743Developing a project with FreeRTOS is a lot of work ! All of the device
6744interfaces have to be written to support multi-threading and great care taken
6745to ensure freedom from race conditions. An alterantive is to use an RTOS
6746with a hardware abstraction layer such as Chibios where much of the heavy
6747lifting has been done for you.
6748You probably have also found that debugging multi-threaded code is
6749very challenging. The message is clear – use threads only when really needed.
6750234 Revision: 14c8a1e (2016-06-05)
6751Chapter 17
6752Next Steps
6753In the preceding chapters you’ve learned many of the basic skills needed
6754to build interesting projects using STM32 processors and off-the-shelf modules.
6755In this chapter, I provide pointers to many additional modules and guidance
6756for how the skills you’ve learned can be applied to develop code to interface to
6757these. By now, it should be evident that SRAM is a major limitation of the
6758STM32 VL Discovery Processor. Both newlib and FreeRTOS need much more
6759memory to operate and large projects can greatly benefit from the additional
6760abstraction layer provided by these libraries. Thus, I begin with a discussion
6761of boards providing STM32 processors with larger memories. It should also
6762be evident by now that using a SPI-based LCD, while adequate for basic
6763display isn’t really up to the performance needs of complex graphics; higher
6764performance is achieved at the expense of a new interface.
6765The interfaces you’ve learned can be applied to a wide variety of new
6766sensors including climate (temperature/pressure/humidity), position and inertial (accelerometer/gyroscope/magnetometer/GPS), force (flex sensors) – I’ll
6767discuss some of these, but a useful step is to peruse the offerings of companies
6768such as Sparkfun while noting the interfaces their modules require. The basic
6769serial interface enables the use of various wireless communication devices including bluetooth, wifi, and GSM (cell phone) while the SPI interface enables
6770the use of low-power radio devices. Finally timers provide the key to motion
6771control including stepper motor and DC control with position feedback.
6772This chapter is intended primarily to illustrate the world your new skills
6773enable – not as definitive guide to interfacing and using new modules; that
6774job is up to you.
6775Revision: 14c8a1e (2016-06-05) 235
6776CHAPTER 17. NEXT STEPS
677717.1 Processors
6778The STM32 F100 micro-controller used on the VL Discovery board is
6779one member of a series of STM32 F1xx components which includes:
6780• Value line STM32 F100 – 24 MHz CPU with motor control and CEC
6781functions
6782• Access line STM32 F101 – 36 MHz CPU, upt to 1 MByte Flash
6783• USB Access line STM32 F102 – 48 MHz with USB file system
6784• Performance line STM32 F103 – 72 MHz, up to 1 Mbyte Flash with
6785motor control, USB and CAN
6786• Connectivity line STM32 F105/STM32 F107 – 72 MHz CPU with Ethernet MAC, CAN and USB 2.0 OTG
6787All of these lines of components utilize the same standard peripheral
6788libraries. They do require modifications to the linker script (particularly the
6789definitions of memory regions) and startup code (the definitions of exception
6790vectors); however neither task is difficult. They also include peripherals that
6791you have not seen including support for external memory (FSMC), a higher
6792level SD interface (SDIO) and communication interfaces such as USB, Ethernet, and CAN. The communication interfaces generally require significant
6793additional software libraries and can be very difficult (e.g. USB) to debug.
6794All of the examples from this book should work without modification
6795on any processor from the the STM32F1xx families. A few changes will be
6796required to the files in the template directory provided with this book. The
6797linker script from STM32-Template needs the following modification:
6798MEMORY
6799{
6800RAM (rwx) : ORIGIN = 0x20000000 , LENGTH = 8K
6801FLASH (rx) : ORIGIN = 0x08000000 , LENGTH = 128K
6802}
6803[frame=none]
6804The lengths of the two memory regions should be modified to reflect the
6805component being use. Makefile.common needs to have its LDSCRIPT, PTYPE,
6806STARTUP variables modified as appropriate. Finally, the vector table in
6807startup_stm32f10x.c will need to be updated to reflect the vectors in the
6808236 Revision: 14c8a1e (2016-06-05)
680917.1. PROCESSORS
6810part family being used. The standard peripheral library includes assembly
6811language startup files that may serve as a guide. Note that the vector table
6812ends with a “magic” number that is necessary if you build projects to boot
6813out of SRAM.
6814There are additional STM32 families including STM32 F0 (Cortex-M0
6815based), STM32 L1 (Ultra low-power Cortex-M3), STM32 F2 (high performance Cortex-M3 – 120MHz), and STM32 F4/F3 (Cortex-M4 based). Each
6816of these requires using a different standard peripheral library. Although many
6817of the peripherals are the same or enhancements of those in the STM32 F1
6818series, some care will be required to port the code in this document to these
6819devices. There are extremely attractive “discovery boards” for the STM32 L1,
6820STM32 F0, and STM32 F4 parts which are worth investigating. At this time,
6821the gdb interface code used in this document supports all but the STM32
6822F0 device; however, it appears that openocd openocd.sourceforge.net can
6823support them all.
6824For the reasons described above, the simplest upgrade from the STM32F100
6825is another member of the STM32F1xx family. Sparkfun sells a header board
6826for the STM32F103 with 20K bytes of RAM and 128K bytes of flash for approximately $40. – the same board is also carried by Mouser. This board,
6827produced by Olimex, also has a USB connector as the STM32F103 has a USB
6828slave peripheral (not for the faint of heart !). Several similar development
6829boards are available from various ebay vendors for $15-$25. For roughly $30
6830it is possible to buy an STM32F103 board with a 2.8” TFT touch-screen
6831on ebay. There are excellent value and support high performance graphics
6832through the FSMC parallel interface peripheral of the STM32F103.
6833Most of the readily available STM32 boards provide a standard JTAG
6834connector for the debugger interface. While it is feasible to use the STM32VL
6835Discovery board to communicate with this interface, the wiring issues may
6836become annoying. ST sells a separate ST-LINK/V2 debugger module which
6837interfaces directly to the JTAG connector. This module is available from both
6838Mouser (www.mouser.com) and Digikey (www.digikey.com) for approximately
6839$22 and would be a good investment for working with STM32 boards. The
6840ST-link/V2 protocol is supported by the gdb driver used in this document –
6841indeed it cause fewer issues in an OS X or Linux environment that the V1
6842protocol.
6843As mentioned above, more powerful displays generally require using a
6844parallel interface such as the FSMC provided by the STM32 F103. Taking
6845advantage of the enhanced capabilities requires a more sophisticated graphics
6846Revision: 14c8a1e (2016-06-05) 237
6847CHAPTER 17. NEXT STEPS
6848library. There are a number of open-source and commercial libraries available. ST provide an STM32 library [22]. While the STM32 library includes a
6849hardware abstraction layer (HAL) which can be modified to support various
6850devices including LCDs, touch-screens, and joysticks.
6851Recently ST Microelectronics has released discovery boards with STM32F4
6852and STM32F3 micro-controllers. These are amazing value. For example, the
6853STM32F3 Discovery board includes a 9 degree inertial motion unit (accelerometer, gyroscope, compass) for less than $15. The biggest barrier to entry will
6854be the need to adapt to a new standard peripheral library. While I am confident that the examples from this book will port with modest work, some
6855peripherals may have changed considerably – for example the initialization of
6856the GPIO pins has additional parameters.
685717.2 Sensors
6858There are many sensors available that have SPI, I2C, or analog interfaces. In this section we discuss a few of these. Interested readers should
6859peruse the Sparkfun site for ideas.
6860Position/Inertial Measurement
6861ST, Analog devices, and Freescale all make accelerometer devices –
6862many of these are supported by break-out boards from Sparkfun.com which
6863provides a handy buying guide http://www.sparkfun.com/tutorials/167.
6864In general, these devices use I2C, SPI, or analog interfaces. A complete “inertial measurement unit” generally contains a 3-axis accelerometer, 3-axis gyroscope, and 3-axis magnetometer; ST produces a module containing all three
6865of these devices in a DIP form-factor (STEVAL-MKI108V2) which is available
6866from Mouser for $29.
6867Another useful position sensing device is a GPS receiver. Sparkfun sells
6868a nice unit based upon the Venus638FLPx for $50. Like most such units, this
6869communicates with asynchronous serial – simply hook it up to a UART.
6870Environmental Sensors
6871Environmental sensors include temperature, humidity, and pressure.
6872These are widely available with I2C interfaces, although some such as Maxim/Dallas 1-wire devices require a special protocol. The 1-wire protocol is not
6873directly supported by the STM32 peripherals, but can be implemented with
6874238 Revision: 14c8a1e (2016-06-05)
687517.3. COMMUNICATION
6876timers and GPIO; the Saleae Logic includes a protocol analyzer for 1-wire devices. Note that there are several similar, but incompatible 1-wire style buses;
6877however, most are relatively simple.
6878In addition to digital protocols, environmental sensors frequently produce an analog signal. Examples include the various gas sensors (alcohol,
6879carbon monixide, hydrogen,...) sold by Sparkfun and others.
6880Motion and Force Sensors
6881There are many force/position sensors whose resistance varies with input. Measuring these requires a reference voltage and resistance to translate
6882the sensor resistance to an analog voltage.
6883ID – Barcode/RFID
6884Sparkfun and others sell RFID and barcode readers with serial and I2C
6885interfaces.
6886Proximity
6887Proximity sensors include both ultrasonic and infrared ranging modules.
6888We have demonstrated the use of ultrasonic sensors in Chapter 10. Reflective
6889IR sensors frequently require a digital output to power an LED and an analog
6890input to measure the reflected light intensity.
689117.3 Communication
6892Many interesting projects require enhanced communication either wireless or wired. In the wireless domain, inexpensive modules bluetooth, wifi,
6893and even GSM cellular phones are available with serial interfaces. For low
6894power applications, dedicated radio links such as the Nordic nRF24L01 utilize
6895SPI interfaces. Finally, it is relatively easy to interface to standard infrared
6896remote controls with a simple IR detector.
689717.4 Discussion
6898I hope the ideas discussed in this chapter give you some idea of the
6899possibilities. There is a vibrant maker community that can provide practical
6900guidance – you might seek out examples developed for the arduino platform.
6901Revision: 14c8a1e (2016-06-05) 239
6902CHAPTER 17. NEXT STEPS
6903I believe the techniques presented in this book will give you a firm foundation
6904for experimenting
6905240 Revision: 14c8a1e (2016-06-05)
6906Attributions
6907Figure 1.10 was obtained from http://commons.wikimedia.org/wiki/
6908File:Potentiometer.jpg under the Creative Commons Attribution-Share
6909Alike 3.0 Unported license (http://creativecommons.org/licenses/by-sa/
69103.0/deed.en). This image is also used in Figure 14.1
6911Figure 1.6 is covered by the Creative Commons Attribution-NonCommercialShareAlike 3.0 Unported license. The image is due to www.sparkfun.com.
6912Revision: 14c8a1e (2016-06-05) 241
6913
6914Bibliography
6915[1] ARM Limited. Cortex-M3 technical reference manual, 2006.
6916[2] ARM Limited. Procedure call standard for the ARM® architecture, October 2009. IHI 0042D.
6917[3] ChaN. FatFs generic FAT file system module, 2011. http://elm-chan.
6918org/fsw/ff/00index_e.html. Accessed April 2012.
6919[4] F. Foust. Secure digital card interface for the MSP430, 2004.
6920http://alumni.cs.ucr.edu/~amitra/sdcard/Additional/sdcard_
6921appnote_foust.pdf. Accessed July 2012.
6922[5] J. Jiu. The Definitive guide to the ARM Cortext-M3. Newnes, 2010.
6923[6] Microchip. 25AA160A/25LC160A 16K SPI bus serial EEPROM, 2004.
6924[7] NXP. ı2c bus specification and user manual (rev 03), June 2007.
6925UM10204.
6926[8] C. Philips. Read wii nunchuck data into arduino. http://www.
6927windmeadow.com/node/42. Accessed February 4, 2012.
6928[9] SD specifications, part 1, physcial layer simplified specification, version
69293.01, May 2010.
6930[10] F. Semiconductor. Tilt sensing using linear accelerometers, 2012.
6931[11] Sitronix Technology Corporation. Sitronix st7735r 262k color single-chip
6932TFT controller/driver, 2009.
6933[12] STMicroelectronics. How to get the best ADC accuracy in the
6934STM32F10xxx devices, November 2008.
6935[13] STMicroelectronics. STM32F10xxx ı2c optimized examples, 2010.
6936Revision: 14c8a1e (2016-06-05) 243
6937BIBLIOGRAPHY
6938[14] STMicroelectronics. User manual STM32 value line discovery, 2010.
6939UM0919.
6940[15] STMicroelectronics. Low & medium-density value line, advanced ARMbased 32-bit MCU with 16 to 128 kb flash, 12 timers, ADC, DAC & 8
6941comm interfaces, 2011. Doc ID 16455.
6942[16] STMicroelectronics. Migrating a microcontroller application from
6943STMF1 to STM32F2 series, 2011. AN3427: Doc ID 019001.
6944[17] STMicroelectronics. Migrating a microcontroller application from
6945STMF1 to STM32L1 series, 2011. AN3422: Doc ID 018976.
6946[18] STMicroelectronics. Migration and compatibility guideslines for STM32
6947microcontroller applications, 2011. AN3364: Doc ID 018608.
6948[19] STMicroelectronics. Programming manual: Stm32f10xxx/ 20xxx/
694921xxx/ l1xxxx cortex-m3 programming manual, March 2011. PM0056.
6950[20] STMicroelectronics. Reference manual stm32f100xx advanced ARMbased 32-bit MCUs rev. 4, 2011. RM0041.
6951[21] STMicroelectronics. Reference manual stm32f101xx stm32f102xx
6952stm32f103xx stm32f105xx and stm32f107xx advanced ARM-based 32-bit
6953MCUs rev. 14, 2011.
6954[22] STMicroelectronics. STM32 embedded graphic objects/touchscreen library, 2011.
6955[23] wiibrew. Wiimote/Extension Controllers. http://wiibrew.org/wiki/
6956Wiimote/Extension_Controllers. Accessed February 6, 2012.
6957[24] wikipedia. Wii remote. http://en.wikipedia.org/wiki/Wii_Remote.
6958Accessed February 2, 2012.
6959244 Revision: 14c8a1e (2016-06-05)