Electronics

How to implement 1MHz interrupt in PlatformIO / Arduino on STM32

In our previous post Minimal STM32 HardwareTimer PlatformIO / Arduino timer interrupt blink example we showed how to use HardwareTimer to blink the onboard LED of our STM32F407 board using a timer interrupt.

In this post, we’ll provide an example of how to use HardwareTimer and have a really fast interrupt which runs at 1 MHz – in other words: one million times per second.

#include <Arduino.h>

HardwareTimer timer(TIM1);
bool ledOn = false;

void OnTimer1Interrupt() {
    ledOn = !ledOn;
    digitalWrite(PC13, ledOn ? HIGH : LOW);
}

void setup() {
    pinMode(PC13, OUTPUT);
    // Configure timer
    timer.setPrescaleFactor(21); // Set prescaler to 21 => timer frequency = 168/21 = 8 MHz (from prediv'd by 1 clocksource of 168 MHz)
    timer.setOverflow(8); // Set ARR to 8 => timer frequency = 1 MHz
    timer.attachInterrupt(OnTimer1Interrupt);
    timer.refresh(); // Make register changes take effect
    timer.resume(); // Start timre
}

void loop() {
}

Note that when running such a quick interrupt, you can’t do all too much within the interrupt before the next time the interrupt will run.

Posted by Uli Köhler in C/C++, PlatformIO, STM32

Minimal STM32 HardwareTimer PlatformIO / Arduino timer interrupt blink example

This is a minimal example of using timer interrupts on PlatformIO / Arduino using HardwareTimer (which is a part of the PlatformIO STM32 Arduino installation – no need to install a library). Tested on the Olimex E407 board. It will run on almost any STM32 processor but you might need to adjust PC13 to the PIN connected to the LED. The example will blink the LED once per second.

#include <Arduino.h>

HardwareTimer timer(TIM1);
bool ledOn = false;

void OnTimer1Interrupt() {
    ledOn = !ledOn;
    digitalWrite(PC13, ledOn ? HIGH : LOW);
}

void setup() {
    pinMode(PC13, OUTPUT);
    // Configure timer
    timer.setPrescaleFactor(2564); // Set prescaler to 2564 => timer frequency = 168MHz/2564 = 65522 Hz (from prediv'd by 1 clocksource of 168 MHz)
    timer.setOverflow(32761); // Set overflow to 32761 => timer frequency = 65522 Hz / 32761 = 2 Hz
    timer.attachInterrupt(OnTimer1Interrupt);
    timer.refresh(); // Make register changes take effect
    timer.resume(); // Start
}

void loop() {
}

 

Posted by Uli Köhler in PlatformIO, STM32

How to use STM32 _Msk and _Pos definitions to read and write registers

The STM32 HAL contains definitions like TIM_CR1_CKD_Msk or TIM_CR1_CKD_Pos which you can use to make it easier to read or write parts of a register.

Reading a part of a register

uint32_t ckd = (TIM1->CR1 & TIM_CR1_CKD_Msk) >> TIM_CR1_CKD_Pos;

Writing a part of a register

uint32_t new_ckd_value = TIM_CLOCKDIVISION_DIV4; // example
TIM1->CR1 &= TIM_CR1_CKD_Msk; // Clear bits
TIM1->CR1 |= new_ckd_value << TIM_CR1_CKD_Pos; // Set bits

 

Posted by Uli Köhler in C/C++, STM32

How to fix PlatformIO “Start debugging” doing nothing

Problem:

When you click on Start debugging, press F5 or click on the debug start triangle in PlatformIO

the firmware builds but then nothing happens:

Linking .pio/build/olimex_e407/firmware.elf
Checking size .pio/build/olimex_e407/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   0.7% (used 936 bytes from 131072 bytes)
Flash: [          ]   1.7% (used 18064 bytes from 1048576 bytes)
Building .pio/build/olimex_e407/firmware.bin
======================================================================== [SUCCESS] Took 2.72 seconds ========================================================================

Solution:

You need to specify a debug_tool in platformio.ini. For STM32 processors, a typical choice is

debug_tool = stlink

A list of options for debug_tool is available here.

Note that you can NOT debug many boards via the USB port. You can not debug boards attached via serial-to-USB converter (like many Arduino boards). Your board need to have a proper debugger on-board (like an stlink which is integrated on many STM32 eval boards) or you need to use an external debugger.

Posted by Uli Köhler in PlatformIO, STM32

Minimal STM32 TimerInterrupt_Generic PlatformIO / Arduino timer interrupt blink example

Note: If you need more flexibility, see Minimal STM32 HardwareTimer PlatformIO / Arduino timer interrupt blink example where we show how to use HardwareTimer instead of TimerInterrupt_Generic. Note that TimerInterrupt_Generic uses HardwareTimer internally.

This is a minimal example of using timer interrupts on PlatformIO / Arduino using the TimerInterrupt_Generic library which runs on the Olimex E407. It will run on almost any STM32 processor but you might need to adjust PC13 to the PIN connected to the LED. The example will blink the LED once per second.

#include <Arduino.h>
#include <TimerInterrupt_Generic.h>

STM32Timer tim1(TIM1);
bool ledOn = false;

void OnTimer1Interrupt() {
    ledOn = !ledOn;
    digitalWrite(PC13, ledOn ? LOW : HIGH);
}

void setup() {
    pinMode(PC13, OUTPUT);
    // Enable TIM4
    
    tim1.attachInterruptInterval(500000, OnTimer1Interrupt);
}

void loop() {
}

Now add

lib_deps =
     khoih.prog/TimerInterrupt_Generic @ ^1.7.0

to your platformio.ini. My full platformio.ini looks like this:

[env:olimex_e407]
platform = ststm32
board = olimex_e407
framework = arduino
lib_deps =
     khoih.prog/TimerInterrupt_Generic @ ^1.7.0

 

 

Posted by Uli Köhler in PlatformIO, STM32

PlatformIO Olimex E407 Arduino LED blink example

This code will make the Olimex E407 LED blink.

#include <Arduino.h>

void setup() {
    pinMode(PC13, OUTPUT);
}

void loop() {
    digitalWrite(PC13, LOW);
    delay(500);
    digitalWrite(PC13, HIGH);
    delay(500);
}

 

Posted by Uli Köhler in PlatformIO, STM32

How to fix PlatformIO Olimex E407 LED_BUILTIN not working

Problem

You are trying to run a firmware on the Olimex E407 that blinks the builtin green status LED. You code uses LED_BUILTIN similar to this:

#include <Arduino.h>

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
}

but when you upload the code onto the board, the LED does not blink and stays off.

Solution

Instead of LED_BUILTIN, use PC13 – the pin the LED is connected to (which you can see on the Olimex E407 schematic:

#include <Arduino.h>

void setup() {
    pinMode(PC13, OUTPUT);
}

void loop() {
    digitalWrite(PC13, LOW);
    delay(500);
    digitalWrite(PC13, HIGH);
    delay(500);
}

 

Posted by Uli Köhler in PlatformIO, STM32

How to fix PlatformIO STM32 Error: libusb_open() failed with LIBUSB_ERROR_ACCESS

Problem:

While trying to program your STM32 board using stlink and PlatformIO (most programmers integrated onto a development board are STLink programmers), you see this error message:

xPack OpenOCD, x86_64 Open On-Chip Debugger 0.11.0-00155-ge392e485e (2021-03-15-16:43)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
debug_level: 1

hla_swd
Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
Error: open failed
in procedure 'program'
** OpenOCD init failed **
shutdown command invoked

Solution:

You need to setup the correct permissions for the STLink usb devices – in other words, install the correct stlink udev rules files. On Ubuntu, install stlink-tools using

sudo apt -y install stlink-tools
sudo systemctl restart udev

After that, unplug your stlink (or development board) for 5 seconds and plugin it in again. This will cause the new device permissions to take effect.

Now you can retry uploading the firmware from PlatformIO.

Posted by Uli Köhler in PlatformIO, STM32

How to start KiCAD installed from flatpak

After you have installed KiCAD from Flatpak using

flatpak install --from https://flathub.org/repo/appstream/org.kicad.KiCad.flatpakref

you can run it using

flatpak run org.kicad.KiCad

You can append any arguments to KiCAD, for example open a project file directly from the command line:

flatpak run org.kicad.KiCad MyProject.pro

 

Posted by Uli Köhler in KiCAD

How to fix KiCAD Unable to add inotify watch: (error 28: No space left on device) on Linux

Problem:

When opening KiCAD on Linux, you see the error message Unable to add inotify watch: (error 28: No space left on device):

Solution:

You need to increase the number of inotify watches that can be active at once:

echo fs.inotify.max_user_watches=65536 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

and then restart KiCAD

Posted by Uli Köhler in KiCAD

How to rotate Raspberry Pi LCD by 180°

In order to rotate a DSI-connected LCD screen like the Raspberry Pi 7″ LCD screen by 180 degrees, append

lcd_rotate=2

to /boot/config.txt

Posted by Uli Köhler in Raspberry Pi

PySerial minimal request-reply example

This example sends the M119 (print endstop status) command to an attached 3D printer and prints the response in a loop

#!/usr/bin/env python3
import serial
ser = serial.Serial("/dev/ttyACM0")

try:
    while True:
        ser.write(b"M119\n")
        response = ser.read_until(b"ok\n")
        print(response.decode("utf-8"))
finally:
    ser.close()

Example output (in a loop):

Reporting endstop status
x_max: open
y_max: TRIGGERED
z_max: TRIGGERED
ok

 

Posted by Uli Köhler in 3D printing, Embedded, Python

How to set Raspberry Pi 4 USB-C to host mode

By default, the Raspberry Pi 4 USB-C port is not set to Host mode and therefore it’s not possible.

In order to set the USB-C port to host mode, add the following line to the end of /boot/config.txt (in the [all] section):

dtoverlay=dwc2,dr_mode=host

and

reboot

 

Posted by Uli Köhler in Raspberry Pi

How to fix Python ModuleNotFoundError: No module named ‘usb’ / usb.util

Problem:

When running a Python script, you see an error message like

Traceback (most recent call last):
  File "./dfuse-tool.py", line 2, in <module>
    import dfuse
  File "/home/uli/dev/tools/dfuse-tool/dfuse/__init__.py", line 1, in <module>
    from dfuse.DfuDevice import DfuDevice
  File "/home/uli/dev/tools/dfuse-tool/dfuse/DfuDevice.py", line 1, in <module>
    import usb.util
ModuleNotFoundError: No module named 'usb'

Solution:

You need to install PyUSB using

sudo pip3 install pyusb
Posted by Uli Köhler in Electronics, Python

How to view endstop status on Marlin using G-Code?

On 3D printer mainboards running the Marlin firmware, you can use M119 to view the current state of the endstops. Example output:

M119
Reporting endstop status
x_max: TRIGGERED
y_max: TRIGGERED
z_min: TRIGGERED
ok

 

Posted by Uli Köhler in 3D printing, Electronics

How to print Marlin firmware version using G-Code

The Marlin 3d printer firmware allows you to print the firmware version (along with different firmware settings) using the M115 command. The M115 command takes no parameters.

Example output:

M115
FIRMWARE_NAME:Marlin bugfix-2.0.x (May 13 2021 14:16:08) SOURCE_CODE_URL:github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:OCTOPUS_V1_0 EXTRUDER_COUNT:4 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff
Cap:SERIAL_XON_XOFF:0
Cap:BINARY_FILE_TRANSFER:0
Cap:EEPROM:1
Cap:VOLUMETRIC:1
Cap:AUTOREPORT_TEMP:1
Cap:PROGRESS:0
Cap:PRINT_JOB:1
Cap:AUTOLEVEL:0
Cap:RUNOUT:0
Cap:Z_PROBE:0
Cap:LEVELING_DATA:0
Cap:BUILD_PERCENT:0
Cap:SOFTWARE_POWER:0
Cap:TOGGLE_LIGHTS:0
Cap:CASE_LIGHT_BRIGHTNESS:0
Cap:EMERGENCY_PARSER:1
Cap:PROMPT_SUPPORT:0
Cap:SDCARD:1
Cap:REPEAT:0
Cap:SD_WRITE:1
Cap:AUTOREPORT_SD_STATUS:0
Cap:LONG_FILENAME:1
Cap:THERMAL_PROTECTION:1
Cap:MOTION_MODES:0
Cap:ARCS:1
Cap:BABYSTEPPING:0
Cap:CHAMBER_TEMPERATURE:0
Cap:COOLER_TEMPERATURE:0
Cap:MEATPACK:0
ok

 

Posted by Uli Köhler in 3D printing, Electronics

What is the difference between BIGTREE_OCTOPUS_V1 and BIGTREE_OCTOPUS_V1_USB

When building Marlin firmware for the BigTreeTech Octopus from the official BigTreeTech GitHub repository Marlin directory, you can see two different targets in PlatformIO:

  • BIGTREE_OCTOPUS_V1
  • BIGTREE_OCTOPUS_V1_USB

It is not immediately made clear what the difference between those is, but a short description can be found in ini/stm32f4.ini:

BIGTREE_OCTOPUS_V1_USB has support for using USB flashdrives directly on the board and serial-over-USB while BIGTREE_OCTOPUS_V1 has not.

In most cases, you want to build BIGTREE_OCTOPUS_V1_USB if printing via USB (e.g. via Octoprint) because the BIGTREE_OCTOPUS_V1 configuration does not allow printing via USB.
The compiler definitions for BIGTREE_OCTOPUS_V1 in ini/stm32f4.ini are:
build_flags        = ${stm32_variant.build_flags}
                     -DSTM32F446_5VX -DUSE_USB_HS_IN_FS

whereas BIGTREE_OCTOPUS_V1_USB enabled more USB-related features:

build_flags       = ${stm_flash_drive.build_flags}
                    -DSTM32F446_5VX -DUSE_USB_HS_IN_FS
                    -DUSE_USBHOST_HS -DUSBD_IRQ_PRIO=5
                    -DUSBD_IRQ_SUBPRIO=6
                    -DUSBD_USE_CDC_MSC
Posted by Uli Köhler in 3D printing, Electronics, PlatformIO, STM32

How I fixed STM32CubeProgrammer CUBEPROGRAMMER_ERROR_NOT_SUPPORTED

I tried to flash the DFU bootloader on the BigTreeTech Octopus V1 3D printer mainboard. However, STM32CubeProgrammer v2.8.0 showed me the following error message when trying to connect:

CUBEPROGRAMMER_ERROR_NOT_SUPPORTED

I could only fix this by completely uninstalling STM32CubeProgrammer and then installing STM32CubeProgrammer v2.7.0 from the BigTreeTech Github Repo. Most likely downloading v2.7.0 from the ST homepage will also work but I didn’t verify this.

Posted by Uli Köhler in 3D printing, Electronics, STM32

Where to find DO214AC package in KiCAD?

The DO214AC package is more commonly called SMA. In KiCAD you can find it in the Diode_SMD library as D_SMA package

Posted by Uli Köhler in Electronics, KiCAD

How long does a ElitechRC-5+ take to generate the PDF report

A full Elitech RC-5+ temperature data logger (32000 values) takes about 35 seconds to generate the PDF report and mount as USB device

Posted by Uli Köhler in Electronics