AHTOXA 18 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба Одна микросекунда дополнительно из-за использования библиотечной функции, и это на 48 МГц ядра. Это 200 тактов? Что-то явный перебор. Я сам не люблю StdPeriphLib, но надо быть объективным. Вы, по всей видимости, не отключили макрос USE_FULL_ASSERT. Если он определён, то там производится куча проверок параметров. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба Это 200 тактов? Что-то явный перебор. 48. Даже меньше, там же не целая микросекунда. Пустяки... Но, все равно, жалко. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 17 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба Это 200 тактов? Что-то явный перебор. Я сам не люблю StdPeriphLib, но надо быть объективным. Вы, по всей видимости, не отключили макрос USE_FULL_ASSERT. Если он определён, то там производится куча проверок параметров. Как тут заметили, тактов меньше (46), но могло бы быть и 200- они часто в этих библиотеках используют сдвиг для формирования битовых флагов. То есть в функцию передают номер бита, а дальше двигают. Универсально, да. Но расточительно. Очень многое из этих функций можно было бы организовать через дефайны или инлайны, без потери универсальности. Ну да ладно, даренному коду в сорцы не смотрят (если работает). Но я уже прочуствовал, почему народ кривится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба Как тут заметили, тактов меньше (46), но могло бы быть и 200- они часто в этих библиотеках используют сдвиг для формирования битовых флагов. Да, я обсчитался, не в ту сторону уможил:) . Но и 48 многовато. Вы всё же для полной ясности гляньте макрос USE_FULL_ASSERT (он обычно определяется в файлах типа stm32f4xx_conf.h). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 17 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба Да, я обсчитался, не в ту сторону уможил:) . Но и 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 21 ноября, 2015 Опубликовано 21 ноября, 2015 · Жалоба USART_GetITStatus(USART2, USART_IT_TXE) - это функция, которую нужно вызвать и вернуться из нее. Там она еще и в стек что-нибудь сохранит, потом извлечет. вот и набежало 46 тактов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 26 ноября, 2015 Опубликовано 26 ноября, 2015 · Жалоба Я тоже, но только если 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); } } } } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 26 ноября, 2015 Опубликовано 26 ноября, 2015 · Жалоба ... Что-то не вижу ожиданий в коде. Можете поподробнее рассказать пожалуйста? ... Функция 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 26 ноября, 2015 Опубликовано 26 ноября, 2015 · Жалоба Спасибо. Надо будет переписать. Получается по флагу буфер пуст заходит в обработчик и сидит там все время пересылки байта до флага передача закончена. Не мудрено, что прием может пропустить один байт. Самое простое решение -- разрешить прерывание по концу передачи и перенести код для которого ожидается в обработчик UART, а там снова запретить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 26 ноября, 2015 Опубликовано 26 ноября, 2015 · Жалоба Не успел переписать :) Они уже сами починили. Кстати именно так как я и собирался: /** * @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); } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 55 26 ноября, 2015 Опубликовано 26 ноября, 2015 · Жалоба Теоретики - как завидую Вам Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 27 ноября, 2015 Опубликовано 27 ноября, 2015 · Жалоба Теоретики - как завидую Вам Да ладно. Просто умные :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 27 ноября, 2015 Опубликовано 27 ноября, 2015 · Жалоба Не успел переписать :) Они уже сами починили. Кстати именно так как я и собирался: ... Выглядит правильно. А для какого проца, какая версия либы, какой 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 - пропал канал температурного сенсора. Но смотрел поверхностно, может еще что поломали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 27 ноября, 2015 Опубликовано 27 ноября, 2015 · Жалоба Выглядит правильно. А для какого проца, какая версия либы, какой 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 28 ноября, 2015 Опубликовано 28 ноября, 2015 · Жалоба Ох, не торопитесь апгрейтить Cube, в последней версии куча гадостей, просто кошмар какой-то. Для начала - он стал самовольно изменять настройки проекта (включает полную оптимизацию) и удаляет из него пользовательские файлы. Ну и сразу какая-то куча глюков со старыми проектами началась, до конца пока не разобрался. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться