Stm32f1, Keil-RTOS, STANDBY.

Исключительно для себя. Выложу и оставлю здесь. Плата — stm32discovery. Запускается, работает (LCD — показывает, ADC — меряет, DAC — выдает), засыпает, просыпается, работает… USER BUTTON (PA0) включает или отключает засыпание.


#include "stm32f10x.h"

#include "stdio.h"
#include "string.h"

#include "rtl.h"

uint8_t StandByAvailable = 1;

OS_TID t_LIFE_LED;
OS_TID t_STANDBY;

void RCC_Configuration (void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure); 
}

void EXTI0_IRQHandler(void)
{
    EXTI_ClearITPendingBit(EXTI_Line0);
	
    StandByAvailable = (StandByAvailable ^ 1);
}

void RTC_Configuration (void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    PWR_BackupAccessCmd(ENABLE);
	
    if(PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
    {
        PWR_ClearFlag(PWR_FLAG_SB);
        RTC_WaitForSynchro();
    }

    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
        BKP_DeInit();
        RCC_LSEConfig(RCC_LSE_ON);
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {};
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
        RCC_RTCCLKCmd(ENABLE);
        RTC_WaitForSynchro();
        RTC_WaitForLastTask();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        RTC_SetPrescaler(32767);
        RTC_WaitForLastTask();
        RTC_SetCounter((12*3600 + 13*60 + 14));
        RTC_WaitForLastTask();
        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    }
    else
    {
        RTC_WaitForSynchro();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
    }
}

void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
    RTC_ClearITPendingBit(RTC_IT_SEC);
    RTC_WaitForLastTask();

    if (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_9))
    {
        GPIOC->BRR = GPIO_Pin_9;
    }
    else
    {
        GPIOC->BSRR = GPIO_Pin_9;
    }
  }
}

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);
}

__task void f_LIFE_LED (void)
{
   while (1)
   {
    if (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_8))
    {
        GPIOC->BRR = GPIO_Pin_8;
    }
    else
    {
        GPIOC->BSRR = GPIO_Pin_8;
    }
    os_dly_wait (100);
   }
}

__task void f_STANDBY (void)
{
   os_itv_set (500);

   while (1)
   {
        os_itv_wait ();
        if (StandByAvailable)
        {
            RTC_SetAlarm(RTC_GetCounter()+ 5);
            RTC_WaitForLastTask();
            PWR_EnterSTANDBYMode();
        }
   }
}

__task void init (void)
{
    os_tsk_prio_self (100);

    t_LIFE_LED = os_tsk_create (f_LIFE_LED, 1);
    t_STANDBY = os_tsk_create (f_STANDBY, 1);
        
    os_tsk_delete_self ();
}


int main (void)
{
    SystemInit ();

    RTC_Configuration ();
    RCC_Configuration ();
    NVIC_Configuration();

    os_sys_init(init);
}

  • +2
  • 11 апреля 2013, 22:11
  • lexanet

Комментарии (21)

RSS свернуть / развернуть
Это конечно не мое дело, но Вы используете и библиотеку STM (Standard Peripherals Library) например GPIO_InitTypeDef GPIO_InitStructure; и управление выводом порта напрямую — GPIOC->BRR = GPIO_Pin_8;

Не запутывает? не лучше использовать или библиотеку Standard Peripherals Library или писать без нее как например тут: we.easyelectronics.ru/STM32/primery-inicializacii-periferii-stm32f103-bez-ispolzovaniya-bibliotek.html
0
  • avatar
  • Nemo
  • 12 апреля 2013, 11:07
А зачем работать с GPIO через SPL, кроме как для инита, если напрямую с регистром работать проще и оптимальней?
0
+1 мне тоже такой подход (игициализация через SPL + работа напрямую) видится допустимым. Если автору он удобнее, то SPL не догма.
0
Ну, будь тут не SPL, а нечто более достойное названия HAL — это таки было бы недопустимо. Но с SPL без разницы, да.
0
нечто более достойное названия HAL
А что достойно названия HAL?

Смотрел аналогичные библиотеки периферии для LM4F, EFM32, Milandr, nuvoton — все они сделаны по одному принципу:
— Определить пространство имен различных констант для периферии;
— Опеределить кучу примитивных функций(API, Driver), в которых даже и алгоритмов, как таковых, обычно нет;

Как я понимаю, это и есть HAL периферии MCU, каким бы скучным и унылым он не казался.
0
А что достойно названия HAL?
libmaple, libstm32pp, например.
Как я понимаю, это и есть HAL периферии MCU, каким бы скучным и унылым он не казался.
Нет. Ключевое слово в любой библиотеке, а уж тем более в HAL — абстракция. Подобные «HAL»-ы как раз именно этого и не предоставляют.
+1
wiring во множестве вариантов (включая мапле), PL кокоса, кодбейз neiver'а. То, что абстрагирует от конкретной периферии и позволяет перетащить код на другой камень не меняя кода работы с периферией. В идеале — сменил в компиляторе таргет с STM32F103 на PIC24Fxxx и все скомпилилось и работает.
0
Производители чипов разрабатывая библиотеки периферии как раз и представляют пользователю Hardware Abstraction Layer для СВОИХ семейств чипов в виде пр-ва глобальных имен для всего внутри периферии и API в виде большого набора атомарных функций, суть которых просто инициализация, последовательный сброс/установка неких битов, чтение/запись регистров и т.п. Видимо их пишут не программеры, а системотехники, которые тестируют чип, т.е. некий пример правильной манипуляции битами и с учетом errata.

Ни о каком HAL, в смысле ГЛОБАЛЬНОЙ переносимости, они и не думают — а зачем, собственно, им это надо? Кроме того, на что они должны ориентироватся, даже если и захотят этого, есть какие-то общие стандарты?

Этот самый HAL можно явно локализовать в библиотеках GUI и TCP/IP — есть алгоритмы реализации самой задачи вне зависимости от железа и есть API интерфейс для работы с модулем(драйвером) самого железа.

Специально посчитал кол-во этих атомарных функций в модуле ADC в различных библиотеках:

— 45 — Milandr MDR32F9x(1986BE9x) Standard Peripheral Driver
— 42 — CooCox CoX Peripheral Library (вариант для STM32F1)
— 36 — STMicro STM32F1 Standard Peripheral Library
— 33 — TI LM4F Stellaris Ware
— 8!!! — Energy Micro EFM32 Peripheral Library
0
Какой это к черту HAL, если
1) Он ни от чего не абстрагирует. Те же яйца, только в профиль.
2) Отсутствует совместимость, AFAIK, даже между разными семействами STM32, не говоря уж о общем API для STM8 и STM32. Конечно, глупо требовать, чтобы библиотека от ST поддерживала конкурентские камни, но эта и свои-то не поддерживает.
Это так, обертка, а не HAL.
0
Если HAL расшифровывал не как принято (hardware abstraction layer), а как hardware access layer то вот вам и возможность применения громгого сокращения на свой недоработанный продукт.
Одно, что китайские GB, оказывающиемя гигабитами — а всё по правилам, от 2-х сокращаемых слов оставляется буква в верхнем регистре.
+1
Посмотрел CoX Peripheral Library, при всем уважении к CooCox, не впечатлило заявленным ГЛОБАЛЬНЫМ целям:
— Мизерная поддержка чипов — только stm32f1, nuvoton(Cortex-M0) и freescale Kinetis KLx (Cortex-M0+);
— Нет поддержки stm32f0/f2/f3/f4, EFM32, TI LM3/LMF4F, NXP LPC;
— Почему-то для каждого производителя своя отдельная упаковка ГЛОБАЛЬНОЙ библиотеки ???;
— Похоже они и сами забили на нее;
0
По крайней мере, при всех его недостатках — это HAL, а не обертка. По крайней мере насколько я его изучал.
— Почему-то для каждого производителя своя отдельная упаковка ГЛОБАЛЬНОЙ библиотеки ???;
Если я правильно понял о чем ты — для HAL это нормально, он сильно зависит от железа. Требуется только общий апи для всех платформ.
0
Это библиотека периферии, и она даже близко не HAL, поддерживаю Vga.

GUI и TCP/IP тоже сложно отнести к HAL, так как это набор алгоритмов, не зависящий уже сам по себе от железа. TCP/IP шке, например, нужны функции приёма и отправки пакетов и всё. Как там настраивается MAC, на какой физике собрано всё это — плевать. Вафля ли, эзернет, блютус, гпрс, модем или ещё что-нибудь. Если оно умеет отправлять и принимать пакеты — оно подходит.
То же самое и Гуи. Ему нужна видеопамять и знание о формате хранения данных в ней. Ну или команд ей оперирующих. Как оно будет выводиться — по эзернету ли, в файл или прямо на экран, коих тоже миллион типов — не её ума дело. Этим займётся соответствующий драйвер.
Хотя, конечно, для простоты эти библиотеки могут быть построены над драйверами соответствующими. Хотя это странно и неудобно.

Вы путаете HAL с чем-то другим. HAL — это как раз прослойка между реальным железом и всем остальным. Такая, чтоб всему остальному было абсолютно пофиг, какое там железо и какими силами управляется. И она сама как раз зависима от железа.
+2
HAL — это как раз прослойка между реальным железом и всем остальным.
Именно: эти библиотеки и есть не более, чем API прослойка между реальным железом и всем остальным.

Про GUI и TCP/IP, как это выглядит на MCU, почитайте здесь lifelover-а про TCP/IP стек для MCU и Ethernet-чипа и вот это про GUI. В обоих случаях можно увидеть отдельный модуль(драйвер), набор функций(API) для работы с конкретным хардвеа, которые и являются прослойкой между хардвэа и основным софтом.
0
Это всего лишь обёртки над периферией, не более того. Они привязаны к железу и к конкретной серии контроллеров. Типа макросов. Это — не абстракция. Точнее, абстракция, но не того уровня, который нужен для гордого звания HAL. Чуть более человекопонятный (кому как) доступ к регистрам.

А тут работу с GPIO не перенесёшь даже с stm32f4xx серии на stm32f1xx и обратно, потому что периферия жесть как отличается, как и библиотека. Что уж тут говорить о совместимости с другими контроллерами и абстракции.

Я знаю, как это выглядит на MCU, я писал и сетевые, и графические (хоть их и немного было) приложения. Библиотека работает с абстрактным оборудованием вообще-то (как вы сказали, через API), которое реализуется совершенно отдельно в драйвере. Этот отдельный драйвер (только он) и будет как раз HAL над сетевым интерфейсом. Как раз потому, что его интерфейс унифицирован. Сами библиотеки подобного плана в состав HAL не входят.
+2
Обертки конечно же, и это хорошо и правильно.

ИМХО, их и надо по возможности юзать, поскольку: это готовое, это от самого производителя, это с учетом errata.

Кроме того, можно взяв 2 такие библиотеки для разных чипов обернуть их сверху еще одной уже своей API оберткой с макросами и написать ПО уже с вызовами своей обертки — видимо только так можно сделать переносимый код самым простым и правильным способом, т.е. без кульбитов над поверхностью 2-х даташитов и переписывания уже готового в библиотеках кода.
0
Насчёт того, нужны они или нет, хорошие или плохие, я и не спорил Оо Да, они есть, чтобы дать полный доступ ко всем возможностям периферии без ограничений. Это их цель =)

Да, поверх можно написать свой код. Я так и делаю. Хотя, для простых драйверов (с минимальными возможностями, типа дёргания ножками через gpio) можно и без библиотеки обойтись.
0
Сравним с ADC для LeafLabs MapleLib:
pinMode(Pin3, INPUT_ANALOG);
val = analogRead(Pin3);

Все собственно — 2 функции…
Ну на самом деле, во многих случаях это просто не серьезно.
0
Да собственно автор и работает с SPL, т.к. определение GPIO_Pin_8 сугубо SPLовское :)
0
Это все пережитки трудного начала :) Я когда только перешел на ARM, к своему стыду, не сумел подружиться с SPL. Я не знал КАК прикрутить ее к проекту. Поэтому, обложившись распечатками референс мануала и вооружившись инженерным калькулятором рассчитывал нулики и единички и пихал их в регистры. Счас то я сдружился с SPL и сполна оценил ее удобство по инициализации различной переферии. Даже RM можно не открывать. Но, дальнейшая работа, все таки удобнее «напрямую». Компактнее и наглядней получается.
0
Есть такая украинская поговорка: «Хто як хоче так и дроче». Почему-то базовые функции работы с портами в SPL довольно неудобны.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.