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:
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!