Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32: регистровый CMSIS или высокоуровневый HAL ?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Страницы: 1, 2
ViKo
USART_GetITStatus(USART2, USART_IT_TXE) - это функция, которую нужно вызвать и вернуться из нее. Там она еще и в стек что-нибудь сохранит, потом извлечет. вот и набежало 46 тактов.
Tarbal
Цитата(ШСА @ Nov 4 2015, 11:30) *
Я тоже, но только если 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. Быстродействие. Пока не поджимает никому не важно, а начнутся проблемы -- легко решить.




Цитата(esaulenka @ Nov 4 2015, 13:03) *
Нафиг-нафиг это HAL.
В случае "что-то пошло не так" разобраться в этом наслоении абстракций довольно сложно.
Судя по слухам "в HAL используется Keil RTOS", "HAL поддерживается только в Keil" и т.д., это не только моя проблема :-)

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


PS что присутствующие подразумевают под CMSIS, я не понял. Есть CMSIS core - набор функций/макросов для доступа к ядру и его периферии (NVIC, например). Это есть, и это удобно.
А идея "все производители чипов напишут единообразный CMSIS Driver API" не взлетела. Я, во всяком случае, не видел.
http://www.arm.com/products/processors/cor...ce-standard.php

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


Цитата(Ruslan1 @ Nov 4 2015, 20:49) *
Ну что же, немного прояснил кое-что для себя
1. Не могу работать в структуре Куба. хочу структуру файлов, которую раньше использовал и привык

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

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


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

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

Цитата(rudy_b @ Nov 6 2015, 01:33) *
Вот именно про это я и писал - HAL по DMA запускает передачу последнего байта, а, затем, по прямому поллингу TC дожидается завершения передачи последнего байта - и это в функции обработки прерывания DMA.

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

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


Что-то не вижу ожиданий в коде. Можете поподробнее рассказать пожалуйста?
CODE
/**
* @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
Цитата(Tarbal @ Nov 26 2015, 05:58) *
...
Что-то не вижу ожиданий в коде. Можете поподробнее рассказать пожалуйста?
...


Функция HAL_UART_Transmit_DMA
Код
...
/* Set the UART DMA transfer complete callback */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
...


Функция UART_DMATransmitCplt вызывает UART_WaitOnFlagUntilTimeout(...UART_FLAG_TC...) - ожидание флага TC.
CODE
...
/* Wait for UART TC Flag */
if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, UART_TIMEOUT_VALUE) != HAL_OK)
...
HAL_UART_TxCpltCallback(huart);
}[/code]

Функция UART_WaitOnFlagUntilTimeout - ждет (!в прерывании!) установки флага TC.
[code]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
Спасибо.
Надо будет переписать.

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

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

Код
/**
  * @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
Теоретики - как завидую Вам
Tarbal
Цитата(x893 @ Nov 27 2015, 01:07) *
Теоретики - как завидую Вам


Да ладно. Просто умные sm.gif
rudy_b
Цитата(Tarbal @ Nov 26 2015, 23:57) *
Не успел переписать sm.gif
Они уже сами починили. Кстати именно так как я и собирался:
...

Выглядит правильно. А для какого проца, какая версия либы, какой 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
Цитата(rudy_b @ Nov 27 2015, 06:47) *
Выглядит правильно. А для какого проца, какая версия либы, какой 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
Ох, не торопитесь апгрейтить Cube, в последней версии куча гадостей, просто кошмар какой-то.

Для начала - он стал самовольно изменять настройки проекта (включает полную оптимизацию) и удаляет из него пользовательские файлы. Ну и сразу какая-то куча глюков со старыми проектами началась, до конца пока не разобрался.
Jenya7
лично мои впечатления.
ни с STM32 ни с HAL ни с SPL раньше интенсивно не работал. так сделал пару несложных проектов. работал напрямую с регистрами.
и тут понадобилось заточить проект на STM32. собирал проект на HAL. два дня собирал. собрал таки. дошел до функции HAL_SPI_TransmitReceive. тихонько перешел на SPL. собрал проект за пол часа целуя в его небритые щеки (или что там у него есть). все что имею сказать по этому поводу.
Allregia
Цитата
собирал проект на HAL. два дня собирал. собрал таки. дошел до функции HAL_SPI_TransmitReceive. тихонько перешел на SPL. собрал проект за пол часа целуя в его небритые щеки


Это конечно все хорошо, я сам SPL пользую (в основном для первичных нициализаций, а где надо скорость - там напрямую в регистры).
Но у меня наклевывается проект на STM32F7, и насколько я помню - для него SPL нет, а только HAL.
Что очень жаль, поскольку этот проект переводится со старого SPL-проекта на STM32F4.
Jenya7
Цитата(Allregia @ Nov 29 2015, 20:56) *
Это конечно все хорошо, я сам SPL пользую (в основном для первичных нициализаций, а где надо скорость - там напрямую в регистры).
Но у меня наклевывается проект на STM32F7, и насколько я помню - для него SPL нет, а только HAL.
Что очень жаль, поскольку этот проект переводится со старого SPL-проекта на STM32F4.

я думаю можно поменть регистры в SPL функциях на свои. логика то понятна. лично я с HAL связываться не буду. ну если только будет для примера рабочий отлаженный проект.
на крайний случай - работа с регистрами. ничего страшного.
Bloom
Я в проектах часто использую Chibios и, соотвественно, его HAL. Сейчас его отвязали от ядра RTOS, и можно пользоваться им отдельно. На мой взгляд, получилось очень даже неплохо. Поддерживает только самое основное, если что-то нужно подкрутить под капотом, то можно и с регистрами поработать. Размер маленький получается за счет черной магии макросов.
yanvasiij
Добавлю свои пять копеек. Как мне кажется использование SPL или HAL обосновано, особенно при смене процессора. В одной руке даташит, в другой сгенерованный код, немного упорства и быстро начинаешь понимать, как работать с периферией. Если там и есть какие сложности или баги, то тут, на мой взгляд все просто, один раз наткнувшись на них достаточно посидеть и поковырять "потроха". После этого начинаешь прекрасно ориентироваться в исходниках и делать на этом процессоре один проект за другим. Тем более, что на STM32 не так уж и сильно эта периферия различается от процессора к процессору.

Что же касается непосредственно HAL, то, лично мне кажется, в своем стремлении абстрагироваться от регистров и низкоуровневой работы с периферией разработчики HAL переборщили. Вроде как теперь и reference manual то читать не надо (точнее похоже на то, что этого хотели добиться), но с другой стороны теперь надо читать код HAL или доку на него (кто что предпочитает). В свою очередь чтобы хорошо ориентироваться в SPL нужно все же обращаться к reference мануалу, поскольку многие типы и макроопределения введенные там непонятны без прочтения документации на проц. Но опять же и в том и другом случае разобраться то надо всего ОДИН раз, потом спокойно работаешь не заботясь о периферии.
x893
C HAL просто начать, но там нет нужных функций. Для их реализации надо написать немного кода, но в их идеологии. А она немного кривовата. Если посмотреть на более популярный mbed - там немного сложнее и еще более корявее. а с переходом на mbedos и yotta - стало просто мозголомкой. Но если не выходить за рамки - почти как в arduino (а это устраивает 95% "разработчиков" sm.gif).
Я использую все известные библиотеки и никаких проблем с выбором нет вообще.
Что надо использую, что не надо - удаляю и делаю своё.

Если функции инициализации делается один раз - мне все равно как она сделана, если правильно работает. Хоть на суахили. Если надо иметь кольцевой буфер, а его нет в HAL - то просто пишется нужный код. Хоть в регистры напрямую, хоть через SPL/HAL/libSTM32 и еще через что угодно.

Но всегда проще написать свою реализацию (хотя иногда она и не так красива как результат труда других людей).
makser
Я свои проекты делаю на SPL, потеря в тактах и байтах минимальна (давно тестил - буквально 1-2%). Сейчас переход на stm32f7 осложняется отсутствием оного для этих чипов. HAL действительно монстроподобен и похоже парой процентов потерь не обойдется.
Насчет SPL для stm32f7, есть такая мысль - судя по даташитам F7 включает в себя F4 с некоторыми новыми наворотами, т.е. по идее можно использовать SPL от F4 для F7. Осталось попробовать перенести ее.
x893
Мне по барабану регистры, SPL, HAL - у меня код аппаратной занимает максимум 5% от всего кода (обычно 1-2%).
Вообще непонятна цель этих дискуссий.
Просто делать нечего в деревне - бабки выходят и начинают ни о чем говорить.
Хотя они при деле и время проходит незаметно.
zltigo
QUOTE (x893 @ Apr 24 2016, 20:30) *
Мне по барабану регистры, SPL, HAL - у меня код аппаратной занимает максимум 5% от всего кода (обычно 1-2%).

Для того что бы угробить производительность, да и вообще превратить продукт в кучу дерьма, достаточно добавления и меньшего его количества.
x893
Это легко сравнивается через DWT, таймером, профайлером и всегда можно выбрать оптимальный вариант. Да и умелым программированием можно производительность угробить без регистров/SPL/HAL.

Нельзя всех сапожников заставить пользоваться одним типом молотка.
alexp74
Ковырял stm32f4xx_hal_eth.c и нашел интересный момент. Много записей в MAC регистры сделаны таким макаром:
Код
static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth)
{
  __IO uint32_t tmpreg1 = 0U;
  
  /* Set the Flush Transmit FIFO bit */
  (heth->Instance)->DMAOMR |= ETH_DMAOMR_FTF;
  
  /* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg1 = (heth->Instance)->DMAOMR;
  HAL_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->DMAOMR = tmpreg1;
}

Т.е. в регистр происходит запись, потом он же читается, потом задержка на от ~0 до 1-го systick и запись прочитанного опять в регистр.
Напрягает плавающая задержка. В мануале на stm32 не нашел требований по задержке...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.