STM8 - программирование, прошивка и всё-всё-всё

Наряду с Arduino у любителей микроконтроллеров сейчас популярна и линейка продуктов от компании STMicroelectronics, включающая 8-разрядные микроконтроллеры STM8 и 32-разрядные микроконтроллеры STM32 (на ядре Cortex).

Микроконтроллеры STM8 состоят из нескольких линееек:
STM8S - основная линейка,
STM8A - для автомобильной промышленности,
STM8L - со сверхнизким потреблением энергии,
STM8T - емкостный сенсор для детектирования прикосновения или приближения.

Отладочную плату с микроконтроллером STM8 на борту можно приобрести за 1 (!) доллар и даже дешевле. Я приобрел несколько таких плат  на основе микроконтроллера STM8S103F3P6 на торговой площадке ebay:
STM8S103F3P6

контакт назначение
D4 UART_CLK
D5 TX
D6 RX
RST сброс
A1 Oscin
A2 Oscin
GND земля
5V вход стабилизатора
3V3 выход стабилизатора
A3 SS
D3 Ain4
D2 Ain3
D1 SWIM
C7 MISO
C6 MOSI
C5 SCK
C4 Ain2
C3  
B4 SDA
B5 SCL

Микроконтроллер STM8S103F3P6 содержит 8 КБайт флэш-памяти с ресурсом стирания 10 000 раз, 640 байт EEPROM и 1 КБайт RAM. Тактовая частота 8-битного процессора серии STM8S составляет 16 МГц.

Для питания платы можно использовать следующие варианты:

  • подключение источника напряжением 4,5 ... 15 В к контактам + или 5V и - или GND;
  • подключение кабеля к microUSB-разъему (этот разъем используется только для питания!).

На плате установлен стабилизатор AMS1117-3.3. Вход стабилизатора соединен с контактом 5V, а выход - с контактом 3V3.

Разработка в среде IdeaSTM8

Установка среды разработки

Для программирования под микроконтроллеры STM8 можно использовать среду разработки IdeaSTM8 от компании Cosmic Software (в версии CXSTM8 special edition package - доступна с марта 2016 года, не имеет ограничений):
IdeaSTM8

Для загрузки дистрибутива следует перейти по этой ссылке: http://cosmicsoftware.com/download_stm8_32k.php.
При этом для использования кросс-компилятора от Cosmic Software перед скачиванием необходимо пройти регистрацию, указав имя (Name), название компании (Company), страну (Other), адрес электронной почты (E-mail), а затем нажав для отправки сведений кнопку «Submit».
В версии 4.4.6 объем дистрибутива (cxstm8_FSE_stm32_32K.exe) составляет 20,7 МБайт. 
Для получения годовой (затем продляемой) бесплатной лицензии при инсталляции необходимо нажать кнопку «Register on the Web», что приведет к отправке файла лицензии на адрес электронной почты, указанный при регистрации. Лицензия привязывается к компьютеру, на котором установлен компилятор (с помощью HOSTNAME, HOSTID и т.п.).
После получения файла license.lic следует разместить его в папке \COSMIC\FSE_Compilers\CXSTM8\License:
лицензия для IdeaSTM8

Разработка программы

В качестве примера создадим программу мигания светодиодом (Hello, world! в мире микроконтроллеров) TEST, размещенным на плате и подключенным к контакту PB.5.

Создаем новый проект, выполняя команду New Application:
IdeaSTM8 создание проекта

Выбираем в качестве целевой платформы микроконтроллер STM8S103F3:
STM8 программирование

Копируем в папку проекта заголовочный файл с определениями stm8s.h, предварительно раскомментировав в нем определение используемого микроконтроллера STM8S103:

 /* #define STM8AF626x */    /*!< STM8A Medium density devices */
  #define STM8S103       /*!< STM8S Low density devices */
 /* #define STM8S903 */      /*!< STM8S Low density devices */

Создаем новый файл (tst.c) с исходным кодом:

создаем файл:
Cosmic Software

выбираем в качестве типа файла - файл с исходным кодом на C:
программа для STM8

Добавляем созданный файл в проект:
IdeaSTM8 программирование

Пишем код программы в созданном файле:

#include <stm8s.h>

static void delay(uint32_t t) //процедура задержки
{
    while(t--) {}
}

int main(void)
{
    GPIOB->DDR |= (1 << 5); //настройка контакта PB.5 на выход
    GPIOB->CR1 |= (1 << 5); //настройка контакта PB.5 как push-pull, можно пропустить
    GPIOB->ODR |= (1 << 5); //вывод 1 в порт
    while(1)
    {
        GPIOB->ODR |= (1 << 5); //вывод 1 в порт
        delay(100000UL); //задержка
        GPIOB->ODR &= ~(1 << 5); //вывод 0 в порт
        delay(100000UL); //задержка
    }
}

Для компиляции и сборки проекта следует нажать клавишу F7 или выполнить команду Build:
сборка проекта для STM8

В результате сборки в папке проекта создается файл с именем проекта и расширением .sm8 (TST.sm8).

Для преобразования файла с расширением .sm8 в готовый для прошивки в микроконтроллер hex-файл  я использую COSMIC Software Hexa Translator (chex.exe) с помощью команды:

chex -oTST.hex -fi TST.sm8  ,

где TST - имя проекта.

Полученный hex-файл (TST.hex) содержит информацию, необходимую для прошивки микроконтроллера:

:20800000820080808200000082000000820000008200000082000000820000008200000050
:20802000820000008200000082000000820000008200000082000000820000008200000030
:20804000820000008200000082000000820000008200000082000000820000008200000010
:208060008200000082000000820000008200000082000000820000008200000082000000F0
:20808000AE03FF94CD809F20FE961C0003CD80F3961C0003A601CD80C9CD80DF26EB8172FB
:2080A0001A5007721A5005721A5005AE86A089AE000189ADD45B04721B5005AE86A089AE2B
:2080C000000189ADC45B0420DE40EB03E703250EE6026A024D2607E60126017A6A01819C1F
:2080E0003D00260E3D0126083D0226043D032702A6018188F6B700E601B701E602B702E64E
:0581000003B7038481B8
:00FFFF0101

SDCC
Разработка в среде SDCC

Установка среды разработки

Для программирования под микроконтроллеры STM8 можно использовать открытую (под лицензией GPLv3) среду разработки SDCC (Small Device C Compiler suite). Версии под различные ОС доступны на http://sdcc.sourceforge.net. Эта среда представляет собой компилятор языка программирования ANSI C под множество архитектур - от Intel 8051 до STMicroelectronics STM8.

Разработка программы

Пишем код программы в файле TST.c:

#include <stdint.h>

#define     __IO    volatile         /*!< defines 'read / write' permissions  */

typedef struct GPIO_struct
{
  __IO uint8_t ODR; /*!< Output Data Register */
  __IO uint8_t IDR; /*!< Input Data Register */
  __IO uint8_t DDR; /*!< Data Direction Register */
  __IO uint8_t CR1; /*!< Configuration Register 1 */
  __IO uint8_t CR2; /*!< Configuration Register 2 */
}
GPIO_TypeDef;

#define GPIOB_BaseAddress       0x5005
#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress)

static void delay(uint32_t t)
{
    while(t--) {}
}

int main(void)
{
    GPIOB->DDR |= (1 << 5);
    GPIOB->ODR |= (1 << 5);
    while(1)
    {
        GPIOB->ODR |= (1 << 5);
        delay(100000UL);
        GPIOB->ODR &= ~(1 << 5);
        delay(100000UL);
    }
}

Выполняем компиляцию программы командой

sdcc -mstm8 --std-c99 TST.c

При компиляции создается hex-файл TST.ihx:

:2080000082008083820000008200000082000000820000008200000082000000820000004D
:20802000820000008200000082000000820000008200000082000000820000008200000030
:20804000820000008200000082000000820000008200000082000000820000008200000010
:208060008200000082000000820000008200000082000000820000008200000082000000F0
:1D808300AE00002707724F00005A26F9AE00002709D68100D700005A26F7CC80807B
:03808000CC80C8E9
:2080A0005208160B17051E0D1F03160517011D00017B06A2006B067B05A2006B0516032626
:2080C000E7160126E35B0881AE5007F6AA20F7AE5005F6AA20F7AE5005F6AA20F74BA04B4F
:2080E000864B014B00CD80A05B04AE5005F6A4DFF74BA04B864B014B00CD80A05B0420D60F
:0181000081FD
:00000001FF

Прошивка

Для прошивки платы я приобрел на торговой площадке ebay программатор ST-LINK V2:
ST-LINK V2

Разъем программатора имеет 10 контактов:

Номер Название Назначение
1 RST сброс
2 SWIM SWIM-интерфейс (для STM8)
3 GND земля
4 3.3V + 3,3 В
5 5.0V + 5 В
6 SWCLK синхронизация (SWD-интерфейс, для STM32)
7 SWDIO данные (SWD-интерфейс, для STM32)
8 GND земля
9 3.3V + 3,3 В
10 5.0V + 5 В

Для подключения программатора к плате я использую 4 контакта на разъеме программатора и на плате - 3.3V(3V3), SWIM(SWM), GND, RST(NRST):
ST-LINK V2 контакты

При общении программатора с платой используется коммуникационный протокол SWIM (через однопроводной интерфейс - контакт SWIM).

Для прошивки я использую утилиту stm8flash, для запуска которой следует выполнить команду:

stm8flash -c stlinkv2 -p stm8s103f3 -w TST.hex (или TST.ihx)

Проект stm8flash размещен на GitHub: https://github.com/vdudouyt/stm8flash

Бинарная версия проекта для ОС Windows (можно взять здесь) содержит два необходимых файла:

stm8flash.exe - исполнимый файл
libusb-1.0.dll - библиотека для доступа к USB-устройствам

После запуска утилиты она выполняет прошивку программы в память и отчитывается о числе записанных байт:
прошивка STM8

После прошивки указанной выше программы мигания светодиодом он начинает мигать с периодом около шести секунд.

Я применил такую плату при создании акустического отпугивателя воробьев.

Полезные примеры кода

подключение заголовочных файлов

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

задержки

//константы для CLK #define CLK_DIVR (*(volatile uint8_t *)0x50c6)
...
static void delay(uint32_t t)
{
    while(t--) {}
}
...
delay(44000000UL); //задержка на одну минуту

работа с UART

//константы для CLK
#define CLK_DIVR    (*(volatile uint8_t *)0x50c6)
#define CLK_PCKENR1    (*(volatile uint8_t *)0x50c7)
//константы для UART
#define UART1_SR    (*(volatile uint8_t *)0x5230)
#define UART1_DR    (*(volatile uint8_t *)0x5231)
#define UART1_BRR1    (*(volatile uint8_t *)0x5232)
#define UART1_BRR2    (*(volatile uint8_t *)0x5233)
#define UART1_CR2    (*(volatile uint8_t *)0x5235)
#define UART1_CR3    (*(volatile uint8_t *)0x5236)
#define UART_CR2_TEN (1 << 3)
#define UART_CR3_STOP2 (1 << 5)
#define UART_CR3_STOP1 (1 << 4)
#define UART_SR_TXE (1 << 7)
...
void putchar(char c) //вывод символа в UART
{
    while(!(UART1_SR & UART_SR_TXE));
    UART1_DR = c;
}
...
CLK_DIVR = 0x00; //установка тактовой частоты 16 MГц
CLK_PCKENR1 = 0xFF; //включение периферии
UART1_CR2 = UART_CR2_TEN; //разрешение TX и RX
UART1_CR3 &= ~(UART_CR3_STOP1 | UART_CR3_STOP2); //1 стоп-бит
UART1_BRR2 = 0x03; UART1_BRR1 = 0x68; //9600 бод
...
printf("Hello,world!"); //вывод строки в UART

работа  с таймером

//регистры таймера
#define TIM1_CR1    (*(volatile uint8_t *)0x5250)
#define TIM1_IER    (*(volatile uint8_t *)0x5254)
#define TIM1_SR1    (*(volatile uint8_t *)0x5255)
#define TIM1_CNTRH    (*(volatile uint8_t *)0x525E)
#define TIM1_CNTRL    (*(volatile uint8_t *)0x525F)
#define TIM1_PSCRH    (*(volatile uint8_t *)0x5260)
#define TIM1_PSCRL    (*(volatile uint8_t *)0x5261)
...
TIM1_PSCRH = 0x09; //настройка предделителя таймера
TIM1_PSCRL = 0x89;
TIM1_CR1 = 0x01; //включение таймера
TIM1_IER = 0x01; //включение прерываний от таймера
__asm__ ("rim"); //включение прерываний
...
//обработчик прерываний таймера
void TIM1_overflow_Handler() __interrupt(11)
{
     TIM1_SR1 &= ~1; //сброс флага прерывания
     //выполнение требуемых действий
}

(1/16000000)*65536*предделитель = интервал в секундах
10 секунд = 2441 0x0989

работа с АЦП

typedef struct ADC1_struct
 {
  __IO uint8_t DB0RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB0RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB1RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB1RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB2RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB2RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB3RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB3RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB4RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB4RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB5RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB5RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB6RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB6RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB7RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB7RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB8RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB8RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  __IO uint8_t DB9RH;         /*!< ADC1 Data Buffer Register (MSB)  */
  __IO uint8_t DB9RL;         /*!< ADC1 Data Buffer Register (LSB)  */
  uint8_t RESERVED[12];       /*!< Reserved byte */
  __IO uint8_t CSR;           /*!< ADC1 control status register */
  __IO uint8_t CR1;           /*!< ADC1 configuration register 1 */
  __IO uint8_t CR2;           /*!< ADC1 configuration register 2 */
  __IO uint8_t CR3;           /*!< ADC1 configuration register 3  */
  __IO uint8_t DRH;           /*!< ADC1 Data high */
  __IO uint8_t DRL;           /*!< ADC1 Data low */
  __IO uint8_t TDRH;          /*!< ADC1 Schmitt trigger disable register high */
  __IO uint8_t TDRL;          /*!< ADC1 Schmitt trigger disable register low */
  __IO uint8_t HTRH;          /*!< ADC1 high threshold register High*/
  __IO uint8_t HTRL;          /*!< ADC1 high threshold register Low*/
  __IO uint8_t LTRH;          /*!< ADC1 low threshold register high */
  __IO uint8_t LTRL;          /*!< ADC1 low threshold register low */
  __IO uint8_t AWSRH;         /*!< ADC1 watchdog status register high */
  __IO uint8_t AWSRL;         /*!< ADC1 watchdog status register low */
  __IO uint8_t AWCRH;         /*!< ADC1 watchdog control register high */
  __IO uint8_t AWCRL;         /*!< ADC1 watchdog control register low */
 }
 ADC1_TypeDef;
#define ADC1_BaseAddress        0x53E0
#define ADC1 ((ADC1_TypeDef *) ADC1_BaseAddress)
...
//считывание данных из АЦП
unsigned int val=0;
ADC1->CSR |= ((0x0F)канал); //выбор канала
ADC1->CR2 |= (1<<3); //данные выравниваются справа
ADC1->CR1 |= (1<<0); //включение АЦП
ADC1->CR1 |= (1<<0); //запуск преобразования
while(((ADC1->CSR)&(1<<7))== 0); //ожидание завершения преобразования
val |= (unsigned int)ADC1->DRL;
val |= (unsigned int)ADC1->DRH<<8;
ADC1->CR1 &= ~(1<<0); //остановка преобразования
val &= 0x03ff; //результат

Необходимо задать номер канала АЦП, соответствующего используемому входу (например, вывод D2 - канал 3).

Напряжение можно определить умножением считанного из АЦП значения на VCC/1023, где VCC - напряжение питания на шине 3.3V.
Например, при подключении к входу 3.3V STM выхода 3.3V преобразователя USB-UART напряжение на нем составило 3,24 В. При этом масштабный коэффициент равен 3,24/1023 = 0,00317 В.

...

Продолжение следует

Яндекс.Метрика