Dallas 1 Wire Protocol with Yocto/Raspberry Pi 3 - linux

I have been trying to get a custom Yocto build off the ground for some time now. The goal is to connect a DS18b20 thermometer to the GPIO pins and test that it is indeed working. I have gotten as far as building out the base image and adding on all of the software packages I needed to it. The problem presents itself when I try to connect and detect the thermometer with my custom firmware image. It boots fine, networking works, wifi works, have not tried BT yet as I don't need it, but the GPIO pins are the ones that are not proving to be of help.
I am using a 4.9.x Linux Kernel on it. Is it recommended I downgrade to a 4.4.x Linux Kernel? I've pretty much run out of ideas at this point, just need some help to figure it out. f

This device is supported by the kernel, no need to mess with searching or writing your own w1 driver.You will need to ensure the CONFIG_W1_SLAVE_THERM, CONFIG_W1_MASTER_GPIO and CONFIG_W1 are set in you kernel config (consult the Yocto kernel documentation for setting this one-time or in a way that will persist over several builds).
This usually leaves the only remaining gap being which GPIO pin is used for w1. Without knowing which device you are using I can only provide some pointers. The connection is defined via a platform data. This can be defined in the device tree, for example with a c.h.i.p.
onewire {
compatible = "w1-gpio";
gpios = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
pinctrl-names = "default";
pinctrl-0 = <&chip_w1_pin>;
};
Where PD2 == LCD-D2 on the header.
Alternatively it can be defined in the mach-* in the kernel, for example
static struct w1_gpio_platform_data w1_gpio_platform_data = {
.pin = GPIO_ONE_WIRE,
.is_open_drain = 0,
};
static struct platform_device raumfeld_w1_gpio_device = {
.name = "w1-gpio",
.dev = {
.platform_data = &w1_gpio_platform_data
}
};
A google search of 'w1-gpio map gpio' should return more and better details. If you can use the device tree approach, that is what they are made for. Just know that the kernel code doesn't cycle through the GPIO pins looking for connected w1 devices, this mapping has to be set.
If the device is attached and working you will be able to get its value by doing 'cat /sys/bus/w1/devices/28*/w1_slave'. If you are using python you can use https://github.com/timofurrer/w1thermsensor to make reading the temperature easy. Or use equivalent libraries for your preferred language.

Related

How to set chip select in SPI programming for multipleslaves ? (struct spi_ioc_transfer)

Maybe I am asking the wrong question actually but I am just making my first steps in the embedded world. So I am sorry if the question is somehow stupid.
I am trying to program a software for 9DOF IMU in c++ and linux environment.
As far as I understood the SPI, the SS pin has to be low active in order for a transmission to occur. I have seen multiple reading or writing bytes function examples and all using the struct spi_ioc_transfer but they were all single slave examples and there is no mention about setting or configuring the SS in the code. Also When I check the structre of spi_ioc_transfer there is the cs_change however, how does it know which cs we are dealing with from the beginning ?
The chip select (CS or SS) to use is determined by which device node you open.
To talk to a SPI chip with the Linux spidev driver, you open a device such as /dev/spidev0.1. The numbers in the device node file name refer to the bus and chip select, respectively — in this example it would be the first bus (0) and the second CS (1). If you want to talk to devices on different chip-selects, you have to open different device nodes and do ioctls on the appropriate one.

How to set a pin between boot and module load for an embedded Linux?

I am facing an interesting problem. I like to set a pin of my cpu. So far I created a module for controlling the pin. This module is setting the default pin configuration(high). The default pin configuration becomes active when the module is loaded. That is working fine.
Now I like to enable my default pin configuration right away from the start of boot process. To archive that I wrote a patch for the ATMEL bootloader(at91bootstrap) and the uboot(u-boot-at91). This works fine till the moment the kernel starts. At the kernel start the pins is set to the ATMEL default. They pins are defined in the device tree as gpios.
I think I have two possibilities:
1st - patch the /init/main.c at the "right" spot. Where is the right spot?
2nd - modify the device tree to set the GPIOs to an other default value. How to "re set" an gpio a value?
When you modify the pin in u-boot level; it will be override by the kernel. /init/main.c is worse idea and so I think you should not followed this approach
In kernel level if you you want to set the GPIO pin, there are two possibilities (apart from your module)
1) Kernel board file.
2) Device tree file.
Suppose if you want to set the SDIO pin as GPIO in i.MX6 board then you need to modify the code like this.
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds>;
red {
gpios = <&gpio7 0 0>;
default-state = "on";
};
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 //set the pin as GPIO
For the default state of the pin please refer the datasheet of your processor. And one pin may have different functionalities.
And if you want to use the same pin for some other functionalities instead of GPIO then you can choose on of the below configuration.
MX6QDL_PAD_SD3_DAT5__UART2_RX_DATA //UART2 RX Data pin
MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 //As a GPIO pin
MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA // UART1 RX data
MX6QDL_PAD_SD3_DAT6__SD3_DATA6 //SDIO pin which is default in this case
Please add more details if you are looking for something more (like pin number and device tree file name).

Need to find and open a USB serial device on linux

I'm writing a small C application to run on my (Linux) QNAP NAS that will talk to an Arduino (I have no difficulty with any of the USB code for the arduino). (The arduino has a trusted application on it that accepts text commands via USB serial.)
My wish was to find it using the USB vendor/product IDs (only half implemented at the moment). What I have so far (see below) works quite nicely in that it does find the device.
// runs on NAS
#include <stdio.h>
#include <usb.h>
main () {
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("Trying %s/%s\n", bus->dirname, dev->filename);
printf("\tVendor = 0x%04x\n", dev->descriptor.idVendor);
printf("\tBus = 0x%03x\n", bus->location);
printf("\tFile = %s\n", dev->filename);
if (dev->descriptor.idVendor==0x403) {
printf("\t HEY, THIS IS MINE!\n");
usb_dev_handle *handle = usb_open(dev);
printf("\t HANDLE 0x%08x\n", (int) handle);
//printf(handle, "1,5,62,75\n");
usb_close(handle);
}
}
}
}
The trouble is that now I want to send/receive a little bit of text with the device and I don't know how to do that.
I have expected I should be generating a device name from something in the usb_device struct and then open it like a file (like one would do on Windows).
If that's correct, I need to know the correct way to find out the device name...
I believe I'm using libusb.
I happen to know that -- as currently configured/connected -- it's ttyUSB0 but I'd like to know that using code.
thank you!
I suggest using libusbp. It is a C library with a C++ wrapper, and there is example code showing how to get the name of a serial port based on the vendor ID and product ID of the USB device:
https://github.com/pololu/libusbp/blob/master/examples/port_name/port_name.cpp
libusb is a library used for low level communication with USB devices. But when your communication is limited just to reading device's USB descriptor - libusb is not the best tool.
Linux systems use udev subsystem to manage hot-plug devices. udev reads descriptors of all plugged USB devices and stores them in its database. libudev is the library that you should use to get such info like device names of enumerated devices. In your case you need to remember that usb_device and usb_interface are separate things - only the latter would have the tty device file assigned to it.
Alternatively you could just use udev config to assign a constant device name to your specific device. So you would not have to be looking for it.

Named GPIOs in DeviceTree

I am trying to create a device tree for an embedded system, and would like to expose a few GPIOs to userspace. These are not and should not be used by kernel drivers. For instance, there is a USB device soldered to the board that is controlled by a user-space driver. It has a GPIO reset line, which the userspace library needs to access.
I would like these to be exposed by name in sysfs somewhere so that userspace can access /sys/class/gpio/usbreset instead of needing to know the magic gpio number and needing to specifically "export" it. I have tried setting it up as a GPIO hog, which initializes the GPIO, but its name does not appear in sysfs, and the gpio cannot be exported when it is hogged. I know that I can pick another kernel driver type such as LED, but it is not an LED, and this does not seem very clean to me.
What is the right way to export a named GPIO in sysfs?
You can use the "gpio-leds" type in the devtree. Make sure you have CONFIG_LEDS_GPIO in your kernel. Set up your devtree as described in Documentation/devicetree/bindings/leds/leds-gpio.txt. I know, it says "LED", but the driver just wiggles the GPIO, and doesn't care what's hooked up to it.
Example devtree entry (copied from the docs):
run-control {
compatible = "gpio-leds";
red {
gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
green {
gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
};
Those entries will be accessible by name in sysfs, and you can manipulate them from userspace there.
I propose writing a simple kernel module to ask for the GPIO and then exporting a link, the link can be named and hence suitable for your request.
https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
from the link above:
After the GPIO has been exported, gpiod_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name

How to program Linux .dts device tree files?

I'm going to launch a Linux on my development board, and i need a dts file (device tree file) to describe the whole hardware. But I only know very little about the syntax of this file which is not enough to run Linux properly on the board.
What i know now are only how to describe a unit's interrupt number, frequency, address, parent-unit and its compatible driver type (as described below):
ps7_scuwdt_0: ps7-scuwdt#f8f00620 {
compatible = "xlnx,ps7-scuwdt-1.00.a";
device_type = "watchdog";
interrupt-parent = <&ps7_scugic_0>;
interrupts = < 1 14 769 >;
reg = < 0xf8f00620 0xe0 >;
} ;
Other advanced usage or grammar is unfamiliar to me.
Take a look at the dts of the board which most closely resembles your dev-board. Use that as a reference and make changes to the dts according to the differences between the reference board and your dev-board.
Also checkout the following :
- Device-tree Documentation project at eLinux (has a vast collection of links to start reading).
- Series of articles on the basics of device tree.
- Walkthrough of migrating to device-tree.
Minimal reg + interrupt example with QEMU virtual device
Our example will add the following device tree node to the versatilepb device tree which QEMU will use due to -M versatilepb:
lkmc_platform_device#101e9000 {
compatible = "lkmc_platform_device";
reg = <0x101e9000 0x1000>;
interrupts = <18>;
interrupt-controller;
#interrupt-cells = <2>;
clocks = <&pclk>;
clock-names = "apb_pclk";
lkmc-asdf = <0x12345678>;
};
Then, by using a Linux kernel module to interact with the device, we will test the following DTS features:
registers addresses
IRQs
read custom properties from the driver
These are the main components of the example:
Linux versatile .dts patch on Linux fork
reg and interrupt match numbers hard-coded in the QEMU versatile machine (which represents the SoC)
compatible matches the platform_driver.name in the kernel module, and informs the kernel which module will handle this device
we also pass a custom property to the driver: lkmc-asdf = <0x12345678>;, which is read with of_property_read_u32
the device tree is passed to QEMU's firmware with the -dtb argument
QEMU fork:
device that reads a register and generates interrupts
insert device into -M versatilepb
kernel module Writes to memory on probe to test things out, which also generates an IRQ.
Device trees have many more features that we haven't covered, but this example should get you started, and easily allow you to play around with any new features that come up.
Further resources:
indispensable elinux tutorial: http://elinux.org/Device_Tree_Usage
play around with dtc for purely syntaxical questions. E.g., it shows how nodes are simply merged by path: https://unix.stackexchange.com/a/375923/32558
https://unix.stackexchange.com/questions/118683/what-is-a-device-tree-and-a-device-tree-blob
Lets take a example and I will explain each one of them as below
auart0: serial#8006a000 {
compatible = "fsl,imx28-auart", "fsl,imx23-auart";
reg = <0x8006a000 0x2000>;
interrupts = <112>;
dmas = <&dma_apbx 8>, <&dma_apbx 9>;
dma-names = "rx", "tx";
};
Required properties:
- compatible : Should be "fsl,-auart". The supported SoCs include
imx23 and imx28.
- reg : Address and length of the register set for the device
- interrupts : Should contain the auart interrupt numbers
- dmas: DMA specifier, consisting of a phandle to DMA controller node
and AUART DMA channel ID.
- dma-names: "rx" for RX channel, "tx" for TX channel.
Note: Each auart port should have an alias correctly numbered in "aliases"
node.
For more advance properties, please go to this link, it is very useful
Device Tree Explanation
Hope it helps!
Complementary to the other answers:
Keep in mind, that there is also a section for devicetrees in the official kernel source under root/Documentation/devicetree(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree?h=v5.2-rc5).

Resources