Перейти к содержанию
    

STM32: регистровый CMSIS или высокоуровневый HAL ?

Одна микросекунда дополнительно из-за использования библиотечной функции, и это на 48 МГц ядра.

Это 200 тактов? Что-то явный перебор. Я сам не люблю StdPeriphLib, но надо быть объективным. Вы, по всей видимости, не отключили макрос USE_FULL_ASSERT. Если он определён, то там производится куча проверок параметров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это 200 тактов? Что-то явный перебор.

48. Даже меньше, там же не целая микросекунда. Пустяки... Но, все равно, жалко.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это 200 тактов? Что-то явный перебор. Я сам не люблю StdPeriphLib, но надо быть объективным. Вы, по всей видимости, не отключили макрос USE_FULL_ASSERT. Если он определён, то там производится куча проверок параметров.

Как тут заметили, тактов меньше (46), но могло бы быть и 200- они часто в этих библиотеках используют сдвиг для формирования битовых флагов. То есть в функцию передают номер бита, а дальше двигают. Универсально, да. Но расточительно.

Очень многое из этих функций можно было бы организовать через дефайны или инлайны, без потери универсальности.

Ну да ладно, даренному коду в сорцы не смотрят (если работает). Но я уже прочуствовал, почему народ кривится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как тут заметили, тактов меньше (46), но могло бы быть и 200- они часто в этих библиотеках используют сдвиг для формирования битовых флагов.

Да, я обсчитался, не в ту сторону уможил:) . Но и 48 многовато. Вы всё же для полной ясности гляньте макрос USE_FULL_ASSERT (он обычно определяется в файлах типа stm32f4xx_conf.h).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, я обсчитался, не в ту сторону уможил:) . Но и 48 многовато. Вы всё же для полной ясности гляньте макрос USE_FULL_ASSERT (он обычно определяется в файлах типа stm32f4xx_conf.h).

Не-не, выключен. есть только закомментированная строка (у меня в stm32f0xx_conf.h).

 

Могу сказать насколько код вырастает:

 

без USE_FULL_ASSERT:

Total ROM Size (Code + RO Data + RW Data) 16352 ( 15.97kB)

 

с USE_FULL_ASSERT:

Total ROM Size (Code + RO Data + RW Data) 22924 ( 22.39kB)

 

попробую позже измерить с включенным USE_FULL_ASSERT, интересно насколько изменяется скорость выполнения библиотечных функций.

 

Да, забыл сказать- это все при оптимизации по дефолту, -O2

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я тоже, но только если HAL годится не только для Keil. Я CooCos-ник.

Я перенес с Кейла на Кокос. Единственное что было неочевидно сходу -- использование другого имени переменной начала стэка в линкер файле. Пришлось минут 15 поискать.

В стартап файле:

Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\gcc\startup_stm32f429xx.s

 

 

ldr sp, =_estack /* set stack pointer */

.word _estack

 

Заменить на

 

ldr sp, =_eram /* set stack pointer */

.word _eram

 

Иначе линкер ругается на то, что _estack неопределен.

 

По поводу темы. Полностью поддерживаю топик стартера. Я тоже достаточно опытный программист микроконтроллеров и не вижу больших проблем с автогенератором. Ну надо изучать структуру полученного кода. Так то что она есть это скорее достоинство. Г-код это когда бессистемное нагромождение кода без продуманных идей. А проблемы со скоростью критических прерываний если потребуется я решу. Да и то если понадобится. Какие основные проблемы с автогенерацией возможны?

1. Баги. А кто без греха?

2. Размер кода. Пока помещается никто с этим не заморачивается. Система интеграции мобильника в БМВ занимает 130 килобайт кода:

http://www.ebay.co.uk/itm/NEW-GENUINE-BMW-...0-/291387105166

Прикиньте насколько можно поджимать код, когда прижмет.

Кстати мой любимый Source Insight тоже не такой много места занимает.

3. Быстродействие. Пока не поджимает никому не важно, а начнутся проблемы -- легко решить.

 

 

 

 

Нафиг-нафиг это HAL.

В случае "что-то пошло не так" разобраться в этом наслоении абстракций довольно сложно.

Судя по слухам "в HAL используется Keil RTOS", "HAL поддерживается только в Keil" и т.д., это не только моя проблема :-)

 

Библиотеки уровня "подрыгать ножкой" и "включить ШИМ" пишутся под конкретные требования на коленке за полчаса.

Заодно и виновный во всех косяках доступен :-)

 

 

PS что присутствующие подразумевают под CMSIS, я не понял. Есть CMSIS core - набор функций/макросов для доступа к ядру и его периферии (NVIC, например). Это есть, и это удобно.

А идея "все производители чипов напишут единообразный CMSIS Driver API" не взлетела. Я, во всяком случае, не видел.

http://www.arm.com/products/processors/cor...ce-standard.php

Да ладно вам. Вы не видели кода для фрискейловского АРМа с зигби периферией. Не помню навскидку его имени. Там один хедер файл и из него ифдефами разные части программы получают разные его варианты. Натуральный шифрокод. Я даже и времени не стал тратить -- нашел обходной маневр.

 

 

Ну что же, немного прояснил кое-что для себя

1. Не могу работать в структуре Куба. хочу структуру файлов, которую раньше использовал и привык

Мне редко удавалось использовать то, что я привык. Даже не заморачиваюсь с этим.

 

2. Посмотрел USART. мда, как-то они намутили с проверками и коллбеками, через эту цепь вызовов даже в прерывании продираться нужно, причем вызовы с аргументами. А у меня есть интерфейсы, где таймауты жестко заданы (например, sdi-12, или modbus-rtu ), или прерывания от внешних сигналов. И даже если я засуну свой код в предусмотренное для этого место в исходнике, то вызов HAL_UART_IRQHandler() никуда не денется. А если его удалить, то при следующей генерации кода он опять

 

Мне UART нужен для дебага только. Я только передатчик использую. Если использовать DMA, то вызывается на все строку только прерывание конец DMA. Да и передача красиво происходит. Вызвал функцию передачи и забыл. Оне не блокирующая. Реалтайм не страдает.

 

На прием сообщений произвольной длины DMA использовать красиво не получится если надо их в реаьном времени обрабатывать. Но кто мешает переписать обработчик прерывания?

 

Вот именно про это я и писал - HAL по DMA запускает передачу последнего байта, а, затем, по прямому поллингу TC дожидается завершения передачи последнего байта - и это в функции обработки прерывания DMA.

 

На скорости 115 кбод это приводит к завешиванию равных и более низкопроиоритетных прерываний (ну и всего нижележащего) примерно на 12 мксек (длительность передачи одного байта). Соответственно завешивается приемник (если он на равном или низшем приоритете) и получаем ORE.

 

Это легко убирается либо коррекцией кода HAL, либо снижением приоритета прерываний DMA передачи ниже DMA приема (именно priority, а не subpriority).

 

Что-то не вижу ожиданий в коде. Можете поподробнее рассказать пожалуйста?

/**
 * @brief  Handles DMA interrupt request.
 * @param  hdma: pointer to a DMA_HandleTypeDef structure that contains
 *			   the configuration information for the specified DMA Stream.  
 * @retval None
 */
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)

{
 /* Transfer Error Interrupt management ***************************************/
 if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma)) != RESET)
 {
if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TE) != RESET)
{
  /* Disable the transfer error interrupt */
  __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE);

  /* Clear the transfer error flag */
  __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma));

  /* Update error code */
  hdma->ErrorCode |= HAL_DMA_ERROR_TE;

  /* Change the DMA state */
  hdma->State = HAL_DMA_STATE_ERROR;

  /* Process Unlocked */
  __HAL_UNLOCK(hdma); 

  if(hdma->XferErrorCallback != NULL)
  {
	/* Transfer error callback */
	hdma->XferErrorCallback(hdma);
  }
}
 }
 /* FIFO Error Interrupt management ******************************************/
 if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_FE_FLAG_INDEX(hdma)) != RESET)
 {
if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != RESET)
{
  /* Disable the FIFO Error interrupt */
  __HAL_DMA_DISABLE_IT(hdma, DMA_IT_FE);

  /* Clear the FIFO error flag */
  __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_FE_FLAG_INDEX(hdma));

  /* Update error code */
  hdma->ErrorCode |= HAL_DMA_ERROR_FE;

  /* Change the DMA state */
  hdma->State = HAL_DMA_STATE_ERROR;

  /* Process Unlocked */
  __HAL_UNLOCK(hdma);

  if(hdma->XferErrorCallback != NULL)
  {
	/* Transfer error callback */
	hdma->XferErrorCallback(hdma);
  }
}
 }
 /* Direct Mode Error Interrupt management ***********************************/
 if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_DME_FLAG_INDEX(hdma)) != RESET)
 {
if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_DME) != RESET)
{
  /* Disable the direct mode Error interrupt */
  __HAL_DMA_DISABLE_IT(hdma, DMA_IT_DME);

  /* Clear the direct mode error flag */
  __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_DME_FLAG_INDEX(hdma));

  /* Update error code */
  hdma->ErrorCode |= HAL_DMA_ERROR_DME;

  /* Change the DMA state */
  hdma->State = HAL_DMA_STATE_ERROR;

  /* Process Unlocked */
  __HAL_UNLOCK(hdma);

  if(hdma->XferErrorCallback != NULL)
  {
	/* Transfer error callback */
	hdma->XferErrorCallback(hdma);
  }
}
 }
 /* Half Transfer Complete Interrupt management ******************************/
 if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)) != RESET)
 {
if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_HT) != RESET)
{ 
  /* Multi_Buffering mode enabled */
  if(((hdma->Instance->CR) & (uint32_t)(DMA_SxCR_DBM)) != 0)
  {
	/* Clear the half transfer complete flag */
	__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));

	/* Current memory buffer used is Memory 0 */
	if((hdma->Instance->CR & DMA_SxCR_CT) == 0)
	{
	  /* Change DMA peripheral state */
	  hdma->State = HAL_DMA_STATE_READY_HALF_MEM0;
	}
	/* Current memory buffer used is Memory 1 */
	else if((hdma->Instance->CR & DMA_SxCR_CT) != 0)
	{
	  /* Change DMA peripheral state */
	  hdma->State = HAL_DMA_STATE_READY_HALF_MEM1;
	}
  }
  else
  {
	/* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
	if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
	{
	  /* Disable the half transfer interrupt */
	  __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
	}
	/* Clear the half transfer complete flag */
	__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));

	/* Change DMA peripheral state */
	hdma->State = HAL_DMA_STATE_READY_HALF_MEM0;
  }

  if(hdma->XferHalfCpltCallback != NULL)
  {
	/* Half transfer callback */
	hdma->XferHalfCpltCallback(hdma);
  }
}
 }
 /* Transfer Complete Interrupt management ***********************************/
 if(__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma)) != RESET)
 {
if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != RESET)
{
  if(((hdma->Instance->CR) & (uint32_t)(DMA_SxCR_DBM)) != 0)
  {
	/* Clear the transfer complete flag */
	__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));

	/* Current memory buffer used is Memory 1 */
	if((hdma->Instance->CR & DMA_SxCR_CT) == 0)
	{
	  if(hdma->XferM1CpltCallback != NULL)
	  {
		/* Transfer complete Callback for memory1 */
		hdma->XferM1CpltCallback(hdma);
	  }
	}
	/* Current memory buffer used is Memory 0 */
	else if((hdma->Instance->CR & DMA_SxCR_CT) != 0) 
	{
	  if(hdma->XferCpltCallback != NULL)
	  {
		/* Transfer complete Callback for memory0 */
		hdma->XferCpltCallback(hdma);
	  }
	}
  }
  /* Disable the transfer complete interrupt if the DMA mode is not CIRCULAR */
  else
  {
	if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
	{
	  /* Disable the transfer complete interrupt */
	  __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TC);
	}
	/* Clear the transfer complete flag */
	__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));

	/* Update error code */
	hdma->ErrorCode |= HAL_DMA_ERROR_NONE;

	/* Change the DMA state */
	hdma->State = HAL_DMA_STATE_READY_MEM0;

	/* Process Unlocked */
	__HAL_UNLOCK(hdma);	  

	if(hdma->XferCpltCallback != NULL)
	{
	  /* Transfer complete callback */
	  hdma->XferCpltCallback(hdma);
	}
  }
}
 }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

Что-то не вижу ожиданий в коде. Можете поподробнее рассказать пожалуйста?

...

 

Функция HAL_UART_Transmit_DMA

...
/* Set the UART DMA transfer complete callback */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
...

 

Функция UART_DMATransmitCplt вызывает UART_WaitOnFlagUntilTimeout(...UART_FLAG_TC...) - ожидание флага TC.

 ...
/* Wait for UART TC Flag */
 if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, UART_TIMEOUT_VALUE) != HAL_OK)
...
HAL_UART_TxCpltCallback(huart);
 }

 

Функция UART_WaitOnFlagUntilTimeout - ждет (!в прерывании!) установки флага TC.

static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Timeout)
{
 uint32_t timeout = 0;

 timeout = HAL_GetTick() + Timeout;

 /* Wait until flag is set */
 if(Status == RESET)
 {
while(__HAL_UART_GET_FLAG(huart, Flag) == RESET)
{
  /* Check for the Timeout */
  if(Timeout != HAL_MAX_DELAY)
  {
	if(HAL_GetTick() >= timeout)
	{
	  /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
	  __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_PE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

	  huart->State= HAL_UART_STATE_READY;

	  /* Process Unlocked */
	  __HAL_UNLOCK(huart);

	  return HAL_TIMEOUT;
	}
  }
}
 }
 else
 {
while(__HAL_UART_GET_FLAG(huart, Flag) != RESET)
{
  /* Check for the Timeout */
  if(Timeout != HAL_MAX_DELAY)
  {
	if(HAL_GetTick() >= timeout)
	{
	  /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
	  __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_PE);
	  __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

	  huart->State= HAL_UART_STATE_READY;

	  /* Process Unlocked */
	  __HAL_UNLOCK(huart);

	  return HAL_TIMEOUT;
	}
  }
}
 }
 return HAL_OK;	  
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо.

Надо будет переписать.

 

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

 

Самое простое решение -- разрешить прерывание по концу передачи и перенести код для которого ожидается в обработчик UART, а там снова запретить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не успел переписать :)

Они уже сами починили. Кстати именно так как я и собирался:

 

/**
  * @brief  DMA UART transmit process complete callback. 
  * @param  hdma: DMA handle
  * @retval None
  */
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
  /* DMA Normal mode*/
  if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
  {
    huart->TxXferCount = 0;

    /* Disable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    huart->Instance->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DMAT);

    /* Enable the UART Transmit Complete Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
  }
  /* DMA Circular mode */
  else
  {
    HAL_UART_TxCpltCallback(huart);
  }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не успел переписать :)

Они уже сами починили. Кстати именно так как я и собирался:

...

Выглядит правильно. А для какого проца, какая версия либы, какой Cube?

 

Приводил тексты для:

проц stm32f207

либа * @version V1.0.1

* @date 25-March-2014

stm32Cube V1 version 4.6.0

 

Ага, загрузил последний апдейт, в новой либе

* @version V1.1.0

* @date 09-October-2015

действительно исправлено. Cube - stm32Cube V1 version 4.11.0

 

Но дырка с регистрами RTC все равно осталась и добавились дырка с ADC1 - пропал канал температурного сенсора. Но смотрел поверхностно, может еще что поломали.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выглядит правильно. А для какого проца, какая версия либы, какой Cube?

 

Приводил тексты для:

проц stm32f207

либа * @version V1.0.1

* @date 25-March-2014

stm32Cube V1 version 4.6.0

 

Ага, загрузил последний апдейт, в новой либе

* @version V1.1.0

* @date 09-October-2015

действительно исправлено. Cube - stm32Cube V1 version 4.11.0

 

Но дырка с регистрами RTC все равно осталась и добавились дырка с ADC1 - пропал канал температурного сенсора. Но смотрел поверхностно, может еще что поломали.

 

stm32Cube V1.0 version 4.7.1

stm32f429

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ох, не торопитесь апгрейтить Cube, в последней версии куча гадостей, просто кошмар какой-то.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...