W5500 Ethernet shield spi dma rx 데이터 수신이 안됩니다.

안녕하세요.
현재 stm32h7 mcu 보드에 W5500 이더넷쉴드를 연결하여 통신기능 테스트중입니다.
기존에 5100S 이더넷 쉴드 모듈을 이용하여 개발하다 여러가지 문제로
W5500 이더넷쉴드 모듈로 변경하였습니다.

기존 W5100S 모듈에서 SPI 통신기능을 DMA를 활성화해서 데이터 송수신이 정상적으로
동작하는것을 확인하였고…
동일 MCU 보드에 W5500 이더넷쉴드만 변경하였습니다.
위즈넷 IO Library는 gitHub에서 최근 버전으로 다운받아서 적용했습니다.
증상은 위에 말씀드린대로 SPI를 DMA모드로 설정 시
TX 데이터는 전송되지만 RX 데이터가 항상 0으로 읽힙니다.
SPI 설정 시 TX만 DMA를 설정하고 RX는 DMA 설정을 하지 않으면 정상 동작합니다.
SPI 클럭은 25Mhz를 사용중입니다.

아래는 코드입니다.

/* Definition for SPIx Pins */
#define SPIx_NSS_PIN GPIO_PIN_12
#define SPIx_NSS_GPIO_PORT GPIOB
#define SPIx_NSS_AF GPIO_AF5_SPI2
#define SPIx_SCK_PIN GPIO_PIN_13
#define SPIx_SCK_GPIO_PORT GPIOB
#define SPIx_SCK_AF GPIO_AF5_SPI2
#define SPIx_MISO_PIN GPIO_PIN_14
#define SPIx_MISO_GPIO_PORT GPIOB
#define SPIx_MISO_AF GPIO_AF5_SPI2
#define SPIx_MOSI_PIN GPIO_PIN_15
#define SPIx_MOSI_GPIO_PORT GPIOB
#define SPIx_MOSI_AF GPIO_AF5_SPI2

/* Definition for SPIx’s NVIC */
#define SPIx_IRQn SPI2_IRQn
#define SPIx_IRQHandler SPI2_IRQHandler

/* SPI2 DMA Setting */
#define DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
#define SPIx_TX_DMA_STREAM DMA1_Stream3
#define SPIx_RX_DMA_STREAM DMA1_Stream2
#define SPIx_TX_DMA_REQUEST DMA_REQUEST_SPI2_TX
#define SPIx_RX_DMA_REQUEST DMA_REQUEST_SPI2_RX
#define SPIx_DMA_TX_IRQn DMA1_Stream3_IRQn
#define SPIx_DMA_RX_IRQn DMA1_Stream2_IRQn
#define SPIx_DMA_TX_IRQHandler DMA1_Stream3_IRQHandler
#define SPIx_DMA_RX_IRQHandler DMA1_Stream2_IRQHandler

int InitSPI2(void)
{
/##-1- Configure the SPI peripheral #######################################/
/* Set the SPI parameters */

g_hSpi2.Instance = SPIx;
//g_hSpi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 50Mhz
g_hSpi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 25Mhz
//g_hSpi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 12.5Mhz

g_hSpi2.Init.Mode = SPI_MODE_MASTER;
g_hSpi2.Init.Direction = SPI_DIRECTION_2LINES;
g_hSpi2.Init.CLKPhase = SPI_PHASE_2EDGE; // SPI Mode3
g_hSpi2.Init.CLKPolarity = SPI_POLARITY_HIGH; // SPI Mode3
g_hSpi2.Init.DataSize = SPI_DATASIZE_8BIT;
g_hSpi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
g_hSpi2.Init.TIMode = SPI_TIMODE_DISABLE;
g_hSpi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
g_hSpi2.Init.CRCPolynomial = 7;
g_hSpi2.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
g_hSpi2.Init.NSS = SPI_NSS_SOFT;
g_hSpi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
g_hSpi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
/*
g_hSpi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
g_hSpi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
g_hSpi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
g_hSpi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
g_hSpi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
//g_hSpi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
g_hSpi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_ENABLE;
g_hSpi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
*/
g_hSpi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; // Recommanded setting
// to avoid glitches

if(HAL_SPI_Init((SPI_HandleTypeDef*)&g_hSpi2) != HAL_OK)
return 0;

return 1;
}

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;

if (hspi->Instance == SPIx)
{
/##-1- Enable peripherals and GPIO Clocks #################################/
/* Enable GPIO TX/RX clock */
SPIx_SCK_GPIO_CLK_ENABLE();
SPIx_MISO_GPIO_CLK_ENABLE();
SPIx_MOSI_GPIO_CLK_ENABLE();

#ifdef SPI2_DMA
DMAx_CLK_ENABLE();
#endif

/* Enable SPI clock */
SPIx_CLK_ENABLE();

/*##-2- Configure peripheral GPIO ##########################################*/
GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;

/* SPI SCK GPIO pin configuration  */    
GPIO_InitStruct.Pin       = SPIx_SCK_PIN;
GPIO_InitStruct.Alternate = SPIx_SCK_AF;
HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);

/* SPI MISO GPIO pin configuration  */
GPIO_InitStruct.Pin = SPIx_MISO_PIN;
GPIO_InitStruct.Alternate = SPIx_MISO_AF;
HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);

/* SPI MOSI GPIO pin configuration  */
GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
HAL_GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStruct);

/* SPI NSS GPIO pin configuration  */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Pin = SPIx_NSS_PIN;
GPIO_InitStruct.Alternate = SPIx_NSS_AF;
GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SPIx_NSS_GPIO_PORT, &GPIO_InitStruct);

HAL_GPIO_WritePin(SPIx_NSS_GPIO_PORT, SPIx_NSS_PIN, GPIO_PIN_RESET); // SPI NSS

#ifdef SPI2_DMA
// Spi2 tx dma setting
g_hDmaSpi2_tx.Instance = SPIx_TX_DMA_STREAM;
g_hDmaSpi2_tx.Init.Request = SPIx_TX_DMA_REQUEST;
g_hDmaSpi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
g_hDmaSpi2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
g_hDmaSpi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
g_hDmaSpi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
g_hDmaSpi2_tx.Init.PeriphBurst = DMA_MBURST_SINGLE;
g_hDmaSpi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
g_hDmaSpi2_tx.Init.MemInc = DMA_MINC_ENABLE;
g_hDmaSpi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
g_hDmaSpi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
g_hDmaSpi2_tx.Init.Mode = DMA_NORMAL;
//g_hDmaSpi2_tx.Init.Priority = DMA_PRIORITY_LOW;
g_hDmaSpi2_tx.Init.Priority = DMA_PRIORITY_MEDIUM;

if(HAL_DMA_Init(&g_hDmaSpi2_tx) != HAL_OK)
{
  return;
}

__HAL_LINKDMA(hspi, hdmatx, g_hDmaSpi2_tx);

// Spi2 rx dma setting
g_hDmaSpi2_rx.Instance = SPIx_RX_DMA_STREAM;
g_hDmaSpi2_rx.Init.Request = SPIx_RX_DMA_REQUEST;
g_hDmaSpi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
g_hDmaSpi2_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
g_hDmaSpi2_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
g_hDmaSpi2_rx.Init.MemBurst = DMA_MBURST_SINGLE;
g_hDmaSpi2_rx.Init.PeriphBurst = DMA_MBURST_SINGLE;
g_hDmaSpi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
g_hDmaSpi2_rx.Init.MemInc = DMA_MINC_ENABLE;
g_hDmaSpi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
g_hDmaSpi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
g_hDmaSpi2_rx.Init.Mode = DMA_NORMAL;
g_hDmaSpi2_rx.Init.Priority = DMA_PRIORITY_HIGH;

if(HAL_DMA_Init(&g_hDmaSpi2_rx) != HAL_OK)
{
  return;
}
__HAL_LINKDMA(hspi, hdmarx, g_hDmaSpi2_rx);

#endif

/*##-3- Configure the NVIC for SPI #########################################*/
/* NVIC for SPI */
HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPIx_IRQn);

#ifdef SPI2_DMA
HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);

//HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
//HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);

#endif
}
}

아래는 Wiznet 초기화 및 통신 함수입니다.

int Init_W5500(void)
{
wizchip_deselect();

// register callback funtions
{
reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);

reg_wizchip_spi_cbfunc(wizchip_read, wizchip_write);

reg_wizchip_spiburst_cbfunc(wizchip_burst_read, wizchip_burst_write);

}

// wizchip initialize
uint8_t tmp;
intr_kind temp;
//uint8_t memsize[2][8] = { {2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,2,2} };
uint8_t memsize[2][8] = { {8,8,0,0,0,0,0,0}, {8,8,0,0,0,0,0,0} };
//uint8_t memsize[2][8] = { {16,0,0,0,0,0,0,0}, {8,0,0,0,0,0,0,0} };

//wiz_PhyConf PhyConfigInfo;

temp = IK_DEST_UNREACH;

if(ctlwizchip(CW_INIT_WIZCHIP, (void*)memsize) == -1)
return 0;

if(ctlwizchip(CW_SET_INTRMASK, &temp) == -1)
{
//printf(“W5500 interrupt\r\n”);
return 0;
}

do {
if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
return 0;
}while(tmp == PHY_LINK_OFF);

return 1;
}

static void wizchip_select(void)
{
HAL_GPIO_WritePin(SPIx_NSS_GPIO_PORT, SPIx_NSS_PIN, GPIO_PIN_RESET);
}

static void wizchip_deselect(void)
{
HAL_GPIO_WritePin(SPIx_NSS_GPIO_PORT, SPIx_NSS_PIN, GPIO_PIN_SET);
}

static uint8_t wizchip_rw(uint8_t byte)
{
uint8_t iReadByte = 0x00;
HAL_SPI_TransmitReceive(&g_hSpi2, &byte, &iReadByte, 1, 10);
return iReadByte;
}

static uint8_t wizchip_read(void)
{
return wizchip_rw(0xff);
}

static void wizchip_write(uint8_t wb)
{
wizchip_rw(wb);
}

static void wizchip_burst_write(uint8_t *pData, uint16_t len)
{
#ifdef SPI2_DMA
memcpy(g_aSpiSendBuf, pData, len);

//SCB_CleanDCache_by_Addr((uint32_t*)g_aSpiSendBuf, len);

g_aSpiDmaCplt[0] = 0;

HAL_SPI_Transmit_DMA(&g_hSpi2, g_aSpiSendBuf, len);
//HAL_SPI_TransmitReceive_DMA(&g_hSpi2, g_aSpiSendBuf, g_aSpiRecvBuf, len);

while(1) // DMA TX 완료 인터럽트가 수신될때까지 대기
{
if(g_aSpiDmaCplt[0] == 1)
break;
}

#else
HAL_SPI_Transmit(&g_hSpi2, pData, len, 1000);
#endif
}

static void wizchip_burst_read(uint8_t *pData, uint16_t len)
{
#ifdef SPI2_DMA
g_aSpiDmaCplt[1] = 0;

//SCB_CleanDCache_by_Addr((uint32_t*)g_aSpiRecvBuf, len);

HAL_SPI_TransmitReceive_DMA(&g_hSpi2, g_aSpiSendBuf, g_aSpiRecvBuf, len);

while(1) // DMA RX 완료 인터럽트가 수신될때까지 대기
{
if(g_aSpiDmaCplt[1] == 1)
break;
}

// SCB_InvalidateDCache_by_Addr((uint32_t*)g_aSpiRecvBuf, len);

memcpy(pData, g_aSpiRecvBuf, len);

#else
uint8_t aTmpBuf[8192];
HAL_SPI_TransmitReceive(&g_hSpi2, aTmpBuf, pData, len, 1000);
#endif
}

Hello,
I have same issue with STM32H723. I found some fixes for DMA memory address.

DMA can’t access everywhere on memory so I think we should re-locate dma variables on memory.