Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как я накололся с stm32f10x.h
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
ViKo
Cоздаю свои SystemInit функции (как и все остальные, по мере понимания). Очередная - не работает! Процессор вылетает неизвестно куда, в фаулты, даже до обработчика HardFault не добирается! В Кейле, в отладчике, на реальной плате вижу.
Хотя предыдущая функция (в том же файле была, повезло) - работает. Ищу отличия - не нахожу! Смотрю в отладчике - все биты RCC одинаковые.
Там с десяток выражений, что только не сравниваю, заменяю, комментирую - везде одинаково. Добрался до латентности. В нерабочей:
Код
/* Задать использовать буфер предвыборки Flash, 2 цикла ожидания */
    FLASH->ACR =
    FLASH_ACR_LATENCY_0 * 2 |  // LATENCY[2:0] bits (Latency)
    FLASH_ACR_HLFCYA    * 0 |      // Flash Half Cycle Access Enable
    FLASH_ACR_PRFTBE    * 1;      // Prefetch Buffer Enable

В рабочей:
Код
/* Задать использовать буфер предвыборки Flash и 2 цикла ожидания
   (half cycle access can only be used with a low-frequency clock of less than 8 MHz
   that can be obtained with the use of HSI or HSE but not of PLL) */
  FLASH->ACR = FLASH_ACR_PRFTBE
             | FLASH_ACR_LATENCY_1;    // 2 WS

Смотрю в stm32f10x.h. А там биты заданы так:
Код
#define  FLASH_ACR_LATENCY                   ((uint8_t)0x03)               /*!< LATENCY[2:0] bits (Latency) */
#define  FLASH_ACR_LATENCY_0                 ((uint8_t)0x00)               /*!< Bit 0 */
#define  FLASH_ACR_LATENCY_1                 ((uint8_t)0x01)               /*!< Bit 0 */
#define  FLASH_ACR_LATENCY_2                 ((uint8_t)0x02)

То есть, не так, как везде, описываются именно биты, как, например:
Код
#define  RCC_CFGR_PLLMULL_0                  ((uint32_t)0x00040000)

а состояния латентности.
В результате, латентность у меня не устанавливалась, доступ к памяти сбоил. Когда задал
Код
    FLASH->ACR =
    FLASH_ACR_LATENCY_2 |    // LATENCY[2:0] bits (Latency)
    FLASH_ACR_HLFCYA    * 0 |    // Flash Half Cycle Access Enable
    FLASH_ACR_PRFTBE    * 1;    // Prefetch Buffer Enable

все заработало.
Что интересно, и вторая функция была с неправильной установкой латентности = 1, но, тем не менее каким-то чудом работала. На 72 MHz, STM32F103.
Уже чешутся руки взяться за правку stm32f10x.h, но боюсь запутаться между проектами.
SII
Так здесь же уже не отдельные биты, а целое битовое поле (из двух битов). Маска поля -- FLASH_ACR_LATENCY, а остальные три константы -- это его возможные значения для разных случаев жизни (латентностей). ИМХО, тут Вы зря ожидали каких-то "битов", поскольку их тут быть и не должно. Для интереса посмотрите какие-нибудь другие константы, касающиеся полей, а не отдельных битов.
ViKo
Цитата(SII @ Feb 9 2014, 14:21) *
Так здесь же уже не отдельные биты, а целое битовое поле (из двух битов). Маска поля -- FLASH_ACR_LATENCY, а остальные три константы -- это его возможные значения для разных случаев жизни (латентностей). ИМХО, тут Вы зря ожидали каких-то "битов", поскольку их тут быть и не должно. Для интереса посмотрите какие-нибудь другие константы, касающиеся полей, а не отдельных битов.

Найдите подобное еще где-либо в stm32f10x.h.
Именно потому, что в большинстве случаев xxx_0, xxx_1 и т.д. описывает биты, так и воспринял эти константы, уже автоматически.
Сергей Борщ
Пишу так:
Код
2 * (FLASH_ACR_LATENCY & ~FLASH_ACR_LATENCY)

ViKo
Цитата(Сергей Борщ @ Feb 9 2014, 15:28) *
Пишу так:
Код
2 * (FLASH_ACR_LATENCY & ~FLASH_ACR_LATENCY)

Видимо, все же не так. rolleyes.gif Сколько на ноль ни умножай...
A. Fig Lee
А зачем все это?
Я сразу беру main() и поехал.
Вроде ж все по дефоулту уже придумано
ViKo
Цитата(A. Fig Lee @ Feb 9 2014, 17:13) *
А зачем все это?
Я сразу беру main() и поехал.
Вроде ж все по дефоулту уже придумано

В библиотеку не хожу. Не хочу пользоваться. У меня - просто, понятно...
Еще прикол - биты USB_CNTR_FRES и т.д. - описаны, а самой структуры USB в stm32f10x.h - нет! w00t.gif
mantech
Цитата(ViKo @ Feb 9 2014, 18:57) *
В библиотеку не хожу. Не хочу пользоваться. У меня - просто, понятно...


А что так сразу? Если инициализация в библиотеке есть и она корректно работает, зачем изобретать велосипед?

Я понимаю еще либы по USB - там пожалуй реально лучше с нуля писать...
Сергей Борщ
Цитата(ViKo @ Feb 9 2014, 14:47) *
Видимо, все же не так. rolleyes.gif Сколько на ноль ни умножай...
Да, действительно. Опечатался.
Код
2 * (FLASH_ACR_LATENCY & -FLASH_ACR_LATENCY)

_Артём_
Цитата(mantech @ Feb 9 2014, 19:09) *
А что так сразу? Если инициализация в библиотеке есть и она корректно работает, зачем изобретать велосипед?
Потому что инициализацию и самому несложно написать.

Цитата(mantech @ Feb 9 2014, 19:09) *
Я понимаю еще либы по USB - там пожалуй реально лучше с нуля писать...
Странная логика - всё с ног на голову. Если USB-библиотека работает, то зачем с нуля писать? Разве что подредактировать немного под нужлы проекта самую малость.


ViKo
Еще хотите ужасов? - В stm32f10x.h напрочь отсутствуют биты DAC_CR_DMAUDRIE2, DAC_CR_DMAUDRIE1.
Интересно, кто занимается коррекцией этих заголовков?
mantech
Цитата(_Артём_ @ Feb 9 2014, 23:15) *
Если USB-библиотека работает, то зачем с нуля писать?


В том-то и дело - не со всеми флешками работает - попробуй разберись, почему? laughing.gif
ViKo
Плетясь в хвосте у библиописателей, всегда ограничиваешься эффективностью этих библиописателей. Там, что, мастера высшего пилотажа работают? Похоже, нет.
ViKo
Мелкий аргумент. CppCheck только что выдала замечание о библиотечной system32f2xx.c:
Кратко: Suspicious use of ; at the end of 'while' statement.
Сообщение: Suspicious use of ; at the end of 'while' statement.
Гляжу, вижу:
Код
    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
mantech
Цитата(ViKo @ Feb 12 2014, 14:03) *
Мелкий аргумент. CppCheck только что выдала замечание о библиотечной system32f2xx.c:
Кратко: Suspicious use of ; at the end of 'while' statement.
Сообщение: Suspicious use of ; at the end of 'while' statement.
Гляжу, вижу:
Код
    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }


Видать "Всемогущие гуру" хотели еще что-нить в скобочках...вписать biggrin.gif
ViKo
Цитата(mantech @ Feb 12 2014, 14:16) *
Видать "Всемогущие гуру" хотели еще что-нить в скобочках...вписать biggrin.gif

И как бы оно {в скобочках} работало после ; ? w00t.gif
MrYuran
Цитата(ViKo @ Feb 10 2014, 16:49) *
Плетясь в хвосте у библиописателей, всегда ограничиваешься эффективностью этих библиописателей. Там, что, мастера высшего пилотажа работают? Похоже, нет.

//не в тему

Столкнулся недавно с "библиотекой" для AD9837 на сайте AD
Я уж было свою наполовину написал, но решил приобщиться к культуре sm.gif
Так Mihai & Bogdan там такого накуралесили..
Код
void AD9837_SetRegisterValue(unsigned short regValue)
{
    unsigned char data[5] = {0x03, 0x00, 0x00};    
    
    data[1] = (unsigned char)((regValue & 0xFF00) >> 8);
    data[2] = (unsigned char)((regValue & 0x00FF) >> 0);
    ADI_CS_LOW;        
    SPI_Write(data,2);
    ADI_CS_HIGH;
}

//кончаю оффтоп
Похоже, место индусов потихоньку занимают славяне sm.gif
А индусы - продвинулись до CEO MS
kolobok0
Цитата(MrYuran @ Feb 12 2014, 15:46) *
..Так Mihai & Bogdan там такого накуралесили....


исторически сложённый похоже.
в опен исходниках такое часто встречается... этим они и отличаются от боевых, коммерческих = нет повышенного
контроля (читай бездельников менагеров), и отсутствие тотального тестирования. У большинства когорты
потребителей(читай программистов) подход какой? хэлох-ты мир пишет, значит можно юзать. с возгласами ух-ты!!!
а вот то, что какое то состояние может выплыть нечаянно и всё встанет совсем поперёк - ну то через пару лет может
и аукнуться на каком-то проценте изделий...

к примеру - сейчас немного перетряхиваю lwip - так там так-же встречаются пёрлы. порой заметна даже разная кисть "мастера".
что поделать sm.gif))
Boriska
Цитата(ViKo @ Feb 9 2014, 18:57) *
В библиотеку не хожу. Не хочу пользоваться. У меня - просто, понятно...

А можно взглянуть на одну какую-нибудь Вашу процедурку, чтобы, так сказать, оценить преимущества подхода?
ViKo
Цитата(Boriska @ Feb 12 2014, 17:00) *
А можно взглянуть на одну какую-нибудь Вашу процедурку, чтобы, так сказать, оценить преимущества подхода?

Преимуществ особых нет, просто я имею представление о том, что хочу сделать.
CODE

/*!****************************************************************************
*
@brief System Clock STM32F100RBT6B initialize
@details Установить тактовую частоту 24MHz
@param
@return
@note Вызывается в startup.s
*/
void SystemInit(void) {

/* Задать начальное состояние (как после сброса) */
RCC->CR = 0x00000083; // HSI On, HSITRIM = 0x80
RCC->CFGR = 0x00000000; // HSI oscillator used as system clock
RCC->CIR = 0x001F0000; // Reset and disable all interrupts

/* Включить HSE генератор
Счетчик таймаута старта HSE генератора, загружается числом из stm32f10x.h
Ждать готовности генератора или окончания таймаута */
uint32_t StartCount = HSE_STARTUP_TIMEOUT;
RCC->CR |= RCC_CR_HSEON;
while (--StartCount && !(RCC->CR & RCC_CR_HSERDY)) { }

/* Если HSE генератор включился (таймаут не вышел) */
if (StartCount) {

/* Конфигурировать SYSCLK, HCLK, PCLK2, PCLK1, ADCPRE
Задать коэффициенты деления частоты */
RCC->CFGR =
RCC_CFGR_SW_0 * 0 | // SW[1:0] bits (System clock Switch): HSI
RCC_CFGR_HPRE_0 * 0 | // HPRE[3:0] bits (AHB prescaler): SYSCLK / 1 = 24 MHz (max)
RCC_CFGR_PPRE1_0 * 0 | // PRE1[2:0] bits (APB1 prescaler): HCLK / 1 = 24 MHz (max)
RCC_CFGR_PPRE2_0 * 0 | // PRE2[2:0] bits (APB2 prescaler): HCLK / 1 = 24 MHz
RCC_CFGR_ADCPRE_0 * 0 | // ADCPRE[1:0] bits (ADC prescaler): PCLK2 / 2 = 12 MHz (max)
RCC_CFGR_PLLSRC * 1 | // PLL entry clock source: PREDIV1
RCC_CFGR_PLLXTPRE * 1 | // HSE divider for PLL entry: / 2 (4 MHz)
RCC_CFGR_PLLMULL_0 * 4 | // PLLMUL[3:0] bits (PLL multiplication factor): * 6 = 24 MHz
RCC_CFGR_MCO_0 * 7 ; // MCO[2:0] bits (Microcontroller Clock Output): PLL / 2 = 12 MHz

/* Пределитель для PLL, не обязательно
Младший бит совпадает с RCC_CFGR_PLLXTPRE */
RCC->CFGR2 =
RCC_CFGR2_PREDIV1_0 * 1 ; // PREDIV1 input clock divided by 2

/* Включить PLL (и защиту HSE от сбоев, если нужно)
Ждать, пока нет готовности PLL */
RCC->CR |=
RCC_CR_PLLON * 1 | // PLL enable
RCC_CR_CSSON * 1 ; // Clock Security System enable
while (!(RCC->CR & RCC_CR_PLLRDY)) { }

/* Выбрать PLL как источник системной частоты
Ждать, пока PLL не выберется как источник системной частоты */
RCC->CFGR |= RCC_CFGR_SW_0 * 2 ; // System clock Switch: PLL
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) { }

/* Выключить внутренний генератор HSI */
RCC->CR &= ~RCC_CR_HSION;
}

/* Если HSE генератор не запустился, работать от HSI */
}
mantech
Цитата(ViKo @ Feb 12 2014, 18:08) *
RCC->CR = 0x00000083; // HSI On, HSITRIM = 0x80
RCC->CFGR = 0x00000000; // HSI oscillator used as system clock
RCC->CIR = 0x001F0000;


"Магические цифры" - тоже не "особенный" вариант. Потом начинаешь мучительно вспоминать, где чего и когда это было laughing.gif
ViKo
Цитата(mantech @ Feb 12 2014, 20:27) *
"Магические цифры" - тоже не "особенный" вариант. Потом начинаешь мучительно вспоминать, где чего и когда это было laughing.gif

Это взято из мануала, состояние после сброса. Оно не особенно и нужно. Будет работать и без этого.
Boriska
Цитата(ViKo @ Feb 12 2014, 18:08) *
Преимуществ особых нет, просто я имею представление о том, что хочу сделать.

Да, отказ от использования стандартной библиотеки не очевиден. Я только пару раз столкнулся с некоторыми неудобствами использования: Если нужна оптимизация по времени, то иногда приходится отказываться от лишних вызовов процедур. И второй момент: не все процедуры получились очевидными, так что приходится смотреть, что они делают.
ViKo
Если хотите очевидного, продемонстрируйте инициализацию порта, например. Желательно, с ассемблерным листингом. И укажите, для какого MCU. А после я покажу свой способ. sm.gif
Boriska
Цитата(ViKo @ Feb 13 2014, 11:00) *
Если хотите очевидного, продемонстрируйте инициализацию порта, например. Желательно, с ассемблерным листингом.

Код
  
/* GPIOD Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

  /* Configure PD0 and PD2 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

На счет листинга - сейчас нет возможности сделать.
MCU - STM32F103
ViKo
Для STM32F100, 103. Такты задаю раньше, одной командой для всех устройств.
CODE

/*! Port bit configuration table */
typedef enum {
IN_ANAL, GO_PP10, GO_PP02, GO_PP50, // Input Analog, GP Output Push-pull 10-2-50MHz
IN_FLOA, GO_OD10, GO_OD02, GO_OD50, // Input Float*, GP Output Open-drain 10-2-50MHz
IN_PDPU, AO_PP10, AO_PP02, AO_PP50, // Input Pull-down/Pull-up, Alt Func Push-pull
CM_NONE, AO_OD10, AO_OD02, AO_OD50 // none(illegal), Alt Func Open-drain 10-2-50MHz
} CONF_MODE;

/*!****************************************************************************
*
@brief Port Low/High byte configuration
@details Конфигурация байтов порта целиком
@param PORT - имя порта (A..G)
@param CM00..CM15 - конфигурация битов 0..15
@note Используется перечисляемый тип CONF_MODE
@note Для IN_PDPU нужный pull-down/pull-up задается в ODR
*/
#define GPIO_CONF(PORT, \
CM00, CM01, CM02, CM03, \
CM04, CM05, CM06, CM07, \
CM08, CM09, CM10, CM11, \
CM12, CM13, CM14, CM15); \
GPIO##PORT->CRL = ((uint32_t) \
CM00 << 0 | CM01 << 4 | CM02 << 8 | CM03 << 12 | \
CM04 << 16 | CM05 << 20 | CM06 << 24 | CM07 << 28); \
GPIO##PORT->CRH = ((uint32_t) \
CM08 << 0 | CM09 << 4 | CM10 << 8 | CM11 << 12 | \
CM12 << 16 | CM13 << 20 | CM14 << 24 | CM15 << 28);

#define GPIO_CONFL(PORT, \
CM00, CM01, CM02, CM03, \
CM04, CM05, CM06, CM07); \
GPIO##PORT->CRL = ((uint32_t) \
CM00 << 0 | CM01 << 4 | CM02 << 8 | CM03 << 12 | \
CM04 << 16 | CM05 << 20 | CM06 << 24 | CM07 << 28);

#define GPIO_CONFH(PORT, \
CM08, CM09, CM10, CM11, \
CM12, CM13, CM14, CM15); \
GPIO##PORT->CRH = ((uint32_t) \
CM08 << 0 | CM09 << 4 | CM10 << 8 | CM11 << 12 | \
CM12 << 16 | CM13 << 20 | CM14 << 24 | CM15 << 28);

/*!****************************************************************************
*
@brief Bit of Low/High byte Port configuration
@details Конфигурация одиночного бита порта
@param PORT - имя порта (A..G)
@param BIT - номер бита (0..15)
@param CM - конфигурация бита
@note Используется перечисляемый тип CONF_MODE
@note Для IN_PDPU нужный pull-down/pull-up задается в ODR
*/
#define GPIO_CONFB(PORT, BIT, CM) \
*(uint32_t *)((uint32_t)(GPIO##PORT) + BIT / 8 * 4) = \
*(uint32_t *)((uint32_t)(GPIO##PORT) + BIT / 8 * 4) \
& (~(0xF << (BIT % 8) * 4)) | (CM << (BIT % 8) * 4)

/* GPIO */
GPIO_CONF(A,
IN_FLOA, IN_FLOA, IN_FLOA, IN_FLOA, // User_Key, _ , _ , _
IN_ANAL, IN_ANAL, IN_FLOA, IN_FLOA, // DAC-1, DAC-2, _ , _
AO_PP50, IN_FLOA, IN_FLOA, IN_FLOA, // MCO, _ , _ , _ , _
IN_FLOA, IN_FLOA, IN_FLOA, IN_FLOA);

А вот листинг
Код
;;;371    /* GPIO */
;;;372      GPIO_CONF(A,
00000e  49e1              LDR      r1,|L1.916|
000010  48df              LDR      r0,|L1.912|
000012  6008              STR      r0,[r1,#0]
000014  1d09              ADDS     r1,r1,#4
000016  48e0              LDR      r0,|L1.920|
000018  6008              STR      r0,[r1,#0]
;;;373        IN_FLOA, IN_FLOA, IN_FLOA, IN_FLOA,    // User_Key, _ , _ , _
;;;374        IN_ANAL, IN_ANAL, IN_FLOA, IN_FLOA,    // DAC-1, DAC-2, _ , _
;;;375        AO_PP50, IN_FLOA, IN_FLOA, IN_FLOA,    // MCO, _ , _ , _ , _
;;;376        IN_FLOA, IN_FLOA, IN_FLOA, IN_FLOA);
Falkon_99
от стандартных CMSIS предпочитаю не отказыватся, типа
- stm32fxxx.c
- system_stm32f2xx.c
- core_cm3.c
Всё равно стартап вызывается только один раз вначале программы.

А вот STM32Fxxx_StdPeriph_Driver ( типа библиотеки GPIO, RCC, DMA ) стараюсь не использовать. Иногда проще пару битов вручную выставить, и тем самым Flash экономиить на пару килобайт.
Вы скажете, флеша и так хватает у STM? Это правда, но в режиме отладки, прошивка быстрее грузится в камень))) smile3046.gif
Boriska
Цитата(ViKo @ Feb 13 2014, 17:35) *
Для STM32F100, 103. Такты задаю раньше, одной командой для всех устройств.
/*! Port bit configuration table */
typedef enum {...

В принципе, нормально. Только может значения CONF_MODE переименовать, чтобы было понятнее? А то IN_ANAL как-то режет глаз wink.gif Да и AO_PP02 менее понятно, чем GPIO_Speed_50MHz.
Иногда, в проекте под каждый датчик/исполнительное устройство есть отдельный файл, а то и несколько. Как в этом случае задавать настройки: какие порты и другие ресурсы контроллера будут использоваться этим датчиком? Если это делать в заголовочном (*.h) файле самого датчика, то иногда возникают ситуации, когда одни и те же ресурсы используются одновременно несколькими устройствами. Меня подмывает перенести все дефайны распределения ресурсов в один заголовочный файл. Стоит так делать?
Может есть что-нибудь вроде "Best practices in embedded systems programming" для начинающих? Посоветуйте.
ViKo
Цитата(Boriska @ Feb 14 2014, 14:20) *
В принципе, нормально. Только может значения CONF_MODE переименовать, чтобы было понятнее? А то IN_ANAL как-то режет глаз wink.gif Да и AO_PP02 менее понятно, чем GPIO_Speed_50MHz.
Иногда, в проекте под каждый датчик/исполнительное устройство есть отдельный файл, а то и несколько. Как в этом случае задавать настройки: какие порты и другие ресурсы контроллера будут использоваться этим датчиком? Если это делать в заголовочном (*.h) файле самого датчика, то иногда возникают ситуации, когда одни и те же ресурсы используются одновременно несколькими устройствами. Меня подмывает перенести все дефайны распределения ресурсов в один заголовочный файл. Стоит так делать?
Может есть что-нибудь вроде "Best practices in embedded systems programming" для начинающих? Посоветуйте.

Пусть режет. Автору виднее! Каждый думает в меру своей распущенности. На некоторых импортных осциллографах выход калибратора назывался "CAL".
У меня все настройки всего - это одна функция, не такая уж и большая. Правда, USB там нет.
andrewlekar
Цитата
Меня подмывает перенести все дефайны распределения ресурсов в один заголовочный файл. Стоит так делать?

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

По поводу оптимизации инициализации ног. Считаю, что бороться за чистоту листинга и прочую оптимизацию при первоначальной настройке ног нет никакого смысла. Сколько бы она тактов не съела, делается настройка один раз и больше на производительность кода не влияет.
_Pasha
libopencm3 как вариант.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.