cancel
Showing results for 
Search instead for 
Did you mean: 

SPI1 DMA hardware nSS control for use with Wiznet W5500 network chip.

Gordon Freemansky
Associate II

Good day everyone.

I'm trying to get Wiznet made W5500 working with STM32F030 series, using SPI in DMA mode.

Unfortunately, in nSS hardware output mode, SPI bus pulls up nSS line after every transmitted byte (see attached image), while W5500 manual states, that nSS line should be low during whole transaction.

I'm not professional. Using Cube MX for device configuration.

Here is the MX generated code for SPI+DMA setup:

void MX_SPI1_Init(void)

{

 LL_SPI_InitTypeDef SPI_InitStruct = {0};

 LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* Peripheral clock enable */

 LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_SPI1);

 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

 /**SPI1 GPIO Configuration 

 PA4  ------> SPI1_NSS

 PA5  ------> SPI1_SCK

 PA6  ------> SPI1_MISO

 PA7  ------> SPI1_MOSI

 */

 GPIO_InitStruct.Pin = SPI1_nSS_Pin;

 GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

 GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

 GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

 GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

 LL_GPIO_Init(SPI1_nSS_GPIO_Port, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = SPI1_SCK_Pin;

 GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

 GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

 GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

 GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

 LL_GPIO_Init(SPI1_SCK_GPIO_Port, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = SPI1_MISO_Pin;

 GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

 GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

 GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

 GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

 LL_GPIO_Init(SPI1_MISO_GPIO_Port, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = SPI1_MOSI_Pin;

 GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

 GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

 GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

 GPIO_InitStruct.Alternate = LL_GPIO_AF_0;

 LL_GPIO_Init(SPI1_MOSI_GPIO_Port, &GPIO_InitStruct);

 /* SPI1 DMA Init */

 /* SPI1_RX Init */

 LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

 LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_MEDIUM);

 LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);

 LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);

 LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);

 LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);

 LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);

 /* SPI1_TX Init */

 LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

 LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_VERYHIGH);

 LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);

 LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);

 LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);

 LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_HALFWORD);

 LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_HALFWORD);

 /* SPI1 interrupt Init */

 NVIC_SetPriority(SPI1_IRQn, 1);

 NVIC_EnableIRQ(SPI1_IRQn);

 SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;

 SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;

 SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;

 SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;

 SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;

 SPI_InitStruct.NSS = LL_SPI_NSS_HARD_OUTPUT;

 SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV64;

 SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;

 SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;

 SPI_InitStruct.CRCPoly = 7;

 LL_SPI_Init(SPI1, &SPI_InitStruct);

 LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);

 LL_SPI_EnableNSSPulseMgt(SPI1);

}

Any ideas?

14 REPLIES 14
Gordon Freemansky
Associate II

Thanks Jan.

Well noted.

Actually the nSS pin (GPIOA Pin4) is configured as a push-pull (alternative) with no pull-up in case of hardware mode, but, according to Wiz850 schematic, there is a separate pull-up resistor on this line. Will keep it in mind.

Now I'm facing another problem. With no regards to nSS mode I use (tried bot hardware and software managed GPIO), SPI transmit function hangs up after sending a set of data. I found that, for some reason, TCIF2 stays 0 and DMA_CNDTR2 register indicates that one byte still left to read, while all data is in. For example I'm trying to read Retry Time-value Register from W5500, and I can see the correct (default) value in last two bits = 0x07D0.

Gordon Freemansky
Associate II

Just found, that it happens only if I try to transmit odd amount of bytes. If I transmit even amount, then there is no problem.

Any Idea why?

TDK
Guru

> LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_HALFWORD);

> LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_HALFWORD);

If you want to send an odd number of bytes, set the size to byte. Currently it only sends a half word at a time.

If you feel a post has answered your question, please click "Accept as Solution".
Gordon Freemansky
Associate II

LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER) helped to sort out the last issue...

Gordon Freemansky
Associate II

Hi Jan. Hi TDK.

Thanks a lot for your help, gentlemen! Much appreciated!

Looks like one of the key moments in SPI DMA configuration is FIFO threshold. After setting it to LL_SPI_RX_FIFO_TH_QUARTER everything worked without issues.

Added LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER); after SPI initialization.

The strings

LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_HALFWORD);

LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_HALFWORD);

were replaced to

 LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);

 LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);

 soon after the first post.

I managed to get both software and hardware driven nSS working! In second case I had to alter W5500.c file, and change one string in WIZCHIP_WRITE_BUF function:

      WIZCHIP.IF.SPI._write_burst(spi_data, 3);

      //WIZCHIP.IF.SPI._write_burst(pBuf, len);

      WIZCHIP.IF.SPI._read_burst(pBuf, len); //Replaced from _write_burst to _read_burst to be able to use hardware nSS

So far no problems spotted with (hardware driven nSS) SPI speeds up to 18MHz, even if I use 10-15sm long link cable between STM and Wiznet chips.

Pinging the module successfully.