# Step Counter Firmware - STM32C071 Nucleo Board

## 1. Description of Overall Project

This project developed firmware for a personal step counter on the STM32C071 Nucleo development board. The goal was to measure steps, compute distance travelled, and track goal progress, using a joystick and rotary potentiometer for navigation and input. The step counter alerts the walker when they have reached their goal by turning on a buzzer. The firmware was split into functional modules (Figure 1). All code ran on C and was verified through serial plotting and step tests.

The system started at zero steps and defaulted to a 1000-step goal. A step size of 1m was assumed. Key features included step detection via SW1, test mode with joystick scaling, goal setting with the potentiometer, and dynamic screen state switching. All requirements for Milestone 2 were implemented and tested in-lab.

## 2. Justification and Description of Modularisation

This project used a clean, modular file structure designed to keep development fast, focused, and manageable. Each folder had a clear role: `app` handled high-level logic, `drivers` interacted directly with the hardware, `middleware` processed signals, `peripherals` managed external components, and `tasks` ran the system’s behaviour in loops. By keeping things separate, it was easier to track down bugs, test features, and make changes without breaking everything else. Having separate modules for different functionality also meant that modules like `task_display.c` would be less cluttered and easier to manage. System setup files were kept in `system`, and everything came together in `main.c`. Figure 1 shows the structure of the file, folders, and modularisation.

<!-- ![Inc and Src](Images/Inc_and_Src.png) -->
<img src="Images/Inc_and_Src.png" alt="Inc and Src" width="400"/>

#### Figure 1: Folder and file organisation

### Description of modules written by the group for this project by folder

#### App

* **app.c:**
  This module determined the high-level logic and determined a scheduling system.

* **globals.c:**
  This module defined global variables (e.g. step count) that are used throughout the code. This was necessary as there were several key variables that need to be used across many modules.

* **imu\_accel.c:**
  This module defined functions that are for reading and initialising the accelerometer. This module allowed simplified usage of the accelerometer in other modules.

#### Middleware

* **filter.c:**
  This module defined functions that filtered out noise from the accelerometer input. This was required for reliable step detection.

* **step\_detection.c:**
  This module defined functions that were used to detect when steps are taken using filtered data from the accelerometer. This was done by setting an upper and lower threshold acceleration. When both thresholds were crossed, a step was detected. Including this module greatly simplified `task_display.c`.

#### Peripherals

* **buzzer.c:**
  This includes the functions to turn the buzzer on and off using a timer using a PWM signal generated by a timer.

#### Tasks

* **task\_blinky.c:**
  This module contains the code to flash an LED.

* **task\_buttons.c:**
  This module manages input from the buttons and performs the tasks related to button presses.

* **task\_display.c:**
  This module manages everything that appears on the display screen. This is the largest module as most functionality somehow relates to the display.

* **task\_joystick.c:**
  This module contains code to read inputs from the joystick and the potentiometer.

* **task\_led.c:**
  This module manages the state of LEDs. Brightness is also managed using a PWM signal from a timer.

## 3. Analysis of Firmware Operation

### Filter Evaluation

IMU signal stability was evaluated using step tests with and without filters. The plot below showed raw IMU output (Figure 2). High-frequency noise and false spikes made accurate joystick displacement detection impractical.

<!-- ![Unfiltered IMU](Images/Unfiltered_IMU.png) -->
<img src="Images/Unfiltered_IMU.png" alt="Unfiltered IMU" width="600"/>

#### Figure 2: Unfiltered IMU

Initial filtering (buffer size = 3) removed some noise but introduced delay. A second iteration (buffer size = 30) was too slow to respond to joystick changes. A final buffer of 20 was selected as a balance—reducing noise while retaining responsiveness. This was referred to as the "Goldilocks filter". The filter output is shown below in Figure 3

<!-- ![Filtered IMU](Images/Filtered_IMU.png) -->
<img src="Images/Filtered_IMU.png" alt="Filtered IMU" width="600"/>

#### Figure 3: Filtered IMU

The chosen filter allowed smooth transitions in test mode and reliable step updates proportional to joystick displacement, fulfilling M2.3c.

VS Code’s live serial plotter was used to evaluate the filtered acceration magnitude from the IMU. The live graphical infomation was useful in determining threshold values for step detection.

## 4. Conclusions

A reliable step counter was made that had display screens for step detection, distance travelled, and goal tracking/goal setting. There was also a test mode. 
Timers, input filtering, and modular firmware design were used to help complete the project. The use of VS Code’s live serial plotter significantly improved debugging speed over the Tera Term 5 + Python + Excel method used previously, especially for tuning filters.

### What went well:

The code could reliably and accurately count steps. In addition to that, all other requirements for this project were met. Parts of the code were also ‘fine-tuned’ to optimise user experience. For example, how long the buzzer should be on once the step goal was met. Additionally, finding an increment size for the potentiometer when setting the goal to let the user easily select the right goal. It was also found that once certain barriers were overcome (initialisation, git repository), creating the code was relatively straight forward.

### Challenges:

Initial setup delays were caused by persistent lab crowding and unfamiliar IDE configuration. A recurring issue was the STM32CubeIDE configuration window disappearing instantly—this was eventually traced to incorrect firmware paths, solved by applying the recommended fix from the common issues sheet.