PiDP-8/I Software

Check-in [bd10d4dde2]
Log In

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added support for Pi 4 GPIO, based on code the Raspberry Pi Foundation published: https://github.com/RPi-Distro/raspi-gpio/commit/80fa7d04eafb3ea34fc6f2d32de5f1873b5fb369 This check-in is based on a version of gpio-common.c.in posted to the PiDP-8 Google Group by Oscar Vermeulen, which is why we're giving him credit for this check-in, even though I (tangent) have done quite a lot of changes to that code, mainly to match the existing code style. This is a branch because it conflicts with the current tip-of-trunk and because it's not yet tested on a Pi 4. It is unknown whether this branch will end up overriding the method we're using on trunk for Pi 0-3 or if we will instead wait for the Foundation to publish a new libbcm_host that obviates some of what this check-in does.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | pi4-gpio-hack
Files: files | file ages | folders
SHA3-256: bd10d4dde2f485a510a7eddd44f9a99ce09997eaa2aa7edc52183d207943849e
User & Date: vermeulen.oscar 2019-08-15 00:22:38
Original Comment: Added support for Pi 4 GPIO, based on code the Raspberry Pi Foundation published: https://github.com/RPi-Distro/raspi-gpio/commit/80fa7d04eafb3ea34fc6f2d32de5f1873b5fb369 This is a branch because it conflicts with the current tip-of-trunk and because it's not yet tested on a Pi 4. It is unkonwn whether this branch will end up overriding the method we're using on trunk for Pi 0-3 or if we will instead wait for the Foundation to publish a new libbcm_host that obviates some of what this check-in does.
Original User & Date: tangent 2019-08-15 00:22:38
Context
2019-08-17
23:15
Merged the use of libbcm_host from trunk with Oscar's new GPIO pull up/down setup code to get the best of both worlds. This requires a version of libbcm_host that was only just released: https://github.com/raspberrypi/firmware/issues/1161 check-in: 1eee471981 user: tangent tags: pi4-gpio-clean
2019-08-15
00:22
Added support for Pi 4 GPIO, based on code the Raspberry Pi Foundation published: https://github.com/RPi-Distro/raspi-gpio/commit/80fa7d04eafb3ea34fc6f2d32de5f1873b5fb369 This check-in is based on a version of gpio-common.c.in posted to the PiDP-8 Google Group by Oscar Vermeulen, which is why we're giving him credit for this check-in, even though I (tangent) have done quite a lot of changes to that code, mainly to match the existing code style. This is a branch because it conflicts with the current tip-of-trunk and because it's not yet tested on a Pi 4. It is unknown whether this branch will end up overriding the method we're using on trunk for Pi 0-3 or if we will instead wait for the Foundation to publish a new libbcm_host that obviates some of what this check-in does. Closed-Leaf check-in: bd10d4dde2 user: vermeulen.oscar tags: pi4-gpio-hack
2019-08-14
23:43
Create new branch named "pi4-gpio-hack" check-in: 9a444fb597 user: tangent tags: pi4-gpio-hack
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pidp8i/gpio-common.c.in.

1
2
3
4
5
6
7
8
9
10
11
/*
 * gpio-common.c: functions common to both gpio.c and gpio-nls.c
 *
 * Copyright © 2015 Oscar Vermeulen, © 2016-2018 by Warren Young
 *
 * 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 the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:



|







1
2
3
4
5
6
7
8
9
10
11
/*
 * gpio-common.c: functions common to both gpio.c and gpio-nls.c
 *
 * Copyright © 2015, 2019 Oscar Vermeulen, © 2016-2019 by Warren Young
 *
 * 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 the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
232
233
234
235
236
237
238





239
240
241
242
243
244
245
246
247
248

249
250

251






252
253
254
255
256
257
258
259
        pidp8i_gpio_present = 0;
    }
}


//// bcm_host_get_peripheral_address ///////////////////////////////////
// Find Pi's GPIO base address






static unsigned bcm_host_get_peripheral_address(void)
{
    unsigned address = ~0;
    FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
    if (fp)
    {   unsigned char buf[4];
        fseek(fp, 4, SEEK_SET);
        if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
            address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;

        fclose(fp);
    }








    return address == ~0 ? 0x20000000 : address;
}


//// DOUBLE BUFFERED DISPLAY MANIPULATION FUNCTIONS ////////////////////

//// swap_displays ////////////////////////////////////////////////////
// Clear the current "paint-from" display, then exchange the double-







>
>
>
>
>

|


|
|
|
|
|

>


>
|
>
>
>
>
>
>
|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
        pidp8i_gpio_present = 0;
    }
}


//// bcm_host_get_peripheral_address ///////////////////////////////////
// Find Pi's GPIO base address
//
// This is and its helper function get_dt_ranges are based on code
// published by the Raspberry Pi Foundation:
//
// https://github.com/raspberrypi/userland/blob/master/host_applications/linux/libs/bcm_host/bcm_host.c

static unsigned get_dt_ranges(const char *filename, unsigned offset)
{
    unsigned address = ~0;
    FILE *fp = fopen(filename, "rb");
    if (fp) {
        unsigned char buf[4];
        fseek(fp, offset, SEEK_SET);
        if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
            address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
        }
        fclose(fp);
    }
    return address;
}

static unsigned bcm_host_get_peripheral_address(void)
{
   unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
   if (address == 0)
      address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
   return address == ~0 ? 0x20000000 : address;
}


//// DOUBLE BUFFERED DISPLAY MANIPULATION FUNCTIONS ////////////////////

//// swap_displays ////////////////////////////////////////////////////
// Clear the current "paint-from" display, then exchange the double-
585
586
587
588
589
590
591
592








593




594






595




596
597






598





599
600
601
602



603




604






605




606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641

































642
643
644
645
646
647
648
    }
    for (size_t row = 0; row < NLEDROWS; ++row) {
        INP_GPIO (ledrows[row]);
    }
}


//// init_pidp8i_gpio //////////////////////////////////////////////////








// Initialize the GPIO pins to the initial states required by




// gpio_thread().   It's a separate exported function so that scanswitch






// can also use it.





void init_pidp8i_gpio (void)






{





    // Set GPIO pins to their starting state
    turn_on_pidp8i_leds ();
    for (size_t i = 0; i < NROWS; i++) {       // Define rows as input
        INP_GPIO (rows[i]);



    }











    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs




    GPIO_PULL = 2;  // pull-up
    usleep(1);  // must wait 150 cycles
#if defined(PCB_SERIAL_MOD_OV) || defined(PCB_SERIAL_MOD_JLW)
    // The Oscar Vermeulen and James L-W serial mods rearrange the PiDP-8/I
    // GPIO matrix to use Pi GPIO pins 2..13, freeing up the hardware
    // serial port on GPIO pins 14 & 15.
    GPIO_PULLCLK0 = 0x03ffc;
#else
    // The standard PiDP-8/I board drive scheme uses Pi GPIO pins 4..15.
    GPIO_PULLCLK0 = 0x0fff0;
#endif
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
    GPIO_PULL = 1;  // pull-down to avoid ghosting (dec2015)
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x0ff00000; // selects GPIO pins 20..27
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
    GPIO_PULL = 0;  // no pull-up no pull down just float
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x070000; // selects GPIO pins 16..18
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

































}


//// gpio_thread ///////////////////////////////////////////////////////
// The GPIO thread entry point: initializes GPIO and then calls
// the gpio_core () implementation linked to this program.








|
>
>
>
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
|
>
>
>
>
|
|
>
>
>
>
>
>
|
>
>
>
>
>
|
|
|
|
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
|
>
>
>
>

















<
<
<
<
<
<
<
<
<
|
<








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685









686

687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
    }
    for (size_t row = 0; row < NLEDROWS; ++row) {
        INP_GPIO (ledrows[row]);
    }
}


//// init_bcm2711_gpio /////////////////////////////////////////////////
// Called from init_pidp8i_gpio() when it sees that it's running on a Pi
// 4 which uses the BCM 2711 GPIO peripheral, which behaves differently
// than GPIO was done in all prior Pi models.  This code is based on
// https://github.com/RPi-Distro/raspi-gpio/blob/master/raspi-gpio.c
//
// Note that there is no "serial mod" handling here: no one has come up
// with such a hardware hack for the Pi 4 yet, and no one has verified
// that you can do one of the existing ones atop the Pi 4.

static void init_bcm2711_gpio (void)
{
    int gpiox, pullreg, pullshift;
    unsigned int pullbits, pull;

    // Configure "columns" GPIO pins
    for (size_t i = 0; i < 12; ++i) {
        gpiox = cols[i];
        pullreg = GPPUPPDN0 + (gpiox>>4);
        pullshift = (gpiox & 0xf) << 1;
        pull = 1;

        pullbits = *(gpio.addr + pullreg);
        pullbits &= ~(3 << pullshift);
        pullbits |= (pull << pullshift);
        *(gpio.addr + pullreg) = pullbits;
    }

    // Configure "rows" GPIO pins
    for (size_t i = 0; i < 3; ++i) {
        gpiox = rows[i];
        pullreg = GPPUPPDN0 + (gpiox>>4);
        pullshift = (gpiox & 0xf) << 1;
        pull = 0;

        pullbits = *(gpio.addr + pullreg);
        pullbits &= ~(3 << pullshift);
        pullbits |= (pull << pullshift);
        *(gpio.addr + pullreg) = pullbits;
    }

    // Configure "ledrows" GPIO pins
    for (size_t i = 0; i < 6; ++i) {
        gpiox = ledrows[i];
        pullreg = GPPUPPDN0 + (gpiox>>4);
        pullshift = (gpiox & 0xf) << 1;
        pull = 0;

        pullbits = *(gpio.addr + pullreg);
        pullbits &= ~(3 << pullshift);
        pullbits |= (pull << pullshift);
        *(gpio.addr + pullreg) = pullbits;
    }
}


//// init_bcm2835_gpio /////////////////////////////////////////////////
// Called from init_pidp8i_gpio() when it sees that it's running on a Pi
// 3 or older.  This is the "classic" Pi GPIO mode.  See page 101 in the
// peripheral's datasheet and // http://elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs

static void init_bcm2835_gpio (void)
{
    // Configure "columns" GPIO pins
    GPIO_PULL = 2;  // pull-up
    usleep(1);  // must wait 150 cycles
#if defined(PCB_SERIAL_MOD_OV) || defined(PCB_SERIAL_MOD_JLW)
    // The Oscar Vermeulen and James L-W serial mods rearrange the PiDP-8/I
    // GPIO matrix to use Pi GPIO pins 2..13, freeing up the hardware
    // serial port on GPIO pins 14 & 15.
    GPIO_PULLCLK0 = 0x03ffc;
#else
    // The standard PiDP-8/I board drive scheme uses Pi GPIO pins 4..15.
    GPIO_PULLCLK0 = 0x0fff0;
#endif
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary










    // Configure "rows" GPIO pins

    GPIO_PULL = 0;  // no pull-up no pull down just float
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x070000; // selects GPIO pins 16..18
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // Configure "ledrows" GPIO pins
    GPIO_PULL = 1;  // pull-down to avoid ghosting
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x0ff00000; // selects GPIO pins 20..27
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary
}


//// init_pidp8i_gpio //////////////////////////////////////////////////
// Initialize the GPIO pins to the initial states required by
// gpio_thread().   It's a separate exported function so that scanswitch
// can also use it.

void init_pidp8i_gpio (void)
{
    // Set GPIO pins to their starting state
    turn_on_pidp8i_leds ();
    for (size_t i = 0; i < NROWS; i++) {       // Define rows as input
        INP_GPIO (rows[i]);
    }

    // Configure GPIO pin pull-ups
    if (gpio.addr_p == 0xfe200000) {
        init_bcm2711_gpio();
    }
    else {
        init_bcm2835_gpio();
    }
}


//// gpio_thread ///////////////////////////////////////////////////////
// The GPIO thread entry point: initializes GPIO and then calls
// the gpio_core () implementation linked to this program.

Changes to src/pidp8i/gpio-common.h.

1
2
3
4
5
6
7
8
9
10
11
/*
 * gpio-common.h: public interface for the PiDP-8/I's GPIO module
 *
 * Copyright © 2015-2017 Oscar Vermeulen and Warren Young
 *
 * 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 the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:



|







1
2
3
4
5
6
7
8
9
10
11
/*
 * gpio-common.h: public interface for the PiDP-8/I's GPIO module
 *
 * Copyright © 2015, 2019 by Oscar Vermeulen, © 2016-2019 by Warren Young
 *
 * 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 the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
49
50
51
52
53
54
55






56
57
58
59
60
61
62
#define GPIO_CLR  *(pgpio->addr + 10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  *(pgpio->addr + 13) &= (1<<(g))

#define GPIO_PULL *(pgpio->addr + 37) // pull up/pull down
#define GPIO_PULLCLK0 *(pgpio->addr + 38) // pull up/pull down clock








// Switch masks, SSn, used against switchstatus[n]
#define SS0_SR_B11 04000
#define SS0_SR_B10 02000
#define SS0_SR_B09 01000
#define SS0_SR_B08 00400
#define SS0_SR_B07 00200







>
>
>
>
>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#define GPIO_CLR  *(pgpio->addr + 10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  *(pgpio->addr + 13) &= (1<<(g))

#define GPIO_PULL *(pgpio->addr + 37) // pull up/pull down
#define GPIO_PULLCLK0 *(pgpio->addr + 38) // pull up/pull down clock

// Pi 4 GPIO pull up/down peripheral I/O offsets.  Based on
// https://github.com/RPi-Distro/raspi-gpio/blob/master/raspi-gpio.c
#define GPPUPPDN0 57        // pins 15:0
#define GPPUPPDN1 58        // pins 31:16
#define GPPUPPDN2 59        // pins 47:32
#define GPPUPPDN3 60        // pins 57:48

// Switch masks, SSn, used against switchstatus[n]
#define SS0_SR_B11 04000
#define SS0_SR_B10 02000
#define SS0_SR_B09 01000
#define SS0_SR_B08 00400
#define SS0_SR_B07 00200