Navigation

  • index
  • next |
  • previous |
  • Mecrisp Stellaris Unofficial 1.0 documentation »
  • heartblink README

heartblink README¶

Project: heartblink
Created: Mon  1 Mar 2021 14:42:11 AEDT
Doc Author 2021 by t.j.porter <terry@tjporter.com.au> license: MIT, please see COPYING
Purpose: Blinks/fades the blue led on a F0 Discovery board like a heartbeat.
Three variations of Sine, Cosine and Triangle modulation are included.
Intended Audience: anyone
MCU:   STM32F051 (any STM32F0xx should work)
Board: STM F0 Discovery
Required: arm-none-eabi, st-flash, linux, freebsd etc
Literature:
Code Author(s): Matthias Koch  <matthias.koch@hot.uni-hannover.de>
Code License: all *.s are GPL3
Binary Size: 58-60 Bytes

Full project Tarball with ready to flash ‘sine’ binary:

  • https://sourceforge.net/projects/mecrisp-stellaris-folkdoc/files/heartblink-03.03.21-9106.zip

Description¶

Heartblink fades a STM F0 Discovery Board LED in and out like a heartbeat. This is done in software only, no timer peripheral is used making it easily portable to other brands of Cortex-M0. Total binary size is only 58-60 Bytes.

How Does It Work¶

A differential equation is numerically approximated (providing the sine/cosine/triangle function), the result interpreted as a floating point number and converted to integer (to get an exp(x) approximation) and fed into a sigma/delta modulator, the output of which drives the LED.

The exp(x) approximation is to correct for human eyesight

Comments by Crest¶

Matthias uses the minsky circle to approximate a sinus function which is faster than the proper cordic algorithm and good enough for a dimming a led.

Given a pair (x, y) on the almost circle the algorithm updates this pair by adding or substracting the upper bits of the other axis shifted right a few places to each axis and he uses one of the axis as the brigthness of the led to get the nice slow fade in and out with almost linear perceived brightness

Three Versions¶

There are three different versions for you to try:

  • Triangle

  • Sine

  • Cosine

Makefile Selection and Build¶

Selection¶

In the Makefile edit by un-commenting, and commenting as required. Select one of the three choices below. In this example “sine” is selected.

SRC  = sine
# SRC  = cosine
# SRC  = triangle

Build¶

  • Build with “make clean and make”

  • flash with “make flash”

Note

Cosine and sine are the same except cosine starts with the led fully on.

Sine¶

  • 58 Byte binary.

@ Heartblink for STM32F0 Discovery, by Matthias Koch  <matthias.koch@hot.uni-hannover.de>
@ Sine Variation
@ Blue Led is connected to PC8.

.syntax unified
.cpu cortex-m0
.thumb
.text

blinky:                         @ Execute the vector table :-)

.word 0x40020C5C                @ Stack pointer: Plus a suitable offset, this gives RCC_AHBENR (0x40021014).
                                @ But it is also this sequence of opcodes:
                                @   lsrs    r4, r3, #17  @ Divide a bit to get blink frequency into visible range.
                                @   ands    r2, r0       @ Doesn't harm here.

.word reset + 1                 @ Reset Handler.
                                @ Opcode sequence:
                                @   movs    r1, r1
                                @   movs    r0, r0
@ -----------------------------------------------------------------------------
reset:
@ -----------------------------------------------------------------------------

   movs r2, #0x48               @ Start to generate address of PIOC_MODER (0x48000800)
   lsls r2, r2, #16             @ 0x48 --> 0x480000
   str r2, [sp, 0x40021014-0x40020C5C] @ Set 0x80000 in RCC_AHBENR (0x40021014). Bit 0x400000 enables PIOF also
   adds r2, #8                  @      --> 0x480008
   lsls r2, #8                  @    --> 0x48000800

   lsls r1, r2, #5              @ 0x48000800 << 5 = 0x10000 for PC8, blue LED
@  lsls r1, r2, #7              @ 0x48000800 << 7 = 0x40000 for PC9, green LED
   str  r1, [r2]                @ Switch pin to output


   movs r5, 1                    @ Set up initial x, y for Minsky circle algorithm
   lsls r6, r5, 19

@ -----------------------------------------------------------------------------
breathe_led: @ Generate smooth breathing LED effect
@ -----------------------------------------------------------------------------

    @ Register usage:

    @ r0 : Unused
    @ r1 : Scratch
    @ r2 : Initialised with IO address for GPIO
    @ r3 : Scratch
    @ r4 : Unused
    @ r5 : Minsky circle alg x = sin(t)
    @ r6 : Minsky circle alg y = cos(t)
    @ r7 : Phase accumulator for sigma-delta modulator

                                 @ Minsky circle algorithm x, y = sin(t), cos(t)
    asrs r1, r5, 17              @ -dx = y >> 17
    subs r6, r1                  @  x += dx
    asrs r1, r6, 17              @  dy = x >> 17
    adds r5, r1                  @  y += dy

    asrs r1, r5, 13              @ -49 <= r4 <= 64   --> scaled sin(t)
    adds r1, 183                 @ 134 <= r4 <= 247  --> scaled sin(t) with offset

    movs r3, 7                   @ Simplified bitexp function.
    ands r3, r1
    adds r3, 8                   @   Valid for inputs from 0x10 = 16 to 0xF7 = 247.
    lsrs r1, r1, 3               @   Gives 0 if below 16, and too small values above 247.
    subs r1, 2                   @ Input  in r1
    lsls r3, r1                  @ Output in r3

    subs r7, r3                  @ Sigma-Delta phase accumulator
    sbcs r3, r3                  @ Sigma-Delta output through carry, which is inverted for subs

    str  r3, [r2, 0x14]          @ Set output accordingly
    b.n breathe_led

Cosine¶

  • 58 Byte binary.

@ Heartblink for STM32F0 Discovery, by Matthias Koch  <matthias.koch@hot.uni-hannover.de>
@ Cosine variation, starts with LED on
@ Blue Led is connected to PC8.

.syntax unified
.cpu cortex-m0
.thumb
.text

blinky:                         @ Execute the vector table :-)

.word 0x40020C5C                @ Stack pointer: Plus a suitable offset, this gives RCC_AHBENR (0x40021014).
                                @ But it is also this sequence of opcodes:
                                @   lsrs    r4, r3, #17  @ Divide a bit to get blink frequency into visible range.
                                @   ands    r2, r0       @ Doesn't harm here.

.word reset + 1                 @ Reset Handler.
                                @ Opcode sequence:
                                @   movs    r1, r1
                                @   movs    r0, r0
@ -----------------------------------------------------------------------------
reset:
@ -----------------------------------------------------------------------------

   movs r2, #0x48               @ Start to generate address of PIOC_MODER (0x48000800)
   lsls r2, r2, #16             @ 0x48 --> 0x480000
   str r2, [sp, 0x40021014-0x40020C5C] @ Set 0x80000 in RCC_AHBENR (0x40021014). Bit 0x400000 enables PIOF also
   adds r2, #8                  @      --> 0x480008
   lsls r2, #8                  @    --> 0x48000800

   lsls r1, r2, #5              @ 0x48000800 << 5 = 0x10000 for PC8, blue LED
@  lsls r1, r2, #7              @ 0x48000800 << 7 = 0x40000 for PC9, green LED
   str  r1, [r2]                @ Switch pin to output


   movs r5, 1                    @ Set up initial x, y for Minsky circle algorithm
   lsls r6, r5, 19

@ -----------------------------------------------------------------------------
breathe_led: @ Generate smooth breathing LED effect
@ -----------------------------------------------------------------------------

    @ Register usage:

    @ r0 : Unused
    @ r1 : Scratch
    @ r2 : Initialised with IO address for GPIO
    @ r3 : Scratch
    @ r4 : Unused
    @ r5 : Minsky circle alg x = sin(t)
    @ r6 : Minsky circle alg y = cos(t)
    @ r7 : Phase accumulator for sigma-delta modulator

                                 @ Minsky circle algorithm x, y = sin(t), cos(t)
    asrs r1, r5, 17              @ -dx = y >> 17
    subs r6, r1                  @  x += dx
    asrs r1, r6, 17              @  dy = x >> 17
    adds r5, r1                  @  y += dy

    asrs r1, r6, 13              @ -49 <= r4 <= 64   --> scaled cos(t)
    adds r1, 183                 @ 134 <= r4 <= 247  --> scaled cos(t) with offset

    movs r3, 7                   @ Simplified bitexp function.
    ands r3, r1
    adds r3, 8                   @ Valid for inputs from 0x10 = 16 to 0xF7 = 247.
    lsrs r1, r1, 3               @ Gives 0 if below 16, and too small values above 247.
    subs r1, 2                   @ Input  in r1
    lsls r3, r1                  @ Output in r3

    subs r7, r3                  @ Sigma-Delta phase accumulator
    sbcs r3, r3                  @ Sigma-Delta output through carry, which is inverted for subs

    str  r3, [r2, 0x14]          @ Set output accordingly
    b.n breathe_led

Triangle¶

  • 60 Byte binary.

@ Heartblink for STM32F0 Discovery, by Matthias Koch  <matthias.koch@hot.uni-hannover.de>
@ Triangle variation
@ Blue Led is connected to PC8.

.syntax unified
.cpu cortex-m0
.thumb
.text

blinky:                         @ Execute the vector table :-)

.word 0x40020C5C                @ Stack pointer: Plus a suitable offset, this gives RCC_AHBENR (0x40021014).
                                @ But it is also this sequence of opcodes:
                                @   lsrs    r4, r3, #17  @ Divide a bit to get blink frequency into visible range.
                                @   ands    r2, r0       @ Doesn't harm here.

.word reset + 1                 @ Reset Handler.
                                @ Opcode sequence:
                                @   movs    r1, r1
                                @   movs    r0, r0
@ -----------------------------------------------------------------------------
reset:
@ -----------------------------------------------------------------------------

   movs r2, #0x48               @ Start to generate address of PIOC_MODER (0x48000800)
   lsls r2, r2, #16             @ 0x48 --> 0x480000
   str r2, [sp, 0x40021014-0x40020C5C] @ Set 0x80000 in RCC_AHBENR (0x40021014). Bit 0x400000 enables PIOF also
   adds r2, #8                  @      --> 0x480008
   lsls r2, #8                  @    --> 0x48000800

   lsls r1, r2, #5              @ 0x48000800 << 5 = 0x10000 for PC8, blue LED
@  lsls r1, r2, #7              @ 0x48000800 << 7 = 0x40000 for PC9, green LED
   str  r1, [r2]                @ Switch pin to output

@ -----------------------------------------------------------------------------
breathe_led: @ Generate smooth breathing LED effect
@ -----------------------------------------------------------------------------

    @ Register usage:

    @ r0 : Unused
    @ r1 : Scratch
    @ r2 : Initialised with IO address for GPIO
    @ r3 : Scratch
    @ r4 : Unused
    @ r5 : Delay counter
    @ r6 : Slow triangle counter, clipped
    @ r7 : Phase accumulator for sigma-delta modulator

    adds r5, 1                   @ Delay counter

    lsls r6, r5, 12              @ Select blinking speed here.
    asrs r6, r6, 15              @ Triangle generator between 0 and 0x10000.
    bpl  1f 
    negs r6, r6                  @ abs((upcounter << 11) >>> 15)
1:
    movs r1, 247-133             @ Scale range:
    muls r6, r1                  @ (high-low) * x / 65536 + low
    lsrs r6, 16                  @
    adds r6, 133                 @ Baseline minimum brightness

    movs r3, 7                   @ Simplified bitexp function.
    ands r3, r6
    adds r3, 8                   @ Valid for inputs from 0x10 = 16 to 0xF7 = 247.
    lsrs r1, r6, 3               @ Gives 0 if below 16, and too small values above 247.
    subs r1, 2                   @ Input  in r6 is kept
    lsls r3, r1                  @ Output in r3

    subs r7, r3                  @ Sigma-Delta phase accumulator
    sbcs r3, r3                  @ Sigma-Delta output through carry, which is inverted for subs

    str  r3, [r2, 0x14]          @ Set output accordingly
    b.n breathe_led

Logo

Table of Contents

  • heartblink README
    • Description
    • How Does It Work
      • Comments by Crest
    • Three Versions
    • Makefile Selection and Build
      • Selection
      • Build
    • Sine
    • Cosine
    • Triangle

Previous topic

Graphics

Next topic

Hosted or Tethered ?

This Page

  • Show Source

Quick search

Navigation

  • index
  • next |
  • previous |
  • Mecrisp Stellaris Unofficial 1.0 documentation »
  • heartblink README
© Copyright 2016-2020, Terry Porter, released under the GPL V3. Last updated on Feb 05, 2025. Created using Sphinx 5.3.0.