# Embedded

Lisa's hard work :)

# Getting started

***This page:** *structure of this subsystem and where to find what.**

<p class="callout success">**Make sure you understand the embedded structure:**<span style="white-space: pre-wrap;"> </span>[Embedded Infastructure](https://bookstack.roboteamtwente.nl/books/embedded-infastructure "Embedded Infastructure")</p>

---

## 1) Main

<p class="callout info"><span style="white-space: pre-wrap;">Main.c can be found in </span>`<span class="editor-theme-code">src/arm_board</span>`</p>

This is the code that will be ran when building and uploading using platformio. Main should contain some multithreading for running separate tasks, otherwise it should use the libraries (common and arm board specific) that are created.

---

## 2) Libraries

<p class="callout info"><span style="white-space: pre-wrap;">The libraries for the arm board can be found in </span>`<span class="editor-theme-code">components/arm_board</span>`</p>

The arm board uses 3 libraries:

- firmware
- movement
- simulink

**Firmware** <span style="white-space: pre-wrap;">contains the generated CubeMX code. </span><span style="background-color: rgb(251, 238, 184);">You do not need to touch this after generating</span>.

<p class="callout info">**NOTE:**<span style="white-space: pre-wrap;"> do make sure that after generating your code in CubeMX, you run the post generation script. You </span>**can** <span style="white-space: pre-wrap;">set a post generation script in CubeMX itself. However, if you use </span>**Windows** <span style="white-space: pre-wrap;">you may need to run the bash script manually. This script can be found in </span>`<span class="editor-theme-code">scripts/post_code_generation.bash</span>`.</p>

**Simulink** <span style="white-space: pre-wrap;">contains code generated by control subteam. </span><span style="background-color: rgb(251, 238, 184);">You also do not need to touch this</span><span style="white-space: pre-wrap;">, since it is not code that is ran on embedded side. It is a helpful </span>**reference** <span style="white-space: pre-wrap;">for the output data that control will be giving your system. </span>  
<span style="white-space: pre-wrap;">Specifically, in </span>`<span class="editor-theme-code">control.h</span>`<span style="white-space: pre-wrap;">, struct </span>`<span class="editor-theme-code">ExtY</span>`<span style="white-space: pre-wrap;"> gives the external outputs. These will be transferred across the robot using protobufs. So for us, this struct contains the inputs for the motors on the robotic arm.</span>

**Movement** is currently the only "real" library that is written by hand. It contains the source code for controlling stepper motors.

---

## 3) Protobuffers

<p class="callout info">**Information on the arm board protobuffers can be found here:**<span style="white-space: pre-wrap;"> </span>[Arm Board Protobuffers](https://bookstack.roboteamtwente.nl/books/communication-system/page/arm-board-protobuffers "Arm Board Protobuffers")</p>

# Example PWM generation

***This page:** *what does the configuration look like for my board, specifically regarding PWM.**

<p class="callout danger"><span style="white-space: pre-wrap;">Make sure you have set up Ethernet according to the following page </span>**FIRST**<span style="white-space: pre-wrap;">: </span>[Introduction and initial setup of embedded ethernet](https://bookstack.roboteamtwente.nl/books/communication-system/page/setup-of-embedded-ethernet "Introduction and initial setup of embedded ethernet")</p>

---

## **PWM**

> **Pulse Width Modulation** <span style="white-space: pre-wrap;">(PWM) is a technique for generating a continuous HIGH/LOW alternating digital signal and programmatically controlling its pulse width and frequency. Certain loads like (LEDs, Motors, etc) will respond to the </span>**average voltage**<span style="white-space: pre-wrap;"> of the signal which gets higher as the PWM signal’s pulse width is increased. This technique is widely used in embedded systems to control LEDs brightness, motor speed, and other applications. </span>  
> <span style="white-space: pre-wrap;">&gt; </span>[DeepblueMbedded.com](https://deepbluembedded.com/stm32-pwm-example-timer-pwm-mode-tutorial/)

<span style="white-space: pre-wrap;">On the embedded subteam, we use PWM to control the motors for the Robotic arm and </span>[Drive system](https://bookstack.roboteamtwente.nl/books/drive-system "Drive system")<span style="white-space: pre-wrap;">. In the world of PWM, two metrics are most important: </span>**duty cycle** <span style="white-space: pre-wrap;">and </span>**frequency**. The duty cycle is determined by the percentage of high/low signal, for example a 75% duty cycle means that the signal is HIGH 75% of the time. How long this total time is, is determined by the frequency. The frequency is to determine motor speed.

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/NaAafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/NaAafbeelding.png)

---

## **CubeMX**

<p class="callout danger"><span style="white-space: pre-wrap;">Make sure you have set up Ethernet according to the following page </span>**FIRST**<span style="white-space: pre-wrap;">: </span>[Introduction and initial setup of embedded ethernet](https://bookstack.roboteamtwente.nl/books/communication-system/page/setup-of-embedded-ethernet "Introduction and initial setup of embedded ethernet")</p>

### 1) Setting Pins

<span style="white-space: pre-wrap;">The only pin that is set at the moment (except for defaults) is </span>**PA0**. It is set to TIM2\_CH1, this means it uses Timer 2 Channel 1 for something, in this case it is PWM generation.

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/ze1afbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/ze1afbeelding.png)

<span style="white-space: pre-wrap;">If we want to set more pins to generate PWM signals, we can use a workflow similar to what will be described below. Of course, you will need to choose a </span>**separate timer**<span style="white-space: pre-wrap;"> for each pin. Also make sure that the pin is </span>**suitable** for PWM!

##### **TIM2 &gt; Mode** 

<span style="white-space: pre-wrap;">After you have set the pin, you need to enable the timer and channel to do something. We set </span>`<span class="editor-theme-code">Clock Source: Internal Clock</span>`<span style="white-space: pre-wrap;"> to enable the timer and </span>`<span class="editor-theme-code">Channel1: PWM Generation CH1 </span>`to use PWM on pin PA0.

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/a8Xafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/a8Xafbeelding.png)

##### **TIM2 &gt; Configuration &gt; NVIC settings** 

Enable global interrupt.

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/phDafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/phDafbeelding.png)

##### **TIM2 &gt; Configuration &gt; Parameter settings &gt; Counter settings**

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/lTKafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/lTKafbeelding.png)<p class="callout info">**NOTE:** -1 for prescaler and counter period because of 0 index counting</p>

<span style="white-space: pre-wrap;">To fully configure the PWM generation, we have to set the above parameters. The </span>**prescaler** <span style="white-space: pre-wrap;">has to do with the clock configuration. You want to set the prescaler </span>**equal to the amount of MHz in the clock configuration**<span style="white-space: pre-wrap;">, because we will divide the clock frequency by the prescaler! Here, we have set the </span>**clock speed to 84 MHz** <span style="white-space: pre-wrap;">(see </span>[Clock configuration](#bkmrk-clock-configuration "Clock configuration")<span style="white-space: pre-wrap;">), so we set the prescaler to 84 (-1) as well. This way we work with </span>**1MHz**<span style="white-space: pre-wrap;"> in calculating the counter period for the wished for PWM frequency (see below). </span>

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/xC5afbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/xC5afbeelding.png)

<p class="callout info">**NOTE:**<span style="white-space: pre-wrap;"> the counter period parameter uses the ARR (AutoReload Register). Those terms are used interchangeably in online sources.</span></p>

<span style="white-space: pre-wrap;">As of now, the counter period is at </span>**65535**<span style="white-space: pre-wrap;">, which is the maximum value for an unsigned 16bit integer. This results in a PWM frequency of </span><span style="color: rgb(0, 0, 0);">1098Hz</span><span style="white-space: pre-wrap;">. The </span>**frequency** <span style="white-space: pre-wrap;">of PWM should be suitable for the motor you are using. We can change this value later. For more information on PWM see </span>[resource 1](https://deepbluembedded.com/stm32-pwm-example-timer-pwm-mode-tutorial/).

### 2) Clock configuration

<span style="white-space: pre-wrap;">The board can be optimized to run at a higher frequency than is preconfigured. You can set the system clock to work at </span>**84 MHz**<span style="white-space: pre-wrap;"> by setting any of the right-hand clocks in the clock configuration menu to 84. The program then auto calculates the settings for the system, also see </span>[resource 2](https://youtu.be/zHWvFchXhvw?si=nGj-vzkVCszjHonW)<span style="white-space: pre-wrap;">. </span>

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/oysafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/oysafbeelding.png)

---

## **Resources**

1. [Deepbluembedded.com: STM32 PWM Output Example Code (PWM Generation Tutorial)](https://deepbluembedded.com/stm32-pwm-example-timer-pwm-mode-tutorial/)
2. [YouTube: STM32 Beginners Guide Part3: PWM, TIMERS, Frequency and Duty Cycle. LED Dimming with PWM example.](https://youtu.be/zHWvFchXhvw?si=nGj-vzkVCszjHonW)

# Stepper library

## **Purpose**

## **CubeMX**

### 1) PWM

<p class="callout info">**NOTE:**<span style="white-space: pre-wrap;"> If you are new to PWM, first take a look at </span>[Example PWM generation](https://bookstack.roboteamtwente.nl/books/robotic-arm/page/example-pwm-generation "Example PWM generation"), it is more in depth</p>

![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-05/scaled-1680-/U6dafbeelding.png)**For each stepper**<span style="white-space: pre-wrap;">, enable pwm on channel 1. This is done by setting </span>`<span class="editor-theme-code">Clock Source = Internal Clock</span>`<span style="white-space: pre-wrap;"> and </span>`<span class="editor-theme-code">Channel 1 = PWM Generation CH1</span>`<span style="white-space: pre-wrap;">. </span>

<p class="callout warning">**NOTE:**<span style="white-space: pre-wrap;"> Each pwm output for each stepper needs a </span>**separate timer**<span style="white-space: pre-wrap;">. Right now, it is hardcoded that </span>**PWM uses Channel 1**, so only use Channel 1!</p>

The following parameters are important:

- `<span class="editor-theme-code">prescaler</span>`  
    <span style="white-space: pre-wrap;">The </span>**prescaler** <span style="white-space: pre-wrap;">has to do with the clock configuration. You want to set the prescaler </span>**equal to the amount of MHz in the clock configuration**<span style="white-space: pre-wrap;">, because we will divide the clock frequency by the prescaler! (On the board right now, the clock speeds is set to 72MHz.) This way we work with </span>**1MHz**<span style="white-space: pre-wrap;"> in calculating the frequency and duty cycle.</span>
- `<span class="editor-theme-code">auto-reload preload</span>`  
    I lowkey don't know what this does, just enable it to be safe.

### 2) DMA

<span style="white-space: pre-wrap;">Now, you have to set up the DMA for the same timer/channel. This is in the </span>`<span class="editor-theme-code">DMA settings</span>`<span style="white-space: pre-wrap;"> tab.</span>

[![afbeelding.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-05/scaled-1680-/VPKafbeelding.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-05/VPKafbeelding.png)

Set the following parameters:

- `<span class="editor-theme-code">DMA Request = TIMx_CH1</span>`  
    <span style="white-space: pre-wrap;">This is the timer and channel which will be using DMA. </span>**Make sure this is on channel 1, as stated above!**
- `<span class="editor-theme-code">Stream</span>`  
    This can be any of the available streams.
- `<span class="editor-theme-code">Direction = Memory to Peripheral</span>`  
    **Important!**<span style="white-space: pre-wrap;"> Because we will be using DMA to transfer PWM signals from the code (memory) to the pin (peripheral) it needs to be set this way.</span>
- `<span class="editor-theme-code">Priority</span>`  
    <span style="white-space: pre-wrap;">This can be set to any level, but note that it is advisable to put </span>**all steppers to the same priority**. I don't know (and am not responsible for) what happens if they are different.
- `<span class="editor-theme-code">Mode = Normal</span>`  
    <span style="white-space: pre-wrap;">In normal mode, DMA transfers the buffer from memory </span>**ONCE** <span style="white-space: pre-wrap;">and then remains at the last sent value (remember this, it is important later). See </span>[resource 1](https://controllerstech.com/pwm-in-stm32/).
- `<span class="editor-theme-code">Data width = Word</span>`  
    This is the width of the values we will be sending. Since the values we will be sending are used to fill the CCR register, we will set this to word (uint32\_t size). Half word would be for 16 bit registers.

### 3) GPIO pins

<span style="white-space: pre-wrap;">Set 2 pins to GPIO\_Output by clicking on them in the CubeMX UI. One of these will be used for the direction pin and another for the enable pin. </span>

//TODO: add driver resource

### 4) Clock Configuration

For PWM it really doesn't matter at what speed you set the clock. The only thing that matters is that the prescalar is set to the same amount. So if your clock speed is 72, set it to 72-1, if your clock speed is 84, set it to 84-1.

---

## **Code**

### 1) Public Methods

### 2) Private Methods

### 3) Example

## **Resources**

1. [Controllerstech: STM32 PWM Output: Generate PWM Signal with &amp; without DMA](STM32%20PWM%20Output:%20Generate%20PWM%20Signal%20with%20&%20without%20DMA)

# Main



# All resources