Writing First Code in Python (Hello World)

The "Hello, World!" program is a computer programming classic that has stood the test of time. For beginners, "Hello, World!" is a simple and full first program that introduces the basic syntax of programming languages and can be used to evaluate systems and programming environments.

The more you learn about Python, the more you may use it for your own purposes. Data analyst, application developer, or the ability to automate your work processes are all examples of jobs that can be automated.

This Python 3 tutorial will show you how to create a simple "Hello, World" program. Python's basic syntax and components include the following:

  • Variable-types
  • Data structures
  • Math operators
  • loops
  • Different function calls
  • Input and output functions
  • Interfaces and classes
  • APIs memorize the syntax.

Python`s IDE

An IDE (Integrated Development Environment) is a software development tool. Integrated development environments (IDEs) include a variety of software development-specific tools. Examples of these instruments include:

  • Build, execution, and debugging tools
  • An editor intended to handle code (such as syntax highlighting)
  • The use of some type of version control

There are many distinct programming languages supported by IDEs, as well as a wide range of additional functionality. Because of this, they can be very huge and take a long time to download and install. Using them correctly may necessitate additional training.

Definition of function?

A function is a piece of code that serves a single purpose and can be reused multiple times. Functions provide for greater modularity and code reuse in your program. Functions have the benefit of being well-known by a variety of names. Functions, methods, subroutines, procedures, etc. are all referred to in different ways by different programming languages. Think about what we'll be talking about later in this session if you come across any of these terms.

Print function – What is it?

Since you all learned Python by printing Hello, World! you might think that there is nothing new to learn about the Python Print function. As with any language, learning to use the Print function in Python or any other is like taking your first baby steps into a new world of programming. When studying a programming language, it's easy to get caught up in the more advanced concepts and lose sight of the simplicity and usefulness of basic functions.

Today's tutorial is all about Python's Print function; you'll learn about one of the most underappreciated functions.

For example, in Python3, parenthesis is required or else you'll get a syntax error as illustrated in the image below.

In Python3, print () is not a statement but a function, as demonstrated by the above output. First things first, let's see what the print () function returns.

Built-in functions and methods are returned by this method, which indicates that it is a Python function.

A new line or vertical space between the two outputs can be added by simply using the print () function without sending any arguments in.

The command Palette

The Command Palette, which is possibly Atom's most essential command, is shown to us on that welcome page. The command palette will appear if you press Ctrl+Shift+P while in an editor pane.

Writing the first Program

Packages from the Atom community are available to help you assemble and run programs. We'll be utilizing "script" to run our application in this example.

go to file>settings>install

Install script by searching for it in the search bar. It should appear under "Packages" in the Settings menu after installation. Please be aware that script does not support human input. The "apm" package manager can be used to install packages on Mac OS or Linux.

Creating our first project

Go to File > Add Project Folder in atom and pick a directory to serve as the project's root directory.

In the folder, right-click the folder and select "New File," type "hello."py," and click "OK."

Now that you've made your adjustments, you can open the new file in the editor by clicking on it and then saving it.

Then, in the Print dialog box, type "hello, world!"

To execute the script, use CTRL+SHIFT+B. You may also use View > Toggle Command Palette and type Script: Run to execute a script.

You can also use your terminal to run the python file by navigating to the file directory containing your hello.py file and running this command

python hello.py

How to edit and save files in atom

File editing is rather simple. You can use your mouse and keyboard to navigate and edit the content of the page. A separate editing mode or key commands are not provided. Take a look at the list of Atom packages if you prefer editors that have modes or more advanced key commands. Many programs are available that mimic popular design elements.

You may save a file by selecting File > Save from the menu bar or by pressing Ctrl+S. There are two ways to save the current material in your editor: by selecting File > Save As or using Ctrl+Shift+S. Finally, you can save all open files in Atom by selecting File > Save All.

How to open directories in atom

The majority of your time will be spent working on projects with numerous files, not just single files. Take advantage of the File > Open Folder menu option and select an appropriate folder from the drop-down menu. File > Add Project Folder or hitting Ctrl+Shift+A can also be used to add other directories to your current Atom window.

The command line utility, atom, allows you to open unlimited number of directories by supplying their paths to it. The command atom./hopes./dreams, for example, can be used to simultaneously open the hopes and dreams directories.

An automated Tree View will be displayed on the side of Atom if one or more directories are open.

When you use the Tree View, it's a breeze to see the whole file and directory structure of your project. You can open, rename, and delete files, as well as create new ones, using this window.

In order to toggle between concealing and showing it, use Ctrl+, use the tree-view: toggle command from the Menu Bar, or press Alt+ to bring focus to it. The A, M, and Delete keys can be used to add, move, or remove files and directories in the Tree view. It's also possible to access these choices by right-clicking on a file or folder in the Tree view, as well as copying or pasting its path into your clipboard.

How is python executed?

Unlike functional programming languages that used a single long list of instructions, Python uses code modules that may be switched out. Cpython is the default Python implementation. It is the most often used Python implementation.

Python does not translate its code into a form that hardware can understand, known as machine code. As a result, it turns it into byte code. Python does have a compiler, but it doesn't compile to a machine language. CPUs are unable to decode the byte code (.pyc or.pyo). We'll run the bytes through Python's virtual machine interpreter.

To convert a script into an executable, the Python source code follows these steps:

First, the python compiler reads a python source code or instruction from the command line. It ensures proper formatting of the instruction by inspecting the grammar of each line. The translation is immediately interrupted if an error is found, and an error message is presented.

Assuming there are no errors and the Python source code or instructions are properly formatted, the compiler proceeds to translate them into a form known as "Byte code," which is an intermediate language.

The Python interpreter is invoked by executing bytes of code in the Python Virtual Machine (PVM). PVM is a Python virtual machine (PVM) that turns bytecode into machine code. If there is a problem with the interpretation, the conversion will be interrupted and an error notice will be displayed.

Conclusion

Congratulations for completing your first program. Beginners who want to learn Python can benefit greatly from this guide. To get the most out of this lesson, you may want to play around with the Print function a little more and discover more features that were not covered.

How to Install Python Software?

The first step to becoming a Python coder is to install or update Python on your computer. Python can be installed in a variety of ways, including through the official Python.org distribution, a software package manager, the IoT (Internet of Things) and scientific computing, just to name a few.

In this article, we'll be using official Python distributions, which are often the best option for beginners.

What will you learn from this?

  • How to check if you have the right Python release installed on your computer before proceeding.
  • Installation of Python3 on Windows pc and Linux machine.
  • How to use Python on the web with the help of online interpreters.

INSTALLING REQUIRED PYTHON ENVIRONMENTS

Installing the most recent versions of Python and the packages you'll need to experiment with is a good place to start when learning Python. To create an environment, you need a certain Python version, as well as the necessary packages. Consequently, separate environments are required if you wish to create or utilize apps that have varied Python or package version needs.

Python environment - what is it?

Python's virtual environment is a valuable tool for managing dependencies and separating projects. It's possible to install Python site packages (third-party libraries) in a specific project directory rather than the entire system Python.

Which are the package and environment managers Available?

  • Pip: With a virtual environment, you may use pip, a Python package manager, which stands for "Pip Installs Packages”. This is a tool for creating isolated environments.
  • Conda: Conda is an open-source package management and environment management system that operates on Windows, Mac OS X, and Linux. Installing, running, and updating packages and their dependencies is a breeze thanks to Conda. You can quickly build, save, load and swap environments on your own computer using Conda. Software for any language may be packaged and distributed using this tool.

In windows

On Windows, there are three installation options:

  • Using Microsoft store.
  • Using the available complete installer.
  • Windows subsystem for Linux implementation.

You'll learn how to check the current release of Python installed on your Windows machine in this section. You'll also discover which of the three installation options is best for you.

Installation

Step 1: Install Python based on your choice of version.

Python 2 and Python 3 are available, each with its syntax and way of doing things.

Here we are going to download python 3 for this course.

Step 2: Download an executable installation file for Python.

Open on your browser and head to the python.org website. On this page click on downloads. Here you can find the latest version of python. Choose the version you require and click Download. For this example, we go with Python 3.10.2.

When you select download, a list of available executable installers with varied operating system requirements will appear. Select the installer that best suits your system's operating system and download it. Let's say we go with the Windows installer (64 bits).

Step 3: Run the Installer Script

If the Python 3.10.2 Windows 64-bit installation was downloaded, run the installation program by double clicking it. Make sure both checkboxes at the bottom are selected before clicking Install New.

Now installation process begins when you click the Install Now button. Wait for a few minutes for installation process to finish.

you should see the screen below if the installation is complete. Now you have python installed in your computer.

Step 4: On Windows, check to see if Python is installed.

To see if Python has been installed successfully on your system. Observe the instructions.

  • Go to the windows search box on the bottom left corner of your display and write "cmd" and click enter. A command prompt window in black will open and this is where you write your commands for execution.
  • Enter 'python --version' into the prompt and press enter.
  • If python is successfully installed on your windows, the version of python that you have installed will be displayed.

In Linux

When installing python in Linux distros, there are two ways involved:

  • Using the Linux os`s package manager: On most Linux distributions, this is the most popular installation technique. It entails using the command line to execute a command.
  • Or building python from source code: Using a package manager is easier than using this method. It requires performing a set of instructions from the command line as well as verifying that you have all of the essential dependencies to compile the Python source code.

You'll find out how to know if your Linux computer has a current version of Python in this section and which of the two installation techniques should you choose?

How to check the python version?

Many Linux versions include Python, but it is unlikely to be the most recent update, and it may even be Python 2 rather than Python 3. Try the following command in a terminal window:

$ python –version

If you have Python installed on your computer, this command should return a version number.

If your current Python version isn't the most recent Python 3 version available, you'll want to upgrade.

Installation

Step 1: Installing Python requires first downloading and installing the necessary development packages

A new version of Debian has been released; therefore, we need to update our old version to the new one.

Open the terminal in your Linux machine. Then run “apt update” in your Linux terminal to update the system before you begin installing python. Then, run "apt-get upgrade" in your terminal to upgrade the system.

then, run " apt install build-essential zlib1g-dev \libncurses5-dev libgdbm-dev libnss3-dev \libssl-dev libreadline-dev libffi-dev curl" to install the build essentials.

Step 2: Download the most recent version

Navigate to your browser in python.org and click on downloads. You will see the latest version of python with a download button, but this is the windows version, instead, navigate to the Linux/UNIX link below it to download the Linux version.

Download the most recent version of Python3 from the official Python website.

You will receive an archive file ("tarball") containing Python's source code when the download is complete.

Step 3: Unzip the tarball folder to a convenient location.

A tar.gz file is a collection of compressed files that may be downloaded in order to conserve space and bandwidth. The tarball, another name for the.tar file, is a container for other files that may be carried about on a flash drive. Because of the extension, gzip is the most extensively used compression application in use. These files can be unzipped in the same way as a standard zipped file:

Run “tar –xvzf a.tar.gz” in the terminal to unzip.

Step 4: The downloaded script must be configured.

Type cd Python-3.*. /configure in your terminal once you've unzipped the Python package and press enter.

Step 5: Begin the build procedure

Use this command below if you need to install an updated version alongside the old version in case you don`t want to delete the old one:

$ sudo make install

Step 6: Verify that the installation is working properly.

Open your terminal and type command below and click enter.

python --version

Python3 has been successfully installed once the output says Python 3.x.

Conclusion

Congratulations! For your system, now you have access to the most recent update of Python. Your Python adventure is just getting started.

Introduction to Python

Greetings! I sincerely hope everything is going well for you all. In this course, we are going to learn step-by-step how to program in Python. The course covers all you need to know about the Python language, from installation to advanced topics. In addition, we'll talk about Python career jobs and do a few projects to strengthen your skills. According to my research, Python is among the top programming languages in use today. (I mean, no offense). Since I am also a Python programmer, I may sound a little prejudiced, but I can certainly declare that I am a huge fan of the language. This tutorial series is meant for absolute beginners with no prior knowledge of python programming, it is also of great help for experienced python programmers looking to brush up on their knowledge. Anyway, let’s start by answering a few questions:

What is Python?

Python is a high-level scripting language for system administration, text processing, and web tasks. Its core language is short and easy to learn, while modules can be added to do a virtually infinite number of functions. It is a genuine object-oriented programming language that runs on a wide range of systems. Python was born out of a desire to build a computer language that was both easy to learn for beginners and powerful enough for advanced users. Python's small, crisp syntax reflects this background, as does the thoroughness with which notions are implemented, without removing the flexibility to program in a more traditional approach. As a result, Python is a fantastic first programming language that provides all of the power and advanced capabilities that users will require in the future. Most experienced programmers claim that Python has restored the fun they normally had during programming, suggesting that van Rossum's inspiration is adequately conveyed in the language itself.

Why Python?

Even those, who aren't computer programmers, have found themselves using it, to perform mundane tasks like raising money because of its relatively low learning curve.

Readability and maintainability

Building a system that is easy to maintain and update requires careful consideration of the quality of the program code. Because of the language's syntactic rules, you may express yourself in Python without writing any more code. With Python, you may use English phrases instead of punctuation, which makes it easier to understand than other computer languages. You don't have to write any more code when using Python to create custom apps. If the code is well-structured, it will make it easier to keep and improve the product.

Compatibility

Code written in this programming language may be executed on a variety of systems and tools thanks to interpreters for this language. When it comes to creating dynamic web pages, Python is also an interpreted programming language. '" There's no need to recompile the application to operate on many operating systems. As a result, changing the code doesn't require recompilation. You don't need to recompile the updated application code to see how the changes affect it. Code updates may be made more rapidly and without increasing development time by using this feature.

Robust Standard Library

Python outweighs other languages because of its vast and robust standard library. You can select from a wide choice of modules in the standard library to meet your specific requirements. If you're building web apps, dealing with operating system interfaces, or working with internet protocols, you can make use of specific packages. The documentation for the Python Standard Library can also help you learn about different modules.

A lot of customizable tools

As an open-source coding language, Python can lower software development costs significantly. Some of the Python modules, libraries, and development tools, all of which are open-source and free, may help you get things done faster. Open-source Python development tools are also available, so you may tailor your project to your exact needs. Flask, Pyramid, and Cherrypy are some of the best Python frameworks for web development.

Make Complex Software Development Easier

Python may be used to build both desktop and web-based applications. Python may also be used to create complex scientific and numerical applications. Easy-to-use Python capabilities make it possible to perform data analysis and visualizations. Data analysis tools can be used to construct custom big data solutions without requiring additional effort or time. You may make your collected data more visually attractive and useful by utilizing its data visualization tools and APIs. Many Python programmers also use Python for AI and NLP jobs.

Python for Cloud Computing

This programming language is used for cloud computing, web and software development, as well as task automation and data analysis.

Since everything is stored in the cloud, you may access it at any time and from anywhere. Web-based software may be used without any installation, an application can be hosted online, and a remote file storage and database system built using cloud computing can be set up. For that purpose, we have different modules like raspberry pi and ESP32 or ESP8266 boards which use python.

The ESP32 is the latest sibling of the ESP8266, which is a microcontroller. For a nominal additional fee, it boosts the device's power and capabilities while also including Bluetooth. The M5 Stack is one of the greatest iterations of these boards. Piezo speakers, batteries, a card reader, and a color screen are all included in this device.

Is python supported?

Python has a big and active community of developers that respond to concerns and build new features at a pace that many commercial software developers would consider exceptional (if not downright shocking). A source-control system is used by Python programmers to coordinate their work remotely. The PEP (Python Enhancement Proposal) procedure must be followed and must be accompanied by improvements to Python's sophisticated regression testing infrastructure for any changes. A far cry from the early days of Python, when an email to the author would suffice, altering Python nowadays is about as complicated as upgrading commercial software. This is a good thing given Python's present vast user base.

What are the technical strengths of python?

  • Python is object-Oriented. Python was designed from the bottom up to be an object-oriented language. Polymorphism, operator overloading, and multiple inheritances are all supported by its class model, but Python's straightforward syntax and type make OOP a breeze to implement. Even if you don't grasp the terminology, you'll find it far easier to learn with Python than with any other OOP language. Later in the course, we'll get to understand this.
  • The language is free to use. Python may be used and distributed without cost. You may get the full Python system's source code for free from the Internet, just like you can with other open-source software like TCL, Perl, Linux, and Apache. If you want to use it in your products, you can do so without fear of violating copyright laws. Python's source code can even be sold if you want to.
  • Python is portable. In addition to being written in ANSI C (American National Standards Institute), Python's standard implementation operates on nearly every major operating system now in use. Python, for example, can run on everything from a PDA to a supercomputer today.
  • Python is easy to use. Python programs may be run by just typing in the code and pressing enter. Unlike in languages like C or C++, there are no intermediary phases of compilation and linking. In many circumstances, you may see the consequence of a program modification as quickly as you type it in Python, which provides for an engaging programming experience and a speedy turnaround following program changes.
  • It is mixable. There are several ways in which Python applications can be "glued" together with other languages. Python's C API, for example, allows C applications to be called by Python programs. As a result, you can tailor the Python system to your own needs, and you can run Python applications in any environment or system.

What are the weaknesses of python?

  • Slow Speed. It is a combination of interpreted and dynamically-typed languages. The execution of line by line is generally sluggish. This slowness may be attributed to Python's dynamic nature, which is also to blame for the language's inability to execute code quickly. Since performance isn't a high priority, Python isn't used in projects.
  • It is not memory efficient. Because of this, Python must make some compromises to keep things simple for programmers. When programming with Python, you'll need a lot of RAM. This could be a problem when you're writing programs, especially if memory efficiency is important.
  • It is weak in mobile computing. When it comes to server-side programming, Python is the most often used language. Python isn't used in client-side or mobile apps for the reasons listed below. When compared to other languages, Python is a poor memory manager and a slow processor.
  • Database access. Python is a breeze to learn and use. Despite this, when we're using the database, it falls behind. While JDBC and ODBC are well-known technologies, Python's database access layer remains basic. Because of this, Python isn't used by big businesses that need to work with complicated old data smoothly.
  • Errors in the code. At any point in time, the data type of a Python variable can change. If an integer number is saved in a variable that is later transformed to a string, there is a risk of runtime issues. The upshot is that Python programmers must properly test their software.

What kinds of jobs are there in Python?

  1. Python Developer. For someone who knows Python, being a Python developer is the quickest path to employment. One can work by using Python to
  • Create web applications
  • Enhance the data algorithms
  • Analyze and solve data-related issues
  • Adopting measures to safeguard personal and financial information
  • Useful, testable, and efficient code writing
  1. Product manager. Product managers are in charge of discovering new user features, identifying market gaps, and making a case for why specific products should be developed. Many firms are increasingly looking for product managers who are fluent in Python because of the importance of data in their job.
  2. Data analyst. When it comes to sorting through large amounts of data, utilizing Python modules like SciPy and Pandas has proven to be a popular method.
  3. Someone has to teach Python, right? Someone who knows Python may immediately think of teaching computer science, but it is far from the only teaching opportunity open to those with this skill set. Python tutors are in high demand at nearly every institution, coding boot camp, and online coaching platform.

How much do jobs as a Python programmer pay?

Now, let's have a look at How to install Python Environment:

HOW TO INSTALL PYTHON ENVIRONMENT

In windows

Python is installed on Windows in a few simple procedures.

Step 1: Install Python based on your choice of version.

Python 2 and Python 3 are available, each with its syntax and way of doing things.

Here we are going to download python 3 for this course.

Step 2: Download an executable installation file for Python.

Use browser to Navigate to the Download for Windows area of the official Python website.

Choose the version you require and click Download. For example, I go with Python 3.9.1.

When you select download, a list of available executable installers with varied operating system requirements will appear. Select the installer that best suits your system's operating system and download it. Let's say we go with the Windows installer (64 bits).

Step 3: Run the Installer Script

The Python 3.9.1 Windows 64-bit installation was downloaded.

Run the installation program. Make sure both checkboxes at the bottom are selected before clicking Install New.

Now installation process begins when you click the Install Now button.

A few minutes after starting the installation process, you should see the screen below.

Step 4: On Windows, check to see if Python is installed.

To see if Python has been installed successfully on your system. Observe the instructions.

  • Go to the command prompt and type "cmd."
  • Enter 'python' into the prompt.
  • If python is successfully installed on your windows, the version of python that you have installed will be displayed.

In Linux

Step 1: Installing Python requires first downloading and installing the necessary development packages.

A new version of Debian has been released.

Run "apt-get upgrade" in your terminal.

then, "libssl-dev libreadline-dev libffi-dev curl"

Step 2: Download the most recent version.

Python has several versions that are available on their website.

Download the most recent version of Python3 from the official Python website. You will receive a.tar.xz archive file (a "py") containing Python's source code when the download is complete.

Step 3: Unzip the py folder to a convenient location.

To extract the file, either use an extractor program or the Linux tar command.

Step 4: The downloaded script must be configured.

Type cd Python-3.*. /configure in your terminal once you've unzipped the Python package and run it

Step 5: Begin the build procedure

Use this command below if you want to install the new version alongside the old version in case you don`t want to delete it:

$ sudo make install

Step 6: Verify that the installation is working properly.

To test it, type the following command into your terminal:

python3 --version

Python 3 has been successfully installed once the output says Python 3.x.

Conclusion

Congratulations! You've just completed the basics of Python, now you know its strengths and where it falls short, as well as what kinds of employment you may expect to be able to land as a python programmer. Let’s meet in the next chapter as we begin coding.

PWM with STM32

PWM stands for Pulse-Width Modulation. Once the switching frequency (fsw) has been chosen, the ratio between the switch-on time (TON) and the switch-off time (TOFF) is varied. This is commonly called duty-cycle (D). The duty cycle can be between 0 and 1 and is generally expressed as a percentage (%).

D = TON / (TON + TOFF) = TON x fsw

The variation of the pulse width, made at a high frequency (kHz), is perceived as continuous and can be translated into a variation of the rotation speed of a motor, dimming a LED, driving an encoder, driving power conversion, and etc. The use of PWM is also widely used in the automotive sector in electronic control units (ECU - Electronic Control Unit) to manage the energy to be supplied to some actuators, both fixed and variable frequency. Among the various actuators used in a vehicle and controlled by PWM i.e. diesel pressure regulator, EGR valve actuator, voltage regulator in modern alternators, turbocharger variable geometry regulation actuator, electric fans, etc.

Where To Buy?
No.ComponentsDistributorLink To Buy
1STM32 NucleoAmazonBuy Now

PWM signal generation through Timer in STM32

Let's see now how it is possible to generate a PWM with STM32. In this case, it can be generated using a timer made available by the microcontroller.

STM32 configuration with STCube

In this article, we will see how to configure and write an application to dim an LED connected to an output pin (GPIO) of the STM32F446RE Nucleo board. First of all, let's see how to configure the initialization code with the STCube tool.

Basic Configurations

GPIO selection and configuration

It is necessary to identify a GPIO to associate a timer to generate the PWM. For example, we choose PB3 associated with Channel 2 of Timer 2 (TIM2_CH2). Note that the pin turns orange to remind us of that timer 2 still needs to be configured.

System Reset and Clock Control (RCC) Initialization

  • To initialize the RCC use the following path: “Pinout & Configuration”-> System Core -> RCC. “High-Speed Clock” (HSE) and “Low-Speed Clock” (LSE) select for both “Crystal/Ceramic Resonators”.

Timer 2 Configuration

Now you need to configure timer two which is hooked to pin PB3.

Clock Configuration

We configure the clock tree so that the clock frequency (HCLK) of the microcontroller is 84 MHz, handling frequency divisor and multiplier of PLLCLK. The bus to which the timers are connected (APB1 timer and APB2 timer clocks) is also at 84 MHz.

Timer Configuration

We now know that timer 2 has a clock source of 84 MHz, so every time the clock switches the timer does a count. If we configure it to count to 84 million (it is a 32-bit timer, the Counter must be between 0 and 4294967295) it will take a second. We can set this number to exactly half so that the LED lights up for half a second and turns it off for another half-second. In practice, we will see at the output a square wave that will have a duty cycle of 50% and a switching frequency of 1Hz (too slow not to notice the switching on and off the LED !!). To do what has been said, the timer must be configured as follows:

  1. Enable PWM Generation on Channel 2;
  1. Set Prescaler to 0
  2. Set Counter Mode to “Up”;
  3. Set Counter Period to 83999999;
  4. Set Internal Clock Division to “No Division”;
  5. Set auto-reload preload to “Disable”;
  6. Set Master-Slave Mode to “Disable”;
  7. Set Trigger Event Selection to “Reset (UG bit from TIMx_EGR”;
  8. Set Mode to “PWM mode 1”;
  9. Set Pulse to 0;
  10. Set Output compare preload to “Enable”;
  11. Set Fast Mode to “Disable”
  12. Set CH Polarity to “High”.

Now we are ready to lunch the initialization code and write our application.

The initialization code

In “Private variables” we find TIM_HandleTypeDef htim2, it is an instance to C struct that needs to manipulate the DAC peripheral. In “Private function prototypes” the function prototype used to initialize and configure the peripherals:
/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void);/* USER CODE BEGIN PFP */
At the end of main() we find the initialization code of System Clock, Timer 2 and GPIO ( as previously selected in STCube):
void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};   /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 16; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; RCC_OscInitStruct.PLL.PLLQ = 2; RCC_OscInitStruct.PLL.PLLR = 2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } }   /** * @brief TIM2 Initialization Function * @param None * @retval None */ static void MX_TIM2_Init(void) {   /* USER CODE BEGIN TIM2_Init 0 */   /* USER CODE END TIM2_Init 0 */   TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0};   /* USER CODE BEGIN TIM2_Init 1 */   /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 83999999; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */   /* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2);   }   /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) {   /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOB_CLK_ENABLE();   }   /* USER CODE BEGIN 4 */   /* USER CODE END 4 */   /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ }

On/Off LED with STM32

Now we are ready to write our code in main() to on/off LED.
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 41999999); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

As mentioned earlier we have set the timer two to count up to 84 million, so we know that counting 84 million a second has elapsed. Now let's use the PWM function to make sure that for half a second the LED stays on and the other half a second off. In practice, to generate a square wave with a duty cycle of 50% and a frequency of one second.

We use the function “HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2)” to enable timer 2 to start in PWM mode and the macro “__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 41999999)” tells the timer which is the value with which to compare the internal count (in this case 41999999) to decide whether the LED should be off or on.

Now we just must connect a led between pin PB3 and ground through a 220OHm resistor to limit the current (if we want to work with a duty cycle of 100%) and compile our application.

Once this is done, we see that the LED will remain on for 500ms second and off for another 500ms as can be seen from the waveform acquired by the PB3.

Since we have chosen a switching frequency of the PWM that is too low (1Hz), we will only see the LED turn on and off and we do not check its luminosity: we will see in the next paragraph how to increase the switching frequency, adjust the duty cycle in order to increase and decrease the brightness.

Dimming LED using PWM in STM32

First, we declare the following define:

#define D_COUNTER 839

Now, we associate it with the field “htim2.Init.Period” of the structure *htim2:

htim2.Init.Period = D_COUNTER;

In this way, we can quickly the number of counts that the timer must do and therefore manage the frequency and duty cycle of our PWM.

This way our timer will count up to 839 in 10us. Consequently, the switching frequency will be 100kHz (clearly exceeding 1Hz !!). Note that as in the previous example we have subtracted 1 from the count value because the timer starts at zero.

Then, we define an unsigned int variable to set the duty cycle:

unsigned int D; //duty cycle In the main() we write; /* USER CODE BEGIN 2 */ D= 10; //it menas duty cycle of 10% HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (D_COUNTER/100)*D); /* USER CODE END 2 */

Where (D_COUNTER/100)*D needs to re-proportion the value of the duty cycle to the count that the timer must perform.

Compiling we will see that now the LED will always be on but with low brightness, in fact, the duty cycle is only 10% as can be seen from the generated waveform and the rms value of the voltage given to the LED is about 1.1 Volt (as you can see in the bottom corner of the RMS figure for the green trace). Furthermore, the figure confirms that the duty cycle is 10% both intuitively by looking at the green trace and by reading the measurement at the bottom center (Dty+ = 10,48%).

If we set D=70, the LED will be brighter, in fact the RMS value is about 2.82 Volt (as you can see in the bottom corner of the RMS figure for the green trace). Furthermore, the figure confirms that the duty cycle is 70% both intuitively by looking at the green trace and by reading the measurement at the bottom center (Dty+ = 69,54%).

If we set D=100, the led will be illuminated with the maximum brightness imposed by the limitation of the 220 Ohm resistor. The rms value at the ends of the LED with the resistance in series will be 3.3 Volts (the maximum generated by the GPIO)

Now if you write the following code on while(), we will see that the LED will change brightness every 100ms (in practice it increases, every 100ms the duty by 1% starting from 1% until it reaches 100% and then starts all over again)

/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ for(D=1; D<=100; D++){ HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (D_COUNTER/100)*D); HAL_Delay(100); } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */

To do this we include the PWM configuration function ( HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, (D_COUNTER/100)*Duty) in the following loop for(D=1; D<=100; D++) which increases the value of variable D by 1 every 100 ms through the function HAL_Delay(100).

Now we are ready to effectively manage the PWM to control the brightness of a led, but in a similar way, we can control the speed of a DC motor or various actuators.

Using DAC with STM32

A Digital to Analog Converter(DAC) performs the task of converting digital words of n bits into voltages whose amplitude will be proportional to the value of the code expressed by the words themselves. Since the input binary words represent a succession of finite codes, the voltage coming out of a DAC cannot be continuous over time but is made up of as many levels as the converted codes are. This means that the devices to which the analog signal produced by a DAC is sent must filter it with a low-pass characteristic (integrating action). The operating criterion of a DAC is simple: in fact, it is sufficient to have a succession of as many voltages as there are convertible codes, obtained for example by means of a weighted resistance network (i.e. the value proportional to the code implied in the binary word). The conversion consists in sending the voltage corresponding to the code applied to the input to the output of the converter.

One of the simplest and most classic DACs is the R-2R ladder, but today there are more complex objects with optimization in the signal reconstruction. Below is shown a 3bit R-2R ladder DAC.

In practice, the circuit is an inverting adder where the bits (B0, B1, ... Bn) command a switch. The output voltage in the case of the 3-bit DAC is:

Vout= -1/2*B1*Vref - (1/4)*B1*Vref- (1/8)*B1*Vref

If the 3bit string is D and Vref is equal to the logical voltage of 3.3V

Vout= (3.3*D)/2^3

The typical output characteristic is shown in the following figure.

Compared to the weighted resistor DAC, the R-2R scale DAC has the advantage of using only two resistive values. Therefore, it is more easily achievable with integrated circuit technology.

Where To Buy?
No.ComponentsDistributorLink To Buy
1STM32 NucleoAmazonBuy Now

DAC on STM32 platform

Many of the STM32 microcontrollers have on board at least one DAC (generally 12 bit) with the possibility of buffering the output signal (with internal operational amplifier OP-AMP). The use of the DAC finds various applications, for example, it can be used to reconstruct a sampled signal or to generate any waveform (sine wave, square wave, sawtooth, etc.), to generate a reference voltage (for example for a digital comparator).

The DAC peripheral can be controlled in two ways:

  • Manually
  • Using a Data Memory Access (DMA) with a trigger source (can be an internal timer or external source).

DAC in manual mode

In this modality we can drive DAC to on/off a LED, to generate a reference voltage, etc. We will use a NUCLEO STM32L053R8 board to show as configure DAC with STCube. This NUCLEO has available a DAC with only one channel (in general every DAC has one or more channels) with resolution up to 12bit with a maximum bus speed of 32 MHz and a maximum sampling rate of 4 Msps. First, let's see how to initialize the peripherals using STCube Tool:

Configuration of DAC in manual mode

DAC Initialization

  • Select DAC with following path: “Pinout & Configuration”-> Analog -> DAC. Select the Output 1 (OUT1 Configuration):
  • In Configuration->Parameter Setting select Output Buffer= Enable and Trigger = None
  • The GPIO PA4 is associated to DAC Output1. PA4 has been configurated in Analog Mode, No Pull-Up and No Pull-Down.

System Reset and Clock Control (RCC) Initialization

  • Select RCC with following path: “Pinout & Configuration”-> System Core -> RCC. “High Speed Clock” (HSE) and “Low Speed Clock” (LSE) select for both “Crystal/Ceramic Resonator”.

Now we are ready to generate the initialization code.

Diving into the initialization code

At this point, let's look at the generated code:

  • In “Private variables” we find DAC_HandleTypeDef hdac, it is an instance to C struct that need to manipulate the DAC peripheral:
typedef struct { DAC_TypeDef *Instance; /*!< Register base address */   __IO HAL_DAC_StateTypeDef State; /*!< DAC communication state */   HAL_LockTypeDefLock; /*!< DAC locking object */   DMA_HandleTypeDef *DMA_Handle1; /*!< Pointer DMA handler for channel 1 */   #if defined (DAC_CHANNEL2_SUPPORT) DMA_HandleTypeDef *DMA_Handle2; /*!< Pointer DMA handler for channel 2 */ #endif __IO uint32_t ErrorCode; /*!< DAC Error code }DAC_HandleTypeDef;
  • In “Private function prototypes” the function prototype used to initialize and configure the peripherals:
/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DAC_Init(void); /* USER CODE BEGIN PFP */
  • Where we find the initialization select in STCube Tool.

Driving DAC to generate a reference voltage

Now, before writing our application, let's see what functions the HAL library makes available to handle the DAC.

  • HAL_DAC_Start(DAC_HandleTypeDef* hdac, uint32_t Channel): need to enable DAC and start conversion of channel.
  • “hdac” is a pointer to DAC structure
  • “Channel” is the selected DAC channel
  • HAL_DAC_Stop(DAC_HandleTypeDef* hdac, uint32_t Channel): need to disable DAC and start the conversion of the channel.
  • “hdac” is a pointer to DAC structure
  • “Channel” is the selected DAC channel
  • HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data): is used to set in DAC channel register the value passed.
  • “hdac” is pointer to DAC structure
  • “Channel” is the selected DAC channel
  • “Alignment” needs to select the data alignment; we can select three configurations, because the DAC wants the data in three integer formats:
  • “DAC_ALIGN_8B_R” to configure 8bit right data alignment;
  • “DAC_ALIGN_12B_L” to configure 12bit left data alignment;
  • “DAC_ALIGN_12B_R” to configure 12bit left data alignment.
  • “Data” is the data loaded in the DAC register.

The voltage output will be:

Vout,DAC = (Vref*data)/2^nb

where nb is a resolution (in our case 12bit), Vref is voltage reference (in our case 2 Volt) and the passed data.

So, to set DAC output to 1 Volt data must be 2047 (in Hexadecimal 0x7FF) so we call the function this way:

HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0x7FF);

To set the output voltage to 3.3 Volt we call function in this way:

HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0xFFF);

 

To verify that change the value in our main we write the following code and then we check the output connecting it to the oscilloscope probe.

int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DAC_Init(); while (1) { /* USER CODE END WHILE */ HAL_DAC_Start(&hdac, DAC_CHANNEL_1); HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0x7FF); HAL_Delay(1000); HAL_DAC_Stop(&hdac, DAC_CHANNEL_1); HAL_Delay(1000); HAL_DAC_Start(&hdac, DAC_CHANNEL_1); HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0x7FF); HAL_Delay(1000); HAL_DAC_Stop(&hdac, DAC_CHANNEL_1); HAL_Delay(1000); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

We expect the output voltage to change every second by repeating the following sequence: 1V - 0V - 2V – floating (as shown in the figure below)

The signal displayed on the oscilloscope checks the sequence we expected. In the first second the output voltage from the DAC is 1V then in the next second 0V then 2V and in the last second of the sequence, the output is floating.

Using DAC in Data Memory Access (DMA) mode with a Timer

In this modality we can drive DAC to on/off a LED, to generate a reference voltage, etc. We will use a NUCLEO STM32L053R8 board to show as configure DAC with STCube. This NUCLEO has available a DAC with only one channel (in general every DAC has one or more channels) with resolution up to 12bit with a maximum bus speed of 32 MHz and a maximum sampling rate of 4 Msps. First, let's see how to initialize the peripherals using STCube Tool:

Configuration DAC in DMA mode

  • DAC Configuration
  • Select DAC with following path: “Pinout & Configuration”-> Analog -> DAC. Select the Output 1 (OUT1 Configuration):
  • In “Parameter Settings” the Output Buffer is enabled, Timer 6 is selected as Trigger Out Event and Wave generation mode is disabled.
  • Activate DMA to handle DAC using channel 2. The direction is Memory to Peripheral. The buffer mode is “circular”, and the data length is a word.
  • Set interrupt related channel 2 of DMA

TIM 6 Configuration

  • We use TIM6 because is one of two timers used by uP to trigger the DAC output. At the moment we do not change the initial configuration, later we will see what we need.
  • TIM6 -> NVIC Setting: flag “TIM6 interrupt and DAC1/DAC2 underrun error interrupts” to activate interrupts.

Now we are ready to generate the initialization code. Before we need to learn as the waveform can be generated using DAC.

Sinewave generation

Let's see mathematically how to reconstruct a sinewave starting from a given number of samples. The greater the number of samples, the more "faithful" the reconstructed signal will be. So, the sampling step is 2pi / ns where ns is the number of samples in this way, we have to save our samples in a vector of length ns. The values ??of every single element of the vector will be given by the following equation:

S[i] = (sin(i*(2p/ns))+1)

We know that the sinusoidal signal varies between 1 and -1 so it is necessary to shift it upwards to have a positive sinewave (therefore not with a null average value) therefore it must be moved to the middle of the reference voltage. To do this, it is necessary to retouch the previous equation with the following:

S[i] = (sin(i*(2p/ns))+1)*((0xFFF+1)/2)

Where 0xFFF is the maximum digital value of DAC (12bit) when the data format is 12 bits right aligned.

To set the frequency of the signal to be generated, it is necessary to handle the frequency of the timer trigger output (freq.TimerTRGO, in our case we use the TIM6) and the number of samples.

Fsinewave = freq.TimerTRGO/ns

In our case, we define Max_Sample = 1000 ( is uint32_t variable) and let's redefine some values of the timer 6 initialization.

static void MX_TIM6_Init(void) { /* USER CODE BEGIN TIM6_Init 0 */ /* USER CODE END TIM6_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6; htim6.Init.Prescaler = 1; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 100; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM6_Init 2 */ /* USER CODE END TIM6_Init 2 */ }

We have changed the following parameters:

htim6.Init.Prescaler = 1; htim6.Init.Period = 100;

So with 1000 samples, the output sinewave will be a frequency of 10 Hz. We can change the number of samples (being careful not to use too few samples) or the “Init.Prescaler” and “Init.Period” values of timer 6.

Driving DAC in DMA mode with Timer

Using the DAC in DMA mode the HAL library makes available to handle the DAC another function to set the DAC output.

HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment)

Compared to the manual function we find two more parameters:

  • uint32_t* pData is the peripheral buffer address;
  • uint32_t Length is the length of data to be transferred from the memory to DAC peripheral.

As you can see from the following code we first need to include the "math.h" library, define the value of pigreco (pi 3.14155926), and write a function to save the sampled sinewave values in a array (we wrote a function declared as get_sineval () ).

#include "math.h" #define pi 3.14155926 DAC_HandleTypeDef hdac; DMA_HandleTypeDef hdma_dac_ch1; TIM_HandleTypeDef htim6; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_DAC_Init(void); static void MX_TIM6_Init(void); uint32_t MAX_SAMPLES =1000; uint32_t sine_val[1000]; void get_sineval() { for (int i =0; i< MAX_SAMPLES; i++) { sine_val[i] = ((sin(i*2*pi/MAX_SAMPLES)+1))*4096/2; } } /* USER CODE END 0 */
  • Once this is done, we can start the DAC by saving the sampled values of the sinewave in the buffer (* pdata) as shown below:
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); MX_TIM6_Init(); /* USER CODE BEGIN 2 */ get_sineval(); HAL_TIM_Base_Start(&htim6); HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_val, MAX_SAMPLES, DAC_ALIGN_12B_R); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

Now we just have to show the acquisition that the oscilloscope:

If we change the number of MAX_SAMPLE to 100 the sinewave will be a frequency of 100 Hz, but as can be seen from the acquisition, the number of samples, in this case, is a bit low.

We can optimize the waveform by acting on timer 6 in order to increase the number of samples. For example by modifying htim6.Init.Period = 400

So, that was all for today. I hope you have enjoyed today's lecture. Let me know if you have any questions. Thanks for reading. Take care !!! :)

How to use ADC with STM32?

An Analog to Digital Converter (ADC) converts a continuous signal (usually a voltage) into a series of discrete values ??(sequences of bits). The main features are:

  • Resolution (in analog terms): It is the minimum variation of the analog input voltage that can determine the variation of the LSB, that is of the least significant bit of the output code. Since the quantization step Q corresponds to the LSB, it can be said that the resolution coincides with the quantization step Q (and therefore is measured in Volts). We can say that the quantization step Q corresponds to the LSB because two contiguous quantization bands, each of amplitude Q, are identified by codes that differ only for the least significant bit.
  • Resolution (in digital terms): It is the number n of bits present at the converter output, that is the number of bits with which the converter encodes a sample of the analog input signal. As the number of bits of the converter increases, the number of quantization bands increases and (with the same full-scale value VFS) their amplitude decreases, an amplitude which is nothing more than the step Quantization Q. If the quantization step narrows, the smaller the voltage variation necessary to determine the variation of the LSB, i.e., of the least significant bit of the code, becomes the exit. So, saying that a converter has many bits is equivalent to saying that the voltage variation necessary to make the LSB vary is small. The image below shows the 3 bits ADC input-output characteristics.
  • Full-scale voltage: It is the range, that is the maximum excursion, of the input voltage. Typical dynamic values are between 10 Vpp ( pp peak to peak) and 20 Vpp, unipolar or bipolar.
  • Types of response: in general, ADCs have a response of a linear theoretical type of response, but there are also types with a logarithmic response.
  • Accuracy: indicates the goodness of the conversion depends on it. The error made by the ADC is usually measured. This error consists of two components: a quantization error and a non-linearity error.
  • Sampling frequency: A sampling is an operation with which the input signal is discretized over time, transforming it into a succession of values, samples in fact, which will subsequently be digitized. The simplest way to extract values is to use a switch, in series with the signal, which closes and opens at defined and equidistant intervals. The smaller this interval, called the sampling step (Ts), the more faithful the reconstruction of the signal will be starting from its samples. Likewise, too small a sampling step leads to a waste of resources (measurement time, memory for data storage). A sampling of the signal generally indicates not only its discretization over time but also its maintenance until the next closing of the circuit-breaker. These two phases are realized by special circuits called Sample & Hold (S / H).

There are different types of ADCs, the most common are listed below (illustrating their operation is not the purpose of this article):

  • A direct conversion ADC (Flash ADC)
  • A Successive Approximation Register (SAR) ADC
  • One dual ramp ADC (Dual Slope or integration)
  • A pipeline ADC
  • A tracking ADC (delta-coded)

Generally, STM32 microcontrollers have at least one ADC (a SAR ADC) with the following characteristics:

  • Resolution: ADCs have a resolution of up to 12 bits with a maximum conversion frequency of 2.5 MHz, with 18 multiplexed channels among which 16 can be available for measurements of external signals, the other two are for internal measurements (temperature and voltage).
  • Conversion Time and Conversion Groups: The conversion time can be individually programmed for each channel. There are 8 discrete times conversions for each ADCCLK clock frequency (Fc), these times range from 1.5 to 239.5 cycles.

Fc = ADCCLK / (12.5 + Number of cycles)

Each ADC has two conversion modes: “regular” and “injected”.

  • The "regular" mode allows you to specify a channel or a group of channels to be converted in turn one after the other. The conversion core can consist of more than 16 channels, and the order in which the channels must be converted can also be programmed. The conversion can be initiated by software or by a hardware event consisting of a series of timer signals or by line 1 of the EXTI. Once the conversion has started, you can carry out continuous conversions, or you can operate discontinuously by converting a selected number of channels and then stopping the conversion pending the triggering of the next core. At the end of a conversion the result is stored in a single register (result register) and an interrupt can be generated. The ADC1 has a dedicated DMA channel that can be used for transferring the converted value from the result register to a memory buffer. Through this method, an entire conversion cycle can be copied into memory, eventually obtaining a single interrupt generated by the DMA. To further speed up the conversion, a double-sized buffer can be used to generate two interrupts: one when the first half has been filled (first conversion cycle) and the other when the second half is filled (second conversion cycle). This mode can be combined with the "DMA circular buffer mode" to handle multiple conversions with hardware.
  • The second conversion mode is called the “injected group”. It is able to carry out the conversion sequence up to a maximum of four channels, which can be triggered by a software or hardware event. Once triggered, it will stop the conversion of the regular group, carry out its sequence of conversion and then will allow the regular group to continue the conversion. A conversion sequence can be configured in this mode. Unlike the regular group, in this mode, each result has its own register (result register) and its own offset register. This last register can be programmed with a 16-bit value automatically deducted from the ADC result.

Furthermore, the "Dual Conversion Modes" can be active:

In the STM32 with almost two ADCs and it is, therefore, possible to perform different conversion modes: in these types of conversion the ADC2 acts as a slave while the ADC1 acts as a master allowing 8 different types of conversion.

  • Injected Simultaneous Mode and Regular Simultaneous Modes: These two modes synchronize the regular and injected group conversion operations on two converters. This is very useful when two quantities (current and voltage) have to be converted simultaneously.
  • Combined Regular / Injected Simultaneous Mode: This mode is a combination of both the regular and injected modes and allows us to have a synchronized conversion sequence.

We are now ready to write a first simple example using the ADC peripheral. The goal is to measure the voltage in a voltage divider composed of a fixed value resistor and a potentiometer (so that by moving the potentiometer cursor, the voltage to be read varies) we begin by configuring our peripheral with STCube Tool. For this project, we will use the NUCLEO STM32L053R8. This board has only one ADC with 16 channels and a resolution of up to 12bit.

Now we’ll see the configuration step by step:

Where To Buy?
No.ComponentsDistributorLink To Buy
1STM32 NucleoAmazonBuy Now

ADC channel selection

We have to flag IN0 to activate Channel 0, then we can configure the peripheral. Channel 0 is on GPIO PA0 as we can see in the picture below:

ADC setting

We select the ADC_prescaler equal to 4, resolution to 12bit (maximum of a resolution, we can choice between 6, 8, 10 and 12 bits), “right data alignment” (we can choose between right and left alignment), and “forward” as scan direction (we can choose between forward and backward).

For this first example we’ll hold disabled Continuous, Discontinuous conversion and DMA mode. Furthermore, the ADC sets, at the end of single conversion, the EoC (End of Conversion) flag.

 

ADC Regular conversion mode

We select 12.5 Cycles as sampling time (in this way the sampling frequency is 320 kHz obtained from the formula described above), the start of conversion is triggered by software. Furthermore, for this application the watchdog is disabled.

After the generation of the initialization code with STCube, we can find in our project the ADC configuration. As for every peripheral, the HAL library defines the dedicated C structure, for the ADC defines “ADC_HandleTypeDef”.

 

In our case the “ADC1” is the instance that points to our ADC. The structure “ADC_InitTypeDef” is used to handle the configuration parameters. In our example is generated as follow:

static void MX_ADC_Init(void) { /* USER CODE BEGIN ADC_Init 0 */ /* USER CODE END ADC_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC_Init 1 */ /* USER CODE END ADC_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc.Instance = ADC1; hadc.Init.OversamplingMode = DISABLE; hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerFrequencyMode = ENABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; if (HAL_ADC_Init(&hadc) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel to be converted. */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC_Init 2 */ /* USER CODE END ADC_Init 2 */ }
The function HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) needs to initialize the peripheral and define the clock and the GPIO ( in our case PA0).
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(hadc->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspInit 0 */ /* USER CODE END ADC1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_ADC1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**ADC GPIO Configuration PA0 ------> ADC_IN0 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN ADC1_MspInit 1 */ /* USER CODE END ADC1_MspInit 1 */ } } /** * @brief ADC MSP De-Initialization * This function freeze the hardware resources used in this example * @param hadc: ADC handle pointer * @retval None */
The function HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) needs to de-initialize the peripheral.
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) { if(hadc->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspDeInit 0 */ /* USER CODE END ADC1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_ADC1_CLK_DISABLE(); /**ADC GPIO Configuration PA0 ------> ADC_IN0 */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0); /* USER CODE BEGIN ADC1_MspDeInit 1 */ /* USER CODE END ADC1_MspDeInit 1 */ } }

Before describing the code let's see how to make the connections on the development board.

We need a 10kOhm potentiometer and a 2kOhm resistor. The potentiometer is connected between 3.3V and 2kOhm resistor, the common point is connected to PA0, and finally, the other end of the 2k Ohm resistor is connected to the ground pin.

Acting on the potentiometer we will see the read voltage vary from 3.3 Volt to about 0 Volt.

Now let's dive into the code: In the Includes section we add the header file of main.
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */

In “Private variables” section we find “ADC_HandleTypeDef hadc” as previous said is an instance to C structure to handle the ADC peripheral. Then, we add three variables:

  • Resolution defines the number of steps used by ADC (12bit = 2^12 -1= 4095) is a constant integer;
  • vs defines the maximum voltage to read, is a constant float;
  • volt is the variable where the voltage value read by the ADC is store ( is a float variable)
/* Private variables -----------------------*/ ADC_HandleTypeDef hadc; /* USER CODE BEGIN PV */ const int Resolution = 4095; const float Vs =3.300; float volt; /* USER CODE END PV */

Then, we can find the protype of function to handle the peripherals and resources initialized (system timer, GPIO, and ADC).

/* Private function prototypes -----------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */

Finally, the main starts.

In the first part we call functions to initialize the peripherals and resources used:

int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ADC_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */

In the second part, that is, inside an infinite loop (while (1)) there is the function to start the conversion of the ADC, read the data and save it in the variable volt and finally stop the conversion wait for a second and start with the conversion and so on.

while (1) { /* USER CODE END WHILE */ HAL_ADC_Start(&hadc); if(HAL_ADC_PollForConversion(&hadc,10)==HAL_OK) { volt=HAL_ADC_GetValue(&hadc)*Vs/Resolution; } HAL_Delay(1000); HAL_ADC_Stop(&hadc); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

Now, once our code has been compiled, we can debug it in real-time, just press the "spider" icon (see figure below) and see how the volt variable varies by acting on the potentiometer.

Once we have clicked on the debug button, at the top right, we can select the "live expression" window and add (by writing the name in the table) the variable to be monitored.

Now we can start the debug by clicking on the “Resume” button (on the top right) or by pressing the F8 key (on our keyboard).

We are now ready to read our voltage value. We will see that by acting on the potentiometer we will read the voltages in the whole range considered.

Some measures are shown below:

  1. First reading volt=1.3188 Volt
 
  1. First reading volt=3.29919 Volt
  1. First reading volt=1.02158 Volt
So, that was all about How to handle ADC in STM32 Microcontrollers. In the next tutorial, we are going to work on STM32 DAC operations. Till then take care !!!

STM32 SPI Communication

The SPI (Serial Peripheral Interface) protocol, or rather the SPI interface, was originally devised by Motorola (now Freescale) to support their microprocessors and microcontrollers. Unlike the I2C standard designed by Philips, the SPI interface has never been standardized; nevertheless, it has become a de-facto standard. National Semiconductor has developed a variant of the SPI under the name Microwire bus. The lack of official rules has led to the addition of many features and options that must be appropriately selected and set in order to allow proper communication between the various interconnected devices. The SPI interface describes a single Master single Slave communication and is of the synchronous and full-duplex type. The clock is transmitted with a dedicated line (not necessarily synchronous transmission that has a dedicated line for the clock) and it is possible to both transmit and receive data simultaneously. The figure below shows a basic connection diagram between two peripherals that make use of the SPI interface.

From the figure, it is immediately possible to notice what has just been said, namely that the communication generally takes place between a Master and a Slave. The interface presents 4 connection lines (excluding the ground however necessary), for which the standard SPI is also known as 4 Wire Interface. The Master starts the communication and provides the clock to the Slave. The nomenclature of the various lines in the SPI interface is normally as follows:

  • MOSI: Master Output Slave In. Through this line the master sends the data to the selected slave;
  • MISO: Master Input Slave Output. Through this line the slave sends the data to the master;
  • SCLK: Serial Clock is generated by the master device, so it is the master starts the communication and the clock synchronizes the data transfer over the bus. The SPI clock speed is usually several MHz (today up to 100 MHz);
  • SS: Slave Select or CS (Chip Select) generated by the master to choose which slave device it wants to communicate with (it must be set to a low logic level). SS (or CS) is not indispensable in all applications.

In addition to this standard nomenclature, there are other acronyms.

For example:
  • The MOSI line is also called: SDO (Serial Data Out), DO (Data Out), DOUT and SO (Serial Out)
  • The MISO line is also called: SDI (Serial Data In), DI (Data In), DIN and SI (Serial In)
  • The Clock line is also called: CLK, SCK (Serial Clock).
  • The Enable line is also called: CS (Chip Select), CE (Chip Enable)

The first advantage in SPI communication is faster communication, instead, the first disadvantage is the presence of the SS pin necessary to select the slave. It limits the number of slave devices to be connected and considerably increases the number of lines of the master dedicated to SPI communication as the connected slaves increase.

To overcome these problems, the devices in the daisy chain can be connected (output of a device connected to the input of the next device in the chain) as shown in the figure below where a single slave selection line is used.

The disadvantages, however, are the lower updating speed of the individual slaves and signal interruption due to the failure of an element.

We can use this communication to put in communication our micro-controller with different peripherals as Analog-Digital Converters (ADCs), Digital-Analog Converters (DACs), EEPROM memories, sensors, LCD screen, RF module, Real Time Clock, etc.

The STM32 micro-controllers provide up to 6 SPI interfaces based on the type of package that can be quickly configured with STCube Tool.

STCube Tool initializes the peripherals with HAL (Hardware Abstraction Layer) library. The HAL library creates for SPI (as all peripherals) an C structure:

  • struct SPI_HandleTypeDef
It is so defined: Where the main parameters are:
  • Instance: is the pointer variable it describes the SPI that we want to use. If we use SPI1, the name of the instance is SPI1.
  • Init: is an instance that points to the structure ( SPI_InitTypeDef) used to initialize the device. We will discuss the structure SPI_InitTypeDef shortly.
  • pTxBuffPtr, pRxBuffPtr: are pointer variables that point to an internal buffer. They are used to store the data during the communication when the programmer handles the SPI in interrupt mode (we will see forward)
  • hdmatx, hdmarx: are the pointer variable to instances of the DMA_HandleTypeDef struct. They are used when the programmer handles the SPI in DMA mode (will see forward).

As just said to initialize the SPI peripheral to be used, it is necessary to use the struct SPI_InitTypeDef. It is defined as follow:

When we use the STcubeMX to initialize the SPI peripheral we are modifying this structure

In details:
  • Mode specifies the SPI operating mode, and Direction specifies the SPI bidirectional mode state. It is very easy to configure in STCubeMx. If we want to configure the SPI1. We can find SPI windows in Pinout&Configuration -> Connectivity. Here we can select between the SPI available. Now is possible to select the communication mode (Master, Slave, half-duplex, full-duplex, etc.) as follow:

If the slave supports, the full-duplex communication can be enabled.

  • DataSize indicates the SPI data size. The user can select 8bit or 16bit.
  • CLKPolarity defines if the serial clock steady state is LOW or HIGH.
  • CLKPhase defines if the bit capture (trigger) takes place when the clock is on the falling edge or rising edge.
  • NSS: if selected "Output Hardware" the slave select signal is managed by hardware otherwise is managed by software using the SSI bit.
  • BaudRatePrescaler can be select the Baud Rate prescaler value.
  • FirstBit indicates if data transfers start from Most Significant Bit (MSB) or Last Significant Bit (LSB).
  • TIMode specifies if the TI mode is enabled or not.
  • CRCCalculation: to enable to activate the CRC calculation.
  • CRCLength: to define the length of CRC data.
  • CRCPolynomial specifies the polynomial (X0+X1+X2) used for the CRC calculation. This parameter is an odd number 1 and 65535.

By enabling the SPI and the chip select pin, the pins available on the microcontroller are automatically chosen to manage this interface (but they can be changed by looking for the alternative functions of the different pins of the microcontroller). For example, in our case the following pins are selected:

  • PA4 SP1_NSS
  • PA5 SP1_SCK
  • PA6 SP1_MISO
  • PA7 SP1_MOSI

Now you can generate the initialization code. Before being able to write the first code to manage this communication interface, it is necessary to understand the functions that the libraries provide and the different communication modes.

As for other communication interfaces, the HAL library provides three modes to communicate: polling mode, interrupt mode, and DMA mode.

Where To Buy?
No.ComponentsDistributorLink To Buy
1STM32 NucleoAmazonBuy Now

STM32 SPI Communication in Polling Mode

Using the SPI in Polling Mode is the easiest way, but it is the least efficient way as the CPU will remain in a waiting state for a long time. HAL library provides the following functions to transmit and receive in polling mode:

  • HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Master receives data packets in blocking mode (polling mode).

The parameters are:

  • hspi is a pointer to a “SPI_HandleTypeDef” structure. “SPI_HandleTypeDef” structure includes the configuration information for SPI module.
  • pData is a pointer to data buffer
  • Size is the amount of data to be sent
  • Timeout is the timeout duration
  • HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Master transmits data packets in blocking mode (polling mode).

If the slave device supports, the full-duplex mode:

  • HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

Master transmits and receives data packets in blocking mode (polling mode).

The parameters are:

  • hspi is a pointer to a “SPI_HandleTypeDef” structure. “SPI_HandleTypeDef” structure includes the configuration information for SPI module
  • pTxData is a pointer to transmission data buffer
  • PRxData is a pointer to reception data buffer
  • Size is the amount of data to be sent
  • Timeout is the timeout duration

STM32 SPI Protocol in Interrupt Mode

Using the SPI in Interrupt Mode, also called non-blocking mode. In this way, the communication can be made more effective by enabling the interrupts of the SPI in order to receive, for example, signals when the data has been sent or received. This improves CPU time management. In applications where all the management must be deterministic and it is not known when an interrupt can arrive, these can potentially manage the time management of the CPU, especially when working with very fast buses such as SPI. We can enable the SPI interrupts directly during the initialization with STCube Mx.

HAL library provides the following functions to transmit and receive in interrupt mode:

  • HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
Master receives data packets in non-blocking mode (interrupt mode). The parameters are:
  • hspi is a pointer to a “SPI_HandleTypeDef” structure. “SPI_HandleTypeDef” structure includes the configuration information for SPI module
  • pData is a pointer to data buffer
  • Size is the amount of data to be sent
To handle the interrupt needs to write our code in the callback:
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef * hspi) { // Message received .. Do Something ... }
  • HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

Master transmits data packets in blocking mode (interrupt mode).

To handle the interrupt needs to write our code in the callback:

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef * hspi) { // Message transmitted.... Do Something ... }

If the slave device supports, the full-duplex mode:

  • HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)

Master transmits and receives data packets in non-blocking mode (interrupt mode).

To handle the interrupt needs to write our code in the callback:

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef * hspi) { // Message transmitted or received.. .. Do Something ... }

STM32 SPI Communication in DMA Mode

Using the SPI in DMA Mode the SPI bus can be used at its maximum speed, in fact, since the SPI must store the received and transmitted data in the buffer to avoid overloading it is necessary to implement the DMA. In addition, use by DMA mode frees the CPU from performing "device-to-memory" data transfers. We can easily configure the DMA during the initialization using STCubeMx :

In this case, the DMA is enabled in normal (we can use it in circular mode) mode both in transmission and reception

HAL library provides the following functions to transmit and receive in DMA mode:

  • HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

Master receives data packets in non-blocking mode (DMA mode).

The SPI device receives all bytes of data in the buffer one by one until the end in DMA mode. At this point, the callback function will be called and executed where something can be done.

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef * hspi) { // Message received .. Do Something ... }
  • HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

Master transmits data packets in non-blocking mode (DMA mode).

The SPI device sends all bytes of data in the buffer one by one until the end in DMA mode. At this point, the callback function will be called and executed where something can be done.

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef * hspi) { // Message transmitted….. Do Something ... }

If the slave device supports, the full-duplex mode:

  • HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,)

Master transmits and receives data packets in non-blocking mode (DMA mode).

The SPI device sends or receives all bytes of data in the buffer one by one until the end in DMA mode. At this point, the callback function will be called and executed where something can be done.

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef * hspi) { // Message transmitted or received.... Do Something ... }

We are now ready to handle an SPI communication with STM32.

Write and Read an I2C EEPROM with STM32

EEPROMs (Electrically Erasable Programmable Read-Only Memories) allow the non-volatile storage of application data or the storage of small amounts of data in the event of a power failure. Using external memories that allow you to add storage capacity for all those applications that require data recording. We can choose many types of memories depending on the type of interface and their capacity.

EEPROMs are generally classified and identified based on the type of serial bus they use. The first two digits of the code identify the serial bus used:

  • Parallel: 28 (for example 28C512) much used in the past but now too large due to having many dedicated pins for parallel transmission
  • Serial I2C: 24 (for example 24LC256)
  • Serial SPI: 25 (for example 25AA080A)
  • Serial - Microwire: 93 (for example 93C56C-E/SN)
  • Serial – UN I/O: 11 (for example 11LC040-I/SN)

Now we will see how to write or read data on an I2C EEPROM like 24C256C. This serial EEPROM is organized as 32,768 words of 8 bits each. The device’s cascading feature allows up to eight devices to share a common 2-wire bus. It is available in various 8-pin packages

The device can be used in applications consuming low power. The device is available in all standard 8-pin packages. The operating voltage is comprised of between 1.7V and 5.5V.

  • Serial Clock (SCL) is an input pin used to control data flow. On the positive-edge clock, the data is inserted into the EEPROM device, while on the negative edge clock, the data is processed out of the EEPROM module.
  • Serial Data (SDA) is a bidirectional input-output for serial data transfer. It is an open-drain pin.
  • Device Addresses (A2, A1, A0) are input pins to set the device address. These pins allow you to customize the address of the device within the I2C bus. They must connect directly to GND or to VCC (hard wired). If these pins are left floating, the A2, A1, and A0 pins will be internally pulled down to GND. When using a pull-up resistor, it recommends using 10kOhm or less.
  • Write Protect (WP) is an input pin. We can perform normal writing operations, by connecting it to GND; When connected directly to VCC, all write operations to the memory are restricted. If this pin is left open/floating, it will be pulled down to the GND(internally). When using a pull-up resistor, it recommends using 10kOhm or less.
  • Device Power Supply (VCC)
  • Ground (GND)

In our example, we connect A0, A1, A2 directly to VCC in this way the device address is 1010111 (in general A0, A1, A2 identify the last three significant bits of the device address 1 0 1 0 A2 A1 A0) is 0x57 in Hexadecimal. The 4 most significant bits are preset (Control Code), the A0, A1, A2 are Chip Select Bits.

Now we start with our project using STNucleoL053R8 and STCube to generate the initialization code. Below is shown the connection

  • A0, A1, A2 are connected directly to VCC in this way the device address is 1010111 (in general A0, A1, A2 identify the last three significant bits of the device address 1 0 1 0 A2 A1 A0) is 0x57 in Hexadecimal.
  • WP is connected to the ground to allow the normal write operation
  • SCL and SDA are connected to PA8 and PA9 respectively of STM32L053R8

So, we configure the I2C1 using STCube and leave all configuration as it is and we will operate in polling mode.

In GPIO setting select PA9 (SDA) and PA8 (SCL).

Now we create a new STM32CubeMX project with the following steps:
  • Select File > New project from the main menu bar. This opens the New Project window.
  • Go to the Board selector tab and filter on STM32L0 Series.
  • Select NUCLEO-L053R8 and click OK to load the board within the STM32CubeMX user interface
      Then the tool will open the pinout view.
  • Select Debug Serial Wire under SYS, for do it click on System Core (on the topo right) and then select SYS and finally flag on “Debug Serial Wire”.
 
  • Select Internal Clock as clock source under TIM2 peripheral. To do this click on Timers and then select TIM2. Now go to clock source and select through the drop-down menu “internal clock”.
  • Select and enable in “Connectivity” the I2C1 and left all configuration as it is and we will operate in polling mode.
  • Configure in GPIO setting PA9 (SDA) and PA8 (SCL) to manage the I2C communication.
  • Check that the signals are properly assigned on pins:
    • SYS_SWDIO on PA13
    • TCK on PA14
    • SDA I2C1on PA9
    • SCL I2C1on PA8
  • Go to the Clock Configuration tab and no change the configuration in order to use the MSI as input clock and an HCLK of 2.097 MHz.
  • Select Timers -> TIM2 and change the Prescaler to 16000 and the Counter Period to 1000.
  • In the Project Manager tab, configure the code to be generated and click OK to generate the code.

Our project has been initialized by STCubeMX. In the /Core/Src/main.c we will find our main where we will write the main body of our program.

Now let’s see what the code generator did:

First of all, we find the “Include” section we can add the library needed.

 
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h"
In our case we can add also “stm32l0xx_hal.h” library to be able to use HAL library (I2C HAL library included)
#include "stm32l0xx_hal.h " #include "Var.h " #include "Funct.h "
In “Private variables” has been defined two privates variable htim2 and hi2c1;
  • - htim2 as first parameter an instance of the C struct TIM_HandleTypeDef;
  • - hi2c1 as first parameter an instance of the C struct UART_HandleTypeDef.
/* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim2; UART_HandleTypeDef hi2c1; unsigned short int address; // eeprom address unsigned char EEP_pag = 0x00 // EEPROM page unsigned char EEP_pos = 0x00 // EEPROM position unsigned char rdata = 0x00 // to store the data read from EEPROM
In “Private function prototypes” we find the protype of function to initialize the System Clock, GPIO, timer and peripheral:
/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); static void MX_I2C1_Init(void);

This function has been generated automatically by STCubeMx with the parameter selected.

The main contains the initialization of the peripherals and variables, before the while loop the code call the function Write_EEPROM() and Read_EEPROM() to write and read a data in a specific address of the EEPROM. these functions were written in EEPROM.c, a C file added to our project in the src folder.

  int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); MX_I2C1_Init();   /* USER CODE BEGIN 2 */ address = 0x00 << 8 | 0x00 // eeprom page 0 , position 0 // Now we want to store 10 in page 0x00 and position 0x00 of EEPROM Write_EEPROM(address, 10, 0) // Now we want store in rdata variable the content of cell memory 0x0000 rdata = Read_EEPROM(address, 0)   /* USER CODE END 2 */   /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
Furthermore, we have added two header files and one c file:
  • Var.h contains the declaration of global variables:
/** Var.h * Created on: 27 ott 2021 * Author: utente */ #ifndef INC_VAR_H_ #define INC_VAR_H_ extern unsigned char buf[20]; extern int i; #endif /* INC_VAR_H_ */
  • Funct.h contains the prototype of the user function
/** Funct.h * Created on: 28 ott 2021 * Author: utente */ #ifndef INC_FUNCT_H_ #define INC_FUNCT_H_ extern unsigned char Read_EEPROM(unsigned int, unsigned char); extern void Write_EEPROM(unsigned int, unsigned char, unsigned char); #endif /* INC_FUNCT_H_ */
  • EEPROM.c contains the function written by the user to handle the writing and reading operation with EEPROM:
  • unsigned char Read_EEPROM(addr, device) reads from cell memory address (addr)and store the content in dato.
  • void Write_EEPROM(addr, dato, device) writes data (dato) to memory address (addr).
/** Serial.c * Created on: Oct 29, 2021 * Author: utente */ #include "stm32l0xx.h" // Device header #include "stm32l0xx_hal_conf.h" #include "stm32l0xx_hal.h " #include "Var.h " #include "Funct.h " extern I2C_HandleTypeDef hi2c1; unsigned char Read_EEPROM(unsigned int addr, unsigned char device) { unsigned char page; uint8_t dato; page=0xAF; // due to chip select bits setting HAL_I2C_Mem_Read(&hi2c1,page, addr, I2C_MEMADD_SIZE_16BIT, &dato,1,5); return dato; } void Write_EEPROM(unsigned int addr, unsigned char dato, unsigned char device) { unsigned char page; page=0xAF; //due to chip select bits setting HAL_I2C_Mem_Write(&hi2c1,page, addr, I2C_MEMADD_SIZE_16BIT, &dato,1,5 ); while(HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 1, HAL_MAX_DELAY) != HAL_OK); HAL_Delay(10); }
Now we are ready to compile and run the project:
  1. Compile the project within IDE.
  1. Download it to the board.
  2. Run the program.
So, that was all for today. I hope you have enjoyed today's lecture. In the next tutorial, we will have a look at How to perform SPI Communication with STM32. Till then take care and have fun !!! :)

Databases and CRUD operations in C#

Are you here to learn about Databases and CRUD operations in the C# programming language? If so, then you will be an expert in no time. Learning Databases and CRUD operations in C# is not a piece of cake. But, if you know all the terms and steps of CRUD operations and databases in C#, it will not be rocket science for you. This article contains all the information you should know regarding databases and CRUD operations. So, keep reading till the end!

C# Programming Language: An Overview 

We know that you are already aware of the C# programming language. So, here is a quick overview of the C# programming language before we move to the actual topic:

C#, also known as C-Sharp, is an object-intended coding language that operates on the .NET Platform and is developed by Microsoft. ISO and ECMA have certified the C# programming language. C# is a broad programming language that can help accomplish hundreds of activities and purposes in different fields. It resembles Java, C++, and other programming languages but, it is truly one of a kind. The best thing is that it is object-oriented and is easy to use. It has an infinite list of advantages.

Some of the advantages of the C# are listed below:

  • C# programming language offers automated garbage pickup.
  • In C# programs, classes may be specified within domains.
  • No obligation to add the “.h” extension within header folders.
  • Because non-Boolean values are not utilized as conditionals, the scripts are less vulnerable to errors.
  • Multithreading is genuinely uncomplicated in C# as compared to other programming languages like C++ or Java.
  • All parameters in the C# are immediately set to their standard settings before being utilized.
  • C# offers reflection skills, which means it can look at and change its composition at execution.
  • With the help of the C# programming languages, many apps and programs have been built like KeePass, Banshee, Paint.NET, FlashDevelop, and many others. In fact, the application where I am writing this article is also an application of the C# programming language (Microsoft Word).

All the above advantages make the C# programming language stand out in other languages. It is undoubtedly the most contemporary and exceptional language out there!

What is a Database In C#?

Before we begin learning about CRUD operations in a database within the C# programming language, it is crucial to know what a Database is.

A database is basically a coordinated set of formatted data kept digitally within a computer network. A database administration tool is generally in charge of a dataset. The DBMS, the dataset, and the programs that interact with these are collectively called a database platform. Every database operation can access a single relational database. It is generated as an inclusion within the data catalog by the data proprietor (usually a database manager with authority for that collection), who gives it a title and a specification. Several databases utilize structured query language (SQL) when generating and accessing data.

What is CRUD?

Here is the most awaited section of the entire article: CRUD operations. Please grab a notebook to note every detail for your better understanding. And if you do not wish to write these, you can always read our article from the website. Let us begin:

The abbreviation CRUD refers to Create, Read, Update, and Delete in software coding. Permanent memory has these four primary functions. Additionally, every letter of the abbreviation may relate to every functionality within a relational network program that is linked to a standard HTTP service, SQL declaration, or DDS action.

It may also apply to consumer-interface standards that let users browse, explore, and alter data using computer-based documentation. Objects are viewed, produced, modified, and removed in this way. Furthermore, CRUD is data-driven, and HTTP operation verbs are regulated.

Standard CRUD Operations In C#

The CRUD feature is present in almost all programs. CRUD is something that every coder has to use at some stage. In the C# programming language, CRUD operations in the database are quite crucial to learn because they are a fundamental component of programming. CRUD is important because of its Create, Read, Update, and Delete features. A brief explanation of these features is listed below:

  • CREATE Operations: Inserts a fresh entry using the INSERT command. This operation is required when we wish to add new data to the database. It basically enables you to add extra rows to your table. When you use the INSERT INTO command, the system will show two possibilities. You can choose the one which is according to your requirement. The two possibilities are:
  • READ Operations: The READ operation retrieves table entries depending on the main key inside the given variable. It works in a similar way to the search feature.
  • UPDATE Operations: Performs an UPDATE assertion on the database depending on the main key provided for an entry in the WHERE statement. You must specify the destination table and attributes to be modified when using UPDATE. The corresponding variables and the rows are also required. Use the code below to make changes to a preexisting record:
  • DELETE Operations: Erases a specific order within the WHERE statement. Certain relational database systems may enable a final delete or a temporary delete, depending on the requirement. The DELETE code is:
  • Here's the table, showing all operations with their description:

Standard CRUD Operations In ASP.NET MVC Utilizing C#

In this section, we will discuss the steps required to operate the standard CRUD operations in ASP.NET MVC within the C# programming language. So, please pay extra attention to this section so that you do not have to face any difficulty while coding.

You must be thinking about the term MVC. Well, MVC abbreviates for Model View Controller. It is actually a development paradigm that isolates the business strategy from the display strategy and information. In a nutshell, it is a framework for designing online applications. According to MVC, the program can be divided into three layers:

  1. Model Layer: The Model element relates to everyone's data-associated reasoning. It will reflect the content being transmitted among the Display and Controlling portions, as well as any additional business logic-associated data. A Client class, for example, will receive client details from a server, change them, or utilize the content.
  2. View Layer: The View element is used for the UI functionality of the device. For example, the Client view will have all of the UI elements that the final user encounters, like input forms, dropdowns, and others.
  3. Controller: Controllers serve as a link among the Framework and View elements to execute all administrative functions and incoming applications, manipulating information with the Framework element, and interacting with Viewpoints to display the final result. For example, the Client manager would manage all activities and entries from the Client Page and use the Client Model to refresh the database.

Now that you know about the MVC, we can begin the discussion of the steps of CRUD operations in C#:

  • Construct A Database Using The Columns Listed Below: It is merely a demonstration to ensure that you comprehend the script. You may construct your custom database based on your requirements. You can also understand it better by the illustrations in each step like the one below:
  • New Project: Build a new project in Visual Basic.
  • Create a Fresh Record: Next, within the freshly formed controller, enter the following script to generate a fresh record within your dataset.

Afterward, select the initial activity outcome and select AddView. Choose to Generate as your theme, model type as your developed model, and info context category as your EDMX developed prototype. After that, execute the project.

  • Read: Next, to view the latest values on your display, use the code provided below.

Then, insert the View. However, make sure the style is set to List. After that, launch the project.

  • Update: Now, use the following code to modify the present record.

Next, insert a view in the same way you did before, but ensure to set the theme to Edit. After that, launch the project.

  • Delete: To erase an entry from the system, use the following code.

Now, just set the theme to Delete and execute the program.

Please remember that you can always change the HTML according to your needs. We hope that you understood how CRUD operations work in databases of the C# programming language.

CRUD Operations in C# Connecting SQL Database

We want our readers to have crystal clear concepts regarding CRUD operations in the C#. That is why we also included this brief section of CRUD operations in C# connecting the SQL Database. Let us begin:

  • Add DLL: First, you must include Dynamic Link Library (DLL).
  • Namespace: To link to a SQL system, you can utilize the System.Data.SqlClient; namespace.
  • Declaration: Next, you should specify the relationship string beyond the class.
  • Insert the Data: Enter data into the system as shown below:
  • Update: Afterwards, you have to update the record like the code mentioned below:
  • Display: Then, display the information like the code below:
  • Delete: Then, follow the code below to erase the record.
  • Use Clear Technique: Lastly, utilize the Clearing technique to remove all the text fields, as shown below:

Please remember these steps. If you mess up in one step, your program will not execute the right way. So, it would be great for you if you note the steps down!

Benefits Of Using CRUD Operations

Now that you know about the launch of CRUD operations in databases within the C# programming language, it is time to know the benefits of using CRUD operations. You must have this question that why do programmers prefer CRUD? In simple words, developers use CRUD because of its exceptional productivity. Additionally, performing CRUD operations protects against SQL manipulation attacks. Because all SQL Entries utilize saved methods rather than string synthesis to generate flexible queries from client input info, everything entered into a variable is quoted.

It would not be wrong to say that CRUD is just too crucial to be overlooked. Mastering it initially can help you feel more confident when working with unknown stacks. CRUD Operations help in our daily desktop tasks. Some of these are:

  • Signing up for a webpage
  • Saving a hyperlink in your account
  • Modifying configurations
  • Deleting a Facebook status

These are just some of them. CRUD is a part of everyone’s life whether one is a programmer or not.

CRUD Restricts Casual Surfing and Changes

Program permissions are a SQL Administration feature that allows code to alter credentials without requiring the person's permission. Individuals should have the necessary rights on the relational records to execute ad hoc SQL queries. Clients can view and change data in apps like Microsoft Excel, PowerPoint, and others after authorization is allowed. Customers can even ignore the app's corporate rules.

However, it is an undesirable scenario that may be avoided by using the Application Authority. Such kind of flaws can be prevented by combining database access protection with an Application License. Because Application licenses are uploaded to the system via a recorded method, CRUD is required. It can also be done by providing authorization to run the CRUD saved methods and removing immediate table entry.

After an Application Account is established, authorization and passcode are granted. The passcode is also hard to change because it is programmed into the program. CRUD is indeed the procedure to utilize while modifying data. Thus, the world of programming would be incomplete without CRUD Operations.

Summing Up

In this article, we discussed the CRUD operations in databases within the C# programming language. We also discussed Standard CRUD Operations In ASP.NET MVC as well as in Connecting SQL Databases Utilizing C#, with some benefits of using CRUD. These might seem complicated to you. Once you become an expert, all the CRUD operations in the C# will not be rocket science for you. Just make sure to follow all the steps correctly to avoid any mistakes.

Happy Programming Precious Readers!

I2C communication with STM32

Hello friends, I hope you all are doing great. In today's lecture, we will have a look at the I2C Communication with STM32 Microcontroller board. I am going to use the Nucleo board for today's lecture. In the previous lecture, we have discussed STM32 Serial communication both in Interrupt Mode and polling Mode. Today, we will study another way of communication(i.e. I2C) with STM32. So, let's first have a look at what is I2C Communication:

Where To Buy?
No.ComponentsDistributorLink To Buy
1STM32 NucleoAmazonBuy Now

What is I2C Communication?

I²C (Inter-Integrated Circuit) is a two-wire serial communication system used between integrated circuits. Like any serial protocol, one of its advantages is that of using only two lines that transmit or receive a sequence of bits, the limit is the communication speed which has been improved over the years.

The bus was conceived and developed by Philips (now NXP) It was designed to overcome the difficulties inherent in the use of parallel buses for communication between a control unit and various peripherals.

Serial transmission is a mode of communication between digital devices in which bits are sent one at a time and sequentially to the receiver in the same order in which they were transmitted by the sender. Although the communication modules are more complex than the parallel transmission, the serial mode is one of the most widespread especially in communications between chips that must communicate with each other over great distances, because:

  • it requires fewer wires and pins available on the integrated circuit with a consequent reduction in costs and space on the board;
  • is more tolerant of interference and transmission errors;
  • up to 128 devices can be connected to each other

I2C Pinout

  • SDA (Serial Data) is the line where master and slave send or receive the information (sequence of bit);
  • SCL (Serial Clock)  is the line dedicated to the clock to synchronize the data flow.

SDA and SCL lines need to be pulled up with resistors. The value of these resistors depends on the bus length ( ie the bus capacitance) and the transmission speed. The common value is 4.7kO. In any case, there are many guides to size them and we refer their reading to the more attentive reader.

The transmission mode is Half-duplex ie the transmission between devices is alternated.

As shown by the previous image, we can use this communication to put in communication different peripherals as Analog-Digital Converters (ADCs), Digital-Analog Converters (DACs), EEPROM memories, sensors, LCD screen, RF module, Real-Time Clock, etc.

I2C Communication in STM32

The Nucleo boards provide one or more I2C interfaces that can be quickly configured with STCube Tool.

There are four modes of operation:

  1. Slave Transmitter
  2. Slave Receiver
  3. Master Transmitter
  4. Master Receiver

The first two are used to operate in slave mode, while the last two are in master mode. By default, the interface is configurated in slave mode.

By default, the I2C interface operates in Slave mode, but it is possible to switch to Master mode to send a Start condition message. Furthermore, it needs to write in I2C_CR2 register the correct clock configuration to generate the expected timings.  The Master sends a Stop condition when the last data byte is transferred, and the interface generates an interrupt.

I2C Packet Message

In general, the packet message is as follow:

  • Start condition: the master pulls SDA low and SCL is High to inform slave devices that a transmission is ready to start.
  • Address frame: the master sends the address of the slave, each device has an address of 7-10bit, then sends the Read (R) or Write (W) bit, which are respectively 1 and 0. Finally, the master waits that the slave sends the Acknowledge bit (ACK).
  • Data frame(s): Send (master) / Receive (slave) Data Byte (DATA) and then Waiting (master) / sending (slave) the Acknowledge bit (ACK)
  • Stop condition: the master sends the stop conditions pull SDA to High defined by a low while SCL remains high.

I2C Modes in STM32

Furthermore, there are three ways to exchange data, named:

  1. Polling Mode
  2. Interrupt Mode

STM32 I2C Polling Mode

  • In polling mode, also called blocking mode, the application waits for the data transmission and reception.
  • This is a simple way to communicate between devices when the bit rate is not very low, for example when we can debug the board and we want to display the result on screen console.

HAL library provides the following functions to transmit and receive in polling mode:

I2C Master Reciever

  • The function to receive data in master mode is as follows:
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
The parameters are:
  • hi2c is a pointer to an I2C_HandleTypeDef structure that contains the configuration information for the specified I2C.
  • DevAddress is device address: The device 7 bits address value in the datasheet must be shifted to the left before calling the interface.
  • pData is a pointer to data buffer.
  • Size is the amount of data to be sent.
  • Timeout is the timeout duration.

I2C Master Transmitter

  • Master transmits in master mode an amount of data in blocking mode.
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

I2C Slave Reciever

  • The function to receive data in slave mode is as follows:
HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

I2C Slave Transmitter

  • The function to transmit data in slave mode is as follows:
HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

I2C Memory Read

  • Master reads an amount of data in blocking mode from a specific memory address.
HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
The additional parameters are:
  • MemAddress is the internal device address.
  • MemAddSize is the size of the internal device address.

I2C Memory Write

  • Master reads an amount of data in blocking mode from a specific memory address.
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

STM32 I2C Interrupt Mode

  • In interrupt mode, also called non-blocking mode, in this way the application waits for the end of transmission or reception.
  • It is used when the transmission is not used continuously with respect to the activity of the microcontroller.
HAL library provides the following functions to transmit and receive in interrupt mode:
HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Master receives in master mode an amount of data in non-blocking mode with interrupt.
HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Master transmits in master mode an amount of data in non-blocking mode with interrupt.
HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Slave receives in master mode an amount of data in non-blocking mode with interrupt.
HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Slave transmits in master mode an amount of data in non-blocking mode with interrupt.

STM32 I2C DMA Mode

  • DMA mode is the best way the exchange data, especially when we want to exchange data quickly and continuously that often require access to memory.
HAL library provides the following functions to transmit and receive in DMA mode:
HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Master receives in master mode an amount of data in non-blocking mode with DMA.
HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Master transmits in master mode an amount of data in non-blocking mode with DMA.
HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Slave receives in master mode an amount of data in non-blocking mode with DMA.
HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
Slave transmits in master mode an amount of data in non-blocking mode with DMA. In the STCube tool, the I2C can be configurated fastly and easily as follow.

In Pinout & Configuration, widow selects Connectivity and selects one of the available I2C (I2C1, I2C2, etc). In parameter settings, the master and slave features can be set. Master features are I2C speed mode (standard mode by default and fast mode) and the I2C clock speed (Hz). In standard mode, the device can send up to 400kbit/s while in fast mode up to 1Mbit/s. In general, like clock speed, the STM32 supports 100kHz, 400kHz and sometimes 1MHz.

The main feature of slaves is the primary address length that in general, as previously said, is 7-Bit. Furthermore, the slave can have a secondary address.

Then need to configure the GPIO, as follow:

Now the I2C configuration is terminated and can be possible to generate the code initialization and finally be ready to write our application.

Syed Zain Nasir

I am Syed Zain Nasir, the founder of <a href=https://www.TheEngineeringProjects.com/>The Engineering Projects</a> (TEP). I am a programmer since 2009 before that I just search things, make small projects and now I am sharing my knowledge through this platform.I also work as a freelancer and did many projects related to programming and electrical circuitry. <a href=https://plus.google.com/+SyedZainNasir/>My Google Profile+</a>

Share
Published by
Syed Zain Nasir