реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> STM32: HardFault
k000858
сообщение Mar 27 2014, 04:16
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978



Реализую 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;

Как так?

точно такая же функция на отправку работает нормально...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 27 2014, 04:55
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ISK2010
сообщение Mar 27 2014, 05:01
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 21-09-10
Из: г.Зеленоград
Пользователь №: 59 631



Может вы хотели написать "tmp = (uint32_t*)pData;" ?
Go to the top of the page
 
+Quote Post
k000858
сообщение Mar 27 2014, 05:38
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978



это не я написал, это библиотека от ST

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

погоняю еще отладчиком, может что выясню
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 27 2014, 08:17
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(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, 08:34
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 27 2014, 11:03
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(KnightIgor @ Mar 27 2014, 10:17) *
Вообще, (uint32_t*)&pData - явно чушь.
Не видя остального кода функции этого нельзя утверждать со 100% уверенностью.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 27 2014, 18:55
Сообщение #7


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Сергей Борщ @ Mar 27 2014, 12:03) *
Не видя остального кода функции этого нельзя утверждать со 100% уверенностью.

100% в инженерной практике не существуют. С 99.9% можно утверждать, что делать ссылку на указатель, переданый в качестве параметра - бессмысленно и вредно (Hardware Fault это доказывает): параметр pData содержит указатель на некий внешний буфер байтов. То есть, по соглашению о передаче параметров в ARM С, указатель содержится в регистре R1. Оператор пытается взять указатель на регистр R1, а это вам не MSC-51 архитектура, где все регистры есть одновременно и ячейки памяти.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 27 2014, 19:19
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(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);
}

Компилятор в курсе, что у него в регистрах, а что в памяти. И переместит в случае необходимости.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 27 2014, 23:53
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(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-ядра. Но по дефолту это там запрещено.
Go to the top of the page
 
+Quote Post
k000858
сообщение Mar 28 2014, 01:07
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978



Проблема решилась. пошагал отладчиком и все такое.
после того как сделал структуры (для инициализации DMA на Tx и RX и тд) глобальными (видимо стека не хватало на локальные переменные) и изменил порядок вызова функций все задышало. + для работы новых HAL библиотек необходимо юзать прерывания для dma. ну в общем там ни мало особенностей появилось по сравнению со стрыми SPL
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 28 2014, 03:39
Сообщение #11


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(k000858 @ Mar 28 2014, 03:07) *
Проблема решилась. пошагал отладчиком и все такое.
А не могли бы вы выложить весь текст функции HAL_UART_Receive_DMA()? А то тут уже пошли теологические споры и было бы хорошо поставить жирную точку.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
k000858
сообщение Mar 28 2014, 04:00
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978



Цитата(Сергей Борщ @ 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;
  }
}


причина хардфаулта крылась либо в использовании локальных структур (а размер у них не малый), что негативно сказывалось на стеке, либо в некорректном порядке инициализации.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 28 2014, 05:08
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(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 заодно).


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
k000858
сообщение Mar 28 2014, 05:39
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 31-01-12
Пользователь №: 69 978



ну библы новые, может причешут!
зато удалось реализовать работу DS18B20 по UART+DMA за пол дня, и даташит открыть пришлось только для того, что бы узнать какой поток/канал DMA активировать для нужного UART'а.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Mar 28 2014, 09:22
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



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


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

Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 12th August 2025 - 16:18
Рейтинг@Mail.ru


Страница сгенерированна за 0.01544 секунд с 7
ELECTRONIX ©2004-2016