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

SPI не принимает больше одного байта, возникает HardFault на STM32F030

Доброго времени суток.

Столкнулся со следующей проблемой.

В данном случае SPI работает корректно:

 

uint8_t    BufReadMR45[3] = {0x03,0x00,0x00};
uint8_t     DataReadMR45[5] = {0};    

    void ReadMR45(void)
    {

        HAL_GPIO_WritePin(PortCSMR45, PinCSMR45, GPIO_PIN_RESET);                                                        // CS on
        HAL_Delay(1);
        HAL_SPI_Transmit(&hspi1, &BufReadMR45[0], 3, 1000);                                                                // Отправка данных по SPI
        HAL_SPI_Receive(&hspi1, &DataReadMR45[0], 1, 1000);                                                                // Получение данных по SPI

        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(PortCSMR45, PinCSMR45, GPIO_PIN_SET);                                                            // CS off
        HAL_UART_Transmit(&huart1, &DataReadMR45[0], 1, 0x1000);                                                    // Отправляю данные по UART
        ByteMR45_R = ByteMR45_R + 1;
    }
 

 

Если я изменю функцию:

HAL_SPI_Receive(&hspi1, &DataReadMR45[0], 5, 1000);
 

Чтобы считывать сразу больше 1 байта, программа зависает.

Отладчик приводит в HardFault_Handler(void)

 

Процессор STM32F030, до этого работал с серией F4, таких проблем вроде как не было.

Изменено пользователем haker_fox
Уточнил название темы, добавил теги, переместил в нужный раздел.

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


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

80% проблем портирования с M3-M7 на M0/0+ - невыравненный доступ к памяти. Посмотрите на какой инструкции выскакивает хард фолт.

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


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

А что бы отладчиком не пройти по шагам и посмотреть где падает.

Выравнивание немного из другой оперы в этом коде.

Еще неплохо при отладке поставить

DBGMCU_APB1_FZ_DBG_I2C1_SMBUS_TIMEOUT

(если конечно I2C1 - но телепатией не владею)

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


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

(если конечно I2C1 - но телепатией не владею)
В заголовке вообще-то SPI. Да и функция называется HAL_SPI_Receive()

 

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


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

Согласен - лопухнулся с I2C.

Но с SPI еще проще отладчиком пройтись.

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


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

80% проблем портирования с M3-M7 на M0/0+ - невыравненный доступ к памяти. Посмотрите на какой инструкции выскакивает хард фолт.

Программа не портировалась, а пишется полностью по новой.

 

 

На приложенном скриншоте, следующим шагом программа уходит в HardFault_Handler(void)

У самого знаний не хватает, почему делает так.

post-84967-1498793037_thumb.jpg

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


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

А что стоит в инициализациии SPI ?

 

hspi->Init.DataSize = ???

 

Читаете 16 битными словами а буфер даете на 5 байт.

Программе конечно пофиг - она читает 16 бит и записывает и 2 к указателю прибывит.

 

Кто такое издевательство выдержит ?

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


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

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

 

Проинициалированно на 8 бит, и считываю по 8.

Не совсем понял про 16 бит.

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


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

Проинициалированно на 8 бит, и считываю по 8.
У STM32F0 немного перемудрили с регистром данных - он 16-битный и если хотите передавать байты -

надо их запихивать по два за раз (они назвали это "упаковка"). А когда количество байт нечетное и остается один последний - надо еще и битик управляющий выставить, типа "пихаю последние 8 бит и все".

 

Не совсем понял про 16 бит.
Ваш указатель pTxData лежит в R5 и имеет значение 0x20000047. Своим приведением *(uint16_t *) вы принуждаете компилятор использовать команду чтения 16 бит. А поскольку адрес в указател у вас не выровнен на границу двух байт, то вы и получаете исключение из-за невыровненного доступа. Пламенный привет писателям "библиотеки". Чтобы этот код работал на CM0(+), адрес начала вашего буфера должен быть кратен двум. Или же переписать этот код правильно: если ваш компилятор умеет указатели на упакованные данные, надо объявить pTxData указателем на упакованные данные (как-то наподобие uint16_t __packed * pTxData). Или же объявить его указателем на uint8_t, вычитывать с его помощью два байта, вручную собирать их в 16-битное слово и уже это слово запихивать в DR. Я бы использовал второй вариант - объектный код получится такой же, а исходник останется портируемым на другие компиляторы.

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


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

У STM32F0 немного перемудрили с регистром данных - он 16-битный и если хотите передавать байты -

надо их запихивать по два за раз (они назвали это "упаковка"). А когда количество байт нечетное и остается один последний - надо еще и битик управляющий выставить, типа "пихаю последние 8 бит и все".

 

Ваш указатель pTxData лежит в R5 и имеет значение 0x20000047. Своим приведением *(uint16_t *) вы принуждаете компилятор использовать команду чтения 16 бит. А поскольку адрес в указател у вас не выровнен на границу двух байт, то вы и получаете исключение из-за невыровненного доступа. Пламенный привет писателям "библиотеки". Чтобы этот код работал на CM0(+), адрес начала вашего буфера должен быть кратен двум. Или же переписать этот код правильно: если ваш компилятор умеет указатели на упакованные данные, надо объявить pTxData указателем на упакованные данные (как-то наподобие uint16_t __packed * pTxData). Или же объявить его указателем на uint8_t, вычитывать с его помощью два байта, вручную собирать их в 16-битное слово и уже это слово запихивать в DR. Я бы использовал второй вариант - объектный код получится такой же, а исходник останется портируемым на другие компиляторы.

Теперь все понял) Спасибо большое)

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


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

Если посмотреть то перед передачей и приемом есть проверка

 

if ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) || (Size > 1U))

{

/* in this case, 16-bit access is performed on Data

So, check Data is 16-bit aligned address */

assert_param(IS_SPI_16BIT_ALIGNED_ADDRESS(pData));

}

 

то есть делается проверка что указатель выравнен на 2 при передаче больше 1 байта.

Можно это проигнорировать конечно и получить, то что получилось.

Обычно компилятор делает сам выравнивание переменных по 4, что бы такого не было.

Но всё можно руками поменять.

С __packed надо аккуратно обращаться.

А запись/чтение по 2 байта там есть при счетчике > 1.

Он конечно развесистый, но какой есть.

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


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

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

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

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

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

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

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

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

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

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