1

For my project, I am attempting to write a code that will (1) monitor an input pin for a rising edge value and (2) toggle an output pin on and off in response. The goal is to determine the latency distributions for different code implementations for different frequencies on various microcontroller and small computer platforms (Arduino, RPi, Beaglebone Black). I'm currently working on the BBB (Debian v7.8) and trying to implement a /dev/mem code, but the code is exiting for an undetermined reason before all of the register values are set.

Here is the whole code (EDITED after adding error code returns for MMAP()):

 /* 1.0 Pre-Main Function Operations */
/* 1.1 Definitions */
#define GPIO_0_START 0x44E07000 // GPIO_0 Bank (Not Used in Current Build)
#define GPIO_0_END 0x44E07FFF
#define GPIO_1_START 0x4804C000 // GPIO_1 Bank (PIN_LED is located here, GPIO1_21)
#define GPIO_1_END 0x4804CFFF
#define GPIO_2_START 0x481AA000 // GPIO_2 Bank ({PIN_MONITOR, PIN_CONFIRM, PIN_RESPONSE} are located here)
#define GPIO_2_END 0x481AAFFF
#define GPIO_3_START 0x481AF000 // GPIO_3 Bank (Not Used in Current Build)
#define GPIO_3_END 0x481AFFFF

/* 1.2 GPIO Pad Memory Sizes */
#define GPIO_0_SIZE (GPIO_0_END - GPIO_0_START)
#define GPIO_1_SIZE (GPIO_1_END - GPIO_1_START)
#define GPIO_2_SIZE (GPIO_2_END - GPIO_2_START)
#define GPIO_3_SIZE (GPIO_3_END - GPIO_3_START)

/* 1.3 Memory Offsets for GPIO Bit Registers */
// Values taken from Table 25-5 (GPIO Registers) of the AM335X Technical Reference Manual
#define GPIO_REVISION 0x0
#define GPIO_SYSCONFIG 0x10
#define GPIO_EOI 0x20
#define GPIO_IRQSTATUS_RAW_0 0x24
#define GPIO_IRQSTATUS_RAW_1 0x28
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_IRQSTATUS_SET_0 0x34
#define GPIO_IRQSTATUS_SET_1 0x38
#define GPIO_IRQSTATUS_CLR_0 0x3C
#define GPIO_IRQSTATUS_CLR_1 0x40
#define GPIO_IRQWAKEN_0 0x44
#define GPIO_SYSSTATUS 0x114
#define GPIO_CTRL 0x130
#define GPIO_OE 0x134
#define GPIO_DATAIN 0x138
#define GPIO_DATAOUT 0x13C
#define GPIO_LEVELDETECT0 0x140
#define GPIO_LEVELDETECT1 0x144
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define GPIO_DEBOUNCENABLE 0x150
#define GPIO_DEBOUNCINGTIME 0x154
#define GPIO_CLEARDATAOUT 0x190
#define GPIO_SETDATAOUT 0x194

/* 1.4 Register Pin NUmbers */
// Definition                       ~Name~  ~ADDRESS~  ~OFFSET~
#define PIN_MONITOR 70          // GPIO2_6    0x8A0      0A0
#define PIN_CONFIRM 73          // GPIO2_9    0x8AC      0AC
#define PIN_LED 21              // GPIO1_21    ---       ---    // USR0 is controlled via another file system
#define PIN_RESPONSE 74         // GPIO2_10   0x8B0      0B0
#define PIN_MONITOR_OFFSET 6
#define PIN_CONFIRM_OFFSET 9
#define PIN_LED_OFFSET 21
#define PIN_RESPONSE_OFFSET 10

/* 1.5 GPIO Directory File Path */
#define DEV_MEM_GPIO_DIR "/dev/mem"

/* 1.6 Bit Setting Commands for GPIO pins & Registers */
#define PIN_MONITOR_0 (0<<PIN_MONITOR_OFFSET)
#define PIN_MONITOR_1 (1<<PIN_MONITOR_OFFSET)
#define PIN_LED_0 (0<<PIN_LED_OFFSET)
#define PIN_LED_1 (1<<PIN_LED_OFFSET)
#define PIN_CONFIRM_0 (0<<PIN_CONFIRM_OFFSET)
#define PIN_CONFIRM_1 (1<<PIN_CONFIRM_OFFSET)
#define PIN_RESPONSE_0 (0<<PIN_RESPONSE_OFFSET)
#define PIN_RESPONSE_1 (1<<PIN_RESPONSE_OFFSET)

/* 2.0 Inclusions */
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <stropts.h>
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

/* 3.0 Function Definitions */
/* None at this time */

/* 4.0 Main Function */
int main() {
        /* 4.1 Initialize GPIO Array Address Pointers */
        volatile unsigned int *gpio1_addr = NULL;
        volatile unsigned int *gpio2_addr = NULL;

        /* 4.2 Initialize GPIO Register Pointers */
        /* 4.2.1 GPIO1 */
        volatile unsigned int *gpio1_oe_addr = NULL;
        volatile unsigned int *gpio1_dataout_addr = NULL;
        volatile unsigned int *gpio1_cleardataout_addr = NULL;
        volatile unsigned int *gpio1_setdataout_addr = NULL;

        /* 4.2.2 GPIO2 */
        volatile unsigned int *gpio2_irqstatus_raw0_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_raw1_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_0_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_1_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_set0_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_set1_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_clr0_addr = NULL;
        volatile unsigned int *gpio2_irqstatus_clr1_addr = NULL;
        volatile unsigned int *gpio2_irqwaken0_addr = NULL;
        volatile unsigned int *gpio2_irqwaken1_addr = NULL;
        volatile unsigned int *gpio2_oe_addr = NULL;
        volatile unsigned int *gpio2_datain_addr = NULL;
        volatile unsigned int *gpio2_dataout_addr = NULL;
        volatile unsigned int *gpio2_risingdetect_addr = NULL;
        volatile unsigned int *gpio2_debounenable_addr = NULL;
        volatile unsigned int *gpio2_debouncingtime_addr = NULL;
        volatile unsigned int *gpio2_cleardataout_addr = NULL;
        volatile unsigned int *gpio2_setdataout_addr = NULL;

        /* 4.3 Accessing /dev/mem/ */
        int fd = open(DEV_MEM_GPIO_DIR,O_RDWR);
        cout << "FD Open.\n";

        /* 4.4 Establishing Addresses */
        // 4.4.1 GPIO Bank Addresses
        printf("Attempting to map GPIO_1.\nGPIO_1 starts at %X, ends at %X, and has size %X.\n",GPIO_1_START,GPIO_1_END,GPIO_1_SIZE);
        gpio1_addr = (unsigned int*)mmap(0, GPIO_1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_1_START);
        if (gpio1_addr == MAP_FAILED) {
            cout << "Unable to map GPIO_1.\n";
            printf("Error Value Returned is: %s.\n",strerror(errno));
            exit(1);
        } else {
            cout << "GPIO_1 mapped successfully.\n";
            cout << "GPIO_1 mmap result is: " << gpio1_addr << endl;
        }
        printf("Attempting to map GPIO_2.\nGPIO_2 starts at %X, ends at %X, and has size %X.\n",GPIO_2_START,GPIO_2_END,GPIO_2_SIZE);
        gpio2_addr = (unsigned int*)mmap(0, GPIO_2_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_2_START);
        if (gpio2_addr == MAP_FAILED) {
            cout << "Unable to map GPIO_2.\n";
            printf("Error Value Returned is: %s.\n",strerror(errno));
            exit(1);
        } else {
            cout << "GPIO_2 mapped successfully.\n";
            cout << "GPIO_2 mmap result is: " << gpio2_addr << endl;
        }
        cout << "MMAP Complete.\n";

        /* 4.4.2 Register Offsets */
        /* 4.4.2.1 GPIO1 Registers */
        gpio1_oe_addr = gpio1_addr + GPIO_OE;
        gpio1_dataout_addr = gpio1_addr + GPIO_DATAOUT;
        gpio1_cleardataout_addr = gpio1_addr + GPIO_CLEARDATAOUT;
        gpio1_setdataout_addr = gpio1_addr + GPIO_SETDATAOUT;
        cout << "GPIO 1 Register Addresses Defined.\n";

        /* 4.4.2.2 GPIO2 Registers */
        gpio2_irqstatus_raw0_addr = gpio2_addr + GPIO_IRQSTATUS_RAW_0;
        gpio2_irqstatus_raw1_addr = gpio2_addr + GPIO_IRQSTATUS_RAW_1;
        gpio2_irqstatus_0_addr = gpio2_addr + GPIO_IRQSTATUS_0;
        gpio2_irqstatus_1_addr = gpio2_addr + GPIO_IRQSTATUS_1;
        gpio2_irqstatus_set0_addr = gpio2_addr + GPIO_IRQSTATUS_SET_0;
        gpio2_irqstatus_set1_addr = gpio2_addr + GPIO_IRQSTATUS_SET_1;
        gpio2_irqstatus_clr0_addr = gpio2_addr + GPIO_IRQSTATUS_CLR_0;
        gpio2_irqstatus_clr1_addr = gpio2_addr + GPIO_IRQSTATUS_CLR_1;
        gpio2_irqwaken0_addr = gpio2_addr + GPIO_IRQWAKEN_0;
        gpio2_irqwaken1_addr = gpio2_addr + GPIO_IRQWAKEN_1;
        gpio2_oe_addr = gpio2_addr + GPIO_OE;
        gpio2_datain_addr = gpio2_addr + GPIO_DATAIN;
        gpio2_dataout_addr = gpio2_addr + GPIO_DATAOUT;
        gpio2_risingdetect_addr = gpio2_addr + GPIO_RISINGDETECT;
        gpio2_cleardataout_addr = gpio2_addr + GPIO_CLEARDATAOUT;
        gpio2_setdataout_addr = gpio2_addr + GPIO_SETDATAOUT;
        cout << "GPIO 2 Register Addresses Defined.\n";

        /* 4.5 Establish Pin Modes */
        cout << "Establishing Pin Modes.\n";
        *gpio2_oe_addr = PIN_MONITOR_0;
        cout << "PIN_MONITOR established as INPUT.\n";
        *gpio1_oe_addr = PIN_LED_1;
        cout << "PIN_LED established as OUTPUT.\n";
        *gpio2_oe_addr = (*gpio2_oe_addr | PIN_CONFIRM_1);
        cout << "PIN_CONFIRM established as OUTPUT.\n";
        *gpio2_oe_addr = (*gpio2_oe_addr | PIN_RESPONSE_1);
        cout << "PIN_RESPONSE established as OUTPUT.\n";
        cout << "Pin Modes Set.\n";

        /* 4.6 Confirm Platform Readiness */
        cout << "Checking Platform Readiness.\n";
        *gpio1_setdataout_addr = PIN_LED_1;
        cout << "PIN_LED on.\n";
        *gpio2_setdataout_addr = PIN_CONFIRM_1;
        cout << "PIN_CONFIRM on.\n";
        cout << "Platform Ready.\n";

        /* 4.7 Primary Experiment Code || Loop */
        uint32_t pollDATA[3] = {0,0,0};
        uint32_t compare_DATAIN_PIN_MONITOR = 32;
        uint32_t pollCompare[3] = {compare_DATAIN_PIN_MONITOR,compare_DATAIN_PIN_MONITOR,0};
        int run = 1;
        cout << "Running Experiment.\n";
        while (run == 1) {
                pollDATA[0] = *gpio2_datain_addr; // Read GPIO2 DATAIN
                if ((pollDATA[0] == pollCompare[0]) && (pollDATA[1] == pollCompare[1]) && (pollDATA[2] == pollCompare[2])) {
                        *gpio2_setdataout_addr = PIN_RESPONSE_1;
                        usleep(1);
                        *gpio2_cleardataout_addr = PIN_RESPONSE_1;
                }
                pollDATA[2] = pollDATA[1];
                pollDATA[1] = pollDATA[0];
        }
        cout << "Experiment Ended.\n";

        /* 4.8 Post-Experiment Procedures */
        *gpio1_cleardataout_addr = PIN_LED_1;
        *gpio2_cleardataout_addr = PIN_CONFIRM_1;
        *gpio2_cleardataout_addr = PIN_RESPONSE_1;
        cout << "Program Ended.\n";
        return 0;
}

Using the output messages, I have determined that the code exits when it gets to the first bit-setting attempt:

    /* 4.5 Establish Pin Modes */
    cout << "Establishing Pin Modes.\n";
    *gpio2_oe_addr = PIN_MONITOR_0;
    cout << "PIN_MONITOR established as INPUT.\n";

I see the first output shown in the snippet above ("Establishing Pin Modes."), but then the code exits. Based on the sample codes that I have seen at this link - Driving Beaglebone GPIO through /dev/mem - I think that I might need to do something like this for all the register addresses I intend to use:

unsigned int reg;
reg = *gpio_reg_addr;
reg = reg & (0xFFFFFF - BIT_SET_COMMAND)
*gpio_reg_addr = reg;

but I have no idea why. Is that assumption correct and if so, why? I did read through the AM335x TRM but I must have missed this step. Any help is appreciated.

A few qualifying statements before anyone tries to deep-dive the code:

(1) I am new to C/C++ programming and Linux. All of my previous coding experience has been Matlab/Simulink and Labview. It would not be farfetched to suggest that I have no idea what I am doing.

(2) What this code should do is to read the 32b value at *gpio2_datain_addr and, when it sees that the 3 most recent read values have been {HIGH, HIGH, LOW}, set PIN_RESPONSE to HIGH, pause for 1ns, then set PIN_RESPONSE to LOW.

(3) Yes, I have checked the DeviceTree and the pins should be configured correctly for GPIO operations.

(4) EDIT: Yes, I am aware that all of my code under Section 1.X are properly called MACROS or definitions, but I refer to them by what purpose they serve in the code versus what they're nominally referred to sans-context. It's more to help me know what the particular information does rather than what it is. See statement (1) for further explanation.

(5) EDIT: As per sawdust's suggestion, I implemented exit code checks on the mmap() calls. The return value is 1 for both mmap() calls. The code is still exiting at the location that I specified earlier in the OP, Section 4.5 Establishing Pin Modes. Specifically, the line that seems to cause the problem is *gpio2_oe_addr = PIN_MONITOR_0.

For reference, the current program output is (EDITED) as follows:

FD Open. Attempting to map GPIO_1. GPIO_1 starts at 4804C000, ends at 4804CFFF, and has size FFF. GPIO_1 mapped successfully. GPIO_1 mmap result is: 1 Attempting to map GPIO_2. GPIO_2 starts at 481AA000, ends at 481AAFFF, and has size FFF. GPIO_2 mapped successfully. GPIO_2 mmap result is: 1 MMAP Complete. GPIO_1 Register Addresses Defined. GPIO_2 Register Addresses Defined. Establishing Pin Modes.

Thanks!

Community
  • 1
  • 1
reroc
  • 11
  • 3
  • 1
    *"the code is exiting for an undetermined reason"* -- Did you check for an exit code? Did you enable a [core dump](http://en.linuxreviews.org/HOWTO_enable_core-dumps)? Did you try using `strace ...`? – sawdust Apr 29 '16 at 00:06
  • Your program does not bother to check for error returns from each system call. That's bad programming, especially when your program does not behave as expected. If you did have error checking, you'd probably be informed that the **mmap()** syscalls were not successful. BTW what you call *"operations"* and *"commands"* in "section 1.x" of your program do not generate code, and are properly called declarations and/or macro definitions. – sawdust Apr 29 '16 at 00:30
  • Hi sawdust, thanks for your responses. I haven't checked for an exit code on the mmap(), because I assumed the program would fail after the mmap() commands earlier in the code. That's probably just a bad habit from my Matlab background. I'll implement those checks now, but, should the mmap() commands be what are failing, i.e. MAP_FAILED, how do I try to fix that? – reroc Apr 29 '16 at 13:32
  • Okay, I implemented the error returns using `errno.h` and `strerror()`. The output was that `mmap()` was successful in both instances that it is used in the code. – reroc Apr 29 '16 at 14:19
  • *"The code is still exiting ..."* -- So enable [core dump](http://stackoverflow.com/questions/2919378/how-to-enable-core-dump-in-my-linux-c-program). *"The return value is 1 for both ..."* -- Those are not successful returns. (1) The two mappings cannot have the same value. (2) A value of 1 is not page aligned; therefore it is a bogus address. BTW: You need to check the return from all syscalls, e.g. **open()**. Your memory sizes are short by one; they each need a `+ 1`. That's all I see. – sawdust Apr 29 '16 at 18:44

0 Answers0