Guest User

hal_bb_gpio.c

a guest
Mar 17th, 2014
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.92 KB | None | 0 0
  1. /********************************************************************
  2. * Description:  hal_bb_gpio.c
  3. *               Driver for the BeagleBone GPIO pins
  4. *
  5. * Author: Ian McMahon <[email protected]>
  6. * License: GPL Version 2
  7. * Copyright (c) 2013.
  8. *
  9. ********************************************************************/
  10.  
  11.  
  12. #include "rtapi.h"     
  13. #include "rtapi_app.h" 
  14.  
  15. #include "hal.h"   
  16.  
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <fcntl.h>
  20. #include <sys/mman.h>
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23.  
  24. #include "beaglebone_gpio.h"
  25.  
  26. #if !defined(BUILD_SYS_USER_DSO)
  27. #error "This driver is for usermode threads only"
  28. #endif
  29. #if !defined(TARGET_PLATFORM_BEAGLEBONE)
  30. #error "This driver is for the BeagleBone platform only"
  31. #endif
  32.  
  33. #define MODNAME "hal_bb_gpio"
  34.  
  35. MODULE_AUTHOR("Ian McMahon");
  36. MODULE_DESCRIPTION("Driver for BeagleBone GPIO pins");
  37. MODULE_LICENSE("GPL");
  38.  
  39. #define HEADERS              2
  40. #define PINS_PER_HEADER  46
  41.  
  42. typedef struct {
  43.     hal_bit_t* led_pins[4];
  44.     hal_bit_t* input_pins[PINS_PER_HEADER * HEADERS]; // array of pointers to bits
  45.     hal_bit_t* output_pins[PINS_PER_HEADER * HEADERS]; // array of pointers to bits
  46.     hal_bit_t  led_inv[4];
  47.     hal_bit_t  input_inv[PINS_PER_HEADER * HEADERS];
  48.     hal_bit_t  output_inv[PINS_PER_HEADER * HEADERS];
  49. } port_data_t;
  50.  
  51. static port_data_t *port_data;
  52.  
  53. static const char *modname = MODNAME;
  54.  
  55. static void write_port(void *arg, long period);
  56. static void read_port(void *arg, long period);
  57.  
  58. static off_t start_addr_for_port(int port);
  59. static void configure_pin(bb_gpio_pin *pin, char mode);
  60.  
  61. static int comp_id;
  62. static int num_ports;
  63.  
  64. static char *user_leds;
  65. RTAPI_MP_STRING(user_leds, "user leds, comma separated.  0-3");
  66.  
  67. static char *input_pins;
  68. RTAPI_MP_STRING(input_pins, "input pins, comma separated.  P8 pins add 100, P9 pins add 200");
  69.  
  70. static char *output_pins;
  71. RTAPI_MP_STRING(output_pins, "output pins, comma separated.  P8 pins add 100, P9 pins add 200");
  72.  
  73. void configure_control_module() {
  74.     int fd = open("/dev/mem", O_RDWR);
  75.  
  76.     control_module = mmap(0, CONTROL_MODULE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, CONTROL_MODULE_START_ADDR);
  77.  
  78.     if(control_module == MAP_FAILED) {
  79.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: Unable to map Control Module: %s", modname, strerror(errno));
  80.         exit(1);
  81.     }
  82.  
  83.     close(fd);
  84. }
  85.  
  86. void configure_gpio_port(int n) {
  87.     int fd = open("/dev/mem", O_RDWR);
  88.  
  89.     gpio_ports[n] = hal_malloc(sizeof(bb_gpio_port));
  90.  
  91.     gpio_ports[n]->gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, start_addr_for_port(n));
  92.  
  93.     if(gpio_ports[n]->gpio_addr == MAP_FAILED) {
  94.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: Unable to map GPIO: %s", modname, strerror(errno));
  95.         exit(1);
  96.     }
  97.  
  98.     gpio_ports[n]->oe_reg = gpio_ports[n]->gpio_addr + GPIO_OE;
  99.     gpio_ports[n]->setdataout_reg = gpio_ports[n]->gpio_addr + GPIO_SETDATAOUT;
  100.     gpio_ports[n]->clrdataout_reg = gpio_ports[n]->gpio_addr + GPIO_CLEARDATAOUT;
  101.     gpio_ports[n]->datain_reg = gpio_ports[n]->gpio_addr + GPIO_DATAIN;
  102.  
  103.  
  104.     rtapi_print("memmapped gpio port %d to %p, oe: %p, set: %p, clr: %p\n", n, gpio_ports[n]->gpio_addr, gpio_ports[n]->oe_reg, gpio_ports[n]->setdataout_reg, gpio_ports[n]->clrdataout_reg);
  105.  
  106.     close(fd);
  107. }
  108.  
  109. int rtapi_app_main(void) {
  110.     char name[HAL_NAME_LEN + 1];
  111.     int n, retval;
  112.     char *data, *token;
  113.  
  114.     num_ports = 1;
  115.     n = 0; // port number... only one for now
  116.  
  117.     // init driver
  118.     comp_id = hal_init(modname);
  119.     if(comp_id < 0) {
  120.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: hal_init() failed\n", modname);
  121.         return -1;
  122.     }
  123.  
  124.     // allocate port memory
  125.     port_data = hal_malloc(num_ports * sizeof(port_data_t));
  126.     if(port_data == 0) {
  127.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: hal_malloc() failed\n", modname);
  128.         hal_exit(comp_id);
  129.         return -1;
  130.     }
  131.  
  132.     // map control module memory
  133.     configure_control_module();
  134.  
  135.     // configure userleds
  136.     if(user_leds != NULL) {
  137.         data = user_leds;
  138.         while((token = strtok(data, ",")) != NULL) {
  139.             int led = strtol(token, NULL, 10);
  140.  
  141.             data = NULL;
  142.  
  143.             if(user_led_gpio_pins[led].claimed != 0) {
  144.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: userled%d is not available as a GPIO.\n", modname, led);
  145.                 hal_exit(comp_id);
  146.                 return -1;
  147.             }
  148.  
  149.             // Add HAL pin
  150.             retval = hal_pin_bit_newf(HAL_IN, &(port_data->led_pins[led]), comp_id, "bb_gpio.userled%d", led);
  151.  
  152.             if(retval < 0) {
  153.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: userled %d could not export pin, err: %d\n", modname, led, retval);
  154.                 hal_exit(comp_id);
  155.                 return -1;
  156.             }
  157.  
  158.             // Add HAL parameter
  159.             retval = hal_param_bit_newf(HAL_RW, &(port_data->led_inv[led]), comp_id, "bb_gpio.userled%d.invert", led);
  160.  
  161.             if(retval < 0) {
  162.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: userled %d could not export pin, err: %d\n", modname, led, retval);
  163.                 hal_exit(comp_id);
  164.                 return -1;
  165.             }
  166.  
  167.             // Initialize HAL parameter
  168.             port_data->led_inv[led] = 0;
  169.  
  170.             int gpio_num = user_led_gpio_pins[led].port_num;
  171.             // configure gpio port if necessary
  172.             if(gpio_ports[gpio_num] == NULL) {
  173.                 configure_gpio_port(gpio_num);
  174.             }
  175.  
  176.             user_led_gpio_pins[led].port = gpio_ports[gpio_num];
  177.  
  178.             configure_pin(&user_led_gpio_pins[led], 'O');
  179.         }
  180.     }
  181.  
  182.     // configure input pins
  183.     if(input_pins != NULL) {
  184.         data = input_pins;
  185.         while((token = strtok(data, ",")) != NULL) {
  186.             int pin = strtol(token, NULL, 10);
  187.             int header;
  188.             bb_gpio_pin *bbpin;
  189.  
  190.             if(pin < 101 || pin > 246 || (pin > 146 && pin < 201)) {
  191.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: invalid pin number '%d'.  Valid pins are 101-146 for P8 pins, 201-246 for P9 pins.\n", modname, pin);
  192.                 hal_exit(comp_id);
  193.                 return -1;
  194.             }
  195.  
  196.             if(pin < 200) {
  197.                 pin -= 100;
  198.                 bbpin = &p8_pins[pin];
  199.                 header = 8;
  200.             } else {
  201.                 pin -= 200;
  202.                 bbpin = &p9_pins[pin];
  203.                 header = 9;
  204.             }
  205.  
  206.             if(bbpin->claimed != 0) {
  207.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d is not available as a GPIO.\n", modname, header, pin);
  208.                 hal_exit(comp_id);
  209.                 return -1;
  210.             }
  211.  
  212.             data = NULL; // after the first call, subsequent calls to strtok need to be on NULL
  213.  
  214.             // Add HAL pin
  215.             retval = hal_pin_bit_newf(HAL_OUT, &(port_data->input_pins[pin + (header - 8)*PINS_PER_HEADER]), comp_id, "bb_gpio.p%d.in-%02d", header, pin);
  216.  
  217.             if(retval < 0) {
  218.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d could not export pin, err: %d\n", modname, header, pin, retval);
  219.                 hal_exit(comp_id);
  220.                 return -1;
  221.             }
  222.  
  223.             // Add HAL parameter
  224.             retval = hal_param_bit_newf(HAL_RW, &(port_data->input_inv[pin + (header - 8)*PINS_PER_HEADER]), comp_id, "bb_gpio.p%d.in-%02d.invert", header, pin);
  225.  
  226.             if(retval < 0) {
  227.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d could not export pin, err: %d\n", modname, header, pin, retval);
  228.                 hal_exit(comp_id);
  229.                 return -1;
  230.             }
  231.  
  232.             // Initialize HAL parameter
  233.             port_data->input_inv[pin + (header - 8)*PINS_PER_HEADER] = 0;
  234.  
  235.             int gpio_num = bbpin->port_num;
  236.            
  237.             // configure gpio port if necessary
  238.             if(gpio_ports[gpio_num] == NULL) {
  239.                 configure_gpio_port(gpio_num);
  240.             }
  241.  
  242.             bbpin->port = gpio_ports[gpio_num];
  243.  
  244.             configure_pin(bbpin, 'U');
  245.             rtapi_print("pin %d maps to pin %d-%d, mode %d\n", pin, bbpin->port_num, bbpin->pin_num, bbpin->claimed);
  246.         }
  247.     }
  248.  
  249.     // configure output pins
  250.     if(output_pins != NULL) {
  251.         data = output_pins;
  252.         while((token = strtok(data, ",")) != NULL) {
  253.             int pin = strtol(token, NULL, 10);
  254.             int header;
  255.             bb_gpio_pin *bbpin;
  256.  
  257.             if(pin < 101 || pin > 246 || (pin > 146 && pin < 201)) {
  258.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: invalid pin number '%d'.  Valid pins are 101-146 for P8 pins, 201-246 for P9 pins.\n", modname, pin);
  259.                 hal_exit(comp_id);
  260.                 return -1;
  261.             }
  262.  
  263.             if(pin < 200) {
  264.                 pin -= 100;
  265.                 bbpin = &p8_pins[pin];
  266.                 header = 8;
  267.             } else {
  268.                 pin -= 200;
  269.                 bbpin = &p9_pins[pin];
  270.                 header = 9;
  271.             }
  272.  
  273.             if(bbpin->claimed != 0) {
  274.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d is not available as a GPIO.\n", modname, header, pin);
  275.                 hal_exit(comp_id);
  276.                 return -1;
  277.             }
  278.  
  279.             data = NULL; // after the first call, subsequent calls to strtok need to be on NULL
  280.  
  281.             // Add HAL pin
  282.             retval = hal_pin_bit_newf(HAL_IN, &(port_data->output_pins[pin + (header - 8)*PINS_PER_HEADER]), comp_id, "bb_gpio.p%d.out-%02d", header, pin);
  283.  
  284.             if(retval < 0) {
  285.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d could not export pin, err: %d\n", modname, header, pin, retval);
  286.                 hal_exit(comp_id);
  287.                 return -1;
  288.             }
  289.  
  290.             // Add HAL parameter
  291.             retval = hal_param_bit_newf(HAL_RW, &(port_data->output_inv[pin + (header - 8)*PINS_PER_HEADER]), comp_id, "bb_gpio.p%d.out-%02d.invert", header, pin);
  292.  
  293.             if(retval < 0) {
  294.                 rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: pin p%d.%02d could not export pin, err: %d\n", modname, header, pin, retval);
  295.                 hal_exit(comp_id);
  296.                 return -1;
  297.             }
  298.  
  299.             // Initialize HAL parameter
  300.             port_data->output_inv[pin + (header - 8)*PINS_PER_HEADER] = 0;
  301.  
  302.             int gpio_num = bbpin->port_num;
  303.            
  304.             // configure gpio port if necessary
  305.             if(gpio_ports[gpio_num] == NULL) {
  306.                 configure_gpio_port(gpio_num);
  307.             }
  308.  
  309.             bbpin->port = gpio_ports[gpio_num];
  310.  
  311.             configure_pin(bbpin, 'O');
  312.         }
  313.     }
  314.  
  315.  
  316.     // export functions
  317.     rtapi_snprintf(name, sizeof(name), "bb_gpio.write");
  318.     retval = hal_export_funct(name, write_port, port_data, 0, 0, comp_id);
  319.     if(retval < 0) {
  320.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: port %d write funct export failed\n", modname, n);
  321.         hal_exit(comp_id);
  322.         return -1;
  323.     }
  324.    
  325.     rtapi_snprintf(name, sizeof(name), "bb_gpio.read");
  326.     retval = hal_export_funct(name, read_port, port_data, 0, 0, comp_id);
  327.     if(retval < 0) {
  328.         rtapi_print_msg(RTAPI_MSG_ERR, "%s: ERROR: port %d read funct export failed\n", modname, n);
  329.         hal_exit(comp_id);
  330.         return -1;
  331.     }
  332.  
  333.     rtapi_print_msg(RTAPI_MSG_INFO, "%s: installed driver\n", modname);
  334.  
  335.     hal_ready(comp_id);
  336.  
  337.     return 0;
  338. }
  339.  
  340. void rtapi_app_exit(void) {
  341.  
  342.     hal_exit(comp_id);
  343. }
  344.  
  345. static void write_port(void *arg, long period) {
  346.     int i;
  347.     port_data_t *port = (port_data_t *)arg;
  348.  
  349.     // set userled states
  350.     for(i=0; i<4; i++) {
  351.         if(port->led_pins[i] == NULL) continue; // short circuit if hal hasn't malloc'd a bit at this location
  352.  
  353.         bb_gpio_pin pin = user_led_gpio_pins[i];
  354.  
  355.         if(pin.claimed != 'O') continue; // if we somehow get here but the pin isn't claimed as output, short circuit
  356.  
  357.         if((*port->led_pins[i] ^ port->led_inv[i]) == 0)
  358.             *(pin.port->clrdataout_reg) = (1 << pin.pin_num);
  359.         else
  360.             *(pin.port->setdataout_reg) = (1 << pin.pin_num);
  361.     }
  362.  
  363.     // set output states
  364.     for(i=1; i<=HEADERS*PINS_PER_HEADER; i++) {
  365.         if(port->output_pins[i] == NULL) continue; // short circuit if hal hasn't malloc'd a bit at this location
  366.  
  367.         bb_gpio_pin pin;
  368.  
  369.         if(i<PINS_PER_HEADER)
  370.             pin = p8_pins[i];
  371.         else
  372.             pin = p9_pins[i - PINS_PER_HEADER];
  373.  
  374.         if(pin.claimed != 'O') continue; // if we somehow get here but the pin isn't claimed as output, short circuit
  375.  
  376.         if((*port->output_pins[i] ^ port->output_inv[i]) == 0)
  377.             *(pin.port->clrdataout_reg) = (1 << pin.pin_num);
  378.         else
  379.             *(pin.port->setdataout_reg) = (1 << pin.pin_num);
  380.     }
  381. }
  382.  
  383.  
  384. static void read_port(void *arg, long period) {
  385.     int i;
  386.     port_data_t *port = (port_data_t *)arg;
  387.  
  388.     // read input states
  389.     for(i=1; i<=HEADERS*PINS_PER_HEADER; i++) {
  390.         if(port->input_pins[i] == NULL) continue; // short circuit if hal hasn't malloc'd a bit at this location
  391.  
  392.         bb_gpio_pin pin;
  393.  
  394.         if(i<PINS_PER_HEADER) {
  395.             pin = p8_pins[i];
  396.         } else {
  397.             pin = p9_pins[i - PINS_PER_HEADER];
  398.         }
  399.  
  400.  
  401.         if(!(pin.claimed == 'I' || pin.claimed == 'U' || pin.claimed == 'D')) continue; // if we get here but the pin isn't claimed as input, short circuit
  402.  
  403.         *port->input_pins[i] = ((*(pin.port->datain_reg) & (1 << pin.pin_num))  >> pin.pin_num) ^ port->input_inv[i];
  404.     }
  405. }
  406.  
  407.  
  408.  
  409. off_t start_addr_for_port(int port) {
  410.     switch(port) {
  411.         case 0:
  412.             return GPIO0_START_ADDR;
  413.             break;
  414.         case 1:
  415.             return GPIO1_START_ADDR;
  416.             break;
  417.         case 2:
  418.             return GPIO2_START_ADDR;
  419.             break;
  420.         case 3:
  421.             return GPIO3_START_ADDR;
  422.             break;
  423.         default:
  424.             return -1;
  425.             break;
  426.     }
  427. }
  428.  
  429.  
  430. void configure_pin(bb_gpio_pin *pin, char mode) {
  431.     volatile unsigned int *control_reg = control_module + pin->control_offset;
  432.     pin->claimed = mode;
  433.     switch(mode) {
  434.         case 'O':
  435.             *(pin->port->oe_reg) &= ~(1 << pin->pin_num); // 0 in OE is output enable
  436.             *control_reg = PIN_MODE7 | PIN_PULLUD_DISABLED | PIN_RX_DISABLED;
  437.             break;
  438.         case 'I':
  439.             *(pin->port->oe_reg) |= (1 << pin->pin_num); // 1 in OE is input
  440.             *control_reg = PIN_MODE7 | PIN_PULLUD_DISABLED | PIN_RX_ENABLED;
  441.             break;
  442.         case 'U':
  443.             *(pin->port->oe_reg) |= (1 << pin->pin_num); // 1 in OE is input
  444.             *control_reg = PIN_MODE7 | PIN_PULLUD_ENABLED | PIN_PULLUP | PIN_RX_ENABLED;
  445.             break;
  446.         case 'D':
  447.             *(pin->port->oe_reg) |= (1 << pin->pin_num); // 1 in OE is input
  448.             *control_reg = PIN_MODE7 | PIN_PULLUD_ENABLED | PIN_PULLDOWN | PIN_RX_ENABLED;
  449.             break;
  450.         default:
  451.             break;
  452.     }
  453. }
Advertisement
Add Comment
Please, Sign In to add comment