diff --git a/docs/src/Master_Documentation.txt b/docs/src/Master_Documentation.txt index fd916f9786c..d3243e67c73 100644 --- a/docs/src/Master_Documentation.txt +++ b/docs/src/Master_Documentation.txt @@ -191,6 +191,8 @@ include::drivers/ax5214h.txt[] include::drivers/gs2.txt[] +include::drivers/hal_pi_gpio[] + include::drivers/hostmot2.txt[] include::drivers/motenc.txt[] diff --git a/docs/src/drivers/hal_pi_gpio.txt b/docs/src/drivers/hal_pi_gpio.txt new file mode 100644 index 00000000000..cdb4d105da2 --- /dev/null +++ b/docs/src/drivers/hal_pi_gpio.txt @@ -0,0 +1,106 @@ +[[cha:hal_pi_gpio-driver]] + += HAL Driver for Raspberry Pi GPIO pins + +Note: This driver will not be compiled into images aimed at non-ARM CPUS. +It is only really intended to work on the Raspberry Pi. It may, or may not, work on similar boards or direct clones. + +== Purpose + +This driver allows the use of the Rapberry Pi GPIO pins in a way analagous to the parallel port driver on x86 PCs. It can use the same step generators, encoder counters and similar components. + +== Usage + +---- +loadrt hal_pi_gpio dir=0x13407 exclude=0x1F64BF8 +---- + +The "dir" mask determines whether the pins are inputs and outputs, the exclude mask prevents the driver from using the pins (and so allows them to be used for their normal RPi purpses such as SPI or UART) + +The mask can be in decimal or hexadecimal (hex may be easier as there will be no carries) + +Add up the values for all pins that should be configured as output, and for all pins that should be excluded according to the following table. + +[cols="1,1,1,1"] +|=== +| GPIO Num | Decimal | Hex | Pin Num + +| 2 | 1 | 0x00000001 | 3 +| 3 | 2 | 0x00000002 | 5 +| 4 | 4 | 0x00000004 | 7 +| 5 | 8 | 0x00000008 | 29 +| 6 | 16 | 0x00000010 | 31 +| 7 | 32 | 0x00000020 | 26 +| 8 | 64 | 0x00000040 | 24 +| 9 | 128 | 0x00000080 | 21 +| 10 | 256 | 0x00000100 | 19 +| 11 | 512 | 0x00000200 | 23 +| 12 | 1024 | 0x00000400 | 32 +| 13 | 2048 | 0x00000800 | 33 +| 14 | 4096 | 0x00001000 | 8 +| 15 | 8192 | 0x00002000 | 10 +| 16 | 16384 | 0x00004000 | 36 +| 17 | 32768 | 0x00008000 | 11 +| 18 | 65536 | 0x00010000 | 12 +| 19 | 131072 | 0x00020000 | 35 +| 20 | 262144 | 0x00040000 | 38 +| 21 | 524288 | 0x00080000 | 40 +| 22 | 1048576 | 0x00100000 | 15 +| 23 | 2097152 | 0x00200000 | 16 +| 24 | 4194304 | 0x00400000 | 18 +| 25 | 8388608 | 0x00800000 | 22 +| 26 | 16777216 | 0x01000000 | 37 +| 27 | 33554432 | 0x02000000 | 13 +|=== + +Note that in the calculation of the masks the GPIO numbers are used. Whereas in the naming of the HAL pins it is the Raspberry Pi header pin numbers. + +So, for example, if you enable GPIO 17 as an output (dir=0x200) then that output will be controlled by the hal pin *hal_pi_gpio.pin-11-out*. + + +== Pins + +* hal_pi_gpio.pin-NN-out +* hal_pi_gpio.pin-NN-in + +Depending on the dir and exclude masks. + +== Parameters + +Only the standard timing parameters which are created for all components exist. + +*hal_pi_gpio.read.tmax +*hal_pi_gpio.read.tmax-increased +*hal_pi_gpio.write.tmax +*hal_pi_gpio.write.tmax-increased + +For unknown reasons the driver also creates HAL _pins_ to indicate timing + +*hal_pi_gpio.read.time +*hal_pi_gpio.write.time + + +== Functions + +* 'hal_pi_gpio.read' - Add this to the base thread to update the HAL pin values to match the physical input values. + +* 'hal_pi_gpio.write' - Add this to the base thread to update the physical pins to match the HAL values. + +Typically the 'read' function will be early in the call list, before any encoder counters and the 'write' function will be later in the call list, after stepgen.make-pulses. + + +== Pin Numbering + +The GPIO connector and the pinout has been consistent since around 2015. +These older Pi models are probably a poor choice for LinuxCNC anyway. +However, this driver is designed to work with them, and will detect and correctly configure for the two alternative pinouts. + +The current pinout mapping between GPIO numbers and connector pin numbers is included in the table above. + +Note that the config string uses GPIO numbers, but once the driver is loaded the HAL pin names refer to connector pin numbers. + +This may be more logical than it first appears. When setting up you need to configure enough pins of each type, whilst avoiding overwriting any other functions that your system needs. Then once the driver is loaded, in the HAL layer you just want to know where to connect the wires for each HAL pin. + +== Known Bugs + +At the moment (2023-07-16) this driver only seems to work on Raspbian as the generic Debian image does not set up the correct interfaces in /dev/gpiomem and restricts access to the /sys/mem interface. diff --git a/docs/src/index.tmpl b/docs/src/index.tmpl index 185bb571147..75c3a230022 100644 --- a/docs/src/index.tmpl +++ b/docs/src/index.tmpl @@ -217,6 +217,7 @@ function setup_page(){
  • AX5214H Driver
  • General Mechatronics GM6-PCI Driver
  • GS2 Driver
  • +
  • Raspberry Pi GPIO Driver
  • Mesa HostMot2 Driver
  • Motenc Driver
  • Modbus to HAL Driver
  • diff --git a/src/hal/drivers/cpuinfo.c b/src/hal/drivers/cpuinfo.c index 8c9db527377..d96ee48ef1a 100644 --- a/src/hal/drivers/cpuinfo.c +++ b/src/hal/drivers/cpuinfo.c @@ -1,10 +1,8 @@ /* -Copyright (c) 2012 Ben Croston - -Revised by Ernesto Lo Valvo (ernesto.lovalvo@unipa.it) (19/03/2022) - Added new version of Raspberry Pi4 and Raspberry Pi 400 - Revised for version 3B (15/01/2021) - https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-revision-codes +Copyright (c) 2023 Andy Pugh +Initially (c) 2012 Ben Croston +Rewritten according to advice at +https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#best-practice-for-revision-code-usage Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -27,86 +25,43 @@ SOFTWARE. #include #include +#include +#include "rtapi.h" -char *get_cpuinfo_revision(char *revision) +int get_rpi_revision(void) { FILE *fp; char buffer[1024]; char *r; + unsigned int revision; if ((fp = fopen("/sys/firmware/devicetree/base/model", "r")) == NULL) - return NULL; + return -1; r = fgets(buffer, sizeof(buffer) , fp); fclose(fp); - if (!r) return NULL; - + if (!r) return -1; + + rtapi_print_msg(RTAPI_MSG_INFO, "%s found\n", buffer); + if (strncmp(buffer, "Raspberry",9) != 0) - return NULL; + return -1; if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) - return NULL; + return -1; while(!feof(fp)) { if (fgets(buffer, sizeof(buffer) , fp)){ - sscanf(buffer, "Revision : %s", revision); + sscanf(buffer, "Revision : %x", &revision); } } fclose(fp); - return revision; -} - - -int get_rpi_revision(void) -{ - char revision[1024] = {'\0'}; - - if (get_cpuinfo_revision(revision) == NULL) - return -1; - - if ((strcmp(revision, "0002") == 0) || - (strcmp(revision, "1000002") == 0 ) || - (strcmp(revision, "0003") == 0) || - (strcmp(revision, "1000003") == 0 )) - return 1; - else if ((strcmp(revision, "0004") == 0) || - (strcmp(revision, "1000004") == 0 ) || - (strcmp(revision, "0005") == 0) || - (strcmp(revision, "1000005") == 0 ) || - (strcmp(revision, "0006") == 0) || - (strcmp(revision, "1000006") == 0 )) + if ( ! (revision & 0x800000)){ // old-style revision code + if ((revision & 0xFF) <= 3) return 1; return 2; - else if ((strcmp(revision, "a01040") == 0) || /* Raspberry Pi 2B */ - (strcmp(revision, "a01041") == 0) || - (strcmp(revision, "a02042") == 0) || - (strcmp(revision, "a21041") == 0) || - (strcmp(revision, "a22042") == 0)) - return 3; - else if ((strcmp(revision, "a02082") == 0) || /* Raspberry Pi 3B */ - (strcmp(revision, "a22082") == 0) || - (strcmp(revision, "a32082") == 0) || - (strcmp(revision, "a52082") == 0) || - (strcmp(revision, "a22083") == 0) || - (strcmp(revision, "a020d3") == 0)) /* Raspberry Pi 3B+ */ - return 4; - else if ((strcmp(revision, "a03111") == 0) || /* Raspberry Pi 4B rev. 1.1, 1.2, 1.4, 1.5 */ - (strcmp(revision, "b03111") == 0) || - (strcmp(revision, "c03111") == 0) || - (strcmp(revision, "b03112") == 0) || - (strcmp(revision, "c03112") == 0) || - (strcmp(revision, "b03114") == 0) || - (strcmp(revision, "c03114") == 0) || - (strcmp(revision, "d03114") == 0) || - (strcmp(revision, "b03115") == 0) || - (strcmp(revision, "c03115") == 0) || - (strcmp(revision, "d03115") == 0)) - return 5; - else if ((strcmp(revision, "c03130") == 0) || /* Raspberry Pi 400 */ - (strcmp(revision, "c03131") == 0)) - return 6; - else /* assume rev 7 */ - return 7; + } else { + return ((revision >> 4) & 0xFF); + } } - diff --git a/src/hal/drivers/hal_pi_gpio.c b/src/hal/drivers/hal_pi_gpio.c index 2760f585903..4abc0df3248 100644 --- a/src/hal/drivers/hal_pi_gpio.c +++ b/src/hal/drivers/hal_pi_gpio.c @@ -47,11 +47,11 @@ s********************************************************************/ // http://elinux.org/index.php?title=RPi_Low-level_peripherals&printable=yes // Rev 1 Raspberry: static unsigned char rev1_gpios[] = {0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, 24, 25}; -static unsigned char rev1_pins[] = {3, 5, 7, 26, 24, 21, 19, 23, 8, 10, 11, 12, 13, 15, 16, 18, 22}; +static unsigned char rev1_pins[] = {3, 5, 7, 26, 24, 21, 19, 23, 8, 10, 11, 12, 13, 15, 16, 18, 22}; // Rev2 Raspberry: static unsigned char rev2_gpios[] = {2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 22, 23, 24, 25, 27}; -static unsigned char rev2_pins[] = {3, 5, 7, 26, 24, 21, 19, 23, 8, 10, 11, 12, 15, 16, 18, 22, 13}; +static unsigned char rev2_pins[] = {3, 5, 7, 26, 24, 21, 19, 23, 8, 10, 11, 12, 15, 16, 18, 22, 13}; // Raspberry2/3: static unsigned char rpi2_gpios[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }; @@ -237,50 +237,30 @@ int rtapi_app_main(void) rtapi_print_msg(RTAPI_MSG_INFO, "%d cores rev %d", ncores, rev); switch (rev) { - case 6: - rtapi_print_msg(RTAPI_MSG_INFO, "RaspberryPi400\n"); - pins = rpi2_pins; - gpios = rpi2_gpios; - npins = sizeof(rpi2_pins); - break; - case 5: - rtapi_print_msg(RTAPI_MSG_INFO, "Raspberry4\n"); - pins = rpi2_pins; - gpios = rpi2_gpios; - npins = sizeof(rpi2_pins); - break; - case 4: - rtapi_print_msg(RTAPI_MSG_INFO, "Raspberry3\n"); - pins = rpi2_pins; - gpios = rpi2_gpios; - npins = sizeof(rpi2_pins); - break; - - case 3: - rtapi_print_msg(RTAPI_MSG_INFO, "Raspberry2\n"); - pins = rpi2_pins; - gpios = rpi2_gpios; - npins = sizeof(rpi2_pins); - break; - - case 1: - rtapi_print_msg(RTAPI_MSG_INFO, "Raspberry1 rev 1.0\n"); + case 1: pins = rev1_pins; gpios = rev1_gpios; npins = sizeof(rev1_pins); break; - - case 2: - rtapi_print_msg(RTAPI_MSG_INFO, "Raspberry1 Rev 2.0\n"); + case 2: pins = rev2_pins; gpios = rev2_gpios; npins = sizeof(rev2_pins); break; - - default: - rtapi_print_msg(RTAPI_MSG_ERR, - "HAL_PI_GPIO: ERROR: board revision %d not supported\n", rev); - return -EINVAL; + default: // This will need to change if there is a V3 pinout + pins = rpi2_pins; + gpios = rpi2_gpios; + npins = sizeof(rpi2_pins); + if (rev > 20){ // Rev 20 is Compute Module 4 + int db = rtapi_get_msg_level(); + rtapi_set_msg_level(3); + rev = get_rpi_revision(); // call the function with a higher message level to print model + rtapi_print_msg(RTAPI_MSG_INFO, "The Pi model %i is not known to " + "work with this driver but will be assumed to be be using " + "the RPi2+ layout 40 pin connector\n", rev); + rtapi_set_msg_level(db); + } + break; } port_data = hal_malloc(npins * sizeof(void *)); if (port_data == 0) {