MicroZed Chronicles: SP701 Environmental Sensor Application

A simple environmental monitoring example using the Xilinx SP701 board.

We have looked at the Vitis embedded flow a couple of times in the blog; however, to date we have not created a real application using it.

As I talked about last week, I recently received a Spartan-7-based SP701 board and wanted to create a simple application that demonstrates some industrial and embedded vision use cases.

One very important use case in the industrial arena is the interfacing with sensors to understand the equipment's environment. This enables prognostics to to be implemented based on the environmental conditions, perhaps detecting failure or other deviations from expectations. Of course, this information can also be provided to a digital twin.

For our first SP701 application, we are going to use a softcore MicroBlaze, which is connected to three Pmods to receive information on its environment.

These are:

  • Pmod Nav — provides X, Y ,Z acceleration, atmospheric pressure and altitude information.
  • Pmod Hygro — provides temperature and humidity information.
  • Pmod ALS — provides ambient light level information.

Having completed the design in Vivado as we did last week, the first thing we need to do is create a new application project.

We can select the SP701 board as the target platform for the development.

As we are working on the MicroBlaze processor, we should see the standalone domain as our default.

Within the platform, we should see the API drivers for the Pmods we are using in the design.

We will be using these in the application to configure and read sensor information.

The application will use a terminal window to allow the user to ask the environmental information that is required from the sensors. The three options will be:

  • Acceleration data
  • Temperature and humidity
  • Ambient light level

To implement this functionality, our software application needs to perform the following functions:

  • Initialize the Pmod NAV, HYGO and ALS.
  • Enter loop asking for environmental data choice.
  • Interface with Pmod NAV, HYGO or ALS to read environmental data.

To convert the raw sensor data into SI values I use several functions, for example, to convert the temperature to degrees C or altitude to meters.

The complete source code can be seen below.

#include "xil_cache.h"
#include "xparameters.h"
#include <stdio.h>
#include "sleep.h"
#include "PmodGPS.h"
#include "PmodALS.h"
#include "PmodHYGRO.h"
#include "math.h"
#include "PmodNAV.h"
#include "xil_printf.h"
void EnableCaches();
void DisableCaches();
void loop() ;
float NavDemo_ComputePref(float hPa, float altitudeMeters);
float NavDemo_ConvPresToAltF(float Pref, float hPa);
float NavDemo_ConvPresToAltM(float Pref, float hPa);
float NavDemo_ConvTempCToTempF(float tempC);
float NavDemo_ConvFeetToMeters(float feet);
float NavDemo_ConvMetersToFeet(float meters);
float NavDemo_AngleInXY(NAV_RectCoord r);
float NavDemo_DegreesFromVertical(NAV_RectCoord r);
float NavDemo_ScalarProjection(NAV_RectCoord orient, NAV_RectCoord r);
#define TIMER_FREQ_HZ XPAR_CPU_M_AXI_DP_FREQ_HZ
//void compass_setup();
PmodGPS GPS;
PmodALS ALS;
PmodHYGRO myDevice;
PmodNAV nav;
bool compass_active = false;
bool temp_active = false;
bool nav_active = false;
float temp_degc, hum_perrh, temp_degf;
float Pref, tempF, dps, magXYd, alt;
u8 light = 0;
int main() {
EnableCaches();
printf("www.adiuvoengineering.com SP701 S7 Example\n\r");
ALS_begin(&ALS, XPAR_PMODALS_0_AXI_LITE_SPI_BASEADDR);
NAV_begin ( // intialize the PmodNAV driver device
&nav,
XPAR_PMODNAV_0_AXI_LITE_GPIO_BASEADDR,
XPAR_PMODNAV_0_AXI_LITE_SPI_BASEADDR
);
NAV_Init(&nav);
HYGRO_begin(
&myDevice,
XPAR_PMODHYGRO_0_AXI_LITE_IIC_BASEADDR,
0x40, // Chip address of PmodHYGRO IIC
XPAR_PMODHYGRO_0_AXI_LITE_TMR_BASEADDR,
XPAR_PMODHYGRO_0_DEVICE_ID,
TIMER_FREQ_HZ // Clock frequency of AXI bus, used to convert timer data
);
while(1){
loop();
}
DisableCaches();
return 0;
}
void loop() {
char key_input;
char *compass[8] = {"North", "North-East", "East", "South-East", "South",
"South-West", "West", "North-West"};
char *str;
char c[50];
while(1){
read(1, (char*)&key_input, 1);
switch (key_input) {
case '0':
NAV_GetData(&nav);
magXYd = NavDemo_AngleInXY(nav.magData);
str = compass[(int)((magXYd + 22.5) / 45.0) % 8];
printf("Direction = %c \n\r ",str);
break;
case '1':
NAV_GetData(&nav);
NAV_ReadPressurehPa(&nav);
alt = NavDemo_ConvFeetToMeters(68); // altitude for Pullman, WA in meters
Pref = NavDemo_ComputePref(nav.hPa, alt);
printf("Alttitude %g \r\n", alt);
printf("Pressure %g \r\n", Pref);
printf("Accelerometer X %g \r\n", nav.acclData.X);
printf("Accelerometer Y %g \r\n", nav.acclData.Y);
printf("Accelerometer Z %g\r\n", nav.acclData.Z);
break;
case '2':
light = ALS_read(&ALS);
printf("Illumination %d \r\n", light);
temp_degc = HYGRO_getTemperature(&myDevice);
printf("Temperature %g \r\n", temp_degc);
hum_perrh = HYGRO_getHumidity(&myDevice);
printf("Humidity %g \r\n", hum_perrh);
break;
}
}
}
float NavDemo_ComputePref(float hPa, float altitudeMeters) {
float altitudeFeet = NavDemo_ConvMetersToFeet(altitudeMeters);
float temp = 1 - (altitudeFeet / 145366.45);
return hPa / (powf(temp, 1 / 0.190284));
}
float NavDemo_ConvPresToAltM(float Pref, float hPa) {
return NavDemo_ConvPresToAltF(Pref, hPa) * 0.3048;
}
float NavDemo_ConvPresToAltF(float Pref, float hPa) {
return ((1 - pow(hPa / Pref, 0.190284)) * 145366.45);
}
float NavDemo_ConvTempCToTempF(float tempC) {
return 32 + (tempC * 1.8);
}
float NavDemo_ConvFeetToMeters(float feet) {
return feet / 0.3048;
}
float NavDemo_ConvMetersToFeet(float meters) {
return meters * 0.3048;
}
float NavDemo_AngleInXY(NAV_RectCoord r) {
float d;
if (r.X == 0)
d = (r.Y < 0) ? 90 : 0;
else
d = atan2f(r.Y, r.X) * 180 / M_PI;
if (d > 360)
d -= 360;
else if (d < 0)
d += 360;
return d;
}
float NavDemo_DegreesFromVertical(NAV_RectCoord r) {
// Determine the magnitude of the vector r.
float rM = sqrtf(powf(r.X, 2) + powf(r.Y, 2) + powf(r.Z, 2));
if (rM == 0)
return 0.0;
return acosf(r.Z / rM) * (180.0 / M_PI);
}
float NavDemo_ScalarProjection(NAV_RectCoord orient, NAV_RectCoord r) {
float oM = sqrtf(powf(orient.X, 2) + powf(orient.Y, 2) + powf(orient.Z, 2));
return (r.X * orient.X + r.Y * orient.Y + r.Z * orient.Z) / oM;
}
void EnableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
Xil_DCacheEnable();
#endif
#endif
}
void DisableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheDisable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
Xil_DCacheDisable();
#endif
#endif
}

When I ran this on the SP701 board, I was able to see the following environmental information.

We have created a simple environmental sensor applications. I am now going to start looking at the image processing capabilities of the SP701 board, so keep an eye on my Hackster.io projects.

See My FPGA / SoC Projects: Adam Taylor on Hackster.io

Get the Code: ATaylorCEngFIET (Adam Taylor)

Access the MicroZed Chronicles Archives with over 300 articles on the FPGA / Zynq / Zynq MpSoC updated weekly at MicroZed Chronicles.

Adam Taylor
Adam Taylor is an expert in design and development of embedded systems and FPGA’s for several end applications (Space, Defense, Automotive)
Related articles
Sponsored articles
Related articles