• main.c

  • §

    Jonas Altrock ew20b126@technikum-wien.at

    To overview.

    • gpio.h, gpio.c,
    • blink.h, blink.c,
    • done.h
    /* compile with `gcc -std=gnu99 -Wall -o assign4 main.c gpio.c blink.c -lpthread` */
  • §

    Assignment 4 - Analog-to-Digital-Converter (ADC)

  • §

    Goal: make a program that repeatedly reads the value of the potentiometer, outputs the corresponding voltage (0-1.8 V), and converts the value into a frequency to blink the two LEDs on the expansion board.

    The potentiometer on the expansion board is wired up to AIN0, which is an analog input of the ADC on the PocketBeagle. The ADC is mapped in the ADC_TSC subsystem registers starting at 0x44E0_D000.

    Looking in /sys/devices/platform/ocp we can find the device 44e0d000.tscadc which maps to adc.0.auto, which exports its lines in the iio:device0 device. We can find this device also in /sys/bus/iio/devices/.

    AIN0 therefore can be accessed over /sys/bus/iio/devices/iio:device0/in_voltage0_raw.

    According to the AM3358 manual, the ADC has a resolution of 12 bits, which means 4096 different values. One could also experiment with both extremes of the potentiometer to reveal that the voltage level is mapped to a range from 0 to 4095 inclusive.

    For the blinking, we re-use most of the the code from assignment 3.

    As the blinking of the LEDs cannot really be distinguished beyond 70 Hz or so, we map the input onto the range 1 to 33 Hz and use that as the frequency.

    #include <stdio.h>
    #include <signal.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <time.h>
  • §

    I split up the blinking into its own file blink.c, the GPIO code extended by the AIN0 read function can be found in gpio.c.

    #include "gpio.h"
    #include "done.h"
    #include "blink.h"
  • §

    Prototypes

  • §

    15 ms in nanoseconds ~ 66 Hz, this is for polling the analog input.

    #define SAMPLE_RATE 15000000l
  • §

    We declared these global communication variables in done.h and blink.h, now we have to define them.

    volatile double frequency = 0;
    volatile sig_atomic_t done = 0;
  • §

    SIGINT sigaction handler

    void sigint(int signo) {
        done = 1;
    }
  • §

    Main

  • §

    This is again very similar to the last assignment.

    int main()
    {
        if (gpio_init()) {
            return 1;
        }
  • §

    Setup a SIGINT handler.

        struct sigaction act; {
            act.sa_handler = sigint;
            act.sa_flags = 0;
            sigfillset(&act.sa_mask);
        }
        sigaction(SIGINT, &act, NULL);
  • §

    Start the blinker thread.

        pthread_t blink;
        pthread_create(&blink, NULL, blink_at_frequency, NULL);
    
        double new_freq, voltage;
        int ain = -2;
    
        printf("Please change the potentiometer.\n");
  • §

    We do not want to check AIN0 in a busy loop, so we sleep for a little.

        struct timespec sleep; {
            sleep.tv_sec = 0;
            sleep.tv_nsec = SAMPLE_RATE;
        }
  • §

    Repeatedly read the analog input.

        while (!done) {
            int new_ain = ain_get_value();
  • §

    Reading AIN0 was jittery on my BeagleBone Black, so I added the option to only consider larger changes in value.

            #ifdef AVOID_JITTER
            if (abs(new_ain - ain) > 1) {
            #endif
                ain = new_ain;
  • §

    Map frequency 0-4095 to 1-33 Hz (4096/128 = 32).

                new_freq = 1.0 + (ain / 128.0);
  • §

    Map voltage to 0-1.8.

                voltage = 1.8 * (ain / 4095.0);
    
                if (new_freq != frequency) {
                    frequency = new_freq;
                    printf("Voltage is %.4lf V\t\tFrequency is %.2lf Hz\n", voltage, frequency);
                }
            #ifdef AVOID_JITTER
            }
            #endif
    
            nanosleep(&sleep, NULL);
        }
  • §

    When interrupted by SIGINT, print a nice exit message.

        fprintf(stderr, "\r");
        printf("Exiting program...\n");
  • §

    If the blinking frequency is really low, join might wait a long time, so unblock the blinker before.

        blink_unblock(SIGALRM);
        pthread_join(blink, NULL);
    
        return 0;
    }