RSS

Posts Tagged ‘Electronics’

Generating PWM Signals using the STM8S

Thursday, August 30th, 2012

In a recent post we looked at the generation of a square wave signal using a timer and the update/overflow interrupt. There we generated a 20 Hz signal from the STM8S by toggling an output port using direct access to a port configured as an output port. In this post we will go one step further and use the capabilities of the timer to generate the pulse directly. We will also look at how we can manipulate the registers to allow the generation of a PWM pulse from the STM8S by simply changing the register values used to configure the port.

It is important that you read and understand the previous post Using Timers on the STM8S before continuing further as we will be using much of the knowledge in that post here.

So the project definition here is simple to start with, we will generate a square wave without using GPIO ports. We will then follow up on this by changing the values in the registers to generate a PWM signal with a duty cycle which can be defined by the programmer.

The Registers

The application will use most of the registers described in the previous post as well as the following:

  1. TIM2_CCR1H & TIM2_CCR1L – Capture/Compare Register 1 High/Low
  2. TIM2_CCER1 – Capture/Compare Enable register 1
  3. TIM2_CCMR1 – Capture/Compare Mode Register 1


TIM2_CCR1H & TIM2_CCR1L – Capture/Compare Register 1 High/Low

These two registers are analogous to the TIM2_ARRH and TIM2_ARRL registers. TIM2_ARRH/L are used to determine the period of the signal whilst TIM2_CCR1H/L are used to determine the duty cycle of the signal. Let us assume that we are using the value of 50,000 for TIM2_ARRH/L as in the last post then by setting TIM2_CCR1H/L to 25,000 will give a duty cycle of 50%. Similarly, setting TIM2_CCR1H/L to 12,500 with give a duty cycle of 25% (or 75%) depending upon the register settings for active high/low – see TIM2_CCER1.

TIM2_CCER1 – Capture/Compare Enable register 1

We will be using two bits in this register, Capture/Compare 1 Output Polarity (CC1P) and Capture/Compare output Enable (CC1E).

So let’s start with the easy one, CC1E. This simply enables or disables the capture/compare for channel 1 of Timer 2. Setting this to 1 enables the mode, setting this to 0 disables the mode.

On to the difficult bit of this register, namely the output polarity (CC1P). This bit determines the polarity of the active state. A value of 1 configures the active state to be low whilst a value of 0 configures the state to be high.

It is important to note here that the meaning of active is different from the meaning of a high or low signal. Let us consider a simple example, namely a PWM signal with a duty cycle of 50%. So, for 50% of the time the signal is logic 1 (high) and for 50% of the time the signal is logic 0 (low). Or another way of looking at it is that if we define high to be active and low to be inactive then for 50% of the time the signal is active and 50% of the time the signal is inactive.

CC1P allows us to define what we mean by active and inactive. Once we have the application written we can change this value and see the effect on the output.

TIM2_CCMR1 – Capture/Compare Mode Register 1

This register allows the application to change the way in which the channel is configured. In this case we will only be concerned with setting this to one of two values, namely 6 or 7.

ValueModeDescription
110 – 6PWM Mode 1In up-counting mode, the channel is active if the counter is less than CCR1, otherwise it is inactive.
In down-counting mode the channel is inactive when the counter is greater than CCR1, otherwise the channel is inactive.
111 – 7PWM Mode 2In up-counting mode the channel is inactive as long as the counter is less than CCR1.

Software

The first two things we will do is steal some code from previous posts, namely the Configuring the System Clock and Using Timers on the STM8S. We will use the InitialiseSystemClock and InitialiseTimer2 methods respectively.

The next thing we need to consider is how we set up the timer. We will continue to use Timer 2 so we can again use some of the code from previous posts. However, we need to make a few modifications to SetupTimer2 method.

So let’s start by having a 25% duty cycle (25% high, 75% low). At the moment we are not too worried about the frequency of the signal so let’s work with TIM2_ARRH/L set to 50,000 as in the previous post. This means that we want the output low for 75% of the time (37,500 counts) and high for 25% of the time (12,500 counts). Time for the first decision, let’s use PWM mode 1 (TIM2_CCMR1_OC1M = 6).

Given the default mode (down-counting) and looking at the register definition for TIM2_CCMR1_OC1M we want to define active as a logic 0 and inactive as a logic 1. So this means we need to set TIM_CCMR1_OC1M = 0.

If we put all of this together we end up with the following method:

void SetupTimer2()
{
    TIM2_PSCR = 0x00;       //  Prescaler = 1.
    TIM2_ARRH = 0xc3;       //  High byte of 50,000.
    TIM2_ARRL = 0x50;       //  Low byte of 50,000.
    TIM2_CCR1H = 0x30;      //  High byte of 12,500
    TIM2_CCR1L = 0xd4;      //  Low byte of 12,500
    TIM2_CCER1_CC1P = 0;    //  Active high.
    TIM2_CCER1_CC1E = 1;    //  Enable compare mode for channel 1
    TIM2_CCMR1_OC1M = 6;    //  PWM Mode 1 - active if counter < CCR1, inactive otherwise.
    TIM2_CR1_CEN = 1;       //  Finally enable the timer.
}

And as we are using a timer to do all of the work, our main method becomes:

void main()
{
    //
    //  Initialise the system.
    //
    __disable_interrupt();
    InitialiseSystemClock();
    InitialiseTimer2();
    SetupTimer2();
    __enable_interrupt();
    while (1)
    {
        __wait_for_interrupt();
    }
}

Let’s Look at the Output

If we look at the clock settings (16MHz) and the value for TIM2_ARR (50,000) we should be looking for a signal with a frequency of around 320 Hz (16 MHz / 50,000). So compiling the above we are expecting a 320Hz signal with a duty cycle of 25%. Here is the output on the oscilloscope:

PWM with a 25% high signal

PWM with a 25% high signal

Changing the value of TIM2_CCER1_CC1P to 1 gives the following:

PWM with a 75% high signal

PWM with a 75% high signal

As you can see, the polarity allows us to change what we mean by active.

Some ideas for you:

  1. Change TIM2_ARR values to change the frequency
  2. Change TIM2_CCR1 values to change the duty cycle

As always, the source code for this example is available for download.

Source Code Compatibility

SystemCompatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Generating a Regular Pulse Using Timer 2

Wednesday, August 29th, 2012

In previous posts you may have seen an example program where we generate a 20Hz signal using the overflow interrupt on Timer 2. Here we will translate the post to use direct register access rather than use the STD Peripheral Library.

So the project definition is simple, output a regular signal (20Hz with a 50% duty cycle) on Port D, Pin 4 (i.e. pin 2 on the STM8S103F3P3).

Algorithm

To make this project a low on processor power we will use interrupts to generate the pulse. To do this we will make use of one of the STM8S timers, namely Timer 2 (T2). The algorithm becomes:

  1. Turn off the timer
  2. Setup the timer to generate an interrupt every 1 / 40th of a second
  3. Set up the output port to generate the signal.
  4. Wait for interrupts indefinitely

The Interrupt Service Routine (ISR) then has one very simple task, toggle the output port and wait for the next interrupt.

The Registers

This application is simple and really only uses a fraction of the power of the STM8S timers. In fact we can set up the chip using relatively few registers. With the exception of resetting the timer to a known state we will be using only six registers in this exercise:

  1. TIM2_PSCR
  2. TIM2_ARRH and TIM2_ARRL
  3. TIM2_IER
  4. TIM2_CR1
  5. TIM2_SR1

TIM2_PSCR – Timer 2 Prescalar

The 16-bit counter in Timer 2 receives a clock signal from the prescalar. This in turn receives a clock from the internal clock of the STM8S (i.e. fmaster). The prescalar divides the fmaster clock by the prescalar set in the TIM2_PSCR register. This allows the timer to receive a slower clock signal than that running the STM8S. The prescalar is a power of 2 and the effective frequency of the clock running Timer 2 is given by the following formula:

fcounter = fmaster / 2TIM2_PSCR

where fcounter is the frequency of the signal being used as a clock source for Timer 2.

TIM2_PSCR is a 4 bit number and this restricts the value of the prescalar to 1 to 32,768.

We will come back to this formula when we write the software in order to calculate the prescalar we will need to generate the 20Hz clock signal.

TIM2_ARRH and TIM2_ARRL – Counter Auto-Reload Registers

We will be using the counter as a simple up/down counter. We will be loading this register with a counter value which the timer will count up to / down from. An interrupt will be generated when the counter value has been reached (for up) or zero is reached (for down). The counter will then be reset using the values in these two registers.

The only important thing to note about these two registers is that TIM2_ARRH must be loaded with a value before TIM2_ARRL.

TIM2_IER – Interrupt Enable Register

This register determines which interrupts Timer2 can generate. In our case we only need one, namely the update interrupt. This is generated when the counter value has been reached.

The interrupt is enabled by setting TIM2_IER_UIE to 1.

TIM2_CR1 – Timer 2 Control Register 1

The only bit we will be interested here is the Counter ENable bit (CEN). This will be used to start the counter.

TIM2_SR1 – Timer 2 Status Register 1

This register gives us status information about the timer. There is only one bit we are interested in for this exercise and that is the Update Interrupt Flag (UIF). This bit determines if an update interrupt is pending. The bit is set by hardware but crucially it must be reset by software.

When we enter the ISR, this bit will have been set by the hardware controlling the timer. On existing the ISR the hardware will check the status of the bit. If it is set then the interrupt will be generated once more. This means that if we are not careful then we can end up in a cycle of generating an interrupt, processing the interrupt in the ISR and then generating the interrupt again ad infinitum. It is therefore crucial that this bit is cleared before the ISR is exited.

Software

One of the first things to note is that as with all of the examples we will discuss in this series, we will assume a clock running using the internal oscillator and set to 16MHz.

The code which will deal with the interrupt has a very simple job to do, namely toggle the pin we are using to generate the output pulse. One thing to note it that as we are toggling the pin in this method we will effectively be halving the output frequency of the signal which has been generated. Lets look at what is happening.

  1. ISR 1 – output is low we will make the output high.
  2. ISR 2 – output is high we will make the signal low
  3. ISR 3 – output is low we will make the signal high
  4. etc.

The frequency of the output for a regular signal is determined by the amount of time between the two rising edges of the output. So in our case, the time is double the frequency of the calls to the ISR as we toggle the output in the ISR. This is important and will be used in the calculations we make regarding the timer settings later.

The remainder of the code looks similar to that used in the external interrupts example presented in an earlier post.

//
//  Timer 2 Overflow handler.
//
#pragma vector = TIM2_OVR_UIF_vector
__interrupt void TIM2_UPD_OVF_IRQHandler(void)
{
    PD_ODR_ODR4 = !PD_ODR_ODR4;     //  Toggle Port D, pin 4.
    TIM2_SR1_UIF = 0;               //  Reset the interrupt otherwise it will fire again straight away.
}

If you have been following the series, the next piece of code should also be familiar (see the Simple GPIO example). We will be setting up Port D, pin 4 to be an output port. This is the pin which will output the signal we will be generating.

//
//  Setup the port used to signal to the outside world that a timer even has
//  been generated.
//
void SetupOutputPorts()
{
    PD_ODR = 0;             //  All pins are turned off.
    PD_DDR_DDR4 = 1;        //  Port D, pin 4 is used as a signal.
    PD_CR1_C14 = 1;         //  Port D, pin 4 is Push-Pull
    PD_CR2_C24 = 1;         //  Port D, Pin 4 is generating a pulse under 2 MHz.
}

The next method resets Timer 2 and put it into a known state. This simply requires resetting all of the Timer 2 registers to 0.

//
//  Reset Timer 2 to a known state.
//
void InitialiseTimer2()
{
    TIM2_CR1 = 0;               // Turn everything TIM2 related off.
    TIM2_IER = 0;
    TIM2_SR2 = 0;
    TIM2_CCER1 = 0;
    TIM2_CCER2 = 0;
    TIM2_CCER1 = 0;
    TIM2_CCER2 = 0;
    TIM2_CCMR1 = 0;
    TIM2_CCMR2 = 0;
    TIM2_CCMR3 = 0;
    TIM2_CNTRH = 0;
    TIM2_CNTRL = 0;
    TIM2_PSCR = 0;
    TIM2_ARRH  = 0;
    TIM2_ARRL  = 0;
    TIM2_CCR1H = 0;
    TIM2_CCR1L = 0;
    TIM2_CCR2H = 0;
    TIM2_CCR2L = 0;
    TIM2_CCR3H = 0;
    TIM2_CCR3L = 0;
    TIM2_SR1 = 0;
}

The next thing we need is a method which sets the Timer 2 to generate the interrupt. This is where we need to start doing some calculations.

So let’s start with the frequency of the clock going into the counter for Timer 2. As we have seen earlier, this is given by the following:

fcounter = fmaster / 2TIM2_PSCR

Now we also know that the interrupts will be generated every time the counter value is reached. So the frequency of the interrupt is given by the following:

finterrupt = fcounter / counter

Putting the two together we get the following:

finterrupt = fmaster / (2TIM2_PSCR * counter)

A little rearranging gives:

(2TIM2_PSCR * counter) = fmaster / finterrupt

If we plug in the numbers we know, fmaster = 16MHz and finterrupt = 40 (remember that the frequency of the signal we are generating is half the frequency of the interrupts) then we find:

(2TIM2_PSCR * counter) = 400,000

So, if we take 400,000 and divide by 50,000 (for simplicity) then we have a factor of 8. So, given that the counter is a 16-bit counter then the counter should be 50,000 and the prescalar should be 3 (23 = 8).

//
//  Setup Timer 2 to generate a 20 Hz interrupt based upon a 16 MHz timer.
//
void SetupTimer2()
{
    TIM2_PSCR = 0x03;       //  Prescaler = 8.
    TIM2_ARRH = 0xc3;       //  High byte of 50,000.
    TIM2_ARRL = 0x50;       //  Low byte of 50,000.
    TIM2_IER_UIE = 1;       //  Enable the update interrupts.
    TIM2_CR1_CEN = 1;       //  Finally enable the timer.
}

Now we have all of the component parts we simply need to call the methods to set everything up and then wait for the interrupts to fire. So our main method looks like this:

//
//  Main program loop.
//
int main( void )
{
    __disable_interrupt();
    SetupOutputPorts();
    InitialiseTimer2();
    SetupTimer2();
    __enable_interrupt();
    while (1)
    {
        __wait_for_interrupt();
    }
}

Running this application results in the following trace on the oscilloscope:

20 Hz Square Wave Output on an Oscilloscope

20 Hz Square Wave Output on an Oscilloscope

A quick look at the measurements shows that this application is generating a 20Hz signal. If you don’t have a scope then you can hook a LED (use the LED circuit from the previous article on external interrupts) through a transistor. You should be able to see the LED flicker as it is turned on and off. You could also slow down the rate of the pulses by looking at changing the prescalar or adding a counter.

As always, the source code is available for download.

Source Code Compatibility

SystemCompatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Using the UART on the STM8S

Monday, August 27th, 2012

We have previously seen how to configure the STM8S using the STD Peripheral Library using both the high level API and the slightly lower level register access. In this post we will use the definitions in the iostm8s103f3.h and we will also have a look at the registers which control the UART ending with a program which uses the UART to send data to a terminal emulator on a desktop computer (in my case a PC). We must remember that while this article looks at low speed communications with a PC, the UARTs on the STM8S have a variety of uses covering other protocols other than those discussed in this article.

The definition of the problem is simple, allow the STM8S to send debug information to a terminal emulator running at 115200,n,8,1 (for all of those who remember DOS MODE commands for serial communication).

It should be noted that UART1 is not available on the STM8S Discovery board and so UART2 is used instead.

The Registers

In order to set up the UART we will need to perform the following tasks:

  1. set the parity and number of data bits
  2. set the parity
  3. set the number of stop bits
  4. setup the baud rate
  5. set the clock polarity etc.

It is important to remember that transmission and reception must both be disabled before we start to change these registers.

UART_CR1 – Data Bits and Parity

The number of data bits is selected using the M bit of CR1. This can be set to either 8 or 9 bits. We will be using 8 data bits and so will need to set UART_CR1_M to 0 (setting to 1 would enable 9 data bits).

To set the parity we would set PCEN and PS. In our case we are disabling parity so only need to worry about PCEN (Parity Control Enable). Setting this bit to 0 will disable the parity calculation.

UART_CR3 – Number of Stop Bits and Clock Settings

The number of stop bits can be set to 1, 1.5 or 2. This is controlled by setting UART_CR3_STOP to one of the following values:

ValueDescription
001 Stop bit
01Reserved
102 Stop bits
111.5 Stop bits

Next, we need to consider the clock settings.

UART_CR3_CPOL determines the idle state of the clock, 0 sets the clock low when idle, 1 sets it high when idle.

UART_CR3_CPHA determines if the data should be stable on the rising or falling edge of the signal. Setting this to 0 means the data is set on the rising edge of the clock signal. Setting this to 1 means the data is ready on the falling edge of the clock signal.

UART_CR3_LBCL determines if the clock pulse for the last data bit is set to the clock pin. A 0 means the last clock pulse is not generated while 1 means that the pulse is generated.

UART_BRR1 & UART_BRR2 – Baud Rate Registers

The baud rate of the UART is controlled by dividing fmaster by the baud rate divisor. The result gives the clock speed of the serial port. In our case we have a 16 MHz clock speed for the microcontroller and we want the serial port to run at 115200 baud. So some simple rearranging of the formula and the UART divider is given by:

UART Divider= fmaster / baud rate
= 16,000,000 / 115,200
= 138
= 0x008a

Now we need to rearrange the number 0x008a a little in order to get the right bits into BRR1 and BRR2 (Baud Rate Register 1 & 2). This was written as a 32 bit number to illustrate how this is put into the registers. To do this we split the number (represented by d3d2d1d0) into three parts:

  • the first digit (d3) – 0
  • the next two digits (d2d1) – 08
  • the last digit (d0) – a

And set up the registers as follows:

BRR1= d2d1
= 0x08
BRR2= d3d0
= 0x0a

When setting these registers it is important to remember to set BRR2 before setting BRR2.

UART_CR2 & UART_CR3 – Enabling the UART

The first action we would need to take is to disable the UART and the last thing we should do is enable it. This is controlled by three bits in two different registers, namely registers UART_CR3 and UART_CR2. All three bits use 0 for disable and 1 for enable. The bits we been to set are:

UART_CR2_TENEnable/disable transmission
UART_CR2_RENEnable/disable reception
UART_CR3_CKENEnable/disable the clock

In our case we do not need to enable the output of the system clock or reception. The software below will enable these anyway in order to provide a generic serial initialisation method which can be using a variety of circumstances.

Software

Moving on to our software, we will need a standard STM8 project for the microcontroller you are using. I am using the STM8S103F3P3 and the default project I set up in a previous article.

Setting Up the UART

This code makes a fundamental assumption, namely that you have configured the chip and your circuit to run at 16 MHz. I did this by setting the chip to use the internal oscillator as its clock source and using a prescalar of 1 (see the previous article on setting up the system clock for more information). The code for this is in the InitialiseSystemClock method.

The next step is to configure the UART. This is performed in the InitialiseUART method.

//
//  Setup the UART to run at 115200 baud, no parity, one stop bit, 8 data bits.
//
//  Important: This relies upon the system clock being set to run at 16 MHz.
//
void InitialiseUART()
{
    //
    //  Clear the Idle Line Detected bit in the status register by a read
    //  to the UART1_SR register followed by a Read to the UART1_DR register.
    //
    unsigned char tmp = UART1_SR;
    tmp = UART1_DR;
    //
    //  Reset the UART registers to the reset values.
    //
    UART1_CR1 = 0;
    UART1_CR2 = 0;
    UART1_CR4 = 0;
    UART1_CR3 = 0;
    UART1_CR5 = 0;
    UART1_GTR = 0;
    UART1_PSCR = 0;
    //
    //  Now setup the port to 115200,n,8,1.
    //
    UART1_CR1_M = 0;        //  8 Data bits.
    UART1_CR1_PCEN = 0;     //  Disable parity.
    UART1_CR3_STOP = 0;     //  1 stop bit.
    UART1_BRR2 = 0x0a;      //  Set the baud rate registers to 115200 baud
    UART1_BRR1 = 0x08;      //  based upon a 16 MHz system clock.
    //
    //  Disable the transmitter and receiver.
    //
    UART1_CR2_TEN = 0;      //  Disable transmit.
    UART1_CR2_REN = 0;      //  Disable receive.
    //
    //  Set the clock polarity, lock phase and last bit clock pulse.
    //
    UART1_CR3_CPOL = 1;
    UART1_CR3_CPHA = 1;
    UART1_CR3_LBCL = 1;
    //
    //  Turn on the UART transmit, receive and the UART clock.
    //
    UART1_CR2_TEN = 1;
    UART1_CR2_REN = 1;
    UART1_CR3_CKEN = 1;
}

We will need to provide a method of sending a simple string to the serial port. The algorithm is simple:

  1. Set a pointer to the start of the string
  2. If the character pointed to be the pointer is not a null (i.e. 0) character then
    1. Transfer the character pointed to be the pointer into the UART data register
    2. Wait until the data register has been sent (Transmission Empty is true)
    3. Move the pointer on one byte

//
//  Send a message to the debug port (UART1).
//
void UARTPrintf(char *message)
{
    char *ch = message;
    while (*ch)
    {
        UART1_DR = (unsigned char) *ch;     //  Put the next character into the data transmission register.
        while (UART1_SR_TXE == 0);          //  Wait for transmission to complete.
        ch++;                               //  Grab the next character.
    }
}

And finally we need a main program to control the application.

//
//	Main program loop.
//
void main()
{
	__disable_interrupts();
	InitialiseSystemClock()
    InitialiseUART()
	__enable_interrupts();
	while (1)
	{
        UARTPrintF("Hello from my microcontroller....\n\r");
		for (long counter = 0; counter < 250000; counter++);
	}
}

The full application code can be downloaded from here. Simply unzip the files and open the project with IAR. The application can be downloaded to the chip by pressing Ctrl-D. Once downloaded to the microcontroller press F5 to run the application.

This application has been tested on my reference platform, the Variable Labs Protomodule and the STM8S Discovery board.

To check the application is working, connect the Tx line of the STM8S (in my case pin 2) to the Rx line on a PC which can accept 3.3V TTL logic signals. This is important, the port must accept 3.3V TTL and NOT standard RS232 signals. To do this I use a 3.3V FTDI cable and connect this to the STM8S and one of the USB ports on my PC. This gives me a COM port which I can connect to devices running at 3.3V. Now open up a terminal emulator (I used PuTTY) and connect to the com port using the correct protocol. You should see the following output:

Output from the STM8S shown on a PuTTY terminal

Output from the STM8S shown on a PuTTY terminal

Conclusion

Adding these methods to you project should allow you to generate debug output from an application running on the STM8S or communicate with devices which are controlled using a serial communication protocol.

Source Code Compatibility

SystemCompatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

External Interrupts on the STM8S

Thursday, August 16th, 2012

In a previous post we looked at the GPIO pins and how we could set the pins to either input or output but we concentrated on output. In this post we will look at using interrupts to detect input from the user and an output to indicate that the input has been detected. Our objective is:

  1. Create a circuit which can register when a button has been pressed.
  2. Toggle a LED when the button is pressed

Should be simple, so let’s give it a go.

Hardware

For the hardware we will need three components:

  1. STM8S Circuit
  2. Switch
  3. LED

STM8S Circuit

For the STM8S we need the STM8S103F3 connected to 3.3V and ground. We will also need to add two ceramic capacitors, a 100nF between Vss and Vdd (pins 7 and 9) and a 1uF between Vss and Vcap (pins 7 and 8).

Switch Circuit

For the switch circuit we need a switch and a pull-up resistor. We will pull the input line to the STM8S high through the pull-up resistor. Pressing the switch will pull the input line low. This part of the circuit looks like this:

This circuit will have the pin held high until the switch is pressed. All we need to do is to detect the falling edge of the input to the STM8S and we have a way to detecting when the user presses the switch.

One thing to note here is that we will be ignoring switch bounce and so we are likely to get the odd spurious message. We will come back to this later.

LED Circuit

This circuit is a simple transistor circuit which is used to switch on a LED. By applying a low current to the base of a transistor we can switch on a larger current to drive the LED. A quick simple circuit looks like this:

By setting a GPIO pin connected to the base of the transistor to high we can turn on a LED.

Putting it all together, we connect the switch to PD4 and the LED to PD3.

Software

The software is a simple extension of the previous post on GPIO pins. Here we are going to use the same port (port D) for both input and output. The full code is:

#include <intrinsics.h>
#include <iostm8s103f3.h>

//
//  Process the interrupt generated by the pressing of the button on PD4.
//
#pragma vector = 8
__interrupt void EXTI_PORTD_IRQHandler(void)
{
    PD_ODR_ODR3 = !PD_ODR_ODR3;     //  Toggle Port D, pin 3.
}

//
//  Main program loop.
//
void main()
{
    //
    //  Initialise the system.
    //
    __disable_interrupt();
    PD_ODR = 0;             //  All pins are turned off.
    PD_DDR = 0xff;          //  All pins are outputs.
    PD_CR1 = 0xff;          //  Push-Pull outputs.
    PD_CR2 = 0xff;          //  Output speeds up to 10 MHz.
    //
    //  Now configure the input pin.
    //
    PD_DDR_DDR4 = 0;        //  PD4 is input.
    PD_CR1_C14 = 0;         //  PD4 is floating input.
    //
    //  Set up the interrupt.
    //
    EXTI_CR1_PDIS = 2;      //  Interrupt on falling edge.
    EXTI_CR2_TLIS = 0;      //  Falling edge only.
    __enable_interrupt();

    while (1)
    {
        __wait_for_interrupt();
    }
}

So let’s start and break the program down. The first thing you will notice is that we initially configure all of the pins on port D as outputs as we have previously seen:

PD_ODR = 0;             //  All pins are turned off.
PD_DDR = 0xff;          //  All pins are outputs.
PD_CR1 = 0xff;          //  Push-Pull outputs.
PD_CR2 = 0xff;          //  Output speeds up to 10 MHz.

The next thing we do is to set up the system to allow PD4 as an input pin:

PD_DDR_DDR4 = 0;        //  PD4 is input.
PD_CR1_C14 = 0;         //  PD4 is floating input.

The final step of the configuration is to set the external interrupt for the port to detect the falling edge of the signal:

EXTI_CR1_PDIS = 2;      //  Interrupt on falling edge.
EXTI_CR2_TLIS = 0;      //  Falling edge only.

The final part of the main program is to wait for an interrupt. This is repeated infinitely:

while (1)
{
    __wait_for_interrupt();
}

The interesting part of the problem is the interrupt routine as this is where the real work is actually done. The code is simple enough you just have to make sure that you declare the method correctly:

#pragma vector = 8
__interrupt void EXTI_PORTD_IRQHandler(void)
{
    PD_ODR_ODR3 = !PD_ODR_ODR3;     //  Toggle Port D, pin 3.
}

The first two lines declare the method as an Interrupt Service Routine (ISR). The #pragma vector = 8 tells the compiler which interrupt this method will be servicing. In this case, this method will be called to process the interrupts for Port D. We will look into ISRs a little more in a later post.

Putting it all Together

If we wire all of the hardware together on a breadboard we end up with something like the following:

and a quick video of it working:

Switch Bounce

As noted earlier, mechanical switches are susceptible to switch bounce. This is caused by the mechanical contacts not closing perfectly when the switch is pressed. You can notice an example of bounce in the above video. When the switch is pressed the second time you can see that the LED is switched off but it is then switched on straight away. This is the effect of the switch contacts causing multiple signals. If a scope is hooked up to a switch you see something like the following:

In this case the switch is held down and then released. Notice the spike; this is caused by the switch bounce. If the signal is large enough then the microcontroller will think that the switch has been pressed twice rather than once – in fact that is what happened in the above video. There are a few ways to solve this but I’ll leave that as an exercise to the reader.

You can find the full source for the above project here. This application has been tested on tmy reference platform, the Variable Labs Protomodule and the STM8S Discovery board.

Compatibility

System Compatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Configuring the STM8S System Clock – The Way of the Register

Sunday, July 29th, 2012

This post continues the low level use of the STM8S registers and shows you how to configure the STM8S system clock. In particular we will configure the system clock to use the internal high speed clock.

So let us start with a little background. The STM8S can be driven by three clock sources:

  • High Speed Internal (HSI) RC oscillator running at 16MHz
  • Low Speed Internal (LSI) RC oscillator running at 128KHz
  • External clock (1-24 MHz) which can be either an external crystal or user supplied clock.

We will be using the internal oscillator as this will be satisfactory for our purposes. An external clock may be more accurate but for most of the work I am doing I am happy to sacrifice the accuracy for the lower component count and greater simplicity of my designs.

At start up, the STM8S will be using HSI with a prescalar to bring the initial clock speed down to 2MHz. We will be resetting the clock prescalar to allow the chip to run at the full 16MHz.

The switching algorithm we will use is as follows:

  1. Reset all of the clock registers to the power on state
  2. Select the clock we wish to use
  3. Enable the switching mechanism
  4. Wait until the STM8S indicates that the clock has stabilised

Clock Registers

The description of the clock registers start around page 89 of the STM8S Reference Manual. In this article we will run through the registers concentrating on the values we will be setting. For a fuller description you should refer to the STM8S Reference Manual.

CLK_ICKR – Internal Clock Register

The only bits we will really be interested in for this example bits 1 and 0, this allows us to select the HSI and see if it is ready.

Register NameDescription
REGAHControl the actions of the internal voltage regulator when the chip enters Active-halt mode.
LSIRDYSet by hardware, this bit determines if the LSI is stabilised and ready. 0 indicates the oscillator is not ready, 1 indicates it is stable.
LSIENSet and cleared by the user program, this bit determines if the LSI has been selected as the clock source for the chip.
This can also be set by hardware to indicate that the LSI is required.
FHWUSet and cleared by the user program, this bit indicates if fast wakeup from Halt/Active -halt is enabled. 0 = disabled, 1 = enabled
HSIRDYSet and reset by hardware, this bit determines if the HSI is stable and ready for use.
HSIENSet and cleared by the user program, this bit determines if the HSI has been selected as the clock source for the chip.
This can also be set by hardware to indicate that the HSI is required.
0 indicates HSI is not selected, 1 indicates HSI is selected.

Our example here will be resetting the clock source on the STM8S chip to use the internal oscillator using HSIEN and using the HSIRDY bit to determine when the clock has been setup and is stable.

CLK_ECKR – External Clock Register

This register is used to provide information about the state of the external clock. We will not be using this register for anything other than resetting the register to the power on state.

Register NameDescription
HSERDYExternal high speed clock state, 0 = not ready, 1 = ready.
HSEENEnable/disable the external high speed clock. 1 = enabled, 0 = disabled

CLK_CMSR – Clock Master Status Register

This register is set and cleared by hardware and indicates which clock source is currently selected as the master clock source.

ValueClock Source
0xe1HSI
0xd2LSI
0xb4HSE

CLK_SWR – Clock Master Switch Register

This register is written to by the user program and is used to select the master clock source. The register cannot be written to whilst a clock source switch is on-going. You can test for the switch using the SWBSY in the CLK_SWCR register.

ValueClock Source Selected
0xe1HSI
0xd2LSI
0xb4HSE

Clock Switch Control Register – CLK_SWCR

The Clock Switch Control Register is used to control how and when the clock switch is performed.

Register NameDescription
SWBSYThis bit indicates if a clock switch is in progress, 1 = clock switch is on-going, 0 indicates that no switch is in progress.
This bit is set and cleared by hardware but can also be cleared in software. Clearing this bit resets the clock switch process.
SWENWriting a 1 into this bit starts the clock switching process.
SWIENEnable (1) or disable (0) an interrupt to be generated when a clock switch takes place.
SWIFIndicates if a clock switch is taking place (interrupts enabled) or is the target clock is ready (interrupts disabled)

In our case we will be using this register to start the clock switch process.

CLK_CKDIVR – Clock Divider Register

The system clock can be divided down to allow for lower clock frequencies to be used. This register allows for the HSI prescalar (divider) and the CPU prescalar to be set.

Register NameDescription
HSIDIVHSI prescalar
CPUDIVCPU Prescalar

The following values can be used for the HSI prescalar:

ValuePrescalar
0HSI frequency
1HSI frequency divided by 2
2HSI frequency divided by 4
3HSI frequency divided by 8

The following values are allowed for the CPU prescalar:

ValuePrescalar
0Master clock frequency
1Master clock frequency divided by 2
2Master clock frequency divided by 4
3Master clock frequency divided by 8
4Master clock frequency divided by 16
5Master clock frequency divided by 32
6Master clock frequency divided by 64
7Master clock frequency divided by 128

In this case we will want the CPU to be running at full speed and so no prescalars will be applied to either the master clock or the HSI.

CLK_PCKENR1 & CLK_ PCKENR2 – Peripheral Clock Gating Registers

These two registers enable (set to 1 and disable (set to 0) the clocks used to control the peripherals used in the application. I have fallen foul of these values a few times. If you set these registers or zero then you will turn off the peripheral clocks. This has the effect of turning off the feature you may be trying to use. If in doubt set both of these registers to 0xff. You can always refine the values later by restricting the clock signals to only those which you are using.

Register NamePeripheralDescription
CLK_PCKENR1TIM1Enable/disable timer 1
TIM3Enable/disable timer 2
TIM2/TIM5Enable/disable timer 2/5 (product dependent)
TIM4/TIM6Enable/disable timer 4/6 (product dependent)
UART1/2/3Enable/disable UART 1/2/3
SPIEnable/disable SPI
I2CEnable/disable I2C
CLK_PCKENR2CANEnable/disable the CAN bus
ADCEnable/.disable the analogue to digital converter
AWUEnable/disable the watchdog service

Enabling the service will use the frequency of the master clock. Disabling the clock to the service will turn it off.

The <iosstm8s103f3.h> file does not contain definitions for these bits, you need to define your own constants for these. I have recently taken to just turning them all on as I’m not too worried about the power requirements for the applications I am working on.

CLK_CSSR – Clock Security System Register

We will not be using this register in this example apart for setting the default power on value. Please see the STM8S Reference Manual for more information.

CLK_CCOR – Configurable Clock Output Register

We will not be using this register in this example apart for setting the default power on value. Please see the STM8S Reference Manual or future examples for more information.

CLK_HSITRIMR – HSI Clock Calibration Trimming Register

We will not be using this register in this example apart for setting the default power on value. Please see the STM8S Reference Manual for more information.

CLK_SWIMCCR – SWIM Clock Control Register

We will not be using this register in this example apart for setting the default power on value. Please see the STM8S Reference Manual for more information.

Software

As previously mentioned, this example will simply set the system clock to the maximum speed the HSI can deliver. We will then toggle a GPIO pin and hook this up to a scope to get an idea of the output. We will never see the full 16MHz clock speed of the HSI but we should be able to see that the output frequency changes when we change the clock dividers.

So first thing, let’s get the system set up and running at the full 16 MHz and see what we the scope produces.

#include <intrinsics.h>
#include <iostm8s103f3.h>

//
//  Setup the system clock to run at 16MHz using the internal oscillator.
//
void InitialiseSystemClock()
{
    CLK_ICKR = 0;                       //  Reset the Internal Clock Register.
    CLK_ICKR_HSIEN = 1;                 //  Enable the HSI.
    CLK_ECKR = 0;                       //  Disable the external clock.
    while (CLK_ICKR_HSIRDY == 0);       //  Wait for the HSI to be ready for use.
    CLK_CKDIVR = 0;                     //  Ensure the clocks are running at full speed.
    CLK_PCKENR1 = 0xff;                 //  Enable all peripheral clocks.
    CLK_PCKENR2 = 0xff;                 //  Ditto.
    CLK_CCOR = 0;                       //  Turn off CCO.
    CLK_HSITRIMR = 0;                   //  Turn off any HSIU trimming.
    CLK_SWIMCCR = 0;                    //  Set SWIM to run at clock / 2.
    CLK_SWR = 0xe1;                     //  Use HSI as the clock source.
    CLK_SWCR = 0;                       //  Reset the clock switch control register.
    CLK_SWCR_SWEN = 1;                  //  Enable switching.
    while (CLK_SWCR_SWBSY != 0);        //  Pause while the clock switch is busy.
}

//
//  Main program loop.
//
int main(void)
{
    __disable_interrupt();
    //
    //  Initialise Port D.
    //
    PD_ODR = 0;             //  All pins are turned off.
    PD_DDR_DDR4 = 1;        //  Port D, bit 4 is output.
    PD_CR1_C14 = 1;         //  Pin is set to Push-Pull mode.
    PD_CR2_C24 = 1;         //  Pin can run up to 10 MHz.
    //
    //  Now setup the system clock
    //
    InitialiseSystemClock();
    __enable_interrupt();
    while (1)
    {
        PD_ODR_ODR4 = 1;    // Turn Port D, Pin 4 on.
        PD_ODR_ODR4 = 0;    // Turn Port D, Pin 4 off.
    }
}

Running this code resulted in the following trace on the oscilloscope:

GPIO Output when the System Clock is set to HSI with no Divider.

GPIO Output when the System Clock is set to HSI with no Divider.

The frequency of the out was 2.693Mhz.

So now let’s see what happens when we set the prescalar for HSI to be 2 (i.e. half the clock speed. To do this we need to edit the code slightly, so change this:

CLK_CKDIVR = 0;                     //  Ensure the clocks are running at full speed.

to this:

CLK_CKDIVR = 0;                     //  Ensure the clocks are running at full speed.
CLK_CKDIVR_HSIDEV = 1;				//	Set the HSI divider to 2.

The result is the following trace:

GPIO Output when System Clock is set to HSI divided by 2

GPIO Output when System Clock is set to HSI divided by 2

This looks remarkably like the trace above but the oscilloscope shows that the frequency of the signal is now 1.335MHz, or approximately half of the frequency of the first trace.

The full project for this article can be downloaded from here. This code has been tested with my reference platform, the Variable Labs Protomodule and the STM8S Discovery board.

Compatibility

SystemCompatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Komodex Seven Segment Display and Breakout Modules

Friday, July 27th, 2012

Komodex Labs recently released a couple of new modules for the Netduino GO! platform. The first is a seven segment display module and as we will see later this can be used to show sensor data. The second module is a breakout module for the GO! bus and this is probably more interesting to module developers.

As the postman was kind to me and managed to get these modules to me this week I thought I’d hook them up to the light sensor I have been playing with to see what they can do.

A Little Background

I have recently been working with a simple sensor to teach myself how to work with the STM8S. It has been a long slow task as the normal competing pressures of work, the house and general life stuff keeps calling for my attention.

The project uses a TSL235R sensor which converts the current ambient light level into a square wave with 50% duty cycle. The STM8S periodically reads the frequency of the signal generated by the sensor. This value is then made available to the Netduino GO! via the GO! Bus.

This project is going to read the value from the STM8S and display it on the seven segment display. The value is a 16-bit value and so can range from 0 to 65535 so we will be showing the value in hex.

Seven Segment Module

The seven segment display is a nice little module very professionally finished. It feels a solid – sort of odd to say that about a module. I was kind of surprised by the weight but then I have only been working with small modules so far.

I’d write more but I think the module is best described my Matt’s blog post. This shows some photos of the module along with a description of the API used to control it.

GO! Bus Breakout Module

This is a handy little module which only had a short production run. I was lucky enough to have ordered one before stock ran out. The module is aimed at module developers. It has a couple of sockets for module cables along with some handy breakout points.

Komodex Labs GO! Bus Breakout Module

Komodex Labs GO! Bus Breakout Module

The idea is simple, you connect your Netduino GO! to one side of the breakout board and your module to the other side of the breakout board. You can then hook up test equipment (scope / logic analyser etc.) to a row of headers on the board. This allows you to debug your module by snooping on the data going down the GO! Bus.

An alternative configuration and one I am using for development on breadboard, is to connect the breakout module to breadboard with the Netduino GO! connected to one side of the breakout board. This allows you to feed the GO! Bus signals into your circuit whilst at the prototype stage.

The breakout also has a lovely feature in that you can connect the ST-LInk/V2 module to the board and at the flick of a switch you can disconnect the SWIM/NRST signals from the Netduino GO! and connect them to the ST-Link/V2 instead. This allows you to re-program the STM8S on the fly without having to modify your circuit – NEAT !

For more information about this module I’d head over to Matt’s blog post.

Hooking it all up

Connecting the Seven Digit Module up to the go was easy, it simply needed a standard 5cm GO! Bus cable and that’s it.

The Breakout module was a little more difficult as it had to be hooked into an existing prototype circuit. From the Netduino side it was easy, just another 5cm GO! Bus cable. The ST-Link/V2 connection was also easy as the module has a connector already on the board and it is designed to ensure that the connection can only be made one way. The only complication was then ensuring that the connections between the GO! Bus and the prototype circuit were correct. Adding this module has in fact made my prototype circuit a little cleaner.

Here’s what the final circuit looks like:

Komodex Seven Segment in Light Sensor Prototype Circuit

Komodex Seven Segment in Light Sensor Prototype Circuit

Installing the Drivers

The Seven Segment Module is supplied with a set of drivers in the form of an executable. The drivers can be found on the Komodex Labs web site. Installation was quick, simple and painless.

Komodex Labs also provide the source code for the drivers along with a sample application. This is a separate download and as you will see later, this came in handy.

As you would expect, the breakout module does not require any drivers as there is no interaction between the module and the PC.

Writing the Software

The API provided with the module is comprehensive but in this case we are going to use only a small part of it. We need to display a hex representation of a 16-bit number.

So the first step is to create a new project and add a reference to the module. You will have to browse to the directory in which you installed the drivers and add the Komodex.NETMF.SevenSegmentDisplay.dll file. On my machine this was installed in C:Program Files (x86)KomodexModule DriversAssembliesv4.2

The next step is to add a using statement

using Komodex.NETMF;

and then declare and instantiate an instance of the module:

SevenSegmentDisplay display = new SevenSegmentDisplay();
display.SetValue(0);

The above shows the module being instantiated and the display value set to 0.

The remainder of the program continuously polls the sensor for a reading. This reading is converted into a string containing the hexadecimal representation of the reading. This reading is then displayed on the Seven Segment Module. The code looks something like this:

while (true)
{
	short diff = module.GetReading();
	string output = "";
	char c;
	for (int index = 3; index >= 0; index--)
	{
		int nibble = (diff >> (4 * index)) & 0xF;
		if (nibble < 10)
		{
			output += nibble.ToString();
		}
		else
		{
			c = (char) ('A' + nibble - 10);
			output += c.ToString();
		}
	}
	display.SetValue(output);
	Thread.Sleep(1000);
}

The line short diff = module.GetReading(); obtains a reading from the sensor module which I am prototyping. This value could come from any sensor or from any source / calculation.

Hitting F5 deployed the code to the Netduino GO! and values quickly started appearing on the display. Success!

No… Wait…

I’m getting some unexpected output. Every now and then the module displays a number with some spaces in place of digits. Hmmmmm… what is going on!

Time for a quick test program. I know that the module works OK as the test projects ran fine. Adding a Debug.Print of the output variable gave me a clue. There was a pattern. Any numbers with the digit 9 in them showed a space instead of a digit. A quick test program showed that displaying 2929 where the variable of type int displayed the number correctly. Doing the same where the value was stored in a string showed any digit except the digit 9, these were replaced with spaces. Now we know where the problem is.

As noted earlier, Komodex Labs supply the source code for the drivers. So opening this project and some poking around the code for the display resulted in the problem being found. A quick modification to the source, recompile and then reference the newly compiled DLL in my code and Success !

Edit: Komodex labs have confirmed that the driver has been patched and as of 27/07/2012 the driver download contains the fix for the problem noted.

Here is a short video of the sensor and display working together:

Simple GPIO – The Way of the Register

Sunday, July 8th, 2012

If you have been following this blog for a while you will be aware that I have recently changed the way I write code for the STM8S from using the STD Peripheral Library to using direct register access. This has required that I go back to basics learning a new way to perform tasks I had only just mastered. The Way of the Register posts will show you have to control the STM8 using register access.

This first post will look at a simple task, controlling GPIO lines. The aim of this first exercise is to simply toggle one of the GPIO lines.

Hardware

For this task we need very little hardware, only the STM8S set up on breadboard. For this we need a minimum of two capacitors and the chip itself. A 1uF capacitor is placed between VSS and VCAP and a 100 nF capacitor is placed between VDD and VSS. An additional 1uF capacitor is also placed across the +3.3V and ground of the power supply. The following shows this set up on breadboard along with the breadboard power supply, connections to the oscilloscope and the ST-Link programmer:

STM8S103 set up on Breadboard

STM8S103 set up on Breadboard

The Registers

Before we can start coding we need to have a look at the registers we will be using. The GPIO pins have five registers used to control the GPIO function and set/read the value of a pin. These are:

Register
Data Direction Register
Control Register 1
Control Register 2
Output Data Register
Input Data Register

The following sections provide a brief description of the registers. For more information you should consult RM0016 – STM8S Reference Manual.

Px_DDR – Data Direction Register

This register determines which or the GPIO pins are outputs and which are inputs. A value of one in a bit sets a port line to output and zero sets the port line to input. You can set the value of the whole register or each individual bit in the register.

To set the whole register in one go you would execute something like the following:

PD_DDR = 0x0f;

This sets bits 0-3 inclusive of port D to output whilst bit 4-7 are inputs.

An alternative to this is to set up each GPIO pin individually, so the equivalent of the above is:

PD_ODR = 0;
PD_DDR_DDR0 = 1;
PD_DDR_DDR1 = 1;
PD_DDR_DDR2 = 1;
PD_DDR_DDR3 = 1;

Px_CR1 & PxCR2 – Control Register 1 and 2

These two registers determine the properties of the pins depending upon the operating mode of the pin. The following table summarises the operating modes:

RegisterModeValueDescription
CR1Input0Floating input
CR1Input1Input with pull-up
CR1Output0Open drain
CR1Output1Push-Pull
CR2Input0Interrupt disabled
CR2Input1Interrupt enabled
CR2Output0Output up to 2 MHz.
CR2Output1Output up to 10 MHz

In our case, we need the output pin to operate in Push-Pull mode and as we do not know the final speed of the output signal we will set this to the maximum, 10 MHz.

As with the data direction register, each bit in the registers maps to a specific GPIO on each port. In the case of these registers the bits are labelled C10-C17 (for Control Register 1) and C20-C27 (for control Register 2). The format appears to be CRB, where C stands for Control Register; R is an integer representing the register number and B is an integer representing the bit to be set.

In our case, this results in the following code:

PD_CR1_C14 = 1;
PD_CR2_C24 = 1;

Px_ODR – Input/Output Data Registers

These two registers allow you to read the value of an input pin and set the value of an output pin. As with the previous registers you can set/read the register in its entirety or bit by bit. So to turn all of the outputs off you would execute something like:

PD_ODR = 0;


In the case we have been using we will be outputting data on pin 4 of port D. So to set the pin high you would execute the following statement:

PD_ODR_ODR4 = 1;

Software

Now we have the theory in place lets put together a simple application which uses it. The following code sets up port D to have pin 4 configured as an output operating to 10 MHz. The main program loop then simply keeps flipping the bit. The result should be a square wave signal.

#include <iostm8S103f3.h>

int main( void )
{
    //
    //  Initialise Port D.
    //
    PD_ODR = 0;             //  All pins are turned off.
    PD_DDR_DDR4 = 1;        //  Port D, bit 4 is output.
    PD_CR1_C14 = 1;         //  Pin is set to Push-Pull mode.
    PD_CR2_C24 = 1;         //  Pin can run upto 10 MHz.
    //
    //  Now lets toggle to IO line.
    //
    while (1)
    {
        PD_ODR_ODR4 = 1;    // Turn Port D, Pin 4 on.
        PD_ODR_ODR4 = 0;    // Turn Port D, Pin 4 off.
    }
}

If we hook an oscilloscope up to PD4 on the STM8 chip we see the following:

Simple GPIO Output

Simple GPIO Output

As you can see, we have a square wave. Note that the wave is not symmetrical. This is due to the branch instruction being executed in the while loop to go back to the start of the loop.

Source Code

Here is the IAR project and source code for this post. This code has been tested on my reference platform, Variable Lab Protomodule and the STM8S Discovery board.

Compatibility

SystemCompatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Using Registers on the STM8S

Saturday, June 23rd, 2012

A few weeks ago I had a rant about the STM8S Standard Peripheral library after it cost me a fair amount of time tracking down what appeared to be a bug in the library. As a result of this I have moved over to accessing the registers on the chip directly to control the operation of the chip. A recent question ion one of the forums I haunt has prompted this post. Here I am going to present a few different ways of achieving the same task, one using the STD Peripheral Library and two examples using the registers directly but in different ways.

The task we are going to be looking at is one I perform as part of my initialisation of the STM8S, namely I set the clock up to a known state. In this case we will be setting the system to use the HSI clock running at 16 MHz with no dividers.

It is important to note that you will need to have a copy of the reference manual for the chip available when using direct register access to control the microcontroller. In this case you should be looking for document RM0016 on ST’s web site.

Using the Standard Peripheral Library

Using the STD Peripheral Library makes this a relatively simple task. We only need to call four methods:

CLK_DeInit();
CLK_SYSCLKConfig(CLK_PRESCALAR_CPUDIV1);    // CPU Prescalar = 1.
CLK_SYSCLKConfig(CLK_PRESCALAR_HSIDIV1);    // Prescalar = 1, 16 MHz.
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO,  // Automatically switch
                      CLK_SOURCE_HSI,       // Switch to internal timer.
                      DISABLE,              // Disable the clock switch interrupt.
                      CLK_CURRENTCLOCKSTATE_DISABLE);   // Disable the previous clock.

The headers for the above methods can be found in the file stm8s_clk.h and the source code for the methods can be found in the file stm8s_clk.c. These source files can be found in the source code folder of the STD Peripheral Library.

Direct Register Access – Method 1

This first method of accessing the registers continues to use the STD Peripheral Library files but we do not make any calls into the library. Instead we use the definitions for the registers to access the chip directly.

So let’s start by breaking the above four methods down into their direct register equivalents.

CLK_DeInit

The first thing we need to do is to reset all of the registers to the default values:

CLK->ICKR = CLK_ICKR_RESET_VALUE;
CLK->ECKR = CLK_ECKR_RESET_VALUE;
CLK->SWR  = CLK_SWR_RESET_VALUE;
CLK->SWCR = CLK_SWCR_RESET_VALUE;
CLK->CKDIVR = CLK_CKDIVR_RESET_VALUE;
CLK->PCKENR1 = CLK_PCKENR1_RESET_VALUE;
CLK->PCKENR2 = CLK_PCKENR2_RESET_VALUE;
CLK->CSSR = CLK_CSSR_RESET_VALUE;
//
//  The following set has to be performed twice.
//
CLK->CCOR = CLK_CCOR_RESET_VALUE;
while ((CLK->CCOR & CLK_CCOR_CCOEN) != 0);
CLK->CCOR = CLK_CCOR_RESET_VALUE;
CLK->HSITRIMR = CLK_HSITRIMR_RESET_VALUE;
CLK->SWIMCCR = CLK_SWIMCCR_RESET_VALUE;

As you can see, the library certainly hides a large amount of work from you. Most of the above code is simply a case of setting up the registers to default values.

To find out how this all works you need to start looking in the stm8s.h file. A quick search for CLK soon leads you to the following type declaration:

typedef struct CLK_struct
{
  __IO uint8_t ICKR;     /*!> Internal Clocks Control Register */
  __IO uint8_t ECKR;     /*!> External Clocks Control Register */
  uint8_t RESERVED;      /*!> Reserved byte */
  __IO uint8_t CMSR;     /*!> Clock Master Status Register */
  __IO uint8_t SWR;      /*!> Clock Master Switch Register */
  __IO uint8_t SWCR;     /*!> Switch Control Register */
  __IO uint8_t CKDIVR;   /*!> Clock Divider Register */
  __IO uint8_t PCKENR1;  /*!> Peripheral Clock Gating Register 1 */
  __IO uint8_t CSSR;     /*!> Clock Security System Register */
  __IO uint8_t CCOR;     /*!> Configurable Clock Output Register */
  __IO uint8_t PCKENR2;  /*!> Peripheral Clock Gating Register 2 */
  uint8_t RESERVED1;     /*!> Reserved byte */
  __IO uint8_t HSITRIMR; /*!> HSI Calibration Trimmer Register */
  __IO uint8_t SWIMCCR;  /*!> SWIM clock control register */
}
CLK_TypeDef;

If you have a look at the technical reference sheet for the chip, you will find section which shows the memory layout for the registers. These are at fixed locations in memory and should map to the above layout. The __IO is defined as volatile and will prevent the compiler from optimising out any references to the variables.

The next thing to note is that we still do not have a definition for CLK. A little more searching in the same file will lead you to the following statement:

#define CLK ((CLK_TypeDef *) CLK_BaseAddress)

So this defines CLK for us as a pointer to a location in memory. Some more searching (again in the same file) leads us to the following line of code:

#define CLK_BaseAddress         0x50C0

So the code CLK->ICKR = 0; will set the register at location 0x50C0 to zero.

One point to note is the statement while ((CLK->CCOR & CLK_CCOR_CCOEN) != 0);. This illustrates the use of another type of declaration you will find in stm8s.h, namely, CLK_CCOR_CCOEN. This declaration allows you to mask off certain bits within a register and use this to set or check values in a register. The name is made up of three parts:

NameDescription
CLKClock registers are being access.
CCORThis relates to the CCOR register.
CCOENMask the CCOEN bits in the register.

CLK_SYSCLKConfig

The next task is to set the prescalar for the system clock. This is being set to 1 to ensure the system runs at 16 MHz.

CLK->CKDIVR  &= (uint8_t) (~CLK_CKDIVR_HSIDIV);
CLK->CKDIVR |= (uint8_t) ((uint8_t) CLK_PRESCALAR_HSIDIV1 & (uint8_t) CLK_CKDIVR_HSIDIV);

The first line resets the prescalar to a known value whilst the second selects the divider which will be used.

CLK_ClockSwitchConfig

The final operation is to switch the system clock to the HSI and this is achieved with the following code:

CLK->SWCR |= CLK_SWCR_SWEN;
CLK->SWCR &= (uint8_t) (~CLK_SWCR_SWIEN);
CLK->SWR = (uint8_t) CLK_SOURCE_HSI;
uint16_t downCounter = CLK_TIMEOUT;
while ((((CLK->SWCR & CLK_SWCR_SWBSY) != 0 ) && (downCounter != 0)))
{
    downCounter--;
}

Direct Register Access – Method 2

This method uses the register declarations found in the header files provided by IAR. So for the STM8S103F3 we will be looking in the file .

CLK_DeInit

As before, the first thing we will do is to reset the registers to a known set of values:

CLK_ICKR = 0;
CLK_ECKR = 0;
CLK_SWR = 0xe1;
CLK_SWCR = 0;
CLK_CKDIVR = 0x10;
CLK_PCKENR1 = CLK_PCKENR1_SPI | CLK_PCKENR1_TIM2;   //  Enable the peripheral clocks we need.
CLK_PCKENR2 = 0;
CLK_CSSR = 0;
CLK_CCOR = 0;
while (CLK_CCOR_CCOEN != 0);
CLK_CCOR = 0;
CLK_HSITRIMR = 0;
CLK_SWIMCCR = 0;

The first thing you will notice is that by using this method we are not using the pointer dereferencing operator. Instead the application is accessing the registers directly. So let’s have a look at the header file and dissect the reset of the ICKR register. Searching for CLK_ICKR leads us to the following code:

typedef struct
{
  unsigned char HSIEN       : 1;
  unsigned char HSIRDY      : 1;
  unsigned char FHW         : 1;
  unsigned char LSIEN       : 1;
  unsigned char LSIRDY      : 1;
  unsigned char REGAH       : 1;
} __BITS_CLK_ICKR;
__IO_REG8_BIT(CLK_ICKR,    0x50C0, __READ_WRITE, __BITS_CLK_ICKR);

The first things we see is the definition of the structure which maps on to the format of the ICKR register. Each bit field is broken out and maps on to the sections of the register as defined in the data sheet.

The final line of code in the above snippet uses the __IO_REG8_BIT macro to map the data structure onto the address 0x50C0 and create a new name with bit level access.

The next thing to note is the while loop which checks the CCOOEN bit in the CCOR register – while (CLK_CCOR_CCOEN != 0);. As above, this uses a three part notation to form a reference, this time it is to a particular bit in a register. This is not a mask as in the previous example. This is broken down as follows:

NameDescription
CLKClock registers are being access.
CCORThis relates to the CCOR register.
CCOENCCOEN bits in the CCOR register.

Some more digging in the file leads to the following definition:

#define CLK_CCOR_CCOEN           CLK_CCOR_bit.CCOEN

The CLK_CCOR_bit declaration was created by the __IO_REG8_BIT macro. This is the name which has been given to the location in memory of the ICKR register.

CLK_SYSCLKConfig

The next task is to set the prescalar for the system clock. This is being set to 1 to ensure the system runs at 16 MHz. Note that a prescalar of 1 maps to the prescalar bits in the register being set to zero.

CLK_CKDIVR = 0;

CLK_ClockSwitchConfig

The final operation is to switch the system clock to the HSI and this is achieved with the following code:

CLK_SWCR_SWEN = 1;
CLK_SWR = 0xe1;                     //  Use HSI as the clock source.
while (CLK_SWCR_SWBSY != 0);        //  Pause while the clock switch is busy.

Conclusion

So there you have it, three different ways of performing the same task. The method used will be down to individual preference. Happy experimenting.

Using the UART on the STM8S

Friday, June 8th, 2012

If you have been reading my recent posts you will have noticed that I have had some problems setting up the UART on the STM8S. IN fact I spent several days getting this working. This post gives a couple of code snippets which I have used to get around this problem. You may need to refer to the data sheet on the processor for more detail on how this code works.

Setting Up the UART

This code makes a fundamental, namely that you have configured the chip and your circuit to run at 16 MHz. I did this by setting the chip to use the internal oscillator as it’s clock source and using a prescalar of 1. If you have this set up then the following method will allow you access to the UART running at 115200 baud, 8 data bits, 1 stop bit and no parity.

Firstly, we need to make sure we are using the right include files:

#include "stm8s.h"
#include "stm8s_uart1.h"

Next we need to set up the port:

void SetupSerialPort()
{
    //
    //  Clear the Idle Line Detected bit in the status register by a read
    //  to the UART1_SR register followed by a Read to the UART1_DR register.
    //
    (void) UART1->SR;
    (void) UART1->DR;

    UART1->CR2 = UART1_CR2_RESET_VALUE;
    UART1->CR4 = UART1_CR4_RESET_VALUE;
    UART1->CR5 = UART1_CR5_RESET_VALUE;
    UART1->GTR = UART1_GTR_RESET_VALUE;
    UART1->PSCR = UART1_PSCR_RESET_VALUE;
    //
    //  Setup the port.
    //
    UART1->CR1 = (u8) UART1_WORDLENGTH_8D | (u8) UART1_PARITY_NO;   // Word length = 8, no parity.
    UART1->CR3 = (u8) UART1_STOPBITS_1;                             // 1 stop bit.

    UART1->BRR1 &= (uint8_t) (~UART1_BRR1_DIVM);
    UART1->BRR2 &= (uint8_t) (~UART1_BRR2_DIVM);
    UART1->BRR2 &= (uint8_t) (~UART1_BRR2_DIVF);
    //
    //  Set the clock prescaler for 11520 baud.  This assumes a 16 MHz clock speed.
    //
    UART1->BRR2 = 0x0b;
    UART1->BRR1 = 0x08;
    //
    //  Disable the Transmitter and Receiver before seting the LBCL, CPOL and CPHA bits
    //
    UART1->CR2 &= (u8) ~(UART1_CR2_TEN | UART1_CR2_REN);
    //
    //  Clear the Clock Polarity, lock Phase, Last Bit Clock pulse
    //
    UART1->CR3 &= (u8)~(UART1_CR3_CPOL | UART1_CR3_CPHA | UART1_CR3_LBCL);
    //
    //  Set the Clock Polarity, lock Phase, Last Bit Clock pulse
    //
    UART1->CR3 |= (u8)((u8) UART1_SYNCMODE_CLOCK_ENABLE &
                       (u8) (UART1_CR3_CPOL | UART1_CR3_CPHA | UART1_CR3_LBCL));
    //
    //  Set the Tx and Rx state
    //
    UART1->CR2 |= (u8) ((u8) UART1_CR2_TEN | (u8) UART1_CR2_REN);
    UART1->CR3 &= (u8) (~UART1_CR3_CKEN);
}

Having set up the UART we need a method to write data to the port. The following method will send simple text strings to the UART:

//
//  Send a message to the debug port (UART1).
//
void Printf(char *message)
{
    char *ch = message;
    while (*ch)
    {
        UART1->DR = (u8) (*ch);
        while ((UART1->SR & (u8) UART1_FLAG_TXE) == RESET);
        ch++;
    }
}

Using the UART

The use of this code can be illustrated by the following program:

void main()
{
    SetupSerialPort()
    Printf("Hello from my program");
}

The Cube Still Lives…

Monday, May 21st, 2012

The 8 x 8 x 8 LED cube has been on it’s travels again. This time it has made an appearance at the Bay Area Maker Faire:

Netduino 8x8x8 LED Cube at the Bay Area Maker Faire 2012

Thanks to fellow Netduino community member Chris Hammond for permission to use this photo.