November 5, 2023

Let's learn USB! - Cortex M3 interrupts and the STM32F103

First of all, a recommendation. Along with studying the STM32F103 datasheet and reference manual, pay special attention to the "Cortex-M3 Technical Reference Manual".

And in addition, and first of all, an important clarification. There are a family of STM32F1 parts. These were once (and sometimes still are) designated "value line" and "performance line". If this doesn't sound like marketing talk, what does?

The STM32F103 is a "performance line" part. This is vital and important. The STM32F1xx datasheet covers all of these and the interrupt layout is different between these two classes. The value line parts have no USB at all! And of course, because of this, for them no interrupts are defined for USB. If you were looking in IRQ tables and not finding USB interrupts, you were probably looking at documentation for a value line part.

Other literature calls our STM32F103 with 64K of flash a "medium density" device.

Yes, it is hard to believe there is anything cheaper and lower on the scale than an STM32F103, but there most certainly is. Now you know.

Three IRQ assigned to USB

Look at page 204 of the reference manual for a table of IRQ numbers. There are 3 assigned to the USB system for our device: IRQ 19 -- USB high priority (or CAN Tx) IRQ 20 -- USB low priority (or CAN Rx0) IRQ 42 -- USB wakeup from suspend via EXTI line We have "hp" on IRQ 19, "lp" on IRQ 20 and "wk" on IRQ42. .long __irq_usb_hp_can_tx .long __irq_usb_lp_can_rx0 .long __irq_usbwakeup

The usb CNTRL registers has 8 bits that mask or enable various interrupts.
The usb ISTR (interrupt status) register has these same 8 bits in the same position in the 16 bit word, along with other information.
Yes these are 16 bit registers on a 32 bit bus.

What do we do about these 3 interrupts? We will certainly ignore (and not enable) the wakeup interrupt. We could also ignore the HP interrupt and rely solely on the LP interrupt. This is what libmaple does.

The NVIC

Unlike the GIC on a Cortex-A device, this is not an interrupt multiplexor. While it has facilities to classify interrupts into priority classes, its main use is to enable or disable specific IRQ numbers.

Stack Pointers

A Corex-M3 processor has two (banked) stack pointers. These are the main stack and the process stack. The processor comes out of reset using the main stack. It is quite possible (and reasonable) to just ignore the process stack.

Processor Registers

When an exception takes place, the processor pushes 8 registers in the following order:
PSR
PC
LR
r12
r3
r2
r1
r0
On return from the ISR, these 8 registers are automatically popped. That it is an interrupt routine has been indicated by a data field in the LR.

This makes it possible for exception vectors to simply reference C functions. You may be asking, what about r4 through r11 which were not saved? The C compiler always saves any of these registers it might use, so it "just works" As the ARM Cortex-M3 manual says on page 5-11 (page 105):

ISR functions can be normal C functions, and do not require a veneer.
A pleasant situation that I have assumed to be true, but not understood fully until now.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org