Sunday, September 15, 2024

4 x 1 Mono Mixer--A Confidence Builder

Readers: If you'd like to build the project featured in today's post, please go to PCBWAY's Community pages--gerber file (main board); gerber for jacks board, front panel gerber, a 3D model of the dual pot (WRL and Freecad formats), KiCAD project/pcb/schematic/library files and a B.O.M. are here.  

You can also help out this site immensely by checking out PCBWAY using the link here. Thanks!

------

I've DIWHY'd many projects lately that don't work due to dumb mistakes and I thought, enough! I'm going to lay out and build something easy, useful and practical. 








Everyone needs more mixers right?

The "EZ MIX" was really easy; it took me an evening to lay out and about a half hour to build: a simple 4 input AC/DC unity gain active mixer in 6HP Eurorack format.





The star of the show: dual concentric pots; you get Eurorack's "fit every damn thing on the head of a pin" paradigm without needing extremely tiny hands to turn the knobs.

           

                              

I laid out a footprint for the concentric potentiometer in Kicad and 3D model in Freecad:  



                                                 

Piece of cake.

The project used 3 boards: front panel, jacks panel, and main PCB, centered around a single dual op amp IC.

Everything on the main board was through-hole; other than triple checking sizes, legends, and drills there wasn't a lot to go wrong. 

To remain old school: JST connectors were used between the main board and jacks board.

Main board

jacks board

Front panel....

Off it all went to this blog's honorable sponsor, PCBWAY....

Happiness: new boards from PCBWAY

Zoom, printed circuit boards were back, I gathered up parts from the junk box and got building.






I was fearful things wouldn't line up, thankfully they did....






Everything worked first time ("WFT")--pots went from no volume to full volume when turning them clockwise, audio signals got mixed, legends on the front panel were correct, and most all silkscreens on the boards were accurate.

One (big) mistake--the "Redstripe" (negative voltage) silkscreen callout was on the wrong end of the Euro power header. This silkscreen error was fixed on the 9-12-24 revision I uploaded to the PCBWAY community.

The only SMD part for the project: I added a 0 ohm 1206 resistor between Out1 and Out2. That way if I reused the 3.5mm jacks board in another project the 2 outputs could be independent of one another.  

But in the spirit of this build I soldered the 2 output wirepads together--who needs SMD?



 Finished!






So much fun I made two of them...

Overall, it was great to kick back and design then build something really easy. 

Getting stoopid from time to time is fun....but now it's back to debugging, dealing with cryptic IDE error messages, C++ that won't compile--all the usual things. I can't wait. 


Saturday, September 7, 2024

Understanding ARM Exceptions/Interrupts

Readers: For upcoming posts--low frequency counter, clock multiplication module, etc., I will dig deeply into ARM processor exceptions, a.k.a. "interrupts."

Exceptions can be complex in the ARM world, requiring mastery of hardware, peripherals, programming concepts, and baffling acronyms (e.g.: "ICSR","AIRCR" "NVIC" etc).

This post captures my lab notes surrounding ARM exceptions.

I will be updating/correcting/augmenting this post going forward as I work at the bench. 

Which means: this post is mostly for me--if you want to skip it, skip it. 

but! if you correct things via the comment section I would be grateful--help from experienced ARM developers is always apprecated. 

Thanks.



LINKS

Good web page for this: https://interrupt.memfault.com/blog/arm-cortex-m-exceptions-and-nvic

Video: https://www.youtube.com/watch?v=Uut2uIODlbQ&t=305s; sadly there is no source code linked--so, useful to RP2040 dev until about 8:00.

SysTick: https://www.youtube.com/watch?v=fMqCBMWZ0pk ARM Programming courses frequently use SysTick exception 15 to demostrate interrupts. SysTick is a relatively simple counter that can throw an exception over and over. The video explains how SysTick is implemented in an ARM core but does not provide code examples one can download.

C code example for Systick: https://users.ece.utexas.edu/~valvano/arm/SysTick.c.  SysTick code for PICO is here. Other forum posts indicate that the PICO SDK does not abstract SysTick functionality, hence, you have to set the registers directly:

#include <stdio.h> #include "pico/stdlib.h" #include "hardware/structs/systick.h" int main() { stdio_init_all(); systick_hw->csr = 0x5; systick_hw->rvr = 0x00FFFFFF;


PDF of the "generic Cortex Users' guide" is here--how an ARM Cortex M core works at a deep level. Section 2.3 covers a lot of what is in this post; section 4.1 covers peripherals such as NVIC (below). I find this PDF more useful than the web based version here.

---------

I hear ARM exceptions referred to as “interrupts” but in the ARM world interrupts are a type of exception.  

Exceptions have a unique number associated with them starting at 1 (not 0!)  

This number is then used as an offset in a vector table; at each offset is a memory address of a routine to be run.

A made-up example:

If the ARM core sees exception 1 run a routine beginning at 0x0002534

If the ARM core sees exception 2 run a routine beginning at 0x0002538

And so on.

Along with this unique number is “priority”.  The idea here: if 2 exceptions are recognized by the processor at the same time, which one gets handled first?  The lower the priority #, the higher the "precedence"—the processor handles the lower priority #’d exception first.

 

ISR

INTERRUPT SERVICE ROUTINE (ISR): the routine that is pointed to by the vector.   


STATES

Exceptions in the ARM world have "STATES":

Pending: the processor has seen the exception but hasn’t done anything yet. Important idea: for an exception to be recognized and eventually run, a 1 is put into a register to make the exception “pending”, then based on other factors the ARM core will process it. See REGISTER section below for details.

Active: the exception handler is running but isn’t finished yet.

Pending and active: the processor sees the same exception that it’s currently processing.

Inactive: an exception is neither pending nor active.

 

ARM EXCEPTIONS--"CORE INTERRUPTS"

These are exceptions hard coded into an ARM Cortex M core.  

Built in exceptions are used for housekeeping--you can’t change them.

The NVIC (below) peripheral is not used when processing these particular exceptions (note, is that right? I read different things about this, so I am not sure--are both core and non-core exceptions handled by the NVIC, or not? Does anyone know for sure?).

0 vector table points to reset value of stack pointer.

Reset: 1. The routine that is executed when the chip comes out of reset.

Non Maskable Interrupt or "NMI"--2: this exception cannot be disabled. It is fired when there is an error in another exception handler.  The vector points to a routine to run in this oh-shit scenario.

Hardfault: 3  Routine is run when there is a major fault: memory error, divide by 0, etc.

MemManage: 4

Busfault: 5

7-10 reserved

SVCALL: 11:  routine to handle calls to handle a service routine—for instance, a call to the OS to do something.

Debug monitor: 12

13 reserved

PendSV: 14

SysTick: 15. See below.


EXTERNAL or "NON-CORE EXCEPTIONS" 16+0 to 16+N 

These interrupts are defined by the SOC developer; they vary from chip to chip....

The Cortex M0+ (RP2040) has 32 non-core exceptions; other ARM chips can have more.

IRQ's are the external exception numbers minus 16, so exception 0x0F is IRQ 0x0, 0x10 is IRQ 0x1, etc. 

REGISTERS

Exception state is captured in registers located in the ARM System Control Space ("SCS")

Interrupt Control and State Register, ICSR

If you want to check up on what the processor is doing or is going to do exception-wise look at this register.  The active/inactive/pending/and "what exception is running now" is stored here.

Application Interrupt and reset Control Register (AIRCR)

used to further prioritize your exceptions.

Also--Writing a 1 to bit 2 fires a system reset.

System handler Priority Register:  SHPR1-3   

Used to set priorities of system faults.   You probably will never change this register.

Interrupt Controller Type Register (ICTR) - 

In cortex M0+ (RP2040) it's always set to all 1’s.  Don’t worry about this one.

 

NVIC REGISTERS

NVIC is a peripheral that handles manufacturer-specific exceptions; NVIC supports up to 496 exceptions; the Cortex M0/M0+ is limited to 32 external exceptions. 

Example: if your UART is throwing an exception when its buffer is full, it's utilizing the NVIC registers to inform the processor of this exception.

Interrupt Set-Enable (NVIC_ISER) and Clear-Enable (NVIC_ICER) Registers

  • NVIC_ISPR0-NVIC_ISPR15: << set pending
  • NVIC_ICPR0-NVIC_ICPR15:   << clear pending

Writing 1 to the correct register memory location will set or clear the pending state of the interrupt.  So—you can make an external interrupt pending, telling the processor to deal with it; or set an already pending to 0—telling the processor: nevermind. On Cortex M0+, this is the main way one sets external exceptions—drop bits into the above registers.

 These “Hello! CPU here: thanks for telling me about this exception, I will deal with this exception soon enough” situations are referred to as asynchronous exceptions.  

There are also synchronous exceptions (SVC is one, I read), but I am going to not worry about those right now.

 

Interrupt Active Bit Registers (NVIC_IABR)

Not implemented in M0 (RP2040).  Don’t worry about it.

 

Software Triggered Interrupt Register (STIR)  

Also not implemented on M0. Don’t worry about it.

 

Interrupt Priority Registers (NVIC_IPR): NVIC_IPR0-NVIC_IPR1-2-3:

Sets interrupt priority.

 

Software Triggered Interrupt Register (STIR)  

Also not implemented on M0. Don’t worry about it.

 

HOW ARM CHIPS DEAL WITH EXCEPTIONS FROM A C COMPILER STANDPOINT

The compiler is set up to conform to Arm Architecture Procedural Calling Standard (AAPCS).

It works like this (oversimplified?):

a)      An exception is called

b)      Caller register values are put on the stack

c)       $lr (link register) gets the EXC_RETURN value—where in the program to go after the exception is handled.

d)      After exception is handled the values are popped back off the stack, the program returns to $lr value and keeps executing. 

      This means the push and pop complexities associated with implementing an exception without clobbering the rest of your code is abstracted by the compiler. That's probably a good thing?

"TAIL CHAINING":

Say we are executing an ISR and another one comes in.  The processor will not redo the caller stack pushes and pulls, it will leave whatever is in the stack, in the stack. This can save CPU cycles.

JTAG to SWD Converter

Readers: If you'd like to build the project featured in today's post, please go to PCBWAY's Community pages--gerber file, KiCAD ...