|
STM32: HardFault |
|
|
|
Mar 27 2014, 04:16
|

Местный
  
Группа: Участник
Сообщений: 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; Как так? точно такая же функция на отправку работает нормально...
|
|
|
|
|
Mar 27 2014, 08:17
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
Mar 27 2014, 19:19
|
Гуру
     
Группа: Свой
Сообщений: 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); } Компилятор в курсе, что у него в регистрах, а что в памяти. И переместит в случае необходимости.
|
|
|
|
|
Mar 27 2014, 23:53
|
Гуру
     
Группа: Свой
Сообщений: 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-ядра. Но по дефолту это там запрещено.
|
|
|
|
|
Mar 28 2014, 04:00
|

Местный
  
Группа: Участник
Сообщений: 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; } } причина хардфаулта крылась либо в использовании локальных структур (а размер у них не малый), что негативно сказывалось на стеке, либо в некорректном порядке инициализации.
|
|
|
|
|
Mar 28 2014, 05:08
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Mar 28 2014, 09:22
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
ну не за пол дня, а за сутки все таки... тем более вы пишите Код причина хардфаулта крылась либо в использовании локальных структур (а размер у них не малый), что негативно сказывалось на стеке, либо в некорректном порядке инициализации. либо в чем то еще, и вы не уверены в чем, и то что оно сейчас завелось, не значит что когда в проекте появиться еще что-то оно так же случайно не выключится...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|