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

 
 
 
Reply to this topicStart new topic
> SPI не принимает больше одного байта
Nosaer
сообщение Jun 29 2017, 11:37
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Доброго времени суток.
Столкнулся со следующей проблемой.
В данном случае 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, таких проблем вроде как не было.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Jun 29 2017, 15:03
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



80% проблем портирования с M3-M7 на M0/0+ - невыравненный доступ к памяти. Посмотрите на какой инструкции выскакивает хард фолт.
Go to the top of the page
 
+Quote Post
x893
сообщение Jun 29 2017, 15:25
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



А что бы отладчиком не пройти по шагам и посмотреть где падает.
Выравнивание немного из другой оперы в этом коде.
Еще неплохо при отладке поставить
DBGMCU_APB1_FZ_DBG_I2C1_SMBUS_TIMEOUT
(если конечно I2C1 - но телепатией не владею)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 29 2017, 16:47
Сообщение #4


Гуру
******

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



QUOTE (x893 @ Jun 29 2017, 18:25) *
(если конечно I2C1 - но телепатией не владею)
В заголовке вообще-то SPI. Да и функция называется HAL_SPI_Receive()


--------------------
На любой вопрос даю любой ответ
"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
x893
сообщение Jun 29 2017, 19:19
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Согласен - лопухнулся с I2C.
Но с SPI еще проще отладчиком пройтись.
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jun 30 2017, 03:27
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Цитата(Kabdim @ Jun 29 2017, 15:03) *
80% проблем портирования с M3-M7 на M0/0+ - невыравненный доступ к памяти. Посмотрите на какой инструкции выскакивает хард фолт.

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


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

Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
x893
сообщение Jun 30 2017, 03:34
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



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

hspi->Init.DataSize = ???

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

Кто такое издевательство выдержит ?
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jun 30 2017, 04:23
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Код
/* 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 бит.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 30 2017, 05:52
Сообщение #9


Гуру
******

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



QUOTE (Nosaer @ Jun 30 2017, 07:23) *
Проинициалированно на 8 бит, и считываю по 8.
У STM32F0 немного перемудрили с регистром данных - он 16-битный и если хотите передавать байты -
надо их запихивать по два за раз (они назвали это "упаковка"). А когда количество байт нечетное и остается один последний - надо еще и битик управляющий выставить, типа "пихаю последние 8 бит и все".

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


--------------------
На любой вопрос даю любой ответ
"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
Nosaer
сообщение Jun 30 2017, 06:35
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Цитата(Сергей Борщ @ Jun 30 2017, 05:52) *
У STM32F0 немного перемудрили с регистром данных - он 16-битный и если хотите передавать байты -
надо их запихивать по два за раз (они назвали это "упаковка"). А когда количество байт нечетное и остается один последний - надо еще и битик управляющий выставить, типа "пихаю последние 8 бит и все".

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

Теперь все понял) Спасибо большое)
Go to the top of the page
 
+Quote Post
x893
сообщение Jun 30 2017, 10:30
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



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

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.
Он конечно развесистый, но какой есть.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 21:36
Рейтинг@Mail.ru


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