2021年4月5日

RaspberryPi Pico FreeRTOS Timer用Java/Qt Timer Style實作

前言:

我將FreeRTOS的Timer封裝,使用方式和Java或Qt的用法相似,好方便使用。

用法:

1. 參考Thread用法實作Class
Runner *runnerA = new Runner(1);

2. 實作Timer物件
每個Timer和Object實作一個Timer物件
CTimer *timer1 = new CTimer("runnerA", runnerA);

3. 設定Timer
timer1->SetTimer(5, true);

參數1: 定時時間(單位是FreeRTOS的tick)
參數2: 是否循環觸發

4. 啟動Timer
timer1->Start();

程式碼:

https://gitlab.com/ycfunet/freertos_timer_template

 






RaspberryPi Pico FreeRTOS Task用Java/Qt Thread Style實作

前言:

我將FreeRTOS的Task用Thread方式實作,使用方式和Java或Qt的用法相似,好處是使用上比較方便習慣些。

用法:

1. 繼承使用Thread
#include "pico/stdlib.h"
#include "thread.h"

class LedWriter : public Thread
{
};

2. 實做run Method
public:
    LedWriter();
.....
    void run();
.....
3. 主程式中實做
TaskHandle_t ledwriter_thread = NULL;
LedWriter *led_writer = new LedWriter();

4. xTaskCreate啟動Task
BaseType_t ret = xTaskCreate(LedWriter::start, "led_writer", 512, led_writer, tskIDLE_PRIORITY, &ledwriter_thread);

程式碼下載:

https://gitlab.com/ycfunet/freertos_thread_template


2021年3月30日

RaspberryPi Pico FreeRTOS Debug測試

前言:

Microcontroller如果同時多個感測器,複雜度會提高,當複雜度比較高時,就需要分時多工,作法上通常是寫或套用個Scheduler,或者往上一階放個RTOS上去,放OS系統複雜度比較高,但提供的功能和彈性比較大。
RTOS當中,目前的主流大概是FreeRTOS,一方面它的Licence是MIT,另一方面它支援的Microcontroller比較多,Plugin也比較多,因此找Pico的FreeRTOS嘗試看看。
因為Microcontroller比較複雜,更需要UI的Debugger協助,除錯或開發才會比較有效率。

環境:

Host: Ubuntu 18.04
SWD Adapter: RaspberryPi 4b
Target: RaspberryPi Pico

安裝設置 (Host端):

Git下載
# cd /tmp
# git clone https://github.com/PicoCPP/RPI-pico-FreeRTOS
# cd RPI-pico-FreeRTOS
# git clone https://github.com/raspberrypi/pico-sdk
# git clone https://github.com/FreeRTOS/FreeRTOS-Kernel

QtCreator編譯FreeRTOS專案:

1. 開啟專案
用QtCreator開啟 /tmp/RPI-pico-FreeRTOS/CMakeLists.txt

2. 修改CMakeLists.txt新增Debug
.....
set(CMAKE_BUILD_TYPE Debug)
.....

3. 建置
Rescan Project
全部清除
清理專案 "hello_world"
全部建置

FreeRTOS除錯:





RaspberryPi Pico C/C++ Debug (QtCreator篇)

前言:

這邊延續前面CLI篇的說明,OpenOCD的設置已經做過了,這邊直接設定QtCreator。

環境:


QtCreator設定:

1. 參考下圖進入設置頁面

2. 設定Debugger
先設定ARM Debugger (需先安裝gdb-multiarch)



設置內容如下:
Name: ARM Debugger
Path: /usr/bin/gdb-multiarch

3. 設置Kits



設置內容如下:
名稱: Pico
裝置型態: 通用 Linux 裝置
Compiler: C:     GCC (C, arm 32bit in /usr/bin)
Compiler: C++: GCC (C++, arm 32bit in /usr/bin)
Debugger: ARM Debugger (前面Debugger設定的名稱)
Qt 版本: 無

4. 設置Linux裝置







裝置名稱: Pico SWD Adapter
Pi 4b SWD Adapter IP: 192.168.1.35
username: root
使用者密碼: root密碼 (Pi 4b要設定sshd_config,PermitRootLogin yes)

5. Kits設定Linux裝置為上面的Pico SWD Adapter





















開始Debug


Kits: Pico
Server Port: 3333
本地執行檔: 選取build路徑下的.elf檔案 (piblink.elf)
Break at "main": v



















RaspberryPi Pico C/C++ Debug (CLI篇)

前言:

RaspberryPi Pico有提供SWD界面(前身是JTAG),能透過SWD Adapter除錯。
身為老古董,以前用JTAG,需要一個JTAG Adapter,現在時代進步到SWD了,以前的JTAG Adapter同樣升級,現在是SWD Adapter,對老古董而言,特別的是以前JTAG Adapter比較貴,而且可能需要個ARM的程式提供Driver和Protocol,現在有OpenOCD,OpenOCD是OpenSource,而現在的RaspberryPi Zero/2b/3b/4b都能用GPIO模擬SWD Adapter,甚至RaspberryPi Pico也有picoprobe,直接放韌體,就能讓Pico當SWD Adapter。
因為是延續JTAG,因此現在主流的Microcontroller看起來都支援SWD,常見的除了新出的Pico之外,STM32也是常見的平台。

因為Debug有點複雜,因此分2篇,這篇做的是OpenOCD環境建置以及gdb指令除錯。
也許會說,那我直接跳下一篇,直接看QtCreator呢?
不太建議,因為設定和建置都在這篇,QtCreator的設定基礎,也都是gdb,這篇實做後,才能銜接上。
SWD Adapter的部份,這篇先用RaspberryPi 4b,原因是,OpenOCD RaspberryPi的設定,預設是RaspberryPi 4b,如果要用其他版本,要修改記憶體位址(memory address)、時脈(clock)、GPIO號碼(GPIO number)。

環境:

Host: Ubuntu 18.04
SWD Adapter: Raspberry Pi 4b
Target: RaspberryPi Pico

接線示意圖:






Pi OpenOCD環境安裝:

1. RaspberryPi OS安裝
先按照官方說明安裝Raspberry PI OS Lite
設置SSH
WiFi,我這邊設定WiFi為固定IP(192.168.1.35)

2. OpenOCD安裝
2a. 安裝套件
# apt-get update
# apt install git gdb-multiarch
# apt install automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev

PS1. 下載OpenOCD Source Code要用git
PS2. Cross GDB執行檔現在直接包成gdb-multiarch套件,能直接支援Pico Binary format

2b. 下載OpenOCD
# git clone https://github.com/raspberrypi/openocd.git --recursive --branch rp2040 --depth=1

2c. 編譯 & 安裝OpenOCD
# cd openocd
# ./bootstrap
# ./configure --enable-ftdi --enable-sysfsgpio --enable-bcm2835gpio
# make -j8
# make install

2d. 安裝完成
安裝後檔案位置如下:
OpenOCD Execute file => /usr/local/bin/
OpenOCD Configure files => /usr/local/share/openocd/scripts/
RaspberryPi OpenOCD cfg => /usr/local/share/openocd/scripts/interface/raspberrypi-swd.cfg
RaspberryPi Pico(RP2040) Target cfg => /usr/local/share/openocd/scripts/target/rp2040.cfg

3. Host端GDB安裝

因為OpenOCD提供telnet、gdbserver、tcl除錯需要的3個界面,因此Host需要安裝:
# apt install gdb-multiarch telnet

4. Pico設置Debug模式
4a. 按下圖步驟將Pico上電



4b. Pi 4b執行OpenOCD
# openocd -f interface/raspberrypi-swd.cfg -f target/rp2040.cfg -c 'bindto 0.0.0.0'


PS1. OpenOCD預設binding在本機(localhost),要加上參數 'bindto 0.0.0.0'
PS2. 如果出現錯誤訊息,請確定是參照4a步驟,按著按鈕插USB Cable (上電)

5. Host上用gdb除錯

QtCreator會Build在不同目錄,專案目錄「/tmp/my_pico_cpp_test」,檔案會產生在「/tmp/build-my_pico_cpp_test-unknown-Default」。

根據CMakeLists.txt設定,Pico燒錄用的檔案是uf2,Debug用的檔案則是elf,因此這裡要使用的是「piblink.elf」。

Debug執行步驟如下:
5a. 執行gdb
# gdb-multiarch /tmp/build-my_pico_cpp_test-unknown-Default/piblink.elf

5b. 連線到OpenOCD並載入piblink.elf
(gdb) target remote 192.168.1.35:3333
(gdb) load




5c. 設置中斷點在main並執行
(gdb) b main
(gdb) continue






補充:

如果要使用Pi Zero (Pi 1)或者Pi 2b當作OpenOCD的SWD Adapter,OpenOCD的cfg檔案內容如下:
Pi 2b:(已測試)
# /usr/local/share/openocd/scripts/interface/rpi2.cfg
# Use RPI GPIO pins
adapter driver bcm2835gpio
bcm2835gpio_peripheral_base 0x3F000000

bcm2835gpio_speed_coeffs 146203 36

# SWD                swclk swdio
# Header pin numbers: 23 22
bcm2835gpio_swd_nums 11 25

transport select swd

adapter speed 1000

Pi Zero (Pi 1):
# /usr/local/share/openocd/scripts/interface/rpizero.cfg
# Use RPI GPIO pins
adapter driver bcm2835gpio
bcm2835gpio_peripheral_base 0x20000000

bcm2835gpio_speed_coeffs 113714 28

# SWD                swclk swdio
# Header pin numbers: 23 22
bcm2835gpio_swd_nums 11 25

transport select swd

adapter speed 1000


2021年3月27日

RaspberryPi Pico C++ IDE開發實做 (QtCreator)

前言:

RaspberryPi出Pico版本,開發比較接近Arduino,是non-OS的系統開發。
Pico提供C/C++和MicroPython開發方式。
因為我比較習慣用QtCreator開發C/C++程式,因此嘗試用QtCreator當IDE。

系統環境:

Ubuntu 18.04

套件安裝:

1. cmake安裝
先參考https://apt.kitware.com/透過下面步驟安裝最新版cmake。

1a. 新增kitware相關的key
# wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null

1b. 新增kitware ppa
# apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main'
# apt-get update

1c. 安裝cmake
# apt install cmake

2. 安裝QrCreator和Pico需要的Cross-Compiler
# apt install git qtcreator gcc-arm-none-eabi libnewlib-arm-none-eabi

3. QtCreator新增專案

3a. 開啟QtCreator

3b. 建立Non-Qt C++ Application專案




3c. 

3d. 選擇CMake

3e. 選擇預設Kit

3f. 目前不使用版本控制





4. 在目錄內git下載pico-sdk

$ cd /tmp/my_pico_cpp_test
$ git clone https://github.com/raspberrypi/pico-sdk
$ cd pico-sdk
$ git submodule update --init

5. 複製pico_sdk_import.cmake (參考pico-sdk github)

$ cd /tmp/my_pico_cpp_test
$ cp pico-sdk/external/pico_sdk_import.cmake ./

6. 修改CMakeLists.txt (參考pico-sdk github)


PS1: 專案內所有cpp檔案都加在 add_executable() 內
PS2: 主程式和產出的uf2名稱加在 add_executable()、target_link_libraries()、pico_add_extra_outputs() 三處內

7. QtCreator新增C++ Class

7a. 檔案 -> 新增檔案或專案 -> C++ -> C++ Class


7b. 設定LedWriter Class













8. 參考blink.c實做LED GPIO Output



9. 實做main.cpp

10. 建置專案

執行
Rescan Project
Clear CMake Configure
全部清理
清理專案
全部建置

11. 產出檔案


12. 燒錄檔案到RaspberryPi Pico

參考Pico官方文件
12a. Pico USB拔除
12b. 按著白色按鈕
12c. 插入Pico USB到電腦
12d. 跳出RPI-RP2 USB資料夾
12e. 把piblink.uf2 檔案複製到上述資料夾內
12f. Pico會自動Reset,並執行piblink.uf2



2021年3月23日

Linux Chroot實作 (Debian)

前言:

Linux Container(容器化)現在已經很常見了,但討論主要集中在Docker,Docker有非常多優勢,像是Docker Hub、Docker Volume、Docker Image與Container,進一步擴展還有K8s。
但Docker使用容量有點大,不論是Docker Image、Container,Docker相對有點點複雜,對於服務隔離而且硬體受限(低階VPS)的場景,找到Chroot,也就是Container的始祖。
相對於Container,Chroot比較少人討論,因為它僅有執行環境隔離,沒有CPU、記憶體隔離,也沒有網路隔離,但以服務隔離的角度,網路由防火牆防護,似乎不錯,於是實做了下,寫一篇分享。

環境:

相同作法應該適用在Ubuntu/Debian系列的實體機和VM內,不適用Container內(LXC、Docker)。
實驗環境是Debian 10 (Buster)

安裝:

1. 需要安裝2個套件,包括debootstrap和schroot。
# apt-get install debootstrap schroot

2. 建立Chroot系統目錄
mkdir /home/chroot

(這裡有個選項,如果有額外的磁碟或分割區,目錄可以用ZFS,好處是ZFS有snapshot功能,能讓Chroot系統支援snapshot)

3. 產生Chroot系統的Template
# debootstrap buster /home/chroot/rootfs http://ftp.tw.debian.org/debian/
(debootstrap能產生Debian/Ubuntu系統的Rootfs,裡面會包含Standard版本的完整系統,不包含fstab之類的設定)

4. 把Template打包
# cd /home/chroot
# tar cjf chroot.tar.bz2 rootfs

設置Chroot系統:

1. 解壓縮並更名Template
# cd /home/chroot
# tar jxf chroot.tar.bz2
# mv rootfs webrootfs (預計要使用的Chroot系統名稱,這裡用webrootfs)

2. 編輯schroot的Chroot系統設定檔
# vi /etc/schroot/chroot.d/webrootfs.conf
[webrootfs]
description=Web Rootfs
directory=/home/chroot/webrootfs
root-users=root
users=myuser
type=directory

進入Chroot系統:

執行指令切換到Chroot系統
schroot -c webrootfs

切換到Chroot系統後,所有的操作都在Chroot系統內,這時候可以安裝套件,準備執行環境。

操作Chroot系統與執行程式:

1. 啟動Chroot系統Session
# schroot -c webrootfs -b
執行後會出現一串像是:
webrootfs-b7738702-b79a-4376-9952-377570356804

這是這個Session的SessionID
(-c 指定Chroot系統名稱)
(-b 啟動Chroot系統,產生Session)

2. 查詢所有SessionID
# ls /run/schroot/mount/
所有SessionID都會紀錄在 /run/schroot/mount/

3. 進入Session
# schroot -r -c webrootfs-b7738702-b79a-4376-9952-377570356804
當SHELL出現(webrootfs)root 就是進入Session了
(-c 指定SessionID)
(-r 進入存在的Session)

4. 離開Session
# exit

5. 刪除Session
# schroot -e -c webrootfs-b7738702-b79a-4376-9952-377570356804
(-c 指定SessionID)
(-e 刪除存在的Session)

參考:

2021年2月18日

Python Qt (PySide) 起手勢

在Python討論區看到有人用PySide實作視窗程式,因此嘗試用PySide寫出Python版本的Qt樣板程式。

用過QtCreator的會發現,產生QWidget (或QDialog) 的Project後,會產生一個預設樣式的程式碼框架,但在PySide上,比較少看到,尤其加上Qt Designer之後,pyside-uic會產生UI Python程式碼,如何和其他程式碼整合,是個入門的門檻,因此寫一個PySide版的Template和作法。

PySide Template程式碼分3塊:
1. Main主程式
2. Dialog主體
3. Qt Designer產生的Dialog內容

Main主程式:
import sys
from PySide.QtGui import *
from PySide.QtCore import *

from main_widget import MainWidget

if __name__ == '__main__':
app = QApplication(sys.argv)
main_widget = MainWidget()
main_widget.show()

sys.exit(app.exec_())


Dialog主體:
from PySide.QtGui import *
from PySide.QtCore import *

from ui_text_dialog import Ui_Dialog

class MainWidget(QDialog):

ui = Ui_Dialog()

def __init__(self):
QDialog.__init__(self)
self.ui.setupUi(self)
self.ui.CloseButton.setText("關閉視窗")

self.ui.CloseButton.clicked.connect(self.on_CloseButton_clicked)

def on_CloseButton_clicked(self):
QApplication.exit(0)

Qt Designer產生的Dialog內容:
Qt設計師產生後,儲存的檔名以ui_開頭做為區別。

框架原理如下:
Main主程式內等同於Qt的main.cpp,主要放的是QApplication和包含Config在內其他初始化程式。

Dialog程式內放的是實際視窗的程式,等同於Qt的widget.cpp(dialog.cpp)和widget.h(dialog.h),實際的視窗程式所在,包括視窗功能,Signal/Slot定義、連接、動作都寫在這裡。
Dialog程式內的關鍵有3個:
1. 繼承QDialog
    class MainWidget(QDialog)

2. 在 __init__(self) 建構子內,要呼叫QDialog的建構子
    QDialog.__init__(self)

3. 透過 setupUi() 把 Qt Designer 的 ui_dialog 整個載入,並把dialog指定到 Qt Designer 的 ui_dialog
self.ui.setupUi(self)

Qt Designer產生的ui_dialog,直接由Qt Designer產生就能套用,objectName要設定,Signal/Slot不寫在這,直接寫在Dialog的實體中。

程式碼: