Stm8 시리얼 디버그 사용 방법

주요 콘텐츠로 건너뛰기

이 브라우저는 더 이상 지원되지 않습니다.

최신 기능, 보안 업데이트, 기술 지원을 이용하려면 Microsoft Edge로 업그레이드하세요.

직렬 연결을 통한 디버그

  • 아티클
  • 10/25/2022
  • 읽는 데 4분 걸림

이 문서의 내용

다른 버전의 Windows와 마찬가지로 팩터리 OS 디바이스에서 Windows 디버거를 사용하여 코드를 디버그할 수 있습니다. 설정을 가져오는 프로세스는 약간 다르지만 팩터리 OS 디바이스가 디버거에 연결되면 디버깅 프로세스는 다른 Windows 버전과 동일합니다.

Windows 시스템 키트에는 팩터리 OS 디바이스에서 디버거를 사용하도록 설정하는 PowerShell 유틸리티가 포함되어 있습니다. 이 항목에서는 로컬 VM에서 디버거에 대한 연결을 설정하는 방법을 보여 줍니다.

팩터리 OS 제품을 사용하는 경우 Debug-WcosDevice를 사용하지 않고 팩터리 OS 디바이스에서 디버거를 사용하도록 설정하는 커널 디버거 기능을 사용할 수 있습니다.

필요한 작업

디버깅을 시작하려면 다음이 필요합니다.

  • 관리자 PC
  • 관리자 PC에서 Hyper-V로 만든 팩터리 OS VM
    • 아래 예에서는 "팩터리 OS VM"이라는 이름을 사용합니다.
    • 보안 부팅이 꺼져 있습니다.
  • 관리자 PC에서 사용 가능한 Windows 시스템 키트

팩터리 OS 디버깅을 위해 PC 설정

1. 디버그할 팩터리 OS 디바이스 준비

  • 커널 디버거를 사용하도록 설정하는 기능이 포함된 팩터리 OS 이미지 빌드

또는

  • 커널 디버깅 기능이 아직 사용하도록 설정되지 않은 이미지가 있는 경우 Debug-WcosDevice 유틸리티를 관리자 PC에 추가합니다.

    관리 PowerShell 창을 사용하여 Windows 시스템 키트 ISO에서 로컬 PC로 debug-wcosdevice 파일을 복사합니다. 이러한 파일은 디버거를 팩터리 OS VM에 연결할 수 있게 해주는 PowerShell 모듈입니다.

    md "C:\Program Files\WindowsPowerShell\Modules\debug-wcosdevice"
    cd "C:\Program Files\WindowsPowerShell\Modules\debug-wcosdevice" 
    copy "K:\Program Files\Windows Kits\10\Tools\Scripts\debug-wcosdevice.*" 
    
    md "C:\Program Files (x86)\WindowsPowerShell\Modules\debug-wcosdevice"
    cd "C:\Program Files (x86)\WindowsPowerShell\Modules\debug-wcosdevice" 
    copy "K:\Program Files\Windows Kits\10\Tools\Scripts\debug-wcosdevice.*"
    

    여기서 K:는 WSK ISO의 루트입니다.

2. 직렬 포트 매핑

  1. 파일 탐색기에서 VM의 VHD를 두 번 클릭하여 탑재합니다.

  2. 관리 PowerShell 창을 사용하여 VM의 직렬 포트를 봅니다.

    Get-VMComPort -VMName "Factory OS VM"
    

    다음과 같은 출력이 표시됩니다.

    VMName       Name    Path
    ------       ----    ----
    Factory OS VM COM 1 
    Factory OS VM COM 2 
    
  3. COM1 포트 매핑:

    Set-VMComPort -VMName "Factory OS VM" -Path \\.\pipe\vmcom1  -Number 1
    

    vmcom1은 위에서 경로에 지정한 이름이지만 다른 이름을 선택할 수 있습니다.

  4. COM 1 포트가 매핑되었는지 확인합니다.

    Get-VMComPort -VMName "Factory OS VM"
    

    출력은 다음과 같습니다.

    VMName       Name  Path
    ------       ----  ----
    Factory OS VM COM 1  \\.\pipe\vmcom1
    Factory OS VM COM 2 
    

    이전 단계에서 매핑한 경로는 COM 1에 할당된 경로로 표시됩니다.

3. 디바이스에 연결하고 디버깅 시작

  1. 커널 디버깅 기능이 사용하도록 설정되지 않은 VM을 사용하는 경우 Debug-WcosDevice를 사용하여 커널 디버깅을 사용하도록 설정하도록 VHDX의 BCD 저장소를 구성합니다.

    Debug-WcosDevice -Transport  SERIAL  1   115200  -BootDebug
    

    -TransportSERIAL과 함께 사용되면 다음 옵션을 지정할 수 있습니다.

    매개 변수 형식설명
    DEBUGPORT 디버그 포트는 1에서 99 사이일 수 있습니다.
    BAUDRATE 전송 속도는 300 이상일 수 있습니다.
    NOBAUD 이는 일부 시스템에서 원하지 않는 BAUD 속도를 설정하지 않도록 시스템에 지정합니다.
  2. 다른 Windows 디바이스와 마찬가지로 디바이스를 디버그합니다.

Programming a new microcontroller often takes a longer time due to the new register handling methods and not knowing what bit does exactly what. The same goes for debugging as well without saying. This is why programmers quite often use breakpoints in their code and step through it using a debugger. But using a debugger might need additional hardware (most times expensive) and also additional time. Being an Arduino fan boy, one thing we all can agree is using serial print statements for debugging and understanding our code makes life a lot easier. What is we can replicate the same on STM8s with cosmic C compiler and SPL libraries? Well, it is very much possible, and that is exactly what we are going to do in this third tutorial of our tutorial series. You also check the getting started with STM8S (tutorial 1) and STM8S GPIO control (tutorial 2) if you are completely new here. Also, we have also explored the possibility of Programming STM8S with Arduino for quick starters. All that being said let’s get into the tutorial.

Serial Communication on STM8S103F3P6

From the datasheet of STM8S103F3P6, we can see that our 8-bit controller supports UART communication in many different modes. The controller also has a clock output pin for synchronous UART communication and can also support SmarCard, IrDA, and LIN. But we will be exploring none of that in this tutorial just to stay away from complexity. We will learn how to do simple UART read and write.

The tutorial also provides a header file called stm8s103 serial.h using which you can perform simple UART commands like Serial begin, Serial read, serial print, etc. Basically, you will be able to print char, int, and string to the serial monitor and also read char from the serial monitor. At the end of this tutorial, you will be able to control an LED from the serial monitor and get feedback about the status of the LED. The header file mentioned above depends on the SPL libraries, so make sure you have followed the getting started tutorial.

Serial Communication Pins on STM8S103F3P6

Let’s start from the hardware side. Taking a quick look at the pinouts on the STM8S103F3P6 microcontroller given below, we can see that pins 1, 2, and 3 will be used for UART communication.

Stm8 시리얼 디버그 사용 방법

Among the three, pin 1 is the UART clock pin which will be used only during synchronous UART communication, so we won’t be needing it here. Pin 2 is the UART Transmitter pin and Pin 3 is the UART Receiver pin. Do note that these pins can also double up as an analog pin or normal GPIO pin.

Circuit Diagram for STM8S Serial Communication

The circuit diagram is very simple here, we need to connect our ST-LINK 2 for programming and a USB to TTL converter for reading serial data. Do note that our STM8S controller works in 3.3V logic level, so make sure your USB to TTL converter also supports 3.3V logic. The complete circuit diagram is shown below.

Stm8 시리얼 디버그 사용 방법

You have to connect your ST-link in one USB port and USB to TTL converter in another USB port of your laptop, so that you can both program and monitor data at the same time. The UART connection is simple, just connect the ground and Rx/Tx pin of your STM8S microcontroller to the Tx/Rx pins of the USB to TTL converter. Here I have powered the controller with the Vcc pin of ST-Link and have left the vss pin of TTL converter open, you can also do this the other way around. There are many types of USB to TTL converter in the market just make sure it can operate on 3.3V Logic signals and simple look for Tx, Rx, and GND pins and make the connection shown above. My hardware set-up is shown below.

Stm8 시리얼 디버그 사용 방법

To make a serial communication way, we have provided the STM8S_Serial.h header file. Using this header file, you can perform simple Arduino like functions for serial communication.

Stm8 시리얼 디버그 사용 방법

You can find all the required files for this project on our STM8S103F3_SPL Github page. If you only need this particular header file, you can download it from the below link.

Download STM8S_Serial.h

Setting up STVD for Serial Communication

To work with serial communication, we will be using many using the STM8S_Serial.h header file function that we discussed earlier. But the library has other dependencies, many the SPL UART and Clock related header and C files. So from this point, it is better to include all the header and C files to our project to avoid a compilation error. My STVD work environment looks like this.

Stm8 시리얼 디버그 사용 방법

Make sure you have included all the SPL source files and Include file like we did in our first tutorial. And also ensure you have added the stm8s103_serial.h header file. There is no C file for this header.

Programming STM8S for Serial Communication

Once the STVD project setup is ready, we can begin writing our code in the main.c file. The complete code for this tutorial can be found at the bottom of this page. The explanation is as follows.

The first step is to include the required header files, here I have added the main header file (stm8s) and the stm8s_103_serial header file that we just downloaded.

//Required Headers
 #include "STM8S.h"
 #include "stm8s103_serial.h" //https://github.com/CircuitDigest/STM8S103F3_SPL/blob/master/stm8s103%20Libraries/stm8s103_Serial.h

Next, we are using the design macros to specify the input and output pins. Here will only be controlling the on-board LED which is connected to pin5 of port B, so we give it a name as test_LED.

#define test_LED GPIOB, GPIO_PIN_5 //test LED is connected to PB5

Moving on inside the main function, we will define the pin as an output. If you are not familiar with basic GPIO functions fall back to the STM8S GPIO tutorial.

//Pin defanitions
//Declare PB5 as push pull Output pin
GPIO_Init (test_LED, GPIO_MODE_OUT_PP_LOW_SLOW);

Then we initialize our serial communication ports at 9600 baud rates. For those who are new, 9600 is the rate of speed at which the data bits will be transferred during communication. If you set 9600 here, you also have to set the same on the monitoring software. Then we also print a string “Enter command” and move on to the next line.

Serial_begin(9600); //Initialize Serial communication at 9600 baud rate
Serial_print_string("Enter command"); //print a string
Serial_newline(); //move to next line

Moving on to the infinite while loop, we use the Serial_available function to check if there is any incoming serial data. If yes, we read and save it in a variable called ch and also print the same using Serial_print. Then if the received value is 0, we will turn off the LED and if it is 1, we will turn on the LED

   if(Serial_available())
     {
Serial_print_string("You have pressed: ");
ch = Serial_read_char();
Serial_print_char(ch);
Serial_newline();                                                                                              
if (ch == '0')
GPIO_WriteHigh(test_LED); //LED OFF                                                                                               
if (ch == '1')
GPIO_WriteLow(test_LED); //LED ON                                                                                               
}

With this, the programming for this tutorial is complete, just upload the code given at the bottom of this page and you should be able to control the LED from the serial monitor.

Controlling LED from Serial monitor

Once you have uploaded the code, you can open any serial monitor at 9600 baud rates. I have used the Arduino serial monitor itself for the ease of using it. Press the reset button and you should see the message “Enter a command”. Then if you enter 1 and press enter, the on-board led should turn on, similarly for 0, it should turn off.

Stm8 시리얼 디버그 사용 방법

Stm8 시리얼 디버그 사용 방법

The complete working can be found in the video linked at the bottom of this page. If you have any questions, please leave them in the comment section. You can also use our forums to post other technical questions.

STM8S Serial Library Deeper Look

For those curious minds who want to know what actually happens inside the STM8S103F3_Serial header file read on….

This header file works well for beginner level programming, but if you are using a different version of the STM8S controller or looking for some advanced options, you might want to tweak this header a bit or directly work with SPL libraries. I wrote this header file just as a ripe off from the UART1 header file, the explanation of my header file is as follows.

Reading a character from Serial Monitor 

This function helps to read a single character that has been sent to the microcontroller from the serial monitor.

char Serial_read_char(void)
 {
                 while (UART1_GetFlagStatus(UART1_FLAG_RXE) == RESET);
                 UART1_ClearFlag(UART1_FLAG_RXNE);
                 return (UART1_ReceiveData8());
 }

We wait till the RXE flag is SET to complete reception and then clear the flag to acknowledge the reception. Finally, we send the received 8-bit data as the result of this function.

Printing a character to Serial Monitor 

This function transmits a single character from a microcontroller to the serial monitor.

void Serial_print_char (char value)
 {
                 UART1_SendData8(value);
                 while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET); //wait for sending
 }

The function simply writes the 8-bit value and waits till the transmission is complete by checking the UART1_FLAG_TXE to SET

Initializing Serial Communication

This function initializes serial communication at the required baud rate.

void Serial_begin(uint32_t baud_rate)
 {
                 GPIO_Init(GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_FAST);
                 GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT);
                 UART1_DeInit(); //Deinitialize UART peripherals                                                              
                               UART1_Init(baud_rate,
                UART1_WORDLENGTH_8D,
                UART1_STOPBITS_1,
                UART1_PARITY_NO,
                UART1_SYNCMODE_CLOCK_DISABLE,
                UART1_MODE_TXRX_ENABLE); //(BaudRate, Wordlegth, StopBits, Parity, SyncMode, Mode)               
                                UART1_Cmd(ENABLE);
 }

Apart from the baud rate, there are other parameters that have to be set for serial communication, like the number of data bits, number of stop bits, parity, etc. The most common one (similar to Arduino) is the 8-bit data with one stop bit and no parity and hence that will be the default setting. You can change it if required.

Printing an Integer to Serial Monitor 

Most time, if we are using a serial monitor for debugging or monitoring, we might want to print a variable of type int to the serial monitor. This function does exactly that

void Serial_print_int (int number) //Funtion to print int value to serial monitor
 {
                 char count = 0;
                 char digit[5] = "";         
                 while (number != 0) //split the int to char array
                 {
                                 digit[count] = number%10;
                                 count++;
                                 number = number/10;
                 }
                 while (count !=0) //print char array in correct direction
                 {
                                UART1_SendData8(digit[count-1] + 0x30);
                                while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET); //wait for sending
                                count--;
                 }
 }

It takes in an integer value and converts it to character array in the first while loop, then in the second while loop, we will sending each of the characters similar to our print char function.

Printing a new line

This is a simple function to print a new line. The hexvalue to do that is “0x0a”, we are just sending it across using the 8-bit transmit command.

void Serial_newline(void)
 {
                 UART1_SendData8(0x0a);
                while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET); //wait for sending
 }

Printing a string to serial monitor

Another useful function is to actually print strings on the serial monitor.

void Serial_print_string (char string[])
 {.
                 char i=0;
                 while (string[i] != 0x00)
                 {
                                UART1_SendData8(string[i]);
                                while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
                                i++;
                }
 }

Again, this function also converts the string to char array and sends each character. As we know all strings end will null. So we just have to keep traversing and transmitting the characters till we reach the null 0x00.

Checking if serial data is available to read

This function checks if there is any serial data in the buffer ready to read.

bool Serial_available()
 {
                 if(UART1_GetFlagStatus(UART1_FLAG_RXNE) == TRUE)
                 return TRUE;
                 else
                 return FALSE;
 }

It checks for the flag UART1_FLAG_RXNE, if it is true, it returns true and if it is not, it returns false.