Skip to content

Commit

Permalink
hal_pi_gpio: Default to assuming that the pin-out is supported
Browse files Browse the repository at this point in the history
Also re-write cpuinfo.c to follow advice at
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#best-practice-for-revision-code-usage
The RPi pinout has been stable since 2015.
Also, add the missing manpage
  • Loading branch information
andypugh committed Jul 16, 2023
1 parent 9ba47b0 commit 2cb7eb3
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 104 deletions.
2 changes: 2 additions & 0 deletions docs/src/Master_Documentation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down
106 changes: 106 additions & 0 deletions docs/src/drivers/hal_pi_gpio.txt
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions docs/src/index.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ function setup_page(){
<li><a href="drivers/ax5214h.html">AX5214H Driver</a></li>
<li><a href="drivers/gm.html">General Mechatronics GM6-PCI Driver</a></li>
<li><a href="drivers/gs2.html">GS2 Driver</a></li>
<li><a href="drivers/hal_pi_gpio.html">Raspberry Pi GPIO Driver</a></li>
<li><a href="drivers/hostmot2.html">Mesa HostMot2 Driver</a></li>
<li><a href="drivers/motenc.html">Motenc Driver</a></li>
<li><a href="drivers/mb2hal.html">Modbus to HAL Driver</a></li>
Expand Down
87 changes: 21 additions & 66 deletions src/hal/drivers/cpuinfo.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -27,86 +25,43 @@ SOFTWARE.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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);
}
}

56 changes: 18 additions & 38 deletions src/hal/drivers/hal_pi_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 2cb7eb3

Please sign in to comment.