Pi IoT In Python Using Linux Drivers - GPIO Using Ioct |
Written by Mike James & Harry Fairhead | |||||
Monday, 29 July 2024 | |||||
Page 3 of 4
GPIO OutputThe next step is to set a GPIO line to output and use it. This involves only a few more ideas than the previous example. We need to go through the same steps, but in this case we first use the GPIO chip to make a GPIO handler device. This represents multiple GPIO lines, i.e. you can work with a group of lines, not just one line at a time. This is a two-stage process. First get the GPIO chip and then ask it to configure the GPIO lines and return a new file descriptor to the GPIO lines. The request constant for setting a line to a particular state and returning a new file descriptor that references the set line is: GPIO_GET_LINEHANDLE_IOCTL=0xC16C B403 The appropriate C struct is: struct gpiohandle_request { __u32 lineoffsets[64]; __u32 flags; __u8 default_values[64]; char consumer_label[32]; __u32 lines; int fd; }; The corresponding Python Struct object is: gpiohandle_request = struct.Struct("64L L 64B 32s L L") This has to be initialized to sensible values before the ioctl call. The lineoffsets is simply a list of GPIO line numbers that you want to set and the flags field is some combination of:
All of the lines specified in lineoffsets are set to the same state. Notice that you can OR the flags together where this makes sense, for example to request an active low output with an open drain. Two additional flags will be made available in the future:
The default_values array sets output lines to high or low, depending on whether you store 1 or 0 in each element. The consumer_label assigns a label to each of the lines. Finally the lines field determines the number of lines being used, i.e. the number of elements of the lineoffsets array that contain meaningful data. The final fd field is used to return a file descriptor for the lines. Now we are ready to write the program. First we set up the gpiohandle_request struct: lines = [0]*64 lines[0] = 4 lines[1] = 17 values = [0]*64 buffer = gpiohandle_request.pack(*lines, You can see that we are using GPIO4 and GPIO17 and setting both to output. They are also both set to start at 0 and are labeled Output test. To actually set up these lines and get a file descriptor to them we need to call ioctl(): f = io.open("/dev/gpiochip0", "rb", buffering=0) result = fcntl.ioctl(f, GPIO_GET_LINEHANDLE_IOCTL, Again, no error checking is included. Notice that we can close the GPIO chip as we now have the file descriptor to the lines that have been set up. Opening the line returns a file descriptor in the gpiohandle_request struct – in this case in the final four bytes of the result. The simplest way of getting the file descriptor is to use: fL = struct.unpack_from("L", result, 360)[0] You don’t export or unexport a line, but you have ownership of the line until you close the file. However, in this case closing the file isn’t a matter of fL.close() because f really is a file descriptor and hence a simple integer. The solution is to use the os module’s close function: os.close(fL) Notice that you have to close the file if you want to open the line in a different configuration.
Now we have the lines set up as outputs, we can use the request: GPIOHANDLE_SET_LINE_VALUES_IOCTL=0xC040B409 to set the line states. It should come as no surprise that there is also a corresponding GET request: GPIOHANDLE_GET_LINE_VALUES_IOCTL =0xC040B408 and both use the C struct: struct gpiohandle_data { __u8 values[GPIOHANDLES_MAX]; }; which has the Python equivalent: gpiohandle_data = struct.Struct("64B") When you use SET the values array specifies what the lines should be set to. When you use GET the values returned are the states of the lines. Now we can write a loop that toggles the GPIO lines we have set up: values[0] = 1 values[1] = 0 state1 = gpiohandle_data.pack(*values) values[0] = 0 values[1] = 1 state2 = gpiohandle_data.pack(*values) while(True): result = fcntl.ioctl(f, Notice that we have to use two byte strings, state1 and state2, because you cannot change byte strings. Again, error handling has been ignored for the sake of simplicity. |
|||||
Last Updated ( Tuesday, 30 July 2024 ) |