Перейти к содержанию
    

Реализую 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"? Тогда они написали тут лишний '&' и возможны проблемы с невыровненным доступом. Надо внимательно смотреть остальной текст функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

сам в Си криминала так же не обнаружил, вероятно есть какие то особенности

 

погоняю еще отладчиком, может что выясню

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не видя остального кода функции этого нельзя утверждать со 100% уверенностью.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Значит, такая конструкция тоже не имеет права на жизнь:

void yyy(int **);

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

Компилятор в курсе, что у него в регистрах, а что в памяти. И переместит в случае необходимости.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть, по соглашению о передаче параметров в ARM С, указатель содержится в регистре R1. Оператор пытается взять указатель на регистр R1, а это вам не MSC-51 архитектура, где все регистры есть одновременно и ячейки памяти.

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

 

Процессор не любит словные (32-битовые) обращения по невыровненному адресу.

"Любит-нелюбит" - это к девушкам.

А вообще Cortex-M вполне нормально переваривает невыровненные доступы (в отличие от ARM7/9) (исключение - инструкции LDM, STM, LDRD, STRD, но вряд-ли компилятор их там нагенерил).

Опционально можно разрешить Usage Fault при невыровненном доступе. Это делается в регистре CCR Cortex-ядра. Но по дефолту это там запрещено.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема решилась. пошагал отладчиком и все такое.

после того как сделал структуры (для инициализации DMA на Tx и RX и тд) глобальными (видимо стека не хватало на локальные переменные) и изменил порядок вызова функций все задышало. + для работы новых HAL библиотек необходимо юзать прерывания для dma. ну в общем там ни мало особенностей появилось по сравнению со стрыми SPL

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема решилась. пошагал отладчиком и все такое.
А не могли бы вы выложить весь текст функции HAL_UART_Receive_DMA()? А то тут уже пошли теологические споры и было бы хорошо поставить жирную точку.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А не могли бы вы выложить весь текст функции 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; 
  }
}

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Да, но вот конкретно этот кусочек кода - шедевр

    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 заодно).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну библы новые, может причешут!

зато удалось реализовать работу DS18B20 по UART+DMA за пол дня, и даташит открыть пришлось только для того, что бы узнать какой поток/канал DMA активировать для нужного UART'а.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну не за пол дня, а за сутки все таки...

тем более вы пишите

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

 

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...