usrp-users@lists.ettus.com

Discussion and technical support related to USRP, UHD, RFNoC

View all threads

B210 GPIO SPI support using UHD Python API

PH
page heller
Thu, Feb 12, 2026 6:43 PM

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO. 

Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins.

I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work.

I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO.  Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins. I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work. I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page
MB
Martin Braun
Thu, Feb 19, 2026 8:48 AM

Hi Page,

I'm not sure where you got the 3.3V info from, but this section in the
manual shows the pins:

https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches

From here, this is the pinout:  1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3,
5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND

Make sure you share a ground pin with your Pi Zero.

If you're just reading pins, follow the manual for set_gpio_attr() (
https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e)
to do the following:

  • Set desired pins CTRL to 0 (GPIO mode)
  • Set DDR to 0 (input)
  • Call get_gpio_attr() on the READBACK attribute. You will get all 8
    pins back, not just the ones you set to input (the others will be whatever
    their state is).

You're right that the manual page for the GPIO API does not spell out B210
specifically, but everything there also applies to B210:
https://uhd.readthedocs.io/en/latest/page_gpio_api.html

Start slowly, without SPI, and read back known pin values. Then, poll the
GPIO bank more quickly to get your bit-banging functionality.

While this does not specifically talk about reading GPIOs, it maybe also be
useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv

--M

On Thu, Feb 12, 2026 at 7:43 PM page heller pageheller@gmail.com wrote:

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it
to a Raspberry Pi Zero acting as the Master for SPI communications, sending
the chip select and clock to the B210. The loopback test on the Pi is
successful. The NI-provided Python example code on the B210 side appears to
'get' (read) the pins on J504. Disconnected I see the chip select signal go
low and back high, but when I connect it to J504, the software to 'get' the
pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the
chip select, 3 for clock, 6 for MOSI. I'm not using MISO.

Some references on line suggest that pin 1 is an output on J504 of 3.3V
power, but, I don't think so. It most certainly is not 3.3V and appears to
be just like the other pins.

I need some help. I've invested about ten hours trying a number of
different methods and code examples. I've tried getting SPI to work, but
the documentation is so poor, I can only guess on the actual
implementation. When that didn't work, I went to bit-banging; also with no
success. I'm just sending datetime from the pi to the B210 to synch them
(doesn't have to be exact, just within hundreds of microseconds). So, I'm
only sending a handful of bytes once, so bit-banging is just fine for this
application. But, I can't get either the SPI nor the bit-banging to work.
If I can't see the pin change when I use the example 'get' python code,
then nothing will work.

I'd love to talk with someone who has transferred data over the B210 GPIO.
(Am I supposed to call this the NI 2109 now?) Thanks. -page


USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-leave@lists.ettus.com

Hi Page, I'm not sure where you got the 3.3V info from, but this section in the manual shows the pins: https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND Make sure you share a ground pin with your Pi Zero. If you're just reading pins, follow the manual for set_gpio_attr() ( https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e) to do the following: - Set desired pins CTRL to 0 (GPIO mode) - Set DDR to 0 (input) - Call get_gpio_attr() on the READBACK attribute. You will get all 8 pins back, not just the ones you set to input (the others will be whatever their state is). You're right that the manual page for the GPIO API does not spell out B210 specifically, but everything there also applies to B210: https://uhd.readthedocs.io/en/latest/page_gpio_api.html Start slowly, without SPI, and read back known pin values. Then, poll the GPIO bank more quickly to get your bit-banging functionality. While this does not specifically talk about reading GPIOs, it maybe also be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv --M On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com> wrote: > I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it > to a Raspberry Pi Zero acting as the Master for SPI communications, sending > the chip select and clock to the B210. The loopback test on the Pi is > successful. The NI-provided Python example code on the B210 side appears to > 'get' (read) the pins on J504. Disconnected I see the chip select signal go > low and back high, but when I connect it to J504, the software to 'get' the > pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the > chip select, 3 for clock, 6 for MOSI. I'm not using MISO. > > Some references on line suggest that pin 1 is an output on J504 of 3.3V > power, but, I don't think so. It most certainly is not 3.3V and appears to > be just like the other pins. > > I need some help. I've invested about ten hours trying a number of > different methods and code examples. I've tried getting SPI to work, but > the documentation is so poor, I can only guess on the actual > implementation. When that didn't work, I went to bit-banging; also with no > success. I'm just sending datetime from the pi to the B210 to synch them > (doesn't have to be exact, just within hundreds of microseconds). So, I'm > only sending a handful of bytes once, so bit-banging is just fine for this > application. But, I can't get either the SPI nor the bit-banging to work. > If I can't see the pin change when I use the example 'get' python code, > then nothing will work. > > I'd love to talk with someone who has transferred data over the B210 GPIO. > (Am I supposed to call this the NI 2109 now?) Thanks. -page > _______________________________________________ > USRP-users mailing list -- usrp-users@lists.ettus.com > To unsubscribe send an email to usrp-users-leave@lists.ettus.com >
PH
page heller
Fri, Apr 10, 2026 2:48 PM

Martin, thanks for your hints. I had indeed watched the video on the gpio pins. The only difference I see is that I am trying to use the Python API to read the pins. I have a question on permissions as I get underway here.

If I run my python3 program as the user, I get a permission-denied error when retrieving the chip0 name. If I run it as super user, it can't fund uhd to import. I read through a number of recommendations, and decided defining PATHs in ./basrc was the way to solve this. But, with the paths I show below, the same errors occur. I am not using a virtual environment since this is a dedicated machine for a single purpose/single user. -page
Linux 6.17.0-14-generic
Ubuntu 24.04.4 LTS
Python 3.12.3
uhd 4.9.0

user@9i:~$ python3 b210_get_time6_bitbang.py
gpiochip0 0 2 6 1e-05
192
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module>
read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits, args.half_period)
File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi
chip = gpiod.Chip(chip_name)
^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied

user@9i:~$ sudo python3 b210_get_time6_bitbang.py
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module>
import uhd
ModuleNotFoundError: No module named 'uhd'

user@9i:~$ ls /usr/local/include
uhd uhd.h
user@9i:~$ ls /usr/local/include/uhd
build_info.hpp device.hpp features stream.hpp utils
cal error.h property_tree.hpp transport version.h
config.h exception.hpp property_tree.ipp types version.hpp
config.hpp experts rfnoc usrp
convert.hpp extension rfnoc_graph.hpp usrp_clock
user@9i:~$ ls /usr/local/lib
cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd

user@9i:~$ sudo nano .bashrc

set up uhd

export LD_LIBRARY_PATH=/usr/local/lib/
export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH
export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH

On 2/19/2026 2:48:28 AM, Martin Braun martin.braun@ettus.com wrote:
Hi Page,

I'm not sure where you got the 3.3V info from, but this section in the manual shows the pins:

https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches [https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches]

From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND

Make sure you share a ground pin with your Pi Zero.

If you're just reading pins, follow the manual for set_gpio_attr() (https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e [https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e]) to do the following:

  • Set desired pins CTRL to 0 (GPIO mode)
  • Set DDR to 0 (input)
  • Call get_gpio_attr() on the READBACK attribute. You will get all 8 pins back, not just the ones you set to input (the others will be whatever their state is).
    You're right that the manual page for the GPIO API does not spell out B210 specifically, but everything there also applies to B210: https://uhd.readthedocs.io/en/latest/page_gpio_api.html [https://uhd.readthedocs.io/en/latest/page_gpio_api.html]

Start slowly, without SPI, and read back known pin values. Then, poll the GPIO bank more quickly to get your bit-banging functionality.

While this does not specifically talk about reading GPIOs, it maybe also be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv [https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv]

--M

On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote:

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO.

Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins.

I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work.

I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page


USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com]
To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com]

_______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com To unsubscribe send an email to usrp-users-leave@lists.ettus.com

Martin, thanks for your hints. I had indeed watched the video on the gpio pins. The only difference I see is that I am trying to use the Python API to read the pins. I have a question on permissions as I get underway here. If I run my python3 program as the user, I get a permission-denied error when retrieving the chip0 name. If I run it as super user, it can't fund uhd to import. I read through a number of recommendations, and decided defining PATHs in ./basrc was the way to solve this. But, with the paths I show below, the same errors occur. I am not using a virtual environment since this is a dedicated machine for a single purpose/single user. -page Linux 6.17.0-14-generic Ubuntu 24.04.4 LTS Python 3.12.3 uhd 4.9.0 user@9i:~$ python3 b210_get_time6_bitbang.py gpiochip0 0 2 6 1e-05 192 Traceback (most recent call last): File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module> read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits, args.half_period) File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi chip = gpiod.Chip(chip_name) ^^^^^^^^^^^^^^^^^^^^^ PermissionError: [Errno 13] Permission denied user@9i:~$ sudo python3 b210_get_time6_bitbang.py Traceback (most recent call last): File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module> import uhd ModuleNotFoundError: No module named 'uhd' user@9i:~$ ls /usr/local/include uhd uhd.h user@9i:~$ ls /usr/local/include/uhd build_info.hpp device.hpp features stream.hpp utils cal error.h property_tree.hpp transport version.h config.h exception.hpp property_tree.ipp types version.hpp config.hpp experts rfnoc usrp convert.hpp extension rfnoc_graph.hpp usrp_clock user@9i:~$ ls /usr/local/lib cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd user@9i:~$ sudo nano .bashrc … # set up uhd export LD_LIBRARY_PATH=/usr/local/lib/ export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH On 2/19/2026 2:48:28 AM, Martin Braun <martin.braun@ettus.com> wrote: Hi Page, I'm not sure where you got the 3.3V info from, but this section in the manual shows the pins: https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches [https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches] From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND Make sure you share a ground pin with your Pi Zero. If you're just reading pins, follow the manual for set_gpio_attr() (https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e [https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e]) to do the following: * Set desired pins CTRL to 0 (GPIO mode) * Set DDR to 0 (input) * Call get_gpio_attr() on the READBACK attribute. You will get all 8 pins back, not just the ones you set to input (the others will be whatever their state is). You're right that the manual page for the GPIO API does not spell out B210 specifically, but everything there also applies to B210: https://uhd.readthedocs.io/en/latest/page_gpio_api.html [https://uhd.readthedocs.io/en/latest/page_gpio_api.html] Start slowly, without SPI, and read back known pin values. Then, poll the GPIO bank more quickly to get your bit-banging functionality. While this does not specifically talk about reading GPIOs, it maybe also be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv [https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv] --M On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote: I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO. Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins. I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work. I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page _______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com] To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com] _______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com To unsubscribe send an email to usrp-users-leave@lists.ettus.com
MB
Martin Braun
Mon, Apr 13, 2026 9:17 AM

Hey Page,

The sudo issue points to the library path not being picked up correctly for
root, or maybe python not finding the installed packages there. So you
might want to change root's bashrc, not the user's.

For the permission denied error when running as user, you'll likely need to
add your user to the 'gpio' group or ensure the necessary permissions are
set on /dev/gpiochip0. What group is that device owned by? Personally, I
prefer this option (giving users access to the Pi's GPIOs).

It's worth pointing out (to future readers of this thread) that the
GPIO-programming on your Pi is unrelated to the GPIO programming of the
USRP itself.

--M

On Fri, Apr 10, 2026 at 4:49 PM page heller pageheller@gmail.com wrote:

Martin, thanks for your hints. I had indeed watched the video on the gpio
pins. The only difference I see is that I am trying to use the Python API
to read the pins. I have a question on permissions as I get underway here.

If I run my python3 program as the user, I get a permission-denied error
when retrieving the chip0 name. If I run it as super user, it can't fund
uhd to import. I read through a number of recommendations, and decided
defining PATHs in ./basrc was the way to solve this. But, with the paths I
show below, the same errors occur. I am not using a virtual environment
since this is a dedicated machine for a single purpose/single user. -page
Linux 6.17.0-14-generic
Ubuntu 24.04.4 LTS
Python 3.12.3
uhd 4.9.0

user@9i:~$ python3 b210_get_time6_bitbang.py
gpiochip0 0 2 6 1e-05
192
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module>
read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits,
args.half_period)
File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi
chip = gpiod.Chip(chip_name)
^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied

user@9i:~$ sudo python3 b210_get_time6_bitbang.py
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module>
import uhd
ModuleNotFoundError: No module named 'uhd'

user@9i:~$ ls /usr/local/include
uhd uhd.h
user@9i:~$ ls /usr/local/include/uhd
build_info.hpp device.hpp features stream.hpp utils
cal error.h property_tree.hpp transport version.h
config.h exception.hpp property_tree.ipp types version.hpp
config.hpp experts rfnoc usrp
convert.hpp extension rfnoc_graph.hpp usrp_clock
user@9i:~$ ls /usr/local/lib
cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd

user@9i:~$ sudo nano .bashrc

set up uhd

export LD_LIBRARY_PATH=/usr/local/lib/
export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH
export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH

On 2/19/2026 2:48:28 AM, Martin Braun martin.braun@ettus.com wrote:
Hi Page,

I'm not sure where you got the 3.3V info from, but this section in the
manual shows the pins:

https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches

From here, this is the pinout:  1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3,
5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND

Make sure you share a ground pin with your Pi Zero.

If you're just reading pins, follow the manual for set_gpio_attr() (
https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e)
to do the following:

- Set desired pins CTRL to 0 (GPIO mode)
- Set DDR to 0 (input)
- Call get_gpio_attr() on the READBACK attribute. You will get all 8
pins back, not just the ones you set to input (the others will be whatever
their state is).

You're right that the manual page for the GPIO API does not spell out B210
specifically, but everything there also applies to B210:
https://uhd.readthedocs.io/en/latest/page_gpio_api.html

Start slowly, without SPI, and read back known pin values. Then, poll the
GPIO bank more quickly to get your bit-banging functionality.

While this does not specifically talk about reading GPIOs, it maybe also
be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv

--M

On Thu, Feb 12, 2026 at 7:43 PM page heller pageheller@gmail.com wrote:

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting
it to a Raspberry Pi Zero acting as the Master for SPI communications,
sending the chip select and clock to the B210. The loopback test on the Pi
is successful. The NI-provided Python example code on the B210 side appears
to 'get' (read) the pins on J504. Disconnected I see the chip select signal
go low and back high, but when I connect it to J504, the software to 'get'
the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as
the chip select, 3 for clock, 6 for MOSI. I'm not using MISO.

Some references on line suggest that pin 1 is an output on J504 of 3.3V
power, but, I don't think so. It most certainly is not 3.3V and appears to
be just like the other pins.

I need some help. I've invested about ten hours trying a number of
different methods and code examples. I've tried getting SPI to work, but
the documentation is so poor, I can only guess on the actual
implementation. When that didn't work, I went to bit-banging; also with no
success. I'm just sending datetime from the pi to the B210 to synch them
(doesn't have to be exact, just within hundreds of microseconds). So, I'm
only sending a handful of bytes once, so bit-banging is just fine for this
application. But, I can't get either the SPI nor the bit-banging to work.
If I can't see the pin change when I use the example 'get' python code,
then nothing will work.

I'd love to talk with someone who has transferred data over the B210
GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page


USRP-users mailing list -- usrp-users@lists.ettus.com
To unsubscribe send an email to usrp-users-leave@lists.ettus.com

_______________________________________________ USRP-users mailing list --
usrp-users@lists.ettus.com To unsubscribe send an email to
usrp-users-leave@lists.ettus.com

Hey Page, The sudo issue points to the library path not being picked up correctly for root, or maybe python not finding the installed packages there. So you might want to change root's bashrc, not the user's. For the permission denied error when running as user, you'll likely need to add your user to the 'gpio' group or ensure the necessary permissions are set on /dev/gpiochip0. What group is that device owned by? Personally, I prefer this option (giving users access to the Pi's GPIOs). It's worth pointing out (to future readers of this thread) that the GPIO-programming on your Pi is unrelated to the GPIO programming of the USRP itself. --M On Fri, Apr 10, 2026 at 4:49 PM page heller <pageheller@gmail.com> wrote: > Martin, thanks for your hints. I had indeed watched the video on the gpio > pins. The only difference I see is that I am trying to use the Python API > to read the pins. I have a question on permissions as I get underway here. > > If I run my python3 program as the user, I get a permission-denied error > when retrieving the chip0 name. If I run it as super user, it can't fund > uhd to import. I read through a number of recommendations, and decided > defining PATHs in ./basrc was the way to solve this. But, with the paths I > show below, the same errors occur. I am not using a virtual environment > since this is a dedicated machine for a single purpose/single user. -page > Linux 6.17.0-14-generic > Ubuntu 24.04.4 LTS > Python 3.12.3 > uhd 4.9.0 > > > user@9i:~$ python3 b210_get_time6_bitbang.py > gpiochip0 0 2 6 1e-05 > 192 > Traceback (most recent call last): > File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module> > read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits, > args.half_period) > File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi > chip = gpiod.Chip(chip_name) > ^^^^^^^^^^^^^^^^^^^^^ > PermissionError: [Errno 13] Permission denied > > > user@9i:~$ sudo python3 b210_get_time6_bitbang.py > Traceback (most recent call last): > File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module> > import uhd > ModuleNotFoundError: No module named 'uhd' > > > > user@9i:~$ ls /usr/local/include > uhd uhd.h > user@9i:~$ ls /usr/local/include/uhd > build_info.hpp device.hpp features stream.hpp utils > cal error.h property_tree.hpp transport version.h > config.h exception.hpp property_tree.ipp types version.hpp > config.hpp experts rfnoc usrp > convert.hpp extension rfnoc_graph.hpp usrp_clock > user@9i:~$ ls /usr/local/lib > cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd > > > > user@9i:~$ sudo nano .bashrc > … > # set up uhd > export LD_LIBRARY_PATH=/usr/local/lib/ > export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH > export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH > > On 2/19/2026 2:48:28 AM, Martin Braun <martin.braun@ettus.com> wrote: > Hi Page, > > I'm not sure where you got the 3.3V info from, but this section in the > manual shows the pins: > > https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches > > From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, > 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND > > Make sure you share a ground pin with your Pi Zero. > > If you're just reading pins, follow the manual for set_gpio_attr() ( > https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e) > to do the following: > > - Set desired pins CTRL to 0 (GPIO mode) > - Set DDR to 0 (input) > - Call get_gpio_attr() on the READBACK attribute. You will get all 8 > pins back, not just the ones you set to input (the others will be whatever > their state is). > > You're right that the manual page for the GPIO API does not spell out B210 > specifically, but everything there also applies to B210: > https://uhd.readthedocs.io/en/latest/page_gpio_api.html > > Start slowly, without SPI, and read back known pin values. Then, poll the > GPIO bank more quickly to get your bit-banging functionality. > > While this does not specifically talk about reading GPIOs, it maybe also > be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv > > --M > > > > On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com> wrote: > >> I am struggling with the GPIO on the Ettus B210 (J504). I am connecting >> it to a Raspberry Pi Zero acting as the Master for SPI communications, >> sending the chip select and clock to the B210. The loopback test on the Pi >> is successful. The NI-provided Python example code on the B210 side appears >> to 'get' (read) the pins on J504. Disconnected I see the chip select signal >> go low and back high, but when I connect it to J504, the software to 'get' >> the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as >> the chip select, 3 for clock, 6 for MOSI. I'm not using MISO. >> >> Some references on line suggest that pin 1 is an output on J504 of 3.3V >> power, but, I don't think so. It most certainly is not 3.3V and appears to >> be just like the other pins. >> >> I need some help. I've invested about ten hours trying a number of >> different methods and code examples. I've tried getting SPI to work, but >> the documentation is so poor, I can only guess on the actual >> implementation. When that didn't work, I went to bit-banging; also with no >> success. I'm just sending datetime from the pi to the B210 to synch them >> (doesn't have to be exact, just within hundreds of microseconds). So, I'm >> only sending a handful of bytes once, so bit-banging is just fine for this >> application. But, I can't get either the SPI nor the bit-banging to work. >> If I can't see the pin change when I use the example 'get' python code, >> then nothing will work. >> >> I'd love to talk with someone who has transferred data over the B210 >> GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page >> _______________________________________________ >> USRP-users mailing list -- usrp-users@lists.ettus.com >> To unsubscribe send an email to usrp-users-leave@lists.ettus.com >> > _______________________________________________ USRP-users mailing list -- > usrp-users@lists.ettus.com To unsubscribe send an email to > usrp-users-leave@lists.ettus.com > >
PH
page heller
Mon, Apr 13, 2026 2:45 PM

Good advice. Thanks, Martin. I didn't actually know that there were separate .bashrc settings. I'm with you, though, in preferring to run as user, so I'll see if I can set up the proper group first. -p
On 4/13/2026 4:17:42 AM, Martin Braun martin.braun@ettus.com wrote:
Hey Page,

The sudo issue points to the library path not being picked up correctly for root, or maybe python not finding the installed packages there. So you might want to change root's bashrc, not the user's.

For the permission denied error when running as user, you'll likely need to add your user to the 'gpio' group or ensure the necessary permissions are set on /dev/gpiochip0. What group is that device owned by? Personally, I prefer this option (giving users access to the Pi's GPIOs).

It's worth pointing out (to future readers of this thread) that the GPIO-programming on your Pi is unrelated to the GPIO programming of the USRP itself.

--M

On Fri, Apr 10, 2026 at 4:49 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote:

Martin, thanks for your hints. I had indeed watched the video on the gpio pins. The only difference I see is that I am trying to use the Python API to read the pins. I have a question on permissions as I get underway here.

If I run my python3 program as the user, I get a permission-denied error when retrieving the chip0 name. If I run it as super user, it can't fund uhd to import. I read through a number of recommendations, and decided defining PATHs in ./basrc was the way to solve this. But, with the paths I show below, the same errors occur. I am not using a virtual environment since this is a dedicated machine for a single purpose/single user. -page
Linux 6.17.0-14-generic
Ubuntu 24.04.4 LTS
Python 3.12.3
uhd 4.9.0

user@9i:~$ python3 b210_get_time6_bitbang.py
gpiochip0 0 2 6 1e-05
192
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module>
read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits, args.half_period)
File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi
chip = gpiod.Chip(chip_name)
^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied

user@9i:~$ sudo python3 b210_get_time6_bitbang.py
Traceback (most recent call last):
File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module>
import uhd
ModuleNotFoundError: No module named 'uhd'

user@9i:~$ ls /usr/local/include
uhd uhd.h
user@9i:~$ ls /usr/local/include/uhd
build_info.hpp device.hpp features stream.hpp utils
cal error.h property_tree.hpp transport version.h
config.h exception.hpp property_tree.ipp types version.hpp
config.hpp experts rfnoc usrp
convert.hpp extension rfnoc_graph.hpp usrp_clock
user@9i:~$ ls /usr/local/lib
cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd

user@9i:~$ sudo nano .bashrc

set up uhd

export LD_LIBRARY_PATH=/usr/local/lib/
export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH
export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH

On 2/19/2026 2:48:28 AM, Martin Braun <martin.braun@ettus.com [mailto:martin.braun@ettus.com]> wrote:
Hi Page,

I'm not sure where you got the 3.3V info from, but this section in the manual shows the pins:

https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches [https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches]

From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND

Make sure you share a ground pin with your Pi Zero.

If you're just reading pins, follow the manual for set_gpio_attr() (https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e [https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e]) to do the following:

  • Set desired pins CTRL to 0 (GPIO mode)
  • Set DDR to 0 (input)
  • Call get_gpio_attr() on the READBACK attribute. You will get all 8 pins back, not just the ones you set to input (the others will be whatever their state is).
    You're right that the manual page for the GPIO API does not spell out B210 specifically, but everything there also applies to B210: https://uhd.readthedocs.io/en/latest/page_gpio_api.html [https://uhd.readthedocs.io/en/latest/page_gpio_api.html]

Start slowly, without SPI, and read back known pin values. Then, poll the GPIO bank more quickly to get your bit-banging functionality.

While this does not specifically talk about reading GPIOs, it maybe also be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv [https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv]

--M

On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote:

I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO.

Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins.

I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work.

I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page


USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com]
To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com]

_______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com] To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com]

Good advice. Thanks, Martin. I didn't actually know that there were separate .bashrc settings. I'm with you, though, in preferring to run as user, so I'll see if I can set up the proper group first. -p On 4/13/2026 4:17:42 AM, Martin Braun <martin.braun@ettus.com> wrote: Hey Page, The sudo issue points to the library path not being picked up correctly for root, or maybe python not finding the installed packages there. So you might want to change root's bashrc, not the user's. For the permission denied error when running as user, you'll likely need to add your user to the 'gpio' group or ensure the necessary permissions are set on /dev/gpiochip0. What group is that device owned by? Personally, I prefer this option (giving users access to the Pi's GPIOs). It's worth pointing out (to future readers of this thread) that the GPIO-programming on your Pi is unrelated to the GPIO programming of the USRP itself. --M On Fri, Apr 10, 2026 at 4:49 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote: Martin, thanks for your hints. I had indeed watched the video on the gpio pins. The only difference I see is that I am trying to use the Python API to read the pins. I have a question on permissions as I get underway here. If I run my python3 program as the user, I get a permission-denied error when retrieving the chip0 name. If I run it as super user, it can't fund uhd to import. I read through a number of recommendations, and decided defining PATHs in ./basrc was the way to solve this. But, with the paths I show below, the same errors occur. I am not using a virtual environment since this is a dedicated machine for a single purpose/single user. -page Linux 6.17.0-14-generic Ubuntu 24.04.4 LTS Python 3.12.3 uhd 4.9.0 user@9i:~$ python3 b210_get_time6_bitbang.py gpiochip0 0 2 6 1e-05 192 Traceback (most recent call last): File "/home/endpoint/b210_get_time6_bitbang.py", line 77, in <module> read_spi(args.chip, args.clk, args.cs, args.mosi, args.bits, args.half_period) File "/home/endpoint/b210_get_time6_bitbang.py", line 10, in read_spi chip = gpiod.Chip(chip_name) ^^^^^^^^^^^^^^^^^^^^^ PermissionError: [Errno 13] Permission denied user@9i:~$ sudo python3 b210_get_time6_bitbang.py Traceback (most recent call last): File "/home/endpoint/b210_get_time6_bitbang.py", line 5, in <module> import uhd ModuleNotFoundError: No module named 'uhd' user@9i:~$ ls /usr/local/include uhd uhd.h user@9i:~$ ls /usr/local/include/uhd build_info.hpp device.hpp features stream.hpp utils cal error.h property_tree.hpp transport version.h config.h exception.hpp property_tree.ipp types version.hpp config.hpp experts rfnoc usrp convert.hpp extension rfnoc_graph.hpp usrp_clock user@9i:~$ ls /usr/local/lib cmake libuhd.so libuhd.so.4.9.0 pkgconfig python3.12 uhd user@9i:~$ sudo nano .bashrc … # set up uhd export LD_LIBRARY_PATH=/usr/local/lib/ export LD_LIBRARY_PATH=/usr/local/include/:$LD_LIBRARY_PATH export PYTHONPATH=/usr/local/lib/python3.12/site-packages/:$PYTHONPATH On 2/19/2026 2:48:28 AM, Martin Braun <martin.braun@ettus.com [mailto:martin.braun@ettus.com]> wrote: Hi Page, I'm not sure where you got the 3.3V info from, but this section in the manual shows the pins: https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches [https://uhd.readthedocs.io/en/latest/page_usrp_b200.html#b200_switches] From here, this is the pinout: 1=GPIO_0, 2=GPIO_1, 3=GPIO_2, 4=GPIO_3, 5=GPIO_4, 6=GPIO_5, 7=GPIO_6, 8=GPIO_7, 9=GND, 10=GND Make sure you share a ground pin with your Pi Zero. If you're just reading pins, follow the manual for set_gpio_attr() (https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e [https://uhd.readthedocs.io/en/latest/classuhd_1_1usrp_1_1multi__usrp.html#a57f25d118d20311aca261e6dd252625e]) to do the following: * Set desired pins CTRL to 0 (GPIO mode) * Set DDR to 0 (input) * Call get_gpio_attr() on the READBACK attribute. You will get all 8 pins back, not just the ones you set to input (the others will be whatever their state is). You're right that the manual page for the GPIO API does not spell out B210 specifically, but everything there also applies to B210: https://uhd.readthedocs.io/en/latest/page_gpio_api.html [https://uhd.readthedocs.io/en/latest/page_gpio_api.html] Start slowly, without SPI, and read back known pin values. Then, poll the GPIO bank more quickly to get your bit-banging functionality. While this does not specifically talk about reading GPIOs, it maybe also be useful: https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv [https://youtu.be/ppD06ZETnek?si=EYGKvF5jfKG9RiGv] --M On Thu, Feb 12, 2026 at 7:43 PM page heller <pageheller@gmail.com [mailto:pageheller@gmail.com]> wrote: I am struggling with the GPIO on the Ettus B210 (J504). I am connecting it to a Raspberry Pi Zero acting as the Master for SPI communications, sending the chip select and clock to the B210. The loopback test on the Pi is successful. The NI-provided Python example code on the B210 side appears to 'get' (read) the pins on J504. Disconnected I see the chip select signal go low and back high, but when I connect it to J504, the software to 'get' the pin doesn't change (same code, but in a for-loop). I'm using pin 1 as the chip select, 3 for clock, 6 for MOSI. I'm not using MISO. Some references on line suggest that pin 1 is an output on J504 of 3.3V power, but, I don't think so. It most certainly is not 3.3V and appears to be just like the other pins. I need some help. I've invested about ten hours trying a number of different methods and code examples. I've tried getting SPI to work, but the documentation is so poor, I can only guess on the actual implementation. When that didn't work, I went to bit-banging; also with no success. I'm just sending datetime from the pi to the B210 to synch them (doesn't have to be exact, just within hundreds of microseconds). So, I'm only sending a handful of bytes once, so bit-banging is just fine for this application. But, I can't get either the SPI nor the bit-banging to work. If I can't see the pin change when I use the example 'get' python code, then nothing will work. I'd love to talk with someone who has transferred data over the B210 GPIO. (Am I supposed to call this the NI 2109 now?) Thanks. -page _______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com] To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com] _______________________________________________ USRP-users mailing list -- usrp-users@lists.ettus.com [mailto:usrp-users@lists.ettus.com] To unsubscribe send an email to usrp-users-leave@lists.ettus.com [mailto:usrp-users-leave@lists.ettus.com]