Even with my previous experience and the respectable amount of information available on the web, getting things working still required banging my head against numerous walls, so I thought I would publish a few blog posts that might save some of you some of those headaches.
The Hardware
The project involves controlling a linear-motor powered model railway. The previous design using a 20-pin PIC was I/O-, memory- and CPU-limited and could (barely) handle 1 set of motor/track outputs, 7 relays and a couple of hall sensors. The new ARM version can handle 2 independent sets of motor/track outputs, 32 relays (using I/O expanders, so easily increased) and 6 hall sensors, with enough memory and processing power to do some fancy stuff.
The system is built up from 3 types of board that daisy-chain together: one CPU board with I/O expanders, controls and sensors; one or more motor drive boards to power the trains; and up to a dozen or so relay boards to switch track sections on and off and switch between multiple trains.
The CPU peripherals that will be used include the system timer, ADCs, USART, SPI, FLASH (simulating EEPROM) and of course GPIO. It may end up needing TIMERs and I2C as well.
Programming on the bare metal is a lot of work, but it does have a few advantages.
The main one is really getting to know the CPU, since all interface libraries add at least one layer of abstraction and hide the fiddly details. Unlike the Arduino libraries, the common ARM and STM libraries (in my opinion) don't even really simplify things very much - they just remap and define a new interface that is just as fiddly. You usually end up having to wade deep into the CPU manual anyway.
Getting Started
There are a number of websites that cover aspects of getting the first stage of a bare metal project up and running, and all are worth a look. After several false starts. I found the most useful one was LEAP#549, which took me right from zero to a blinking LED:
https://leap.tardate.com/arm/stm32f103c8t6/baremetal/