Skocz do zawartości

PN532 - brak odpowiedzi na linii MISO, dziwny syf na linii MOSI


DeadGeneratio

Pomocna odpowiedź

Dzień dobry, mam pytanie odnośnie modułu PN532. Podłączyłem go po SPI do stm32 w trybie full duplex i badam jego dziwne zachowanie analizatorem logicznym. Wysyłając proste ramki otrzymuję kompletny brak odpowiedzi na linii MISO, a linia MOSI czasami zawiera takie dziwne rzeczy, że nie wiem co o tym myśleć. Tutaj ramka wake-up:

image.thumb.png.5fbc831e105326573469b5e109df10b8.png 

Nie spodziewam się odpowiedzi więc nie ustawiam stm na tryb odbierania. Chwilę po tym ustawiam moduł na szukanie kart w pobliżu:

image.thumb.png.c51bff410995f91e81b28af3822f709b.png

Także nie spodziewam się odpowiedzi. I przechodzę do sprawdzenia wersji firmware:

image.thumb.png.cac80a7a71f058b707dc28a82e37e16c.png

Tutaj zaczyna dziać się magia. Wysyłam D4 02, a następnie ustawiam na odczyt. I zamiast odczytać cokolwiek, na linii MOSI pojawiają się powtórzone komendy w odwrotnej kolejności, pomieszane - D4 14 01 itd. Na lini MISO odpowiedzi na temat firmware nie otrzymałem, a dalej robi się jeszcze ciekawiej. D4 4A 01 00 wyszukuje karty w okolicy, więc naturalnym jest, że po nadaniu komendy, przestawiam się na tryb nasłuchu. I dostaję po chwili kompletny szum danych na lini MOSI, a linia MISO pozostaje głucha. Każde kolejne sprawdzenie wygląda już lepiej, bo komendy się nie powtarzają jak w powyższym przypadku:

image.thumb.png.4fb6962ddbc16d68515a79fef1eacc04.png

Jednak odpowiedzi nie dostaję takiej jaką bym chciał, bo powinno zwrócić ramkę o ilości urządzeń znalezionych czyli 0 itd. Ktoś wie dlaczego pojawia się taki syf na liniach transmisyjnych? Plik main.c:

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "PN532.h"
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN PV */
uint8_t firmware[4];  // Tablica na dane o firmware
uint8_t cardUID[7];   // Bufor na UID karty
volatile uint8_t responseReady = 0;  // Flaga wskazująca na gotowość odpowiedzi
uint8_t response[20];  // Bufor odpowiedzi z PN532
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// Funkcja do skanowania w poszukiwaniu kart NFC

// Funkcja do listowania pasywnych tagów NFC (karty) i odczytu UID
void PN532_InListPassiveTarget() {
    uint8_t command[] = { 0xD4, 0x4A, 0x01, 0x00 };  // Komenda InListPassiveTarget
    uint8_t response[20];  // Bufor na odpowiedź

    // Wysyłanie komendy
    PN532_SendCommand_IT(command, sizeof(command));
    while (!txComplete);  // Oczekiwanie na zakończenie transmisji

    // Odbieranie odpowiedzi
    PN532_ReadData_IT(response, sizeof(response));
    while (!rxComplete);  // Oczekiwanie na zakończenie odbioru

    // Przetwarzanie odpowiedzi
    if (response[0] == 0xD5 && response[1] == 0x4B) {
        // Poprawna odpowiedź, tag (karta) został wykryty

        uint8_t numTags = response[7];  // Liczba wykrytych tagów
        if (numTags > 0) {
            uint8_t uidLength = response[12];  // Długość UID karty
            uint8_t uid[uidLength];
            memcpy(uid, &response[13], uidLength);  // Skopiowanie UID do bufora
        }
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
  HAL_Delay(100);
	PN532_Wakeup();
	PN532_GetFirmwareVersion(firmware);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	while (1) {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		PN532_InListPassiveTarget();
		HAL_Delay(100);
	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  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_32;
  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();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SS_GPIO_Port, SS_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : SS_Pin */
  GPIO_InitStruct.Pin = SS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SS_GPIO_Port, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
// Callback wywoływany po zakończeniu transmisji
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi->Instance == hspi1.Instance) {
        txComplete = 1;  // Ustawiamy flagę zakończenia transmisji
        PN532_Unselect();  // Kończymy transmisję (CS na high)
    }
}

// Callback wywoływany po zakończeniu odbioru danych
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi->Instance == hspi1.Instance) {
        rxComplete = 1;  // Ustawiamy flagę zakończenia odbioru
        PN532_Unselect();  // Kończymy odbiór (CS na high)
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1) {
	}
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Mój utworzony plik PN532.h:

#include "stm32g4xx_hal.h"

extern SPI_HandleTypeDef hspi1;

#define PN532_SPI_CS_PIN GPIO_PIN_4
#define PN532_SPI_CS_PORT GPIOA

#define PN532_SPI_READY_TIMEOUT 100

#define PN532_CMD_GETFIRMWAREVERSION 0x02
#define PN532_CMD_SAMCONFIGURATION   0x14


volatile uint8_t txComplete = 0;
volatile uint8_t rxComplete = 0;
uint8_t spiResponseBuffer[20];

void PN532_Select() {
	HAL_GPIO_WritePin(PN532_SPI_CS_PORT, PN532_SPI_CS_PIN, GPIO_PIN_RESET);
}

void PN532_Unselect() {
	HAL_GPIO_WritePin(PN532_SPI_CS_PORT, PN532_SPI_CS_PIN, GPIO_PIN_SET);
}

void PN532_SendCommand_IT(uint8_t *cmd, uint8_t cmdlen) {
	PN532_Select();
	txComplete = 0;
	HAL_SPI_Transmit_IT(&hspi1, cmd, cmdlen);
}

void PN532_ReadData_IT(uint8_t *buffer, uint8_t length) {
	PN532_Select();
	rxComplete = 0;
	HAL_SPI_Receive_IT(&hspi1, buffer, length);
}

void PN532_Wakeup(void) {
	uint8_t wakeupCommand[] = { 0x55, 0x55, 0x00, 0x00, 0x00 };
	PN532_SendCommand_IT(wakeupCommand, sizeof(wakeupCommand));
	while (!txComplete)
		;
	HAL_Delay(10);
	uint8_t samConfigCommand[] = { 0xD4, 0x14, 0x01, 0x14, 0x01 };
	PN532_SendCommand_IT(samConfigCommand, sizeof(samConfigCommand));
	while (!txComplete)
		;
	HAL_Delay(100);
}



void PN532_GetFirmwareVersion() {
	uint8_t command[] = { 0xD4, 0x02 };
	uint8_t response[12];

	PN532_SendCommand_IT(command, sizeof(command));
	while (!txComplete)
		;

	PN532_ReadData_IT(response, sizeof(response));
	while (!rxComplete)
		;
}

 

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.