Controlling a LED via CAN

Sending data from Linux (via socketcan) is neat and works well. Sending data from Arduino (via AA_MCP2515) is working too. But receiving devices I only have one: the SERVO42D.

Thus it’s time to make the Arduino receive CAN frames and act on them. Since the MEGA2560 I have has the typical built-in LED, it’s what I’d like to control.

  • to turn the LED on, send a 0x01
  • to turn the LED off, send a 0x00
  • to toggle the LED, send a 0x02

I chose CAN ID 2 and there’s no error checking whatsoever to keep it simple. Here is the complete code:

#include "AA_MCP2515.h"

const CANBitrate::Config CAN_BITRATE = CANBitrate::Config_8MHz_500kbps;
const uint8_t CAN_PIN_CS = 53;
const int8_t CAN_PIN_INT = 2;

const int ledPin = LED_BUILTIN;
int ledState = 0;

CANConfig config(CAN_BITRATE, CAN_PIN_CS, CAN_PIN_INT);
CANController CAN(config);

void onReceive(CANController&, CANFrame frame) {
/*
  frame.print("RX");
  int id = frame.getId();
  uint8_t *data;
  data = frame.getData();
  int dlc = frame.getDlc();
  Serial.print("Ch ");
  Serial.print(id);
  Serial.print(" DLC ");
  Serial.print(dlc);
  Serial.print(" data ");
  for (int i=0; i<dlc; ++i) {
    Serial.print(data[i]);
    Serial.print(" ");
  }
  Serial.print('\n');
*/
  if (id == 2) {
    if (data[0] == 0) ledState = 0;
    else if (data[0] == 1) ledState = 1;
    else if (data[0] == 2) ledState = !ledState;
    digitalWrite(ledPin, ledState);
  }
}

void onWakeup(CANController& controller) {
  controller.setMode(CANController::Mode::Normal);
}

void setup() {
  Serial.begin(115200);

  while(CAN.begin(CANController::Mode::Config) != CANController::OK) {
    Serial.println("CAN begin FAIL - delaying for 1 second");
    delay(1000);
  }
  Serial.println("CAN begin OK");

  // CAN controller is in Config mode so setup receive filters, then change to Normal mode.
  // The receive filters will be setup to only receive 11-bit ID's 0x0100, and 0x0103. All other ID's will be filtered out / ignored.
  // 11-bit ID filter
  // Filter for ID=1 and ID=2
  CAN.setFiltersRxb0(0x001, 0x002, 0x07ff, false);
  CAN.setFiltersRxb1(0x100, 0x001, 0x001, 0x001, 0x07ff, false);
  CAN.setFilters(true);
  
  // -or- 29-bit ID filter
  // CAN.setFiltersRxb0(0x100, 0x106, 0x1FFFFFFF, true);
  // CAN.setFiltersRxb1(0x100, 0x100, 0x100, 0x100, 0x1FFFFFFF, true);
  // CAN.setFilters(true);

  Serial.println("CAN filters setup");

  CAN.setMode(CANController::Mode::Normal);

  pinMode(ledPin, OUTPUT);

  CAN.setInterruptCallbacks(&onReceive, &onWakeup);
}

void loop() {
  delay(2000);
}

The filter is set up for ID=1 and ID=2. The code only acts on ID=2 though.

Now you can turn the LED on or off via

# LED on
cansend can0 '002#01'
# LED off
cansend can0 '002#00'
# Toggle LED
cansend can0 '002#02'

With that, I can control something more complex, like a bunch of WS2812B LEDs too!

CAN Bus on a Banana Pi M1

The AllWinner A20 has a built-in CAN Bus controller and the only thing needed is the transceivers like a SN65HVD230. Since I have a Banana Pi M1 how hard is it too use it as a CAN Bus node?

Turns out to be very simple and the only thing required was a small CAN Bus transceiver module for about US$3.

Needed parts:

  • Banana Pi M1
  • SN65HVD230 CAN Bus transceiver module (found on AliExpress)
  • SD card with Armbian 23.11.1

Add this one line to /boot/armbianEnv.txt resp. add can as another overlay if you added already some modules:

overlays=can

Also edit one line in the sun7i-a20-bananapi.dtb module:

cp /boot/dtb/sun7i-a20-bananapi.dtb /boot/dtb/sun7i-a20-bananapi-original.dtb
dtc -O dts -o /tmp/sun7i-a20-bananapi.dts /boot/dtb/sun7i-a20-bananapi.dtb
# edit the status from disabled to okay for the can@1c2bc00 section (phandle 0xb7)
dtc -O dtb -o /boot/dtb/sun7i-a20-bananapi.dtb /tmp/sun7i-a20-bananapi.dts

Next create a new sun7i-a20-can.dtb:

cp /boot/dtb/overlay/sun7i-a20-can.dtbo /boot/dtb/overlay/sun7i-a20-can-original.dtbo

cat > sun7i-a20-can.dts << _EOF_
/dts-v1/;
/plugin/;

/ {
        compatible = "allwinner,sun7i-a20";

        fragment@0 {
                target = <&can0>;
                __overlay__ {
                        pinctrl-names = "default";
                        pinctrl-0 = <&can_ph_pins>;
                        status = "okay";
                };
        };
};
_EOF_

dtc -O dtb -o /boot/dtb/overlay/sun7i-a20-can.dtbo

The changed to the two sun7i-a20 modules enable CAN on port H pins. No idea why this is not done by default for the BananaPi…

Important things to be aware of to make the CAN controller on the A20 work:

  • There are 2 possible sets of pins for CAN bus on the A20: A port (PA16/PA17) or H port (H20/H21). On the BananaPi H port must be used as only those are available on the 26 pin connector
  • The A20 is not 5V compatible, so do not use a 5V transceiver: Using 5V will kill the pins on the A20, and using 3.3V will make a not-compatible CAN bus signal. Thus do not use a 5V SPI MCP2515 module either.

Install can-utils if not already done: apt install can-utils and after a reboot, you should have can0 (check with ip link).

To initialize it at boot time, I added this to /etc/rc.local:

( sleep 5 ; ip link set can0 type can bitrate 500000 ; ip link set up can0 ; ip link set can0 txqueuelen 128 ) &
exit 0

And the result is a working can0 interface:

# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: end0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:19:08:64:20:fe brd ff:ff:ff:ff:ff:ff
3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 128
    link/can

Doing my usual test to make slow spinning stepper (on CAN ID 0x001): cansend can0 "001#f600100108" works!

CAN Galore!

Thus now I have several CAN Bus nodes:

  • The Banana Pi M1
  • Any Linux USB computer via e.g. Makerbase CANable 2.0 SHELL USB to CAN adapter
  • Arduino Micro via SPI and a 5V MCP2515/transceiver module (US$ 2)
  • Arduino Mega 2560 via the same SPI module
  • ESP32C3 and its CAN bus extension
  • and of course the “Makerbase MKS SERVO42D NEMA17 closed loop stepper motor” with CAN

PWM on a Banana Pi M1

While waiting for CAN bus transceivers, here’s how to enable PWM on the Banana Pi M1. There’s 2 PWM pins: one is used for the internally connectable LCD (PWM0), and the other one (PWM1) is available on the 26 pin GPIO list (pin 7, PI3)

Enable in /boot/armbianEnv.txt:

overlays=pwm
param_pwm_pins=both

To enable and use:

cd /sys/devices/platform/soc/1c20e00.pwm/pwm/pwmchip0
# use 1 to export PWM1, and 0 to export PWM0
echo 1 > export
# After enabling export, there's a new directory:
cd pwm1
# All times in ns
echo 1000000 > period
echo 300000 > duty_cycle
echo 1 > enable

and you get a 30% off, 70% on PWM with 1kHz.

I am assuming a recent Armbian, e.g. from November 2023 (kernel 6.1.63).

CAN on Orange Pi Zero

Enabling CAN is not that difficult once SPI works, although you lose the SPI interface since it’s used by the MCP251x module.

Here the needed parts:

  • Recent Armbian for orange Pi Zero
  • Edit /boot/armbianEnv.txt to have those lines:
overlays=spi-add-cs1 spi-spidev tve usbhost2 usbhost3
param_spidev_spi_bus=1
param_spidev_max_freq=100000000
user_overlays=spi-mcp251x
  • This DTS file:
/dts-v1/;
/plugin/;

/ {
        compatible = "allwinner,sun4i-a10", "allwinner,sun7i-a20", "allwinner,sun8i-h3", "allwinner,sun50i-a64", "allwinner,sun50i-h5";

        fragment@0 {
                target-path = "/clocks";
                __overlay__ {
//                      #address-cells = <1>;
                        #size-cells = <1>;
                        can0_osc_fixed: can0_osc_fixed {
                                compatible = "fixed-clock";
                                #clock-cells = <0>;
                                clock-frequency  = <8000000>;
                        };
                };
        };

        fragment@1 {
                target = <&pio>;
                __overlay__ {
                        can0_pin_irq: can0_pin_irq {
                                pins = "PA7";
                                function = "irq";
                                bias-pull-up;
                        };
                };
        };

        fragment@2 {
                target = <&spi1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";
                        can:mcp2515@0 {
                                reg = <0>;
                                compatible = "microchip,mcp2515";
                                pinctrl-names = "default";
                                pinctrl-0 = <&can0_pin_irq>;
                                spi-max-frequency = <10000000>;
                                interrupt-parent = <&pio>;
                                interrupts = <0 7 8>;
                                clocks = <&can0_osc_fixed>;
                                status = "okay";
                        };
                };
        };
};

and compile via

dtc -@ -o spi-mcp251x.dtbo spi-mcp251x.dts
cp spi-mcp251x.dtbo /voot/overlay-user/
  • Reboot and you should have a CAN interface showing up (check dmesg or ip link)

Initialize the CAN bus like this:

ip link set can0 type can bitrate 500000
ip link set up can0
# test CAN 2.0A
cansend can0 '123#1122334455667788'
# test CAN 2.0B
cansend can0 '1F334455#1122334455667788'

You should at this point see CAN messaged being sent out repeatedly since they don’t get acknowledged:

Taken via Saleae and its CAN bus analyzer, signal taken from Pin 1 of the TJA1050

SPI on Orange Pi Zero

I had no need for SPI on my many Orange Pi Zero. Now I do, and thus enabling it is needed. Not hard, but not trivial either, which is why I document it here:

  1. Have a recent Armbian, e.g. https://www.armbian.com/orange-pi-zero/
  2. Run “sudo armbian-config”, System, Hardware, enable spi-spidev
  3. Reboot

In theory that should be it and you should now have a /dev/spidev0.0, however I had to edit /boot/armbianEnv.txt first:

verbosity=1
bootlogo=false
console=both
disp_mode=1920x1080p60
overlay_prefix=sun8i-h3
overlays=spi-spidev tve usbhost2 usbhost3
param_spidev_spi_bus=1
param_spidev_max_freq=100000000
rootdev=UUID=01234567-ffff-eeee-dddd-000000000001
rootfstype=ext4
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u

and add the two param_spidev_* lines. Once rebooted, I finally got /dev/spidev1.0

Note that the pins for spidev0 are not available on an Orange Pi Zero, while the pins for spidev1 are:

AKG Lyra – Opening

I got myself a nice AKG Lyra microphone when it came out about 4 years ago. If you do a lot of audio/video conferencing, it’s worth to have a good microphone. This one counts as a good one.

This morning when I used it, I could only hear sound on my left monitor headphone. I once had this and a repeated tap on the microphone fixed it. Today that did not help. So time to check if maybe a microphone capsule has a contact or cable problem.

To make this easier for everyone I’ll explain how to open the top part:

Lyra and how to open

  1. Unscrew the microphone from the microphone holder. There’s some washers. Keep them on the screw.
  2. Pop off the AKG round plate. Below it is a hex screw. Unscrew it. Same on the back.
  3. The above screw holds the piece 3 in place. After being unscrewed, simply lift it off
  4. Now the front/top/back mesh can be moved upwards.
  5. The sides do not move off.

After removing the mesh, you’ll see the 4 microphone capsules.

In my case all were working just fine and the culprit was the headphone which had the right side somehow broken. Cable broken internally is my guess. Another headphone worked perfectly. Time for a new headphone.

Identiv uTrust FIDO2 NFC+ Security Key (USB-C): Lacking Linux Support

I was looking for a USB-C NFC enabled FIDO2 key which also works as a SmartCard (AKA PIV mode). The Yubikey 5C NFC is known to work, but the Identiv uTrust FIDO2 NFC+ does (on paper) the same and costs half even after importing from US (via amazon.com). It’s a bit thicker, but generally comparable to the similar Yubikey.

And given that the old Yubikey Neo works well with OpenSC’s pkcs11-tool, I did not expect any issues with the uTrust key…

Well, I was wrong.

On Windows, using the Identiv’s uTrust Key Manager Software I can see that there’s PIV available and I can set PIN, PUK and a management key (same as Yubikey), and create/import certificates.

However on Linux the key is not recognized as PKCS#11 compatible SmartCard. I’d need a module as the default opensc-pkcs11.so does not work, but I cannot find one and Identiv does not seem to have one available (unlike Yubico). To make it worse, this uTrust FIDO2 NFC+ key is rare enough that this is not a common problem which would usually thus be a solved problem.

Ah well…it works as FIDO2 key, it has NFC, it has USB-C. That’s the main reason I wanted this. The PIV mode would have been nice.

Let’s see if Identiv has a usable support service to answer the question how to use PIV under Linux.

Update from 2023-08-13: No reply from Identiv. FIDO2 works on Windows and Android. On Linux it’s a bit different: the libfido2 tools work (thus they recognize the FIDO2 part just fine), but browsers Firefox (v115) has issues: the key is either not recognized at all, or I get the request for the PIN, and then it fails. NFC works reliably though (on my Android phone), and Chrome on Linux works too.
All-in-all, I do not recommend the NFC+ model as PIV totally does not work on Linux. If the choice is between the uTrust NFC (without plus) model or a Yubikey, I’d pick the Yubikey: it’s thinner and better supported on Linux.

iHost – Zigbee fun!

I knew about Zigbee for a long time but never had a reason to use them: WiFi usually works better as long as battery is not an issue, and if it does, Bluetooth LE is really good.

And then I saw that Sonoff built a thing:

  • Ethernet-Zigbee gateway
  • Planned to support Matter
  • Allows IoT to run locally (no Internet needed)
  • No Internet means: much less latency, more secure and more stable
  • A 1.2TOps NPU (2 TOps on the bigger model)
  • With an API to use, so no weird hacks needed
  • Buttons, a speaker and a microphone
  • Can do WiFi and Bluetooth LE too (but not yet supported)
  • Works with Sonoff Zigbee devices, but also Philips and Ikea
  • It runs containers
  • for US$80

Yeah, I could not say “No, I don’t need that”. So I got one. And buttons, power plugs, temperature/humidity sensors and door/window sensors to play with.

Power to the iHost

Powering on the iHost was simple: plug in. Works. Has a web interface. As easy as it sounds. There was no “firmware update” button and it did not update automatically. Turns out that this is only possible via its phone app. And to make that work, you have to let the iHost know your eWeLink account.

This software is in development so upgrading is pretty much mandatory.

Enabling the first wireless button

Since it’s battery-driven and the battery is already installed, there’s usually a plastic insulator to remove. How hard can that be? The instructions look simple:

That looks easy!

Turns out to be harder than expected: problem no. 1 was: how much force am I allowed to use to open that case? Too much force will break parts of plastic off, or break the whole thing, or make it visibly damaged. Also what exactly am I removing here? Just the bottom plate? There seem to be quite some plastic parts inside.

In short: it was confusing. So here some photos of the parts for future generations so they know what to do.

This is the bottom part which is the only part to pry off, and it’s easy to do once you know:

Bottom part. This is supposed to be removed to reach the battery insulator.

Those 4 noses are what holds it to the middle part. Use a flat screwdriver to pull those noses out one by one.

Here is the inner part with the battery and electronics:

The middle part. The actual button is the small thing in the middle. Below that is the board and below that is the battery.

The bottom side of the middle part with the holes for the noses of the bottom plate:

Bottom side of the middle part. You see the plastic insulator to pull out.

I had huge issues pulling out the insulator: it simply would not come out. The tab even broke off and I had to remove the battery, which was not easy at all:

Broken insulator. Once the battery is removed, the board is not held in any way to the plastic.

Re-assembly is very simple however. The arrows help a lot.

Here the top shell, but the inside, so you can see how and where it has flanges:

Top/outer shell, as seen from the inside. Note the nice arrows which make it easy to reassemble.

After inserting the battery again and re-assembling the top and the middle part, pushing the reset button for 5s makes it go into pairing mode. Works within 10-20s and was very reliable after upgrading the firmware to v1.5.5 (from v1.4.x which paired, but it did not tell me about it, so I paired again and again for no good reason).

Paired! What now?

Once some Zigbee devices are paired, you can connect their actions in an easy interface. Here an example which toggles Outlet 2 when I push the Button 2. A simple switch:

An example of a very simple workflow: push a button, and toggle power.

Other actions are: making sound (alarm clock or intruder alarms), or disarm all monitoring etc.

Summary

The iHost is a very neat concept: well thought out features at a good price. Plenty usability features, but also high geek and fun factor (API, runs containers).

It’s not perfect (No BLE, no WiFi, no camera integration, the TPU is not yet used as far as I can see).

The Zigbee devices are cheerful and cheap and their plastic shells are pleasant.

The distance Zigbee operates in this household is about as good (or bad) as Bluetooth LE: 1 wall only. 2 walls don’t work. Not sure what concrete they use here, but it blocks 2.4GHz quite efficiently. Thus I need more Zigbee devices which act as router.

PS: As I am writing this, v1.6.0 is out, and this time the web interface of the iHost allows me to upgrade.

Raspberry Pico RP2040 and JavaScript

I like Espruino on ESP32: It has WiFi, enough I/O to be useful and it runs on JavaScript (Espruino). The RP2040 from the Raspberry Pi Organization has one thing I have not seen though: a clever I/O engine which can be used to create various protocols with its surprisingly capable state machine.

This needs to be tested!

Cytron Maker Pi RP2040

So I went to my favorite electronics shop and got myself a Cytron Maker Pi RP2040. Initially a “normal” Raspberry Pi Pico would have been ok, but the Cytron has Grove connectors, a bunch of LEDs, servo connectors, a motor driver and a noise-making piezo. I got a lot of Grove modules from my M5Stack, so Cytron it was!

Once at home, turn it on, see and hear the demo, then flash with Kaluma. Nice CLI, but less interactive compared to Espruino. Tested the built-in WS2812B LEDs and they worked.

Kind’a. Colors worked as expected, and zero and max brightness worked, but anything between seemed random. I think I fixed it. Was a good introduction to the PIO state machine and its capabilities.

Then I tried to make the simplest I2C device I have available work with Kaluma: a VL53L0X TOF sensor and lo-and-behold: it worked! Package available here.

So far good fun for the ¥1240 I paid for the Cytron board!

An Example of AI Generated Article

No, I am a human and I wrote this very article. This one is all it is about. It was written either by an AI, or by a very bad article writer. I cannot say. The border between those two is very fuzzy.

Let’s start with some actual facts:

  • ZimaBoard is a small single board computer with an Intel N3350 (2 cores, 1.1-2.4GHz) or N3450 (4 cores, 1.1-2.2GHz) CPU. See here for more details. Names are ZimaBoard 216, 432, 832. The first digit is the amount of RAM in GB, the next 2 digits is the amount of Flash memory in GB.
  • Udoo Bolt v8 (see here for detailed specs) runs on an AMD Ryzen V1605B with Radeon VEGA 8 graphics. The older version Udoo Bolt v3 runs with a Ryzen V1202B and VEGA 3.

The Offending Blog Article

When reading this blog entry, the very first picture is already a bad start, but I gave it a benefit of doubt since everyone knows the size of a ZimaBoard and RPi4, so it’s like the banana for scale, but with a RPi4.

Showing a picture of a Raspberry Pi 4 and an Udoo Bolt

Stated specs for the Udoo Bolt v3:

Udoo Bolt v3 does not use a V1605B

Speaking of the various Udoo Bolt versions, it gets worse:

Udoo Bolt version inflation!

There is no V3 Plus, and how a human (or an AI) can write “The V3 and V3 Plus models are designed with an AMD Ryzen 1605B processor, while the V8 model is designed with an AMD Ryzen V1605B processor” is beyond me.

It Gets Worse

Keep in mind, this is a blog entry on the zimaboard.com web page, so making errors for a different vendor’s product (Udoo) is one thing, but you surely know your own products better. Or do you?

Almost nothing in this paragraph is correct

This is totally incorrect data, displayed with a confidence only ChatGPT can have. Nothing is correct in this paragraph: There are no A55E or A55E2 models, no ZimaBoard had ever a Celeron J3355 nor a Pentium N4200, 32GB (not 64GB) eMMC is all you get at most, and WiFi and Bluetooth you do not get. The only correct info is “up to 8GB RAM”, but it’s LPDDR4, not DDR3L.

Here is the part where I questioned whether someone put some alcohol into my morning coffee:

ZimaBoard CPU switcharoo

In one paragraph there’s two models: ZimaBoard A55E and A55E2, and then there’s two models ZimaBoard Basic and Pro. And they switched CPUs to be ARM based.

And it switches again in a later section:

ZimaBoard now has a AMD CPU

Here the ZimaBoard runs on an Ryzen V1807B. And again, while it states there’s WiFi and Bluetooth, the ZimaBoard has neither. Also no USB-C.

Let’s Try ChatGPT

Since this looks like a ChatGPT article, let’s try that:

Captured from ChatGPT

Yeah, that’s pretty much the same nonsense I read in the zimaboard.com blog page.

In Conclusion

I see a lot of low-quality (insert 4-letter-words here) articles on the Internet. To find it on the blog of zimaboard.com is very disappointing though.

I think what happened here is that ChatGPT was asked three times to write an article comparing the ZimaBoard and the Udoo Bolt. Each part in the blog entry was a separate ChatGPT request of the type “Write an article comparing the ZimaBoard and the Udoo Bolt focusing on X”. It would explain the repetitive nature, the jump in specs and the overall lack of “quality” in the whole blog article.

I was interested to get one of those ZimaBoards since it has 2 SATA ports which is pretty unique among low power SBCs. But when a company sets that low standards on their blog, chances are they cut corners somewhere else too.

Pass.