Sunday, August 29, 2021

STM32/ARM Microcontrollers--Choosing the next MCU--and: Hello World ARM assembly

After a few months of digging into Embedded C on the AVR 8-bit processor family a problem emerged: the Atmel 328P processor wasn't fast enough for some audio DiWhy circuits I wanted to design and build.

This became most apparent when rewriting the Dirty DigitalLFO code to use lookup tables. Maximizing my AVR embedded C code to produce a decent ramp wave via memory lookup had an output frequency that topped out at about 300hz. 

This was fine for a Low Frequency Oscillator. Designing and building a professional sounding wave table based audio oscillator with an output frequency ranging from 20hz to 20khz, using only an AVR 8 bit, might be pushing the limits of the hardware.

The obvious thing was to get my hands on a faster processor--one that has a processor speed well above the 328's 16-20Mhz speed limit and its restrictive 4-5Mhz limit for SPI.  

My search came down to two processor families for future DiWhy adventures: the RP2040 and the STM32.  

Choosing between these two was a bit difficult. The RP2040 is inexpensive, powerful, and extremely well documented. It also has an interesting peripheral--"PIO pins".  

I need to discuss PIO with my urologist at some point but not for this post. 

For me RP2040's have a big problem: they are only available in QFN  SMD packages. This means the IC has no exposed pins for soldering since its solder pins are under the IC. Which makes fabricating custom RP2040 dev boards at home, using a hot air SMD solder process, difficult and/or impossible. I am not sure why RP made this choice, to make the chip fit on smaller boards?  Fortunately existing RP2040 development boards are affordable so I will probably go that route in the future.  

How about STM32?

The processors look a bit easier to solder....and, there are plenty of affordable STM32 development boards on the market, ready for experimentation; I chose a Blackpill and a Nucleo F031K6. 

Blackpill...

Nucleo F301JK6....


Next question: what development platform(s), aka "toolchains" to use? 

The STM32 family is quite popular and there are many IDEs to choose from; I have gotten comfortable with the toolchain I've been using for AVR, but none of that works for STM32. 

After discussing with some pro EE's I know, I downloaded and installed free versions of STMcubeMX and Keil on my trusty lab NUC PC

 A really good video series for getting started with STMcubeMX is by Mitch Davis, here. He has good AVR embedded C content as well! And--hear Mellow Count Dracula explain the CubeMX IDE setup here. Cool! 

Likewise, for Keil, check out the video here.  

Lots of new things to learn--for instance, DMA and I2S will be used extensively in future projects, and both these development boards support them, while Atmel 328's natively do not.   

Good news, after an evening's work, I can get embedded C blink and debug to work using the useful STM HAL library. Follow the excellent video here

Update: During the 2019-2023 global pandemic I ended up using RP2040's for MCU projects almost exclusively. Simple reason why: it was easier to find RP2040's in stock vs. STM32 chips and development boards; STM32 processors were in extremely short supply for months from 2020 until late 2023.

RP2040 toolchain is also configured--posts start here.

WHEN YOU ASSSEMBLY....

 Let's next discuss ARM assembly.  Both STM32 and RP2040 uses this instruction set architecture.

Other than writing 1's and 0's directly to the processor--good luck with that--ARM assenbly programming is as low as I can go.   

As you might imagine, assembly is much tougher on modern ARM processors than say a 6502. But let's roll up our sleeves.  

To get my feet wet with ARM assembly I figured a path of lesser resistance is to learn ARM assembly on a Raspberry Pi 4 Single Board Computer ("SBC").  

The latter has the ability to display the assembly program's output to a monitor for instance--not as easy with an embedded processor for an assembly beginner like me.

I bought a textbook from Amazon--"Raspberry PI Assembly Language Programming" by Stephen Smith. See the github here--even if you don't buy the book, its code examples are free....the book goes over every 1 and 0 for ARM assembly, it's extremely detailed; I used that as a programming reference.

Next, I incorporated a Raspberry Pi4--also in short supply during the Pandemic but luckily I had purchased a few in 2019--into my lab as the target for ARM assembly language attempts.  

Again, there were a lot of ways I could have set this up, and here is how I did it, and yes, i got "hello world" written in ARM assembly to work without having to leave my W10 development computer....the rest of this post explains the steps I took:

Raspberry Pi4's are cheap, reasonably fast, run the greatest DIwhy OS made (Debian, baby!), and thus there is no reason any AudioDiWhyer shouldn't have at least on on his or her bench.

The rest of this post also assumes you have a decent knowledge of Windows and Linux OS. There are so many videos and web pages about all of this I won't bother linking everything but if you get stuck let me know I will try to help....here we go:

Get latest Rasberry PI OS--32 bit.   

Install on RPI4, make sure PI boots, etc etc etc.--a page for RPi setup is here.  

Install the xrdp  RDP server for RPI.  That way we can see graphics on a "headless" RPi4 computer from Windows:

sudo apt install xrdp

sudo adduser xrdp ssl-cert

from: https://linuxize.com/post/how-to-install-xrdp-on-raspberry-pi/

test RDP:

from rpi terminal:

sudo ifconfig

and note IP in stdout.

from Windows 10, run mstsc (RDP client) using the IP you noted just above.  

You should see your xorg RPi4 login screen; login.  If it all works it will take you to your RPi desktop.  

So far, for me, this all works.

Next, we need to set a static IP address.

I set RPi to static IP to 192.168.4.200 as local IP; gateway as 192.168.4.1, and used 8.8.8.8 and 1.1.1.1 for DNS servers; your IPs will be different):

sudo vi /etc/dhcpcd.conf

(change stuff you need to change)

and save your dhcpcd.conf file.  

Details about how top do this are here:

https://thepihut.com/blogs/raspberry-pi-tutorials/how-to-give-your-raspberry-pi-a-static-ip-address-update

Reboot RPI:

sudo shutdown -h now

After reboot, test RDP from Windows again with the static IP.

For me, RDP still works!

Next: let's share saved data between Windows and RPi.

On windows system, run lusrmgr.msc ("loser manager")

  • create new local W10 user PI and add to admin group
  • share out folder(s) on C; 
  • give your PI local user full rights to share

MS post detailing how to set up CIFS shares and rights for Windows is here.

OK, next, finish getting your RPi4 talking CIFS with windows:

Go back to RPI

Run term:

cd /mnt

sudo mkdir audiodiwhy

run this command:

sudo mount.cifs //aa.bb.cc.dd/audiodiwhy ./audiodiwhy -o user=pi,password=xxxx

where aa.bb.cc.dd is the IPV4 address of your windows system and xxxx is pwd for local windows user you created above.  

Your folder names of course can be whatever you want.

next, cd to mnt/audiodiwhy:

cd /mnt/audiodiwhy

Do a directory listing:

ls -ltru

I can see the Windows folders from the mnt now. 

Next: Create a subfolder from RPi4 on your Windows system. Make sure your target windows folder has Linux read/write rights set; very permissive rights would be something like this:

sudo mkdir /mnt/audiowhy/write2here

sudo chmod 777 /mnt/audiodiwhy/write2here 

...and test everything by creating a text file, something like this:

sudo vim mnt/audiodiwhy/write2here/test

I can now see all the windows C data from the linux machine using RDP (by the way, SSH works as well, and might be preferable for some users, here is how to set up Rpi4 to allow it.  

This all works, we are writing new files to the windows system from the RPi4 using vim!

So you are RDPing or SSHing from W10 to RPI, then using CIFS to go back to Windows storage from Linux

Super COOL!!!!

(I mostly did this to add files etc to c:\users\audiodiwhy\dropbox since dropbox client isn't currently supported on ARM processors. But in general you can seamlessly save and open files on Windows from linux RPI using RDP in this manner--not 100% necessary, but very useful!)

Assembly time:

Now that I have my headless RPI4 working, I will create my assembly .s, .o, build etc., on the RPI Linux system but save them in dropbox windows (why not?),  that way everything lives in the cloud and is available whenever I have an Internet connection.

So on W10 system in c:\users\audiodiwhy\dropbox I created a folder /assembly/arm

Then I create these 2 files using the RPI gnome text editor --or vim or whatever you like, also, the code for these 2 files is available in  Chapter one of the github mentioned above (go here).  

HelloWorld.s

============snip=================

@

@ Assembler program to print "Hello World!"

@ to stdout.

@

@ R0-R2 - parameters to linux function services

@ R7 - linux function number

@


.global _start @ Provide program starting address to linker


@ Setup the parameters to print hello world

@ and then call Linux to do it.

_start: mov R0, #1 @ 1 = StdOut

ldr R1, =helloworld @ string to print

mov R2, #13 @ length of our string

mov R7, #4 @ linux write system call

svc 0 @ Call linux to output the string


@ Setup the parameters to exit the program

@ and then call Linux to do it.

mov R0, #0 @ Use 0 return code

mov R7, #1 @ Service command code 1 terminates this program

svc 0 @ Call linux to terminate the program


.data

helloworld: .ascii "Hello World!\n"

============snip=================


Now create another file called build

============snip=================

as -o HelloWorld.o HelloWorld.s

ld -o HelloWorld HelloWorld.o

============snip=================


from rpi term run this:

sudo ./build

this creates .o file, helloworld.o, objdump.txt etc as well as compiled HelloWorld we can run.

now let's run it!

sudo ./HelloWorld

STDOUT indeed shows HelloWorld on the screen--it all works!

OK, can we turn a C file into assembly, so we can see how the compiler is going to treat our c code? Of course!  Ctest.c is another helloworld....but this time written in C, not assembly.

sudo gcc -g -O -c ./ctest.c

That produces a .o file, which we can then dissassemble:

objdump -s -d ctest.o

Output is assembly:

00000000 <main>:

   0:   e92d4010        push    {r4, lr}

   4:   e59f0008        ldr     r0, [pc, #8]    ; 14 <main+0x14>

   8:   ebfffffe        bl      0 <puts>

   c:   e3a00000        mov     r0, #0

  10:   e8bd8010        pop     {r4, pc}

  14:   00000000        .word   0x00000000

 

More fun than a barrel of monkeys!!!  

Update: more ARM assembly practice using the fantastic CPUlator: post here.

OK that's enough for now.  Lots on the bench, I will continue with STM32 and RP2040 low level madness in future posts. Until next time:  Eat the PI, Don't breathe the ST(ea)M!


No comments:

Post a Comment

Rotary Encoder Expermenter's Board: Improving the Hardware

Quick one this time....I have posted a few projects lately that incorporated a Raspberry Pi Pico, rotary encoder, and .96" OLED:  here ...