CodeSnippets/Peripherals/ADC/LinuxSysfsNodes/linux_sysfs_nodes.c (70 lines of code) (raw):
/* Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. */
// Code Snippet: Read ADC channel via sysfs nodes on Raspberry Pi
// This code snippet demonstrates how to read a value from the MCP3008 ADC chip (which is connected
// to a Raspberry Pi 4 Model B) using Linux sysfs nodes and displays the value in volts.
// Refer to LinuxSysfsNodes/README.md for prerequisites and circuit information.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int OpenAdc(int adcChannel);
static int ReadAdc(int adcFd, int *outSampleValue);
static int ReadAdcChannel(void);
static const char iioSysPath[] = "/sys/bus/iio/devices/iio:device0/";
static const int channelNumber = 0; // Channel 0.
static const int sampleBitCount = 10;
static const float referenceVoltage = 3.3f; // Vref is 3.3V.
/// <summary>
/// Reads the value from the ADC channel and displays the value in volts.
/// </summary>
/// <returns>0 on success, else -1.</returns>
static int ReadAdcChannel(void)
{
int adcFd = -1;
int sampleValue = 0;
int retVal = -1;
adcFd = OpenAdc(channelNumber);
if (adcFd == -1) {
goto cleanup;
}
if (ReadAdc(adcFd, &sampleValue) == -1) {
goto cleanup;
}
// Calculate voltage.
float maxSample = (float)((1 << sampleBitCount) - 1);
float voltage = ((float)sampleValue * referenceVoltage) / maxSample;
printf("The out sample value is %.3f V.\n", voltage);
retVal = 0;
cleanup:
// Close the file descriptor.
if (adcFd >= 0) {
int result = close(adcFd);
if (result != 0) {
fprintf(stderr, "ERROR: Could not close ADC fd: %s (%d).\n", strerror(errno), errno);
}
}
return retVal;
}
/// <summary>
/// Helper function to open the ADC file descriptor.
/// </summary>
/// <param name="adcChannel">Channel number to open.</param>
/// <returns>Value of fd if succesful, -1 on error</returns>
static int OpenAdc(int adcChannel)
{
// Format the path for the channel.
char path[128];
int len = snprintf(path, sizeof(path), "%sin_voltage%d_raw", iioSysPath, adcChannel);
if (len < 0 || len >= sizeof(path)) {
fprintf(stderr, "ERROR: Cannot format ADC path to buffer.\n");
return -1;
}
int fd = open(path, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "ERROR: OpenAdc failed with error: %s (%d) for path %s.\n", strerror(errno),
errno,
path);
return -1;
}
return fd;
}
/// <summary>
/// Helper function which reads the specified ADC channel.
/// </summary>
/// <param name="adcFd">ADC file descriptor.</param>
/// <param name="outSampleValue">Holds the value read from the channel.</param>
/// <returns>0 on success, else -1</returns>
static int ReadAdc(int adcFd, int *outSampleValue)
{
if (adcFd < 0) {
fprintf(stderr, "ERROR: Invalid file descriptor.\n");
return -1;
}
// Buffer to hold decimal representation of 4-byte integer value and null terminator.
char dataBuffer[12];
memset(dataBuffer, 0, sizeof(dataBuffer));
if (read(adcFd, dataBuffer, sizeof(dataBuffer)) == -1) {
fprintf(stderr, "ERROR: ReadAdc failed with error: %s (%d).\n", strerror(errno), errno);
return -1;
}
*outSampleValue = atoi(dataBuffer);
return 0;
}