Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 HAL SPI ошибка или глюки IAR,
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Pasa
STM32F051, IAR, CubeMX

Читаю в пакетном режиме два регистра - ответ правильный. Добавляю чтение 3-его регистра - в приемном буфере ерунда.
На осцилографе картинка нормальная - все диаграмы и ответы красивые и правильные...

В парметрах функции пробовал и 3 сразу читать и в цикле по одному байту - не получается....

И вот так уже попробовал:
Код
uint8_t localRxBuf[4];
uint8_t data1,data2,data3;

HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data1 = localRxBuf[0];
HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data2 = localRxBuf[0];
//HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
//data3 = localRxBuf[0];
придобавлении третьего чтения портятся data1,data2,data3......мистика какая-то. Повторюсь - на осцилографе все красиво и правильно

Такое ощущение, что HAL-библиотека глючит...
внутрь HAL что-ли полезть
serglg
хочу заметить, что с HAL_SPI_Receive и у меня какое-то подозрение (STM32L476).
Пока я не вставил CHTREG = SPI1->DR:

HAL_SPI_Receive(&hspi1, OTVRC522, 1, 20);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
CHTREG = SPI1->DR;
BUFRC522[j]=OTVRC522[0];

у меня был полный дурдом.
Там же регистр 16-битный, а прием 8-битный. Такое подозрение, что путаются ст. и мл. байты.
Pasa
Цитата(serglg @ Jul 27 2016, 19:27) *
Пока я не вставил CHTREG = SPI1->DR:

HAL_SPI_Receive(&hspi1, OTVRC522, 1, 20);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
CHTREG = SPI1->DR;
BUFRC522[j]=OTVRC522[0];

...... ээээ ....я не совсем с наскоку понял CHTREG = SPI1->DR;
- вызываете HAL_Recive
- CS вверх
- CHTREG = SPI1->DR; кудато руками читаете приемные данные? название CHTREG непонятно...
- зачем BUFRC522[j]=OTVRC522[0]; ......вроде выше все считано в CHTREG(что это такое?)

...или я не правильно понял...поясните пж-ста...

p.s.
у самого бродит идея весь прием переписать через CMSIS...только вот времени нету
Pasa
В инициализации SPI в HAL:

Код
  if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
  {
    frxth = SPI_RXFIFO_THRESHOLD_HF;
  }
  else
  {
    frxth = SPI_RXFIFO_THRESHOLD_QF;
  }


похоже тут надо наоборот.....может быть
serglg
Цитата(Pasa @ Jul 27 2016, 23:27) *
...... ээээ ....я не совсем с наскоку понял CHTREG = SPI1->DR;
- вызываете HAL_Recive
- CS вверх
- CHTREG = SPI1->DR; кудато руками читаете приемные данные? название CHTREG непонятно...
- зачем BUFRC522[j]=OTVRC522[0]; ......вроде выше все считано в CHTREG(что это такое?)

...или я не правильно понял...поясните пж-ста...

p.s.
у самого бродит идея весь прием переписать через CMSIS...только вот времени нету


CHTREG - совсем левая переменная. Чтобы было куда считать регистр данных SPI ( SPI1->DR).

BUFRC522[j]=OTVRC522[0] - у меня все регистры платы RFID-RC522 (их там больше 30 рабочих) считывались в массив.
А OTVRC522[0] - это же просто массив куда HAL-функция складывает текущий байт.

Так вот. Без этой дурацкой строки (признаю полностью, что дурацкой):
CHTREG = SPI1->DR;
у меня читается в массив OTVRC522[0] черт те что.
Таким образом что-то там в HAL-функциях по SPI у них накосячено.


Цитата(Pasa @ Jul 28 2016, 02:17) *
В инициализации SPI в HAL:

Код
  if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
  {
    frxth = SPI_RXFIFO_THRESHOLD_HF;
  }
  else
  {
    frxth = SPI_RXFIFO_THRESHOLD_QF;
  }


похоже тут надо наоборот.....может быть


Ну вот, может и у меня тут потому глюк?
tehn1k
Как Вы выбираете чтение того или иного регистра, если работаете только в режиме приема? Пользуюсь HALовскими функциями HAL_SPI_TransmitReceive и HAL_SPI_TransmitReceive_IT, работают как часы, проц stmf745. В режиме дебага посмотрите, что по факту находится в дата регистре. Про порчу data1, data2 - такого не может быть, если только что то еще в коде не обращается к этим переменным.
k155la3
Цитата(Pasa @ Jul 27 2016, 13:20) *
STM32F051, IAR, CubeMX

Читаю в пакетном режиме два регистра - ответ правильный. Добавляю чтение 3-его регистра - в приемном буфере ерунда.
На осцилографе картинка нормальная - все диаграмы и ответы красивые и правильные...

. . . .

Такое ощущение, что HAL-библиотека глючит...
внутрь HAL что-ли полезть


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

Полезть внутрь HAL. Тоже вариант. Выкопать исполнимый код будет сложновато.
Можно посмотреть что там творится на уровне ASM-листинга или дизассемблера в отладчике.
serglg
Цитата(tehn1k @ Jul 28 2016, 11:41) *
Как Вы выбираете чтение того или иного регистра, если работаете только в режиме приема? Пользуюсь HALовскими функциями HAL_SPI_TransmitReceive и HAL_SPI_TransmitReceive_IT, работают как часы, проц stmf745. В режиме дебага посмотрите, что по факту находится в дата регистре. Про порчу data1, data2 - такого не может быть, если только что то еще в коде не обращается к этим переменным.


Мне надо прочитать регистр в RC522 c определенным адресом. Для этого надо сначала передать этот адрес (1 байт) и потом (не снимая CS) принять один байт. Вы может предложить пример вызова функции HAL_SPI_TransmitReceive для такого случая? У меня почему-то не получалось.
tehn1k
Цитата(serglg @ Jul 28 2016, 10:09) *
Мне надо прочитать регистр в RC522 c определенным адресом. Для этого надо сначала передать этот адрес (1 байт) и потом (не снимая CS) принять один байт. Вы может предложить пример вызова функции HAL_SPI_TransmitReceive для такого случая? У меня почему-то не получалось.

1) Проверьте вот это
Data bytes on both MOSI and MISO lines are sent with the MSB first. Data on both MOSI and MISO lines must be stable on the rising edge of the clock and can be changed on the falling edge. Data is provided by the MFRC522
on the falling clock edge and is stable during the rising clock edge

2) Вместо NSS SPI интерфейса подключите к NSS любой свободный пин и управляйте им. Опускаете его в 0, передаете принимаете нужное количество байт вызвав HAL_SPI_TransmitReceive и поднимаете пин вверх.
Lagman
Цитата(serglg @ Jul 28 2016, 09:09) *
Мне надо прочитать регистр в RC522 c определенным адресом. Для этого надо сначала передать этот адрес (1 байт) и потом (не снимая CS) принять один байт. Вы может предложить пример вызова функции HAL_SPI_TransmitReceive для такого случая? У меня почему-то не получалось.

А зачем тогда читать 3 байта подряд?

Если исходить из того, что используется функция HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout) то можно поступить так, надо отправить 1 байт с адресом регистра и принять 1 байт с данными (не одновременно), размер Size будет равен 2 байтам, pTxData[0] = адресу регистра откуда будут читаться данные, pTxData[1] = 0xff; При обработке pRxData[0] игнорируем и данные берем из pRxData[1].
k155la3
Цитата(Lagman @ Jul 28 2016, 12:35) *
А зачем тогда читать 3 байта подряд?

Если исходить из того, что используется функция HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout) то можно поступить так, надо отправить 1 байт с адресом регистра и принять 1 байт с данными (не одновременно), размер Size будет равен 2 байтам, pTxData[0] = адресу регистра откуда будут читаться данные, pTxData[1] = 0xff; При обработке pRxData[0] игнорируем и данные берем из pRxData[1].


Чотбы прочитать один байт из 8-разрядного регистра.
1. Установить CS
2. Передать опкод, принять мусор (или регистр статуса)
3. Передать адрес регистра, принять мусор
4. Передать мусор, принять значение регистра.
5. Снять CS
Это если "SPI-безвыпендривания"
Для конкретного девайса надо смотреть диаграмму запроса по конкретному опкоду.
k155la3
Цитата(Pasa @ Jul 27 2016, 13:20) *
И вот так уже попробовал:
Код
uint8_t localRxBuf[4];
uint8_t data1,data2,data3;

HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data1 = localRxBuf[0];
HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data2 = localRxBuf[0];
//HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);

//data3 = localRxBuf[0];
придобавлении третьего чтения портятся data1,data2,data3......мистика какая-то. Повторюсь - на осцилографе все красиво и правильно

. . . . .


"при добавлении третьего чтения портятся data1,data2,data3"

uint8_t localRxBuf[4];
uint8_t data1,data2,data3;

Исходя из объявления, эта память находится в одном сегменте, одного типа (uint8_t) , и вполне вероятно "слитно".
Похоже что ф-ия HAL пишет в массив данные, которые не того типа, или не того кол-ва, или и то и другое.
Запись начиная с localRxBuf[0] зашкаливает за localRxBuf[3] и возможно, затирает data123

rudy_b
Что-то я не понял, у вас SPI в режиме slave или master?
Если в slave - то дергание CS недопустимо, в этом режиме это входной сигнал.
А если master - вы сами должны дергать CS. Проверьте, что периферия правильно на него реагирует.

С работой SPI в режиме slave через DMA (не IT) действительно есть какие-то проблемы (f207). Они есть даже без HAL. Очень долго мучился заставляя его правильно работать, но, в конце концов, это удалось. Подробностей уже не помню, но долго возился с тем, чтобы не было перестановки байт и не пропадал первый байт посылки.
x893
Функция SPI Receive в HAL занимает строк 20 из них 10 фуфло всякое. Пройдите по шагам и посмотрите что там делается. За пять минут (вместо дня гадания) уже всё определили бы и получали свои байты.
alag57
В CR2 есть такой хитрый битик - FRXTH, так вот у меня получилось только так:

CODE

void SPI1_WriteRead(uint8_t *tx_buf, uint8_t *rx_buf, uint8_t length)
{
SPI1_CS_On();
SPI1_WriteRead_NotCS(tx_buf, rx_buf, length);
SPI1_CS_Off();
}

void SPI1_WriteRead_NotCS(uint8_t *tx_buf, uint8_t *rx_buf, uint8_t length)
{
uint8_t rx_length = length;

if (length > 1)
{
SPI1->CR2 &= ~SPI_CR2_FRXTH; // Threshold = 16
}
else
{
SPI1->CR2 |= SPI_CR2_FRXTH; // Threshold = 8
}

while (length)
{
while ((SPI1->SR & SPI_I2S_FLAG_TXE) == 0);

if (length > 1)
{
SPI1->DR = *((uint16_t *)tx_buf);
tx_buf += 2;
length -=2;
}
else
{
*(__IO uint8_t *)&SPI1->DR = *tx_buf++;
length--;
}

while ((SPI1->SR & SPI_I2S_FLAG_RXNE) == 0);

if (rx_length > 1)
{
*((uint16_t *)rx_buf) = SPI1->DR;
rx_buf += 2;
rx_length -= 2;
if (rx_length <= 1)
{
SPI1->CR2 |= SPI_CR2_FRXTH; // Threshold = 8
}
}
else
{
(*rx_buf++) = *(__IO uint8_t *)&SPI1->DR;
}
}
}

x893
Ничего хитрого
The RXNE flag is set depending on the FRXTH bit value in the SPIx_CR2 register: If FRXTH is set, RXNE goes high and stays high until the RXFIFO level is greater or equal to 1/4 (8-bit). If FRXTH is cleared (default), RXNE goes high and stays high until the RXFIFO level is greater than or equal to 1/2 (16-bit).
и сначала ставим CR2 а потом CR1

SPI1->CR2 = 0; // 16 bit
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_SPE; // или как надо

В RM есть.

В HAL SPI_Init() есть код

/* Align by default the rs fifo threshold on the data size */
if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
{
frxth = SPI_RXFIFO_THRESHOLD_HF;
}
else
{
frxth = SPI_RXFIFO_THRESHOLD_QF;
}

Pasa
Обмен идет с CC2500

Цитата(k155la3 @ Jul 28 2016, 09:39) *
Про осцилограф.
Проверьте соответствие настроек полярности-фазы SPI и их соответствие девайсу с которым работаете.


Проверял в самом начале проекта. Осцллограммы идеальные - и STM32 и СС2500 выдают правильные картинки.

Цитата(k155la3 @ Jul 28 2016, 16:15) *
"при добавлении третьего чтения портятся data1,data2,data3"

uint8_t localRxBuf[4];
uint8_t data1,data2,data3;

Исходя из объявления, эта память находится в одном сегменте, одного типа (uint8_t) , и вполне вероятно "слитно".
Похоже что ф-ия HAL пишет в массив данные, которые не того типа, или не того кол-ва, или и то и другое.
Запись начиная с localRxBuf[0] зашкаливает за localRxBuf[3] и возможно, затирает data123


Расположил вот так:

Код
uint8_t localRxBuf1[16];
uint8_t localRxBuf2[16];
uint8_t localRxBuf3[16];
uint8_t localRxBuf4[16];
uint8_t data1,data2,data3;
uint16_t dataX1,dataX2,dataX3;
.......
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf1[0], 1, 10000);
   data1=localRxBuf1[0];
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf2[0], 1, 10000);
   data2=localRxBuf2[0];
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf3[0], 1, 10000);
   data3=localRxBuf3[0];


все равно прием неправильный...


Цитата(x893 @ Jul 28 2016, 19:44) *
Ничего хитрого
The RXNE flag is set depending on the FRXTH bit value in the SPIx_CR2 register: If FRXTH is set, RXNE goes high and stays high until the RXFIFO level is greater or equal to 1/4 (8-bit). If FRXTH is cleared (default), RXNE goes high and stays high until the RXFIFO level is greater than or equal to 1/2 (16-bit).
и сначала ставим CR2 а потом CR1

SPI1->CR2 = 0; // 16 bit
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_SPE; // или как надо

В RM есть.

В HAL SPI_Init() есть код

/* Align by default the rs fifo threshold on the data size */
if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
{
frxth = SPI_RXFIFO_THRESHOLD_HF;
}
else
{
frxth = SPI_RXFIFO_THRESHOLD_QF;
}


Я об этом как раз и упоминал.
В HAL_SPI_Init() ниже в CR2 ставится/снимается бит FRXTH.
hspi->Instance->CR2 = (((hspi->Init.NSS >> 16) & SPI_CR2_SSOE) | hspi->Init.TIMode | hspi->Init.NSSPMode | hspi->Init.DataSize ) | frxth;

Для 8-битного режима FRXTH должен быть сброшен, собственно переменная принимает значение0: frxth = SPI_RXFIFO_THRESHOLD_HF;
Но непонятно условие для этого: if(hspi->Init.DataSize > SPI_DATASIZE_8BIT) ????
Не получается ли, что это никогда не выполняется и всегда ставится режим SPI_RXFIFO_THRESHOLD_QF(16 бит)?
x893
Проверил с stm32f030 и CC2500 - всё работает как часы.
Проверьте инициализацию spi
SPI_DIRECTION_2LINES
SPI_CRCCALCULATION_ENABLE
SPI_DATASIZE_8BIT
и пройдите по шагам
HAL_StatusTypeDef HAL_SPI_Receive(...
никаких чудес нет.
SPI_CS программный у меня.

Там все понятно. Если байтов принимается > 1, то включается 16 бит режим - SPI пофигу, а процессору меньше работы.
Последний байт (если есть) принимается в 8-бит режиме. Но можно использовать от 4-х бит до 9-бит (байтовый обмен) или от 9 до 16 (2 байта на обмен)

Но проще посмотреть дебаггером, что конкретно происходит.
Pasa
Цитата(x893 @ Jul 28 2016, 17:47) *
Функция SPI Receive в HAL занимает строк 20 из них 10 фуфло всякое. Пройдите по шагам и посмотрите что там делается. За пять минут (вместо дня гадания) уже всё определили бы и получали свои байты.


Никакого гадания нет. Уже давно все посмотрел. Потому и поднял тему, что не понятно каким образом аппартано в регистр DR залетает мусор и на выходе HAL-функции получаем полный бред, портящий буфер приема.

на всякий случай SPI проинициализирован вот так:
Код
  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_DISABLE;



Цитата(x893 @ Jul 28 2016, 23:19) *
Проверил с stm32f030 и CC2500 - всё работает как часы.
Проверьте инициализацию spi
SPI_DIRECTION_2LINES
SPI_CRCCALCULATION_ENABLE
SPI_DATASIZE_8BIT
и пройдите по шагам
HAL_StatusTypeDef HAL_SPI_Receive(...
никаких чудес нет.
SPI_CS программный у меня.

Там все понятно. Если байтов принимается > 1, то включается 16 бит режим - SPI пофигу, а процессору меньше работы.
Последний байт (если есть) принимается в 8-бит режиме. Но можно использовать от 4-х бит до 9-бит (байтовый обмен) или от 9 до 16 (2 байта на обмен)

Но проще посмотреть дебаггером, что конкретно происходит.


читаю от CC2500 три регистра:
Код
    
cmd_byte = ( (regAddr & 0x3f) | TI_CCxxx0_READ_BURST );  // regAddr - начальный адрес регистра

   CS_LO(); // /CS = 0

   HAL_SPI_Transmit(&hspi1, &cmd_byte, 1, 10000);

   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf1[0], 1, 10000);
   data1 = localRxBuf1[0];
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf2[0], 1, 10000);
   data2 = localRxBuf2[0];
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf3[0], 1, 10000);
   data3 = localRxBuf3[0];

   CS_HI(); // /CS = 1


на выходе в data1,data3,data3 путаница
А на осциллографе совершенно правильная картинка.....и на MISO и на MOSI

Попробуйте пж-ста мою конструкцию....заработает ли у вас? .......не могу понять что у меня происходит


в CC2500 для теста пишу так:
Код
uint8_t localRxBuf1[16];
uint8_t localRxBuf2[16];
uint8_t localRxBuf3[16];
uint8_t localRxBuf4[16];
uint8_t data1,data2,data3;
uint16_t dataX1,dataX2,dataX3;

CC2500_Init();
CC2500_WriteRegSingle(0x09,     0x55);
CC2500_WriteRegSingle(0x0A,     0x33);
CC2500_WriteRegSingle(0x0B,     0x07);

while(1)
{

   HAL_Delay(1000);

   cmd_byte = ( 0x09  | TI_CCxxx0_READ_BURST );  // regAddr - начальный адрес регистра

   CS_LO(); // /CS = 0

   HAL_SPI_Transmit(&hspi1, &cmd_byte, 1, 10000);


   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf1[0], 1, 10000);
   data1 = localRxBuf1[0];
   dataX1=(uint16_t)hspi1.Instance->DR;

   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf2[0], 1, 10000);
   data2 = localRxBuf2[0];
   dataX2=(uint16_t)hspi1.Instance->DR;

   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf3[0], 1, 10000);
   data3 = localRxBuf3[0];
   dataX3=(uint16_t)hspi1.Instance->DR;

   CS_HI(); // /CS = 1


}

[/code]

Значения dataX1 dataX2 dataX3 по циклам:
0x000F - 0x3355 - 0x0007
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
0x0733 - 0x0007 - 0x5500
.......

p.s.
с работы сторожа выгоняют...появлюсь через 30 минут ( в 0:10)
alag57
Цитата(x893 @ Jul 28 2016, 21:14) *
Ничего хитрого

Хитрость для меня была в том, что CR2->FRXTH пришлось инициализировать при каждой
записи-чтении.

Цитата(x893 @ Jul 28 2016, 21:14) *
сначала ставим CR2 а потом CR1

Может быть винт от хитрости как раз в этом. Надо будет проверить.
serglg
Ну вот и моя хитрость. Чтение делаю 3 (три) раза подряд. К примеру мне надо установить бит в каком либо регистре.
Раньше (в типовом пример из интернета) было так:
Код
    void TM_MFRC522_SetBitMask(uint8_t reg, uint8_t mask)
        {
    TM_MFRC522_WriteRegister(reg, TM_MFRC522_ReadRegister(reg) | mask);
        }
Глючит.
А вот так работает уверенно:
Код
    void TM_MFRC522_SetBitMask(uint8_t reg, uint8_t mask)
        {
        int BUFR;
        BUFR=TM_MFRC522_ReadRegister(reg);
        BUFR=TM_MFRC522_ReadRegister(reg);
        BUFR=TM_MFRC522_ReadRegister(reg);
        BUFR=BUFR | mask;
        
    TM_MFRC522_WriteRegister(reg, BUFR);
            
        }
А можно и по другому, саму функцию TM_MFRC522_ReadRegister вызываем только раз,
Код
    void TM_MFRC522_SetBitMask(uint8_t reg, uint8_t mask)
        {
        int BUFR;
        BUFR=TM_MFRC522_ReadRegister(reg);
        BUFR=BUFR | mask;
        
    TM_MFRC522_WriteRegister(reg, BUFR);
            
        }
а вот в ней:
Код
uint8_t TM_MFRC522_ReadRegister(uint8_t addr)
    {
    uint8_t val;
    uint8_t j;
    j=addr;
    
    ZAPRC522[0] = (addr << 1) & 0x7E;
    ZAPRC522[0] = ZAPRC522[0] | 0x80;

    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
    BUFRC522[j]=OTVRC522[0];
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
    BUFRC522[j]=OTVRC522[0];
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
    BUFRC522[j]=OTVRC522[0];
    val = OTVRC522[0];
    return val;
        
    }
k155la3
Цитата(Pasa @ Jul 28 2016, 23:08) *
Никакого гадания нет. Уже давно все посмотрел. Потому и поднял тему, что не понятно каким образом аппартано в регистр DR залетает мусор и на выходе HAL-функции получаем полный бред, портящий буфер приема.
. . . .


0. Как выделена память под буфер и данные - проверьте "время жизни". Ведь при передаче в ф-ю вы используете адрес,
а оптимизатору-компилятору это ПОФИГ sm.gif
1. Ваш код работает в составе проекта или "отсажен" в минимальный вид для отладки.
(в смысле нет ли "сторонних" факторов влияния)
2. Я бы разобрался почему портится приемный буфер.
Заполните буфер паттерном.
Поставть на отладчике breakpoint типа "изменение памяти". Или вообще пошагово оттрасируйте состояние этй области.
Этот путь вылавливания демона проще всего - ведь есть "устойчивый сбой", и это хорошо sm.gif
Проверьте, ведь возможно работу ф-ии SPI сбивает вообще что-то другое, к ней не относящиеся.
3. Ну и классика - размеры стека итп.

ps к п.0:
Чтоб компилятор не своевольничал, я нужные переменные итд
объявляю в глоб. области, в виде
Код
__root char flag_Alarm;
#pragma required=flag_Alarm

(IAR)
alag57
Цитата(serglg @ Jul 29 2016, 11:12) *
Ну вот и моя хитрость


Это не хитрость. Это глупость. Вы не попытались разобраться, почему не работает
первый вариант и чего в нем не хватает. А не хватает только второго чтения из
вашей MRFC, так как данные отдаются следующим после адреса байтом.
serglg
Цитата(alag57 @ Jul 29 2016, 13:30) *
Это не хитрость. Это глупость. Вы не попытались разобраться, почему не работает
первый вариант и чего в нем не хватает. А не хватает только второго чтения из
вашей MRFC, так как данные отдаются следующим после адреса байтом.


Какого второго чтения?
Функция HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20) в первом байте передает адрес вторым байтом принимает.
Чувствую, что в HAL-драйверах какая-то засада при работе с 8-битным приемом.
Или? Вы намекаете что в функции HAL_SPI_TransmitReceive надо ставить не 2 байта а 4?
Pasa
На сегодняшний момент вызывает вопрос код в HAL_SPI_Init()

Код
  if(hspi->Init.DataSize > SPI_DATASIZE_8BIT)
  {
    frxth = SPI_RXFIFO_THRESHOLD_HF;
  }
  else
  {
    frxth = SPI_RXFIFO_THRESHOLD_QF;
    //frxth = SPI_RXFIFO_THRESHOLD_HF;   //  может надо здесь так?
  }


При установке 8-битного режима при инициализации SPI всегда делается frxth = SPI_RXFIFO_THRESHOLD_QF;
Хотя ручное прописывание frxth = SPI_RXFIFO_THRESHOLD_HF; не помогло...



Функция HAL_SPI_Receive() собственно сводится к вызову HAL_SPI_TransmitReceive().

В ней тоже вызывает вопрос вот это:

Код
  if((hspi->Init.DataSize > SPI_DATASIZE_8BIT) || (hspi->RxXferCount > 1))
  {
    /* set fiforxthreshold according the reception data length: 16bit */
    CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
  }
  else
  {
    /* set fiforxthreshold according the reception data length: 8bit */
    SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
    //CLEAR_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);   // может надо так?
  }


Хотя в stm32f0xx_hal_spi.h прописано вот это:

Код
/** @defgroup SPI_FIFO_reception_threshold SPI FIFO Reception Threshold
  * @{
  * This parameter can be one of the following values:
  *     SPI_RXFIFO_THRESHOLD or SPI_RXFIFO_THRESHOLD_QF :
  *          RXNE event is generated if the FIFO
  *          level is greater or equal to 1/2(16-bits).
  *     SPI_RXFIFO_THRESHOLD_HF: RXNE event is generated if the FIFO
  *          level is greater or equal to 1/4(8 bits). */
#define SPI_RXFIFO_THRESHOLD            SPI_CR2_FRXTH
#define SPI_RXFIFO_THRESHOLD_QF         SPI_CR2_FRXTH
#define SPI_RXFIFO_THRESHOLD_HF         ((uint32_t)0x00000000)



В результате на сегодняшнее утро предварительно помогла перед вызовом HAL_SPI_Receive() пачковая вычитка DR регистра:
Код
   dataX1=(uint16_t)hspi1.Instance->DR;
   dataX1=(uint16_t)hspi1.Instance->DR;
   dataX1=(uint16_t)hspi1.Instance->DR;
   dataX1=(uint16_t)hspi1.Instance->DR;
   HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf1[0], 1, 10000);


Но надо все проверить .... думаю к вечеру это дело прояснится


Цитата(k155la3 @ Jul 29 2016, 10:17) *
0. Как выделена память под буфер и данные - проверьте "время жизни". Ведь при передаче в ф-ю вы используете адрес,
а оптимизатору-компилятору это ПОФИГ sm.gif
1. Ваш код работает в составе проекта или "отсажен" в минимальный вид для отладки.
(в смысле нет ли "сторонних" факторов влияния)
2. Я бы разобрался почему портится приемный буфер.
Заполните буфер паттерном.
Поставть на отладчике breakpoint типа "изменение памяти". Или вообще пошагово оттрасируйте состояние этй области.
Этот путь вылавливания демона проще всего - ведь есть "устойчивый сбой", и это хорошо sm.gif
Проверьте, ведь возможно работу ф-ии SPI сбивает вообще что-то другое, к ней не относящиеся.
3. Ну и классика - размеры стека итп.

ps к п.0:
Чтоб компилятор не своевольничал, я нужные переменные итд
объявляю в глоб. области, в виде
Код
__root char flag_Alarm;
#pragma required=flag_Alarm

(IAR)


0. Буфер объявлен как глобальные переменные. Оптимизация компилера полностью отключена.
1. Собственно это начальный проект, но весь код отрублен и из main() вызывается единственный этот тестовый процесс чтения по SPI. Ничего лишнего нет. Все прерывания запрещены, кроме системного тика для HAL_Delay();
2. Собственно портится не сам буфер, а портится регистр DR.....ну и соответственно портится буфер
3. Стек не смотрел....но вроде ничего не делается для переполнения.

__root char flag_Alarm - эта штука для меня новинка, так как STM32 занимаюсь только около месяца....почитаю, разберусь и попробую применить...


Цитата(serglg @ Jul 29 2016, 12:06) *
Чувствую, что в HAL-драйверах какая-то засада при работе с 8-битным приемом.

У меня вот тоже ОЧЕНЬ-ОЧЕНЬ похожие чувства.....сильно похоже на засаду....еще в коде полностью не разобрался, но есть большое желание это все прошерстить
k155la3
Цитата(Pasa @ Jul 27 2016, 13:20) *
(1)
HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data1 = localRxBuf[0];
HAL_SPI_Receive(&hspi1, (uint8_t*)&localRxBuf[0], 1, 10000);
data2 = localRxBuf[0];
(2)
. . . .


Позволю себе.
Если после точки (1) Вы не упоминаете, и не используете явно массив localRxBuf, т.е.
Код
(2)
localRxBuf[2] =  localRxBuf[3] +  localRxBuf[4];  // обман компилятора
MyCalc( localRxBuf[2] );
.....

и тожесамое по data123, то даже при полностью отключенной оптимизации считайте, что массива в (1) уже нет.
Точнее, это компилятор так считает sm.gif И память которая там была, уже занята под другие данные (или не занята). Или там стек или ....
На то, что глобальное - не расчитыайте. Разве что есть на эти данные ссылка по extern из других модулей.
И это не оптимизация sm.gif
Pasa
Цитата(k155la3 @ Jul 29 2016, 13:33) *
Позволю себе.
Если после точки (1) Вы не упоминаете, и не используете явно массив localRxBuf, т.е.
Код
(2)
localRxBuf[2] =  localRxBuf[3] +  localRxBuf[4];  // обман компилятора
MyCalc( localRxBuf[2] );
.....

и тожесамое по data123, то даже при полностью отключенной оптимизации считайте, что массива в (1) уже нет.
Точнее, это компилятор так считает sm.gif И память которая там была, уже занята под другие данные (или не занята). Или там стек или ....
На то, что глобальное - не расчитыайте. Разве что есть на эти данные ссылка по extern из других модулей.
И это не оптимизация sm.gif


вы считаете что глобальный массив localRxBuf[] несмотря на то что он используетя в HAL_Recive() и далее
data1=localRxBuf[0] самопроизвольно исчезает????????????????????????????????????????????????????????????????????????????????????????????????????
w00t.gif excl.gif w00t.gif excl.gif w00t.gif excl.gif w00t.gif excl.gifw00t.gif excl.gifw00t.gif
k155la3
Цитата(Pasa @ Jul 29 2016, 13:55) *
вы считаете что глобальный массив localRxBuf[] несмотря на то что он используетя в HAL_Recive() и далее
data1=localRxBuf[0] самопроизвольно исчезает????????????????????????????????????????????????????????????????????????????????????????????????????
w00t.gif excl.gif w00t.gif excl.gif w00t.gif excl.gif w00t.gif excl.gifw00t.gif excl.gifw00t.gif

Если вы после приведенного фрагмента кода не используете явно data1,2,3.
- data1 после (2) не упоминается - так зачем он нужен ?
- элемент массива записывается в неупоминаемый data1 - так зачем он (массив) нужен ?
А то что вы в ф-ию передали &Var, и что этот адрес принадлежит именно Var - компилятор "не знает".
-------
В общем мои "смутные сомненья" Вы поняли. Это IMHO.
esaulenka
Цитата(k155la3 @ Jul 29 2016, 13:03) *
Позволю себе.
Если после точки (1) Вы не упоминаете, и не используете явно массив localRxBuf, т.е.
Код
(2)
localRxBuf[2] =  localRxBuf[3] +  localRxBuf[4];  // обман компилятора
MyCalc( localRxBuf[2] );
.....

и тожесамое по data123, то даже при полностью отключенной оптимизации считайте, что массива в (1) уже нет.
Точнее, это компилятор так считает sm.gif И память которая там была, уже занята под другие данные (или не занята). Или там стек или ....
На то, что глобальное - не расчитыайте. Разве что есть на эти данные ссылка по extern из других модулей.
И это не оптимизация sm.gif

Так. Ещё раз, медленно и по буквам.

Упрощаю до предела. Пишем
Код
void DoIt (char * p)
{
   for (int i = 0; i < 5; i++)
       p[i] = i;
}

....
char data[10];
DoIt (data);
// data больше не используем


Вы утверждаете, что DoIt() будет записывать не в data[], а портить стек?
Как интересно...
(да, я в курсе, что особо умный компилятор не будет делать НИЧЕГО - выкинет и массив, и функцию заполнения. Но изначальный этот HAL_SPI_Receive() выкинуть так просто нельзя - у него внутри volatile много).
alag57
Цитата(serglg @ Jul 29 2016, 13:36) *
Вы намекаете?

Нет, не намекаю, я привел рабочий код. Нормальное чтение из SPI у меня получилось только
после инициализации бита FRXTH при каждой передаче. Т.е. если длина передаваемых
данных больше 1 сбрасываем бит и передаем в 16-разрядном режиме, если длина передаваемых
данных равна 1 - устанавливаем бит FRXTH и передаем в 8 разрядном режиме. При этом
SPI настроен на SPI_DataSize_8b.

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

Надо бы еще попробовать инициализировать сначала CR2, затем CR1, как здесь отмечали,
может даст результат, хотя такого упоминания я нигде не нашел. И в SPL и в HAL(какой ужас,
специально сейчас вот посмотрел) сначала инициализируется CR1, затем CR2.
esaulenka
Цитата(serglg @ Jul 29 2016, 09:12) *
Ну вот и моя хитрость. Чтение делаю 3 (три) раза подряд.


Извините за резкость, но, может быть, стоило разик подумать?..
В даташите прямо картинками нарисовано, даже читать особо не надо:
- записать адрес регистра0
- считать мусор
- записать адрес регистра1
- считать данные регистра0


Код
uint8_t TM_MFRC522_ReadRegister(uint8_t addr)
{
    uint8_t cmd[2];
    uint8_t answ[2];

    cmd[0]=cmd[1]= (addr << 1) | 0x80;

    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, cmd, answ, 2, 20);
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);

    return answ[1];
}

Pasa
может здесь и говорится о нашей проблемке ..... страница 9

Цитата(k155la3 @ Jul 29 2016, 15:42) *
Если вы после приведенного фрагмента кода не используете явно data1,2,3.
- data1 после (2) не упоминается - так зачем он нужен ?
- элемент массива записывается в неупоминаемый data1 - так зачем он (массив) нужен ?
А то что вы в ф-ию передали &Var, и что этот адрес принадлежит именно Var - компилятор "не знает".
-------
В общем мои "смутные сомненья" Вы поняли. Это IMHO.


возможно есть такие сверхумные компиляторы...с суппероптимизацией....я пока до сих пор с такими "глубокими" эффектами не сталкивался.
Неиспользуемые переменные, невызываемые функции, глухие циклы для задержек - это я видел, убирает на раз.
Но чтобы компилятор отслеживал всю цепочку присвоений, да еще глобальных переменных.... Возможно такое и есть.
Но возникает вопрос работы с указателями. И какова "глубина" этих цепочек.
Если к примеру:
Код
int a1,a2,a3............................a999;
a1=0;
a2=a1;
a3=a2;
......
a999 = a998;

data1= a999;


Если все эти строки разбросаны по сотням тысяч строк кода, и не будет присвоения data1=a999 то все уберется?
А если будет присвоение data1=a999, то компилер полезет искать использование data1 во всем проекте и участие data1 в многочисленных структурах, массивах, указателях, функциях. И соотвественно начнет смотреть на использование этих структур,массивов, функций в проекте...и так далее и так до бесконечности?
Утверждать стопроцентно не буду....но есть у меня сомнения....
serglg
Открываются глаза. Народ говорит, что вся разница в том, что 'L4 есть "Data packing", а вот в семействах STM32f4... его нет.
Pasa
На сегодняшний момент моя примочка по предварительной очистке DR регистра успешно опробована, все работает, обмен с CC2500 идет нормально. Будем надеятся, что в следующих ревизиях все поправят.
serglg
Цитата(Pasa @ Aug 1 2016, 13:57) *
На сегодняшний момент моя примочка по предварительной очистке DR регистра успешно опробована, все работает, обмен с CC2500 идет нормально. Будем надеятся, что в следующих ревизиях все поправят.


Фактически я делаю то же самое, но другим способом. :-)
Pasa
Цитата(serglg @ Aug 1 2016, 15:44) *
Фактически я делаю то же самое, но другим способом. :-)

Собственно так и есть. Единственно - я напрямую читаю DR без вызова HAL-функции. Тройной вызов HAL_Recive() думается достаточно сильно замедляет многобайтовое чтение.
Хотя там где скорости не важны, то можно делать как кому больше нравится.
serglg
Цитата(Pasa @ Aug 2 2016, 01:24) *
Собственно так и есть. Единственно - я напрямую читаю DR без вызова HAL-функции. Тройной вызов HAL_Recive() думается достаточно сильно замедляет многобайтовое чтение.
Хотя там где скорости не важны, то можно делать как кому больше нравится.


Ну да, там у меня чтение нескольких байт за 25 мсек.
Хотя прямое чтение DR - это надо иметь в виду.
Теперь скоро буду с 1-мегабайтной памятью по SPI работать.
Вот там посмотрим. :-)
ave!
Прочитал всю ветку, пробовал все варианты под CooCox и Keil, SPL и HAL - у меня не работает на STM32F030K6.

На STM32F103С8 у меня работает и SPL и HAL - https://zxlogin.com/stm/stm32f103-rc522+hal.zip

Поделитесь рабочим кодом под STM32F030 для RC522.
serglg
Цитата(ave! @ May 10 2017, 00:34) *
Прочитал всю ветку, пробовал все варианты под CooCox и Keil, SPL и HAL - у меня не работает на STM32F030K6.

На STM32F103С8 у меня работает и SPL и HAL - https://zxlogin.com/stm/stm32f103-rc522+hal.zip

Поделитесь рабочим кодом под STM32F030 для RC522.


Могу только предложить то, что у меня работает для STM32L476.

Куб проиницилизировал SPI так (8 бит, 5 МГц):

Код
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_16;
  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();
  }

}


Все функции в файле - mfrc522.c (прикладываю).
После запуска моей программы - инициализация RC522:

Код
void TM_MFRC522_Init(void)
    {
    TM_MFRC522_Reset();

    TM_MFRC522_WriteRegister(MFRC522_REG_T_MODE, 0x8D);
    TM_MFRC522_WriteRegister(MFRC522_REG_T_PRESCALER, 0x3E);
    TM_MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_L, 30);          
    TM_MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_H, 0);

    /* 48dB gain */
    TM_MFRC522_WriteRegister(MFRC522_REG_RF_CFG, 0x70);
    
    TM_MFRC522_WriteRegister(MFRC522_REG_TX_AUTO, 0x40);
    TM_MFRC522_WriteRegister(MFRC522_REG_MODE, 0x3D);

    TM_MFRC522_AntennaOn();        //Open the antenna
        
    }


Потом для чтения ID карты вызываю:

Код
                STAT=TM_MFRC522_Check(CardID);
                SC522=0;
                if (STAT==0)
                    {
                                        }


Все мои беды в прошлом году были с буфером Фифо в STM32.
И всё поперло после глупости, что я применил при чтении регистров RC522:

Код
uint8_t TM_MFRC522_ReadRegister(uint8_t addr)
    {
    uint8_t val;
    
    ZAPRC522[0] = (addr << 1) & 0x7E;
    ZAPRC522[0] = ZAPRC522[0] | 0x80;

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    val = OTVRC522[0];
        
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    val = OTVRC522[0];

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    HAL_SPI_TransmitReceive(&hspi1, ZAPRC522, OTVRC522, 2, 20);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    val = OTVRC522[0];
        
    return val;
        
    }


Глупость в 3-кратном чтении одно и того же.
Но работает.
Но работает только с HAL-драйверами для STM32L4... не позже октября 2016 (версия 1.5.0).
После их обновления в феврале (версия 1.7.0) перестала работать.
Я смотрел отличия - ребята пытались как раз что-то замутить с фифо.
Но я убирал своё 3-краное чтение, комбинировал всяко, но облом.
Пришлось вернуться на драйверы октября 2016 и так оставить.
Похоже вопрос с 8-битным чтением по SPI в STM32 (через HAL) так нормально и не решен.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.