Get Started with the NXP i.MX RT1010 Development Kit

Page 1

> LED and LCDs > ADC > I2C > SPI > PWM > UART > Motor Control > Audio and Digital Audio Processing (DSP)

About the Author Prof Dr Dogan Ibrahim has a BSc degree in electronic engineering, an MSc degree in automatic control engineering, and a PhD degree in digital signal processing. Dogan has worked in many industrial organizations before he returned to academic life. Prof Ibrahim is the author of over 60 technical books and over 200 technical articles on microcontrollers, microprocessors, and related fields. He is a Chartered electrical engineer and a Fellow of the Institution of Engineering Technology.

Get Started with the NXP i.MX RT1010 Development Kit

Conveniently, several on-board debug probes are supplied with the kit allowing you to debug your programs by talking directly to the MCU. Helped by the debugger, you can single-step through a program, insert breakpoints, view and modify variables, and so on. Using the MCUXpresso IDE and the SDK, many working and tested projects are developed in the book based on parts, modules, and technologies, including:

H0W2

At the heart of NXP Semiconductors‘ MIMXRT1010 Development Kit is the i.MX RT1010 Crossover MCU sporting an Arm Cortex-M7 core truly capable of running power- and memory hungry DSP applications. The popular MCUXpresso IDE is key to creating software for the development kit, while a powerful SDK is provided to reduce program development time and effort. The dev kit offers great connectivity through its audio CODECs, 4-way headphone jack, external speaker connection, microphone, and Arduino interface.

H0W2

Volume 3

Get Started with the NXP i.MX RT1010 Development Kit Develop Arm® Cortex®-M7 powered Audio, DSP and Motor Control Projects

Dogan Ibrahim

Dogan Ibrahim

Elektor International Media www.elektor.com

3 Cover HOW2 - Getting Started With NXP iMX Development Board.indd 3

knows how

26-10-2023 10:14



Get Started with the

NXP i.MX RT1010 Development Kit

Develop Arm® Cortex®-M7 powered Audio, DSP and Motor Control Projects

● Dogan Ibrahim

Getting Started with NXP i.MX Development Board - UK.indd 3

26-10-2023 09:34


● This is an Elektor Publication. Elektor is the media brand of Elektor International Media B.V.

PO Box 11, NL-6114-ZG Susteren, The Netherlands Phone: +31 46 4389444

● All rights reserved. No part of this book may be reproduced in any material form, including photocopying, or

storing in any medium by electronic means and whether or not transiently or incidentally to some other use of this publication, without the written permission of the copyright holder except in accordance with the provisions of the Copyright Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licencing Agency Ltd., 90 Tottenham Court Road, London, England W1P 9HE. Applications for the copyright holder's permission to reproduce any part of the publication should be addressed to the publishers.

● Declaration The author, editor, and publisher have used their best efforts in ensuring the correctness of the information contained in this book. They do not assume, and hereby disclaim, any liability to any party for any loss or damage caused by errors or omissions in this book, whether such errors or omissions result from negligence, accident or any other cause. All the programs given in the book are Copyright of the Author and Elektor International Media. These programs may only be used for educational purposes. Written permission from the Author or Elektor must be obtained before any of these programs can be used for commercial purposes.

● British Library Cataloguing in Publication Data

A catalogue record for this book is available from the British Library

● ISBN 978-3-89576-582-7 Print ISBN 978-3-89576-583-4

eBook

● © Copyright 2023: Elektor International Media B.V. Editor: Clemens Valens

Prepress Production: D-Vision, Julian van den Berg Print: Ipskamp Printing, Enschede (NL)

Elektor is the world's leading source of essential technical information and electronics products for pro engineers, electronics designers, and the companies seeking to engage them. Each day, our international team develops and delivers high-quality content - via a variety of media channels (including magazines, video, digital media, and social media) in several languages - relating to electronics design and DIY electronics. www.elektormagazine.com

●4

Getting Started with NXP i.MX Development Board - UK.indd 4

26-10-2023 09:34


Contents

Contents Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Chapter 1 • The MIMXRT1010 Evaluation Kit (EVK) . . . . . . . . . . . . . . . . . . . . . . . . 10 1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2 The MIMXRT1010 Evaluation Kit hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2.1 The i.MX RT1010 processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2.2 ON/OFF button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.2.3 Reset button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.2.4 User button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.2.5 LED indicators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.2.6 JTAG connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.2.7 Audio input/output connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.2.8 Power supply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.2.9 Digital and analog modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.3 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Chapter 2 • Installing the Mcuxpresso Software . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.2 Installing the MCUXpresso SDK and IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.3 Testing the installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.4 Creating a project from scratch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.6 Importing an exported project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.7 MCUXpresso for Visual Studio Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Chapter 3 • Simple Program Examples and Debugging . . . . . . . . . . . . . . . . . . . . . 30 3.1 Software only programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.2 Example 1 – Sum of integer numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.3 Example 2 – Table of squares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.4 Example 3 – Centigrade to Fahrenheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.5 Example 4 – Times table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.6 Example 5 – Table of trigonometric sine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.7 Example 6 – Table of trigonometric sine, cosine and tangent . . . . . . . . . . . . . . . . 40 3.8 Example 7 – Integer calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

●5

Getting Started with NXP i.MX Development Board - UK.indd 5

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit 3.9 Example 8 – Solution of a quadratic equation . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.10 Example 9 – Squares and cubes of numbers . . . . . . . . . . . . . . . . . . . . . . . . . . 46 3.11 Example 10 – Factorial of a number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.12 Debugging a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.12.1 Example debug session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Chapter 4 • LED Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 4.2 Project 1 – Flashing an external LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.3 Project 2 – LED flashing as Morse SOS signal . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 4.4 Project 3 – Alternately flashing two LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.5 Project 4 – Chasing LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.5.1 More efficient program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 4.5.2 Using PortClear and PortSet functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 4.6 Project 5 – Binary counting LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.7 Project 6 – Random flashing LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 4.8 Project 7 – Lucky day of the week . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 4.9 Project 8 – Binary up/down counter with LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . 90 4.10 Project 9 – Binary event counter with LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Chapter 5 • 7-Segment LED Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.2 7-Segment LED display structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.3 Project 1 – 7-Segment 1-digit LED counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 5.4 Project 2 – 7-Segment 4-digit multiplexed LED display . . . . . . . . . . . . . . . . . . . 102 5.5 Project 3 – 7-Segment 4-digit multiplexed LED display counter – timer interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 5.6 Project 4 – 7-Segment 4-digit multiplexed LED display counter – blanking leading zeroes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Chapter 6 • Using Serial Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 6.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 6.2 Project 1 – Serial communication between the MIMXRT1010-EVK Development Kit and an Arduino UNO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Chapter 7 • I²C Bus Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 7.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

●6

Getting Started with NXP i.MX Development Board - UK.indd 6

26-10-2023 09:34


Contents 7.2 The I²C Bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 7.3 Project 1 – Port expander . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 7.4 Project 2 – TMP102 temperature sensor chip . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Chapter 8 • SPI Bus Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 8.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 8.2 Project 1 – Port expander . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Chapter 9 • Using LCDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 9.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 9.2 The HD44780 LCD module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 9.3 Project 1 – Displaying text on LCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 9.4 Project 2 – Using LCDs – simple up counter . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 9.5 Including the LCD codes in a program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 9.6 Project 3 – Using LCDs – simple up counter – including LCD header file . . . . . . . 180 9.7 Project 4 – LCD-based conveyor belt goods counter . . . . . . . . . . . . . . . . . . . . . 182 9.8 Project 5 – Event counter – using external interrupts . . . . . . . . . . . . . . . . . . . . 187 Chapter 10 • Analog-To-Digital Converter (ADC) . . . . . . . . . . . . . . . . . . . . . . . . . 191 10.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 10.2 Project 1 – Voltmeter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 10.3 Project 2 – Analog temperature sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 10.4 Project 3 – ON/OFF temperature controller . . . . . . . . . . . . . . . . . . . . . . . . . . 201 10.5 Project 4 – ON/OFF temperature controller – using LCD . . . . . . . . . . . . . . . . . . 206 10.6 Project 5 – Measuring the ambient light intensity . . . . . . . . . . . . . . . . . . . . . . 211 10.7 Project 6 – Ohmmeter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Chapter 11 • Using Pulse Width Modulation (PWM) . . . . . . . . . . . . . . . . . . . . . . . 220 11.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 11.2 Basic theory of the pulse width modulation . . . . . . . . . . . . . . . . . . . . . . . . . . 220 11.3 Features of the i.MXRT1010 processor PWM . . . . . . . . . . . . . . . . . . . . . . . . . . 222 11.4 Operation of the PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 11.5 Project 1 – Mosquito repeller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Chapter 12 • Electric Motors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 12.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 12.2 Project 1 – Two-speed motor speed control . . . . . . . . . . . . . . . . . . . . . . . . . . 232

●7

Getting Started with NXP i.MX Development Board - UK.indd 7

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit 12.3 Project 2 – Varying the motor speed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 12.4 Project 3 – Changing the speed and motor direction . . . . . . . . . . . . . . . . . . . . 244 Chapter 13 • Using the CMSIS-DSP Library. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 13.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 13.2 Project 1 – Matrix addition, multiplication, and transpose . . . . . . . . . . . . . . . . 255 Chapter 14 • Sound and Audio Signal Processing (DSP) . . . . . . . . . . . . . . . . . . . 262 14.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 14.2 Analog and digital audio sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 14.3 Digital audio sound file formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 14.3.1 Uncompressed audio file formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 14.3.2 Audio files with lossy compressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 14.3.3 Audio files with lossless compressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 14.3.4 Which audio file format to choose? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 14.3.5 High-quality digital audio sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 14.4 Audio digital signal processing (Audio DSP) . . . . . . . . . . . . . . . . . . . . . . . . . . 265 14.4.1 The SAI module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 14.4.2 The I2S bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 14.4.3 The SAI bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 14.5 MIMXRT1010-EVK development kit audio demo project files . . . . . . . . . . . . . . 269 Chapter 15 • References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

●8

Getting Started with NXP i.MX Development Board - UK.indd 8

26-10-2023 09:34


Preface It is becoming important for microcontroller users to adapt to new technologies quickly and learn the architecture and use of high-performance 32-bit microcontrollers. Several manufacturers offer 32-bit microcontrollers as general-purpose processors in embedded applications. For example, companies like NXP Semiconductors, STMicroelectronics and several others offer Arm-based processors for high-speed professional applications. Arm offers 32-bit and 64-bit processors, mainly for embedded applications. Nowadays, the majority of mobile devices such as mobile phones, tablets, and GPS receivers are based on Arm processors. The low cost, low-power consumption, and high performance of Arm processors make them ideal candidates for use in complex communication and mixed-signal applications. This book is about the use of the MIMXRT1010-EVK development kit developed by NXP Semiconductors. This is a two-layer low-cost through-hole USB-powered PCB. At its heart lies the i.MX RT1010 crossover MCU in an 80LQFP package, featuring NXP's advanced implementation of the Arm Cortex-M7 core. This core operates at speeds of up to 500 MHz to provide high CPU performance and best real-time response. It is supported by Zephyr OS for developing the Internet of Things with a free, open-source embedded operating system. The popular MCUXpresso IDE can be used for the development of software for the development kit. Additionally, a powerful SDK is provided which simplifies program development greatly. The kit is shipped with the MIMXRT1011DAE5A MCU, providing 128-Mbit QSPI flash memory, 64 KB ROM, 128 KB RAM, audio codec, 4-way headphone jack, external speaker connection, microphone, ADC, UART, SPI, I2C and additional peripheral support. The board also supports Arduino UNO form factor header pins, making it compatible with many Arduino shields, though NXP also provides dedicated shields for brushless DC and PMSM motor control and LED matrix driver applications. Conveniently, several on-board debug probes are supplied with the kit allowing you to debug your programs by talking directly to the MCU. Helped by the debugger, you can single step through a program, insert breakpoints, view and modify variables and so on. Many working and tested projects have been developed in the book using the popular MCUXpresso IDE and the SDK with various sensors and actuators. The project descriptions, block diagrams, circuit diagrams, complete program listings, and detailed descriptions of all the developed programs are given in the book for all the projects. Use of the popular CMSIS-DSP library is also explained with several matrix operations. The author hopes that readers use the MIMXRT1010-EVK development kit in their future projects. The projects provided in the book can be used without modifications in many applications. Alternatively, readers can base their projects on the ones provided in the book during the development of their projects. Hope you enjoy reading the book. Dr. Dogan Ibrahim London, 2023

●9

Getting Started with NXP i.MX Development Board - UK.indd 9

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 1 • The MIMXRT1010 Evaluation Kit (EVK) 1.1 Overview The MIMXRT1010 Evaluation Kit (EVK) is an entry-level board, based on the NXP Semiconductor i.MX RT1010 Processor that is fully supported by NXP Semiconductor. This book provides detailed information and various projects on using this evaluation kit. In this chapter you will get to know the most commonly used features of the MIMXRT1010 Evaluation Kit.

1.2 The MIMXRT1010 Evaluation Kit hardware Figure 1.1 shows the MIMXRT1010 evaluation kit. The board features are shown in Table 1.1. The board includes the i.MX RT1010 500 MHz ARM Cortex-M7 Core processor, a large amount of memory, audio (SPDIF and I2S), debug, and USB connectors, Arduino compatible interface, user button, user LED, and a motion sensor.

Table 1.1 MIMXRT1010 board features

● 10

Getting Started with NXP i.MX Development Board - UK.indd 10

26-10-2023 09:34


Chapter 1 • The MIMXRT1010 Evaluation Kit (EVK)

Figure 1.1 The MIMXRT Evaluation Kit. Figure 1.2 shows the block diagram of the Evaluation Kit.

Figure 1.2 Block diagram of the Evaluation Kit.

1.2.1 The i.MX RT1010 processor At the heart of the evaluation kit is the ARM Cortex-M7 Core i.MX RT1010 processor. This is a fast 500 MHz processor with the following features (see Figure 1.3): • Full-featured Floating-Point Unit (FPU) • 128 KB on-chip RAM • 64 KB boot ROM • External memory interface

● 11

Getting Started with NXP i.MX Development Board - UK.indd 11

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

• Two General Programmable Timers (GPT), 4-channel 32-bit resolution each • 4× Watchdogs • 4× Periodic Interrupt Timer (PIT) • FlexPWM • SPDIF audio input and output • 2× I2S, AC97, TDM and Codec/DSP audio interfaces • MQS medium quality audio interface (via GPIO ports) • 2× I2C and 2 x SPI interfaces • 4× UART interfaces • 1× 15-channel Analog-to-Digital Converter (ADC) • 44× GPIO with interrupt capability and FlexIO • Temperature sensor with programmable trim points • Arm® Cortex®-M7 CoreSight debug and trace architecture • Trace Port Interface Unit (TPIU) to support off-chip real-time trace • Support for 5-pin JTAG and SWD debug interfaces • AES-128, SHA-1, SHA-256 and CRC-32 • True random number generation (TRNG) • Real-time clock (RTC) • Secure JTAG controller • Power management controller

Figure 1.3 Features of the i.MXRT 1010 MCU.

1.2.2 ON/OFF button A short pressing of the ON/OFF button turns ON power to the board. A short pressing while in the ON mode generates an interrupt. To turn OFF power, keep the button pressed for approximately 5 seconds.

1.2.3 Reset button There are two Reset buttons. SW9 is the Power Reset button. Pressing the SW9 in the Power ON state will force resetting the system power except for the SNVS domain. The processor will be immediately turned OFF and reinitiate a boot cycle from the Processor Power OFF state. SW3 is the standard POR Reset button.

● 12

Getting Started with NXP i.MX Development Board - UK.indd 12

26-10-2023 09:34


Chapter 1 • The MIMXRT1010 Evaluation Kit (EVK)

1.2.4 User button SW4 is the user button (see Figure 1.1) (GPIO_SD_05 by default) to be used by the developers. Pressing this button changes the state of the port from logic HIGH to LOW.

1.2.5 LED indicators The following LEDs are mounted on the board: • User LED at D25 (turned ON when logic HIGH is applied to GPIO_11) • Main power LED at D27 • Reset LED at D7 • OpenSDA LED at D5

1.2.6 JTAG connector J55 is a standard 10-pin/1.27 mm boxheader Connector for JTAG. The pin definitions are shown in Figure 1.4, support SWD by default.

Figure 1.4 JTAG pin definitions.

1.2.7 Audio input/output connector The audio CODEC used on the MIMXRT1010 EVK Board is Wolfson's Low Power, high-quality Stereo Codec, WM8960. The MIMXRT1010 EVK Board includes one headphone interface (J11), one on-board MIC (P1), two speaker interfaces (J12, J13), and the SPDIF interface (top of the board, J52 & J53, DNP). J11 is a 3.5 mm audio stereo headphone jack, which supports jack detect.

1.2.8 Power supply J41 and J9 (see Figure 1.1) can be used to power the EVK Board. A 5 VDC external power supply can also be used to power the EVK Board by connecting two pins in J1. Different power supplies need different jumper settings of J1. Table 1.2 shows the details.

Table 1.2 Power selection.

● 13

Getting Started with NXP i.MX Development Board - UK.indd 13

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

1.2.9 Digital and analog modules The i.MX RT1010 processors contain various digital and analog modules. A list of all the modules is detailed in the following NXP document: i.MX RT1010 Crossover Processors Data Sheet for Industrial Products, Document Number: IMXRT1010IEC Rev. 0, 09/2019 Some modules are described below. ADC1: The ADC is a 12-bit general-purpose analog to digital converter. DAP: The DAP provides real-time access for the debugger without halting the core to: System memory and peripheral registers and all debug configuration registers. The DAP also provides debugger access to JTAG scan chains. The DAP module is internal to the Cortex-M7 Core Platform. FlexIO1: The FlexIO is capable of supporting a wide range of protocols including, but not limited to: UART, I2C, SPI, I2S, camera interface, display interface, PWM waveform generation, etc. The module can remain functional when the chip is in a low-power mode, provided the clock it is using remains active. FlexPWM1: The pulse-width modulator (PWM) contains four PWM submodules, each of which is set up to control a single half-bridge power stage. Fault channel support is provided. The PWM module can generate various switching patterns, including highly sophisticated waveforms. FlexSPI: FlexSPI acts as an interface to one or two external serial flash devices, each with up to four bidirectional data lines. GPIO1 GPIO2 GPIO5: Used for general purpose input/output to external ICs. Each GPIO module supports up to 32 bits of I/O. GPT1 GPT2: Each GPT is a 32-bit 'free running' or 'set and forget' mode timer with programmable prescaler and compare and capture register. A timer counter value can be captured using an external event and can be configured to trigger a capture event on either the leading or trailing edges of an input pulse. When the timer is configured to operate in 'set and forget' mode, it is capable of providing precise interrupts at regular intervals with minimal processor intervention. The counter has output compare logic to provide the status and interrupt at comparison. This timer can be configured to run either on an external clock or on an internal clock. KPP: The KPP is a 16-bit peripheral that can be used as a keypad matrix interface or as general-purpose input/output (I/O). It supports an 8 × 8 external keypad matrix. The main features are: Multiple-key detection, long key-press detection, Standby key-press detection. Supports a 2-point and 3-point contact key matrix.

● 14

Getting Started with NXP i.MX Development Board - UK.indd 14

26-10-2023 09:34


Chapter 1 • The MIMXRT1010 Evaluation Kit (EVK)

LPI2C1 LPI2C2: The LPI2C is a low power Inter-Integrated Circuit (I²C) module that supports an efficient interface to an I²C bus as a master. The I²C provides a method of communication between a number of external devices. LPUART1 LPUART2 LPUART3 LPUART4: Each of the UART modules support the following serial data transmit/receive protocols and configurations: 7- bit or 8-bit data words, 1 or 2 stop bits, programmable parity (even, odd or none) and programmable baud rates up to 5 Mbps. PIT: The PIT features a 32-bit counter timer, programmable count modules, clock division, interrupt generation, and a slave mode to synchronize count enable for multiple PITs. SAI1 SAI3: The SAI module provides a synchronous audio interface (SAI) that supports full duplex serial interfaces with frame synchronization, such as I2S, AC97, TDM, and codec/ DSP interfaces. SA-TRNG: The SA-TRNG is a hardware accelerator that generates a 512-bit entropy as needed by an entropy consuming module or by other post-processing functions. Temp Monitor: The temperature sensor implements a temperature sensor/conversion function based on a temperature-dependent voltage to time conversion. WDOG1 WDOG2 WDOG3: The Watch Dog Timer supports two comparison points during each counting period. Each of the comparison points is configurable to evoke an interrupt to the Arm core, and a second point evokes an external event on the WDOG line.

1.3 Getting started The board is supplied with a Micro-B USB cable. A demo program is preloaded to the demo kit. Connect the board to a PC using the supplied cable. The demo program flashes the on-board LED. Figure 1.5 shows connecting the board to a PC. The green user LED at the central part of the board should start to flash.

Figure 1.5 Connecting the board to a PC.

● 15

Getting Started with NXP i.MX Development Board - UK.indd 15

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 2 • I nstalling the MCUXpresso Software Development Kit (SDK) 2.1 Overview In this book, we will be using the MCUXpresso SDK and the IDE for developing projects using the development board. MCUXpresso IDE is an Eclipse-based development environment for NXP MCUs using Cortex-M cores. It supports the i.MX RT, LPC and Kinetis devices, from Cortex-M0+ to up to Cortex-M7. The SDK and the IDE must be installed before they can be used.

2.2 Installing the MCUXpresso SDK and IDE The steps to install the MCUXpresso SDK and IDE are given below: • Go to following website: https://www.nxp.com/design/software/development-software/mcuxpressosoftware-and-tools-/mcuxpresso-integrated-development-environmentide:MCUXpresso-IDE?tid=vanMCUXPRESSO/IDE • Click on DOWNLOADS (Figure 2.1)

Figure 2.1 Click on DOWNLOADS • Click on DOWNLOAD to download the IDE (Figure 2.2)

Figure 2.2 Click to download the IDE • Select your operating system as shown in Figure 2.3 and click to download the IDE

Figure 2.3 Select your operating system

● 16

Getting Started with NXP i.MX Development Board - UK.indd 16

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

• Save the file in a folder, unzip it, and click to install it • Run the program by double-clicking on it • Click Download and Install SDKs (Figure 2.4)

Figure 2.4 Click to install SDK • Select the development board as shown in Figure 2.5

Figure 2.5 Select the development board • Click Import SDK Examples • Select examples from the list and click Finish • Download the driver from the following site. At the time of writing this book, it was called: mbedWinSerial_16466.exe. Click to install it: https://www.nxp.com/document/guide/getting-started-with-i-mx-rt1010evaluation-kit:GS-MIMXRT1010-EVK This completes the installation of the MCUXpresso and the IDE.

2.3 Testing the installation Now that the installation is complete, you should check the installation by compiling and running one of the demo programs supplied. Here, you will compile and run the demo example called iled_blinky which flashes the on-board LED. The steps are as follows: • Start the IDE • Select Workspace evkmimxrt1010_iled_blinky (Figure 2.6)

● 17

Getting Started with NXP i.MX Development Board - UK.indd 17

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 2.6 Select the iled_blinky workspace • Click IDE to load the source file (Figure 2.7)

Figure 2.7 Click IDE • You should see the File Explorer in the left window, the program code in the middle window, the header filenames and functions used in the right-hand window, and the console terminal, etc. at the bottom of the window (Figure 2.8). Do not worry if you do not understand how the program works at this stage.

Figure 2.8 The IDE window • The default program is set to flash the on-board LED every second. Let's change the flashing rate to 250 ms. Scroll down and locate the second 'while' statement in the main program. Change 1000U to 250U as shown in Figure 2.9

● 18

Getting Started with NXP i.MX Development Board - UK.indd 18

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

Figure 2.9 Change the delay to 250 ms • The program can be uploaded to the development kit and run either in Debug mode or in Release mode. To compile and upload in Release mode, click Project → Build Configurations → Set Active → Release • Click Project → Build Project to build the project. You should see a successful compilation message at the bottom of the screen (Figure 2.10). Make sure the bottom part of the screen is set to Console mode.

Figure 2.10 Project built successfully message • You now have to upload the code to the processor on the development kit. Click Release to expand the folder. Connect USB connector J41 of the development board to your PC. You should see a new drive with the name RT1010-EVK(E:) appear in your devices (The drive letter E: may be different in your computer). • Copy file evkmimxrt1010_iled_blinky.axf and paste it to the new drive RT1010EVK(E:). Initially, nothing seems to happen. Then, press the reset button and after a few seconds, you should see the red LED flashing on the development board during the program loading process. Note, if you have difficulty copying the .axf file to the board, you may have to reinstall the WinUSB driver and remove and reinstall the mbed serial port driver (see https://github.com/ ARMmbed/DAPLink/issues/487). • The .axf file contains both the debug code and running binary code. Alternatively, you can convert the .axf file into a smaller binary file and upload it to the development kit. To achieve this, right-click on the .axf file and select Binary Utilities, followed by Create binary. Copy the .bin file and paste it onto the drive RT1010-EVK (E:).

● 19

Getting Started with NXP i.MX Development Board - UK.indd 19

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

• Press the Reset button at the bottom right of the development board. You should now see the on-board LED flashing every 250 ms. • Alternatively, to run the program in Debug mode, click the Debug button under MCUXpresso IDE – Quickstart Panel at the bottom left-hand corner (pull up the Quickstart Panel if you can't see the debug button). When the debugger is ready, click Run followed by Resume to run the program in debug mode. Click Run followed by Terminate to stop the program. Some information on the program The program generates interrupts at every 250 ms and then the state of the LED is changed. Notice that at the beginning of the program the following header files are included: #include "pin_mux.h" #include "clock_config.h" #include "board.h"

You can right-click on the filenames the right-hand side of the window and display the contents of these files if you wish. File pin_mux.h stores the I/O direction definitions. File clock_config.h stores the clock definitions. File board.h stores the board name, debug and UART configurations, on-board accelerator configurations, user LED configurations, user Button configuration and other configurations. Here we are interested in the user LED configurations, which are defined as follows: /*! @brief The USER_LED used for board */ #define LOGIC_LED_ON (0U) #define LOGIC_LED_OFF (1U) #define BOARD_USER_LED_GPIO GPIO1 #define BOARD_USER_LED_GPIO_PIN (11U)

Logic HIGH and LOW are defined as 0U and 1U, respectively. The on-board user LED GPIO is defined as GPIO1, with the pin number defined as 11 (GPIO_11). Some other on-board LED based definitions are: #define USER_LED_INIT(output) GPIO_PinWrite(BOARD_USER_LED_GPIO, BOARD_USER_LED_ GPIO_PIN, output); BOARD_USER_LED_GPIO->GDIR |= (1U << BOARD_USER_LED_GPIO_PIN)

#define USER_LED_OFF() GPIO_PortClear(BOARD_USER_LED_GPIO, 1U << BOARD_USER_LED_GPIO_PIN)

#define USER_LED_ON() GPIO_PortSet(BOARD_USER_LED_GPIO, 1U << BOARD_USER_LED_GPIO_PIN)

● 20

Getting Started with NXP i.MX Development Board - UK.indd 20

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

#define USER_LED_TOGGLE()

GPIO_PinWrite(BOARD_USER_LED_GPIO,

BOARD_USER_LED_GPIO_PIN, 0x1 ^ GPIO_PinRead(BOARD_USER_LED_GPIO,BOARD_USER_LED_GPIO_PIN))

The function GPIO_PinWrite() sets the output state of a port pin to logic LOW or HIGH. Delay is introduced using function SysTick_DelayTicks(). This function waits until the value specified in its argument becomes zero. This value is the required delay in milliseconds. Function SysTick_Handler() is called every millisecond, and it decrements variable g_systickCounter by one every time it is called. i.e. every millisecond. Function SysTick_ Config() initializes the system timer and its interrupt, and starts the system tick number. The Counter is in free-running mode and generates periodic interrupts. Its only argument is the number of ticks between two interrupts. Here, it is set to 1 ms. In this program, we could have used the following GPIO SDK function GPIO_PortToggle() to toggle the LED pin. This simplified program is shown in Figure 2.11 /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ #define LED_PIN 11 /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void)

● 21

Getting Started with NXP i.MX Development Board - UK.indd 21

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{ if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } /*! * @brief Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while (1) { /* Delay 250 ms */ SysTick_DelayTicks(250U); GPIO_PortToggle(GPIO1, 1u << LED_PIN); } }

Figure 2.11 Program using the GPIO_PortToggle() function

● 22

Getting Started with NXP i.MX Development Board - UK.indd 22

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

The GPIO ports must be configured before they can be used (e.g. the input or output mode, default state, analog or digital, etc.). This is normally done in files pin_mux.c and pi_mux.h in folder board. This configuration is already done for the on-board LED. You will learn in the next chapter how to configure the GPIO ports using the ConfigTools menu option of MCUXpresso IDE. Some other GPIO-related functions supported by the SDK are (see web link: https://mcuxpresso.nxp.com/api_doc/dev/1393/a00123.html): Initialize a GPIO pin used by the board: GPIO_PinInit() Set the output level of the multiple GPIO pins to logic 1 or 0: GPIO_PinWrite() Set the output level of the multiple GPIO pins to logic 1: GPIO_PortSet() Set the output level of the multiple GPIO pins to logic 0: GPIO_Port_Clear() Reverse the current output logic of the multiple GPIO pins: GPIO_PortToggle() Read the current input value of the GPIO port: GPIO_PinRead() MCUXpresso IDE is a powerful IDE supporting many features. Interested readers can download the 293-page user guide: MCUXpresso IDE User Guide, Rev. 11.7.1 – 28 March 2023 from the NXP website.

2.4 Creating a project from scratch In this section, you will learn how to create a project from scratch. This is an elementary example project where the message Hello From the MIMXRT1010-EVK is displayed on the Console. The aim of this example is to show how a program can be created, uploaded to the development kit, and then be executed. The steps are: • Start the MCUXpresso IDE and enter a workspace name, e.g. SIMPLE, and click Launch • Click IDE • Click Create a new C/C++ project under the Quickstart Panel • Select MIMXRT1010 as shown in Figure 2.12. Click Next

● 23

Getting Started with NXP i.MX Development Board - UK.indd 23

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 2.12 Select MIMXRT1010 • Enter a project name. e.g. MySimple as shown in Figure 2.13. Note that you can select various drivers at this stage if your program needs them. Here, we have left the default drivers. • Select the Semihost for the SDK Debug Console so that PRINTF displays on the Console. Click Finish.

Figure 2.13 Enter a project name • You will be presented with the screen as shown in Figure 2.14.

● 24

Getting Started with NXP i.MX Development Board - UK.indd 24

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

Figure 2.14 MCUXpresso screen (part of the screen is shown) • At the left-hand side, you have the Project Explorer listing all the required project files. The source code is displayed in the middle part of the screen by default. Global variables and header files are displayed at the top right. The bottom part of the screen displays the installed SDKs, Properties, Problems, Console, Terminal, etc. Click to select the Console. • Modify the provided source code as shown in Figure 2.15. /* * Copyright 2016-2023 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file

MySimple.c

* @brief

Application entry point.

*/ #include <stdio.h> #include "board.h" #include "peripherals.h" #include "pin_mux.h" #include "clock_config.h" #include "MIMXRT1011.h" #include "fsl_debug_console.h" /* TODO: insert other include files here. */ /* TODO: insert other definitions and declarations here. */ /*

● 25

Getting Started with NXP i.MX Development Board - UK.indd 25

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

* @brief

Application entry point.

*/ int main(void) { /* Init board hardware. */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitBootPeripherals(); #ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL /* Init FSL debug console. */ BOARD_InitDebugConsole(); #endif PRINTF("Hello From the MIMXRT1010-EVK\r\n"); while(1); }

Figure 2.15 Modified source code • You are now ready to compile and run the program in debug mode. Connect your development kit to your PC. Click Debug at the Quickstart Panel and follow the instructions. Select the default debug probe. Wait until the debugger is ready. By default, the program will highlight the first instruction in main() in green and stop there. • Click Run followed by Resume to run the program. • The program will display the message Hello From the MIMXRT1010-EVK on the console as shown in Figure 2.16.

Figure 2.16 Message displayed on the Console • Click Run followed by Terminate to terminate the debug session

● 26

Getting Started with NXP i.MX Development Board - UK.indd 26

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

Exporting a project You can save your project by clicking File, followed by Export. Select Archive under General and click Next. Click Select All and give a name to your project. Select to save as .zip (Figure 2.17). Click Finish.

Figure 2.17 Export your project

2.6 Importing an exported project All the projects in this book are available as exported projects in the form of .zip files. The steps to import them are as follows: • Start the MCUXpresso IDE by specifying a new workspace name (e.g. test) and click Launch • Click IDE • In Quickstart Panel, click Import project(s) from file system • Click Browse in the top Archive field • Select the required project folder and click Next • Click Finish When accessing the projects in the book, you are recommended to use the workspace name to be the same name as the project name. For example, to import project folder LM35, set the workspace name to LM35. This way, the project programs will be available in your default workspace. The same project files can then easily be started by entering the same workspace name (e.g. LM35).

● 27

Getting Started with NXP i.MX Development Board - UK.indd 27

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

2.7 MCUXpresso for Visual Studio Code The new software development tool MCUXpresso for Visual Studio Code (VS Code) provides an optimized embedded developer experience for code editing and development. MCUXpresso for VS Code supports NXP MCUs based on Arm Cortex-M cores including MCX, LPC, Kinetis and i.MX RT. MCUXpresso for VS Code allows developers the flexibility to work on projects from Zephyr or MCUXpresso SDK with Open-CMSIS-Packs. A QuickStart panel provides access to the most popular actions. Auto-format and autocomplete features are provided. The debug view provides access to breakpoints, variable/ register views, call stack and thread awareness while using normal debug controls to step through the code. MCUXpresso for VS Code supports various debug probes from NXP, PEmicro and SEGGER. Some features of the MCUXpresso for Visual Code are: • Built on Microsoft Visual Studio Code platform, customize using marketplace extensions • Advanced editing: multi-cursor, auto-format, syntax highlighting, code snippets • Code smarter with Intellisense: completions for variables, methods and imported modules • Flexible use of MCUXpresso SDK using GitHub, with optional Open-CMSIS-Packs • Full support for Zephyr-based project development • Industry-standard GNU tool chain with a choice of libraries: optimized C library or the standard GNU Newlib / Nano library • Easy SDK example importing with MCUXpresso Configuration tools, including pins, clocks, peripheral and trusted execution tools • Source Control Management / Git integration • Project management view displays application information on target architecture, components, build configurations and software repository • Advanced debug capabilities including support for SEGGER J-Link, MCULink or LPC-Link2 probes. Support for FreeRTOS, Azure RTOS ThreadX and Zephyr RTOS. Additionally, improved view capabilities for peripheral registers, global variables, textual/graphical live variables, and integrated GUI Flash programming tool. Figure 2.18 shows the structure of the MCUXpresso for Visual Studio Code.

● 28

Getting Started with NXP i.MX Development Board - UK.indd 28

26-10-2023 09:34


Chapter 2 • Installing the MCUXpresso Software Development Kit (SDK)

Figure 2.18 MCUXpresso for Visual Studio Code The download link for the MCUXpresso for Visual Studio Code is: https://marketplace.visualstudio.com/items?itemName=NXPSemiconductors.mcuxpresso Interested readers can get further information on MCUXpresso for Visual Studio Code from the following websites: https://www.nxp.com/products/processors-and-microcontrollers/mcuxpresso-for-visualstudio-code:MCUXPRESSO-VSC?tid=vanMCUXPRESSO-VSC https://community.nxp.com/t5/MCUXpresso-for-VSCode/bd-p/mcuxpresso-vscode https://github.com/nxp-mcuxpresso/vscode-for-mcux/wiki https://www.nxp.com/products/processors-and-microcontrollers/mcuxpresso-for-visualstudio-code:MCUXPRESSO-VSC?tid=vanMCUXPRESSO-VSC Tutorial and training are available for the MCUXpresso for Studio Code at the following link: https://www.nxp.com/design/training/getting-started-with-mcuxpresso-for-visual-studiocode:TIP-GETTING-STARTED-WITH-MCUXPRESSO-FOR-VS-CODE

● 29

Getting Started with NXP i.MX Development Board - UK.indd 29

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 3 • Simple Program Examples and Debugging 3.1 Software-only programs In this chapter simple programs are given to review the basic principles of programming in the C language using the MCUXpresso IDE and SDK. The interface to these programs are the PC screen and keyboard. The aim here has been to review the C language programming concepts by developing simple programs, and then uploading and running them on the development kit. All the example programs in this chapter are run under the debugging mode. Examples are given in the chapter on how to use the debugger. Readers who have good working knowledge of the C language and who are familiar using the MCUXpresso IDE can skip this chapter.

3.2 Example 1 – Sum of integer numbers Write a program to read an integer number N from the keyboard, and then calculate and display the sum of all the integer numbers from 1 to N. Solution Figure 3.1 shows the program listing. Comments are used at the beginning of the program to describe the function of the program. It is strongly recommended by the author to include comments in your programs to make them easy to follow and also easy to modify in the future. The program prompts the user by displaying the text 'How many numbers are there ?' by using the debug function PRINTF(). The function SCANF() reads an integer number N from the keyboard. Then, a for loop is formed where the sum of all the integer numbers from 1 to N is calculated and stored in the variable Sum. The sum is finally displayed as an integer number using the function PRINTF(). Running the program Assuming the program has been written, the steps to run the program (and all other programs in this chapter) are as follows (Note: all the programs in this chapter are run in Debug mode): • Click Project → Build Configurations → Set Active → Debug • Click the project name at the top of the Project Explorer window • Click Quick Settings under Miscellaneous at the bottom left window. Then click to select SDK Debug Console, followed by Semihost console (Figure 3.2) • Click Debug at the left-hand side of the window • Select the debugging tool and wait until the program is compiled and loaded into the development kit. The program will display a message similar to: Debug

● 30

Getting Started with NXP i.MX Development Board - UK.indd 30

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

started on port 58974 @ 127.0.0.1] at the bottom part (Console) of the screen. • Click Run → Resume to run the program • The results of the program will be displayed at the Console part of the screen /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Sum of numbers 1 to N*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ int N, Sum = 0; /******************************************************************************* * Code ******************************************************************************/ /* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while(1) { PRINTF("How many numbers are there ? "); SCANF("%d", &N); for (int i = 1; i <= N; i++)

// Do for 1 to N

● 31

Getting Started with NXP i.MX Development Board - UK.indd 31

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{ Sum = Sum + i;

// Calculate the sum

} PRINTF("\r\nSum of numbers from 1 to %d are: %d", N, Sum); while(1);

// Wait here forever

} }

Figure 3.1 Program listing

Figure 3.2 Select the Semihost console Testing the program • Click Run → Resume • Figure 3.3 shows an example output from the program • Click Run → Terminate to stop the program

Figure 3.3 Example output You could also display the program output using a virtual terminal such as the Tera Term, Putty, or any other one by selecting the serial communication and entering the virtual COM port assigned to your development kit (this can be found from the Device Manager on your PC). You should change the SDK Debug Console to UART, terminate the debugger if it is running, and click Debug before you can direct the output to a virtual serial terminal. The virtual terminal port number is displayed automatically if Tera Term is used (if no other serial devices are used on your PC). An example is shown in Figure 3.4 where the assigned port number was COM14. Make sure that the port speed is set to 115200.

● 32

Getting Started with NXP i.MX Development Board - UK.indd 32

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

Figure 3.4 Virtual terminal port number

3.3 Example 2 – Table of squares Write a program to tabulate the squares of integer numbers from 1 to 10. Solution Figure 3.5 shows the program listing. A for loop is set up in the main program loop, which tabulates the squares of numbers from 1 to 10. The display items are separated with a tab (i.e. '\t'). /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Squares*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) {

● 33

Getting Started with NXP i.MX Development Board - UK.indd 33

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

/* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { int i, N; PRINTF("TABLE OF SQUARES FROM 1 TO 10\n"); PRINTF("=============================\n"); PRINTF("N\tSQUARE\n"); for (i = 1; i <= 10; i++)

// Do for 1 to N

{ N = i * i;

// Calculate the square

PRINTF("%d\t%d\n", i, N);

// Display

} while(1); } }

Figure 3.5 Program listing Figure 3.6 shows the output from the program, displayed on the Serial Monitor.

Figure 3.6 Output from the program

3.4 Example 3 – Centigrade to Fahrenheit Write a program to receive the temperature as Centigrade and then convert it to Fahrenheit and display on the Serial Monitor. You should read the temperature from the keyboard.

● 34

Getting Started with NXP i.MX Development Board - UK.indd 34

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

Solution Given the temperature in degrees C, it can be converted into degrees F using the following formula: F = 1.8 × C + 32 Figure 3.7 shows the program listing (CtoF). Function ToF receives Degrees C as its argument, converts into Degrees F and returns to the main program. The temperature in degrees Centigrade is read from the keyboard. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Centigrade to Fahrenheit*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ // // Function to convert Degrees C to Degrees F // float ToF(float C) { return (1.8 * C + 32); } int main(void) { float F; int C, Fint;

● 35

Getting Started with NXP i.MX Development Board - UK.indd 35

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

/* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("Enter temperature as Degreec C: "); SCANF("%d", &C); Fint = ToF(C);

// COnvert to F

PRINTF("%d Degrees C = %d Degrees F\n", C, Fint); while(1); } }

Figure 3.7 Program listing Figure 3.8 shows output from the program, where 100 degrees Centigrade is converted into Fahrenheit and displayed on the Serial Monitor.

Figure 3.8 Output from the program

3.5 Example 4 – Times table Write a program to read an integer number and then tabulate the times table from 1 to 12 for the given number. Solution Figure 3.9 shows the program listing (Timestable). An integer number is read from the keyboard and stored in variable N. Then a for loop is set up that runs from 1 to 12. The number N is multiplied by 1 to 12 inside this loop and is then displayed on the Serial Monitor. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause *

● 36

Getting Started with NXP i.MX Development Board - UK.indd 36

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

*Times table*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) { int N, i; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("Enter the number: ");

// Prompt for a number

SCANF("%d", &N); PRINTF("\nTimes table for number %d\n", N);

// Heading

for(i = 1; i <=12; i++) { PRINTF("%d X %d = %d\n", i, N, i*N); } while(1); } }

Figure 3.9 Program listing Figure 3.10 shows output from the program, where the times table for number 5 is displayed.

● 37

Getting Started with NXP i.MX Development Board - UK.indd 37

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 3.10 Output from the program

3.6 Example 5 – Table of trigonometric sine Write a program to tabulate the trigonometric sine between the angles of 0 to 90 degrees, in steps of 5 degrees. Solution Figure 3.11 shows the program listing (Trigonometric-sine). After displaying a heading, a for loop is set up which runs from 0 to 90 in steps of 5. Inside this loop, the sine of the angles are calculated. Notice that the angles for trigonometric functions must be entered in radians. Degrees are converted into radians by multiplying with Pi/180 /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Trigonometric sine*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ #define pi 3.14159 /******************************************************************************* * Prototypes ******************************************************************************/ /*******************************************************************************

● 38

Getting Started with NXP i.MX Development Board - UK.indd 38

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

* Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) { int degree; float rad; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) {

PRINTF("TRIGONOMETRIC SINE\n");

// Heading

PRINTF("==================\n"); PRINTF("Degree\t Sine\n"); for(degree = 0; degree <=90; degree += 5)

// 0 to 90

{ rad = degree * pi / 180.0; PRINTF("%d\t%6.3f\n", degree, sin(rad));

// Convert to radians // Display degree

} while(1); } }

Figure 3.11 Program listing Figure 3.12 shows the output from the program.

● 39

Getting Started with NXP i.MX Development Board - UK.indd 39

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 3.12 Output from the program Note that by default floating-point variables are not displayed by the PRINTF() function and this feature must be enabled as follows: • Click Project followed by Properties • Click C/C++ Build followed by Settings • Click to expand Preprocessor • Click on CR_INTEGER_PRINTF and click on Delete to remove it

3.7 Example 6 – Table of trigonometric sine, cosine and tangent Write a program to tabulate the trigonometric sine between the angles of 0 to 45 degrees, in steps of 5 degrees. Solution The program (sine-cosine-tangent) is similar to the one given in Figure 3.11, but here cosine and tangent are also included. Figure 3.13 shows the program listing. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Trigonometric sine,cosine,tangent*/ #include "clock_config.h"

● 40

Getting Started with NXP i.MX Development Board - UK.indd 40

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

#include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ #define pi 3.14159 /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) { int degree; float rad; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("TRIGONOMETRIC FUNCTIONS\n");

// Heading

PRINTF("=======================\n"); PRINTF("Degree\tSine\tCosine\tTangent\n"); for(degree = 0; degree <=45; degree += 5)

// 0 to 45

{ rad = degree * pi / 180.0;

// Convert to radians

PRINTF("%d\t%6.3f\t%6.3f\t%6.3f\n", degree, sin(rad), cos(rad), tan(rad)); } while(1); } }

Figure 3.13 Program listing

● 41

Getting Started with NXP i.MX Development Board - UK.indd 41

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 3.14 shows the output from the program.

Figure 3.14 Output from the program

3.8 Example 7 – Integer calculator Write an integer calculator program. The program should receive two integer numbers from the keyboard and the operation to be performed. The result of the calculation should be displayed on the Serial Monitor. Only the four basic operations (+ - * /) should be used in the program. Solution: Figure 3.15 shows the program listing (integer-calculator). Two integer numbers (N1 and N2) and the required operation (oper as + - * /) are read from the keyboard, separated with spaces. A switch block is used to determine the type of operation to be performed. For example, if oper is equal to '+' then numbers N1 and N2 are added together. The result of the operation is stored in variable result, which is displayed at the end of the program. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Integer calculator*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /*******************************************************************************

● 42

Getting Started with NXP i.MX Development Board - UK.indd 42

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

* Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) { int N1, N2, result; char oper; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("Enter the numbers and operation: "); SCANF("%d %d %c", &N1, &N2, &oper); switch(oper) { case '+':

// Is it +

result = N1 + N2;

// Add

break; case '-':

// Is it -

result = N1 - N2;

// Subtract

break; case '*':

// Is it *

result = N1 * N2;

// Multiply

break; case '/':

// Is it /

result = N1 / N2;

// Divide

break; } PRINTF("\nResult = %d\n", result); while(1); } }

Figure 3.15 Program listing

● 43

Getting Started with NXP i.MX Development Board - UK.indd 43

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 3.16 shows an example output from the program where numbers 23 and 3 are multiplied to give the result 69.

Figure 3.16 Example output from the program

3.9 Example 8 – Solution of a quadratic equation Write a program to calculate the roots of a quadratic equation of the following form and display the roots. Enter a, b, and c from the keyboard. ax2 + bx + c = 0 Solution The roots of a quadratic equation are calculated using the following formula:

x1,2 =

� b ± b 2 � 4ac 2a

Figure 3.17 shows the program listing (quadratic). /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Quadratic equation*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/

● 44

Getting Started with NXP i.MX Development Board - UK.indd 44

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

/******************************************************************************* * Variables ******************************************************************************/ float a, b, c, root1, root2, rootreal, rootimag; int real; /******************************************************************************* * Code ******************************************************************************/ // // This function calculates and returns the roots // void quadratic() { float det = b * b - 4.0 * a * c; if(det >= 0.0)

// If positive determinant

{ real = 1; det = sqrt(det);

// Claculate square root

root1 = (-b + det) / (2.0 * a);

// Root 1

root2 = (-b - det) / (2.0 * a);

// Root 2

} else

// Negative determinant

{ real = 0; det = -det;

// Negate the determinant

det = sqrt(det);

// Calculate square toot

rootreal = -b / (2.0 * a);

// Real part of root

rootimag = det / (2.0 * a);

// Imaginary part of root

} } int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("Enter a b c: ");

// Enter a

SCANF("%f %f %f", &a, &b, &c); quadratic();

// Calculate roots

if(real == 1)

// If real roots

{ PRINTF("Root1 = %6.3f\n", root1);

● 45

Getting Started with NXP i.MX Development Board - UK.indd 45

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

PRINTF("Root2 = %6.3f\n", root2); } else

// If complex roots

{ PRINTF("Root1 = %6.3f+j%6.3f\n", rootreal, rootimag); PRINTF("Root2 = %6.3f-j%6.3f\n", rootreal, rootimag); } while(1); } }

Figure 3.17 Program listing An example output is shown in Figure 3.18 for the solution of the quadratic equation: −2x2 + 2x + 1 = 0

Figure 3.18 Solution of: −2x2 + 2x + 1 = 0 Figure 3.19 shows an example with complex roots for the equation: 2x2 +2x + 1 = 0

Figure 3.19 Solution of: 2x2 + 2x + 1 = 0

3.10 Example 9 – Squares and cubes of numbers Write a program to tabulate the squares and cubes of numbers from 1 to 10. Solution The program listing is shown in Figure 3.20 (squares-and-cubes). Example output from the program is shown in Figure 3.21.

● 46

Getting Started with NXP i.MX Development Board - UK.indd 46

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Squares and cubes*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/

int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("SQUARES AND CUBES OF NUMBERS\n"); PRINTF("============================\n"); PRINTF("N\tN*N\tN*N*N\n"); for(int i = 1; i < 11; i++) {

PRINTF("%d\t%d\t%d\n", i, i*i, i*i*i); }

● 47

Getting Started with NXP i.MX Development Board - UK.indd 47

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

while(1); } }

Figure 3.20 Program listing

Figure 3.21 Example output

3.11 Example 10 – Factorial of a number Write a program to calculate the factorial of a number entered from the keyboard. Solution The program listing is shown in Figure 3.22 (factorial). Figure 3.23 shows example output from the program. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Factorial*/ #include "clock_config.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /*******************************************************************************

● 48

Getting Started with NXP i.MX Development Board - UK.indd 48

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

* Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/

int main(void) { int N; int32_t factorial; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while (1) { PRINTF("Enter a number: "); SCANF("%d", &N); factorial = 1; if(N == 0)PRINTF("The factorial of 0 is 1"); else {

for(int i = 1; i <= N; i++)

factorial = factorial*i;

} PRINTF("The factorial of %d is %d\n", N, factorial); while(1); } }

Figure 3.22 Program listing

Figure 3.23 Example output

● 49

Getting Started with NXP i.MX Development Board - UK.indd 49

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

3.12 Debugging a project The process of debugging is essential during program development. It is the process of finding and fixing errors or bugs in a program. When a program does not work as expected, it is common to use debugging tools to run the program in a controlled environment, usually step by step, to analyze and fix the errors. A debug operation requires a physical connection between the host computer and the target MCU via a debug probe. The debug probe translates the high-level commands provided by MCUXpresso IDE into the appropriate low-level operations supported on the target MCU. Fortunately, the MIMXRT 1010-EVK development board has on-board debug probes, which simplifies the debugging task greatly. To debug a program, simply highlight the program in the Project Explorer and then click Debug under MCUXpresso IDE → Quickstart Panel (Figure 3.24). Alternatively, click the blue bug icon to perform the same action (The green bug icon should not be used because this invokes the standard Eclipse debug operation and so skips certain essential MCUXpresso IDE debug steps). For a newly created project, a debug operation will perform a number of steps. By default, it will first build the selected project and (assuming there are no build errors) launch a debug probe discovery operation to allow the user to select the required debug probe. A launch configuration file will automatically be created with default options (per build configuration) and will be associated with the project. Like a project's build configuration, launch configuration files control what occurs each time a debug operation is performed.

Figure 3.24 Click Debug The first time you debug a project, the IDE will perform a probe discovery operation and display the discovered Debug Probes for selection. This will show a dialogue listing all supported probes that are attached to the host computer. For any future debug sessions, the stored probe selection will be automatically used to match the project being debugged with the previously used debug probe. This greatly simplifies the case where multiple debug probes are being used. However, if a debug operation is performed and the previously remembered debug probe cannot be found, then a debug probe discovery operation will be performed from within the same family e.g. LinkServer, PEmicro or SEGGER. When you have started a debug session, a default breakpoint is set on the first instruction in main(), the application is started (by simulating or performing a processor reset), and code is ex-

● 50

Getting Started with NXP i.MX Development Board - UK.indd 50

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

ecuted until the default 'breakpoint is hit. Program execution can now be controlled using the common debug control buttons, as listed in Table 3.1, which are displayed on the global toolbar.

Table 3.1 Debug control buttons Clean up debug will kill all debug processes associated with LinkServer, PEmicro and SEGGER debug connections. This may be necessary if the IDE is restarted with a connected debug session or if a crash occurs – and will remove any failed or orphaned debug processes. Setting a breakpoint: To set a breakpoint, simply double-click on the left margin area of the line on which you wish to set the breakpoint (before the line number). Restarting the application: If you hit a breakpoint or pause execution and want to start execution of the application from the beginning again, you can do this using the Restart button. Stopping debugging: To stop debugging, just press the Terminate/Stop button. This action will disconnect MCUXpresso IDE from the target (board). The subsequent behaviour is controllable by the disconnect behaviour. Pause debugging: Typically, debugging is paused due to the action of a breakpoint or watch point since these will be set to observe the target when an event of interest has occurred. However, the pause button can be used to pause the target at an instant of time. The debugger has many configuration options. Interested readers can find detailed information on using the debugger in the following document: MCUXpresso IDE User Guide, Rev. 11.7.1 - 28 March, 2023 In the remainder parts of this chapter, we will be looking at an example program and learn how the debugger can be used with this program.

● 51

Getting Started with NXP i.MX Development Board - UK.indd 51

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

3.12.1 Example debug session In this example, we will use the simple program given in Example 1 (Sum of integer numbers) of this chapter, shown in Figure 3.1. The steps are as follows: • Load the program to your MCUXpresso • Connect your development kit to your PC • Click Quick Settings under tab Miscellaneous under the MCUXpresso IDE – Quickstart Panel • Click SDK Debug Console and select Semihost console • Click the Debug button under MCUXpresso IDE – Quickstart Panel • If this is the first time you are using the debugger, you will be presented with an option to choose a debug probe on your development kit (there are 3 debugger probes on the MIMXRT1010-EVK development kit); otherwise the debugger will start to compile the program and initiate the debug session. After a short delay, the debugger will highlight the first executable statement in green in the main() program as shown in Figure 3.25.

Figure 3.25 Debugger stopped at the first executable line in main() • Pressing Run followed by Resume will run the program at this stage. But here we will single step through the program. Press key F6 to step through the program. You should see the green highlight moving down the program statements as you press F6. Enter 5 to the prompt How many numbers are there ? • Place the cursor over Sum, you should see the value of this variable (in decimal, hexadecimal, binary and octal) as you step through the program (Figure 3.26)

● 52

Getting Started with NXP i.MX Development Board - UK.indd 52

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

Figure 3.26 Place the cursor over Sum • Step through until the program comes out of the for loop. You should see the result displayed in the Console (Figure 3.27);

Figure 3.27 result is displayed • Click Run followed by Terminate to end the debug session. • We will now insert breakpoints in the program. The breakpoint will be inserted to a point just before displaying the result. The steps are: • Click Run followed by Debug Last Launched • Place the cursor on the left margin where the numbers are, on the line PRINTF and double-click the mouse. You should see a small mark on the left side of the number in the margin.

● 53

Getting Started with NXP i.MX Development Board - UK.indd 53

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

• This has placed a breakpoint marker at this statement. Now, click Run followed by Resume. The program will run up to the breakpoint and then stop there. Enter 10 as the numbers to be added (Figure 3.28)

Figure 3.28 Program stopped at the breakpoint • Now, press F6 to step through the program and display the result of PRINTF (Figure 3.29).

Figure 3.29 Press F6 to step to the result • Double-click on the breakpoint marker to remove the breakpoint. Click Run followed by Terminate to terminate debugging. We will now watch a variable as its value changes during single stepping. For this example, a simple program code is shown in Figure 3.30. Here, we will watch the variable Count, which is a global variable.

● 54

Getting Started with NXP i.MX Development Board - UK.indd 54

26-10-2023 09:34


Chapter 3 • Simple Program Examples and Debugging

Figure 3.30 Simple program The steps are: • Start the debugger. • Click Window followed by Show View. Then click Global Variables. A new window will appear at the right-hand side. • Click icon Add global variables and select Count from the shown list. You should see variable Count displayed as shown in Figure 3.31.

Figure 3.31 Displaying variable Count • Click F6 and single step until statement PRINTF. Observe that Count has the value 0. • Click F6 until the statement while() is highlighted. You should see the value of Count changed to 100 (Figure 3.32).

Figure 3.32 Value of Count changed

● 55

Getting Started with NXP i.MX Development Board - UK.indd 55

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 4 • LED Projects 4.1 Overview In this chapter you will be developing various projects using external LEDs. The aim of this chapter is to show how LEDs can be interfaced to the development kit and how they can be programmed using the MCUXpresso. Table 4.1 shows the pin configuration of the commonly used peripheral protocols (they must be routed to the required functions. Some functions are also available on different pads). Name

Function

Usage

GPIO_11

GPIO

On-board LED

GPIO_SD_05

GPIO

On-board SW4

GPIO_10

LPUART1_TX

UART Console

GPIO_09

LPUART1_RX

UART Console

GPIO_13

LPUART2_RX

UART 2 RX

GPIO_AD_00

LPUART2_TX

UART2 TX

GPIO_12

LPUART3_TX

UART3 TX

GPIO_07

LPUART3_RX

UART3 RX

GPIO_AD_02

LPUART4_TX

UART4 TX

GPIO_AD_01

LPUART4_RX

UART4 RX

GPIO_01

LPI2C1_SDA

I2C1 SDA

GPIO_02

LPI2C1_SCL

I2C1 SCL

GPIO_AD_08

LPI2C2_SCL

I2C2 SCL

GPIO_AD_07

LPI2C2_SDA

I2C2 SDA

GPIO_AD_03

LPSPI1_SDI

SPI1 MISO

GPIO_AD_04

LPSPI1_SDO

SPI1 MOSI

GPIO_AD_05

LPSPI1_PCS0

SPI1 CS

GPIO_AD_06

LPSPI1_SCK

SPI1 CLK

GPIO_00

LPSPI2_PCS3

SPI2 CS

GPIO_AD_12

LPSPI2_SCK

SPI2 CLK

GPIO_AD_09

LPSPI2_PCS0

SPI2 CS

GPIO_AD_10

LPSPI2_SDO

SPI2 MOSI

GPIO_AD_09

LPSPI2_SDI

SPI2 MISO

GPIO_AD_14

ADC

ADC channel 14

GPIO_AD_13

ADC

ADC channel 13

GPIO_AD_12

ADC

ADC channel 12

GPIO_AD_11

ADC

ADC channel 11

● 56

Getting Started with NXP i.MX Development Board - UK.indd 56

26-10-2023 09:34


Chapter 4 • LED Projects

GPIO_AD_10

ADC

ADC channel 10

GPIO_AD_09

ADC

ADC channel 9

GPIO_AD_08

ADC

ADC channel 8

GPIO_AD_07

ADC

ADC channel 7

GPIO_AD_06

ADC

ADC channel 6

GPIO_AD_05

ADC

ADC channel 5

GPIO_AD_04

ADC

ADC channel 4

GPIO_AD_03

ADC

ADC channel 3

GPIO_AD_02

ADC

ADC channel 2

GPIO_AD_01

ADC

ADC channel 1

GPIO_AD_00

ADC

ADC channel 0

GPIO_02

PWM1:A,0

PWM1

GPIO_08

PWM1:A,3

PWM1

GPIO_07

PWM1:B,3

PWM1

GPIO_06

PWM1:A,2

PWM1

GPIO_05

PWM1:B,2

PWM1

GPIO_04

PWM1:A,1

PWM1

GPIO_03

PWM1:B,1

PWM1

GPIO_01

PWM1:B,0

PWM1

GPIO_08

SA1:MCLK

SA1

GPIO_07

SA1:TX_SYNC

SA1

GPIO_06

SA1:TX_BCLK

SA1

GPIO_05

SA1:TX_RX_DATA1

SA1

GPIO_04

SA1:TX_DATA0

SA1

GPIO_03

SA1:RX_DATA0

SA1

GPIO_02

SA1:RX_SYNC

SA1

GPIO_01

SA1:RX_BCLK

SA1

GPIO_00

SA13:MCLK

SA13

GPIO_SD_04

SA13:RX_SYNC

SA13

GPIO_SD_03

SA13:RX_DATA

SA13

GPIO_SD_02

SA13:TX_DATA

SA13

GPIO_SD_01

SA13:TX_BCLK

SA13

GPIO_SD_00

SA13:TX_SYNC

Table 4.1 Peripheral protocol pin configurations

● 57

Getting Started with NXP i.MX Development Board - UK.indd 57

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

4.2 Project 1 – Flashing an external LED Description: This project flashes an external LED connected to Arduino header J57, pin 8 every 2 seconds. The aim of the project is to show how an external LED can be connected to the development board and how it can be configured and programmed. Block diagram: Figure 4.1 shows the block diagram of the project.

Figure 4.1 Block diagram of the project Circuit diagram: The circuit diagram is shown in Figure 4.2. The LED is connected in current sinking mode with a 1 kΩ current limiting resistor connected in series with the LED. Assuming a voltage drop of 2 V across the LED, the current drawn from the port pin will be approximately (3.3 V – 2 V) / 1 kΩ = 1.3 mA. A smaller resistor, e.g. 330 Ω can be used for higher brightness.

Figure 4.2 Circuit diagram of the project The GPIO pins of the development board can be configured for several different functions. The default I/O pin names of the Arduino header pins are shown in Table 4.2 to Table 4.5. The pin you will be using in this project is IO18.

● 58

Getting Started with NXP i.MX Development Board - UK.indd 58

26-10-2023 09:34


Chapter 4 • LED Projects

1. NC

2. UART1_RXD (IO9)

3. NC

4. UART1_TXD (IO10)

5. NC

6. GPIO_AD_05 (IO19)

7. NC

8. GPIO_AD_06 (IO20)

9. NC

10. NC

11. NC

12. NC

13. NC

14. GPIO_AD_01 (IO15)

15. NC

16. ADC12_2 (IO16)

Table 4.2 Arduino header J56 1. NC

2. GPIO_SD_02 (IO2)

3. NC

4. NC

5. NC

6. GPIO_AD_05 (IO19)

7. NC

8. GPIO_AD_04 (IO18)

9. NC

10. GPIO_AD_03 (IO17)

11. NC

12. GPIO_AD_06 (IO20)

13. NC

14. NC

15. NC

16. NC

16. NC

18. I2C1_SDA (IO1)

17. NC

20. I2C1_SCL (IO2)

Table 4.3 Arduino header J57 12. GPIO_AD_02 (IO16)

11. NC

10. GPIO_AD_01 (IO15)

9. NC

8. GPIO_AD_14 (IO28)

7. NC

6. GPIO_AD_10

5. NC

4. GPIO_AD_09

3. NC

2. GPIO_AD_07 (IO21)

1. NC

Table 4.4 Arduino header J26

● 59

Getting Started with NXP i.MX Development Board - UK.indd 59

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

16. +5 V

15. NC

14. GND

14. NC

12. GND

11. NC

10. +5 V

9. NC

8. +3.3 V

7. NC

6. RESET

5. NC

4. +3.3 V

3. GND

2. NC

1. GND

Table 4.5 Arduino header J60 Be careful with the pin numbering of headers J26 and J60. Program listing: The GPIO pin at header J57, pin 8 (GPIO_AD_04) must be configured before it can be used as an output port. This is easily done using the ConfigTools menu option of MCUXpresso IDE. The steps are: • Start the MCUXpresso with the same Workspace as in Figure 2.11 (i.e. project iled_blinky). • Click ConfigTools menu option, followed by Pins. You should see the configuration menu as in Figure 4.3. In the left-hand side window are the pin names and their functions, the middle part of the window shows the package, the bottom part of the window shows the pin routing details.

Figure 4.3 The configuration menu

● 60

Getting Started with NXP i.MX Development Board - UK.indd 60

26-10-2023 09:34


Chapter 4 • LED Projects

• Click to select Pin 56, GPIO_AD_04 and select GPIO1:gpio (Figure 4.4)

Figure 4.4 Select Pin 56 • You should see the selected pin routing details at the bottom of the screen. Set the Direction to Output (Figure 4.5). Notice that the port number is 18, and you can select various other options for the port.

Figure 4.5 Set the Direction to Output • Click menu option Update Code and then OK to exit the configuration mode • Port pin 18 is now configured as digital output. Files pin_mux.c and pin_mux.h have been modified automatically to reflect the changes. The following lines of code are added to file pin_mux,c: /* GPIO configuration of LPSPI1_SDO on GPIO_AD_04 (pin 56) */ gpio_pin_config_t LPSPI1_SDO_config = { .direction = kGPIO_DigitalOutput, .outputLogic = 0U, .interruptMode = kGPIO_NoIntmode }; /* Initialize GPIO functionality on GPIO_AD_04 (pin 56) */ GPIO_PinInit(GPIO1, 18U, &LPSPI1_SDO_config); IOMUXC_SetPinMux(IOMUXC_GPIO_AD_04_GPIOMUX_IO18, 0U);

● 61

Getting Started with NXP i.MX Development Board - UK.indd 61

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

The following lines of code are added to file pin_mux.h: /* GPIO_AD_04 (number 56), LPSPI1_SDO/J57[8]/U27[5] */ /* Routed pin properties */ #define BOARD_LPSPI1_SDO_PERIPHERAL GPIO1

/*!< Peripheral name */

#define BOARD_LPSPI1_SDO_SIGNAL gpiomux_io

/*!< Signal name */

#define BOARD_LPSPI1_SDO_CHANNEL 18U

/*!< Signal channel */

The new code in pin_mux.c configures the port as an output with no interrupt, and it then initializes it. The new code in pin_mux.h defines the signal and channel names for port 18. Figure 4.6 shows the complete program listing (ext-led). This program is the same as the one in Figure 2.11, but here port 18 is used. Figure 4.7 shows the project constructed using a breadboard. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *This program flashes an external LED every 2 seconds*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ #define LED_PIN (18U) /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void)

● 62

Getting Started with NXP i.MX Development Board - UK.indd 62

26-10-2023 09:34


Chapter 4 • LED Projects

{ if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } /*! * @brief Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while (1) { /* Delay 2000 ms */ SysTick_DelayTicks(2000U); GPIO_PortToggle(GPIO1, 1u << LED_PIN); } }

Figure 4.6 Program listing

● 63

Getting Started with NXP i.MX Development Board - UK.indd 63

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 4.7 Construction of the project

4.3 Project 2 – LED flashing as Morse SOS signal Description: This project flashes the external LED connected to Arduino header J57, pin 8 as a Morse SOS signal (ON ON ON OFF OFF OFF ON ON ON i.e. … --- …). The block diagram and circuit diagram of the project are the same as in Figure 4.1 and Figure 4.2. Program listing: Figure 4.8 shows the program listing (SOS). The main program runs inside a while loop. Here, the LED is flashed three times, with 200 ms between each flash to represent three dots (letter 'S' in Morse code). After 500 ms the LED is flashed again, but this time 600 ms between each flash to represent the letter 'O' in Morse code. Then, the LED flashes again three times with 200 ms to represent three dots (letter 'S' in Morse code). This process is repeated after a two-second delay. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *This program flashes an external LED as a Morse SOS signal*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ #define LED_PIN (18U)

● 64

Getting Started with NXP i.MX Development Board - UK.indd 64

26-10-2023 09:34


Chapter 4 • LED Projects

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } /* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } }

● 65

Getting Started with NXP i.MX Development Board - UK.indd 65

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

while (1) { for(int i=0; i < 3; i++)

// Send S

{

GPIO_PinWrite(GPIO1, LED_PIN, 1U);

SysTick_DelayTicks(200U); GPIO_PinWrite(GPIO1, LED_PIN, 0U);

// ON // OFF

SysTick_DelayTicks(200); } SysTick_DelayTicks(500); for(int i=0; i < 3; i++)

// Send O

{ GPIO_PinWrite(GPIO1, LED_PIN, 1U);

// ON

SysTick_DelayTicks(600); GPIO_PinWrite(GPIO1, LED_PIN, 0U);

// OFF

SysTick_DelayTicks(600); } SysTick_DelayTicks(100); for(int i=0; i < 3; i++)

// Send S

{ GPIO_PinWrite(GPIO1, LED_PIN, 1U);

// ON

SysTick_DelayTicks(200); GPIO_PinWrite(GPIO1, LED_PIN, 0U);

// OFF

SysTick_DelayTicks(200); } SysTick_DelayTicks(2000);

// Wait 2 sec

} }

Figure 4.8 Program listing

4.4 Project 3 – Alternately flashing two LEDs Description: In this project, two LEDs are connected to the development kit. The LEDs flash alternately 250 ms each. The aim of this project is to show how more than one LED can be connected to the development kit and how these LEDs can be configured and programmed. Block diagram: Figure 4.9 shows the block diagram of the project.

● 66

Getting Started with NXP i.MX Development Board - UK.indd 66

26-10-2023 09:34


Chapter 4 • LED Projects

Figure 4.9 Block diagram of the project Circuit diagram: The circuit diagram of the project is shown in Figure 4.10. LED1 is connected to Arduino header J57, pin 8 (GPIO_AD_03, IO8). LED2 is connected to header J57, pin 10 (IO17). 1 kΩ current limiting resistors are used with each LED.

Figure 4.10 Circuit diagram of the project Program listing: You should configure port pin GPIO_AD_03 for output as described in the previous project (Figure 4.11). Figure 4.12 shows the program listing (alternate-leds). Inside the main program loop, the two LEDs are turned ON alternately for 250 ms each. Figure 4.12 shows the project constructed on a breadboard.

● 67

Getting Started with NXP i.MX Development Board - UK.indd 67

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 4.11 Configure GPIO_AD_03 as output /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *This program flashes 2 LEDs alternately for 250 ms each*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ #define LED1 (18U)

// At port 18

#define LED2 (17U)

// At port 17

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter;

● 68

Getting Started with NXP i.MX Development Board - UK.indd 68

26-10-2023 09:34


Chapter 4 • LED Projects

/******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } /* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while (1) { GPIO_PinWrite(GPIO1, LED1, 1U);

// LED1 ON

GPIO_PinWrite(GPIO1, LED2, 0U);

// LED2 OFF

SysTick_DelayTicks(250);

// 250 ms delay

GPIO_PinWrite(GPIO1, LED1, 0U);

// LED1 OFF

GPIO_PinWrite(GPIO1, LED2, 1U);

// LED2 ON

SysTick_DelayTicks(250);

// 250 ms delay

● 69

Getting Started with NXP i.MX Development Board - UK.indd 69

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

} }

Figure 4.12 Program listing

Figure 4.13 Project constructed on a breadboard

4.5 Project 4 – Chasing LEDs Description: In this project, 8 LEDs are connected to the Arduino headers of the development kit. The LEDs chase each other as shown in Figure 4.14, with a 250 ms delay between each output. The aim of this project is to show how multiple LEDs can be connected, configured, and programmed.

Figure 4.14 Chasing LEDs Block diagram: The block diagram of the project is shown in Figure 4.15.

● 70

Getting Started with NXP i.MX Development Board - UK.indd 70

26-10-2023 09:34


Chapter 4 • LED Projects

Figure 4.15 Block diagram of the project Circuit diagram: Figure 4.16 shows the circuit diagram. The 8 LEDs are connected to Arduino header J57 and J56 as follows using 1 kΩ current limiting resistors: LED1 LED2 LED3 LED4 LED5 LED6 LED7 LED8

J57, pin 6 J57, pin 8 J57, pin 10 J57, pin 12 J57, pin 18 J57, pin 20 J56, pin 14 J56, pin 16

GPIO_AD_05 GPIO_AD_04 GPIO_AD_03 GPIO_AD_06 I2C1_SDA I2C1_SCL GPIO_AD_01 ADC12_2

(IO19) (IO18) (IO17) (IO20) (IO1) (IO2) (IO15) (IO16)

Figure 4.16 Circuit diagram of the project Program listing: You should, first of all, configure all the used ports as outputs as described in the previous projects (Figure 4.17). Function ALLOFF() turns OFF all the LEDs. Function OnlyOne() receives the LED name as its parameter and turns ON the specified

● 71

Getting Started with NXP i.MX Development Board - UK.indd 71

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

LED for 250 ms. Inside the main program the function OnlyOne() is called with its parameters ranging from LED1 to LED8. As a result, the LEDs turn ON from right to left as if they are chasing each other. Figure 4.18 shows the program listing (chasing-1). The project built on a breadboard is shown in Figure 4.19.

Figure 4.17 Configure ports as outputs /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Chasing 8 LEDs - 1*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ #define LED1 (19U)

// At port 19

#define LED2 (18U)

// At port 18

#define LED3 (17U)

// At port 17

#define LED4 (20U)

// At port 20

#define LED5 (1U)

// At port 1

#define LED6 (2U)

// At port 2

#define LED7 (15U)

// At port 15

● 72

Getting Started with NXP i.MX Development Board - UK.indd 72

26-10-2023 09:34


Chapter 4 • LED Projects

#define LED8 (16U)

// At port 16

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Turn OFF all LEDs // void ALLOFF() { GPIO_PinWrite(GPIO1, LED1, 0U);

// LED1 OFF

GPIO_PinWrite(GPIO1, LED2, 0U);

// LED2 OFF

GPIO_PinWrite(GPIO1, LED3, 0U);

// LED3 OFF

GPIO_PinWrite(GPIO1, LED4, 0U);

// LED4 OFF

GPIO_PinWrite(GPIO1, LED5, 0U);

// LED5 OFF

GPIO_PinWrite(GPIO1, LED6, 0U);

// LED6 OFF

GPIO_PinWrite(GPIO1, LED7, 0U);

// LED7 OFF

GPIO_PinWrite(GPIO1, LED8, 0U);

// LED8 OFF

} //

● 73

Getting Started with NXP i.MX Development Board - UK.indd 73

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

// Only 1 LED ON for 250 ms // void OnlyOne(int ThisLED) { GPIO_PinWrite(GPIO1, ThisLED, 1U); SysTick_DelayTicks(250); GPIO_PinWrite(GPIO1, ThisLED, 0U); } /* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } ALLOFF();

// All LEDs OFF

while (1)

// DO FOREVER

{ OnlyOne(LED1);

// LED1 ON

OnlyOne(LED2);

// LED2 ON

OnlyOne(LED3);

// LED3 ON

OnlyOne(LED4);

// LED4 ON

OnlyOne(LED5);

// LED5 ON

OnlyOne(LED6);

// LED6 ON

OnlyOne(LED7);

// LED7 ON

OnlyOne(LED8);

// LED8 ON

} }

Figure 4.18 Program listing

● 74

Getting Started with NXP i.MX Development Board - UK.indd 74

26-10-2023 09:34


Chapter 4 • LED Projects

Figure 4.19 Project built on a breadboard

4.5.1 More efficient program The program given in Figure 4.18 can be made simpler and more efficient by using an array to store the port numbers, and then using this array to control the LEDs. In this modified version (chasing-2) of the program (Figure 4.20), the port numbers are stored in an array called LEDS[] as follows: static uint32_t LEDS[8] = {19U, 18U, 17U, 20U, 1U, 2U, 15U, 16U}; Function ALLOFF() turns OFF all LEDs and it is simplified as follows: void ALLOFF() { for(int i = 0; i < 8; i++) GPIO_PinWrite(GPIO1, LEDS[i], 0U); }

The main program that controls the LEDs is much simpler and efficient and is as follows: while (1) { for(int j = 0; j < 8; j++) {

GPIO_PinWrite(GPIO1, LEDS[j], 1U);

// LED[j] ON

SysTick_DelayTicks(500);

// 500 ms delay

GPIO_PinWrite(GPIO1, LEDS[j], 0U);

// LED[j] OFF

} }

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause *

● 75

Getting Started with NXP i.MX Development Board - UK.indd 75

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

*Chasing 8 LEDs - 2*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {19U,18U,17U,20U,1U,2U,15U,16U}; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Turn OFF all LEDs // void ALLOFF() {

● 76

Getting Started with NXP i.MX Development Board - UK.indd 76

26-10-2023 09:34


Chapter 4 • LED Projects

for(int i = 0; i < 8; i++) GPIO_PinWrite(GPIO1, LEDS[i], 0U); } /* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } ALLOFF();

// All LEDs OFF

while (1)

// DO FOREVER

{ for(int j = 0; j < 8; j++) {

GPIO_PinWrite(GPIO1, LEDS[j], 1U);

// LED[j] ON

SysTick_DelayTicks(500);

// 500 ms delay

GPIO_PinWrite(GPIO1, LEDS[j], 0U);

// LED[j] OFF

} } }

Figure 4.20 Modified program

4.5.2 Using PortClear and PortSet functions The program in Figure 4.20 can further be improved by using the PortClear and PortSet functions. These functions apply to multiple I/O pins. Function PortClear is used to clear more than one port in multiple I/Os. Similarly, PortSet is used to set more than one port in multiple I/Os. Figure 4.21 shows the modified program (chasing-3). These functions require the ports to be set or cleared to be specified in a 32-bit mask. Setting a bit in the mask clears or sets that I/O port. For example, to set ports 1, 2, and 3 the mask should be: 0000 0000 0000 0000 0000 0000 0000 1110 i.e. hexadecimal number 0x0E.

● 77

Getting Started with NXP i.MX Development Board - UK.indd 77

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

In the program in Figure 4.21, all LEDs are cleared in function ALLOFF() using the following function: void ALLOFF() { uint32_t k = pow(2, 0x1F8006); GPIO_PortClear(GPIO1, k); }

The mask 0x1F8006 corresponds to the bit pattern: 0000 0000 0001 1111 1000 0000 0000 0110 where the following bit positions are set to 1: 1, 2, 15, 16, 17, 18, 19, 20 The built-in function pow() calculates the power of 2. Here, 2k is calculated based on the bits to be set or cleared in the mask. Inside the main program, the LEDs are turned ON and OFF using the following statements: while (1) { for(int j = 0; j < 8; j++) {

uint32_t k = pow(2, LEDS[j]);

GPIO_PortSet(GPIO1, k);

SysTick_DelayTicks(250);

GPIO_PortClear(GPIO1, k);

} }

The for-loop runs from 0 to 8 and extracts the port numbers from array LEDS[]. The bit positions of these numbers are calculated in the mask using the pow() function. The LEDs are then turned ON and OFF as required to give the chasing effect. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Chasing 8 LEDs - 3*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h"

● 78

Getting Started with NXP i.MX Development Board - UK.indd 78

26-10-2023 09:34


Chapter 4 • LED Projects

#include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {19U,18U,17U,20U,1U,2U,15U,16U}; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Turn OFF all LEDs // void ALLOFF() { uint32_t k = pow(2, 0x1F8006); GPIO_PortClear(GPIO1, k); } /* Main function */

● 79

Getting Started with NXP i.MX Development Board - UK.indd 79

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } ALLOFF();

// All LEDs OFF

while (1)

// DO FOREVER

{ for(int j = 0; j < 8; j++) {

uint32_t k = pow(2, LEDS[j]);

GPIO_PortSet(GPIO1, k);

SysTick_DelayTicks(250);

GPIO_PortClear(GPIO1, k);

} } }

Figure 4.21 Program listing

4.6 Project 5 – Binary counting LEDs Description: In this project, 8 LEDs are connected to the development board as in the previous project. As shown in Figure 4.22, the LEDs count up in binary with a 500 ms delay between each count. The aim of this project is to show how a group of port pins can be combined into a port and accessed at the same time.

● 80

Getting Started with NXP i.MX Development Board - UK.indd 80

26-10-2023 09:34


Chapter 4 • LED Projects

Figure 4.22 Binary counting LEDs The block diagram and circuit diagram are as in Figure 4.15 and Figure 4.16. Program listing: Figure 4.23 shows the program listing (counting-leds). As in the previous projects, the GPIO ports used must be configured as outputs using the ConfigTools. At the beginning of the program, variable count is set to 0. Function Display() combines the 8 port pins 16, 15, 2, 1, 20, 17, 18, and 19 into a single port group and accesses them at the same time. This function has two arguments: the width of the data, and the data to be sent to the port. The data width is set to 8 since there are 8 LEDs. For example, setting the function to Display(8, 5) sends number 5 (bit pattern 0000 0101) to the ports, i.e. the LEDs at ports 17 and 19 turn ON. The variable count is incremented by one, and the function Display() is called to turn ON the appropriate LEDs to display the number stored in count. When count reaches 255, it is reset to 0. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Binary counting LEDs*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "math.h" /*******************************************************************************

● 81

Getting Started with NXP i.MX Development Board - UK.indd 81

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

* Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {16U,15U,2U,1U,20U,17U,18U,19U}; int count = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2;

● 82

Getting Started with NXP i.MX Development Board - UK.indd 82

26-10-2023 09:34


Chapter 4 • LED Projects

if((No & j) != 0) GPIO_PinWrite(GPIO1, LEDS[i], 1U); else GPIO_PinWrite(GPIO1, LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } Display(0, 8);

// All LEDs OFF

while (1)

// DO FOREVER

{ count++;

// Increment count

if(count > 255) count = 0;

// If count>255, set to 0

Display(count, 8);

// Display result

SysTick_DelayTicks(500);

// 500 ms delay

} }

Figure 4.23 Program listing

4.7 Project 6 – Random flashing LEDs Description: In this project 8 LEDs are connected to the development board as in the previous project. The LEDs flash randomly as if they are Christmas lights. The block diagram and circuit diagram are as in Figure 4.15 and Figure 4.16.

● 83

Getting Started with NXP i.MX Development Board - UK.indd 83

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Program listing: Figure 4.24 shows the program listing (random-leds). As in the previous projects, the GPIO ports used must be configured as outputs using the ConfigTools. The program is very similar to Figure 4.23. Here, an integer random number is generated between 0 and 255 and this number is used to flash the LEDs randomly every 100 ms. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Lucky day*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {16U,15U,2U,1U,20U,17U,18U,19U}; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) {

● 84

Getting Started with NXP i.MX Development Board - UK.indd 84

26-10-2023 09:34


Chapter 4 • LED Projects

g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1, LEDS[i], 1U); else GPIO_PinWrite(GPIO1, LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } srand(0);

// Random seed

● 85

Getting Started with NXP i.MX Development Board - UK.indd 85

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

while (1)

// DO FOREVER

{ int rnd = rand();

// Random int number

rnd = rnd % 255;

// Between 0 and 255

Display(rnd, 8);

// Display the number

SysTick_DelayTicks(100);

// 100 ms delay

} }

Figure 4.24 Program listing

4.8 Project 7 – Lucky day of the week Description: In this project, 7 LEDs are positioned in the form of a circle and are connected to the development kit. Each LED is assumed to represent a day of the week. Pressing an external button generates a random number between 1 and 7 and lights up only one of the LEDs. The day name corresponding to this LED is assumed to be your lucky day of the week. The aim of this project is to show how an external button can be used in a project. Block diagram: Figure 4.25 shows the block diagram of the project.

Figure 4.25 Block diagram of the project Circuit diagram: The circuit diagram is shown in Figure 4.26. It is similar to Figure 4.15, but here 7 LEDs are used together with an external button (called MyButton) connected to Arduino header J56, pin 2 (i.e. UART1_RXD, IO9).

● 86

Getting Started with NXP i.MX Development Board - UK.indd 86

26-10-2023 09:34


Chapter 4 • LED Projects

Figure 4.26 Circuit diagram of the project Program listing: As before, the LED ports must be configured as outputs. Also, the button at UART1_RXD must be configured as digital input and pulled up with 22 kΩ pull-up resistor using the menu option ConfigTools (Figure 4.27).

Figure 4.27 Configure the button as digital input Figure 4.28 shows the program listing (lucky-day). At the beginning of the program, MyButton is defined as 9 (i.e. port 9), and the random number generator seed MySeed is cleared to 0. Function Display() is used as in the previous project to turn ON/OFF the required LEDs. Inside the main program, a while loop is formed. Inside this loop, the button state is checked and if the button is not pressed (i.e. MyButton = 1) then the random number generator seed MySeed is incremented by 1. This is so that the generated number is random, and the same number is not generated every time the program is started. The while loop terminates when the button is pressed, and the resulting number is used as the seed for the random number generator. The generated random number is set to be between 0 and 7 and is then used to turn ON only one of the LEDs, which represents the

● 87

Getting Started with NXP i.MX Development Board - UK.indd 87

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

lucky day of the user. The program then terminates and can be restarted after pressing the Reset button. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Lucky day*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {16U,15U,2U,1U,20U,17U,18U,19U}; #define MyButton 9U uint32_t MySeed = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) {

● 88

Getting Started with NXP i.MX Development Board - UK.indd 88

26-10-2023 09:34


Chapter 4 • LED Projects

g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1, LEDS[i], 1U); else GPIO_PinWrite(GPIO1, LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while(GPIO_PinRead(GPIO1, MyButton) == 1)

// Wait until button

● 89

Getting Started with NXP i.MX Development Board - UK.indd 89

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

pressed { MySeed++;

// Increment seed

} srand(MySeed);

// Random seed

int rnd = rand();

// Random int number

rnd = rnd % 8;

// Between 0 and 7

int k = pow(2, rnd);

// As power of 2

Display(k, 8);

// Display the number

while(1);

// Wait here forever

}

Figure 4.28 Program listing Figure 4.29 shows the project built on a breadboard.

Figure 4.29 Project built on a breadboard

4.9 Project 8 – Binary up/down counter with LEDs Description: This project is similar to Project 5, but here the counting can be up or down controlled with an external button. Normally, the counting is up. Pressing the button counts down. While counting up, when the count reaches 255, it is reset to 0. Similarly, while counting down, when the count reaches 0 it is reset to 255. The block diagram and circuit diagram of the project are the same as in Figure 4.25 and Figure 4.26 respectively. Program listing: As in the previous project, you should configure the 8 LEDs as outputs and the button as input using the menu option ConfigTools. Figure 4.30 shows the program listing (led-up-down). Variable count is initialized to 0 at the beginning of the program. Inside the main program loop, the state of the button is checked. If the button is not pressed (MyButton = 1) then counting continues upwards.

● 90

Getting Started with NXP i.MX Development Board - UK.indd 90

26-10-2023 09:34


Chapter 4 • LED Projects

If, on the other hand, the button is pressed (MyButton = 0), then the counting continues downwards while the button is kept pressed. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LED up/down counter*/

#include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {16U,15U,2U,1U,20U,17U,18U,19U}; #define MyButton 9U int count = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) {

● 91

Getting Started with NXP i.MX Development Board - UK.indd 91

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1, LEDS[i], 1U); else GPIO_PinWrite(GPIO1, LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } }

● 92

Getting Started with NXP i.MX Development Board - UK.indd 92

26-10-2023 09:34


Chapter 4 • LED Projects

while(1)

// Do Forever

{ if(GPIO_PinRead(GPIO1, MyButton) == 1)

// If button not pressed

{

count++;

// Increment count

if(count == 256)count = 0;

// Back to 0

} else

// Button pressed

{

count--;

// Decrement count

if(count < 0)count = 255;

// Back to 255

} Display(count, 8);

// Display

SysTick_DelayTicks(250);

// Wait 250 ms

} }

Figure 4.30 Program listing

4.10 Project 9 – Binary event counter with LEDs Description: In this project, 8 LEDs and a button are used as in the previous project. Here, the button simulates the occurrence of external events. The count is incremented by 1 and displayed on the LEDs when the button is pressed. The block diagram and circuit diagram of the project are the same as in Figure 4.25 and Figure 4.26 respectively. Program listing: As in the previous project, you should configure the 8 LEDs as outputs and the button as input using the menu option ConfigTools. Figure 4.31 shows the program listing (led-event-counter). Variable count is initialized to 0 at the beginning of the program. The program checks the button MyButton and when it is pressed, the variable count is incremented by 1 and is displayed on the LEDs. The program waits until the button is released and also a 50 ms delay is introduced to eliminate any contact bouncing problems. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LED event counter*/

#include "pin_mux.h"

● 93

Getting Started with NXP i.MX Development Board - UK.indd 93

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

#include "clock_config.h" #include "board.h" #include "math.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {16U,15U,2U,1U,20U,17U,18U,19U}; #define MyButton 9U int count = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j;

● 94

Getting Started with NXP i.MX Development Board - UK.indd 94

26-10-2023 09:34


Chapter 4 • LED Projects

m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1, LEDS[i], 1U); else GPIO_PinWrite(GPIO1, LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while(1)

// Do Forever

{ while(GPIO_PinRead(GPIO1, MyButton) == 1);

// Wait for press

count++;

// Increment count

Display(count, 8); while(GPIO_PinRead(GPIO1, MyButton) == 0);

// Wait for release

SysTick_DelayTicks(50);

// Contact debounce

} }

Figure 4.31 Program listing

● 95

Getting Started with NXP i.MX Development Board - UK.indd 95

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 5 • 7-Segment LED Displays 5.1 Overview In the previous chapter, you learned how to develop projects using LEDs only. In this chapter you will be using 7-segment LED displays in projects.

5.2 7-Segment LED display structure 7-segment LED displays are frequently used in electronic circuits to show numeric or alphanumeric values. As shown in Figure 5.1, a 7-segment LED display basically consists of 7 LEDs connected such that numbers from 0 to 9 and some letters can be displayed. Segments are identified by letters from a to g and Figure 5.2 shows the segment names of a typical 7-segment LED display.

Figure 5.1 Some 7-segment LED displays

Figure 5.2 Segment names of a 7-segment display Figure 5.3 shows how numbers from 0 to 9 can be obtained by turning ON different segments of the display.

● 96

Getting Started with NXP i.MX Development Board - UK.indd 96

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

Figure 5.3 Displaying numbers 0–9 (courtesy of electronics-fun.com) 7-segment displays are available in two different configurations: common cathode and common anode. As shown in Figure 5.4, in common cathode configuration, all the cathodes of all segment LEDs are connected to ground. The segments are turned ON by applying a logic 1 to the required segment LED via current limiting resistors. In common cathode configuration, the 7-segment LED is connected to the microcontroller in current sourcing mode.

Figure 5.4 Common cathode 7-segment display In a common anode configuration, the anode terminals of all the LEDs are connected as shown in Figure 5.5. This common point is then normally connected to the supply voltage. A segment is turned ON by connecting its cathode terminal to logic 0 via a current limiting resistor. In common anode configuration, the 7-segment LED is connected to the microcontroller in current sinking mode.

Figure 5.5 Common cathode 7-segment display

● 97

Getting Started with NXP i.MX Development Board - UK.indd 97

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

5.3 Project 1 – 7-Segment 1-digit LED counter Description: In this project, you will use a 1-digit display to count from 0 to 9. Block diagram: Figure 5.6 shows the project block diagram.

Figure 5.6 Block diagram of the project Circuit diagram: The 7-segment display used in this project is type 5161AH, red common cathode type, with a digit height of 0.56 inches. Figure 5.7 shows the display structure with its connection diagram. This is a 10-pin display with pin 1 located as shown in the figure. Pin numbering is 1 to 5 going right from pin 1. Pins 6 to 10 are located at the top part of the display, with pin 6 at the top right-hand side. Notice where pin 1 is located.

Figure 5.7 The supplied display Figure 5.8 shows the display connected to the development board through 1 kΩ current limiting resistors. The common pins of the display are connected to GND.

● 98

Getting Started with NXP i.MX Development Board - UK.indd 98

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

Figure 5.8 Circuit diagram of the project The connections between the ports and the 7-segment LED pins are as follows: 7-segment LED pin a (pin 7) b (pin 6) c (pin 4) d (pin 2) e (pin 1) f (pin 9) g (pin 10) common (pins 3,8)

Port pin J57, pin 6 57, pin 8 J57 pin 10 J57 pin 12 J57, pin 18 J57, pin 20 J56, pin 14 J60, pin 12

Before using a 7-segment display, you have to map the pins to the MCU ports. Table 5.1 shows the number to be displayed and the data to be sent to the port pins. Notice that the MSB bit (shown as x in the table) is not used and is set to 0. Number

x g f e d c b a

Port data in Hex

0

0 0 1 1 1 1 1 1

0x3F

1

0 0 0 0 0 1 1 0

0x06

2

0 1 0 1 1 0 1 1

0x5B

3

0 1 0 0 1 1 1 1

0x4F

4

0 1 1 0 0 1 1 0

0x66

5

0 1 1 0 1 1 0 1

0x6D

6

0 1 1 1 1 1 0 1

0x7D

7

0 0 0 0 0 1 1 1

0x07

8

0 1 1 1 1 1 1 1

0x7F

9

0 1 1 0 1 1 1 1

0x6F

Table 5.1 Number to be displayed and port data

● 99

Getting Started with NXP i.MX Development Board - UK.indd 99

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Program listing: Figure 5.9 shows the program listing (sevenseg-1). Array LEDS[] stores the pin numbers corresponding to the connections between the display and the development board ports. Array SEG stores the mapping between the numbers and the data to be sent to display a number, as shown in Table 5.1. As in the previous LED-based projects, you should configure the LED ports as outputs using the menu option ConfigTools. Function Display() groups a number of port pins and sends data to the group as described in earlier multiple-LED projects. Here, 8 port pins are grouped together (MSB bit is not used) and hexadecimal byte data is sent to the group as shown in Table 5.1. Variable Count stores the number to be sent to the display. The program displays numbers 0 to 9 continuously with one-second delay between each display. Notice that Count is rest to 0 when it reaches 10. Figure 5.10 shows the project built on a breadboard. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *7-segment 1 digit*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {0,15U,2U,1U,20U,17U,18U,19U};

// Only 7 used

static unsigned char SEG[] = {0x3F,0x06,0x5B,0x4F,0x66,

// See Table 5.1

0x6D, 0x7D, 0x07, 0x7F, 0x6F}; int Count = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) {

● 100

Getting Started with NXP i.MX Development Board - UK.indd 100

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

// // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,LEDS[i], 1U); else GPIO_PinWrite(GPIO1,LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */

● 101

Getting Started with NXP i.MX Development Board - UK.indd 101

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while(1)

// Do forever

{ unsigned char Pattern = SEG[Count];

// Get number to send to

Display(Pattern, 8);

// Display the number

Count++;

// Increment Count

if(Count == 10) Count = 0;

// If Count=10, set to 0

SysTick_DelayTicks(1000);

// 1 second delay

} }

Figure 5.9 Program listing

Figure 5.10 Project built on a breadboard Suggestion Note that the program can be made more readable if you create a function to display the required number and then call this function from the main program.

5.4 Project 2 – 7-Segment 4-digit multiplexed LED display Project Description This project is similar to the previous one, but here a multiplexed four-digit 7-segment display is used instead of one digit. The program displays the number 5346 on the 7-segment display. Block diagram: Figure 5.11 shows the project block diagram.

● 102

Getting Started with NXP i.MX Development Board - UK.indd 102

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

Figure 5.11 Block diagram of the project Circuit diagram: The 7-segment 4-digit display used in this project is red color common cathode type, having digit heights of 0.36 inches. Figure 5.12 shows the display structure with its connection diagram. The display features one decimal point per digit. The LEDs have a forward voltage of 1.8 VDC and a max forward current of 30 mA. The hardware interface is twelve (two rows of six) through-hole pins. Pin 1 is located as shown in the figure. Pins 1 to 6 are at the bottom, and pins 7 to 12 are at the top, with pin 7 being at the top right-hand side. Corresponding a-g pins of each digit are connected. Digit 1 is the leftmost digit.

Figure 5.12 The supplied display The individual digits of multiplexed 7-segment displays are normally enabled using transistors, as shown in Figure 5.13. This is because the current sourcing/sinking capabilities of the MCU may not be enough to turn ON the required segments. In general, any type NPN

● 103

Getting Started with NXP i.MX Development Board - UK.indd 103

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

transistor can be used, but in his project BC337 type small NPN transistors were used.

Figure 5.13 Enabling digits using transistors Figure 5.14 shows the 7-segment display connected to the GPIO ports of the development kit. A display segment is turned on when logic 1 is applied to it and when its digit is enabled by setting the port pin LOW.

Figure 5.14 Circuit diagram of the project The connections between the ports and the 7-segment LED pins are as follows (see also Table 3.1 to Table 3.4): 7-segment LED pin a (pin 11) b (pin 7) c (pin 4) d (pin 2) e (pin 1) f (pin 10) g (pin 5)

Port pin J57, pin 6 J57, pin 8 J57, pin 10 J57, pin 12 J57, pin 18 J57, pin 20 J56, pin 14

Port number 19 18 17 20 1 2 15

● 104

Getting Started with NXP i.MX Development Board - UK.indd 104

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

DIG1 DIG2 DIG3 DIG4

(pin 12) (pin 9) (pin 8) (pin 6)

J56, pin 16 J56, pin 2 J56, pin 4 J26, pin 8

16 9 10 28

Program Listing: By displaying each digit for several milliseconds, the eye cannot differentiate that the digits are not ON all the time. This way, you can multiplex any number of 7-segment displays together. For example, to display number 5346, you have to send 5 to the first digit and enable its common pin. After a few milliseconds, number 3 is sent to the second digit and the common point of the second digit is enabled, and so on. When this process is repeated continuously the user sees as if both displays are ON continuously. As in the previous projects using LEDs, the port pins used must be configured as outputs using menu option ConfigTools (Figure 5.15). Figure 5.16 shows the program listing (sevenseg-4digit). Array LEDS[] stores the LED segment port assignments, array SEG[] stores the bit pattern to turn on a digit, and array DIGITS[] stores the digit port assignments where transistors are used. The program is similar to the one with one digit. Here, number 5 is sent to digit 1 (MSD) and DIG1 (DIGITS[0]) is enabled for about 5 milliseconds. Then, DIG1 is disabled and number 3 is sent to digit 2 and DIG2 (DIGITS[1]) is enabled for about 5 milliseconds. Then, DIG2 is disabled and number 4 is sent to the third digit and DIG3 (DIGITS[2]) is enabled for about 5 seconds. Finally, DIG3 is disabled and number 6 is sent to the last digit (LSD) and DIG4 (DIGITS[3]) is enabled for about 5 seconds. This process is repeated after disabling DIG4, thus displaying number 5346 on the 7-segment display as shown in Figure 5.17. Note: You might have to increase the Drive Strength of some of the digit ports in ConfigTools to have a display with equal brightness digits.

Figure 5.15 Configure ports as outputs /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *7-segment 4 digit - display 5346*/

● 105

Getting Started with NXP i.MX Development Board - UK.indd 105

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

#include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static uint32_t LEDS[8] = {0,15U,2U,1U,20U,17U,18U,19U};

// Only 7 used

static unsigned char SEG[] = {0x3F,0x06,0x5B,0x4F,0x66,

// See Table 5.1

0x6D, 0x7D, 0x07, 0x7F, 0x6F}; static unsigned char DIGITS[] = {16U, 9U, 10U, 28U};

// DIGIT ports

static unsigned int Cnt = 5346;

// Number to

display int D1, D2, D3, D4, D5, D6; unsigned char Pattern; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

● 106

Getting Started with NXP i.MX Development Board - UK.indd 106

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

// // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,LEDS[i], 1U); else GPIO_PinWrite(GPIO1,LEDS[i], 0U); m--; } }

/* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } while(1) { D1 = Cnt / 1000;

// 1000s

Pattern = SEG[D1];

// Get the bit pattern

digit

Display(Pattern, 8);

// Send to display

GPIO_PinWrite(GPIO1, DIGITS[0], 1U);

// Enable DIG1

SysTick_DelayTicks(5);

// Wait a while

● 107

Getting Started with NXP i.MX Development Board - UK.indd 107

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

GPIO_PinWrite(GPIO1, DIGITS[0], 0U);

// Disable DIG1

D2 = Cnt % 1000; D3 = D2 / 100;

// 100s digit

Pattern =

// Get the bit pattern

SEG[D3];

Display(Pattern, 8);

// Send to display

GPIO_PinWrite(GPIO1, DIGITS[1], 1U);

// Enable DIG2

SysTick_DelayTicks(5);

// Wait a while

GPIO_PinWrite(GPIO1, DIGITS[1], 0U);

// Disable DiG2

D4 = D2 % 100; D5 = D4/10;

// 10s digit

Pattern = SEG[D5];

// Get the bit pattern

Display(Pattern, 8);

// Send to display

GPIO_PinWrite(GPIO1, DIGITS[2], 1U);

// Enable DIG3

SysTick_DelayTicks(5);

// Wait a while

GPIO_PinWrite(GPIO1, DIGITS[2], 0U);

// Disable DIG3

D6 = D4 % 10;

// 1s digit

Pattern = SEG[D6];

// Get the bit pattern

Display(Pattern, 8);

// Send to display

GPIO_PinWrite(GPIO1, DIGITS[3], 1U);

// Enable DIG4

SysTick_DelayTicks(5);

// Wait a while

GPIO_PinWrite(GPIO1, DIGITS[3], 0U);

// Disable DIG4

} }

Figure 5.16 Program listing

Figure 5.17 Project constructed on a breadboard

● 108

Getting Started with NXP i.MX Development Board - UK.indd 108

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

5.5 Project 3 – 7-Segment 4-digit multiplexed LED display counter – timer interrupts Why timer interrupts? In the previous example, you displayed a fixed number on the 7-segment display. This was not a real application, since we almost always want to display different numbers. For example, during counting, different numbers are displayed. The problem here is that the 7-segment display has to be refreshed nearly every a few milliseconds and the CPU cannot refresh the display and at the same time execute other user code as it requires multitasking. The solution is to refresh the display in a timer interrupt routine and carry out the normal user tasks in the main program. In this program, you will refresh the display in the timer interrupt service routine and then send data to the display in the main program. Description: In this project, the display will count up every second and display on the 7-segment display. A timer will be used to refresh the display every 5 milliseconds inside the timer interrupt service routine. The display counts up by 1 every second to up to 9999. It is then reset back to 0 where the counting continues. Block diagram and circuit diagram of the project are as in Figure 5.11 and 5.14 respectively. Program listing: As in the previous projects using LEDs, the port pins used must be configured as outputs using menu option ConfigTools (Figure 5.15). Figure 5.18 shows the program listing (sevenseg-counter). The main program loop is elementary. It simply increments variable cnt and waits for one second. The value of cnt is displayed inside the interrupt service routine. Inside the timer interrupt service routine, variable ms_counter is used to introduce the required delays to the main program code. This variable is incremented by one at every millisecond (i.e. at every timer interrupt). Function delay_ms() checks the value of ms_counter and waits until it equals the required delay in milliseconds. For example, calling the function as delay_ms(1000) will delay the main program loop by a second. Variable g_sysTickCounter is set to 5 at the beginning of the main program loop. It decrements by one every time a timer interrupt occurs (i.e. at every millisecond) and this variable is used to refresh the display every 5 milliseconds. The variable called flag is used inside the timer interrupt service routine, and it is used to determine which digit to enable. Initially, the flag is set to 0 and first digit is enabled. On the next entry to the interrupt service routine, flag is incremented by 1 and the second digit is enabled. While the first digit is disabled. This is done for all the four digits. Flag is cleared to zero at the end of the cycle.

● 109

Getting Started with NXP i.MX Development Board - UK.indd 109

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *7-segment 4 digit - Counter with timer interrupts*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; volatile uint32_t ms_counter = 0; static uint32_t LEDS[8] = {0,15U,2U,1U,20U,17U,18U,19U};

// Only 7 used

static unsigned char SEG[] = {0x3F,0x06,0x5B,0x4F,0x66,

// See Table 5.1

0x6D, 0x7D, 0x07, 0x7F, 0x6F}; static unsigned char DIGITS[] = {16U, 9U, 10U, 28U};

// DIGIT ports

unsigned int MSD, m, MID2, n, MID1, LSD; volatile int flag =

0, cnt = 0;

unsigned char Pattern; /******************************************************************************* * Code ******************************************************************************/ // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1;

● 110

Getting Started with NXP i.MX Development Board - UK.indd 110

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,LEDS[i], 1U); else GPIO_PinWrite(GPIO1,LEDS[i], 0U); m--; } } // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { ms_counter++;

// Increment ms

g_systickCounter--;

// Decrement 5 ms

} else {

g_systickCounter = 5; MSD = cnt / 1000;

// Every 5 ms // Get MSD

m = cnt % 1000; MID2 = m / 100;

// Get MID2

n = m % 100; MID1 = n / 10;

// Get MID1

LSD = n % 10;

// Get LSD

if(flag == 0) { GPIO_PinWrite(GPIO1, DIGITS[3], 0U);

// Disable DIG4

Pattern = SEG[MSD];

// Get pattern

Display(Pattern, 8);

// Display number

GPIO_PinWrite(GPIO1, DIGITS[0], 1U);

// Enable DIG1

flag++; } else if(flag == 1) { GPIO_PinWrite(GPIO1, DIGITS[0], 0U);

// Disable DIG1

Pattern = SEG[MID2];

// Get pattern

Display(Pattern, 8);

// Display number

GPIO_PinWrite(GPIO1, DIGITS[1], 1U);

// Enable DIG2

● 111

Getting Started with NXP i.MX Development Board - UK.indd 111

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

flag++; } else if(flag == 2) { GPIO_PinWrite(GPIO1, DIGITS[1], 0U);

// DIsable DIG2;

Pattern = SEG[MID1];

// Get pattern

Display(Pattern, 8);

// Display number

GPIO_PinWrite(GPIO1, DIGITS[2], 1U);

// Enable DIG3

flag++; } else if(flag == 3) { GPIO_PinWrite(GPIO1, DIGITS[2], 0U);

// Disable DIG3

Pattern = SEG[LSD];

// Get pattern

Display(Pattern, 8);

// Display number

GPIO_PinWrite(GPIO1, DIGITS[3], 1U);

// Enable DIG4

flag = 0; } } }

// // This function waits for the specified number of milliseconds // void delay_ms(uint32_t ms) { while(ms_counter != ms); ms_counter = 0; }

/* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { }

● 112

Getting Started with NXP i.MX Development Board - UK.indd 112

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

} g_systickCounter = 5;

// Set to 5 ms

while(1) { cnt++;

// Increment count

if(cnt > 9999) cnt = 0;

// If 9999, reset to 0

delay_ms(1000);

// Wait 1 second

} }

Figure 5.18 Program listing

5.6 Project 4 – 7-Segment 4-digit multiplexed LED display counter – blanking leading zeroes Description: In the program in Figure 5.18 the leading digits are shown as 0 when the number is lower than these digits. For example, number 12 is displayed as 0012 and not as 12. This is not desirable in many applications. In this project, we disable the leading zeroes. Program listing: Figure 5.19 shows the modified program (sevenseg-counter-blank) where the leading 0s are disabled by disabling their digits. For example, digit 1 is enabled if the number to be displayed is greater than 999, digit 2 is enabled if the number is greater than 99 and so on. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *7-segment 4 digit - Counter with timer interrupts*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /*******************************************************************************

● 113

Getting Started with NXP i.MX Development Board - UK.indd 113

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

* Variables ******************************************************************************/ volatile uint32_t g_systickCounter; volatile uint32_t ms_counter = 0; static uint32_t LEDS[8] = {0,15U,2U,1U,20U,17U,18U,19U};

// Only 7 used

static unsigned char SEG[] = {0x3F,0x06,0x5B,0x4F,0x66,

// See Table 5.1

0x6D, 0x7D, 0x07, 0x7F, 0x6F}; static unsigned char DIGITS[] = {16U, 9U, 10U, 28U};

// DIGIT ports

unsigned int MSD, m, MID2, n, MID1, LSD; volatile int flag =

0, cnt = 0;

unsigned char Pattern; /******************************************************************************* * Code ******************************************************************************/ // // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,LEDS[i], 1U); else GPIO_PinWrite(GPIO1,LEDS[i], 0U); m--; } } // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { ms_counter++;

// Increment ms

● 114

Getting Started with NXP i.MX Development Board - UK.indd 114

26-10-2023 09:34


Chapter 5 • 7-Segment LED Displays

g_systickCounter--;

// Decrement 5 ms

} else {

g_systickCounter = 5; MSD = cnt / 1000;

// Every 5 ms // Get MSD

m = cnt % 1000; MID2 = m / 100;

// Get MID2

n = m % 100; MID1 = n / 10;

// Get MID1

LSD = n % 10;

// Get LSD

if(flag == 0) { GPIO_PinWrite(GPIO1, DIGITS[3], 0U);

// Disable DIG4

Pattern = SEG[MSD];

// Get pattern

Display(Pattern, 8);

// Display number

if(cnt > 999)GPIO_PinWrite(GPIO1, DIGITS[0], 1U); flag++; } else if(flag == 1) { GPIO_PinWrite(GPIO1, DIGITS[0], 0U);

// Disable DIG1

Pattern = SEG[MID2];

// Get pattern

Display(Pattern, 8);

// Display number

if(cnt > 99)GPIO_PinWrite(GPIO1, DIGITS[1], 1U); flag++; } else if(flag == 2) { GPIO_PinWrite(GPIO1, DIGITS[1], 0U);

// DIsable DIG2;

Pattern = SEG[MID1];

// Get pattern

Display(Pattern, 8);

// Display number

if(cnt > 9)GPIO_PinWrite(GPIO1, DIGITS[2], 1U); flag++; } else if(flag == 3) { GPIO_PinWrite(GPIO1, DIGITS[2], 0U);

// Disable DIG3

Pattern = SEG[LSD];

// Get pattern

Display(Pattern, 8);

// Display number

GPIO_PinWrite(GPIO1, DIGITS[3], 1U);

// Enable DIG4

flag = 0; } } }

● 115

Getting Started with NXP i.MX Development Board - UK.indd 115

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

// // This function waits for the specified number of milliseconds // void delay_ms(uint32_t ms) { while(ms_counter != ms); ms_counter = 0; }

/* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } g_systickCounter = 5;

// Set to 5 ms

while(1) { cnt++;

// Increment count

if(cnt > 9999) cnt = 0;

// If 9999, reset to 0

delay_ms(1000);

// Wait 1 second

} }

Figure 5.19 Program listing

● 116

Getting Started with NXP i.MX Development Board - UK.indd 116

26-10-2023 09:34


Chapter 6 • Using Serial Communication

Chapter 6 • Using Serial Communication 6.1 Overview Serial communication is a simple means of sending data to long distances quickly and reliably. Serial communication can be done either in software or by using a UART chip. Using UART chip has the advantage that the communication can be very high speed. Error detection is also easily handled in UART-based systems. The most commonly used serial communication method is based on the RS-232 standard. In this standard, data is sent over a single line from a transmitting device to a receiving device in bit serial format at a pre-specified speed, also known as the baud rate, or the number of bits sent each second. Typical Baud rates are 4800, 9600, 19200, 38400, etc. RS-232 serial communication is a form of asynchronous data transmission where data is sent character by character using dedicated hardware. Each character is preceded with a Start bit, seven or eight data bits, an optional parity bit, and one or more stop bits. The most commonly used format is eight data bits, no parity bit and one stop bit. Therefore, a data frame consists of 10 bits. With a baud rate of 9600, we can transmit and receive 960 characters every second. The least significant data bit is transmitted first, and the most significant bit is transmitted last. In standard RS-232 communication, a logic high is defined to be at -12 V, and a logic 0 is at +12 V. Figure 11.1 shows how character 'A' (ASCII binary pattern 0010 0001) is transmitted over a serial line. The line is normally idle at -12 V. The start bit is first sent by the line going from high to low. Then eight data bits are sent starting from the least significant bit. Finally, the stop bit is sent by raising the line from low to high.

Figure 6.1 Sending character 'A' in serial format In serial connection, a minimum of three lines are used for communication: transmit (TX), receive (RX), and ground (GND). Some high-speed serial communication systems use additional control signals for synchronization, such as CTS, DTR, and so on. Some systems use software synchronization techniques where a special character (XOFF) is used to tell the sender to stop sending, and another character (XON) is used to tell the sender to restart transmission. RS-232 devices are connected to each other using two types of connectors: 9-way connectors, and 25-way connectors. Table 6.1 shows the TX, RX, and GND pins of each types of connectors. The connectors used in RS-232 serial communication are shown in Figure 6.2.

● 117

Getting Started with NXP i.MX Development Board - UK.indd 117

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

9-pin connector Pin

Function

2

Transmit (TX)

3

Receive (RX)

5

Ground (GND)

25-pin connector Pin

Function

2

Transmit (TX)

3

Receive (RX)

7

Ground (GND)

Table 6.1 Minimum pins required for RS-232 serial communication

Figure 6.2 RS-232 connectors As described above, RS-232 voltage levels are at ±12 V. On the other hand, microcontroller input-output ports operate at 0 to +5V voltage levels. It is therefore necessary to translate the voltage levels before a microcontroller can be connected to a RS-232 compatible device. Thus, the output signal from the microcontroller has to be converted into ±12 V, and the input from an RS-232 device must be converted into 0 to +5V before it can be connected to a microcontroller. This voltage translation is normally done using special RS232 voltage converter chips. One such popular chip is the MAX232. This is a dual converter chip having the pin configuration as shown in Figure 6.3. This particular device requires four external 1 μF capacitors for its operation.

● 118

Getting Started with NXP i.MX Development Board - UK.indd 118

26-10-2023 09:34


Chapter 6 • Using Serial Communication

Figure 6.3 MAX232 pin configuration Nowadays, serial communication is done using standard TTL logic levels instead of ±12 V, where logic 1 is +5 V (or greater than +3 V) and logic 0 is 0 V. A serial line is idle when the voltage is at +5 V. The start bit is identified on the high-to-low transition of the line, i.e. the transition from +5 V to 0 V.

6.2 Project 1 – Serial communication between the MIMXRT1010-EVK Development Kit and an Arduino UNO Description: In this project, a MIMXRT1010-EVK development kit (named the GENERATOR) and an Arduino UNO (named the SQUARER) are connected to each other via serial communication lines. The GENERATOR sends numbers to the SQUARER. The square of these numbers is taken by SQUARER and then sent back to the GENERATOR where they are displayed on the Console. Block diagram: Figure 6.4 shows the block diagram of the project.

Figure 6.4 Block diagram of the project

● 119

Getting Started with NXP i.MX Development Board - UK.indd 119

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Circuit diagram: The circuit diagram of the project is shown in Figure 6.5. In this project, serial output LPUART4 (TX, GPIO_AD_02) and serial input (RX, GPIO_AD_01) of the GENERATOR are connected to inputs 2 and 3 of the Arduino UNO (SQUARER). Pin 3 and pin 2 of the Arduino UNO are software configured as serial TX and RX pins, respectively. Additionally, the GND pins of both development kits are connected. Notice that a resistive voltage divider circuit is used to lower the Arduino UNO output voltage to +3.3 V.

Figure 6.5 Circuit diagram of the project Program listing: Before writing the program, the serial lines TX and RX of LPUART4 on the MIMXRT1010-EVK development kit must be configured as shown in Figure 6.6

Figure 6.6 Configure the LPUART4 Figure 6.7 shows the Arduino UNO program listing (Program: UART). This is a basic serial communication program. Inside the setup() function, the software serial port baud rate is set to 115200. Inside the main program loop the program reads numbers from the serial port, calculates the squares of these numbers and then sends them to UART to the MIMXRT1010-EVK development board. /************************************************************************ *

UART COMMUNICATIONS

*

===================

* * This program receives numbers from the development kit, takes * the square of these numbers and sends them back to the development kit

● 120

Getting Started with NXP i.MX Development Board - UK.indd 120

26-10-2023 09:34


Chapter 6 • Using Serial Communication

* * Program: UART * Date

: September, 2023

* Author : Dogan Ibrahim ************************************************************************/ #include "SoftwareSerial.h" SoftwareSerial MySerial(2, 3); void setup() { MySerial.begin(115200); } void loop() { while(MySerial.available() > 0)

// If data available

{ unsigned int dat = MySerial.read();

// Read data

dat = dat * dat; MySerial.print(dat); } }

Figure 6.7 Arduino UNO program Make sure that lpuart is included in the project using the SDK Manager. Figure 6.8 shows the MIMXRT1010-EVK program listing (GENERATOR). At the beginning of the program, UART LPUART4 is defined. Inside the main program loop 3 numbers are generated (1, 2, 3) and sent to the Arduino UNO over the serial link. The received numbers are displayed on the Console as shown in Figure 6.9. Note that the program must run in the Debug mode so that the data can be displayed on the Console. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *GENERATOR*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_lpuart.h"

● 121

Getting Started with NXP i.MX Development Board - UK.indd 121

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

/******************************************************************************* * Definitions ******************************************************************************/ #define MyUart

LPUART4

#define MyUart_CLK_FREQ BOARD_DebugConsoleSrcFreq() /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ int main(void) { PRINTF("BEGINNING\n\r"); uint8_t wr, rd; lpuart_config_t config; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole();

/*config.baudRate_Bps = 115200U; config.parityMode = kLPUART_ParityDisabled; config.stopBitCount = kLPUART_OneStopBit; config.txFifoWatermark = 0; config.rxFifoWatermark = 0; config.enableTx = false; config.enableRx = false; */ LPUART_GetDefaultConfig(&config); config.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE; config.enableTx

= true;

config.enableRx

= true;

LPUART_Init(MyUart, &config, MyUart_CLK_FREQ); for(wr = 1; wr < 4; wr++) { PRINTF("Sent: %d

", wr);

// Display Sent:

LPUART_WriteBlocking(MyUart, &wr, 1);

// Send a number

● 122

Getting Started with NXP i.MX Development Board - UK.indd 122

26-10-2023 09:34


Chapter 6 • Using Serial Communication

LPUART_ReadBlocking(MyUart, &rd, 1);

// Receive its square

PRINTF("Received: %c\n\r",rd);

// Display the number

} while(1); }

Figure 6.8 Program listing

Figure 6.9 Data displayed on the Console

● 123

Getting Started with NXP i.MX Development Board - UK.indd 123

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 7 • I²C Bus Interface 7.1 Overview The I²C (or I2C, or Inter Integrated Circuit) bus is commonly used in microcontroller-based projects. This is a hardware specification and protocol developed by the semiconductor division of Philips back in 1982. The aim of this chapter is to make the reader familiar with the I²C bus library functions and to show how they can be used in a real project. Before looking at the details of the project, it is worthwhile to look at the basic principles of the I²C bus.

7.2 The I²C Bus I²C bus is one of the most commonly used microcontroller communication protocols for communicating with external devices such as sensors and actuators. The I²C bus is a single master, multiple slave, half-duplex, single-ended,8-bit bus, and it can operate at standard mode: 100 Kbit/s, full speed: 400 Kbit/s, fast mode: 1 Mbit/s, and high speed: 3.2 Mbit/s. The bus consists of two open-drain signals, pulled up with resistors. The values of these resistors depend on the bus capacitance and the transmission speed. SDA: data line SCL: clock line Figure 7.1 shows the structure of an I²C bus with one master and three slaves.

Figure 7.1 I²C bus with one master and three slaves Because the I²C bus is based on just two wires, there should be a way to address an individual slave device on the same bus. For this reason, the protocol defines that each slave device provides a unique slave address for the given bus. This address is usually 7-bits wide. When the bus is free, both lines are HIGH. All communication on the bus is initiated and completed by the master, which initially sends a START bit, and completes a transaction by sending a STOP bit. This alerts all the slaves that some data is coming on the bus, and all the slaves listen on the bus. After the start bit, a 7-bit slave address is sent. Each slave device on the bus has its own address, and this ensures that only the addressed slave communicates on the bus at any time to avoid any collisions. The last sent bit is a read/ write bit such that if this bit is 0, it means that the master wishes to write to the bus (e.g. to a register of a slave), if this bit is a 1, it means that the master wishes to read from the bus (e.g. from the register of a slave). The data is sent on the bus with the MSB bit first.

● 124

Getting Started with NXP i.MX Development Board - UK.indd 124

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

An acknowledgement (ACK) bit takes place after every byte. This bit allows the receiver to signal the transmitter that the byte was received successfully and that another byte may be sent. ACK bit is sent at the 9th clock pulse. The communication over the I²C bus is simply as follows: • The master sends on the bus the address of the slave it wants to communicate with • The LSB is the R/W bit which establishes the direction of data transmission, i.e. from mater to slave (R/W = 0), or from slave to master (R/W = 1) • Required bytes are sent, each interleaved with an ACK bit, until a stop condition occurs Depending on the type of slave device used, some operations may require more than one transaction. For example, the steps to read data from an I²C compatible memory device are: • Master starts the transaction in write mode (R/W = 0) by sending the slave address on the bus • The memory location to be retrieved is then sent as two bytes (assuming 64 Kbit memory) • The master sends a STOP condition to end the transaction • The master starts a new transaction in read mode (R/W = 1) by sending the slave address on the bus • The master reads the data from the memory. If reading the memory in sequential format then more than one byte will be read. • The master sets a stop condition on the bus

7.3 Project 1 – Port expander Description: A simple project is given in this section to show how the I²C functions can be used in a program. In this project, the I²C bus compatible Port Expander chip (MCP23017) is used to add an additional 16 I/O ports to your development kit. This is useful in some applications where many I/O ports may be required. In this simple project, an LED is connected to MCP23017 port pin GPA0 (pin 21) and the LED is flashed ON and OFF every second. A 1K current limiting resistor is used in series with the LED. Block diagram: The block diagram of the project is shown in Figure 7.2.

● 125

Getting Started with NXP i.MX Development Board - UK.indd 125

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 7.2 Block diagram of the project The MCP23017 The MCP23017 is a 28-pin chip with the following features. The pin configuration is shown in Figure 7.3: • 16 bidirectional I/O ports, up to 1.7 MHz operation on I²C bus. • Interrupt capability • External reset input • Low standby current • +1.8 to +5.5 V operation • 3 address pins so that up to 8 devices can be used on the I²C bus • 28-pin DIL package

Figure 7.3 Pin configuration of the MCP23017

● 126

Getting Started with NXP i.MX Development Board - UK.indd 126

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

The pin descriptions are shown in Table 7.1. Pin

Description

GPA0-GPA7

Port A pins

GPB0-GPB7

Port B pins

VDD

Power supply

VSS

Ground

SDA

I²C data pin

SCL

I²C clock pin

RESET

Reset pin

A0-A2

I²C address pins

Table 7.1 MCP23017 pin descriptions The MCP23017 is addressed using pins A0 to A2. Table 7.2 shows the address selection. In this project, the address pins are connected to ground, thus the address of the chip is 0x20. The chip address is 7 bits wide, with the low bit is set or cleared depending on whether we wish to read data from the chip or write data to the chip respectively. Since in this project, you will be writing to the MCP23017, the low bit should be 0, making the chip byte address (also called the device opcode) as 0x40. A2

A1

A0

Address

0

0

0

0x40

0

0

1

0x21

0

1

0

0x22

0

1

1

0x23

1

0

0

0x24

1

0

1

0x25

1

1

0

0x26

1

1

1

0x27

Table 7.2 Address selection of the MCP23017 The MCP23017 chip has 8 internal registers that can be configured for its operation. The device can either be operated in one 16-bit bank mode or in two 8-bit banks mode by configuring bit IOCON.BANK. On power-up, this bit is cleared which chooses the 8-bit bank mode by default. The I/O direction of the port pins are controlled with registers IODIRA (at address 0x00) and IODIRB (at address 0x01). Clearing a bit to 0 in these registers makes the corresponding port pin(s) as output(s). Similarly, setting a bit to 1 in these registers makes the corresponding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and 0x13, respectively. This is shown in Figure 7.4.

● 127

Getting Started with NXP i.MX Development Board - UK.indd 127

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 7.4 Configuring the I/O ports Circuit diagram: Figure 7.5 shows the circuit diagram of the project. Notice that the I²C SDA and SCL pins of the port expander are connected to Arduino header pins J57 (pin 18) and J57 (pin 20) of the development kit. These pins are internally pulled up by 4.7 kΩ resistors on the development kit, and therefore there is no need to use any external pull-up resistors on the I²C bus. The LED is connected to port pin GPA0 of the MCP23017 (pin 21). The address select bits of the MCP23017 are all connected to ground.

Figure 7.5 Circuit diagram of the project Figure 7.6 shows the circuit built on a breadboard. Connections to the development kit were made using jumper wires.

Figure 7.6 Circuit built on a breadboard

● 128

Getting Started with NXP i.MX Development Board - UK.indd 128

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

More information on the MCP23017 chip can be obtained from the data sheet: http://docs-europe.electrocomponents.com/webdocs/137e/0900766b8137eed4.pdf Configuring the MCUXpresso: Before writing the program, the MCUXpresso IDE must be configured correctly. The steps are given below. • Configure Arduino header J57 (pin 18, GPIO1) and J57 (pin 20, GPIO2) as SDA and SCL ports respectively. Click ConfigTools followed by Pins • Click chip pin number 11 at the left (Figure 7.7) and then click to select I²C_ SCL, click Done • Click chip pin number 12 at the left and then click to select I²C_SDA, click Done

Figure 7.7 Configure chip pins 11 and 12 • In window Routing Details, set (Figure 7.8): Software Input On: Enabled Drive strength: R0/6 Pull/Keeper select: Keeper Pull/Keeper enable: Enabled Pull up/Down Config: No init

Figure 7.8 Configure routing details • Click ConfigTools and click Peripherals • Enable Peripherals (Figure 7.9)

● 129

Getting Started with NXP i.MX Development Board - UK.indd 129

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 7.9 Enable Peripherals • Click at the left Peripheral drivers (Device specific) at the left (Figure 7.10)

Figure 7.10 Select Peripherals • Click to select LPI² C1. You should see a window similar to Figure 7.11. Make sure that LPI² C1 is selected as the Master and the clock field is not blank. Leave the other fields as they are

Figure 7.11 Peripheral drivers

● 130

Getting Started with NXP i.MX Development Board - UK.indd 130

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

• Click ConfigTools followed by Clocks and make sure that clock is assigned to port LPI²C_CLK_ROOT • Click Update Code followed by OK The MCUXpresso is now configured correctly, and you are ready to write the program. Program listing: The program listing is shown in Figure 7.12 (PortExpander). You must include the I²C from Manage SDK Components before compiling your project (see Chapter 7 which describes how to use the Manage SDK Components tool). At the beginning of the program, the used library header files are included. MCP2307 direction register (IODIRA) and GPIO register (MCP_GPIOA) are assigned to 0x0 and 0x12 respectively. Then, various I²C based definitions and the MCP2307 slave address (shifted right and given as 0x20) are given. The system timer is set to generate interrupts every millisecond so that 1-second delays can be used in the program. Function SEND () sends data to the MCP2307 device. This function has two arguments: register address and data. Function LPI²C_MasterStart () sends a Start bit and slave address on the I²C bus to the slave device (here the MCP2307). Functions LPI²C_MasterSend () send data bytes to the slave device whose address was sent on the bus by function LPI²C_MasterStart (). Arrays buff [0] and buff [1] store the MCP2307 register address and the data to be sent to this register, respectively. Here, only one byte of register address is specified with one byte of data. Function LPI²C_MasterStop () is finally called in function SEND () to terminate the transaction on the I²C bus. Inside the main program, various I²C parameters are configured. Notice that instead of defining each parameter, you could have set the default parameters by calling function LPI²C_MasterGetDefaultConfig (&masterConfig). Before entering the program loop, function SEND (IODIRA, 0xFE) configures bit 0 of PORT A as output. Then the program loop is formed using a while statement. Inside this loop, function SEND () is called to set bit 0 of the port to 0 and to 1 with one-second delay between each output. The result is that the LED is flashing every second. If you wish to run the program in debug mode, click Debug under Quickstart Panel, and then click Run → Resume to run the program. Alternatively, select to run in Release mode (Project → Build Configurations → Set Active → Release) and load the .axf file (or right click on .axf file followed by Binary Utilities → Create bin file to create the .bin file) to the target development kit. You should see the LED flashing every second. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *MCP23017 Port Expander*/

● 131

Getting Started with NXP i.MX Development Board - UK.indd 131

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

#include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "stdio.h" #include "fsl_debug_console.h" #include "fsl_lpi2c.h" #include "string.h"

/******************************************************************************* * Definitions ******************************************************************************/ #define IODIRA 0x00 #define MCP_GPIOA 0x12 #define EXAMPLE_I2C_MASTER_BASE (LPI2C1_BASE) /* Select USB1 PLL (480 MHz) as master lpi2c clock source */ #define LPI2C_CLOCK_SOURCE_SELECT (0U) /* Clock divider for master lpi2c clock source */ #define LPI2C_CLOCK_SOURCE_DIVIDER (5U) /* Get frequency of lpi2c clock */ #define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk)/8)/ (LPI2C_CLOCK_SOURCE_DIVIDER+1U)) #define LPI2C_MASTER_CLOCK_FREQUENCY LPI2C_CLOCK_FREQUENCY #define WAIT_TIME

10U

#define EXAMPLE_I2C_MASTER ((LPI2C_Type *)EXAMPLE_I2C_MASTER_BASE) #define LPI2C_MASTER_SLAVE_ADDR_7BIT 0x20U #define LPI2C_BAUDRATE

100000U

/******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code

● 132

Getting Started with NXP i.MX Development Board - UK.indd 132

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

// // This function sends register address and register data to MCP23017 chip // void SEND(uint32_t port, uint32_t data) { uint32_t buff[2]; status_t reVal = kStatus_Fail; buff[0]=port; // Address buff[1]=data; // Data if (kStatus_Success == LPI2C_MasterStart(EXAMPLE_I2C_MASTER, LPI2C_MASTER_ SLAVE_ADDR_7BIT, kLPI2C_Write)) { PRINTF("STARTED\n\r"); } reVal = LPI2C_MasterSend(EXAMPLE_I2C_MASTER, &buff[0], 1); if (reVal != kStatus_Success) {

PRINTF("ERROR IN SEND\n\r");

}

● 133

Getting Started with NXP i.MX Development Board - UK.indd 133

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

reVal = LPI2C_MasterSend(EXAMPLE_I2C_MASTER, &buff[1], 1); if (reVal != kStatus_Success) {

PRINTF("ERROR IN SEND\n\r");

} LPI2C_MasterStop(EXAMPLE_I2C_MASTER); }

/* Main function */ int main(void) { PRINTF("BEGINNING\n\r"); BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); lpi2c_master_config_t masterConfig; /*Clock setting for LPI2C*/ CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT); CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER); // // I2C configuration // masterConfig.debugEnable = false; masterConfig.ignoreAck = false; masterConfig.pinConfig = kLPI2C_2PinOpenDrain; masterConfig.baudRate_Hz = 100000U; masterConfig.busIdleTimeout_ns = 0; masterConfig.pinLowTimeout_ns = 0; masterConfig.sdaGlitchFilterWidth_ns = 0; masterConfig.sclGlitchFilterWidth_ns = 0; //

LPI2C_MasterGetDefaultConfig(&masterConfig);

/* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } }

● 134

Getting Started with NXP i.MX Development Board - UK.indd 134

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

/* Change the default baudrate configuration */ masterConfig.baudRate_Hz = LPI2C_BAUDRATE; /* Initialize the LPI2C master peripheral */ LPI2C_MasterInit(EXAMPLE_I2C_MASTER, &masterConfig, LPI2C_MASTER_CLOCK_FREQUENCY); SEND(IODIRA, 0xFEU);

// Configure as outputs

while(1) {

SEND(MCP_GPIOA, 0U);

// LED OFF

SysTick_DelayTicks(1000);

// One sec delay

SEND(MCP_GPIOA, 1U);

// LED ON

SysTick_DelayTicks(1000);

// One sec delay

} }

Figure 7.12 Program listing

7.4 Project 2 – TMP102 temperature sensor chip Description: In this project the I²C compatible TMP102 temperature sensor chip is used. The ambient temperature is read every second and is displayed on the debug Console. The aim of this project is to show how the temperature sensor chip TMP102 can be used in a program. The TMP102 The TMP102 is an I²C compatible temperature sensor chip having the following basic features: Supply voltage: 1.4 V to 3.6 V Supply current: 10 μA Accuracy: 2ºC Resolution: 12 bits (0.0625ºC) Accuracy: ±0.5ºC TMP102 is a 6-pin chip as shown in Figure 7.13. The pin descriptions are: Pin 1 2 3 4 5 6

Name Description SCL I²C line GND power supply ground ALERT Over temperature alert. Open-drain output, requires a pull-up resistor ADD0 Address select V+ power supply SDA I²C line

● 135

Getting Started with NXP i.MX Development Board - UK.indd 135

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 7.13 TMP102 pin layout The default operating mode of TMP102 is continuous conversion where the internal ADC converts the temperature into digital with the default rate of 4 Hz, with a conversion time of 26 ms. The temperature register is a 16-bit register where bits 0, 1, 2, and 3 are set to 0, and bits 4 to 15 store the 12-bit temperature data. TMP102 has the following operational modes: • Continuous conversion: by default, an internal ADC converts the temperature into digital format with the default conversion rate of 4 Hz, with a conversion time of 26 ms. The conversion rate can be selected using bits CR1 and CR0 of the configuration register as 0.25Hz, 1Hz, 4 Hz (default), and 8Hz. In this project, the default 4 Hz is used. • Extended mode: Bit EM of the configuration register selects normal mode (EM = 0), or extended mode (EM = 1). In normal mode (default mode) the converted data is 12 bits. Extended mode is used if the temperature is above 128ºC and the converted data is 13 bits. In this project, the normal mode is used. • Shutdown mode: This mode is used to save power where the current consumption is reduced to less than 0.5 μA. The shutdown mode is entered when configuration register bit SD = 1. The default mode is normal operation (SD = 0). • One-shot conversion: Setting configuration register bit OS to 1 selects the one-shot mode, which is a single conversion mode. The default mode is continuous conversion (OS = 0). • Thermostat mode: This mode indicates whether to operate in comparator mode (TM = 0) or in interrupt mode (TM = 1). The default is the comparator mode. In comparator mode, the Alert pin is activated when the temperature equals or exceeds the value in the THIGH register and remains active until the temperature drops below TLOW. In interrupt mode, the Alert pin is activated when the temperature exceeds THIGH or goes below TLOW registers. The Alert pin is cleared when the host controller reads the temperature register. A Pointer Register selects various registers in the chip as shown in Table 7.3. The upper 6 bits of this register are 0s.

● 136

Getting Started with NXP i.MX Development Board - UK.indd 136

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

P1

P0

REGISTER SELECTED

0

0

Temperature register (read only)

0

1

Configuration register

1

0

TLOW register

1

1

THIGH register

Table 7.3 Pointer register bits Table 7.4 shows the temperature register bits in normal mode (EM = 0). BYTE 1: D7

D6

D5

D4

D3

D2

D1

D0

T11

T10

T9

T8

T7

T7

T5

T4

D7

D6

D5

D4

D3

D2

D1

D0

T3

T2

T1

T0

0

0

0

0

BYTE 2:

Table 7.4 Temperature register bits Table 7.5 shows the configuration register bits. The power-up default bit configuration is shown in the Table. BYTE 1: D7

D6

D5

D4

D3

D2

D1

D0

OS

R1

R0

F1

F0

POL

TM

SD

0

1

1

0

0

0

0

0

D6

D5

D4

D3

D2

D1

D0

BYTE 2: D7 CR1

CR0

AL

EM

0

0

0

0

1

0

1

0

0

0

0

0

Table 7.5 Configuration register bits The Polarity bit (POL) allows the user to adjust the polarity of the Alert pin output. If set to 0 (default), the Alert pin becomes active low. When set to 1, the Alert pin becomes active high. TMP102 is available as a module (breakout module) as shown in Figure 7.14. The default device address is 0x48. The temperature register address is 0x00, and this should be sent after sending the device address. This is then followed with a read command where 2 bytes are read from the TMP102. These 2 bytes contain the temperature data.

● 137

Getting Started with NXP i.MX Development Board - UK.indd 137

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

The temperature read sequence is as follows: • Master sends the device address 0x48 with the R/W set to 0 • Device responds with ACK • Master sends the temperature register address 0x00 • Device responds with ACK • Master re-sends device address 0x48 with the R/W bit set to 1 • Master reads upper byte of temperature data • Device sends ACK • Master reads lower byte of temperature data • Device sends ACK • Master sends stop condition on the bus

Figure 7.14 TMP102 as a module Block diagram: Figure 7.15 shows the block diagram of the project.

Figure 7.15 Block diagram of the project Circuit diagram: The circuit diagram of the project is shown in Figure 7.16. On-chip pullup resistors are available on the development kit and are not needed in this project.

● 138

Getting Started with NXP i.MX Development Board - UK.indd 138

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

Figure 7.16 Circuit diagram of the project Program listing: Before writing the program, the SDA and SCL ports must be configured as described in the previous project. You must include the I²C from Manage SDK Components before compiling your project. Figure 7.17 shows the program listing (TMP102). At the beginning of the program, various definitions used by the I²C library are defined. The TMP102 address is set to 0x48. The function GET_TEMPERATURE () operates as follows: • Call MasterStart() with the LSB set to 0 (i.e. write) • Call MasterSend() to send the pointer register address as 0 (temperature register) • Call MasterRepeatedStart() with the LSB set to 1 (i.e. read) • Call MasterReceive() to receive two bytes of data from the TMP102 The received two bytes are then converted into temperature in Degrees Centigrade. The main program loop calls the function GET_TEMPERATURE () and displays the temperature every 3 seconds. Example output from the program on the Console is shown in Figure 7.18. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *TMP102*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "stdio.h" #include "fsl_debug_console.h" #include "fsl_lpi2c.h" #include "string.h"

● 139

Getting Started with NXP i.MX Development Board - UK.indd 139

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

/******************************************************************************* * Definitions ******************************************************************************/ uint8_t Temp_Reg = 0x00; #define EXAMPLE_I2C_MASTER_BASE (LPI2C1_BASE) /* Select USB1 PLL (480 MHz) as master lpi2c clock source */ #define LPI2C_CLOCK_SOURCE_SELECT (0U) /* Clock divider for master lpi2c clock source */ #define LPI2C_CLOCK_SOURCE_DIVIDER (5U) /* Get frequency of lpi2c clock */ #define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_ CLOCK_SOURCE_DIVIDER + 1U)) #define LPI2C_MASTER_CLOCK_FREQUENCY LPI2C_CLOCK_FREQUENCY #define WAIT_TIME

10U

#define EXAMPLE_I2C_MASTER ((LPI2C_Type *)EXAMPLE_I2C_MASTER_BASE) #define LPI2C_MASTER_SLAVE_ADDR_7BIT 0x48U #define LPI2C_BAUDRATE

100000U

/******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) {

● 140

Getting Started with NXP i.MX Development Board - UK.indd 140

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

// // This function sends register address and register data to MCP23017 chip // float GET_TEMPERATURE() { uint8_t buff[10]; int16_t comb; float temperature, LSB = 0.0625; status_t reVal = kStatus_Fail; buff[0]=Temp_Reg; if (!kStatus_Success == LPI2C_MasterStart(EXAMPLE_I2C_MASTER, LPI2C_MASTER_ SLAVE_ADDR_7BIT, kLPI2C_Write)) {

PRINTF("WRITE FAILED..\n\r");

} reVal = LPI2C_MasterSend(EXAMPLE_I2C_MASTER, &buff[0], 1); if (reVal != kStatus_Success) {

PRINTF("SEND FAILED\n\r");

} if (!kStatus_Success == LPI2C_MasterRepeatedStart(EXAMPLE_I2C_MASTER, LPI2C_MASTER_SLAVE_ADDR_7BIT, kLPI2C_Read)) {

PRINTF("READ FAILED..\n\r");

} reVal = LPI2C_MasterReceive(EXAMPLE_I2C_MASTER, buff, 2); if (reVal != kStatus_Success)

● 141

Getting Started with NXP i.MX Development Board - UK.indd 141

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{

PRINTF("ERROR IN RECEIVE\n\r");

} LPI2C_MasterStop(EXAMPLE_I2C_MASTER); comb = ((int16_t)buff[0] << 4) | (buff[1] >> 4);

// Combine the

bytes if (comb > 0x7FF )

// If negative

{ comb = (~comb) & 0xFFF; comb = comb + 1; temperature = -comb * LSB; } else temperature = comb * LSB; return temperature;

// Return temperature

}

/* Main function */ int main(void) { PRINTF("BEGINNING\n\r"); float T; char buff[7]; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); lpi2c_master_config_t masterConfig; /*Clock setting for LPI2C*/ CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT); CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER); // // I2C configuration // /*

masterConfig.debugEnable = false; masterConfig.ignoreAck = false; masterConfig.pinConfig = kLPI2C_2PinOpenDrain; masterConfig.baudRate_Hz = 100000U; masterConfig.busIdleTimeout_ns = 0; masterConfig.pinLowTimeout_ns = 0; masterConfig.sdaGlitchFilterWidth_ns = 0;

● 142

Getting Started with NXP i.MX Development Board - UK.indd 142

26-10-2023 09:34


Chapter 7 • I²C Bus Interface

masterConfig.sclGlitchFilterWidth_ns = 0; */ LPI2C_MasterGetDefaultConfig(&masterConfig);

/* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } SysTick_DelayTicks(50); /* Change the default baudrate configuration */ masterConfig.baudRate_Hz = LPI2C_BAUDRATE; /* Initialize the LPI2C master peripheral */ LPI2C_MasterInit(EXAMPLE_I2C_MASTER, &masterConfig, LPI2C_MASTER_CLOCK_FREQUENCY);

while(1) { T = GET_TEMPERATURE(); PRINTF("Temperature = %d\n", (int)T);

SysTick_DelayTicks(3000);

// Read temperature // Display it // One second delay

} }

Figure 7.17 Program listing Table 7.6 shows the data output format of the temperature. Let us look at two examples: Example 1: Measured value = 0011 00100000

= 0x320

= 800 decimal

This is positive temperature, so the temperature is 800 x 0.0625 = +50ºC Example 2: Measured value = 1110 01110000

= 0xE70

This is negative temperature, complement is 0001 10001111 adding 1 gives 0001 10010000 = 400 decimal. The temperature is 400 x 0.0625 = 25 or, -25ºC

● 143

Getting Started with NXP i.MX Development Board - UK.indd 143

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 7.18 Example output from the program Temperature

Digital Output (Binary)

Digital Output (Hex)

128

011111111111

7FF

100

011001000000

640

50

001100100000

320

0.25

000000000100

004

-0.25

111111111100

FFC

-25

111001110000

E70

-55

110010010000

C90

Table 7.6 Data output for some temperature readings. To run the program, click the Debug button under the Quickstart Panel. Then, click Run → Resume. Make sure that the Quick Settings → SDK Debug Console is set to Semihost console. Stop the program by clicking Run → Terminate. Figure 7.19 shows the project built on a breadboard.

Figure 7.19 Project built on a breadboard

● 144

Getting Started with NXP i.MX Development Board - UK.indd 144

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

Chapter 8 • SPI Bus Interface 8.1 Overview In the previous chapter, you have learned how to interface I²C devices to your development kit. In this chapter you will be developing projects using the SPI bus (Serial Peripheral Interface). The SPI bus is one of the commonly used protocols to connect sensors and many other devices to microcontrollers. The SPI bus is a master-slave type bus protocol. In this protocol, one device (the microcontroller) is designated as the master, and one or more other devices (usually sensors) are designated as slaves. In a minimum bus configuration, there is one master and only one slave. The master establishes communication with the slaves and controls all the activity on the bus. Figure 8.1 shows an SPI bus example with one master and 3 slaves. The SPI bus uses 3 signals: clock (SCK), data in (SDI), and data out (SDO). SDO of the master is connected to the SDIs of the slaves, and SDOs of the slaves are connected to the SDI of the master. The master generates the SCK signals to enable data to be transferred on the bus. In every clock pulse, one bit of data is moved from master to slave, or from slave to master. The communication is only between a master and a slave, and the slaves cannot communicate with each other. It is important to note that only one slave can be active at any time, since there is no mechanism to identify the slaves. Thus, slave devices have enable lines (e.g. CS or CE) which are normally controlled by the master. A typical communication between a master and several slaves is as follows: • Master enables slave 1 • Master sends SCK signals to read or write data to slave 1 • Master disables slave 1 and enables slave 2 • Master sends SCK signals to read or write data to slave 2 • The above process continues as required

Figure 8.1 SPI bus with one master and 3 slaves The SPI signal names are also called MISO (Master in, Slave out), and MOSI (Master out, Slave in). Clock signal SCK is also called SCLK and the CS is also called SSEL. In the SPI projects in this chapter the development kit is the master, and one or more slaves can be connected to the bus. Transactions over the SPI bus are started by enabling the SCK line. The master then asserts the SSEL line LOW so that data transmission can begin. The data transmission involves two registers, one in the master and one in the slave device. Data

● 145

Getting Started with NXP i.MX Development Board - UK.indd 145

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

is shifted out from the master into the slave, with the MSB bit first. If more data is to be transferred, then the process is repeated. Data exchange is complete when the master stops sending clock pulses and deselects the slave device. Both the master and the slave must agree on the clock polarity and phase on the line, which are known as the SPI bus modes. These two settings are named as Clock Polarity (CPOL) and Clock Phase (CPHA) respectively. CPOL and CPHA can have the following values: CPOL 1 1

Clock active state Clock active HIGH Clock active LOW

CPHA 1 2

Clock phase Clock out of phase with data Clock in phase with data

The four SPI modes are: Mode 0 1 2 3

CPOL 0 0 1 1

CPHA 0 1 0 1

When CPOL = 0, the active state of the clock is 1, and its idle state is 0. For CPHA = 0, data is captured on the rising clock, and data is shifted out on the falling clock. For CPHA = 1, data is captured on the falling edge of the clock, and is shifted out on the rising edge of the clock. When CPOL = 1, the active state of the clock is 0, and its idle state is 1. For CPHA = 0, data is captured on the falling edge of the clock and is output on the rising edge. For CPHA = 1, data is captured on the rising edge of the clock and is shifted out on the falling edge.

8.2 Project 1 – Port expander Description: A simple project is given in this section to show how the SPI functions can be used in a program. This project is similar to the port expander project from the previous chapter where an LED is connected to one of the port expander pins and the LED is flashed every second. In this project, the MCP23S17 port expander chip is used. This is the SPI version of the MCP23017 chip.

● 146

Getting Started with NXP i.MX Development Board - UK.indd 146

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

Block diagram: Figure 8.2 shows the block diagram of the project.

Figure 8.2 Block diagram of the project The MCP23S17 port expander chip The MCP23S17 is a 28-pin chip with the following features. The pin configuration is shown in Figure 8.3, which is the same as the pin configuration of MCP23017, but SPI pins are used instead of I²C pins: • 16 bidirectional I/O ports • Up to 1.7 MHz operation on I²C bus • Interrupt capability • External reset input • Low standby current • +1.8 V to +5.5 V operation • 3 address pins so that up to 8 devices can be used on the SPI bus • 28-pin DIL package

Figure 8.3 Pin configuration of the MCP23S17

● 147

Getting Started with NXP i.MX Development Board - UK.indd 147

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

The pin descriptions are given in Table 8.1. Pin

Description

GPA0-GPA7

Port A pins

GPB0-GPB7

Port B pins

VDD

Power supply

VSS

Ground

SI

SPI MOSI data pin

SCK

SPI clock pin

SO

SPI MISO data pin

CS

SPI SSEL chip enable pin

A0-A2

I²C address pins

RESET

Reset pin

INTA

Interrupt pin

INTB

Interrupt pin

Table 8.1 MCP23S17 pin descriptions The MCP23S17 is a slave SPI device. The slave address contains four upper fixed bits (0100) and three user-defined hardware address bits (pins A2, A1 and A0) with the read/ write bit filling out the control byte. These address bits are enabled/disabled by control register IOCON.HAEN. By default, the user address bits are disabled at power-up (i.e. IOCON.HAEN = 0) and A2 = A1 = A0 = 0 and the chip is addressed with 0x40. As such, we can use two MCP23S17 chips on SPI0 by connecting one CS bit to CE0, and the other one to CE1 and addressing both chips with 0x40. By setting bit HAEN to 1, you can change the addresses of the devices in multiple MCP23S17 based applications (e.g. more than 2) by connecting the A2, A1, and A0 accordingly. Sixteen of such chips can be connected (8 to CE0 and 8 to CE1), corresponding to 16x16 = 256 I/O ports. Figure 8.4 and Figure 8.5 show the addressing format. The address pins should be externally biased even if disabled.

Figure 8.4 MCP23S17 control byte format

● 148

Getting Started with NXP i.MX Development Board - UK.indd 148

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

Figure 8.5 MCP23S17 addressing registers Like the MCP23017, the MCP23S17 chip has 8 internal registers that can be configured for its operation. The device can either be operated in 16-bit-bank mode or in two 8-bit-bank mode by configuring bit IOCON.BANK. On power-up, this bit is cleared which chooses the two 8-bit-bank mode by default. The I/O direction of the port pins are controlled with registers IODIRA (at address 0x00) and IODIRB (at address 0x01). Clearing a bit to 0 in these registers makes the corresponding port pin(s) as output(s). Similarly, setting a bit to 1 in these registers makes the corresponding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and 0x13, respectively. This is shown in Figure 8.6.

Figure 8.6 Configuring the I/O ports Further information on the MCP23S17 chip can be obtained from the Microchip Inc data sheet at the following website: http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf Circuit diagram: Figure 8.7 shows the circuit diagram of the project. The LED is connected to port pin 21 (GPIAO bit 0) of the MCP23S17 through a current limiting resistor. The interface between the development kit and the MCP23S17 chip is as follows: MCP23S17 Development Kit Arduino header Pin name SI J57, pin 8 GPIO_AD_04 (IO18) SCK J57, pin 12 GPIO_AD_06 (IO20) CS J57, pin 6 GPIO_AD_05 (IO19) GND J60, pin 12 GND +3.3 V J60, pin 8 +3.3 V

● 149

Getting Started with NXP i.MX Development Board - UK.indd 149

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 8.7 Circuit diagram of the project Program listing: Before writing the program, you should configure the SPI ports as described below: • Click ConfigTools followed by Pins and configure GPIO_AD_04 as LPSPI_SO, GPIO_AD_05 as LPSPI_PCS0 and GPIO_AD_06 as LPSPI_SCK as shown in Figure 8.8

Figure 8.8 Configure the SPI ports • Click ConfigTools followed by Peripherals and then click Peripheral drivers (Device specific). Click on LPSPI (Figure 8.9)

● 150

Getting Started with NXP i.MX Development Board - UK.indd 150

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

Figure 8.9 Click on Peripheral drivers (Device specific) • You should see the LPSPI window as shown in Figure 8.10 (If there are any errors or warnings, right-click on the displayed error/warning on the right-hand side window called Problems and accept to correct the error/warning)

Figure 8.10 LPSPI window • Click ConfigTools followed by Clocks and make sure that clock is assigned to LPSPI_CLK_ROOT • Click Update Code followed by OK to exit the configuration tool You must include lpspi in your project using the Manage SDK Components, as described in the previous chapter on how to use the SDK manager. You are now ready to write the program. Figure 8.11 shows the program listing (MCP23S17). At the beginning of the program, the MCP23S17 device address and used register addresses are defined. Also, various SPI bus parameters are defined here. Function SEND () sends data to the MCP23S17 over

● 151

Getting Started with NXP i.MX Development Board - UK.indd 151

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

the SPI bus. A buffer is created and the MCP23S17 device address, the register address to be accessed, and the data to be sent to the device are all stored in a buffer called buff. Data in this buffer is then sent over the SPI bus using call LPSPI_MasterTransferBlocking (). Inside the main program loop, the MCP23S17 port GPIOA bit 0 is configured as output. Then a while loop is formed where 1 and 0 are sent to the LED to flash it every second. If you want to receive data over the SPI bus, you can use the same program but use the receive data option by specifying masterXfer. rxData = masterRxData. Figure 8.12 shows the project built on a breadboard. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *MCP23S17*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_lpspi.h" /******************************************************************************* * Definitions ******************************************************************************/ #define SPI_Address 0x40

// Device addr

#define MCP_GPIOA 0x12 // GPIOA #define MCP_IODIRA 0 // IODIRA #define EXAMPLE_LPSPI_MASTER_BASEADDR

(LPSPI1)

#define EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT

(kLPSPI_Pcs0)

#define EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER (kLPSPI_MasterPcs0) /* Select USB1 PLL PFD0 (720 MHz) as lpspi clock source */ #define EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT (1U) /* Clock divider for master lpspi clock source */ #define EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER (7U) #define LPSPI_MASTER_CLK_FREQ (CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (EXAMPLE_ LPSPI_CLOCK_SOURCE_DIVIDER + 1U)) #define TRANSFER_BAUDRATE 500000U /*! Transfer baudrate - 500k */ /******************************************************************************* * Prototypes

● 152

Getting Started with NXP i.MX Development Board - UK.indd 152

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; volatile uint32_t g_systickCounter

= 20U;

lpspi_master_config_t masterConfig; lpspi_transfer_t masterXfer; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // This function sends register address and register data to MCP23S17 chip // float SEND(uint8_t port, uint8_t data) { uint8_t buff[3]; buff[0] = SPI_Address; buff[1] = port; buff[2] = data; /*Start master transfer, transfer data to slave.*/

● 153

Getting Started with NXP i.MX Development Board - UK.indd 153

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

masterXfer.txData

= buff;

masterXfer.rxData

= NULL;

masterXfer.dataSize = 3; masterXfer.configFlags = EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap; LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer); /* Delay 20 ms to wait slave is ready */ SysTick_DelayTicks(20); }

/* Main function */ int main(void) { PRINTF("BEGINNING\n\r"); BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } /*Set clock source for LPSPI*/ CLOCK_SetMux(kCLOCK_LpspiMux, EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT); CLOCK_SetDiv(kCLOCK_LpspiDiv, EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER); uint32_t srcClock_Hz;

LPSPI_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate = TRANSFER_BAUDRATE; masterConfig.whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT; masterConfig.pcsToSckDelayInNanoSec

= 1000000000U / (masterConfig.

baudRate * 2U); masterConfig.lastSckToPcsDelayInNanoSec

= 1000000000U / (masterConfig.

baudRate * 2U); masterConfig.betweenTransferDelayInNanoSec = 1000000000U / (masterConfig.

● 154

Getting Started with NXP i.MX Development Board - UK.indd 154

26-10-2023 09:34


Chapter 8 • SPI Bus Interface

baudRate * 2U); srcClock_Hz = LPSPI_MASTER_CLK_FREQ; LPSPI_MasterInit(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterConfig, srcClock_Hz); SEND(MCP_IODIRA, 0xFE);

// Configure GPIOA bit 0 as output

while(1) { SEND(MCP_GPIOA, 1);

// GPIOA bit 0 is 1

SysTick_DelayTicks(1000);

// One second delay

SEND(MCP_GPIOA, 0);

// GPIOA bit 0 is 0

SysTick_DelayTicks(1000);

// One second delay

} }

Figure 8.11 Program listing

Figure 8.12 Project built on a breadboard

● 155

Getting Started with NXP i.MX Development Board - UK.indd 155

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 9 • Using LCDs 9.1 Overview In microcontroller systems, the output of a measured variable is usually displayed using LEDs, 7-segment displays, or LCD-type displays. LCDs have the advantages that they can be used to display alphanumeric or graphical data. Some LCDs have 40 or more character lengths with the capability to display several lines. Some other LCDs can be used to display graphic images. Some modules offer color displays, while some others incorporate back lighting so that they can be viewed in dimly lit conditions. There are basically two types of LCDs as far as the interface technique is concerned: parallel LCDs and serial LCDs. Parallel LCDs (e.g. Hitachi HD44780) are connected to a microcontroller using more than one data line and the data is transferred in parallel form. It is common to use either 4 or 8 data lines. Using a 4-wire connection saves I/O pins, but it is slower since the data is transferred in two stages. Serial LCDs are connected to the microcontroller using only one data line, and data is usually sent to the LCD using the standard RS-232 asynchronous data communication protocol. Serial LCDs are much easier to use, but they cost more than the parallel ones. The programming of a parallel LCD is usually a complex task and requires a good understanding of the internal operation of the LCD controllers, including the timing diagrams. Fortunately, most high-level languages provide special library commands for displaying data on alphanumeric as well as on graphical LCDs. All the user has to do is connect the LCD to the microcontroller, define the LCD connection in the software, and then send special commands to display data on the LCD.

9.2 The HD44780 LCD module HD44780 is one of the most popular alphanumeric LCD modules used in industry and also by hobbyists. This module is monochrome and comes in different sizes. Modules with 8, 16, 20, 24, 32, and 40 columns are available. Depending on the model chosen, the number of rows varies between 1, 2 or 4. The display provides a 14-pin (or 16-pin) connector to a microcontroller. Table 9.1 gives the pin configuration and pin functions of a 14-pin LCD module. Below is a summary of the pin functions: Pin no

Name

Function

1

VSS

Ground

2

VDD

+ ve supply

3

VEE

Contrast

4

RS

Register select

5

R/W

Read/write

6

E

Enable

7

D0

Data bit 0

8

D1

Data bit 1

● 156

Getting Started with NXP i.MX Development Board - UK.indd 156

26-10-2023 09:34


Chapter 9 • Using LCDs 9

D2

Data bit 2

10

D3

Data bit 3

11

D4

Data bit 4

12

D5

Data bit 5

13

D6

Data bit 6

14

D7

Data bit 7

Table 9.1 Pin configuration of HD44780 LCD module VSS is the 0 V supply or ground. The VDD pin should be connected to the positive supply. Although the manufacturers specify a 5 V DC supply, the modules will usually work with as low as 3 V or as high as 6 V. Pin 3 is named VEE and this is the contrast control pin. This pin is used to adjust the contrast of the display, and it should be connected to a variable voltage supply. A potentiometer is normally connected between the power supply lines, with its wiper connected to this pin so that the contrast can be adjusted. Pin 4 is the Register Select (RS) and when this pin is LOW, data transferred to the display is treated as commands. When RS is HIGH, character data can be transferred to and from the module. Pin 5 is the Read/Write (R/W) line. This pin is pulled LOW to write commands or character data to the LCD module. When this pin is HIGH, character data or status information can be read from the module. Pin 6 is the Enable (E) pin, which is used to initiate the transfer of commands or data between the module and the microcontroller. When writing to the display, data is transferred only on the HIGH to LOW transition of this line. When reading from the display, data becomes available after the LOW to HIGH transition of the enable pin, and this data remains valid as long as the enable pin is at logic HIGH. Pins 7 to 14 are the eight data bus lines (D0 to D7). Data can be transferred between the microcontroller and the LCD module using either a single 8-bit byte, or as two 4-bit nibbles. In the latter case, only the upper four data lines (D4 to D7) are used. 4-bit mode has the advantage that four less I/O lines are required to communicate with the LCD. In this book, we shall be using alphanumeric-based LCD only and look at the 4-bit interface only. Figure 9.1 shows a typical HD44780 controller based 2 × 16 (2 rows and 16 columns) character LCD. In this chapter you will learn how to interface and program an LCD to the development Kit.

● 157

Getting Started with NXP i.MX Development Board - UK.indd 157

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 9.1 2 × 16 character LCD Connecting the LCD to the development board The following pins are used in 4-bit mode: D4:D7 E R/S It is important to connect the R/W pin to ground pin of the power supply before applying power to the LCD. The following connections will be used between the LCD and the development kit in LCD-based projects in this book: LCD Pin Development Kit Arduino header pin D4 J57, pin6 IO19 D5 J57, pin 8 IO18 D6 J57, pin 10 IO17 D7 J57, pin 12 IO20 R/S J57, pin 18 IO1 E J57, pin 20 IO2 R/W J60, pin 12 GND

9.3 Project 1 – Displaying text on LCD Description: In this project, text is displayed on the LCD. The aim of this simple project is to show how an LCD can be programmed using the MCUXpresso IDE with your development kit. The text TESTING LCD is displayed on the LCD. Block diagram: The block diagram of the project is shown in Figure 9.2.

● 158

Getting Started with NXP i.MX Development Board - UK.indd 158

26-10-2023 09:34


Chapter 9 • Using LCDs

Figure 9.2 Block diagram of the project Circuit diagram: Figure 9.3 shows the connections between the LCD and the development kit. The LCD contrast is adjusted using a 10 kΩ potentiometer.

Figure 9.3 Circuit diagram of the project Program listing: The used port pins must be configured as outputs, as in the previous projects. In this project, the HD44780 compatible LCD is programmed from the first principles without using a library. Programming an LCD requires good knowledge of its pins and timing details, which are available in the LCD data sheets. Although this is beyond the scope of this book, some details are given here. Initializing the LCD: The HD44780 LCD has 8 data pins D0 to D7. It can either be programmed in 8-bit mode where data is sent to all 8 bits in parallel and at the same time, or 4-bit programming mode can be selected where the 8-bit data is divided into two nibbles (4-bits) and first the higher nibble is sent followed by the lower nibble on data pins D4 to D7 (i.e. the lower bits D0 to D3 are not used). The LCD should be initialized before it can be used. The initialization sequence is described in detail in the data sheet, and it basically consists of sending nibble 0x03 three times followed by sending nibble 0x02. The enable input E must be clocked after sending each nibble of data. Clocking the E input simply consists of sending logic HIGH followed by logic LOW with some delay in between. This is also called applying STROBE to the LCD. At the end of sending the four nibbles, the LCD is initialized to operate in 4-bit mode. The remaining parts of the initialization sequence involve configuring the function set, which sets the number of lines and the character set (5 × 10 or 5 × 8). Usually, command 0x28 is sent to the LCD, which selects two lines with a 5 × 8 dot character set. The initialization sequence is terminated by setting the display on/off control, clearing the display, and configuring the entry mode set. The LCD operates either in command mode or in data mode. The command mode is identified with pin R/S set to LOW. During the data mode, R/S is set HIGH. After the initialization sequence, various LCD functions are defined, such as homing the cursor, moving the cursor to a specified position, displaying a character or text, etc.

● 159

Getting Started with NXP i.MX Development Board - UK.indd 159

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 9.4 shows the program listing (lcd1). The LCD initialization and the definition of various LCD functions are done in the early parts of the code, starting with the comment LCD CODES, and terminating with the comment END OF LCD CODES. Inside the main program, the text TESTING LCD is displayed and the program terminates. Figure 9.5 shows the project constructed on a breadboard. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LCD-1*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ // // LCD connections // #define LCD_EN

2U

#define LCD_RS

1U

#define LCD_D4

19U

#define LCD_D5

18U

#define LCD_D6

17U

#define LCD_D7

20U

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static int PORTS[] = {20U, 17U, 18U, 19U}; /******************************************************************************* * Code ******************************************************************************/ //

● 160

Getting Started with NXP i.MX Development Board - UK.indd 160

26-10-2023 09:34


Chapter 9 • Using LCDs

// Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } //============================= LCD CODES ============================== // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,PORTS[i], 1U); else GPIO_PinWrite(GPIO1,PORTS[i], 0U); m--; } } // // LCD_STROBE // void LCD_STROBE() { GPIO_PinWrite(GPIO1, LCD_EN, 1U);

● 161

Getting Started with NXP i.MX Development Board - UK.indd 161

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

SysTick_DelayTicks(1); GPIO_PinWrite(GPIO1, LCD_EN, 0U); SysTick_DelayTicks(1); }

// // Send a command to the LCD // void lcd_write_cmd(unsigned char c) { unsigned int d; d = c; d = (d >> 4);

// Extract upper nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U); LCD_STROBE();

// Clock enable bit

d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U); LCD_STROBE();

// Clock enable bit

SysTick_DelayTicks(1); } // // Send data to the LCD // void lcd_write_data(unsigned char c) { unsigned int d; d = c; d = (d >> 4);

// Extract upper nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE();

// Clock enable bit

d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Clear LCD //

● 162

Getting Started with NXP i.MX Development Board - UK.indd 162

26-10-2023 09:34


Chapter 9 • Using LCDs

void lcd_clear(void) { lcd_write_cmd(0x1); SysTick_DelayTicks(5); } // // Home cursor // void lcd_home_cursor(void) { lcd_write_cmd(0x2); SysTick_DelayTicks(5); } // // Cursor blinking // void lcd_cursor_blinking(void) { lcd_write_cmd(0x0F); SysTick_DelayTicks(3); } // // Cursor non blinking // void lcd_cursor_nonblinking(void) { lcd_write_cmd(0x0E); SysTick_DelayTicks(3); } // // Shift right // void lcd_shift_all_right(void) { lcd_write_cmd(0x1C); SysTick_DelayTicks(5); } // // Shift left // void lcd_shift_all_left(void)

● 163

Getting Started with NXP i.MX Development Board - UK.indd 163

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{ lcd_write_cmd(0x18); SysTick_DelayTicks(5); } // // Move cursor left // void lcd_cursor_left(void) { lcd_write_cmd(0x10); SysTick_DelayTicks(3); } // // Move cursor right // void lcd_cursor_right(void) { lcd_write_cmd(0x14); SysTick_DelayTicks(3); } // // Display text message on LCD // void lcd_print(const char * s) { while(*s) lcd_write_data(*s++); } // // Display single character on LCD // void lcd_putch(char c) { unsigned int d; d = c; d = (d >> 4); Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); d = c; d = (d & 0x0F); Display(d, 4);

● 164

Getting Started with NXP i.MX Development Board - UK.indd 164

26-10-2023 09:34


Chapter 9 • Using LCDs

GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Position the cursor at column,row. (0,0) is left corner // void lcd_goto(int col, int row) { char address; if(row == 0)address = 0; if(row == 1)address = 0x40; address += col - 1; lcd_write_cmd(0x80 | address); } // // Initialize the LCD // void lcd_init(void) { SysTick_DelayTicks(100); GPIO_PinWrite(GPIO1, LCD_RS, 0U); GPIO_PinWrite(GPIO1, LCD_EN, 0U); Display(0x03,4); SysTick_DelayTicks(5); LCD_STROBE(); SysTick_DelayTicks(30); LCD_STROBE(); SysTick_DelayTicks(20); LCD_STROBE(); SysTick_DelayTicks(20); Display(0x02,4); SysTick_DelayTicks(1); LCD_STROBE(); SysTick_DelayTicks(5); lcd_write_cmd(0x28); SysTick_DelayTicks(5); lcd_write_cmd(0x0F); SysTick_DelayTicks(5); lcd_write_cmd(0x01); SysTick_DelayTicks(5); lcd_write_cmd(0x06); SysTick_DelayTicks(5); GPIO_PinWrite(GPIO1, LCD_RS, 1U); }

● 165

Getting Started with NXP i.MX Development Board - UK.indd 165

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

//======================= END OF LCD CODES =================================

/* Main function */ int main(void) { BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } lcd_init();

// Initialize LCD

lcd_clear();

// Clear LCD

lcd_print("TESTING LCD");

// Display text

while(1);

// Stop here

}

Figure 9.4 Program listing

Figure 9.5 Construction of the project

● 166

Getting Started with NXP i.MX Development Board - UK.indd 166

26-10-2023 09:34


Chapter 9 • Using LCDs

The following functions are supported by the LCD: lcd_init() this must be the first function to be called lcd_clear() clear LCD lcd_home_cursor() home cursor lcd_cursor_blinking() set blinking cursor ON lcd_cursor_nonblinking() set blinking cursor OFF lcd_shift_all_right() shift all (next) characters right by one place lcd_shift_all_left() shift all (next) characters left by one position lcd_cursor_left() move cursor left by one position lcd_cursor_right() move cursor right by one position lcd_print() display string of data lcd_putch() display single character lcd_goto(col, row) move cursor to specified (col, row)

9.4 Project 2 – Using LCDs – simple up counter Description: In this project an up counter is developed which counts up every second and the result is displayed on the LCD in the following format: Count: nn Where the text Count is displayed at the beginning of row 0, and the number is displayed starting from row 1. The aim of this project is to show how both text and numbers can be displayed on the LCD. The block diagram and circuit diagram of the project are the same as in Figure 9.2 and Figure 9.3 respectively. Program listing: The used port pins must be configured as outputs, as in the previous projects. The program listing is shown in Figure 9.6 (lcd-counter). A variable called Count is initialized to 0 at the beginning of the program. An array called Txt is defined to store the count in string format. Count is incremented by one every second. It is then converted into a character array and stored in Txt using the standard function itoa. String Txt is then displayed on the LCD in the required format every second. Figure 9.7 shows the LCD. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LCD-counter*/ #include "pin_mux.h" #include "clock_config.h"

● 167

Getting Started with NXP i.MX Development Board - UK.indd 167

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

#include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ // // LCD connections // #define LCD_EN

2U

#define LCD_RS

1U

#define LCD_D4

19U

#define LCD_D5

18U

#define LCD_D6

17U

#define LCD_D7

20U

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; static int PORTS[] = {20U, 17U, 18U, 19U}; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) {

● 168

Getting Started with NXP i.MX Development Board - UK.indd 168

26-10-2023 09:34


Chapter 9 • Using LCDs

} } //============================= LCD CODES ============================== // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0) GPIO_PinWrite(GPIO1,PORTS[i], 1U); else GPIO_PinWrite(GPIO1,PORTS[i], 0U); m--; } } // // LCD_STROBE // void LCD_STROBE() { GPIO_PinWrite(GPIO1, LCD_EN, 1U); SysTick_DelayTicks(1); GPIO_PinWrite(GPIO1, LCD_EN, 0U); SysTick_DelayTicks(1); }

// // Send a command to the LCD // void lcd_write_cmd(unsigned char c) { unsigned char d; d = c; d = (d >> 4);

// Extract upper nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U);

● 169

Getting Started with NXP i.MX Development Board - UK.indd 169

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

LCD_STROBE();

// Clock enable bit

d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U); LCD_STROBE();

// Clock enable bit

SysTick_DelayTicks(1); } // // Send data to the LCD // void lcd_write_data(unsigned char c) { unsigned char d; d = c; d = (d >> 4);

// Extract upper nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE();

// Clock enable bit

d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Clear LCD // void lcd_clear(void) { lcd_write_cmd(0x1); SysTick_DelayTicks(5); } // // Home cursor // void lcd_home_cursor(void) { lcd_write_cmd(0x2); SysTick_DelayTicks(5); } //

● 170

Getting Started with NXP i.MX Development Board - UK.indd 170

26-10-2023 09:34


Chapter 9 • Using LCDs

// Cursor blinking // void lcd_cursor_blinking(void) { lcd_write_cmd(0x0F); SysTick_DelayTicks(3); } // // Cursor non blinking // void lcd_cursor_nonblinking(void) { lcd_write_cmd(0x0E); SysTick_DelayTicks(3); } // // Shift right // void lcd_shift_all_right(void) { lcd_write_cmd(0x1C); SysTick_DelayTicks(5); } // // Shift left // void lcd_shift_all_left(void) { lcd_write_cmd(0x18); SysTick_DelayTicks(5); } // // Move cursor left // void lcd_cursor_left(void) { lcd_write_cmd(0x10); SysTick_DelayTicks(3); } // // Move cursor right

● 171

Getting Started with NXP i.MX Development Board - UK.indd 171

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

// void lcd_cursor_right(void) { lcd_write_cmd(0x14); SysTick_DelayTicks(3); } // // Display text message on LCD // void lcd_print(const char * s) { while(*s) lcd_write_data(*s++); } // // Display single character on LCD // void lcd_putch(char c) { unsigned int d; d = c; d = (d >> 4); Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); d = c; d = (d & 0x0F); Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Position the cursor at column,row. (0,0) is left corner // void lcd_goto(int col, int row) { char address; if(row == 0)address = 0; if(row == 1)address = 0x40; address += col - 1; lcd_write_cmd(0x80 | address); }

● 172

Getting Started with NXP i.MX Development Board - UK.indd 172

26-10-2023 09:34


Chapter 9 • Using LCDs

// // Initialize the LCD // void lcd_init(void) { SysTick_DelayTicks(100); GPIO_PinWrite(GPIO1, LCD_RS, 0U); GPIO_PinWrite(GPIO1, LCD_EN, 0U); Display(0x03,4); SysTick_DelayTicks(5); LCD_STROBE(); SysTick_DelayTicks(30); LCD_STROBE(); SysTick_DelayTicks(20); LCD_STROBE(); SysTick_DelayTicks(20); Display(0x02,4); SysTick_DelayTicks(1); LCD_STROBE(); SysTick_DelayTicks(5); lcd_write_cmd(0x28); SysTick_DelayTicks(5); lcd_write_cmd(0x0F); SysTick_DelayTicks(5); lcd_write_cmd(0x01); SysTick_DelayTicks(5); lcd_write_cmd(0x06); SysTick_DelayTicks(5); GPIO_PinWrite(GPIO1, LCD_RS, 1U); } //======================= END OF LCD CODES =================================

/* Main function */ int main(void) { char Txt[10]; int Count = 0; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U))

● 173

Getting Started with NXP i.MX Development Board - UK.indd 173

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{ while (1) { } } lcd_init();

// Initialize LCD

lcd_print("Count:");

// Display Count:

while(1) { lcd_goto(1,1); itoa(Count, Txt, 10);

// Convert to string

lcd_print(Txt);

// Display Count

Count++;

// Increment Count

SysTick_DelayTicks(1000);

// Wait 1 second

} }

Figure 9.6 Program listing

Figure 9.7 LCD

9.5 Including the LCD codes in a program In Figure 9.6 all the LCD functions were included at the beginning of the program. This is not desirable in many applications. In this section, you will see how to include the LCD files LCD.c and LCD.h in the project sources directory and then include them at the beginning of your programs. The steps are as follows: • Create a new file with the name LCD.h, whose contents are shown in Figure 9.8 #include "pin_mux.h" #include "clock_config.h" #include "board.h" void SysTick_DelayTicks(uint32_t); void LCD_STROBE(void); void Display(int,int);

● 174

Getting Started with NXP i.MX Development Board - UK.indd 174

26-10-2023 09:34


Chapter 9 • Using LCDs

void lcd_write_cmd(unsigned char); void lcd_write_data(unsigned char); void lcd_clear(void); void lcd_home_cursor(void); void lcd_cursor_blinking(void); void lcd_cursor_nonblinking(void); void lcd_shift_all_right(); void lcd_shift_all_left(); void lcd_cursor_left(); void lcd_cursor_right(); void lcd_print(const char * s); void lcd_putch(char c); void lcd_goto(int,int); void lcd_init(void);

Figure 9.8 File: LCD.h • Create a new file with the name LCD.c, whose contents are shown in Figure 9.9 include "board.h" // // LCD connections // #define LCD_EN

2U

#define LCD_RS

1U

#define LCD_D4

19U

#define LCD_D5

18U

#define LCD_D6

17U

#define LCD_D7

20U

static int PORTS[] = {20U, 17U, 18U, 19U}; extern void SysTick_DelayTicks(uint32_t); //============================= LCD CODES ============================== // Group the port pins together. L is the number of bits (8 here),and No // is the data to be displayed // void Display(int No, int L) { int i, m, j; m = L - 1; for(i = 0; i < L; i++) { j = 1; for(int k = 0; k < m; k++)j = j * 2; if((No & j) != 0)

● 175

Getting Started with NXP i.MX Development Board - UK.indd 175

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

GPIO_PinWrite(GPIO1,PORTS[i], 1U); else GPIO_PinWrite(GPIO1,PORTS[i], 0U); m--; } } // // LCD_STROBE // void LCD_STROBE() { GPIO_PinWrite(GPIO1, LCD_EN, 1U); SysTick_DelayTicks(1); GPIO_PinWrite(GPIO1, LCD_EN, 0U); SysTick_DelayTicks(1); }

// // Send a command to the LCD // void lcd_write_cmd(unsigned char c) { unsigned char d; d = c; d = (d >> 4);

// Extract upper nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U); LCD_STROBE();

// Clock enable bit

d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 0U); LCD_STROBE();

// Clock enable bit

SysTick_DelayTicks(1); } // // Send data to the LCD // void lcd_write_data(unsigned char c) { unsigned char d; d = c; d = (d >> 4);

// Extract upper nibble

● 176

Getting Started with NXP i.MX Development Board - UK.indd 176

26-10-2023 09:34


Chapter 9 • Using LCDs

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); // Clock enable bit d = c; d = d & 0x0F;

// Extract lower nibble

Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Clear LCD // void lcd_clear(void) { lcd_write_cmd(0x1); SysTick_DelayTicks(5); } // // Home cursor // void lcd_home_cursor(void) { lcd_write_cmd(0x2); SysTick_DelayTicks(5); } // // Cursor blinking // void lcd_cursor_blinking(void) { lcd_write_cmd(0x0F); SysTick_DelayTicks(3); } // // Cursor non blinking // void lcd_cursor_nonblinking(void) { lcd_write_cmd(0x0E); SysTick_DelayTicks(3); }

● 177

Getting Started with NXP i.MX Development Board - UK.indd 177

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

// // Shift right // void lcd_shift_all_right(void) { lcd_write_cmd(0x1C); SysTick_DelayTicks(5); } // // Shift left // void lcd_shift_all_left(void) { lcd_write_cmd(0x18); SysTick_DelayTicks(5); } // // Move cursor left // void lcd_cursor_left(void) { lcd_write_cmd(0x10); SysTick_DelayTicks(3); } // // Move cursor right // void lcd_cursor_right(void) { lcd_write_cmd(0x14); SysTick_DelayTicks(3); } // // Display text message on LCD // void lcd_print(const char * s) { while(*s) lcd_write_data(*s++); }

● 178

Getting Started with NXP i.MX Development Board - UK.indd 178

26-10-2023 09:34


Chapter 9 • Using LCDs

// // Display single character on LCD // void lcd_putch(char c) { unsigned int d; d = c; d = (d >> 4); Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); d = c; d = (d & 0x0F); Display(d, 4); GPIO_PinWrite(GPIO1, LCD_RS, 1U); LCD_STROBE(); } // // Position the cursor at column,row. (0,0) is left corner // void lcd_goto(int col, int row) { char address; if(row == 0)address = 0; if(row == 1)address = 0x40; address += col - 1; lcd_write_cmd(0x80 | address); } // // Initialize the LCD // void lcd_init(void) { SysTick_DelayTicks(100); GPIO_PinWrite(GPIO1, LCD_RS, 0U); GPIO_PinWrite(GPIO1, LCD_EN, 0U); Display(0x03,4); SysTick_DelayTicks(5); LCD_STROBE(); SysTick_DelayTicks(30); LCD_STROBE(); SysTick_DelayTicks(20); LCD_STROBE(); SysTick_DelayTicks(20);

● 179

Getting Started with NXP i.MX Development Board - UK.indd 179

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Display(0x02,4); SysTick_DelayTicks(1); LCD_STROBE(); SysTick_DelayTicks(5); lcd_write_cmd(0x28); SysTick_DelayTicks(5); lcd_write_cmd(0x0F); SysTick_DelayTicks(5); lcd_write_cmd(0x01); SysTick_DelayTicks(5); lcd_write_cmd(0x06); SysTick_DelayTicks(5); GPIO_PinWrite(GPIO1, LCD_RS, 1U); } //======================= END OF LCD CODES =================================

Figure 9.9 File: LCD.c • Save both LCD.h and LCD.c in the source directory of your workspace. Assuming your workspace is evkmimxrt1010_iled_blinky: C:\users\username\Documents\MCUXpressoIDE_11.7.1_9221\ workspace\evkmimxrt1010_iled_blinky\source • The username and workspace name will be different on your computer. Notice that you could also save the include files in the compiler Build directory. • The following statement should be added to the beginning of the program: #include "LCD.h" An example project of using the new files is given below.

9.6 Project 3 – Using LCDs – simple up counter – including LCD header file Description: In this project an up counter is developed as in the previous project. Here, the LCD header file is included at the beginning of the program. The block diagram and circuit diagram of the project are the same as in Figure 9.2 and Figure 9.3 respectively. Program listing: The used port pins must be configured as outputs, as in the previous projects. The program is much simpler, and its listing is shown in Figure 9.10 (lcd-counter-header-included).

● 180

Getting Started with NXP i.MX Development Board - UK.indd 180

26-10-2023 09:34


Chapter 9 • Using LCDs

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LCD-counter - header included*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U)

● 181

Getting Started with NXP i.MX Development Board - UK.indd 181

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

{ } }

/* Main function */ int main(void) { char Txt[10]; int Count = 0; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } lcd_init();

// Initialize LCD

lcd_print("Count:");

// Display Count:

while(1) { lcd_goto(1,1); itoa(Count, Txt, 10);

// Convert to string

lcd_print(Txt);

// Display Count

Count++;

// Increment Count

SysTick_DelayTicks(1000);

// Wait 1 second

} }

Figure 9.10 Program listing

9.7 Project 4 – LCD-based conveyor belt goods counter Description: In this project we count the number of items (e.g. bottles) passing on a conveyor belt and display the result continuously on the LCD. Block diagram: Figure 9.11 shows the project block diagram. A light beam is directed at a point to the passing bottles. At the other side of the beam, a light dependent resistor (LDR) is used to detect when the light beam is interrupted. When this happens, a signal is

● 182

Getting Started with NXP i.MX Development Board - UK.indd 182

26-10-2023 09:34


Chapter 9 • Using LCDs

sent to the development kit, which then increments a counter and displays the total count on the LCD.

Figure 9.11 Block diagram of the project Light dependent resistor A light dependent resistor is simply a resistor whose resistance changes with the application of light to its surface (Figure 9.12). The resistance of an LDR increases as the light intensity falling on the device is reduced (see Figure 9.12).

Figure 9.12 LDR and its typical characteristics LDRs are usually used in series with resistors in a circuit to form a resistive potential divider circuit. The voltage at the output of the potential divider circuit is used to send a trigger signal when the light intensity is below (or above) a set level. The trigger point can be detected by an MCU using both analog or digital inputs. Circuit diagram: Figure 9.13 shows the circuit diagram of the project. A 10 kΩ potentiometer is used in series with the LDR. The potentiometer is adjusted such that the output voltage goes over 2 V when the light falling on the LDR is reduced by a passing bottle. The output of the potential divider circuit is fed to digital port IO15 (J56, pin 14) of the development kit.

● 183

Getting Started with NXP i.MX Development Board - UK.indd 183

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

Figure 9.13 Circuit diagram of the project It was measured by the author that the resistance of the used LDR was about 0.5 kΩ in light and increased to about 100 kΩ when in dark. Assuming the potentiometer is set to its middle position, i.e. 5 kΩ: The voltage at the output when light falls on the LDR is Vo = 3.3 × 0.5/(5 + 0.5) = 0.3 V which is a logic 0. Similarly, the voltage at the output when it is dark is Vo = 3.3 × 100/ (5 + 100) = 3.14 V which is seen as a logic 1. We will set the potentiometer arm to just below its mid-point so that the output voltage is even lower than 0.3 V when it is light. The exact point can easily be determined by experimentation. Program listing: Figure 9.14 shows the program listing (lcd-conveyor-belt). The LCD connections must be configured as output ports. Similarly, the LDR must be configured as an input port (Figure 9.15). The LCD is initialized and the heading Count: is sent to the top row of the LCD. Inside the main program loop, the cursor is set to (1, 1), and the program waits while there is light on the LDR (i.e. no bottle detected). When a bottle is detected, the program comes out of the while statement and increment the total count (variable Count). This variable is converted into a character array in Txt and displayed on the LCD. The program then waits again until a bottle passes in front of the LDR. This cycle is repeated after a small delay. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LCD- conveyor belt*/ #include "pin_mux.h"

● 184

Getting Started with NXP i.MX Development Board - UK.indd 184

26-10-2023 09:34


Chapter 9 • Using LCDs

#include "clock_config.h" #include "board.h" #include "LCD.h" void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Definitions ******************************************************************************/ #define LDR 15U /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[10];

● 185

Getting Started with NXP i.MX Development Board - UK.indd 185

26-10-2023 09:34


Get Started with the NXP i.MX RT1010 Development Kit

int Count = 0; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } lcd_init();

// Initialize LCD

lcd_print("Count:");

// Display Count:

while(1) { lcd_goto(1,1); while(GPIO_PinRead(GPIO1, LDR) == 0);

// Wait if light (no bottle)

Count++; itoa(Count, Txt, 10);

// Convert to string

lcd_print(Txt);

// Display Count

while(GPIO_PinRead(GPIO1, LDR) == 1);

// Wait if dark

SysTick_DelayTicks(100); } }

Figure 9.14 Program listing

Figure 9.15 Configure GPIO ports

● 186

Getting Started with NXP i.MX Development Board - UK.indd 186

26-10-2023 09:35


Chapter 9 • Using LCDs

9.8 Project 5 – Event counter – using external interrupts Description: In this project a button is connected to the development board where pressing the button simulates the occurrence of external events. When the button is pressed, an external interrupt is generated and this causes a count to be incremented by one. The total count is displayed on LCD. Block diagram: Figure 9.16 shows the block diagram of the project.

Figure 9.16 Block diagram of the project Circuit diagram: The circuit diagram is shown in Figure 9.17. One pin of the button (called the EventButton) is connected to +3.3 V where the other pin is connected to port pin J56, pin 14 (IO15). The button state is pulled down in software. Therefore, normally, the state of the button is at logic LOW and goes to logic HIGH when the button is pressed (i.e. on the low-to-high transition of the button output).

Figure 9.17 Circuit diagram of the project Program listing: before developing the program, the GPIO pins must be configured as follows using the Pins option of menu item ConfigTools:

● 187

Getting Started with NXP i.MX Development Board - UK.indd 187

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

J57, pin 6 (IO19) Direction: output J57, pin 8 (IO18) Direction: output J57, pin 10 (IO17) Direction: output J57, pin 12 (IO20) Direction: output J57, pin 18 (IO1) Direction: output J57, pin 20 (IO2) Direction: output J56, pin 14 (IO15) Direction: input, GPIO interrupt: Rising Edge, Pull Up/Down: 100 kΩ Pull Down Figure 9.18 shows the program listing (lcd-interrupt). At the beginning of the program, EventButton is assigned to 15. GPIO_IRQHandler and GPIO_IRQ are defined, and the variable flag is cleared to 0. The interrupt service routine is the function named GPIO_ IRQHandler(). This function is called whenever an external interrupt occurs by pressing the button. Here, the interrupt flag is cleared so that new interrupts can be detected. Also, the variable flag is set to 1 to indicate that an external interrupt has occurred. Inside the main program loop, interrupts are enabled on button EventButton. The program displays text COUNT: on the top row of the LCD and waits until an external interrupt occurs. When variable flag is set (i.e. EventButton is pressed) then the variable Count is incremented, converted into a character array and displayed on the bottom row of the LCD. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LCD- event counter - external interrupt*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Definitions ******************************************************************************/ #define EventButton 15U #define GPIO_IRQHandler GPIO1_Combined_0_15_IRQHandler #define GPIO_IRQ GPIO1_Combined_0_15_IRQn /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables

● 188

Getting Started with NXP i.MX Development Board - UK.indd 188

26-10-2023 09:35


Chapter 9 • Using LCDs

******************************************************************************/ volatile uint32_t g_systickCounter; volatile int flag = 0; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } // // External interrupt service routine. Clear the interrupts and set flag // void GPIO_IRQHandler(void) { GPIO_PortClearInterruptFlags(GPIO1, 1U << EventButton); flag = 1; SDK_ISR_EXIT_BARRIER; }

/* Main function */ int main(void) { char Txt[10]; int Count = 0; BOARD_ConfigMPU(); BOARD_InitBootPins();

● 189

Getting Started with NXP i.MX Development Board - UK.indd 189

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } /* Enable GPIO pin interrupt */ GPIO_PortEnableInterrupts(GPIO1, 1U << EventButton);

// Enable pin 15 int

EnableIRQ(GPIO_IRQ);

// Enable interrupts

lcd_init();

// Initialize LCD

lcd_print("Count:");

// Display Count:

while(1) { lcd_goto(1,1); if(flag == 1) {

flag = 0;

Count++; itoa(Count, Txt, 10);

// Convert to chars

lcd_print(Txt);

// Display Count

} } }

Figure 9.18 Program listing

● 190

Getting Started with NXP i.MX Development Board - UK.indd 190

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

Chapter 10 • Analog-To-Digital Converter (ADC) 10.1 Overview Most sensors in real life are analog and give analog output voltages or currents which are proportional to the measured variable. Such sensors cannot be directly connected to digital computers without using ADCs. In this chapter you will learn how to use the ADC channels of the development kit. Most ADCs for general-purpose applications are 8-bits or 10-bits wide, although some higher-grade professional ones are 16 or even 32-bit wide. The conversion time of an ADC is one of its important specifications. This is the time taken for the ADC to convert an analog input into digital. The shorter the conversion time, the better. Some cheaper ADCs give the converted digital data in serial format, while some more expensive professional ones provide parallel digital outputs. The ADC of the i.MXRT 1010 processor has a resolution of 12 bits, thus converting an analog input voltage into 4096 (0 to 4095) levels. There are 15 channels from input 0 (GPIO_AD_00) to input 14 (GPIO_AD_14). The ADC can be configured for 8, 10, or 12 bits of resolution. ADC conversion can be done either by polling or it can be interrupt-driven. When using polling, the program waits until the conversion is ready. In interrupt-driven applications, an interrupt is generated when the conversion is complete.

10.2 Project 1 – Voltmeter Description: This is a voltmeter project. The voltage to be measured is applied to an analog input and its value in millivolts is displayed on the LCD. The maximum allowable input voltage is +3.3 V. It is shown later in the project how to use a resistive voltage divider circuit to extend the range of the voltmeter. Circuit diagram: As shown in Figure 10.1, in this project the voltage to be measured is applied to Arduino header J56, pin14 (GPIO_AD_01, i.e. ADC channel 1). The LCD is connected to the development kit as in the previous LCD-based projects.

Figure 10.1 Circuit diagram of the project

● 191

Getting Started with NXP i.MX Development Board - UK.indd 191

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Program listing: You should configure the port pins connected to the LCD as outputs, and the analog pin at header J56, pin 14 (GPIO_AD_01) as an analog input (Figure 10.2).

Figure 10.2 Configure the used GPIO ports At the beginning of the program the ADC_BASE, ADC_USER_CHANNEL, and ADC_ CHANNEL_GROUP are set to ADC1, 1U, and 0U respectively. The ADC channel is configured as follows: // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource =

kADC_ReferenceVoltageSourceAlt0;

adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

Files fsl_adc.h and fsl_adc.c must be in the drivers folder before the project is compiled. They can be included in the project as follows: • Click the orange icon to open Manage SDK Components • Click tab Drivers • Click to expand Device • Click to expand SDK Drivers • Click to include ADC driver adc_12b1msps.sar • Click OK to exit • Click drivers under Project Explorer and make sure that files fsl_adc.h and

● 192

Getting Started with NXP i.MX Development Board - UK.indd 192

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

fsl_adc.c are included in the project Note that these files could also be included in the project during the project creation under Configure the project tab and by selecting tab Drivers and following the above steps Figure 10.2 shows the program listing (voltmeter). Note that calling function: ADC_GetDefaultConfig(&adcConfigStruct) sets the default channel configurations as above. Therefore, instead of the above configuration settings, you can just call this function. Interrupts on conversion are then disabled. Inside the main program loop, the conversion is triggered by calling the function ADC_SetChannelConfig(). The ADC is then calibrated by calling the function ADC_DoAutoCalibration(). The program then waits in a while loop until the conversion is complete. After this, the function ADC_GetChannelConversionValue() is called to read the converted digital data. This data is the raw reading from the channel in the range 0 to 4095. It is converted into millivolts by multiplying by 3300 and diving by 4096. The resulting voltage is then displayed on the second row of the LCD as shown in Figure 10.3. In this figure, the ADC input was connected to +3.3 V of the development kit. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - Voltmeter*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" #include "fsl_adc.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

#define ADC_CHANNEL_GROUP 0U

// Channel group

/******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables

● 193

Getting Started with NXP i.MX Development Board - UK.indd 193

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

int adcreading = 0; /******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[10]; int Count = 0; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) {

● 194

Getting Started with NXP i.MX Development Board - UK.indd 194

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

} } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; lcd_init();

// Initialize LCD

lcd_print("Voltmeter (mV):");

// Display heading

while(1) { lcd_goto(1,1); ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); adcreading = adcreading * 3300 / g_Adc_12bitFullRange; itoa(adcreading, Txt, 10);

// Convert to chars

lcd_print(Txt);

// Display in mV

● 195

Getting Started with NXP i.MX Development Board - UK.indd 195

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

SysTick_DelayTicks(1000);

// Wait 1 second

} }

Figure 10.3 Program listing

Figure 10.4 Example display Extending the voltmeter range The useful range of our voltmeter can easily be extended by using resistive potential divider circuits. For example, the circuit shown in Figure 10.5 attenuates the input voltage by a factor of 4 so that input voltages up to 13 V can be measured. You should, of course, have to multiply the readings by 4.

Figure 10.5 Resistive potential divider circuit

10.3 Project 2 – Analog temperature sensor Description: In this project, you will be using the LM35 analog temperature sensor chip to measure and display the ambient temperature on the LCD every second. Block diagram: Figure 10.6 shows the block diagram of the project which consists of the LM35 sensor chip, the development kit, and the LCD.

Figure 10.6 Block diagram of the project

● 196

Getting Started with NXP i.MX Development Board - UK.indd 196

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

Circuit diagram: LM35 is a 3-pin temperature sensor chip (Figure 10.7) with the pins: +V, GND, and OUT. The OUT pin is connected to analog input GPIO_AD_01 (J56, pin 14) of the development kit.

Figure 10.7 LM35 temperature sensor chip The LM35 temperature sensor has the following basic specifications: • Calibrated in Celsius • Linear 10 mV/°C output • 0.5ºC accuracy • -55ºC to +125ºC operation • Operation from +4 V to +30 V • Less than 60 μA current drain • Low self-heating (0.08ºC in still air) The output voltage of LM35 is linearly proportional to the measured temperature and is given by: T = Vo / 10 Where T is the measured temperature in degrees C, and Vo is the sensor output voltage in millivolts. For example, 250 mV output corresponds to 25ºC, 300 mV corresponds to 30ºC and so on. For simplicity, to find the measured temperature, divide the analog voltage read in millivolts by 10. Figure 10.8 shows the circuit diagram of the project.

● 197

Getting Started with NXP i.MX Development Board - UK.indd 197

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Figure 10.8 Circuit diagram of the project Program listing: The program listing is shown in Figure 10.9 (LM35). Make sure that files fsl_adc.h and fsl_adc.h are included in the project, as described in the previous project. The main program reads the raw data output of the LM35. The temperature in Degrees C is then obtained by multiplying this value by 330 (i.e. 3300 mV / 10) and diving by 4096. Variable mV stores the temperature as a floating-point number. The decimal part (TDec) and fractional parts (TFrac) of the temperature are extracted and displayed on the LCD as shown in Figure 10.9. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - LM35*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" #include "fsl_adc.h" #include "stdio.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

#define ADC_CHANNEL_GROUP 0U

// Channel group

/*******************************************************************************

● 198

Getting Started with NXP i.MX Development Board - UK.indd 198

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

* Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

/******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[20]; float mV; int TDec, TFrac, adcreading;

BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole();

● 199

Getting Started with NXP i.MX Development Board - UK.indd 199

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

/* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; lcd_init();

// Initialize LCD

lcd_print("Temperature (C)");

// Display heading

while(1) { lcd_goto(1,1); ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { }

● 200

Getting Started with NXP i.MX Development Board - UK.indd 200

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); mV = adcreading * 330.0 / g_Adc_12bitFullRange; TDec = mV;

// Decimal part

mV = 10.0*(mV - TDec); TFrac = mV;

// Fractional part

itoa(TDec, Txt, 10); lcd_print(Txt);

// Display decimal

lcd_print(".");

// Display "."

itoa(TFrac, Txt, 10);

// Display fraction

lcd_print(Txt); SysTick_DelayTicks(1000);

// Wait 1 second

} }

Figure 10.9 Program listing

Figure 10.10 The display

10.4 Project 3 – ON/OFF temperature controller Description: Temperature control is important in many chemical industrial, commercial, and in domestic applications as well as in many other applications. A temperature control system basically consists of a temperature sensor, a heater, a fan (optional), and a controller. Negative feedback is used to control the heater so that the temperature is kept at the desired set-point value. Accurate temperature control systems are based on the PID (Proportional+Integral+Derivative) algorithms. In this project, an ON/OFF type simple control system is designed. ON/OFF temperature control systems commonly use relays to turn the heater ON or OFF, depending on the set-point temperature and the measured temperature. If the measured temperature is below the set-point value, then the relay is activated, which turns the heater ON so that the temperature reaches the set-point value. If, on the other hand, the measured temperature is above the set-point value, then the relay is deactivated to turn OFF the heater so that the temperature is lowered and reaches the set-point value. In this project, a LM35 type temperature sensor chip is used together with a heater, a relay, and an LED to control the temperature of a small room. The heater is turned ON by the relay if the measured room temperature (RoomTemp) is below the set-point temperature (SetTemp), and it is turned OFF if it is above the set-point value. The LED turns ON if the room temperature is below the set point value to indicate that the heater is ON. This process is repeated every 3 seconds. The aim of this project is to show how an ON/OFF type

● 201

Getting Started with NXP i.MX Development Board - UK.indd 201

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

temperature controller system can be designed using a low-cost temperature sensor chip with the development kit. Block diagram: Figure 10.11 shows the block diagram of the project.

Figure 10.11 Block diagram of the project Circuit diagram: The circuit diagram of the project is shown in Figure 10.12. The LM35 sensor chip is connected to analog channel GPIO_AD_0 (Arduino header J56, pin14, IN1) as in the previous project. An external LED is connected to pin ADC12_2 (Arduino header J56, pin 16, IO16) through a current limiting 1 kΩ resistor. A 3.3 V relay is connected to pin UART1_RXD (Arduino header J56, pin 2, IO9). The connections between the development kit and various components are as follows: Development kit J56, pin 14 J56, pin 16 J56, pin 2

Component TMP36 out LED Relay

Configuration configure as analog input configure as output configure as output

Figure 10.12 Circuit diagram of the project Operation of the project The operation of the project is described in Figure 10.13 as a PDL (Program Description Language).

● 202

Getting Started with NXP i.MX Development Board - UK.indd 202

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

BEGIN Read the set temperature (SetTemp) Read the maximum temperature (MaxTemp) DO FOREVER

Read the room temperature (RoomTemp)

IF SetTemp > RoomTemp THEN Activate relay LED ON ELSE Deactivate relay LED OFF ENDIF

Wait 3 seconds

ENDDO END

Figure 10.13 PDL of the project Program listing: Configure the LED and Relay as outputs and the LM35 as analog input as in the previous project. Figure 10.14 shows the program listing (LM35-on-off-control). Make sure that files fsl_adc.h and fsl_adc.h are included in the project, as described in the previous projects. The desired temperature is set to 24ºC and is stored in variable SetTemp. Inside the program loop, the room temperature (RoomTemp) is read and compared with the desired temperature (SetTemp). If the room temperature is below the desired value, then both the relay (heater) and the LED are turned ON; otherwise they are both turned OFF. This process is repeated after a delay of three seconds. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - LM35 - ON-OFF Control*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_adc.h" #include "stdio.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

● 203

Getting Started with NXP i.MX Development Board - UK.indd 203

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

#define ADC_CHANNEL_GROUP 0U

// Channel group

#define LED 16U // LED #define RELAY 9U // Relay /******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

/******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[20]; int adcreading; int RoomTemp, SetTemp = 24;

● 204

Getting Started with NXP i.MX Development Board - UK.indd 204

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; GPIO_PinWrite(GPIO1, RELAY, 0U);

// Relay OFF

GPIO_PinWrite(GPIO1, LED,0U);

// LED OFF

while(1) { ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP))

● 205

Getting Started with NXP i.MX Development Board - UK.indd 205

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

{ } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); RoomTemp = adcreading * 330 / g_Adc_12bitFullRange; if(RoomTemp < SetTemp) { GPIO_PinWrite(GPIO1, RELAY, 1U);

// Relay ON

GPIO_PinWrite(GPIO1, LED, 1U);

// LED ON

} else { GPIO_PinWrite(GPIO1, RELAY, 0U);

// Relay OFF

GPIO_PinWrite(GPIO1, LED, 0U);

// LED OFF

} SysTick_DelayTicks(3000);

// Wait 3 secs

} }

Figure 10.14 Program listing

10.5 Project 4 – ON/OFF temperature controller – using LCD Description: This project is similar to the previous one, but here an LCD is used as a display. The display shows the SetTemp and the RoomTemp every time the display is refreshed (every 3 seconds). Block diagram: Figure 10.15 shows the block diagram of the project.

Figure 10.15 Block diagram of the project Circuit diagram; The circuit diagram is shown in Figure 10.16. The LCD is connected as in the previous LCD-based projects. Also, the relay and the LED are connected as in the previous project.

● 206

Getting Started with NXP i.MX Development Board - UK.indd 206

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

Figure 10.16 Circuit diagram Program listing: Figure 10.17 shows the program listing (LM35-on-off-cotrol-lcd). Make sure that files fsl_adc.h and fsl_adc.h are included in the project, as described in the previous projects. Text SetTemp: is displayed on the top row of the LCD. Similarly, the text RoomTemp: is displayed at the bottom row. If the variable RoomTemp is lower than the SetTemp than both the LED and the relay are turned ON; otherwise they are both turned OFF. This process repeats every 3 seconds. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - LM35 - ON-OFF Control with LCD*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" #include "fsl_adc.h" #include "stdio.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

● 207

Getting Started with NXP i.MX Development Board - UK.indd 207

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

#define ADC_CHANNEL_GROUP 0U

// Channel group

#define LED 16U // LED #define RELAY 9U // Relay /******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

/******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[20]; int adcreading; int RoomTemp, SetTemp = 24;

● 208

Getting Started with NXP i.MX Development Board - UK.indd 208

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;

//

adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; GPIO_PinWrite(GPIO1, RELAY, 0U);

// Relay OFF

GPIO_PinWrite(GPIO1, LED,0U);

// LED OFF

lcd_init();

// Initialize LCD

lcd_print(" SetTemp:");

// Display heading

itoa(SetTemp, Txt, 10); lcd_print(Txt);

● 209

Getting Started with NXP i.MX Development Board - UK.indd 209

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

while(1) { lcd_goto(1,1); lcd_print("RoomTemp:"); ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); RoomTemp = adcreading * 330 / g_Adc_12bitFullRange; itoa(RoomTemp, Txt, 10); lcd_print(Txt);

// Display head

if(RoomTemp < SetTemp) { GPIO_PinWrite(GPIO1, RELAY, 1U);

// Relay ON

GPIO_PinWrite(GPIO1, LED, 1U);

// LED ON

} else { GPIO_PinWrite(GPIO1, RELAY, 0U);

// Relay OFF

GPIO_PinWrite(GPIO1, LED, 0U);

// LED OFF

} SysTick_DelayTicks(3000);

// Wait 3 secs

} }

Figure 10.17 Program listing Figure 10.18 shows the display.

Figure 10.18 The display

● 210

Getting Started with NXP i.MX Development Board - UK.indd 210

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

10.6 Project 5 – Measuring the ambient light intensity Description: In this project, a light-dependent-resistor (LDR) is used to measure and display the ambient light intensity on an LCD. Block diagram: Figure 10.19 shows the block diagram of the project.

Figure 10.19 Block diagram of the project Circuit diagram: The circuit diagram of the project is shown in Figure 10.20. A 10 kΩ fixed resistor is used in the resistive voltage divider circuit. The voltage across this resistor is measured using channel 1 of the ADC (J56, pin 14).

Figure 10.20 Circuit diagram of the project Program listing: Figure 10.21 shows the program listing (ambient-ldr). Make sure that files fsl_adc.h and fsl_adc.h are included in the project, as described in the previous projects. The program reads the analog voltage across the fixed resistor. Notice that there is no need to know the absolute voltage. You can just use the digital value of the voltage (0 to 4095) read (raw in this program). The reading is displayed starting on the top row of the LCD in the format: Light: nnnnn. This value should be calibrated to give the actual physical light intensity in Lux.

● 211

Getting Started with NXP i.MX Development Board - UK.indd 211

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - Ambient light intensity*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" #include "fsl_adc.h" #include "stdio.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

#define ADC_CHANNEL_GROUP 0U

// Channel group

/******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

/******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter // void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; }

● 212

Getting Started with NXP i.MX Development Board - UK.indd 212

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

} void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[20]; int adcreading; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

● 213

Getting Started with NXP i.MX Development Board - UK.indd 213

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; lcd_init();

// Initialize LCD

while(1) { lcd_clear(); lcd_home_cursor(); lcd_print("Light: "); ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); itoa(adcreading, Txt, 10); lcd_print(Txt);

// Display result

SysTick_DelayTicks(1000);

// WAit 1 sec

} }

Figure 10.21 Program listing Calibration A light meter is required to calibrate the readings. Measurements should be made at different light levels and a table should be created to list the Lux readings of the meter and the corresponding output from the ADC. Then, a formula can be derived that describes the relationship between the light level and the ADC readings. Alternatively, this table can be indexed for a given ADC reading to find the corresponding light level. Interpolation can be made for values between two readings.

10.7 Project 6 – Ohmmeter Description: This is an ohmmeter project. The project measures the value of an unknown resistor and displays on the LCD.

● 214

Getting Started with NXP i.MX Development Board - UK.indd 214

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

Circuit diagram: The circuit diagram of the project is shown in Figure 10.22. A fixed resistor (10 kΩ) is used in series with the unknown resistor. The program measures the voltage across the fixed resistor and then calculates the value of the unknown resistor (Rx).

Figure 10.22 Circuit diagram of the project Program listing: Figure 10.23 shows the program listing (ohmmeter). If RF is the fixed resistance and Rx is the unknown resistance, assuming the circuit is supplied from +3.3 V (3300 mV), the voltage at the output of the fixed resistor will be: V = 3300 × RF / (RF + Rx) If we choose RF to be 10 kΩ then, V = 33000 / (10 + Rx) Where V is in millivolts and RF and Rx are in kilohms. As Rx changes from, say, 1 kΩ to 1 MΩ, the voltage across the fixed resistor will change from: V = 33000/11 = 3000 mV to V = 33000/1001 = 33 mV We can easily measure these voltages with the ADC. Therefore, the resistance measurement range of our ohmmeter is well below 1 kΩ and above 1 MΩ. What we really want is to measure resistance Rx. We can write: Rx = 3300 × RF/V – RF

● 215

Getting Started with NXP i.MX Development Board - UK.indd 215

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Remembering that the ADC resolution is 4096 steps and RF = 10 kΩ, we can write: Rx = 4096 × RF / Vm – RF Where Vm is the digital value directly read from the ADC. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *ADC - Ohmmeter*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "LCD.h" #include "fsl_adc.h" #include "stdio.h" /******************************************************************************* * Definitions ******************************************************************************/ #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

#define ADC_CHANNEL_GROUP 0U

// Channel group

/******************************************************************************* * Prototypes ******************************************************************************/ void SysTick_DelayTicks(uint32_t); /******************************************************************************* * Variables ******************************************************************************/ volatile uint32_t g_systickCounter; const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

/******************************************************************************* * Code ******************************************************************************/ // // Timer interrupt service routine. Refresh the display every 5 ms. // Also, increment the millisecond counter //

● 216

Getting Started with NXP i.MX Development Board - UK.indd 216

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } }

/* Main function */ int main(void) { char Txt[20]; int adcreading; float Rx; const float RF = 10.0; uint32_t RxOhms; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Set systick reload value to generate 1 ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct; // // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true;

● 217

Getting Started with NXP i.MX Development Board - UK.indd 217

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false; lcd_init();

// Initialize LCD

while(1) { lcd_clear(); ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); Rx = g_Adc_12bitFullRange * RF / adcreading - RF;

// Calculate Rx

RxOhms = 1000 * Rx;

// In Ohms

lcd_print("R= ");

// Display R=

itoa(RxOhms, Txt, 10); lcd_print(Txt);

// Display Rx

SysTick_DelayTicks(1000);

// Wait 1 sec

} }

Figure 10.23 Program listing Example output from the program is shown in Figure 10.24. In this example, the unknown resistor was 1000 Ω.

● 218

Getting Started with NXP i.MX Development Board - UK.indd 218

26-10-2023 09:35


Chapter 10 • Analog-To-Digital Converter (Adc)

Figure 10.24 Example output

● 219

Getting Started with NXP i.MX Development Board - UK.indd 219

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 11 • Using Pulse Width Modulation (PWM) 11.1 Overview Pulse Width Modulation (PWM) is commonly used to drive heavy loads such as motors, actuators and so on. As you will see in this chapter, PWM is basically a positive rectangular waveform whose pulse width can be changed. By changing the pulse width, you can effectively change the average voltage supplied to the load.

11.2 Basic theory of the pulse width modulation Pulse Width Modulation (PWM) is a commonly used technique for controlling the power delivered to analog loads using digital waveforms. Although analog voltages (and currents) can be used to control the delivered power, they have several drawbacks. Controlling large analog loads requires large voltages and currents that cannot easily be obtained using standard analog circuits and DACs. Precision analog circuits can be heavy, large, and expensive, and they are also sensitive to noise. By using the PWM technique, the average value of voltage (and current) fed to a load is controlled by switching the supply voltage ON and OFF at a fast rate. The longer the power on time, the higher is the voltage supplied to the load. Figure 11.1 shows a typical PWM waveform where the signal is basically a repetitive positive pulse, having the period T, ON time TON and OFF time of T – TON seconds. The minimum and maximum values of the voltage supplied to the load are 0 and VP, respectively. The PWM switching frequency is usually set to be very high (usually in the order of several kHz) so that it does not affect the load that uses the power. The main advantage of PWM is that the load is operated efficiently since the power loss in the switching device is very low. When the switch is ON, there is practically no voltage drop across the switch, and when the switch is OFF there is no current supplied to the load.

Figure 11.1 PWM waveform The duty cycle (or D) of a PWM waveform is defined as the ratio of the ON time to its period. Expressed mathematically, Duty Cycle (D) = TON / T The duty cycle is usually expressed as a percentage, and therefore, D = (TON / TOFF) × 100% ● 220

Getting Started with NXP i.MX Development Board - UK.indd 220

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

By varying the duty cycle between 0% and 100%, we can effectively control the average voltage supplied to the load between 0 and Vp. The average value of the voltage applied to the load can be calculated by considering a general PWM waveform shown in Figure 1. The average value A of waveform f(t) with period T and peak value ymax and minimum value ymin is calculated as:

or,

In a PWM waveform, ymin = 0 and the above equation becomes

or,

As it can be seen from the above equation, the average value of the voltage supplied to the load is directly proportional to the duty cycle of the PWM waveform, and by varying the duty cycle we control the average load voltage. Figure 11.2 shows the average voltage for different values of the duty cycle.

Figure 11.2 Average voltage (shown as dashed line) supplied to a load It is interesting to notice that with correct low-pass filtering, the PWM can be used as a DAC if the MCU does not have a DAC channel. By varying the duty cycle, you can effectively vary the average analog voltage supplied to the load.

● 221

Getting Started with NXP i.MX Development Board - UK.indd 221

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

11.3 Features of the i.MXRT1010 processor PWM The PWM module (called the eFlexPWM module) on the development kit has the following features: • An eFlexPWM module contains four PWM submodules, each of which is set up to control a single half-bridge power stage. • 16 bits of resolution for center, edge aligned, and asymmetrical PWMs. • Fractional delay for enhanced resolution of the PWM period and edge placement. • PWM outputs that can operate as complementary pairs or independent channels. • Ability to accept signed numbers for PWM generation. • Independent control of both edges of each PWM output. • Support for synchronization to external hardware or other PWMs. • Double buffered PWM registers: - Integral reload rates from 1 to 16. • Halfcycle reload capability. • Multiple output trigger events can be generated per PWM cycle via hardware. • Support for double switching PWM outputs. • Fault inputs can be assigned to control multiple PWM outputs. • Programmable filters for fault inputs. • Independently programmable PWM output polarity. • Independent top and bottom dead time insertion. • Each complementary pair can operate with its own PWM frequency and dead time values. • Individual software control for each PWM output. • All outputs can be programmed to change simultaneously via a FORCE_OUT event. • The PWMX pin can optionally output a third PWM signal from each submodule. • Channels not used for PWM generation can be used for buffered output compare functions. • Channels not used for PWM generation can be used for input capture functions. • Enhanced dual edge capture functionality. • The option to supply the source for each complementary PWM signal pair from any of the following: - Crossbar Switch (XBAR) module outputs. - External ADC input, taking into account the values set in ADC high- and low-limit registers.

11.4 Operation of the PWM The PWM module on the development kit has been developed for complex motor control applications. Its operation is very complex, although it is very flexible. It has numerous features that may seem unnecessary for simple PWM generation. In this section, I will try to summarize its operation briefly.

● 222

Getting Started with NXP i.MX Development Board - UK.indd 222

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

The general idea is that each eFlexPWM contains up to 4 submodules (plus one auxiliary submodule called PWMX, but it is preferable not to use it). Each submodule has its own set of counters and channel values to generate two PWMs because in motor control we usually use PWM pairs for high and low side of transistor bridges. Figure 11.3 shows the internal structure of a single PWM submodule that controls two PWM outputs. Basically, VAL 2 and 3 define the pulse width of one channel and VAL 4 and 5 define the other channel. Different from most PWM modules, instead of one register to define the pulse width, two registers are used: one for the start of the pulse, and one for the end of the pulse, so you are not defining the pulse width, instead you are defining the start and end of the pulse. This allows for a lot more flexibility in the generation of PWM waveforms. The INIT register defines the value at which the period starts, and VAL1 defines the end of the period. So, for example, a PWM duty cycle for the first channel pair would go: Start of count at INIT value > Start of duty cycle at VAL2 > end of duty cycle at VAL3 > end of period and VAL1 > return to INIT value and repeat. The process can be edge aligned or center aligned. In the edge aligned case: write 0 to INIT and to VAL2, write PWM period value for VAL1 (for example 1000 counts) and the use VAL3 for the duty cycle from 0 to 1000. For the center aligned case: repeat the similar setup but move VAL2 to half of the desired duty cycle on VAL3 the other half. For center aligned (Figure 11.4), it is easier to imagine the values are in the negative and positive range, this way, your period will go from a negative value (two's complement) to a positive value (the positive of the same number as the INIT). This way, the center aligned duty cycle is easy to define, it is simply the number of necessary counts divided by 2, VAL2 would be the negative of that and VAL3 the positive.

Figure 11.3 Internal structure of a PWM submodule

● 223

Getting Started with NXP i.MX Development Board - UK.indd 223

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Figure 11.4 Center aligned operation PWM outputs can be configured to operate as a pair of complementary channels. The PWM pins are paired, as shown in Figure 11.5. Complimentary operation is useful in bridge type transistor-based motor drive control applications (Figure 11.6). Deadtime insertion logic is used for each submodule to create non-overlapping complementary signals when in complimentary mode of operation.

Figure 11.5 Complementary operation

Figure 11.6 Transistor-based AC-motor drive Figure 11.7 shows the PWM clocking block diagram of each submodule. Each submodule can select between three clock signals: the IPBus clock, EXT_CLK, and AUX_CLK. The EXT_CLK goes to all the submodules. The AUX_CLK signal is broadcast from submodule0 and can be selected as the clock source by other submodules so that the 8-bit prescaler and MCTRL[RUN] from submodule0 can control all the submodules. To permit lower PWM frequencies, the prescaler produces the PWM clock frequency by dividing the IPBus clock frequency by 1–128. The prescaler bits, CTRL[PRSC], select the prescaler divisor. This pres-

● 224

Getting Started with NXP i.MX Development Board - UK.indd 224

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

caler is buffered and will not be used by the PWM generator until MCTRL[LDOK] is set and a new PWM reload cycle begins or CTRL[LDMOD] is set.

Figure 11.7 Clocking block diagram For each submodule, software can select between eight signal sources for the FORCE_OUT signal. The local signals are used when the user simply wants to change the signals on the output pins of the submodule without regard for synchronization with other submodules. However, if it is required that all signals on all submodule outputs change at the same time, the Master, EXT_SYNC, or EXT_FORCE signals should be selected. Register reload logic is used to determine when the outer set of registers for all double buffered register pairs will be transferred to the inner set of registers. The register reload event can be scheduled to occur every 'n' PWM cycles. A half cycle reload option is also supported. Further detailed information on the PWM can be obtained from the NXP reference manual: i.MX RT1010 Processor Reference Manual, Document Number: IMXRT1010RM Rev. 0, 09/2019

11.5 Project 1 – Mosquito repeller Description: It is a well-known fact that sound at 40 kHz ultrasonic frequencies can be used to repel mosquitos. In this project, a 40 kHz PWM waveform is generated. This waveform can be used to drive a piezo transducer to generate ultrasonic sound and repel mosquitos. The aim of this project is to show how a PWM waveform can be generated using the development kit. Block diagram: Figure 11.8 shows the block diagram of the project.

● 225

Getting Started with NXP i.MX Development Board - UK.indd 225

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Figure 11.8 Block diagram of the project Circuit diagram: Arduino UNO header pin J57, pin 20 (IO2) is connected to a piezo ultrasonic transducer through a switching transistor. Figure 11.9 shows the circuit diagram of the project.

Figure 11.9 Circuit diagram of the project Program listing: Before writing the program, you must configure the PWM port. The steps are as follows: • Click ConfigTools followed by Pins • Click on pin number 11 (GPIO_02) and select PWM1 • Click on ConfigTools followed by Peripherals • Click on Peripheral drivers (Device specific) and select eFlexPWM (Figure 11.10)

● 226

Getting Started with NXP i.MX Development Board - UK.indd 226

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

Figure 11.10 Select eFlexPWM • Click Update Code followed by OK Make sure you include pwm using the SDK Manager as described earlier. You are now ready to write the program. Figure 11.11 shows the program listing (PWM-40KHz). At the beginning of the program, the various definitions used in the program are included. The frequency is set to 40,000 Hz in definition APP_DEFAULT_PWM_FREQUENCE. Function PWM_DRV() sets the PWM clock source and configures the PWM port. Inside the main program loop, the PWM is configured and the timer is started. The PWM runs in the background and generates a 40 kHz square waveform as shown in Figure 11.12. In this figure, the frequency is shown to be 40,064 kHz and the height of the waveform is +3.3 V. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *PWM 40 kHz signal with 50% duty cycle*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_pwm.h" #include "fsl_xbara.h" /******************************************************************************* * Definitions ******************************************************************************/

● 227

Getting Started with NXP i.MX Development Board - UK.indd 227

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

#define BOARD_PWM_BASEADDR PWM1

// PWM base address

#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) #ifndef APP_DEFAULT_PWM_FREQUENCE #define APP_DEFAULT_PWM_FREQUENCE (40000UL)

// 40 kHz

#endif /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ static void PWM_DRV(void) { uint16_t deadTimeVal; pwm_signal_param_t pwmSignal[1]; uint32_t pwmSourceClockInHz; uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCE; pwmSourceClockInHz = PWM_SRC_CLK_FREQ; /* Set deadtime count, we set this to about 650ns */ deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000; pwmSignal[0].pwmChannel

= kPWM_PwmA;

pwmSignal[0].level

= kPWM_HighTrue;

pwmSignal[0].dutyCyclePercent = 50;

// 50 percent duty cycle

pwmSignal[0].deadtimeValue

= deadTimeVal;

pwmSignal[0].faultState

= kPWM_PwmFaultState0;

pwmSignal[0].pwmchannelenable = true; /*********** PWMA_SM0 - phase A, configuration, setup 1 channel as an example ************/ PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, pwmSignal, 1, kPWM_ SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); } /* Main function */ int main(void) {

● 228

Getting Started with NXP i.MX Development Board - UK.indd 228

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

PRINTF("BEGINNING\n\r"); pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while(1) { CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2); /* Set AHB PODF to 2, divide by 3 */ CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); /* Set IPG PODF to 3, divede by 4 */ /* Set the PWM Fault inputs to a low value */ XBARA_Init(XBARA); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3); pwmConfig.enableDebugMode = false; pwmConfig.enableWait = false; pwmConfig.reloadSelect = kPWM_LocalReload; pwmConfig.clockSource = kPWM_BusClock; pwmConfig.prescale = kPWM_Prescale_Divide_1; pwmConfig.initializationControl = kPWM_Initialize_LocalSync; pwmConfig.forceTrigger = kPWM_Force_Local; pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; pwmConfig.reloadLogic = kPWM_ReloadImmediate; pwmConfig.pairOperation = kPWM_Independent; //

PWM_GetDefaultConfig(&pwmConfig); #ifdef DEMO_PWM_CLOCK_DEVIDER pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER; #endif /* Use full cycle reload */ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;

● 229

Getting Started with NXP i.MX Development Board - UK.indd 229

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

/* Initialize submodule 0 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) == kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* config->faultClearingMode = kPWM_Automatic; config->faultLevel = false; config->enableCombinationalPath = true; config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig); #ifdef DEMO_PWM_FAULT_LEVEL faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL; #endif PWM_DRV();

// Call Init function

/* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); /* Start the PWM generation from Submodules 0 */ PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0); while (1U) { /* Delay at least 100 PWM periods. */ SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 100, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); } } }

Figure 11.11 Program listing

● 230

Getting Started with NXP i.MX Development Board - UK.indd 230

26-10-2023 09:35


Chapter 11 • Using Pulse Width Modulation (PWM)

Figure 11.12 Generated waveform on the oscilloscope Notice that the following lines of code set the PWM channel to a positive logical level, and this way when the trigger condition of the PWM occurs the channel will go to a HIGH State. If these lines are commented, then when the trigger condition of the PWM occurs, nothing will happen, and the channel will stay on the same logical level. XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3);

To run the program, compile it in Release mode and then copy the .axf file to the virtual COM port assigned to the development board. Changing the duty cycle In the program in Figure 11.11, the duty cycle is fixed at 50%. The duty cycle can easily be changed by setting a variable (e.g. pwmVal) to the required duty cycle between 0 and 100 and then calling the following function: PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_ PwmA, kPWM_SignedCenterAligned, pwmVal);

● 231

Getting Started with NXP i.MX Development Board - UK.indd 231

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 12 • Electric Motors 12.1 Overview An electric motor is an electrical machine that converts electrical energy into mechanical energy in the form of linear or rotational movement (or torque). Electric motors operate on the principles of magnetic fields where a force is generated between the motor's magnetic field and the current through its windings and this force causes linear or rotational movement. Electric motors are classified into two categories as follows: • AC motors • DC motors Electric motors are used in many industrial, commercial, and domestic applications. The MIMXRT1010 processor provides complex and very flexible PWM channels that are aimed for motor control applications. In this chapter we will be looking at the design of simple DC electric motor control applications using the MIMXRT1010-EVK development kit with a PWM channel.

12.2 Project 1 – Two-speed motor speed control Description: This is a simple project where a small, brushed DC motor is connected to the development board through a power MOSFET transistor switch. In addition, a push-button switch is connected to the development board. Normally, the motor spins at 25% of full speed. Pressing the button will increase the speed to 50% of its maximum value. The aim of this project is to show how PWM can be used to control the speed of a DC brushed motor. Block Diagram: Figure 12.1 shows the block diagram of the project. A motor driver (MOSFET transistor) and a push-button switch are connected to the development board.

Figure 12.1 Block diagram of the project Circuit Diagram: The circuit diagram of the project is shown in Figure 12.2. The MOSFET transistor is connected to Arduino header J57, pin 20 (PWM1 output) through a bipolar transistor switch, and the push-button switch is connected to J57 pin 6 (GPIO_19). The button output pin is pulled high by the software, and therefore it is normally at logic 1. Pressing the button changes the button output to logic 0. Figure 12.3 shows the circuit built on a breadboard.

● 232

Getting Started with NXP i.MX Development Board - UK.indd 232

26-10-2023 09:35


Chapter 12 • Electric Motors

Figure 12.2 Circuit diagram

Figure 12.3 Circuit built on a breadboard A bipolar transistor can be used as a switch in small motor applications. There are many applications, however, where a larger motor may be used and/or the motor requires large current to operate, and a bipolar transistor may not be able to supply the required current. In such applications, it is recommended to use a power MOSFET transistor. A MOSFET transistor where the Gate voltage is logic level compatible with +3.3 V, such as the IRL520, IRF3708 and so on can be used. In this project, an IRFZ44 type MOSFET is used which is not +3.3 V compatible. A BC337 type bipolar transistor is used to drive the MOSFET. The continuous Drain current of this power MOSFET transistor can be as high as 20 A (of course an external power supply must be used for large currents since the USB-driven power supply cannot provide more than 0.8 A of current). The pin configurations of the IRL540 MOSFET transistor and BC337 are shown in Figure 12.4.

● 233

Getting Started with NXP i.MX Development Board - UK.indd 233

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Figure 12.4 Pin configuration of IRFZ44 and BC337 Program Listing: Before writing the program, the development board must be configured as in the PWM projects (see Chapter 10). Additionally, J57, pin 6 (GPIO_AD_05, IO19) must be configured as an input (Figure 12.5).

Figure 12.5 Configure J57, pin 6 (IO19) as input Figure 12.6 shows the program listing (Two-speed-motor). The program generates a PWM waveform with the frequency of 1 kHz. By default, the duty cycle is set to 25% so that the motor operates at a quarter of its full speed. Pressing the button increases the duty cycle to 50% so that the motor rotates at half of its full power (notice the logic inversion by the bipolar transistor and the inverse duty cycle. The MOSFET is ON when the bipolar transistor is OFF. i.e. when its base is at logic LOW).

● 234

Getting Started with NXP i.MX Development Board - UK.indd 234

26-10-2023 09:35


Chapter 12 • Electric Motors

/* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Two Speed Motor*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_pwm.h" #include "fsl_xbara.h" /******************************************************************************* * Definitions ******************************************************************************/ #define Button 19

// Button at IO19

#define BOARD_PWM_BASEADDR PWM1

// PWM base address

#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) #ifndef APP_DEFAULT_PWM_FREQUENCE #define APP_DEFAULT_PWM_FREQUENCE (1000UL)

// 1000 Hz

#endif /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ static void PWM_DRV(void) { uint16_t deadTimeVal; pwm_signal_param_t pwmSignal[1]; uint32_t pwmSourceClockInHz; uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCE; pwmSourceClockInHz = PWM_SRC_CLK_FREQ; /* Set deadtime count, we set this to about 650ns */ deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000;

● 235

Getting Started with NXP i.MX Development Board - UK.indd 235

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

pwmSignal[0].pwmChannel

= kPWM_PwmA;

pwmSignal[0].level

= kPWM_HighTrue;

pwmSignal[0].dutyCyclePercent = 25;

// 25% by default

pwmSignal[0].deadtimeValue

= deadTimeVal;

pwmSignal[0].faultState

= kPWM_PwmFaultState0;

pwmSignal[0].pwmchannelenable = true; /*********** PWMA_SM0 - phase A, configuration, setup 1 channel as an example ************/ PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, pwmSignal, 1, kPWM_ SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); } /* Main function */ int main(void) { uint8_t DutyCycle; PRINTF("BEGINNING\n\r"); pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while(1) { CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2); /* Set AHB PODF to 2, divide by 3 */ CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); /* Set IPG PODF to 3, divede by 4 */ /* Set the PWM Fault inputs to a low value */ XBARA_Init(XBARA); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3);

● 236

Getting Started with NXP i.MX Development Board - UK.indd 236

26-10-2023 09:35


Chapter 12 • Electric Motors

pwmConfig.enableDebugMode = false; pwmConfig.enableWait = false; pwmConfig.reloadSelect = kPWM_LocalReload; pwmConfig.clockSource = kPWM_BusClock; pwmConfig.prescale = kPWM_Prescale_Divide_1; pwmConfig.initializationControl = kPWM_Initialize_LocalSync; pwmConfig.forceTrigger = kPWM_Force_Local; pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; pwmConfig.reloadLogic = kPWM_ReloadImmediate; pwmConfig.pairOperation = kPWM_Independent; //

PWM_GetDefaultConfig(&pwmConfig); #ifdef DEMO_PWM_CLOCK_DEVIDER pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER; #endif /* Use full cycle reload */ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; /* Initialize submodule 0 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) ==

kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* config->faultClearingMode = kPWM_Automatic; config->faultLevel = false; config->enableCombinationalPath = true; config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig); #ifdef DEMO_PWM_FAULT_LEVEL faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL; #endif PWM_DRV();

// Call Init function

/* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true);

● 237

Getting Started with NXP i.MX Development Board - UK.indd 237

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

/* Start the PWM generation from Submodules 0 */ PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0); while (1U) { if(GPIO_PinRead(GPIO1, Button) == 0) {

DutyCycle = 25;

PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0,

// 25% Inverse Duty Cycle (faster)

kPWM_PwmA, kPWM_SignedCenterAligned, DutyCycle); } else {

DutyCycle = 50;

PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0,

// 50% Inverse Duty Cycle (slower)

kPWM_PwmA, kPWM_SignedCenterAligned, DutyCycle); } PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); } } }

Figure 12.6 Program listing

12.3 Project 2 – Varying the motor speed Description: This is again a basic project where a small brushed DC motor is connected to the development board through a power MOSFET transistor switch as in the previous project. In addition, a potentiometer is connected to one of the analog inputs of the kit. In this project, the speed of the motor is varied by moving the potentiometer arm. Block diagram: Figure 12.7 shows the block diagram of the project. A motor driver (bipolar transistor and MOSFET) and a potentiometer are connected to the microcontroller.

Figure 12.7 Block diagram of the project The DC motor in this project is controlled by varying the duty cycle of a PWM wave sent to the motor. By turning the potentiometer, the analog voltage read by the microcontroller is varied and this in turn changes the PWM duty cycle of the voltage applied to the motor.

● 238

Getting Started with NXP i.MX Development Board - UK.indd 238

26-10-2023 09:35


Chapter 12 • Electric Motors

Circuit Diagram: The circuit diagram of the project is shown in Figure 12.8. The MOSFET transistor is connected as in the previous project through a bipolar transistor. A 10 kΩ potentiometer is connected to Arduino header J56, pin 14 (GPIO_AD_01, i.e. ADC channel 1).

Figure 12.8 Circuit diagram Program listing: Before writing the program, the PWM channels must be configured as in the previous project. Also, GPIO_AD_01 pin must be configured as an analog input (Figure 12.27).

Figure 12.9 Configure the ports The frequency of the PWM is set to 1,000 Hz, as in the previous project. Figure 12.10 shows the program listing (Varying-motor-speed). Compile the program as usual and upload to your development kit. At the beginning of the program, the PWM and ADC parameters are defined. The PWM part of the program is the same as in the previous program. Inside the

● 239

Getting Started with NXP i.MX Development Board - UK.indd 239

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

main program, the potentiometer voltage is read and stored in variable adcreading. This reading is then multiplied by 100.0 and divided by 4096.0 to map the reading to allowed duty cycle ranges. Varying the potentiometer arm changes the speed of the motor. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *Varying the motor speed*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_pwm.h" #include "fsl_xbara.h" #include "fsl_adc.h" /******************************************************************************* * Definitions ******************************************************************************/ #define BOARD_PWM_BASEADDR PWM1

// PWM base address

#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) #ifndef APP_DEFAULT_PWM_FREQUENCE #define APP_DEFAULT_PWM_FREQUENCE (1000UL)

// 1000 Hz

#endif #define ADC_BASE

ADC1

// ADC Base

#define ADC_USER_CHANNEL

1U

// ADC used

#define ADC_CHANNEL_GROUP 0U

// Channel group

/******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ const uint32_t g_Adc_12bitFullRange = 4096U;

// 12-bits

int adcreading = 0; /******************************************************************************* * Code ******************************************************************************/

● 240

Getting Started with NXP i.MX Development Board - UK.indd 240

26-10-2023 09:35


Chapter 12 • Electric Motors

static void PWM_DRV(void) { uint16_t deadTimeVal; pwm_signal_param_t pwmSignal[1]; uint32_t pwmSourceClockInHz; uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCE; pwmSourceClockInHz = PWM_SRC_CLK_FREQ; /* Set deadtime count, we set this to about 650ns */ deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000; pwmSignal[0].pwmChannel

= kPWM_PwmA;

pwmSignal[0].level

= kPWM_HighTrue;

pwmSignal[0].dutyCyclePercent = 25;

// 25% by default

pwmSignal[0].deadtimeValue

= deadTimeVal;

pwmSignal[0].faultState

= kPWM_PwmFaultState0;

pwmSignal[0].pwmchannelenable = true; /*********** PWMA_SM0 - phase A, configuration, setup 1 channel as an example ************/ PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, pwmSignal, 1, kPWM_ SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); } /* Main function */ int main(void) { uint8_t DutyCycle; float mapping; PRINTF("BEGINNING\n\r"); pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); adc_config_t adcConfigStruct; adc_channel_config_t adcChannelConfigStruct;

● 241

Getting Started with NXP i.MX Development Board - UK.indd 241

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

// // Configure ADC channel // adcConfigStruct.enableAsynchronousClockOutput = true; adcConfigStruct.enableOverWrite =

false;

adcConfigStruct.enableContinuousConversion =

false;

adcConfigStruct.enableHighSpeed =

false;

adcConfigStruct.enableLowPower =

false;

adcConfigStruct.enableLongSample =

false;

adcConfigStruct.referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; adcConfigStruct.samplePeriodMode =

kADC_SamplePeriod2or12Clocks;

adcConfigStruct.clockSource =

kADC_ClockSourceAD;

adcConfigStruct.clockDriver =

kADC_ClockDriver1;

adcConfigStruct.resolution =

kADC_Resolution12Bit;

//

ADC_GetDefaultConfig(&adcConfigStruct); ADC_Init(ADC_BASE, &adcConfigStruct);

// Initialize

kStatus_Success == ADC_DoAutoCalibration(ADC_BASE);

// Auto calibrate

adcChannelConfigStruct.channelNumber = ADC_USER_CHANNEL;

// ADC channel

adcChannelConfigStruct.enableInterruptOnConversionCompleted = false;

while(1) { CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2);

/* Set AHB PODF to 2, divide by 3

CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3);

/* Set IPG PODF to 3, divede by 4

*/ */ /* Set the PWM Fault inputs to a low value */ XBARA_Init(XBARA); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3); pwmConfig.enableDebugMode = false; pwmConfig.enableWait = false; pwmConfig.reloadSelect = kPWM_LocalReload; pwmConfig.clockSource = kPWM_BusClock; pwmConfig.prescale = kPWM_Prescale_Divide_1;

● 242

Getting Started with NXP i.MX Development Board - UK.indd 242

26-10-2023 09:35


Chapter 12 • Electric Motors

pwmConfig.initializationControl = kPWM_Initialize_LocalSync; pwmConfig.forceTrigger = kPWM_Force_Local; pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; pwmConfig.reloadLogic = kPWM_ReloadImmediate; pwmConfig.pairOperation = kPWM_Independent; //

PWM_GetDefaultConfig(&pwmConfig); #ifdef DEMO_PWM_CLOCK_DEVIDER pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER; #endif /* Use full cycle reload */ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; /* Initialize submodule 0 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) ==

kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* config->faultClearingMode = kPWM_Automatic; config->faultLevel = false; config->enableCombinationalPath = true; config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig); #ifdef DEMO_PWM_FAULT_LEVEL faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL; #endif PWM_DRV();

// Call Init function

/* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); /* Start the PWM generation from Submodules 0 */ PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0); while (1U) {

● 243

Getting Started with NXP i.MX Development Board - UK.indd 243

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

ADC_SetChannelConfig(ADC_BASE, ADC_CHANNEL_GROUP, &adcChannelConfigStruct); while (0U == ADC_GetChannelStatusFlags(ADC_BASE, ADC_CHANNEL_GROUP)) { } adcreading = ADC_GetChannelConversionValue(ADC_BASE, ADC_CHANNEL_GROUP); mapping = 100.0 * adcreading / g_Adc_12bitFullRange; DutyCycle = mapping; PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_ PwmA, kPWM_SignedCenterAligned, DutyCycle); PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); } } }

Figure 12.10 Program listing

12.4 Project 3 – Changing the speed and motor direction Description: This project shows how the speed and direction of a DC motor can be changed. In this project, the motor is controlled as follows: • Turn clockwise at high speed • Wait 5 seconds • Turn clockwise at low speed • Wait 5 seconds • Turn anticlockwise at high speed • Wait 5 seconds • Turn anticlockwise at low speed The above process is repeated indefinitely until stopped manually. The speed of a DC motor can be changed by changing the applied voltage level. The direction of rotation can be changed by simply reversing the polarity of the supply voltage. In DC motor direction control applications, an H bridge circuit is commonly used to change the polarity of the voltage applied to the motor and hence change the direction of rotation. Figure 12.11 shows the basic operation of an H bridge circuit. Here, we have 4 switches labeled A, B, C, D and the motor is connected in the middle of the circuit. By controlling the switches, we can easily change the polarity of the voltage applied to the motor. For example, by clocking switches A and D and opening B and C, the motor will rotate clockwise. Similarly, by closing switches B and C and opening A and D, the motor will rotate counterclockwise. This is illustrated below (0 and 1 correspond to switch open and close conditions, respectively):

● 244

Getting Started with NXP i.MX Development Board - UK.indd 244

26-10-2023 09:35


Chapter 12 • Electric Motors

A B C D 0 0 0 0 1 0 0 1 0 1 1 0

Motor rotation No rotation Clockwise Anti-clockwise

It is clear from the above table that switches A and D and also B and C must be operated together.

Figure 12.11 H bridge with switches In real motor direction control applications, the switches are replaced by transistors. Figure 12.12 shows an H bridge circuit built using bipolar transistors. In this circuit, four signals are required to control the motor direction as explained above. A simpler circuit using only two control signals is shown in Figure 12.13. By using logic inverters, we can make sure that only one transistor on either side of the motor is turned ON. For example, when A is set to logic 1, the transistor at the top left is turned ON and the one at the bottom left is OFF. NPN and PNP bipolar transistors can also be used in H bridge circuits requiring two control lines, as shown in Figure 12.14.

Figure 12.12 Simple H bridge circuit built using bipolar transistors

● 245

Getting Started with NXP i.MX Development Board - UK.indd 245

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Figure 12.13 H bridge circuit using only 2 control signals

Figure 12.14 H bridge circuit with NPN and PNP transistors An H bridge circuit built using power MOSFET transistors is shown in Figure 12.15. Notice that diodes are used in the H bridge circuits to protect the transistors from the back emf. Also, in a 4-wire control, A and C or B and D must not be enabled at the same time as this will short the power supply to ground and possibly damage the bridge transistors.

Figure 12.15 H bridge circuit built using MOSFET transistors

● 246

Getting Started with NXP i.MX Development Board - UK.indd 246

26-10-2023 09:35


Chapter 12 • Electric Motors

Using an H Bridge module Block diagram: The block diagram of the project is shown in Figure 12.16. In this project, the LMD18200 H bridge motor controller module is used. The module has a built-in H bridge where the speed and the direction of rotation of a motor can be controlled. The speed is controlled by sending PWM waves to the chip, and the direction of rotation is controlled by setting or clearing a direction control bit. LMD18200 has the following features: • Up to 3A continuous current • Operating voltage: 12 V to 55 V • TTL and CMOS compatible inputs • Motor speed and direction control • Thermal shutdown • Motor stop (break) input

Figure 12.16 Block diagram of the project The LMD18200 module is available with an on-board heat sink, capacitors, resistors, screw terminals, and it has the following pins (Figure 12.17): Left Screw Terminal (J2) GND power supply ground PWM PWM speed control input DIR motor direction control input BRAKE motor brake control (logic 1 to brake) Right Screw Terminal (J3) V+ external power supply input (max 55 V) GND external power supply ground OUT1, 2 motor terminals

Figure 12.17 The LMD18200 module

● 247

Getting Started with NXP i.MX Development Board - UK.indd 247

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Table 11.1 shows the operational logic table of the LMD18200 module. PWM

DIR

BRAKE

Active output drivers

1

1

0

Rotate in one direction

1

0

0

Rotate in reverse direction

1

1

1

Brake

1

0

1

Brake

X

1

Brake

0

Table 11.1 LMD18200 operational logic table Circuit Diagram: Figure 12.18 shows the circuit diagram of the project. A 12 V DC motor is connected to screw terminals OUT1 and OUT2, and an external +12 V power supply is connected to the V+ input. Arduino header J56 pin 14 (GPIO_AD_01, IO15) and J57 pin 20 (PWM1 output as in the previous project) are connected to the DIR and PWM inputs of the LMD18200 module respectively. Figure 12.19 shows the project built on a breadboard.

Figure 12.18 Circuit diagram

Figure 12.19 Project built on a breadboard

● 248

Getting Started with NXP i.MX Development Board - UK.indd 248

26-10-2023 09:35


Chapter 12 • Electric Motors

Program listing: Before writing the program you must configure the PWM port (Arduino header J57 pin 20) and also configure Arduino header J56 pin 14 (GPIO_AD_01, IO15) as output (Figure 12.20).

Figure 12.20 Configure the I/O ports The program listing is shown in Figure 12.21 (LMD18200). At the beginning of the program, DIR is defined as 15 and various PWM parameters are also defined. The frequency of the PWM waveform is set to 1,000 Hz. The function Rotate has two character arguments: direction and speed. If the direction is 'c' (i.e. clockwise) then the DIR pin of the LMD18200 module is set LOW. If, on the other hand, the direction is 'a' (i.e. anticlockwise) then the DIR pin of the LMD18200 module is set HIGH. If the speed is 'f' (i.e. fast) then the PWM duty cycle is set to 50%; otherwise it is set to 25%. Inside the main program loop, the motor is rotated as required. Notice that a delay was introduced using the function SDK_DelayAtLeastUs(). With a PWM frequency of 1,000 Hz and a setting of 2,000, the delay was approximately 5 seconds. /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * *LMD18200*/ #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_debug_console.h" #include "fsl_pwm.h" #include "fsl_xbara.h" #include "fsl_adc.h" /******************************************************************************* * Definitions

● 249

Getting Started with NXP i.MX Development Board - UK.indd 249

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

******************************************************************************/ #define DIR 15U // Motor direction #define BOARD_PWM_BASEADDR PWM1

// PWM base address

#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) #ifndef APP_DEFAULT_PWM_FREQUENCE #define APP_DEFAULT_PWM_FREQUENCE (1000UL)

// 1000 Hz

#endif /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ static void PWM_DRV(void) { uint16_t deadTimeVal; pwm_signal_param_t pwmSignal[1]; uint32_t pwmSourceClockInHz; uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCE; pwmSourceClockInHz = PWM_SRC_CLK_FREQ; /* Set deadtime count, we set this to about 650ns */ deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000; pwmSignal[0].pwmChannel

= kPWM_PwmA;

pwmSignal[0].level

= kPWM_HighTrue;

pwmSignal[0].dutyCyclePercent = 10; pwmSignal[0].deadtimeValue

= deadTimeVal;

pwmSignal[0].faultState

= kPWM_PwmFaultState0;

// 10% by default

pwmSignal[0].pwmchannelenable = true; /*********** PWMA_SM0 - phase A, configuration, setup 1 channel as an example ************/ PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, pwmSignal, 1, kPWM_ SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz); } //

● 250

Getting Started with NXP i.MX Development Board - UK.indd 250

26-10-2023 09:35


Chapter 12 • Electric Motors

// This function rotates the motor. Argument direction can be 'c' for clockwise or 'a' for // anticlockwise. Argument speed can be 'f' for fast or 's' for slow // void Rotate(char direction, char speed) { uint8_t DutyCycle; if(direction == 'c') GPIO_PinWrite(GPIO1, DIR, 0U); else if(direction == 'a') GPIO_PinWrite(GPIO1, DIR, 1U); if(speed == 'f') DutyCycle = 50; else if(speed == 's') DutyCycle = 25; PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_ SignedCenterAligned, DutyCycle); PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); }

// // The motor is rotated as follows: // 5 seconds clockwise and fast // 5 seconds clockwise and slow // 5 seconds anticlockwise and fast // 5 seconds anticlockwise and slow // int main(void) { PRINTF("BEGINNING\n\r"); pwm_config_t pwmConfig; pwm_fault_param_t faultConfig; BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); while(1) { CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2);

/* Set AHB PODF to 2, divide by 3

CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3);

/* Set IPG PODF to 3, divede by 4

*/ */

● 251

Getting Started with NXP i.MX Development Board - UK.indd 251

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

/* Set the PWM Fault inputs to a low value */ XBARA_Init(XBARA); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2); XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3); pwmConfig.enableDebugMode = false; pwmConfig.enableWait = false; pwmConfig.reloadSelect = kPWM_LocalReload; pwmConfig.clockSource = kPWM_BusClock; pwmConfig.prescale = kPWM_Prescale_Divide_1; pwmConfig.initializationControl = kPWM_Initialize_LocalSync; pwmConfig.forceTrigger = kPWM_Force_Local; pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; pwmConfig.reloadLogic = kPWM_ReloadImmediate; pwmConfig.pairOperation = kPWM_Independent; //

PWM_GetDefaultConfig(&pwmConfig); #ifdef DEMO_PWM_CLOCK_DEVIDER pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER; #endif /* Use full cycle reload */ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; /* Initialize submodule 0 */ if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) ==

kStatus_Fail) { PRINTF("PWM initialization failed\n"); return 1; } /* config->faultClearingMode = kPWM_Automatic; config->faultLevel = false; config->enableCombinationalPath = true; config->recoverMode = kPWM_NoRecovery; */ PWM_FaultDefaultConfig(&faultConfig);

● 252

Getting Started with NXP i.MX Development Board - UK.indd 252

26-10-2023 09:35


Chapter 12 • Electric Motors

#ifdef DEMO_PWM_FAULT_LEVEL faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL; #endif PWM_DRV();

// Call Init function

/* Set the load okay bit for all submodules to load registers from their buffer */ PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true); /* Start the PWM generation from Submodules 0 */ PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0); while (1U) { Rotate('c', 'f');

// Clockwise, fast

SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 2000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); Rotate('c', 's');

// Clockwise, slow

SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 2000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); Rotate('a', 'f');

// Anticlockwise, fast

SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 2000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); Rotate('a', 's');

// Anticlockwise, slow

SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 2000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); } } }

Figure 12.21 Program listing

● 253

Getting Started with NXP i.MX Development Board - UK.indd 253

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 13 • Using the CMSIS-DSP Library 13.1 Overview CMSIS-DSP is an optimized compute library developed for embedded microcontroller-based systems. The library provides optimized compute kernels for Cortex-M and Cortex-A based processors. The CMSIS-DSP library provides functions in the following topics: • Basic math functions • Fast math functions • Complex math functions • Filtering functions • Matrix functions • Transform functions • Motor control functions • Statistical functions • Support functions • Interpolation functions • Support Vector Machine functions (SVM) • Bayes classifier functions • Distance functions • Quaternion functions Each topic includes many functions related to the topic. For example, the Matrix functions library includes the following matrix operations: • Matrix addition • Cholesky and LDLT decompositions • Complex Matrix Multiplication • Complex Matrix Transpose • Matrix Initialization • Matrix Inverse • Matrix Multiplication • Matrix Scale • Matrix Subtraction • Matrix Transpose • Matrix Vector Multiplication Further details on the CMSIS-DSP library functions can be obtained from the following link: https://www.keil.com/pack/doc/CMSIS/DSP/html/index.html

● 254

Getting Started with NXP i.MX Development Board - UK.indd 254

26-10-2023 09:35


Chapter 13 • Using the CMSIS-DSP Library

In this chapter you will be developing a MCUXpresso based program to show how matrix addition, multiplication, and transpose can be carried out on a 4×4 matrix using the CMSIS-DSP library.

13.2 Project 1 – Matrix addition, multiplication, and transpose Description: In this project two 4×4 matrices, A32 and B32, are defined. Also, two empty matrices C32 and AT32 are defined. The program initially adds matrices A32 and B32 and stores the result in C32. All the elements of matrix C32 are displayed on the Console. Then A32 and B32 are multiplied and the result is stored in C32. Again, all the elements of C32 are displayed on the Console. Finally, the transpose of matrix A32 is taken and stored in matrix AT32. All elements of matrix AT32 are also displayed on the Console. Program listing: The library functions operate on matrix data structures. For example, the type definition for the floating-point matrix structure is shown below (see the above link for further information): typedef struct { uint16_t numRows;

// number of rows of the matrix.

uint16_t numCols;

// number of columns of the matrix.

float32_t *pData;

// points to the data of the matrix.

} arm_matrix_instance_f32;

There is an associated initialization function for each type of matrix data structure. The initialization function sets the values of the internal structure fields. Use of the initialization function is optional. However, if an initialization function is used, then the instance structure cannot be placed into a const data section. To place the instance structure in a const data section, manually initialize the data structure. For example: arm_matrix_instance_f32 S = {nRows, nColumns, pData}; There are similar definitions for Q15 and Q31 data types. Where, nRows specifies the number of rows, nColumns specifies the number of columns, and pData points to the matrix data array. Figure 13.1 shows the program listing (MatrixTest). At the beginning of the program, the header file arm_math.h and other required header files are included in the program. Matrix A32 and matrix B32 are defined as follows: const float32_t A32[16] = { 1.0, 1.0, 4.0, 6.0, 1.0, 12.0, 10.0, 2.0,

● 255

Getting Started with NXP i.MX Development Board - UK.indd 255

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

3.0, 10.0, 4.0, 5.0, 5.0, 16.0, 2.0, 8.0, }; const float32_t B32[16] = { 2.0, 3.0, 4.0, 5.0, 1.0, 3.0, 5.0, 7.0, 3.0, 10.0, 4.0, 5.0, 5.0, 10.0, 2.0, 8.0, };

The matrix instances are then initialized by specifying their names, number of rows (nRows) and number of columns (nColumns). Matrix addition is done using the function arm_mat_add_f32(&A, &B, &C), where matrices A and B are the inputs and C is the result. The result is displayed in the form of rows and columns by calling the function DisplayMatrix. Note that pData points to the resultant matrix structure. Matrix multiplication is done using the function arm_mat_mult_f32(&A, &B, &C), where matrices A and B are the inputs and C is the result as before. The result is displayed by calling the function DisplayMatrix. Transpose of matrix A is done using function: arm_mat_trans_f32(&A, &AT), where matrix A is the input and AT is the result. The result is again displayed by calling the function DisplayMatrix. /* * Copyright 2016-2023 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file

MatrixTest.c

* @brief

Application entry point.

* Matrix addition, multiplication, and transpose*/ #include "arm_math.h" #include <stdio.h> #include "board.h" #include "peripherals.h" #include "pin_mux.h"

● 256

Getting Started with NXP i.MX Development Board - UK.indd 256

26-10-2023 09:35


Chapter 13 • Using the CMSIS-DSP Library

#include "clock_config.h" #include "MIMXRT1011.h" #include "fsl_debug_console.h" arm_status status; // // Define matrix A // const float32_t A32[16] = { 1.0,

1.0,

4.0,

6.0,

1.0,

12.0,

10.0,

2.0,

3.0,

10.0,

4.0,

5.0,

5.0,

16.0,

2.0,

8.0,

}; // // Define matrix B // const float32_t B32[16] = { 2.0,

3.0,

4.0,

5.0,

1.0,

3.0,

5.0,

7.0,

3.0,

10.0,

4.0,

5.0,

5.0,

10.0,

2.0,

8.0,

}; // // Display the matrix elements // void DisplayMatrix(float32_t *M) { int i = 0; for(int j=0; j < 16; j++) { if(i == 4) {

i = 0;

PRINTF("\n");

} PRINTF("%3.2f\t", *(M+j)); i++; } PRINTF("\n"); }

● 257

Getting Started with NXP i.MX Development Board - UK.indd 257

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

// // MAin program // void main(void) { float32_t C32[16]; float32_t AT32[16]; /* Board pin init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); arm_matrix_instance_f32 A;

/* Matrix A Instance */

arm_matrix_instance_f32 AT;

/* Matrix AT(A transpose) instance

arm_matrix_instance_f32 B;

/* Matrix B instance */

*/ arm_matrix_instance_f32 C; uint32_t nRows, nColumns;

/* Matrix B instance */

/* Temporary variables */

/* Initialise the matrix Instances */ nRows = 4; nColumns = 4; arm_mat_init_f32(&A, nRows, nColumns, (float32_t *)A32); arm_mat_init_f32(&B, nRows, nColumns, (float32_t *)B32); arm_mat_init_f32(&C, nRows, nColumns, (float32_t *)C32); arm_mat_init_f32(&AT, nRows, nColumns, (float32_t *)AT32); // // Matrix operation: C = A + B // status=arm_mat_add_f32(&A, &B, &C); PRINTF("Matrix operation: C = A + B\n"); DisplayMatrix(C.pData); // // Matrix operation: C = A * B // status=arm_mat_mult_f32(&A, &B, &C); PRINTF("\nMatrix operation: C = A * B\n"); DisplayMatrix(C.pData); // // Matrix transpose of A

● 258

Getting Started with NXP i.MX Development Board - UK.indd 258

26-10-2023 09:35


Chapter 13 • Using the CMSIS-DSP Library

// status = arm_mat_trans_f32(&A, &AT); PRINTF("\nMatrix operation: Transpose of A\n"); DisplayMatrix(AT.pData); }

Figure 13.1 Program listing Creating the program Load the program from the Elektor book website, or carry out the steps below to create the program: • Click to open the MCUXpresso IDE • Enter MatrixTest as the name for your workspace and Click Launch • Click IDE • Click Create a new C/C++ project (Figure 13.2)

Figure 13.2 Click C/C++ to create a new project • Select MIMXRT1010 (Figure 13.3) and click Next

Figure 13.3 Select MIMXRT1010 • Give a name to your project (e.g. MatrixTest)

● 259

Getting Started with NXP i.MX Development Board - UK.indd 259

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

• Click tab CMSIS Drivers and enable to include the DSP library (Figure 13.4)

Figure 13.4 Enable to include the DSP library • Select the Semihost as the SDK Debug Console so that the program outputs will be displayed on the Console • Click Finish • Copy the program shown in Figure 13.1 to your IDE Testing the program • Connect the development kit to your PC • Click Debug under the Quickstart Panel • Select the default debugger probe • Wait until the compilation is ready and the first statement in the program is highlighted (Figure 13.5)

Figure 13.5 The program is ready in the debugger • Click Run, followed by Resume. The program should run and display the results as shown in Figure 13.6.

● 260

Getting Started with NXP i.MX Development Board - UK.indd 260

26-10-2023 09:35


Chapter 13 • Using the CMSIS-DSP Library

Figure 13.6 Program output • Click Run followed by Terminate to terminate the program and the debugger.

● 261

Getting Started with NXP i.MX Development Board - UK.indd 261

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Chapter 14 • Sound and Audio Signal Processing (DSP) 14.1 Overview Sound waves are created by the vibration of objects, for example, the string of a guitar, the speaker of a radio, the voice box of a person and so on. You can hear sounds because the vibrations of the air cause the ear drum to vibrate, which are converted into nerve signals and sent to the brain. This book is about audible sound waves. Adult humans can hear in a frequency range from about 20 Hz to 20 kHz (20,000 Hz). Children and babies can hear frequencies slightly higher than 20 kHz. Some animals, on the other hand, can hear sounds at higher than 20 kHz or lower than 20 Hz. For example, some bats can hear sounds as high as 200 kHz, but their low limits are around 20 kHz. The hearing frequency ranges of some animals are given below: Animal Dog Horse Rat Elephant Chicken Sheep Mouse Rabbit

Hearing frequency range (Hz) 67 – 45,000 55 – 33,500 200 – 76,000 16 – 10,500 125 – 2,000 125 – 42,500 900 – 79,000 96 – 49,000

The human audio spectrum is divided into 7 bands, with the following frequencies: Band Brilliance Presence Upper midrange Midrange Lower midrange Bass Sub-bass

Frequency range 6 – 20 kHz 4 – 6 kHz 2 – 4 kHz 500 Hz – 2 kHz 250 – 500 Hz 60 – 250 Hz 20 – 60 Hz

The MIMXRT1010-EVK development kit includes an on-board microphone, a headphone output with 3.5 mm jack connector, and a speaker connector. In the following sections, we will be looking at some important theory of analog and digital audio. Several audio-based demo project files are available in the MCUXpresso demo files folders. In the remainder parts of this chapter, we will be looking at some of these audio projects using the development kit.

14.2 Analog and digital audio sound Analog audio has been around for many years and much earlier than digital audio. In analog audio recording, a microphone is used to convert the sound signals into electrical

● 262

Getting Started with NXP i.MX Development Board - UK.indd 262

26-10-2023 09:35


Chapter 14 • Sound and Audio Signal Processing (DSP)

analog signals and then save these audio signals on a medium such as a tape (or tape cassette) or vinyl records with spiral grooves. Most of the early music and speech recordings were analog, with tape cassettes used by the public to record private speech or to play pre-recorded music. In digital audio recording, a microphone is still used to convert the sound signals into electrical signals, but then these analog signals are converted into digital forms using analog-to-digital converter hardware and the resulting digital signals are saved as files in computer memory. Nowadays, it is also possible to use digital microphones and record signals directly in digital form. A comparison of the analog and digital audio signals is given below: Degradation of quality: The quality of analog audio degrades as tape cassettes or vinyl record age. This degradation is also noticeable when a recording is copied or played many times. Digital signals, on the other hand, do not degrade by aging. Digital signals can be copied to other mediums without using their qualities. Signal-to-noise ratio (SNR): SNR is the amount of noise generated when a recording is played. In other words, it describes how much unwanted noise signal is present in a played sound signal. SNR is measured in decibels (dB). The higher the value, the less noise there is in the signal. For example, if an audio signal has a SNR ratio of 50 dB, it means that the level of the desired signal is 50 dB higher than the level of noise. Audio bandwidth: The audio bandwidth is the range of signals permitted to be recorded or played back. The higher the bandwidth, the higher will be the maximum frequency that can be recorded correctly. Media type: Digital audio signals can be stored in digital memories. Nowadays, smartphones, iPads, and tablets can store thousands of digital audio files in minimal space. This is not the case with analog media. Tape cassettes or vinyl records are bulky, and they can store only a limited amount of data. In this book, we are interested in using digital audio files and also carry out digital audio signal processing (DSP) using digital audio files.

14.3 Digital audio sound file formats Digital audio files can be in various formats. Some of the popular file formats are given in this section.

14.3.1 Uncompressed audio file formats Uncompressed audio files are not processed, and they are available as captured and converted to digital format. As a result of this, uncompressed audio files are large and take up a lot of disk space. Some uncompressed audio file formats are:

● 263

Getting Started with NXP i.MX Development Board - UK.indd 263

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

PCM: This stands for Pulse-Code Modulation and there is no compression. The digital recording is very close to its exact representation of analog sound. The average size of a PCM file is about 10 MB per second. Therefore, a 3-minute PCM music file can take up to 30 MB disk space. WAV: This stands for Waveform Audio file format, developed by Microsoft and IBM. Although not all WAV files are uncompressed, most are, and they are in PCM format with wrappers, making them suitable for Windows systems. The average size of a WAV file is about 10 MB per second. Therefore, a 3-minute WAV music file can take up to 30 MB of disk space. AIFF: This stands for Audio Interchange File Format and is similar to WAV. AIFF was developed by Apple for their MAC systems. AIFF is basically PCM type files with wrappers, making them suitable for MAC systems (they can be opened on Windows systems). Although most AIFF audio files are uncompressed PCM files, there are compressed versions as well, called AIFF-C. The average size of a AIFF file is about 10 MB per second. Therefore, a 3-minute AIFF music file can take up to 30 MB of disk space.

14.3.2 Audio files with lossy compressions These files are compressed, and some data is lost during the compression process. The reason for compression is to minimize the disk usage, since uncompressed files take up a lot of disk space. As a result, the sound quality is sacrificed for smaller file sizes. Some lossy compressed audio file formats are: MP3: This stands for MPEG-1 Audio Layer 3. This format is very popular for music files. In this format, the quality of sound is reduced beyond the hearing range of normal ear. Also, the quality of the sound is reduced for sounds that are not easy to hear. Almost all digital devices nowadays with audio playback capabilities (e.g. PCs, smartphones, tablets, smart TVs etc.) can play MP3 audio files. The average bitrate for an MP3 file is 128 kbits per second, which requires about one megabyte of data per minute of audio. Note: do not confuse MP3 and MP4. MP3 is audio only, while MP4 supports both audio and video. AAC: This stands for Advanced Audio Coding. Although it was developed as a competitor to MP3, it never became as popular as MP3, even though it uses a much more advanced compression algorithm than the MP3. AAC is currently used by YouTube, iOS, Android, and by the PlayStation. AAC files are slightly smaller than MP3 files. WMA: This stands for Windows Media Audio. It was developed as a competitor to MP3 and its compression algorithm is very similar to AAC, giving higher quality audio sound. WMA is a proprietary format created by Microsoft and, as such, it has not become very popular. WMA files are slightly larger than MP3 files.

14.3.3 Audio files with lossless compressions In these file formats, the file size is reduced with compression without any data quality loss. These files are larger than the lossy compressed files and smaller than uncompressed files. Some lossless compressed audio file formats are:

● 264

Getting Started with NXP i.MX Development Board - UK.indd 264

26-10-2023 09:35


Chapter 14 • Sound and Audio Signal Processing (DSP)

FLAC: This stands for Free Lossless Audio Codec, and it is a popular file format that can compress a file by up to 60% without losing its quality. FLAC is the main competitor of MP3 for music files, and it is currently regarded as the best audio file format as far as size and sound quality are concerned. For example, a 3-minute FLAC music file takes about 15 MB as compared to WAV which takes about 30 MB. ALAC: This stands for Apple Lossless Audio Codec, and it is similar to FLAC, although it is less efficient as far as compression is concerned. Apple products such as iOS and iTunes support ALAC. ALC file size is similar to those of FLAC. There is also a lossless version of the WMA file format, but it is not as efficient as the FLAC or ALAC.

14.3.4 Which audio file format to choose? The choice depends on the sound quality you are after and the amount of disk space you can spare. If you wish to listen to high quality raw music and not worried about the disk space it will occupy, you should choose an uncompressed file. If at the same time, you wish to use less disk space, then a file with lossless compression, such as FLAC or ALAC could be a good choice. If you wish to listen to music at ordinary quality and worried about disk space, then MP3 or another file format with lossy compression could be a good choice.

14.3.5 High-quality digital audio sound In general terms, high-quality digital audio refers to music files that have higher sampling rates and larger bit depths than standard CD music files. CD music files are specified at 16 bits, 44.1 kHz sampling rate. With a 44.1 kHz sampling rate, all the audible frequencies are covered. Higher quality (Hi-res) audio files are sampled with 24 bits and 48 kHz sampling rate, or 24 bits 96 kHz sampling rate, or even 24 bits 192 kHz sampling rate. In most cases, the human ear cannot differentiate music sampled higher than 16 bits and 44.1 kHz sampling rate. One disadvantage of sampling at higher than 16 bits is that more disk space is required to store the file.

14.4 Audio digital signal processing (Audio DSP) The abbreviation DSP stands for one of two things: Digital Signal Processor, or Digital Signal Processing. A Digital Signal Processor refers to specialized microcontroller hardware which is designed to execute specialized instructions in real time. The topic of this chapter is Digital Signal Processing, we will call it DSP from now on in this chapter. DSP is a very broad field covering signals from very low frequencies to very high frequencies. Here, we are interested only in audio signals which cover the frequency range of 20 Hz to 20 kHz. In a typical DSP application, the input signal (e.g. from a microphone) can either be digital or analog. In the case of analog input, the signal is converted into digital form using an ADC (analog-to-digital converter) and is fed to a microcontroller for further processing. The signal is then processed, such as filtered to remove unwanted high-frequency noise, noise is canceled using special noise-canceling algorithms, the frequency spectrum of the signal is extracted and analyzed, signal shape is modified, audio signals are synthesized, and so on, and the resulting digital signal is converted back into

● 265

Getting Started with NXP i.MX Development Board - UK.indd 265

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

analog using a DAC (digital-to-analog converter) and sent to a speaker or to some other output device. All of the signal processing is carried out using software algorithms with the target microcontroller. It is much easier to edit and manipulate digital signals than analog signals. DSP is used extensively nowadays by professional music makers. Many plugins are available on PCs which simplify the editing and processing of already recorded music files and other audio files. The global audio DSP market size was valued at $11.06 billion in 2019, and is projected to reach $23.43 billion by 2027 (Allied Market Research). In this chapter, you will be using the MIMXRT1010-EVK development board for some real-time DSP projects.

14.4.1 The SAI module SAI is a Serial Audio Interface module that can be used to send and/or receive audio. In addition to I2S, it supports other audio interfaces as well. The MIMXRT1010-EVK development board includes two synchronous SAI modules, which support I2S, AC97, TDM, codec/ DSP interfaces, and MQS interface for medium quality audio via GPIO pad. MQS is used to convert I2S audio data from SAI3 to PWM, and then can drive external speakers, but in practical usage, an amplifier drive circuit is required. Additionally, a headphone jack, external speaker connections, and a microphone are provided on the board.

14.4.2 The I2S bus The I2S (Inter-Integrated Circuit Sound Protocol) is a serial bus interface standard used commonly to connect digital audio devices together. It was introduced in 1986 by Philips Semiconductors (now NXP Semiconductors) and then revised in 1996 and 2022. The I2S protocol sends pulse-code modulation (PCM) digital audio data from a controller to a target. The bus has at least 3 lines: bit clock, word select, and data line. Word select is used to specify which of the stereo channels, left or right, the data should be sent to. Readers should understand that the I2C and I2S are entirely different bus protocols, and they are unrelated. Figure 14.1 shows the block diagram of a conventional audio DSP system which does not use the I2S bus. Here, the audio signal is received from an analog microphone. This signal is then converted into digital form using an ADC. The resulting digital signal is then fed to a microcontroller, which processes this digital signal. At the end, the signal is converted back into analog using a DAC converter and is fed to a speaker. An analog amplifier is usually used (not shown) to increase the signal level for the speaker. In most low frequency applications, the ADC and DAC can be part of the microcontroller. In high-speed and high-quality applications, it may be necessary to use external professional quality ADC and DAC converters.

Figure 14.1 Conventional audio DSP system

● 266

Getting Started with NXP i.MX Development Board - UK.indd 266

26-10-2023 09:35


Chapter 14 • Sound and Audio Signal Processing (DSP)

Figure 14.2 shows the block diagram of a digital audio DSP system using the I2S bus interface. Here, a digital microphone is used, compatible with the I2S bus. The output of the microphone, which is a digital signal, is fed to the microcontroller's I2S bus input. The signal is processed by the microcontroller as required and is sent in digital form to an I2S compatible amplifier module. The output of the amplifier is an analog signal which drives the speaker.

Figure 14.2 Digital audio DSP system The line definitions of the I2S bus are summarized below: Bit clock: this pin is the serial clock line, usually denoted as BCLK. The clock runs continuously. Word select: this pin is usually denoted by WS, and it selects the channels. 0 corresponds to the left channel, while 1 corresponds to the right channel. Data: This pin is usually denoted by SD, or SDATA and is the serial data line. The data is sent out in 2's complement format, with the MSB bit first. The transmitter and receiver do not need to have an agreed-upon word length; the transmitter sends what it has, and the receiver takes what it can use. New data bits can be clocked out on the rising or falling edge of the clock. However, they must be clocked in on the rising edge. The bit clock is sent out for each bit of data on the data line. The frequency of this clock is the given by the product of the sample rate, the number of bits per channel, and the number of channels. In a typical audio CD, the standard is 44.1 kHz sample rate with 16 bits of data. Assuming 2 channels (i.e. stereo), the bit clock frequency will be: 44.1 kHz × 16 × 2 = 1.4112 MHz Therefore, if you want to send two channels of high-quality audio, we would need a clock rate of 1.4112 MHz. The telephone quality sound is sampled at 8 kHz with 8 bits and there is only one channel. Therefore, to send telephone quality audio, you will need a clock frequency of: 8 kHz × 8 × 1 = 64 kHz I2S allows up to two channels to be used on the same data line, and this is selected by the Word select bit. For 2-channel stereo operation, the left audio is transmitted on the low cycle of the Word select, and the right channel is transmitted on the high cycle. The I2S bus

● 267

Getting Started with NXP i.MX Development Board - UK.indd 267

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

is not like the I2C bus, where multiple devices can be connected on the same bus line. In I2S only two channels of a device can be used, multiple devices cannot be connected to the bus. The maximum length of the I2S bus is specified as 3 meters. The bit clock and Word select signals can be generated with a receiver, transmitter, or a third-party controller (see Figure 14.3).

Figure 14.3 I2S configurations (taken from the I2S specification) Figure 14.4 shows the timing diagram of the I2S bus.

Figure 14.4 I2S bus timing (taken from the I2S specification) The advantages of the I2S bus are: • There are no data synchronization issues since there is a single master device • An I2S microphone does not require an analog front end • Separate clock and data lines are used, which results in low jitter • ADC and DAC are not required since the signals are digital The disadvantages of the I2S bus are: • There is no error detection or correction and therefore, errors can occur on the line • As a result of the propagation delays, there could be synchronization problems at high clock rates • There is no standard I2S cabling or connector procedure, different manufacturers use different cables and connectors

● 268

Getting Started with NXP i.MX Development Board - UK.indd 268

26-10-2023 09:35


Chapter 14 • Sound and Audio Signal Processing (DSP)

14.4.3 The SAI bus The SAI module on the MIXRT1010-EVK development board contains a Transmitter and Receiver with the following signals (see Chapter 3.1): • SAI_MCLK: master clock, used to generate the bit clock, master output, slave input. • SAI_TX_BCLK: Transmit bit clock, master output, slave input • SAI_TX_SYNC: Transmit Frame sync, master output, slave input, L/R channel select • SAI_TX_DATA[4]:Transmit data line, 1-3 share with RX_DATA[1-3] • SAI_RX_BCLK: receiver bit clock • SAI_RX_SYNC: receiver frame sync • SAI_RX_DATA[4]: receiver data line SAI module clocks are audio master clock, bus clock, and bit clock. The SAI module Frame sync has 3 modes: 1: Transmit and receive using its own BCLK and SYNC 2) Transmit async, receive sync: use transmit BCLK and SYNC, transmit enable at first, disable at last. 3) Transmit sync, receive async: use receive BCLK and SYNC, receiver enable at first, disable at last.

14.5 MIMXRT1010-EVK development kit audio demo project files Several audio demo project files are included in the MCUXpresso SDK. These files are in the demo folders demo_apps and usb_examples (see Figure 14.5). There is only one file (sai) in demo_apps, and six files in usb_examples (dev_audio_…). Readers can modify and use these project files in their own projects.

Figure 14.5 Audio demo project files In this section, we will look at some details of project file sai. When this project file is run in debug mode, the following options are given to the user: • Record and playback at the same time • Playback sine wave

● 269

Getting Started with NXP i.MX Development Board - UK.indd 269

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Users can use the on-board analog microphone to record and at the same time play the recording. There is also the option of using an SD card and an external digital microphone, but these are disabled in the code and are highlighted. First, load the project files in folder sai: • Start the MCUXpresso IDE by specifying a workspace name • Click IDE • Click Import SDK Examples under the Quickstart Panel • Click to select MIMXRT1011xxxxx under MIMXRT1010 and click Next • Click to expand demo_apps and select sai to load the project files and click NEXT followed by FINISH • You should see the project files loaded. Click to expand source and you should see the following C programs: playbackSineWave.c recordPlayback.c sai.c Program sai: This is the main program that runs when debugging is started. At the beginning of the programs, the required header files are included in the program and various CODEC and audio definitions are declared. Notice here that the headphone volume is set to 100 which is the maximum value (the range is 0 to 100). Then, the SAI1 clock source and frequency are defined. The wm8960 Codec is initialized by specifying the route, left and right input sources, play source, the I2S bus, the format of the data (16-bit data with 16 kHz sample rate), and the master_slave mode is set to false. Code relating to the SD card and external digital microphone are highlighted and are not compiled. WM8960 Codec is initialized with the following options: wm8960_config_t wm8960Config = { .i2cConfig = {.codecI2CInstance = BOARD_CODEC_I2C_INSTANCE, .codecI2CSourceClock = BOARD_CODEC_I2C_CLOCK_FREQ}, .route = kWM8960_RoutePlaybackandRecord, .leftInputSource = kWM8960_InputDifferentialMicInput3, .rightInputSource = kWM8960_InputDifferentialMicInput2, .playSource = kWM8960_PlaySourceDAC, .slaveAddress = WM8960_I2C_ADDR, .bus = kWM8960_BusI2S, .format = {.mclk_HZ = 6144000U, .sampleRate = kWM8960_AudioSampleRate16KHz, .bitWidth = kWM8960_AudioBitWidth16bit},

● 270

Getting Started with NXP i.MX Development Board - UK.indd 270

26-10-2023 09:35


Chapter 14 • Sound and Audio Signal Processing (DSP)

.master_slave = false, };

kWM8960_InputDifferentialMicInput2 refers to the on-board analog microphone, and kWM8960_InputDifferentialMicInput3 to the headphone microphone. Inside the main program loop, the LPI2C and SAI1 clocks are set and MCLK is enabled. Function CODEC_Init() initializes the Codec. Function CODEC_SetVolume() sets the volume to DEMO_CODEC_VOLUME on the right headphone. The program displays the message SAI Demo Started on the console, initializes the SAI, configures I2S, enables interrupts to handle FIFO errors, and then displays the following menu (note that the SD card and external digital microphone options are disabled): Please choose the option: 1.Record and Playback at same time 2.Playback sine Wave 3.Quit If option 1 is selected: The board is configured for record-playback by calling function BOARD_CONFIGCODEC_FOR_RECORD_PLAYBACK(). Finally, the function RecordPlayback() is called (program: recordPlayback.c) to record audio and playback on the headphone. If option 2 is selected: function BOARD_CONFIGCODEC_FOR_RECORD_PLAYBACK() is called, followed by function PlaybackSine() (program: playbackSineWave.c) to play a sine wave on the headphone. Function playbackSineWave: This function has 3 arguments: base address, frequency in Hz, and duration in seconds. The function arm_sin_q15() is called to generate values for trigonometric sine in q15 format. The generated sine wave values are stored in audioBuff(). The frequency of the data is then calculated by calling the FFT function do_ fft(). The calculated frequency is displayed on the Console. The function plays a 250 Hz sine wave for 5 seconds. The Function SAI_TransferSendEDMA() is called to perform a non-blocking SAI transfer to the headphone using DMA. All the prepared data in audioBuff() is sent out. Function recordPlayback: This function has 2 arguments: the base address and the duration in seconds. In this project, the duration is set to 30 seconds by the calling program sai.c. This function calls SAI_TransferReceiveEDMA() to read non-blocking data using DMA from the microphone into structure xfer and then to transfer this data to the headphone by calling function SAI_TransferSendEDMA(), in non-blocking mode using DMA.

● 271

Getting Started with NXP i.MX Development Board - UK.indd 271

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Testing The steps are: • Connect the MIMXRT1010-EVK development kit to your PC • Connect a headphone to the headphone jack • Click on the project name (evkmimxrt1010_sai<Debug>) in Project Explorer. Click Quick Settings → SDK Debug Console and make sure that Semihost console is selected • Click debug under the Quickstart Panel to load the programs and start debugging • Click Run followed by Resume to start the program running in debug mode • You should see the menu displayed (Figure 14.6). Choose option 2 to hear the 250 Hz sine wave played for 5 seconds. You may find that the volume is very low. • Choose option 1. Speak to the on-board analog microphone, and you should hear the sound on the right speaker of the headphone • Repeat the testing as many times as desired • Click Run followed by Terminate to exit the debug mode

Figure 14.6 The menu

● 272

Getting Started with NXP i.MX Development Board - UK.indd 272

26-10-2023 09:35


Chapter 15 • References

Chapter 15 • References Readers may find useful information on MCUXpresso and related topics at the following web sites: https://www.nxp.com/design/development-boards/i-mx-evaluation-and-developmentboards/i-mx-rt1010-evaluation-kit:MIMXRT1010-EVK https://www.nxp.com/webapp/sps/download/preDownload.jsp?render=true https://www.nxp.com/document/guide/getting-started-with-i-mx-rt1010-evaluationkit:GS-MIMXRT1010-EVK https://www.nxp.com/webapp/sps/download/preDownload.jsp?render=true https://www.nxp.com/design/development-boards/i-mx-evaluation-and-developmentboards/i-mx-rt1010-evaluation-kit:MIMXRT1010-EVK https://community.nxp.com/t5/Blog/New-updated-MCUXpresso-tool-training-videosavailable/ba-p/1131113 https://www.nxp.com/design/training/getting-started-with-the-i-mx-rt1010-evk-andmcuxpresso:TIP-GS-IMXRT1010 https://arm-software.github.io/CMSIS_5/DSP/html/group__groupMatrix.html https://developer.arm.com/Additional%20Resources/CMSIS%20DSP%20Software%20 Library

● 273

Getting Started with NXP i.MX Development Board - UK.indd 273

26-10-2023 09:35


Get Started with the NXP i.MX RT1010 Development Kit

Index A ACK ADC AIFF Audio bandwidth Audio file formats Audio sound

125 191 264 263 263 262

B BC337 Binary down counter Binary up counter Bit clock Breakpoint

234 90 90 267 51

C Center aligned Common anode Common cathode ConfigTools Continuous conversion Conveyor belt CPHA CPOL

223 97 97 60 136 182 146 146

D DAP Deadtime insertion logic Debugging Degradation of quality DSP Duty cycle

14 224 30 263 262 220

E Edge aligned Event counter Export Extended mode External interrupt

223 93 27 136 187

F FPU

11

G GPT1 GPT2

14 14

H H-bridge H-bridge module HD44780

245 247 156

I Import IRFZ44

27 234

J JTAG connector

13

K KPP

14

L LDR LED indicators Light intensity LMD18200 LM35 197 LPUART

183 13 211 249 27 15

M Matrix operations Motor speed and direction control Motor speed control MP3 Multiplexed LED MQS

255 244 232 264 102 12

O Ohmmeter One-shot conversion

214 136

P PCM Periodic interrupt timer Pin_mux.c

264 12 23

● 274

Getting Started with NXP i.MX Development Board - UK.indd 274

26-10-2023 09:35


Index

Pointer register PortClear Port expander PortSet Pow Power supply PWM

136 77 125, 147 77 78 13 220

Q Quickstart Panel

50

R Random number Resume RS232

83 26 118

S SAI bus SCL SDA Serial communication Signal to noise ratio SPDIF SPI bus SysTick

269 124 124 117 263 12 145 21

T Temperatue controller Temperature sensor Terminate Thermostat mode Timer interrupt TMP102 TRNG

201 196 26 136 109 135 12

U Update code User button

61 13

V Visual studio

28

W WAV WMA Word select

264 264 267

● 275

Getting Started with NXP i.MX Development Board - UK.indd 275

26-10-2023 09:35


> LED and LCDs > ADC > I2C > SPI > PWM > UART > Motor Control > Audio and Digital Audio Processing (DSP)

About the Author Prof Dr Dogan Ibrahim has a BSc degree in electronic engineering, an MSc degree in automatic control engineering, and a PhD degree in digital signal processing. Dogan has worked in many industrial organizations before he returned to academic life. Prof Ibrahim is the author of over 60 technical books and over 200 technical articles on microcontrollers, microprocessors, and related fields. He is a Chartered electrical engineer and a Fellow of the Institution of Engineering Technology.

Get Started with the NXP i.MX RT1010 Development Kit

Conveniently, several on-board debug probes are supplied with the kit allowing you to debug your programs by talking directly to the MCU. Helped by the debugger, you can single-step through a program, insert breakpoints, view and modify variables, and so on. Using the MCUXpresso IDE and the SDK, many working and tested projects are developed in the book based on parts, modules, and technologies, including:

H0W2

At the heart of NXP Semiconductors‘ MIMXRT1010 Development Kit is the i.MX RT1010 Crossover MCU sporting an Arm Cortex-M7 core truly capable of running power- and memory hungry DSP applications. The popular MCUXpresso IDE is key to creating software for the development kit, while a powerful SDK is provided to reduce program development time and effort. The dev kit offers great connectivity through its audio CODECs, 4-way headphone jack, external speaker connection, microphone, and Arduino interface.

H0W2

Volume 3

Get Started with the NXP i.MX RT1010 Development Kit Develop Arm® Cortex®-M7 powered Audio, DSP and Motor Control Projects

Dogan Ibrahim

Dogan Ibrahim

Elektor International Media www.elektor.com

3 Cover HOW2 - Getting Started With NXP iMX Development Board.indd 3

knows how

26-10-2023 10:14


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.