Июн 032012
 

Мониторинг посещаемости сайта выявил – подавляющее большинство просмотров приходится на самые первые 2 статьи, в которых описан процесс создания и настройки проекта в среде IAR EWARM, и процедура настройки портов ввода-вывода данных. Во всех проектах, где не используются библиотечные функции, а инициализация периферии и рабочий код программы построены на работе напрямую с регистрами периферийных модулей, всегда в этих случаях подключается внешний файл с описанием периферии. Для серии STM32L это файл stm32l1xx.h, для микроконтроллеров STM32F10x это будет файл stm32f10x.h. Чтобы было понятно в дальнейшем, по какому принципу в тексте программы строятся команды, управляющие значениями регистров, и что это за непонятные наборы букв в них содержатся, пора бы познакомиться с этими файлами, подключаемыми к проекту. Что они содержат, и для чего служат – читайте ниже.

Структуру этих файлов будем рассматривать на примере заголовочного файла для серии STM32L – это файл stm32l1xx.h. Файл описания периферии stm32f10x.h для серии STM32F10x выполняет абсолютно те же функции и построен по тому же принципу, но структура периферийных модулей, внутренних регистров, карта памяти у этих серий имеют отличия, потому и разные файлы описания периферии, что вполне естественно. Вот поэтому и рассмотрим структуру файла только для серии L, дабы не распыляться и не плодить лишний текст, а постараться изложить покороче.

Внутри архивов с примерами проектов, которые можно загрузить на этом сайте, содержится библиотека STM32L1xx_StdPeriph_Lib версии 1.1.0. На данный момент на сайте STMicroelectronics доступна более новая версия 1.1.1. Какие изменения коснулись файла stm32l1xx.h, будет описано ниже. Но если вы используете отладочную плату STM32L-DISCOVERY, нет смысла переходить на более новую версию, вкратце я об этом писал в предыдущей статье STM32L. Библиотеки от STMicroelectronics. Итак, начнем рассмотрение данного файла.

В самом начале его находятся такие строки

#ifndef __STM32L1XX_H #define __STM32L1XX_H


Подобные строки, по-моему, встречаются в самом начале всех заголовочных файлов с расширением .h. Это защита от многократного подключения одного и того же файла. Файлов, подключенных к проекту, может быть великое множество, и файл stm32l1xx.h может быть подключен в качестве внешнего сразу в нескольких из них. А подобная конструкция как раз и проверяет, был ли уже подключен данный файл к проекту или еще нет. Далее идут строки

#ifdef __cplusplus extern "C" { #endif 

Это для использования функций, написанных на разных языках программирования (C и C++), для их корректной работы.

Далее в файле последней версии идут такие строки

#if !defined (STM32L1XX_MD) && !defined (STM32L1XX_MDP) && !defined (STM32L1XX_HD) 
  /* #define STM32L1XX_MD */ /*!< STM32L1XX_MD: STM32L Ultra Low Power Medium-density devices */ 
  /* #define STM32L1XX_MDP */ /*!< STM32L1XX_MDP: STM32L Ultra Low Power Medium-density Plus devices */ 
#define STM32L1XX_HD /*!< STM32L1XX_HD: STM32L Ultra Low Power High-density devices */ 
#endif

Здесь надо оставить не закомментированной только одну строку. Именно ту, что соответствует типу вашего микроконтроллера. А типов этих для серии STM32L в данных строках (и на данный момент) предполагается 3:

  • Medium-density devices. Устройства с объемом флэш-памяти от 64 КБайт до 128 КБайт
  • Medium-density Plus devices. Устройства с объемом флэш-памяти 256 КБайт
  • High-density devices. Устройства с объемом флэш-памяти 384 КБайт

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

Эти же строки в предыдущей версии библиотек (именно они используются в предыдущих примерах проектов на этом сайте) выглядят по другому

#if !defined (STM32L1XX_MD)
 #define STM32L1XX_MD /*!< STM32L1XX_MD: STM32L Ultra Low Power Medium-density devices */ 
#endif

Здесь еще никакого выбора производить не требовалось, подразумевалось, что работа будет только с одним типом: MD — Medium-density devices. Какую версию библиотек использовать – выбор за вами. Опять же замечу, что если у вас отладочная плата STM32L-DISCOVERY, то нет смысла переходить на новую версию библиотек, как видите обновление тут произошло в связи появлением новых типов МК. А предыдущая версия “заточена” только под устройства Medium-density, именно к ним и относится STM32L152RBT6, размещенный на данной плате.

Назначение следующих строк – выдача ошибки, если ни один из типов микроконтроллеров не выбран (случайно оказались закомментированы все строки выбора, например)

#if !defined (STM32L1XX_MD) && !defined (STM32L1XX_MDP) && !defined (STM32L1XX_HD)
 #error "Please select first the target STM32L1xx device used in your application (in stm32l1xx.h file)" 
#endif


В предыдущей версии файла эти строки, естественно, проверяют выбор только одного типа

#if !defined (STM32L1XX_MD)
 #error "Please select first the target STM32L1xx device used in your application (in stm32l1xx.h file)" 
#endif


Далее уже будем рассматривать структуру этого файла, не акцентируя на версии. В общих чертах, там уже все одинаково, отличия только в деталях — регистрах и адресах, как уже было сказано. В следующих строках проверяется был ли ранее задан макрос USE_STDPERIPH_DRIVER. С этого места разберем подробней.

#if !defined  USE_STDPERIPH_DRIVER
/**
 * @brief Comment the line below if you will not use the peripherals drivers.
   In this case, these drivers will not be included and the application code will 
   be based on direct access to peripherals registers 
   */
  /*#define USE_STDPERIPH_DRIVER*/
#endif


Как видим, в исходном варианте, в этих строках абсолютно никаких действий пока не выполняется. Здесь проверяется есть ли данное макроопределение. И если нет, то должно объявиться, но строка объявления макроса изначально закомментирована

/*#define USE_STDPERIPH_DRIVER*/

Почему выполняется проверка? Опять же из-за того, что можно это прописать и в настройках проекта, там же в секции C/C++ Compiler->Preprocessor в поле Defined symbols вписав USE_STDPERIPH_DRIVER (каждое такое макроопределение там необходимо вписывать в отдельной строке). Для использования данного макроса можно также убрать символы комментария у данной строки в рассматриваемом файле. Что это дает? А вариант этот предусмотрен на случай использования файлов-драйверов периферии. Это такие же заголовочные файлы с расширением .h (хедеры), но используемые только при работе с определенным периферийным устройством (например, stm32l1xx_adc.h – АЦП, stm32l1xx_gpio.h – порты ввода-вывода и т.д.). Работают эти файлы в связке с другими библиотечными файлами с расширением .c, в которых написаны готовые функции на языке С для работы с конкретной периферией (stm32l1xx_adc.c – АЦП, stm32l1xx_gpio.c – порты ввода-вывода и т.д.). В связке эти файлы работают так, в файле .c готовые функции для управления периферией, в соответствующих файлах .h при помощи макроопределений #define задаются параметры, подставляемые в функцию и т.п., а также сделаны предварительные объявления этих функций для компилятора.

Так вот, если присутствует макрос USE_STDPERIPH_DRIVER, происходит следующее. Теперь надо перейти уже в самый конец рассматриваемого файла stm32l1xx.h к строкам

#ifdef USE_STDPERIPH_DRIVER #include "stm32l1xx_conf.h" #endif


которые означают, что если это макрос используется (то есть мы хотим использовать файлы драйверов периферии), то подключается еще один внешний файл stm32l1xx_conf.h. А в этом файле как раз происходит подключение всех остальных внешних заголовочных файлов для периферии, сразу всех до кучи.

#include "stm32l1xx_adc.h"
#include "stm32l1xx_crc.h"
#include "stm32l1xx_comp.h"
#include "stm32l1xx_dac.h"
#include "stm32l1xx_dbgmcu.h"
#include "stm32l1xx_dma.h"
#include "stm32l1xx_exti.h"
#include "stm32l1xx_flash.h"
#include "stm32l1xx_gpio.h"
#include "stm32l1xx_syscfg.h"
#include "stm32l1xx_i2c.h"
#include "stm32l1xx_iwdg.h"
#include "stm32l1xx_lcd.h"
#include "stm32l1xx_pwr.h"
#include "stm32l1xx_rcc.h"
#include "stm32l1xx_rtc.h"
#include "stm32l1xx_spi.h"
#include "stm32l1xx_tim.h"
#include "stm32l1xx_usart.h"
#include "stm32l1xx_wwdg.h"
#include "misc.h"

Можно закомментировать строки с подключением ненужных заголовочных файлов, можно пойти другим путем — не используя макрос USE_STDPERIPH_DRIVER, добавлять нужные файлы в проект по отдельности с помощью инструкций #include.

Если же использование готовых библиотечных функций не планируется, а будет работа напрямую с регистрами (что ускорит доступ к ним), то использовать этот макрос для подключения заголовочных файлов периферии нет смысла, в большинстве случаев все необходимое есть в рассматриваемом файле stm32l1xx.h. Вернемся снова к этому файлу и посмотрим что там идет дальше. А далее там заданы макроопределения для частот всех возможных используемых генераторов и времени ожидания для их гарантированного запуска такого вида.

#if !defined  (HSE_VALUE)
#define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif

/**
 * @brief In the following line adjust the External High Speed oscillator (HSE) Startup 
   Timeout value 
   */
#if !defined  (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500) /*!< Time out for HSE start up */
#endif

/**
 * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup 
   Timeout value 
   */
#if !defined  (HSI_STARTUP_TIMEOUT)
#define HSI_STARTUP_TIMEOUT   ((uint16_t)0x0500) /*!< Time out for HSI start up */
#endif

#if !defined  (HSI_VALUE)
#define HSI_VALUE  ((uint32_t)16000000) /*!< Value of the Internal High Speed oscillator in Hz.
                                             The real value may vary depending on the variations
                                             in voltage and temperature.  */
#endif

#if !defined  (LSI_VALUE)
#define LSI_VALUE  ((uint32_t)37000)    /*!< Value of the Internal Low Speed oscillator in Hz
                                             The real value may vary depending on the variations
                                             in voltage and temperature.  */
#endif

#if !defined  (LSE_VALUE)
#define LSE_VALUE  ((uint32_t)32768)    /*!< Value of the External Low Speed oscillator in Hz */
#endif


Версии библиотек

#define __STM32L1XX_STDPERIPH_VERSION_MAIN   (0x01) /*!< [31:24] main version */
#define __STM32L1XX_STDPERIPH_VERSION_SUB1   (0x01) /*!< [23:16] sub1 version */
#define __STM32L1XX_STDPERIPH_VERSION_SUB2   (0x01) /*!< [15:8]  sub2 version */
#define __STM32L1XX_STDPERIPH_VERSION_RC     (0x00) /*!< [7:0]  release candidate */ 
#define __STM32L1XX_STDPERIPH_VERSION       ( (__STM32L1XX_STDPERIPH_VERSION_MAIN << 24)
                                             |(__STM32L1XX_STDPERIPH_VERSION_SUB1 << 16)
                                             |(__STM32L1XX_STDPERIPH_VERSION_SUB2 << 8)
                                             |(__STM32L1XX_STDPERIPH_VERSION_RC))


В этой секции задана структура векторов прерываний

/*!< Interrupt Number Definition */
typedef enum IRQn
{
/******  Cortex-M3 Processor Exceptions Numbers ******************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt                 */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                         */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                       */
  SVC_IRQn                    = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                          */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                    */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                          */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                      */

/******  STM32L specific Interrupt Numbers ***********************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                               */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt               */
  TAMPER_STAMP_IRQn           = 2,      /*!< Tamper and Time Stamp through EXTI Line Interrupts      */
  RTC_WKUP_IRQn               = 3,      /*!< RTC Wakeup Timer through EXTI Line Interrupt            */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                                  */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                    */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                    */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                    */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                    */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                    */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt 
... 
... 
...


Ниже можно найти такие строки

typedef struct
{
  __IO uint32_t SR;           /*!< ADC status register,                         Address offset: 0x00 */
  __IO uint32_t CR1;          /*!< ADC control register 1,                      Address offset: 0x04 */
  __IO uint32_t CR2;          /*!< ADC control register 2,                      Address offset: 0x08 */
  __IO uint32_t SMPR1;        /*!< ADC sample time register 1,                  Address offset: 0x0C */
  __IO uint32_t SMPR2;        /*!< ADC sample time register 2,                  Address offset: 0x10 */
  __IO uint32_t SMPR3;        /*!< ADC sample time register 3,                  Address offset: 0x14 */
  __IO uint32_t JOFR1;        /*!< ADC injected channel data offset register 1, Address offset: 0x18 */
  __IO uint32_t JOFR2;        /*!< ADC injected channel data offset register 2, Address offset: 0x1C */
  __IO uint32_t JOFR3;        /*!< ADC injected channel data offset register 3, Address offset: 0x20 */
  __IO uint32_t JOFR4;        /*!< ADC injected channel data offset register 4, Address offset: 0x24 */
  __IO uint32_t HTR;          /*!< ADC watchdog higher threshold register,      Address offset: 0x28 */
  __IO uint32_t LTR;          /*!< ADC watchdog lower threshold register,       Address offset: 0x2C */
  __IO uint32_t SQR1;         /*!< ADC regular sequence register 1,             Address offset: 0x30 */
  __IO uint32_t SQR2;         /*!< ADC regular sequence register 2,             Address offset: 0x34 */
  __IO uint32_t SQR3;         /*!< ADC regular sequence register 3,             Address offset: 0x38 */
  __IO uint32_t SQR4;         /*!< ADC regular sequence register 4,             Address offset: 0x3C */
  __IO uint32_t SQR5;         /*!< ADC regular sequence register 5,             Address offset: 0x40 */
  __IO uint32_t JSQR;         /*!< ADC injected sequence register,              Address offset: 0x44 */
  __IO uint32_t JDR1;         /*!< ADC injected data register 1,                Address offset: 0x48 */
  __IO uint32_t JDR2;         /*!< ADC injected data register 2,                Address offset: 0x4C */
  __IO uint32_t JDR3;         /*!< ADC injected data register 3,                Address offset: 0x50 */
  __IO uint32_t JDR4;         /*!< ADC injected data register 4,                Address offset: 0x54 */
  __IO uint32_t DR;           /*!< ADC regular data register,                   Address offset: 0x58 */
  __IO uint32_t SMPR0;        /*!< ADC sample time register 0,                  Address offset: 0x5C */
} ADC_TypeDef;

Здесь создается структура регистров аналого-цифрового преобразователя ADC пока без привязки к конкретным адресам. Элементы структуры – это регистры АЦП. В структуре определены их символические имена SR, CR1 и т.д., которые будут использоваться в дальнейшем при написании программы, размерность — uint32_t, и тип разрешенного доступа __IO — “чтение/запись”. Таким образом созданы структуры для всех регистров каждого периферийного модуля. Символические имена элементов в каждой структуре расположены именно в том порядке, в каком располагаются физические адреса соответствующих регистров в области памяти, выделенной под данный периферийный модуль.

После описания структур всех периферийных модулей начинается создание их базовых адресов. Вначале задаются адреса самых основных регионов памяти: SRAM, FLAH и области периферии.

#define FLASH_BASE            ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
#define SRAM_BASE             ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

С памятью SRAM и FLASH все понятно, далее начинается “дробление” памяти периферии на базовые адреса периферийных модулей. Начинается все снова с “крупных модулей” – это домены шин тактирования AHB, APB1, APB2.

#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

А теперь уже происходит размещение базовых адресов всех периферийных модулей . Берется базовый адрес, например APB1PERIPH_BASE, а к нему прибавляется смещение.

#define TIM2_BASE             (APB1PERIPH_BASE + 0x0000)
#define TIM3_BASE             (APB1PERIPH_BASE + 0x0400)
#define TIM4_BASE             (APB1PERIPH_BASE + 0x0800)
#define TIM5_BASE             (APB1PERIPH_BASE + 0x0C00)
#define TIM6_BASE             (APB1PERIPH_BASE + 0x1000)
#define TIM7_BASE             (APB1PERIPH_BASE + 0x1400)
#define LCD_BASE              (APB1PERIPH_BASE + 0x2400)
#define RTC_BASE              (APB1PERIPH_BASE + 0x2800)
... 
... 
... 
и т.д.

Таким образом, создаются начальные адреса для каждого периферийного модуля, прибавлением смещения адреса относительно начальных адресов доменов AHB, APB1, APB2. А начальные адреса этих более крупных доменов заданы соответственно прибавлением смещения относительно начального адреса всей периферии PERIPH_BASE (0x40000000).

Когда все начальные адреса периферийных модулей сформированы, начинается привязка их к ранее созданным структурам модулей, где элементами структур являются внутренние регистры периферии.

Делается это с помощью создания указателей на эти структуры с присвоением им значений начальных адресов периферийных модулей.

#define TIM2                ((TIM_TypeDef *) TIM2_BASE)
#define TIM3                ((TIM_TypeDef *) TIM3_BASE)
#define TIM4                ((TIM_TypeDef *) TIM4_BASE)
#define TIM5                ((TIM_TypeDef *) TIM5_BASE)
#define TIM6                ((TIM_TypeDef *) TIM6_BASE)
#define TIM7                ((TIM_TypeDef *) TIM7_BASE)
#define LCD                 ((LCD_TypeDef *) LCD_BASE)
#define RTC                 ((RTC_TypeDef *) RTC_BASE) 
... 
...

А поскольку размерность и порядок расположения элементов структур (регистров) уже заданы ранее, то и они теперь получаются жестко привязанными к конкретным физическим адресам памяти.

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

GPIOB->MODER |= GPIO_MODER_MODER7_0;


можно понять, что в левой ее части происходит обращение к регистру MODER порта B по указателю, созданному в подключаемом файле stm32l1xx.h. Здесь производится операция ЛОГИЧЕСКОЕ ИЛИ содержимого регистра и значения из правой части выражения, т.е. установка нужных разрядов. А разряды эти заданы единичными значениями в разрядах битовой маски GPIO_MODER_MODER7_0.

#define GPIO_MODER_MODER7_0 ((uint32_t)0x00004000)


Все эти битовые маски для регистров размещены далее в файле stm32l1xx.h. С их помощью в регистрах устанавливаются или сбрасываются нужные биты, достаточно разобраться какие именно необходимы и выбрать подходящую маску в секции нужного регистра. Масок этих очень много, для каждого регистра заданы практически все возможные варианты, многие из них снабжены подробными комментариями. Вот, например, как в секции для системы тактирования RCC заданы битовые маски регистра управления RCC_CR

/******************************************************************************/
/*                                                                            */
/*                      Reset and Clock Control (RCC)                         */
/*                                                                            */
/******************************************************************************/
/********************  Bit definition for RCC_CR register  ********************/
#define  RCC_CR_HSION                        ((uint32_t)0x00000001)        /*!< Internal High Speed clock enable */
#define  RCC_CR_HSIRDY                       ((uint32_t)0x00000002)        /*!< Internal High Speed clock ready flag */

#define  RCC_CR_MSION                        ((uint32_t)0x00000100)        /*!< Internal Multi Speed clock enable */
#define  RCC_CR_MSIRDY                       ((uint32_t)0x00000200)        /*!< Internal Multi Speed clock ready flag */

#define  RCC_CR_HSEON                        ((uint32_t)0x00010000)        /*!< External High Speed clock enable */
#define  RCC_CR_HSERDY                       ((uint32_t)0x00020000)        /*!< External High Speed clock ready flag */
#define  RCC_CR_HSEBYP                       ((uint32_t)0x00040000)        /*!< External High Speed clock Bypass */

#define  RCC_CR_PLLON                        ((uint32_t)0x01000000)        /*!< PLL enable */
#define  RCC_CR_PLLRDY                       ((uint32_t)0x02000000)        /*!< PLL clock ready flag */
#define  RCC_CR_CSSON                        ((uint32_t)0x10000000)        /*!< Clock Security System enable */

#define  RCC_CR_RTCPRE                       ((uint32_t)0x60000000)        /*!< RTC/LCD Prescaler */
#define  RCC_CR_RTCPRE_0                     ((uint32_t)0x20000000)        /*!< Bit0 */
#define  RCC_CR_RTCPRE_1                     ((uint32_t)0x40000000)        /*!< Bit1 */

Если теперь снова взглянуть на инструкцию,

GPIOB->MODER |= GPIO_MODER_MODER7_0;

можно понять – вывод 7 порта B настроен в качестве выхода.

После всех этих битовых масок, которые занимают не менее половины всего файла (регистров и возможных режимов много), в самом конце заданы еще несколько макросов

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))

#define READ_BIT(REG, BIT)    ((REG) & (BIT))

#define CLEAR_REG(REG)        ((REG) = (0x0))

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

#define READ_REG(REG)         ((REG))

#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

Как видно, они также задают различные варианты операций с содержимым регистров.

Другие статьи:

  12 Responses to “STM32. Файлы stm32l1xx.h и stm32f10x.h из библиотек Standard Peripherals Library”

  1. Здравствуйте!! Хотелось бы про UART что ни будь увидеть))

  2. Не подскажите в чем неладное. Пытался в IAR запустить стандартные функции инициализации типа GPIO_Init(); и другие. Не работают пишет ошибка файл не найден «Error[Li005]: no definition for «GPIO_Init» [referenced from C:\Project\Led\Debug\Obj\main.o » а структуру функций видит, файл «stm32l1xx_gpio.h» подлючил. В чем может быть проблема?

  3. Файл stm32l1xx_gpio.c подключен к проекту? В опциях проекта, в разделе C/C++ Compiler -> Preprocessor надо добавить еще путь к файлам библиотек
    $PROJ_DIR$\..\Libraries\STM32L1xx_StdPeriph_Driver\src\
    Если изменения вносятся в пример проекта мигания светодиодом, как я понял.
    В файле stm32l1xx_gpio.c находятся сами функции, а в stm32l1xx_gpio.h только их объявления.

  4. Да путь к файлам библиотек указан. Подключил stm32l1xx_gpio.c к проекту теперь новая ошибка Error[Li005]: no definition for «assert_param» нашел её описание в библиотеке «stm32l1xx_conf.h» но не получается ее прикрутить.

  5. Ураааа!!!! Всё заработало! Надо было в библиотеке «stm32l1xx.h» убрать комментировать со строчки #define USE_STDPERIPH_DRIVER ))) Спасибо за помощь!!!!!

    • Ну да, можно и в свойствах проекта указать, чтобы библиотечные файлы не изменять. Там же в свойствах проекта C/C++ Compiler -> Preprocessor можно добавить строку USE_STDPERIPH_DRIVER в поле Defined simbols. В какой-то из статей в комментариях этот вопрос обсуждали.

  6. Здравствуйте.
    Уже долго мучаюсь над созданием make-файлика для простейшего проекта. Вроде как подключил все необходимые разделы, но всеравно идут ошибки..
    Вот вывод:
    main.c: In function ‘main’:
    main.c:78:33: error: ‘GPIO_PIN_X’ undeclared (first use in this function)
    main.c:78:33: note: each undeclared identifier is reported only once for each function it appears in
    main.c:78:46: error: ‘GPIO_PIN_Y’ undeclared (first use in this function)
    main.c:93:20: error: ‘BSRR_VAL’ undeclared (first use in this function)
    make: *** [main.o] Error 1