Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32: HardFault
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
k000858
Реализую 1-wire на UART+DMA, камень STM32F407
Делается все на фирменных ST библиотеках HAL (новые SPL)

После вызова функции HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)ds18b20_buf_rx, sizeof(ds18b20_buf_rx)); попадаю в хардфаулт.
uint8_t ds18b20_buf_rx[8];

часть внутренностей функции:
Код
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
  tmp = (uint32_t*)&pData;
}


Прерывание происходит на строчке tmp = (uint32_t*)&pData;

Как так?

точно такая же функция на отправку работает нормально...
Сергей Борщ
Сама по себе строчка некриминальна. Надо пройтись по инструкциям в окне дизассемблера.

Зачем им указатель на указатель - надо смотреть дальше. И вот снова, хоть вы и говорите, что библиотека новая, но написана она кривовато. Они делают тут указатель на переданный вами указатель и явно приводят его к типу "указатель на uint32_t". Если это действительно то, чего они хотели, то нужно было применить специально созданный для таких случаев тип uintptr_t *, а не uint32_t *. А может они хотели привести ваш указатель на буфер к типу "указатель на uint32_t"? Тогда они написали тут лишний '&' и возможны проблемы с невыровненным доступом. Надо внимательно смотреть остальной текст функции.
ISK2010
Может вы хотели написать "tmp = (uint32_t*)pData;" ?
k000858
это не я написал, это библиотека от ST

сейчас убрал все лишнее, только инициализация UART+DMA и отправка по dma, и сново хардфаулт.
сам в Си криминала так же не обнаружил, вероятно есть какие то особенности

погоняю еще отладчиком, может что выясню
KnightIgor
Цитата(k000858 @ Mar 27 2014, 05:16) *
Реализую 1-wire на UART+DMA, камень STM32F407
часть внутренностей функции:
Код
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
  tmp = (uint32_t*)&pData;
}


Прерывание происходит на строчке tmp = (uint32_t*)&pData;

Как так?

Процессор не любит словные (32-битовые) обращения по невыровненному адресу.
Вообще, (uint32_t*)&pData - явно чушь. Либо должно быть (uint32_t*)&pData[0], либо (uint32_t*)pData. Без вариантов. И если вышеуказаный код в библиотеке стоит, значит в ней типичная индусская ошибка.
Сергей Борщ
Цитата(KnightIgor @ Mar 27 2014, 10:17) *
Вообще, (uint32_t*)&pData - явно чушь.
Не видя остального кода функции этого нельзя утверждать со 100% уверенностью.
KnightIgor
Цитата(Сергей Борщ @ Mar 27 2014, 12:03) *
Не видя остального кода функции этого нельзя утверждать со 100% уверенностью.

100% в инженерной практике не существуют. С 99.9% можно утверждать, что делать ссылку на указатель, переданый в качестве параметра - бессмысленно и вредно (Hardware Fault это доказывает): параметр pData содержит указатель на некий внешний буфер байтов. То есть, по соглашению о передаче параметров в ARM С, указатель содержится в регистре R1. Оператор пытается взять указатель на регистр R1, а это вам не MSC-51 архитектура, где все регистры есть одновременно и ячейки памяти.
aaarrr
Цитата(KnightIgor @ Mar 27 2014, 22:55) *
100% в инженерной практике не существуют. С 99.9% можно утверждать, что делать ссылку на указатель, переданый в качестве параметра - бессмысленно и вредно (Hardware Fault это доказывает): параметр pData содержит указатель на некий внешний буфер байтов. То есть, по соглашению о передаче параметров в ARM С, указатель содержится в регистре R1. Оператор пытается взять указатель на регистр R1, а это вам не MSC-51 архитектура, где все регистры есть одновременно и ячейки памяти.

Значит, такая конструкция тоже не имеет права на жизнь:
Код
void yyy(int **);

void xxx(int *a)
{
    yyy(&a);
}

Компилятор в курсе, что у него в регистрах, а что в памяти. И переместит в случае необходимости.
jcxz
Цитата(KnightIgor @ Mar 28 2014, 00:55) *
То есть, по соглашению о передаче параметров в ARM С, указатель содержится в регистре R1. Оператор пытается взять указатель на регистр R1, а это вам не MSC-51 архитектура, где все регистры есть одновременно и ячейки памяти.

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

Цитата(KnightIgor @ Mar 27 2014, 14:17) *
Процессор не любит словные (32-битовые) обращения по невыровненному адресу.

"Любит-нелюбит" - это к девушкам.
А вообще Cortex-M вполне нормально переваривает невыровненные доступы (в отличие от ARM7/9) (исключение - инструкции LDM, STM, LDRD, STRD, но вряд-ли компилятор их там нагенерил).
Опционально можно разрешить Usage Fault при невыровненном доступе. Это делается в регистре CCR Cortex-ядра. Но по дефолту это там запрещено.
k000858
Проблема решилась. пошагал отладчиком и все такое.
после того как сделал структуры (для инициализации DMA на Tx и RX и тд) глобальными (видимо стека не хватало на локальные переменные) и изменил порядок вызова функций все задышало. + для работы новых HAL библиотек необходимо юзать прерывания для dma. ну в общем там ни мало особенностей появилось по сравнению со стрыми SPL
Сергей Борщ
Цитата(k000858 @ Mar 28 2014, 03:07) *
Проблема решилась. пошагал отладчиком и все такое.
А не могли бы вы выложить весь текст функции HAL_UART_Receive_DMA()? А то тут уже пошли теологические споры и было бы хорошо поставить жирную точку.
k000858
Цитата(Сергей Борщ @ Mar 28 2014, 07:39) *
А не могли бы вы выложить весь текст функции HAL_UART_Receive_DMA()? А то тут уже пошли теологические споры и было бы хорошо поставить жирную точку.

на самом деле в самой функции ошибки нет. все работает корректно с передачей вышеописанных переменных.


Код
/**
  * @brief  Receives an amount of data in non blocking mode.
  * @param  huart: UART handle
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be received
  * @note   When the UART parity is enabled (PCE = 1) the data received contain the parity bit.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
  uint32_t tmp1 = 0;
  
  tmp1 = huart->State;    
  if((tmp1 == HAL_UART_STATE_READY) || (tmp1 == HAL_UART_STATE_BUSY_TX))
  {
    if((pData == NULL ) || (Size == 0))
    {
      return HAL_ERROR;
    }
    
    /* Process Locked */
    __HAL_LOCK(huart);
    
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a transmit rocess is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX)
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }
    
    /* Set the UART DMA transfer complete callback */
    huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
    
    /* Set the UART DMA Half transfer complete callback */
    huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
    
    /* Set the DMA error callback */
    huart->hdmarx->XferErrorCallback = UART_DMAError;

    /* Enable the DMA Stream */
    tmp = (uint32_t*)&pData;
    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);
    
    /* Enable the DMA transfer for the receiver request by setting the DMAR bit
    in the UART CR3 register */
    huart->Instance->CR3 |= USART_CR3_DMAR;
    
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
    
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}


причина хардфаулта крылась либо в использовании локальных структур (а размер у них не малый), что негативно сказывалось на стеке, либо в некорректном порядке инициализации.
Сергей Борщ
Цитата(k000858 @ Mar 28 2014, 06:00) *
на самом деле в самой функции ошибки нет. все работает корректно с передачей вышеописанных переменных.

Да, но вот конкретно этот кусочек кода - шедевр
Код
    tmp = (uint32_t*)&pData;
    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);
Не говоря уже о том, что второе приведение типа абсолютно лишнее, можно было написать прямее:
Код
    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, (uintptr_t)pData, Size);

Далее, pData надо было делать void * а преобразование типа перенести внутрь HAL_DMA_Start_IT. А еще правильнее было бы объявить как void * сам регистр DMA_Channel_TypeDef.CPAR (и CMAR заодно).
k000858
ну библы новые, может причешут!
зато удалось реализовать работу DS18B20 по UART+DMA за пол дня, и даташит открыть пришлось только для того, что бы узнать какой поток/канал DMA активировать для нужного UART'а.
Golikov A.
ну не за пол дня, а за сутки все таки...
тем более вы пишите
Код
причина хардфаулта крылась либо в использовании локальных структур (а размер у них не малый), что негативно сказывалось на стеке, либо в некорректном порядке инициализации.


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

jcxz
Цитата(Golikov A. @ Mar 28 2014, 15:22) *
либо в чем то еще, и вы не уверены в чем, и то что оно сейчас завелось, не значит что когда в проекте появиться еще что-то оно так же случайно не выключится...

Во-во - в точку! Шаманство вобщем sm.gif
Обычная практика когда не хотят открывать даташит...
DASM
За это и можно ненавидеть язык С. В fault на ровном месте.
Genadi Zawidowski
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);
Ничего себе, ровное место!
RusikOk
Цитата(k000858 @ Mar 27 2014, 07:16) *
Реализую 1-wire на UART+DMA
как успехи? получилось довести до ума?
k000858
Цитата(RusikOk @ Sep 3 2016, 22:59) *
как успехи? получилось довести до ума?

да, все работает
RusikOk
Цитата(k000858 @ Sep 7 2016, 15:17) *
да, все работает
поделитесь пожалуйста кодом. имейл отпраил Вам в личку
k000858
Цитата(RusikOk @ Sep 8 2016, 01:38) *
поделитесь пожалуйста кодом. имейл отпраил Вам в личку

к сожалению, не получится: разработка коммерческая, исходниками не делюсь
но если есть конкретные вопросы, постараюсь помочь чем смогу
RusikOk
Цитата(k000858 @ Sep 8 2016, 10:28) *
постараюсь помочь чем смогу
буджу благодарен.
скажите какая схема подключения датчиков к контроллеру? и какая реальная максимальная длинна линии?
k000858
Цитата(RusikOk @ Sep 10 2016, 12:01) *
буджу благодарен.
скажите какая схема подключения датчиков к контроллеру? и какая реальная максимальная длинна линии?

на сколько помню, до 100 метров в нашем случае работает
схемы у меня толком нету (для меня, как для программиста, это просто ЮАРТ + 1 джио ножка для подтяжке питания на линию на время преобразования температуры), а если б и была то выложить по той же причине не смог бы
RusikOk
схема мне не нужна. главное что все построено на UART. a DMA у вас используется? по примеру как тут http://we.easyelectronics.ru/STM32/stm32-1...odolzhenie.html
планирую использовать эту библиотеку переписав ее под HAL

P.S.
дело в том, что это мой первый проект на STM32 да еще и такой сложный а тут еще этот HAL с минимальным набором готовых библиотек на нем и сроки поджимают. а в проекте не только датчики...
k000858
Цитата(RusikOk @ Sep 13 2016, 08:20) *
схема мне не нужна. главное что все построено на UART. a DMA у вас используется? по примеру как тут http://we.easyelectronics.ru/STM32/stm32-1...odolzhenie.html
планирую использовать эту библиотеку переписав ее под HAL

P.S.
дело в том, что это мой первый проект на STM32 да еще и такой сложный а тут еще этот HAL с минимальным набором готовых библиотек на нем и сроки поджимают. а в проекте не только датчики...

все так же делал: все написано на основе HAL:
DMA используется по RX линии, по TX линии использовать его не вижу смысла; в ТХ плюю байтики, а между тем они же (но с учетом влияния шины 1-wire и устройств на ней) складываются по DMA в RX.
IgorC
проект на CubeMx? как делали изменение скорости порта?
Если я правильно понял нужно прыгать между 9600 и 115200, но хотелось бы оставить сгенерированный кубом код
RusikOk
Цитата(IgorC @ Feb 11 2017, 12:56) *
но хотелось бы оставить сгенерированный кубом код
так скопируй этот кусок в нужное место с подправленной скоростью
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.