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

 
 
 
Reply to this topicStart new topic
> STM32F070, SPI, HAL проблемы
alexf
сообщение Oct 3 2016, 20:54
Сообщение #1


Местный
***

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



Проблемы с HAL уже обсуждались, но у меня немного другая, так что открыл новую тему.
Имеется STM32F070 и делаю SPI на HAL. (Нахально?)
Задача вроде не хитрая. Обмен с чипом SI4432 всегда по 2 байта. В режиме 8 бит NSS дергался между байтами, так что сделал управление по GPIO. Так проще.
И все бы ничего, по осциллографу картинка идеальная. А дальше вылезла проблема. Когда чтение происходило из (внешнего) прерывания, по осциллографу картинка все так же хороша, а читаются нули. Отладчик показал, что в DRA лежит правельный байт и уровень FIFO выше 0.
Код
uint8_t
extIntSpiReadReg (U8 reg){
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,  GPIO_PIN_RESET);
  spi_buf_out[0] = reg & 0x7f; // MSB first
  spi_buf_out[1] = 0; // ignored
  HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)&spi_buf_out,(uint8_t *) &spi_buf_in, 2,10);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,  GPIO_PIN_SET);
  return spi_buf_in[1];
}


После долгих мучений попробовал по простому (в 16 битном режиме):
Код
uint16_t ReadSPI(uint8_t addr){
    uint16_t val;
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SPI active
    while((SPI1->SR & SPI_SR_TXE) == 0); // wait for TX empty
    SPI1->DR = (uint16_t)(addr << 8);

    while(SPI1->SR & SPI_SR_BSY); // wait for TX empty
    while((SPI1->SR & SPI_SR_RXNE) == 0); // wait for RX
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // SPI not active
    val = SPI1->DR;
    return val;
}



Вопрос к знатокам: почему HAL так странно себя ведет? Что не так делаю?
Go to the top of the page
 
+Quote Post
serglg
сообщение Oct 4 2016, 04:44
Сообщение #2


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

Группа: Участник
Сообщений: 146
Регистрация: 19-07-16
Пользователь №: 92 603



Да, я тоже так и не понял с чтением по SPI.
Просто тупо читаю одно и то же 3 раза подряд (в STM32L476).
И тогда получаю правильный байт.
На осциллографе тоже всегда всё хорошо и при однократном чтении.

Go to the top of the page
 
+Quote Post
k155la3
сообщение Oct 4 2016, 06:20
Сообщение #3


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

Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848



Цитата(alexf @ Oct 3 2016, 23:54) *
. . . . .
Когда чтение происходило из (внешнего) прерывания, по осциллографу картинка все так же хороша, а читаются нули.
....
После долгих мучений попробовал по простому (в 16 битном режиме):
....


Имел дело с HAL другого процессора, MSP

HAL может использовать прерывания. Соотв-но, это надо соотносить откуда (из основной программы или из вектора какого либо прерывания)
происходит вызов HAL.
Исходя из "Когда чтение происходило из (внешнего) прерывания", вызов HAL в векторе аппаратного прерывания ?

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

"После долгих мучений" - посмотрите исходник HAL на эти вызовы. Отладчиком тоже можно посмотреть ктоестьху.
Go to the top of the page
 
+Quote Post
alexf
сообщение Oct 4 2016, 07:02
Сообщение #4


Местный
***

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



Цитата(k155la3 @ Oct 3 2016, 23:20) *
Если так, для проверки выведите вызов в основную программу и проверьте будет ли глючить там.


В том то и дело, что пара вызовов из основной программы вроде работала как надо. А в коде HAL прерываний не заметил. Это первое, что пришло в голову.

Я слегка соврал, что всегда по 2 байта. Забыл что есть чтение/запись Si4432 FIFO с произвольным, не обязательно четным числом байт. Поэкспериментировал с переключением с 8 на 16 бит и обратно, и тоже глючит. В результате скатился на всегда по 8 бит и даже 8 битное обращение к регистру. Скорость мне не важна - пока идет обмен, процессор все равно ждет.
После отказа от вызовов HAL SPI, размер кода на 2 К уменьшился. Хоть памяти и много, все равно приятно.

Код получился корявый, но вроде работает как надо. Пришлось, возможно в лишних местах, делать чтениа SDR для очистки RX FIFO.

CODE
void SPI1_init(){
__HAL_RCC_SPI1_CLK_ENABLE();
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_BR_0 | SPI_CR1_SSM | SPI_CR1_SSI;
SPI1->CR2 = SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0; // 8 bit
SPI1->CR2 |= SPI_CR2_FRXTH; // fifo treshold for 8 bits
SPI1->CR1 |= (1 << 6); // enable
}

#define SPI1_DR_8_bit (*(__IO uint8_t *)((uint32_t) & (SPI1->DR)))

void WriteSPI(uint8_t addr, uint8_t data){
uint8_t val;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SPI active
val = SPI1->DR; // clear just in case

while((SPI1->SR & SPI_SR_TXE) == 0); // wait for TX empty
SPI1_DR_8_bit = addr;
while((SPI1->SR & SPI_SR_RXNE) == 0); // wait for RX
val = SPI1_DR_8_bit; // discarded

while((SPI1->SR & SPI_SR_TXE) == 0); // wait for TX empty
SPI1_DR_8_bit = data;
while(SPI1->SR & SPI_SR_BSY);
while((SPI1->SR & SPI_SR_RXNE) == 0); // wait for RX
val = SPI1_DR_8_bit;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // SPI not active
}

uint8_t ReadSPI(uint8_t addr){
uint8_t val;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SPI active
val = SPI1->DR; // clear just in case

while((SPI1->SR & SPI_SR_TXE) == 0); // wait for TX empty
SPI1_DR_8_bit = addr;
while((SPI1->SR & SPI_SR_RXNE) == 0); // wait for RX
val = SPI1_DR_8_bit; // discarded

while((SPI1->SR & SPI_SR_TXE) == 0); // wait for TX empty
SPI1_DR_8_bit = 0xff;
while(SPI1->SR & SPI_SR_BSY);
while((SPI1->SR & SPI_SR_RXNE) == 0); // wait for RX
val = SPI1_DR_8_bit;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // SPI not active
return val;
}


Сообщение отредактировал IgorKossak - Oct 4 2016, 09:24
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
Go to the top of the page
 
+Quote Post
k155la3
сообщение Oct 4 2016, 07:44
Сообщение #5


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

Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848



Цитата(alexf @ Oct 4 2016, 10:02) *
Код
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SPI active
     . . . . .
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // SPI not active
}


если это в смысле CS, лучше, на мой взгляд, совместить функции Wr + Rd для работы с SPI.
Я пользую нечто вроде
Код
           SET_SELECT_SPI_FLASH;
           in_dat[0] = SPI_WrRd( out_dat[0] );
           in_dat[1] = SPI_WrRd( out_dat[1] );          
           . . . .
           CLEAR_SELECT_SPI_ALL;

так как выбор CS открывает "сессию" SPI, которая имеет свойство "одновременности" RD WR.
И что сделает slave с приемным регистром при "переоткрытии" по CS - зависит от реализации slave.
Ну, например, очистит приемный регистр передачи sm.gif

Сообщение отредактировал k155la3 - Oct 4 2016, 07:48
Go to the top of the page
 
+Quote Post

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

 


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


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