Skip to main content

Stm32 Peripheral Drivers from Scartch

Series Introduction

What is a microcontroller(µC) without its peripherals?  There is not much you can do, if anything at all, with a µC if you do not know how to use the GPIO,USART, I2C,SPI,CAN, TIMERS etc...

So what better way to teach yourself how to use a µC than to attempt to write register level drivers for the peripherals.

I have always steered away from using third party libraries when attempting to learn how to program a certain µC especially the vendor specific libraries for 2 reasons.
One being the fact that you dont learn much from calling a function that sets everything up for you, unless you wrote the function yourself. Reason two is that the vendor specific libraries have layer after layer of abstraction. Trying to work backwards from a function call to figure out how it works is tedious, doable but tedious. On another note those libraries tend to make your program size a lot bigger than necessary, almost 3 times times bigger.

To not misconstrued things I will clear up that for fast prototyping and getting a project up and off the ground and if you have a µC with enough memory then yes the libraries are easy peezy to use and get things going. However my goal is to become an embedded systems engineer of some sort, so relying on fat libraries will not benefit me in the future when I am asked about something like how the SPI protocol works and I have no idea because all I ever did was call an  enable_SPI() ;  function.

This series is NOT an intro to MicroControllersI will not explain things like what is a PIN what does HIGH or LOW state on a pin means..etc.. if you are looking for that type of introduction this is not it and I will perhaps work on a series of that type on a later date. This series is to show you how to use this specific Microcontroller (STM32F103C8) and related MicroControllers from the STM32 family. As well as provide an introduction to the Cortex core.

Parts and Software

For this series I will be using the STM32F103C8 µC pictured above. It is dirt cheap, about $2.99 on ebay just search for STM32F103  there is another version that looks a little different, square in shape with female headers Arduino style, either way its the same thing. This µC sports an ARM Cortex M3 core and maxes out at 72Mhz. 
Full specs:

Key Features
  • ARM® 32-bit Cortex® -M3 CPU Core
    • 72 MHz maximum frequency,1.25 DMIPS/MHz (Dhrystone 2.1) performance at 0 wait state memory access
    • Single-cycle multiplication and hardware division
  • Memories
    • 64 or 128 Kbytes of Flash memory
    • 20 Kbytes of SRAM
  • Clock, reset and supply management
    • 2.0 to 3.6 V application supply and I/Os
    • POR, PDR, and programmable voltage detector (PVD)
    • 4-to-16 MHz crystal oscillator
    • Internal 8 MHz factory-trimmed RC
    • Internal 40 kHz RC
    • PLL for CPU clock
    • 32 kHz oscillator for RTC with calibration
  • Low-power
    • Sleep, Stop and Standby modes
    • VBAT supply for RTC and backup registers
  • 2 x 12-bit, 1 μs A/D converters (up to 16 channels)
    • Conversion range: 0 to 3.6 V
    • Dual-sample and hold capability
    • Temperature sensor
  • DMA
    • 7-channel DMA controller
    • Peripherals supported: timers, ADC, SPIs, I2 Cs and USARTs
  • Up to 80 fast I/O ports
    • 26/37/51/80 I/Os, all mappable on 16 external interrupt vectors and almost all 5 V-tolerant
  • Debug mode
    • Serial wire debug (SWD) & JTAG interfaces
  • 7 timers
    • Three 16-bit timers, each with up to 4 IC/OC/PWM or pulse counter and quadrature (incremental) encoder input
    • 16-bit, motor control PWM timer with dead-time generation and emergency stop
    • 2 watchdog timers (Independent and Window)
    • SysTick timer 24-bit downcounter
  • Up to 9 communication interfaces
    • Up to 2 x I2 C interfaces (SMBus/PMBus)
    • Up to 3 USARTs (ISO 7816 interface, LIN, IrDA capability, modem control)
    • Up to 2 SPIs (18 Mbit/s)
    • CAN interface (2.0B Active)
    • USB 2.0 full-speed interface
  • CRC calculation unit, 96-bit unique ID
  • Packages are ECOPACK®

 You will need a programming unit pictured below which cost about $4 on ebay Just search ST-link V2 the color does not matter:

Another thing you will need is the datasheet for the STM32 which you can download HERE , when you click that link scroll down to "Reference Manual" and download the latest version of RM00008.

Next you will need to download Keil's µVision software. They have free version with code size limit on it, for learning purposes this will suffice and once you learn you can port your skills over to a different IDE. 
You can register HERE to download their free software, at the bottom select the ST and Cortex M3 and M4 options as well as any other chips you may want to experiment with. 

Once you have that up and running watch the following video where I show you how to configure the IDe to work with this programmer and this specific µC.

Now that we have the IDE setup we can start programming, I will start with the GPIO because it is the obvious place to start since all other peripherals depend on the GPIO, along with GPIO I will show you how to enable the clocks for specific peripherals and anything else that may present itself along the way. This series is to be read and watched alongside the reference manual because this is where I get and show you the information from.

NEXT: GPIO register overview >>


  1. Hi Eddie,
    I am a retired programmer. I too love to tinker with u-controllers. (Even after spending much of my life formally working with these beasts. I just love em.)

    I have a legal copy of the (OLD ;-( ) Keil UV2 and have used it to program the Silabs F120 chip for a very sophisticated RADAR data capture and analyze system. Using a mix of c and Assy. But I'm not good at C. I understand HW. I could stick to Assembly but this chip deserves more. I think using C is a MUST.

    I have been able to program this (stm32f103) little board (blinking led) using what little I know about C and my experience with Assembly programming. Searching through the data manual for addresses and characteristics of the on-chip peripherals is a pain in the botty.

    My problem is that I want to be able to use The standard peripheral library published by STM. Unfortunately I can make no head or tail of the confusing mess of defines and structures etc. I am going absolutely crazy. Where is what defined and how? and where are the routines.

    Now I want to at least be able use the port and pin definitions which I expected to find in the library.

    Please help me. I will be extremely grateful.

    I completely agree with your view that for learning and understanding uCs one should write code at the metal level. And for that nothing like Assy. how ever with the ARM chips there are so many registers and bits that it is tedious looking through the data manuals for addresses and specific characteristics of the chips. Some simple defines are a must.

    Where can I go to find an explanation to find the definitions and use the standard routines.
    I am a bit shaky with C but can get over that with some help.

    I will be very grateful for any help I am literally losing my sanity.

    Azzy M.


Post a Comment

Popular posts from this blog

Interface a Rotary Encoder the right way.

So whilst reading my favorite odyssey found here I stumbled onto something I never spotted before. It turns out that the general purpose timers support hardware interfacing with an incremental encoder. This means no more interrupts and no need to increment whatever variable you had. Now all you have to do is get the value from the Count register in the timer. Did I also mention it takes care of figuring out which direction you are turning it? Amazing! Lets talk about it.

Encoder Interface Mode Verbatim from the reference manual of the STM32F103 page 392 or Section 15.3.12  "Encoder interface mode acts simply as an external clock with direction selection. This 
means that the counter just counts continuously between 0 and the auto-reload value in the 
TIMx_ARR register (0 to ARR or ARR down to 0 depending on the direction). So the user 
must configure TIMx_ARR before starting. In the same way, the capture, compare, 
prescaler, trigger output features continue to work as normal."

STM32L0/F0/F3 I2C : Part 3 RX TX via DMA

Most modern microcontroller come with a peripheral called DMA which allows for an even more hands-off approach. The Direct Memory Access controller will get a tutorial of it's own in the future. However, it is so simple to use that I can easily explain the required bits in this tutorial without feeling like I will overwhelm the reader. In this iteration of the I2C series I will cover how to TX and RX date on the peripheral in conjunction with the DMA controller. 

First let me briefly explain in a high level what the DMA controller does. It allows you to transfer data in 3 ways: Peripheral to memoryMemory to peripheralMemory to memory. What does this mean? For example, when you receive data on I2C in your RXDR register, you can have the DMA controller move that data received into an array. At the end of the day your variables are just memory locations, so if you have declared an array it has an address associated with it, this is address is what the DMA considers  "Memory"…

STM32 I2C Does it suck?

Recently I have been annoyed with  bugs in the I2C implementation in ST's F1/L1/F40/F2 series, and  any microcontroller made by ST before 2012. There appears to be, what I can only describe as, a race condition when attempting to receive data in I2C interrupt(low priority)  or polling mode.

Just to be clear a race condition is defined as , verbatim from wiki: "the behavior of an electronics, software, or other system where the system's substantive behavior is dependent on the sequence or timing of other uncontrollable events. It becomes a bug when one or more of the possible behaviors is undesirable."
I was humming along trying to make my YouTube tutorials when I arrived to the I2C protocol implementation. I have used I2C with the F1 series plenty of times, however I have never had the need to receive data from a slave. However for the sake of completeness I decided to implement an RXing routine in I2C for my tutorial. Only to find statements like this in the referen…