Apparent diameter plot for Jupiter 2017-2026

The apparent diameter of Jupiter varies with the Earth-Jupiter distance. Depending on the distance, the apparent angular diameter of Jupiter is between approx. 0.5 and 0.8 arcminutes. For best astrophotography results, one should pick a time when Jupiter is closest. Similar to my plot of the apparent size of Venus, I wrote a short program to plot Jupiter’s apparent diameter for the time period 2017-2026 (see featured image).

Apparent diameter plot for the Moon 2017-2018

The apparent diameter of the Moon varies with the Earth-Moon distance. Depending on the distance, the apparent angular diameter of the Moon is between 29.4 and 33.5 arcminutes. For best astrophotography results, one should pick a time when the moon is closest. Similar to my plot of the apparent size of Venus, I wrote a short program to plot the Moon’s apparent diameter (see featured image).

Venus apparent diameter plot for 2017-2020

The apparent size of Venus varies dramatically with the Earth-Venus distance, depending on both orbits around the sun. The apparent angular diameter of Venus is between 0.175 and 1 arcminutes.

Wikipedia has nice images on that and says that…

“the extreme crescent phase of Venus can be seen without a telescope by those with exceptionally acute eyesight, at the limit of human perception.”

I will definitely try next time with my naked eyes, but if you have an entry-level telescope, you will be certainly be better able to see the crescent phase during closest approach.

The question is, when does Venus come closest to Earth for best observation? Not finding anything on the interwebs, I wrote a quick plotting program with Python’s ephem package and gnuplot.

Venus apparent diameter plot for 2017-2020

Graph of apparent diameter of Venus in arcminutes for the time period 2017-2020
Graph of apparent diameter of Venus in arcminutes for the time period 2017-2020

Here is the very short Python program that calculates the apparent diameter of Venus for 4 years beginning with January 2017:

#!/usr/bin/python3

import datetime as dt
import ephem
import math
from math import radians as rad, degrees as deg

venus = ephem.Venus()

venus_diameter_meters = 2 * 6051800
au_meters = 149597870700

t = dt.datetime.strptime("20170101", "%Y%m%d")

diff = dt.timedelta(days = 1)

for i in range(0, int(4 * 365)):
    venus.compute(t)
    
    dist_venus_meters = venus.earth_distance * au_meters
    
    angular_diameter_arcminutes = 60 * deg(2 * math.asin(venus_diameter_meters / (2 * dist_venus_meters)))
    
    print(t.strftime("%Y-%m-%d"), angular_diameter_arcminutes)
    t += diff

Reading Raspberry Pi chip temperature with mainline Linux kernel

This tutorial is based on a previous article where we installed pure Debian 9 with a recent mainline/vanilla Linux kernel on a Raspberry Pi, and so differs from what would be done on a Raspbian Distribution with a Raspbian kernel. In this article, we will read the Raspberry Pi chip temperature. Here is my previous article:

https://blog.michael.franzl.name/2016/10/31/raspberry-pi-debian-stretch/

As of mainline Linux Kernel 4.9.0-rc3, the sysfs entry /sys/class/thermal for the Broadcom BCM283x chip found on Raspberry Pi’s is empty. You can apply the following patch to Linux kernel 4.9.0-rc3, even though it will soon be superfluous because it seems that currently there is ongoing work by Linux Kernel developers to add in the missing functionalities.

The patch which will get you the standard sysfs temperature node which you can read like this:

cat /sys/class/thermal/thermal_zone0/temp
40084

This is the chip temperature in thousandths of degrees cenigrade, i.e. 40.084 degrees Celsius.

The following patch will give you a new entry in the mainline Kernel config, under Drivers -> SoC -> BCM -> Raspberry Pi thermal sysfs driver, which you have to enable, then recompile your kernel.

I have actually submitted this patch to a Linux kernel developer, but the process to get code into the Linux kernel is quite elaborate, and he said that they are already working on it, so I let it drop and decided to write this blog post instead.

Copied drivers/thermal/bcm2835-thermal.c from Raspberry Pi
Foundation Linux kernel to drivers/soc/bcm/raspberry-thermal.c
and added respective entry to the device tree.

Tested and confirmed working on a Raspberry Pi 2 Model B V1.1 2014.

Signed-off-by: Michael Franzl <office@blog.michael.franzl.name>
Tested-by: Michael Franzl <office@blog.michael.franzl.name>

 arch/arm/boot/dts/bcm2835-rpi.dtsi    |   5 ++
 arch/arm/configs/multi_v7_defconfig   |   1 +
 drivers/soc/bcm/Kconfig               |   9 +++
 drivers/soc/bcm/Makefile              |   1 +
 drivers/soc/bcm/raspberrypi-thermal.c | 109 ++++++++++++++++++++++++++++++++++
 5 files changed, 125 insertions(+)
 create mode 100644 drivers/soc/bcm/raspberrypi-thermal.c

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e9b47b2..389ee83 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -22,6 +22,11 @@
 			mboxes = <&mailbox>;
 		};
 
+		thermal: thermal {
+			compatible = "raspberrypi,bcm2835-thermal";
+			firmware = <&firmware>;
+		};
+
 		power: power {
 			compatible = "raspberrypi,bcm2835-power";
 			firmware = <&firmware>;
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 11f37ed..1368e63 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -838,6 +838,7 @@ CONFIG_XILINX_XADC=y
 CONFIG_CM36651=m
 CONFIG_AK8975=y
 CONFIG_RASPBERRYPI_POWER=y
+CONFIG_RASPBERRYPI_THERMAL=y
 CONFIG_PWM=y
 CONFIG_PWM_ATMEL=m
 CONFIG_PWM_ATMEL_HLCDC_PWM=m
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
index a39b0d5..c951de4 100644
--- a/drivers/soc/bcm/Kconfig
+++ b/drivers/soc/bcm/Kconfig
@@ -20,4 +20,13 @@ config SOC_BRCMSTB
 
 	  If unsure, say N.
 
+config RASPBERRYPI_THERMAL
+	tristate "Raspberry Pi thermal sysfs driver"
+	depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
+	depends on RASPBERRYPI_FIRMWARE=y
+	depends on THERMAL
+	help
+	  This enables a thermal sysfs driver for the thermal sensor on
+	  Broadcom283x chips found on a Raspberry Pi.
+
 endmenu
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
index dc4fced..41734e1 100644
--- a/drivers/soc/bcm/Makefile
+++ b/drivers/soc/bcm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_RASPBERRYPI_POWER)	+= raspberrypi-power.o
 obj-$(CONFIG_SOC_BRCMSTB)	+= brcmstb/
+obj-$(CONFIG_RASPBERRYPI_THERMAL)	+= raspberrypi-thermal.o
diff --git a/drivers/soc/bcm/raspberrypi-thermal.c b/drivers/soc/bcm/raspberrypi-thermal.c
new file mode 100644
index 0000000..34a829f
--- /dev/null
+++ b/drivers/soc/bcm/raspberrypi-thermal.c
@@ -0,0 +1,109 @@
+/*****************************************************************************
+* Copyright 2011 Broadcom Corporation.  All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+static int bcm2835_thermal_get_property(struct thermal_zone_device *tz,
+					int *temp, u32 tag)
+{
+	struct rpi_firmware *fw = tz->devdata;
+	struct {
+		u32 id;
+		u32 val;
+	} packet;
+	int ret;
+
+	*temp = 0;
+	packet.id = 0;
+	ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
+	if (ret) {
+		dev_err(&tz->device, "Failed to get temperature\n");
+		return ret;
+	}
+
+	*temp = packet.val;
+	dev_dbg(&tz->device, "%stemp=%d\n",
+		tag == RPI_FIRMWARE_GET_MAX_TEMPERATURE ? "max" : "", *temp);
+
+	return 0;
+}
+
+static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
+				    int *temp)
+{
+	return bcm2835_thermal_get_property(tz, temp,
+					    RPI_FIRMWARE_GET_TEMPERATURE);
+}
+
+static struct thermal_zone_device_ops ops  = {
+	.get_temp = bcm2835_thermal_get_temp,
+};
+
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+	struct device_node *fw_np;
+	struct rpi_firmware *fw;
+	struct thermal_zone_device *tz;
+
+	fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+	if (!fw_np) {
+		dev_err(&pdev->dev, "Missing firmware node\n");
+		return -ENOENT;
+	}
+	fw = rpi_firmware_get(fw_np);
+	if (!fw)
+		return -EPROBE_DEFER;
+
+	tz = thermal_zone_device_register("bcm2835_thermal", 0, 0, fw, &ops,
+					  NULL, 0, 0);
+	if (IS_ERR(tz)) {
+		dev_err(&pdev->dev, "Failed to register the thermal device\n");
+		return PTR_ERR(tz);
+	}
+
+	platform_set_drvdata(pdev, tz);
+
+	return 0;
+}
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+	thermal_zone_device_unregister(platform_get_drvdata(pdev));
+
+	return 0;
+}
+
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
+	{ .compatible = "raspberrypi,bcm2835-thermal", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
+
+static struct platform_driver bcm2835_thermal_driver = {
+	.probe = bcm2835_thermal_probe,
+	.remove = bcm2835_thermal_remove,
+	.driver = {
+		.name = "bcm2835_thermal",
+		.of_match_table = bcm2835_thermal_of_match_table,
+	},
+};
+module_platform_driver(bcm2835_thermal_driver);
+
+MODULE_AUTHOR("Dorian Peake");
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+MODULE_LICENSE("GPL");
-- 
2.1.4


 

Setting I2C bus speed on a Raspberry Pi via Device Tree

This tutorial is based on my previous article where we installed pure Debian 9 with a recent mainline/vanilla Linux kernel, and so differs from what would be done on a Raspbian Distribution with a Raspbian kernel. In this article, we will set the I2C bus speed on a Raspberry Pi. Here is my previous article:

https://blog.michael.franzl.name/2016/10/31/raspberry-pi-debian-stretch/

Device Trees

The I2C bus on the Broadcom BCM283x chips found on Raspberry Pi’s is well and directly supported by the mainline/vanilla Linux kernel. Since with the Raspberry Pi we’re dealing with a System on a Chip (SoC), and not a regular PC, the hardware is configured with so-called device trees, which is a low-level description of the chip hardware compiled from text into binary format.

The rpi23-gen-image script mentioned in my previous tutorial installs the binary device tree into /boot/firmware/bcm2836-rpi-2-b.dtb. The U-Boot bootloader can read this file and pass it to the Linux kernel which interprets it and enables all the mentioned features in it.

The clock frequency for the I2C bus is configured in this .dtb file, and the default is 100kHz. There is a tool which allows you to inspect the .dtb file, outputting regular text. With this tool you also can make changes to the device configuration. Nowadays, this is the proper way to configure low-level devices on SoC’s!

 

Read the device tree

apt-get install device-tree-compiler
fdtdump /boot/firmware/bcm2836-rpi-2-b.dtb

This will output the decoded device tree as text. Regarding I2C, you will find i2c@-entries like this:

        i2c@7e205000 {
            compatible = "brcm,bcm2835-i2c";
            reg = <0x7e205000 0x0000005c>;
            interrupts = <0x00000002 0x000000e9>;
            clocks = <0x00000008 0x00000022>;
            #address-cells = <0x00000001>;
            #size-cells = <0x00000000>;
            status = "okay";
            clock-frequency = <0x000186a0>;
        };
        i2c@7e804000 {
            compatible = "brcm,bcm2835-i2c";
            reg = <0x7e804000 0x0000005c>;
            interrupts = <0x00000002 0x000000e9>;
            clocks = <0x00000008 0x00000022>;
            #address-cells = <0x00000001>;
            #size-cells = <0x00000000>;
            status = "okay";
            clock-frequency = <0x000186a0>;
        };

Change the device tree

The clock-frequency value is what we want to change. The value is a raw binary unsigned 32-bit int stored big-endian, unreadable for humans.

But you can use another tool fdtget to read just this value decoded:

fdtget /boot/firmware/bcm2836-rpi-2-b.dtb /soc/i2c@7e205000 clock-frequency

This will output 100000.

In my case, I wanted to set the I2C bus to the slowest frequency, to compensate for long cable lengths. I found that one of the lowest supported I2C clock frequencies is 4kHz. With fdtput you can set the clock-frequency property for each i2c device (there are 3 on the RPi):

fdtput --type u /boot/firmware/bcm2836-rpi-2-b.dtb /soc/i2c@7e205000 clock-frequency 4000

And that’s it. You have to reboot for these settings to take effect.

I used an oscilloscope to verify that the SCL pin of the GPIO of the RPi indeed toggled with 4kHz, and it did!