Stephen Smith's Blog

Musings on Machine Learning…

Archive for the ‘raspberry pi’ Category

Introducing the Raspberry Pi Pico W

leave a comment »

Introduction

At the end of June, the Raspberry Pi foundation released a new version of the Raspberry Pi Pico that includes a wireless communications chip. This new Pico is named the Raspberry Pi Pico W and only costs $2 more than the base Pico. Basically, they added an Infineon CYW43439 chip which supports Wifi and Bluetooth, though only Wifi is supported through the SDK currently. Thus the Raspberry Pi Pico W is a true IoT (Internet of Things) chip, not requiring a physical connection to communicate.

Several other vendors have already added Wifi and Bluetooth in their independent RP2040 based boards. We reviewed the SeeedStudio Wio RP2040 here.

Compatibility

The hardware designers at Raspberry worked hard to add this wireless chip without affecting people’s existing applications. This meant they couldn’t use any of the exposed GPIO connectors. They also didn’t want to release a new version of the RP2040 chip, so they had to use a connection that was already exposed. The choice they made to minimize impact on people’s existing projects was to take over the connector that was previously used to control the Pico’s onboard LED. The reasoning being that flashing the onboard LED couldn’t be too important to people’s projects. You can still access the LED, but it is now wired to a pin on the CYW43439 chip and you need to go through the CYW43 device driver included in the Pico’s SDK. To blink the LED you need to initialize the high level driver:

    cyw43_arch_init()

Then you can set the LED high or low with:

    cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_state);

To make room for the new chip, a few things on the board have been moved around, notably the debug pins are now in the middle of the board rather than at the edge. When wiring the Pico W up, make sure you use the “Getting Started” guide for the Pico W, which contains the correct diagrams.

Programming the Pico W

The Pico W was added as the pico_w board type in the SDK. By default the RP2040 SDK will build for a regular Pico, so if you want wireless functionality you need to add “-DPICO_BOARD=pico_w” to your cmake command:

    cmake -DPICO_BOARD=pico_w -DCMAKE_BUILD_TYPE=Debug ..

Then pico_w.h from the boards/include/boards folder will be used and you have access to all the wireless features.

The documentation in the SDK is still a bit thin on the new features, but the SDK examples are a great source on how to do something, as working code is better than a dry API reference.

Wireless Interface

The Infineon CYW43439 uses an SPI interface to communicate with the RP2040. The RP2040 chip contains hardware to handle SPI communications; however, the Pico W cannot use these since they are connected to GPIO pins exposed externally. Raspberry didn’t want to reduce the number of GPIO pins, so instead they chose to use the programmable I/O processors (PIO)  to handle the communications. I imagine this will be a problem for anyone already using PIO in their projects as the program memory for PIO is only 32 instructions. There seems to be a #define in the SDK to use PIO for this, but I don’t see any support for not using this if you turn it off.

The CYW43 chip supports Bluetooth, but that support isn’t in the Pico’s SDK yet. There are already lots of examples of using various internet protocols to perform tasks like transmitting weather data to a web server to display on web pages. There is support for both C and MicroPython.

The source code for the CYW43 driver and any other aspects are all included with the SDK. Infineon has good documentation for their chip if you want to get into the details.

Pico H

Raspberry also officially released the Pico H and Pico WH which are just a Pico and Pico W with pre-soldered headers. If you are using a breadboard and want to save some soldering, I would recommend getting these versions.

Summary

It’s great to see Raspberry producing a version of the Pico with built-in wireless capability for true IoT applications. At this point the SDK is still being filled out, but there is plenty there to get you started. Too bad they couldn’t use the RP2040’s SPI hardware and instead use PIO for this, I enjoy using PIO and would rather it was left all for me. I predict the Raspberry Pi Pico WH will become the most popular Pico model.

Written by smist08

August 26, 2022 at 11:29 am

Assembly Language Tutorial Six for MagPi Magazine

with one comment

Assembly Language Tutorial Six for MagPi Magazine

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The sixth and final one appeared in issue #121 on page 58.

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This article doesn’t look at ARM Assembly Language, instead it looks at the special Assembly Language used by the Raspberry Pi Pico’s Programmable I/O processors. If a CPU needs to handle all the aspects of I/O operations itself, this can take a significant percentage of its processing power. To offload this I/O processing from the CPU, the RP2040 chip includes a set of special PIO coprocessors that can do the I/O processing independently from the CPU. This special Assembly Language is simpler than ARM Assembly Language and there is only room for 32 instructions in the coprocessor, but even so the RP2040’s PIO processor is powerful and can leave the RP2040’s main ARM CPU free to perform more application oriented processing.

Unfortunately this article was written before the Raspberry Pi Pico W was released. The Pico W adds Wifi and Bluetooth to the Raspberry Pi Pico. To do this, Raspberry took over the GPIO pin that connected the on-board LED to the CPU. As a result the program in this article won’t work on a Pico W, only the regular Pico. On the Pico W, the onboard LED is connected to the wireless chip and you have to go through the device driver for this chip to access the LED. There is an example program to do this in the Pico W’s SDK samples.

This tutorial can only give so much detail. If you want more detail, you can always consider my book RP2040 Assembly Language Programming.





Written by smist08

August 25, 2022 at 10:05 am

Rust Never Sleeps

leave a comment »

Introduction

Rust is a relatively new programming language that first appeared in 2010. The purpose of Rust is to provide a systems programming language with the performance of C/C++ but without all the memory/pointer/multithreading/security problems. Version 6 of the Linux kernel will be adding support for writing modules in Rust and many companies have been writing their backend web servers in Rust.

I thought I’d have a look at programming in Rust and had a go on both a regular Raspberry Pi as well as with embedded Rust on the Raspberry Pi Pico. In this article we’ll look at a simple program to generate a Koch snowflake, a relatively simple program that still shows some of the features of Rust. The program listing is at the end of the article.

How to Create Graphics?

Rust doesn’t include a giant do everything runtime like C# has in .Net or Java has in the JRE. Instead people outside of the core language group have developed wrapper libraries of various commonly used systems. For GUI and graphics, I chose to use the wrapper for GTK3 as this seems to have good support and the included Cairo 2D drawing library is fairly good.

This works, but you can’t write GUI type design patterns like MVC in Rust because their memory management schemes are inherently unsafe or require garbage collection. Rust enforces the lifetime of every object and ensures there are no hanging references, this makes the sea of objects model most GUIs use where each object has references to a bunch of other objects illegal. Rust recommends alternate design patterns, but if you are wrapping an existing legacy library then you will have to work around a few issues.

Installing Rust and Required Libraries

Rust is easy to install, but it only installs Rust components. Any wrapped components need to be installed separately, in our case GTK3’s development components:

    sudo apt-get install libgtk-3-dev

Now we can install Rust, using rustup from their website: https://rustup.rs/. The current command to do this is:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

But best to copy the command from their website, in case it’s been updated. Then at the prompt select “1 – proceed with installation” to download and install Rust.

The installation adds a number of environment variables to the shell initialization scripts, to proceed you need to either restart a new terminal window or run:

    source "$HOME/.cargo/env"

Now we can create our Rust project, first creating a folder for our Rust projects and then using Rust’s cargo utility to create a project.

    mkdir rust
    cd rust
    cargo new fractal1 --bin --vcs none

The “–vcs none” part is to start cargo creating a github repository as well. We now have a working Rust program, which if we run with:

    cargo run

Will compile the simple program and print “Hello World”. The first time you run, the compilation takes a while since there are a number of system components that need to be compiled the first time.

To produce the Koch snowflake fractal, copy the Cargo.toml file at the bottom of this article over the one created by cargo and then copy the main.rs file over the created file in the src folder.

With these in place, type:

    cargo run

Then after everything compiles, the program should run and produce a window with the Koch snowflake at level 3.

Notes on the rust.rs

The GTK3 wrapper is from https://gtk-rs.org/. I based the program on one of the examples in their Github repository. I found these examples to be the best source of information on the usage of this library as the documentation tends to be of a reference nature and doesn’t show how to put the parts together into a working program.

If you’ve seen any of my other blog articles where I created a Koch snowflake as an example, then you might wonder why I don’t store the Cairo drawing context in the TurtleGraphics struct rather than having it as a parameter to most method calls. The reason is Rust’s rules around avoiding dangling pointers, where you need to ensure the lifetime rules of every object. This means you can’t just store references in objects without guaranteeing their lifetime is less than the reference. In most practical cases this is difficult and the hoops to jump through are far worse than just passing it as a parameter. Not as object oriented perhaps, but on the other hand, no dangling pointers and no garbage collection.

Summary

Rust wants to replace C as a system programming language for projects such as the Linux kernel, web servers and even video games. Rust isn’t a simple language, it is large and some of its parts are quite complex. The safety rules to ensure that pointers are correct place a lot of limitations on what you can do as a programmer. The Rust parts of your program are safer than corresponding C programs, but with the state of things today, your Rust program will wrap a lot of components written in C/C++ that could be doing all sorts of bad things with pointers. The other limitation is that you can’t easily call Rust objects from other languages, limiting some interoperability scenarios.

I’m going to continue learning and playing with Rust. It has a number of appealing features, but I’m not sure if its complexity and strict enforcement of lifetime and ownership rules are too constraining.

Source Code Listings

The Cargo.toml file:

[package]
name = “fractal1”
version = “0.1.0”
edition = “2021”

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
gtk = “*”
gio = “*”
gdk = “*”
cairo = “*”

The main.rs follows:

use std::f64::consts::PI;
use gtk::prelude::*;
use gtk::DrawingArea;
use gtk::cairo::{Context};

const STARTX:f64 = 50.0;
const STARTY:f64 = 130.0;
const STARTANGLE:f64 = 0.0;
const LEVEL:i64 = 3;

fn build_ui(application: &gtk::Application) {
    drawable(application, 500, 500, |_, cr| {
        cr.set_source_rgb(0.0, 0.0, 0.0);
        cr.set_line_width(1.0);
        cr.move_to(STARTX, STARTY);
        let tg = TurtleGraphics{x:STARTX, y:STARTY, angle:STARTANGLE};
        let mut kf = KochFlake{tg: tg};
        kf.koch_snowflake(cr, LEVEL);
        cr.stroke().expect(“Invalid cairo surface state”);
        Inhibit(false)
    });
}

fn main() {
    let application = gtk::Application::new(
        Some(“com.github.gtk-rs.examples.cairotest”),
        Default::default(),
    );
    application.connect_activate(build_ui);
    application.run();
}

pub fn drawable<F>(application: &gtk::Application, width: i32, height: i32, draw_fn: F)
where
    F: Fn(&DrawingArea, &Context) -> Inhibit + ‘static,
{
    let window = gtk::ApplicationWindow::new(application);
    let drawing_area = Box::new(DrawingArea::new)();
    drawing_area.connect_draw(draw_fn);
    window.set_title(“Koch Snowflake”);
    window.set_default_size(width, height);
    window.add(&drawing_area);
    window.show_all();
}

struct KochFlake
{
    tg: TurtleGraphics
}

impl KochFlake
{
    pub fn koch_snowflake(&mut self, cr:&Context, level:i64)
    {
        self.tg.turn( 60 );
        self.koch_snowflake_side(cr, level , 400);
        self.tg.turn( -120 );
        self.koch_snowflake_side(cr, level, 400);
        self.tg.turn( -120 );
        self.koch_snowflake_side(cr, level, 400);
    }

    pub fn koch_snowflake_side(&mut self, cr:&Context, level:i64, size:i64)
    {
        if level == 0
        {
            self.tg.move_dist( cr, size );
        }
        else
        {
            self.koch_snowflake_side( cr, level – 1, size / 3 );
            self.tg.turn( 60 );
            self.koch_snowflake_side( cr, level-1, size / 3);
            self.tg.turn( -120 );
            self.koch_snowflake_side( cr, level-1, size / 3);
            self.tg.turn(60);
            self.koch_snowflake_side( cr, level-1, size / 3);
        }
    }    

}

struct TurtleGraphics
{
    x:f64,
    y:f64,
    angle:f64
}

impl TurtleGraphics
{
    pub fn move_dist(&mut self, cr:&Context, dist:i64)
    {
        self.x = self.x + dist as f64 * f64::cos( self.angle * PI / 180.0);
        self.y = self.y + dist as f64 * f64::sin( self.angle * PI / 180.0);
        cr.line_to(self.x, self.y); 
    }

    pub fn turn(&mut self, angle_increment:i64)
    {
        self.angle = self.angle + angle_increment as f64;
    }
}

Written by smist08

August 8, 2022 at 12:37 pm

Assembly Language Tutorial Five for MagPi Magazine

leave a comment »

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The fifth one appeared in issue #120 on page 52.

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This article leads readers through how to access the Raspberry Pi Pico’s hardware by reading and writing to special memory addresses that double as hardware access and status registers. This is typical of how the ARM processor is interfaced to hardware devices. Since the Raspberry Pi Pico doesn’t run an operating system, our program can directly access the hardware rather than going through device drivers or an SDK. In this tutorial we read temperature values directly from the Raspberry Pi Pico’s built in temperature sensor using Assembly Language. We write this code in the form of a function and call it from a C program that prints out the values for us to read.

This tutorial can only give so much detail. If you want more detail, you can always consider my book RP2040 Assembly Language Programming.

Written by smist08

July 29, 2022 at 10:33 am

Assembly Language Tutorial Four for MagPi Magazine

leave a comment »

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The fourth one appeared in issue #119 on page 50.

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This article leads readers through using the Raspberry Pi’s floating point unit (FPU) to perform a calculation. This article uses the 64-bit of Raspberry Pi OS and shows how to write an Assembly Language routine to calculate the distance between two points in two dimensions. This shows how to use the FPU to add, subtract, multiply and perform square roots. There is a C program that uses this Assembly Language distance() routine to calculate the distance between  a couple of sets of points. The tutorial shows how to use the gdb debugger to step through the program and examine the data as it is calculated.

If you want more detail, you can always consider my book Programming with 64-Bit ARM Assembly Language.

Written by smist08

June 30, 2022 at 1:17 pm

Assembly Language Tutorial Three for MagPi Magazine

leave a comment »

Assembly Language Tutorial Three for MagPi Magazine

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The third one appeared in issue #118 on page 52.

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This article looks at writing Assembly Language code for the Raspberry Pi Pico. The Pico is Raspberry’s entry into the microcontroller market and includes a dual core ARM-M0+ CPU. This CPU runs ARM’s thumb instruction set, a subset of the full ARM 32-bit instruction set. This article shows how to create a project, include Assembly Language source code and then run or debug the program on the Raspberry Pi Pico.

This tutorial can only give so much detail. If you want more detail, you can always consider my book RP2040 Assembly Language Programming.

Written by smist08

May 26, 2022 at 1:51 pm

Assembly Language Tutorial Two for MagPi Magazine

with 2 comments

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The second one appeared in issue # 117 on page 50. 

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This second article looks at writing Assembly Language for the 64-bit version of Raspberry Pi OS. This tutorial shows how to access memory, use 64-bit registers, use loops, conditional logic and call functions. The completed program prints out the value of a register in both decimal and hexadecimal showing how to convert a binary value to ASCII.

This was a fairly long tutorial but I can only give so much detail. If you want more detail, you can always consider my book Programming with 64-Bit ARM Assembly Language.

Written by smist08

April 29, 2022 at 9:58 am

Assembly Language Tutorials for MagPi Magazine

with 2 comments

I’m in the process of writing a series of Assembly Language tutorials for MagPi Magazine. The first one appeared in issue # 116 on page 46. 

The PDF version of the magazine is free to download, but MagPi always appreciates any donations.

This first article was written before Raspberry released the 64-bit version of their operating system and so uses 32-bit ARM Assembly Language, this still has many applications and is a good springboard to using ARM based microcontrollers like the Raspberry Pi Pico.

It was a challenge to write in a tutorial format, but I think it ended up working well. With a four page article, I can only give so much detail, but of course if you want more detail, you can always consider my book Raspberry Pi Assembly Language Programming.

Written by smist08

April 20, 2022 at 10:21 am

Adding Assembly Language to MicroPython

with 2 comments

Introduction

My book “RP2040 Assembly Language Programming”, covered how to interact with modules written in compiled languages like C. However, there isn’t a chapter on adding Assembly Language to MicroPython, a popular programming environment in the Raspberry Pi Pico world. In this article we’ll look at adding a simple Assembly Language function to the MicroPython program we presented in “Playing with the Seeed Studio Grove Starter Kit for the Raspberry Pi Pico”. We’ll place the temperature and humidity together on the first line and then calculate their sum and output that on the second line.

Assembly Language in MicroPython

MicroPython has a syntax to add ARM “Thumb” Assembly Language instructions directly into your Python source code. This is great if you are using an ARM M-series based microcontroller such as Raspberry’s RP2040 or the Seeed Studio Wio Terminal which is based on an ARM M4 CPU. You specify that a function will be in Assembly Language by placing the directive:

@micropython.asm_thumb

before the function definition. The parameters to the Assembly Language function must be r0, r1, r2 & r4, allowing up to four arguments that are all 32-bit integers, other data types aren’t supported. The return value for the function will be whatever is in r0. Our simple Assembly Language function is:

@micropython.asm_thumb
def sum(r0, r1):
    add(r0, r0, r1)

Notice how the Assembly Language instructions are entered as functions to conform to Python syntax, though MicroPython compiles these directly to Assembly Language. There is a function for each instruction in the ARM M-series Thumb instruction set, including the floating point instructions, in case your microcontroller has a floating point unit such as in M4 based systems like the Wio Terminal. The MicroPython documentation for this is quite good and available here.

There is a separate label() function to define labels so you can create loops. You can access constants defined in the main Python program and use the << operator to specify shifts where they are allowed. There is a data() function to define data and an align() function to define alignment.

Inside our Assembly Language function, we can create additional functions and BL to them, and BX to return.

Next is the complete MicroPython program for this project.

from lcd1602 import LCD1602
from dht11 import *
from machine import Pin, I2C
from time import sleep
import math
i2c = I2C(1,scl=Pin(7), sda=Pin(6), freq=400000)
d = LCD1602(i2c, 2, 16)
dht2 = DHT(18) #temperature and humidity sensor connect to D18 po0rt
@micropython.asm_thumb
def sum(r0, r1):
    add(r0, r0, r1)
while True:  
    temp,humid = dht2.readTempHumid()
    d.home()
    d.print("T,H:  " + str(temp) +" " + str(humid))
    d.setCursor(0, 1)
    d.print("Sum: " + str(sum(temp, humid)))
    sleep(0.5)

Notice that in our program, we didn’t need to build a custom version of MicroPython to include our routine, our program is strictly a MicroPython source file. This allows you to add Assembly Language functions to any build of MicroPython without requiring any rebuilding or worrying about conflicting versions.

Limitations & Uses

The main complaint I’ve seen about this is that you don’t have access to the RP2040 SDK, this is compiled into MicroPython and MicroPython doesn’t expose it for use. The best use for this is smaller functions that specifically optimize some aspect of Python that is slow, or access hardware registers that don’t have MicroPython libraries. Another use is to call specific Assembly Language instructions that there isn’t something corresponding to MicroPython. Similarly you can’t build other libraries into MicroPython and then call them directly from Assembly Language, you have to have MicroPython mediate access. There are tools like the Zerynth/Viper Emitter to generate your initial code, which can be helpful.

Another limitation is that you can’t write PIO Assembly Language for the RP2040’s programmable I/O.

Summary

Most people looking to use MicroPython, don’t want to mess with C or Assembly Language. They are using MicroPython to make their microcontroller projects easier. However, if you are stuck, this is a great way out of nearly any problem. Similarly, if you are writing a MicroPython interface for custom piece of hardware, this could be necessary to hit the hardware registers correctly. The MicroPython inline Assembly Language is a nice extension to the language and gives programmers great power from this system, but it is limited to ARM M-series type microcontrollers.

Raspberry Pi OS Goes 64-Bit

with 3 comments

Introduction

The Raspberry Pi Zero 2, Raspberry Pi 3 and Raspberry Pi 4 all sport a 64-bit ARM CPU; however, the Raspberry Pi OS has remained at 32-bits until now. This new 64-bit version of the Raspberry Pi OS has been in beta for over a year and was finally officially released on February 2, 2022. Raspberry’s previous argument for staying at 32-bits was that they produced one operating system that worked on all Raspberry Pi’s no matter how old; however, there are quite a few compelling reasons to move to 64-bits so I’m glad they finally made the move.

This isn’t the first 64-bit Linux for Raspberry Pis. Many of the standard distributions including Kali and Ubuntu Linux have been shipping 64-bit versions since shortly after the Raspberry Pi 3 came out. My book, “Programming with 64-Bit ARM Assembly Language”, was written using the 64-bit version of Kali Linux, except for the parts specifically for Android or iOS.

Raspberry will still be releasing their OS in both 32-bit and 64-bit flavors for quite some time, so if you don’t want to move, you don’t have to. In this article we will have a quick look at some aspects of the new 64-bit version.

How Does it Run?

First off, even though it will run on a Raspberry Pi 3 or even a Raspberry Pi Zero 2, I wouldn’t recommend it. A 64-bit operating system uses more memory than the corresponding 32-bit version and 1 Gig of RAM isn’t enough. To use this, you really need a Raspberry Pi 4 with at least 4 Gig of RAM. On my Raspberry Pi 4 with 8 Gig of RAM, it is noticeably peppier than the 32-bit version, especially when browsing with Chromium.

Installing the 64-bit operating system is nearly identical to installing the 32-bit version. It has been added to the list of operating systems in the Raspberry Pi Imager. By default the imager will install the 32-bit version, but you can choose the 64-bit from the “Raspberry Pi (other)” menu. From that point on it is hard to tell the difference. When you boot the new image it first resizes the filesystem for your SD card, then boots the Raspberry Pi OS as usual and puts you in the same setup wizard as you get in the 32-bit version, asking the same questions about timezone, wifi and whether the menu fits on your monitor. After installing any updates, it reboots and you are happily running the 64-bit version.

The only caveat that Raspberry lists is that the Chromium library for running streaming services like Netflix is missing. This isn’t something I do and I’m sure it won’t be long. Otherwise all the usual Raspberry Pi programs are there and from my experience using Kali and Ubuntu, most things are available to install through the apt system. In fact one of the reasons Raspberry was finally forced to move to 64-bit is that several software packages have dropped 32-bit support.

Why Move to 64-Bit?

The Raspberry Pi OS has been around for a while in 32-bits, the advantage is that it runs on all Raspberry Pi’s no matter how old and it runs in compact memory footprints of 512 MB or 1 Gig. It runs a vast library of open source software and has provided a great platform for millions of students and DIY’ers. However, most of the rest of the world including mainstream Linux, Windows, MacOS, Android and iOS have all been 64-bit for some time. So let’s look at some reasons to move to 64-bits.

  1. Memory addressing simplifies, making life simpler for Linux.
  2. In 64-bit mode, each ARM CPU has twice as many general purpose registers (32 vs 16) allowing programs to keep more variables in registers, saving loading and storing things to and from memory.
  3. All new compiler optimizations are targeting the ARM 64-bit instructions set, not much work is being done on the 32-bit code generators.
  4. The CPU registers are now 64-bits, so if you are doing lots of long integer arithmetic, it will now be done in one clock cycle rather than taking several under 32-bits.

All that being said, there are a couple of disadvantages, namely 64-bit tends to take more memory due to:

  1. If integers are 64-bit, rather than 32-bit then it takes twice as much memory to hold each one.
  2. Normal ARM instructions are 32-bits in size when running in either 32-bit or 64-bit mode. However in 32-bit mode there is a special “thumb” mode where each instruction is only 16-bits in size. Using these can greatly reduce memory footprint and the GCC compiler supports producing these as an option.

Summary

Raspberry has done a good job making their 64-bit operating system painless to use. It is a direct 64-bit compilation of the current 32-bit one, and most users wouldn’t know the difference, unless they know where to look. I find the 64-bit version noticeably peppier than the 32-bit version and so far everything works as expected. The future is 64-bit and better late than never.

If you are interested in learning more about ARM’s 64-bit architecture, check out my book: “Programming with 64-Bit ARM Assembly Language”.

Written by smist08

February 4, 2022 at 11:43 am