ECG & Temperature Sensor with BLE Lab
BME554L - Fall 2025 - Palmeri
- Fork this repository to your userspace.
- Add Dr. Palmeri as a
Maintainer. - Questions should be asked exclusively through GitLab Issues.
Git Version Control
- Use best practices for version control (branching, commit messages, etc.).
- Do all development on a dedicated branch that is merged into
mainonce it is functional. - Commits should be very specific to the changes/additions you are making to your code. This will help you and others understand what you did and why you did it.
- On a given development branch, try to implement one small piece of functionality at a time, commit it, and then move on to the next piece of functionality.
You do not want one, monolithic git commit right before you submit your project.
Best Coding Practices
- Use best coding practices throughout the development of your firmware.
- Functions should be short and do one thing. They should return an exit code that is checked in the calling function, indicating success or failure.
- MACROS! Avoid hard-coded values in your code.
- Use structs to organize related data.
- Use libraries for code that is self-contained.
- Use the
LOGGINGmodule to log errors, warnings, information and debug messages. - You should not have any compiler/build warnings. The CI script will build against
v2.9.0of the Zephyr SDK.
Firmware Functional Specifications
- Write all firmware using the state machine framework.
- Do all device initialization in an
INITstate. - Have an
IDLEstate when the device isn’t making any measurements. - Have an
ERRORstate if any error exit codes are returned from any functions.- All 4 LEDs should blink at a 50% duty cycle (
ON:OFFtime), in-phase with each other, in theERRORstate. - An error condition should post an error-related event that causes the device to enter the
ERRORstate. - The error code should specify the error condition that caused the device to enter the
ERRORstate. For example, you may choose to have a bit array that can capture multiple error conditions. - A BLE notification should be sent with the error code (see BLE custom service/characteristic below).
- All 4 LEDs should blink at a 50% duty cycle (
- Implement states of your choosing for the following measurements, calculations and BLE communications.
- Do all device initialization in an
- Have a heartbeat
LED0that blinks every 1 second with a 50% duty cycle (ON:OFFtime) in all states. - Implement functionality to measure a battery voltage (0-3.0 V) using
AIN0:- When the device first powers on, and then
- Every 1 minute thereafter, but only when in the
IDLEstate. - You won’t actually be connecting a battery to your device; you can use a power support or another voltage source to input a voltage to
AIN0to simulate a battery level.
- Have the brightness of
LED1linearly modulated by the percentage of the battery level. - Implement functionality to make two measurements after pressing
BUTTON1:- Read temperature with your
MCP9808sensor (in degrees Celsius). - Calculate the average heart rate (40-200 BPM) using 25-30 seconds of an ECG signal (ranging from -500 - 500 mV, note this is bipolar) from the function generator (see video on how to setup the function generator to output an ECG signal).
- Read temperature with your
- Pressing
BUTTON1during the measurements should post an error and go to theERRORstate. - Blink
LED2with a 25% duty cycle (ON:OFFtime) at the average heart rate after the measurements are complete. - Have Bluetooth notifications after the measurements are complete and data have been processed, using the BLE services and characteristics described below.
- Configure the DIS (Device Information Service) to report the device model as your Team Name (come up with something fun).
- Set the BAS (Battery Service) to report the battery level of your device. (This isn’t actually a battery level, but we’re using the
AIN0measurement as a surrogate for a battery level.) - Set the Heart Rate Service to report the average heart rate. (See Resources section below.)
- Setup a custom service with the following custom characterisitics:
Temperaturefor the I2C temperature sensor data in degrees Celcius.Error Codefor the error code that caused the device to enter theERRORstate.
BUTTON2should clear (turn off) a blinkingLED2, and ifLED2is not blinking because a measurement hasn’t been taken, then it should log a warning (LOG_WRN()) as to why it appears nothing happened.BUTTON3should be used to reset the device from theERRORstate and return to theIDLEstate.- Use timers, kernel events, work queues, threads and any other Zephyr RTOS features as needed to implement the above functionality.
BLE Server (Mobile App)
- Your device can connect via BLE to a mobile app called nRF Connect.
- This app can be used to read the services and characteristics that your device is advertising.
State Diagram
- Generate a detailed state diagram that all states, events and actions for your firmware.
- A starter diagram is provided in the
state_diagram.pumlfile, along with its rendering below.
- You should add states, events and actions as needed to fully describe the functionality of your firmware.

Testing & Verification
Battery Voltage Measurement
Verify the accuracy of your battery level measurement (AIN0) for 0-3.7 V, as read through the nRF Connect app Bluetooth Battery Level GATT. Quantitative analysis should include:
Linear regression analysis of the input voltage versus the battery level for both the
LOG_INF()output, the oscilloscope measurement of the PWM duty cycle, and the nRF Connect app.95% confidence intervals for the slope and intercept of the linear regression.
ECG Heart Rate Measurement
Demonstrate that your average heart rate measurement is accurate, as recorded through LOG_INF() output, the oscilloscope measurements, and the nRF Connect app, relative to what was set on the function generator. This should be done for 40, 60, 120, 150, and 180 bpm. The 25% duty cycle should also be verified. Quantitative analysis should include:
Linear regression analysis of the recorded heart rate versus the set heart rate for both the
LOG_INF()output, oscilloscope measurements, and the nRF Connect app.95% confidence intervals for the slope and intercept of the linear regression.
Verification that the duty cycle of out output is 25% for all heart rates.
Temperature Sensor Measurment
Demonstrate that your temperature sensor can have a room temperature measurement read through
LOG_INF()output and the nRF Connect app.Do this in 3 locations with different temperatures.
You do not need to verify accuracy, just a reasonable measurements with agreement.
How to Generate an ECG Signal
Grading
- This final project is worth 75% of your grade. Absolutely no late submissions will be accepted.
- Git version control will be graded based on best practices.
- Firmware will be graded based on all best practices taught throughout the semester.
- Code organization and coding best practices will be graded.
- State diagram will be graded based on completeness, accuracy and ease of interpretation.
- Testing and analysis technical report will be graded based on presentation, completeness, and accuracy.
How to Ask for Help
- If you have a general / non-coding question, you should ask your TAs / Dr. Palmeri on Ed to allow any of them to respond in a timely manner.
- Push you code to your GitLab repository, ideally with your active development on a non-
mainbranch. - Create an Issue in your repository.
- Add as much detail as possible as to your problem, and add links to specific lines / section of code when possible.
- Assign the label “Bug” or “Question”, as appropriate.
- Be sure to specify what branch you are working on.
- Assign the Issue to one of the TAs.
- If your TA cannot solve your Issue, they can escalate the Issue to Dr. Palmeri.
- You will get a response to your Issue, and maybe a new branch of code will be pushed to help you with some example syntax that you can use
git diffto visualize.
What to Submit
- Make sure that all of your branches have been merged into the
mainbranch. - Create an annotated tag called
v1.0.0to mark the commit that you want to be graded.- If you fix any bugs after creating this tag, you can create another tag called
v1.0.1, etc.
- Your latest tag will be the one that is graded up until the final due date/time of the project.
- If you fix any bugs after creating this tag, you can create another tag called
- Create an Issue in your repository with the title “Final Project Submission”, and assign it to Dr. Palmeri.
- All repositories will be cloned at the due date/time for grading. Absolutely no changes will be accepted after this time.