Getting started with the blinking LED

First we need to look at the Hardware of the STM8S105C6T6. From the Circuit diagram we can find in the discovery user manual :-

We find that pin 41 (PDO) is connected to the LED, the LED is connected to VDD so a 0 on the PD0 pin will cause it to light up. Now in the datasheet the STM8S105C6T6 has nine 8 bit ports named A to I that we can control individually as GPIO'S (General Purpose Input Outputs) in total this should equal 72 GPIO pins. Clearly not all can be connected to the outside world on a chip with only 48 pins. , Indeed port I is not connected at all in the STM8S105C6T6 and port F for instance only has one pin connected to the  outside world. Other ports also have bits that are not connected to the outside world, however port D happens to be one of those that does have all of its port bits routed to pins on the STM8S105C6T6.

When the st8s starts up from a reset all of the pins connected to ports are in GPIO mode by default , Many pins can also have alternate functions such as ADC ect.

If we look up pin 41 on the chip diagram we will see a more detailed description of PD0's capabilities.

Now turned around so we can read it:


So the pin we need to flash the LED can be accessed via bit zero on port D, Note that (HS) means PD0 has high sink capability and TIM3_CH2 means the general purpose timer 3 has its channel 2 as the default alternate function. However also  [TIM1_BKIN] or [CLK_CC0] can be selected by setting bits in a special register as the alternate function for this pin instead of using TIM3_CH2 so this particular pin can be used in 4 different ways. While the fact it can be used as a timer output channel is interesting as it could be used for PCM in order to blink the led, for now lets stick to the simpler default GPIO behaviour.

GPIO Name  PD7  PD6  PD5  PD4  PD3  PD2  PD1  PD0
Bit position
 7  6  5  4  3  2  1  0
Pin No *
 48  47  46  45  44  43  42  41
Other Selectable
Alternate functions
 TIM1_CH4  -  -  Beep  ADC_ETR  TIM2_CH3  

* Pin No's are only for the STM8S105C6T6.

Lets look at Port D in more detail it consists of 5 registers of 8 bits (1 byte) mapped into the stm8's memory space.

Three of the registers are control registers and by setting/clearing the bits that correspond with the GPIO pin we are interested in we can control its behaviour.

Port D Registers

 Addr  Name
 Description  Default  R/W  Function  Notes  
 0x0500F  PD_ODR  Port D data output latch register
 0x00  rw Set the relevant bit high or low for the corresponding pin to go high or low when pin is in output mode.
Reading this port will return the previous latched value  
 0x0510  PD_IDR  Port D input pin value register
 0x00  r Read the relevant bit for the pins logic value when pin is in input mode
After reset all the pins of the port are in input mode by default
 0x0511  PD_DDR  Port D data direction register
 0x00  rw If corresponding bit set to 0 = Pin in input mode
If corresponding bit set to 1 = Port in output mode
 0x05012  PD_CR1  Port D control register 1
 rw In input mode:
0 :Floating input
1: Input with 45k pull up resistor enabled
In output mode:
0: Pseudo open drain
1: Push-pull, slope control for the output depends on the corresponding CR2 bit
Note: This bit has no effect on true open drain ports (refer to pin marked “T” in datasheet pin
description table).
 0x05013  PD_CR2  Port D control register 2
 0x00  rw In input mode:
0: External interrupt disabled
1: External interrupt enabled
In output mode:
0: Output speed up to 2 MHz
1: Output speed up to 10 MHz

At reset, all ports are input floating (all registers are generally set to zero upon reset) with a few Exceptions, We see such an exception with PD_CR1 we can see that the PD1 pin has its pull up resistor enabled. PD1 is the swim debug pin.

Now on to the code ...

Run the ST visual develop program
On vista you will need to run as administrator as it has problems accessing certain files when you reload the workspace latter.

From the File Menu create a new Empty Workspace ( The second icon )

Give the Workspace filename as Adventure and use the folder
  button to
set the workspace location , I've set it to C:\sm8Adventure but you can set it anywhere.


Now right click on the newly created workspace and select Add New Project to Workspace... you will get the following dialog.

Select New Project and use
the folder button to create a new folder called blink. We need to do this otherwise the IDE will place other new project files in the same workspace directory, this way we keep our projects separate.

Now fill in the rest. The project name is blink and we set the toolchain to be ST Assembler Linker , the tool chain root is set automatically and need not be changed.

We are the given a dialog box to select the MCU , type in stm8s105 and this will filter the list down a bit , then select the STM8S105C6 Device

A Stub project has now been created with the following directory structure and auto generated files ..

The mapping files are auto generated and represent the STM8S105C6 memory map, the main.asm contains some default start up code. To keep things simple delete all the code from this file and place the following absolutely minimal program ....

Please note that the indents here are important (can be tabs or spaces) and separate labels from assembler instructions, also note that the end statement is needed as is a blank line after the end statement.

  • stm8/ tells the assembler that we are dealing with instructions for the stm8 cpu.
  • segment 'rom'  tells the assembler where to place the code , we are starting the code at the very beginning of the flash rom , 'rom' is defined in the mapping.asm file which is included by the linker and starts at address 0x8080.
  • loop_forever is a label for the memory address at that point , as it is the first line its value will be set to 0x8080.
  • jra loop_forever is the first and only instruction and is located at the first address 0x8080. It stands for "jump relative always"  and jumps back on itself in a endless loop.
  • end specifies the end of the program

In order to see more clearly what is happening we will add one more instruction the nop instruction which stands for no ouput and simply does and affects nothing except taking up one byte of memory space and using one cpu clock cycle.

Now on to the running the program in the debugger , what we are expecting to see with the LED is that is stays unlit as by default the PD0 pin is set to floating input mode.

Plug in the discovery board to the USB socket, If its the first time wait for the drivers to load.

From the Build Menu select Build and you should get no errors in the output window at the bottom of the screen

If you do get errors check the above code.

From the Debug Menu select Start Debugging. Place you cursor on the nop instruction at line 6 and again from the Debug Menu select Run to Cursor

Now pressing the F11 key will step through the code and you can see it looping. (This disassembler on the right has the assembler instruction JRT rather than JRA, it turns out they are the same both with op-code 0x20).
From the picture above you can see other  instructions from 0x8083 onwards appear to be just "random junk" in the flash memory and could be different for you.

OK now lets blink that LED, First let turn it on, In order to turn the LED on we must set PD0 to be an output port and set its output value to zero, as its default output value is already zero then simple setting it to output mode should suffice. In order to do this we use the bset instruction which stands for bit set , the data direction register (PD_DDR ) for Port D is at 0x5011 so we need to set bit 0 of that memory address to 1.

The $ sign in Motorola syntax represents a number in hexadecimal notation and leaving out the $ will represent a number in decimal notation, The # signifies "immediate addressing" that is the value is used as is and not referenced from another source.

OK Try it , Use Stop Debugging then Build and Start Debugging as before. Place the cursor on the bset instruction select Run to Cursor.

Now press F11 to execute the bset instruction .. We have Light.

Now we introduce another bit setting instruction the bcpl instruction which flips the bit at the given bit position i.e. if the bit was zero it become one and visa versa.
Note that there is also a start label that has been added, this is purely so the debugger will highlight the first line (bset) when we step through.

Register 0x500F is Port D's data output register which we continuously toggle.

OK Try it , Use Stop Debugging then Build and Start Debugging as before. Place the cursor on the bset instruction select Run to Cursor.

Keep pressing F11 to execute the instructions. .... We have a blinking LED

Finally we add a delay loop of 0xFFFF using the cpu's 16 bit X register to slow down the blinking for autonomous blinking ....

Here we have introduced the ldw which stands for "Load Word" instruction which loads the constant value 0xFFFF into the X register. Next decw (Decrement Word) subtracts one from the value in X then the jrne (jump relative not equal)
jumps to loop_delay if the result of decw X is not zero, as soon as it is zero after 0xFFFF times then the jump to loop_delay is not executed and the bcpl instruction is executed instead we then jump back to loop_forever and start all over.

This time use Stop Debugging then Build and Start Debugging as before then select the Run command in the debug menu.

It now runs on its own , you can stop the debugger and power down the discovery board by removing the USB Cable , when the USB cable is connected again it will boot and run the program from flash memory.

You can add more nop's to slow it even further or lower the value set in the X register to make it faster. If you lower the ldw X value say to 0x0008 then you can step through the code with the debugger and see what is happening.

OK that's it for new we will be back with Revenge of the blinking LED.