cancel
Showing results for 
Search instead for 
Did you mean: 

SPI with extra CE# pulse and not enough bytes

RLosc.1
Associate II

Hey,

I'm a beginner.

I'm working with STM32F303RET6 and I'm trying to communicate with SST26VF064B (Flash) over SPI.

This is how I configured my SPI (Using MXCuce):

static void MX_SPI2_Init(void)
{
 
  /* USER CODE BEGIN SPI2_Init 0 */
 
  /* USER CODE END SPI2_Init 0 */
 
  /* USER CODE BEGIN SPI2_Init 1 */
 
  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
 
  /* USER CODE END SPI2_Init 2 */
 
}

I'm expecting to receive a byte of data by doing so:

static void Read_Flash(unsigned char *buffer, uint8_t add0, uint8_t add1, uint8_t add2)
{
	unsigned char TX[4];
	TX[0] = READ;
	TX[1] = add0;
	TX[2] = add1;
	TX[3] = add2;
	HAL_SPI_TransmitReceive_IT(&hspi2, &TX, &buffer, 5);
}

I was not getting any answer from the flash so I looked at it's pins with a scope and noticed that it's not behaving as the datasheet of the Flash is expecting to.

0693W000001sUQpQAM.png

As you can see in the picture above, once you start communicating with the flash, the CE# goes low and stays low throughout the entire communication.

Now in my case there's 2 problems:

  1. The CE# goes low before every byte of data and then goes up again. creating this narrow pulses before each byte.
  2. I can only send 2 bytes (in my case it sends TX[0] and TX[1]). for some reason it stops sending after the seconds byte.

What am I doing wrong?

Thanks in advance,

Rony.

1 ACCEPTED SOLUTION

Accepted Solutions

> hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;

Read in SPI chapter of RM, what does this mean.

Don't try to use the hardware NSS, set it up as GPIO Output and manipulate it "manually".

Don't use a non-static local variable as buffer, it ceases to exist when you leave the function.

> I can only send 2 bytes

I don't know why, but Cube is open source, debug it as your own coffee, if you want to use it and have problems with it.

JW

View solution in original post

6 REPLIES 6

> hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;

Read in SPI chapter of RM, what does this mean.

Don't try to use the hardware NSS, set it up as GPIO Output and manipulate it "manually".

Don't use a non-static local variable as buffer, it ceases to exist when you leave the function.

> I can only send 2 bytes

I don't know why, but Cube is open source, debug it as your own coffee, if you want to use it and have problems with it.

JW

Hey,

I should have mentioned I'm a beginner.

I'm not quite sure what the RM is.

any way I tried changing hspi2.Init.NSSPMode from "SPI_NSS_PULSE_ENABLE" to "SPI_NSS_PULSE_DISABLE" and it's not the solution for now the CE# goes low and stays low forever.

And what do you mean by "debug it as your own coffee"?

Rony.

TDK
Guru

> I'm not quite sure what the RM is.

RM = reference manual. This is the best source of information on how the chip works.

Go here and select Resources -> Reference Manuals.

https://www.st.com/en/microcontrollers-microprocessors/stm32f303re.html

> I tried changing hspi2.Init.NSSPMode from "SPI_NSS_PULSE_ENABLE" to "SPI_NSS_PULSE_DISABLE" and it's not the solution for now the CE# goes low and stays low forever.

Jan suggested changing the CE# pin to a GPIO pin and controlling its state manually. I second this suggestion.

Unless you specifically need interrupt mode, I'd recommend using the blocking mode of transmission and it's conceptually easier. Something like:

HAL_GPIO_WritePin(...); // <-- set CS low
HAL_SPI_TransmitReceive(&hspi2, &TX, &buffer, 5);
HAL_GPIO_WritePin(...); // <-- set CS high

If you feel a post has answered your question, please click "Accept as Solution".
LMI2
Lead

Using CS like TDK and RLosc.1 have shown, is one problem less. Do it. HAL SPI works but at first it is difficult when you can't see is the problem with your HW settings, how you drive the memory or in your program. An oscilloscope or a logic analyser helps a lot.

It looks like a Flash rom is not so simple as a user might think. Have you anything easier to begin with?

Here is a working SPI HAL driving MAX31865 temperature sensor board from Adafruit. The whole main.c is too long to fit. It is for STM32H750 and anyway CPU pins should be checked with CubeMX.

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_RESET);	//cs 0
HAL_Delay(5);	
txBuffer[0]=0x80;//
txBuffer[1]=0x83;//
HAL_SPI_Transmit(&hspi1,(uint8_t*)txBuffer,2,1000);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_SET);	//cs 1
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
HAL_Delay(5);
 
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_RESET);	//cs 0
HAL_Delay(5);	
txBuffer[0]=0x80;//
txBuffer[1]=0xc3;//
HAL_SPI_Transmit(&hspi1,(uint8_t*)txBuffer,2,1000);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_SET);	//cs 1
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
HAL_Delay(5);	
 
	
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_RESET);	//cs 0
//HAL_Delay(5);	
 
txBuffer[0]=0x00;//
txBuffer[1]=0x01;//
txBuffer[2] = 0x02;
txBuffer[3]=0x03;
txBuffer[4] = 0x04;
txBuffer[5]=0x05;
txBuffer[6] = 0x06;
txBuffer[7]=0x07;
txBuffer[8] = 0x08;
txBuffer[9]=0x09;
nollaatx(8);
HAL_SPI_TransmitReceive(&hspi1,(uint8_t*)txBuffer,	(uint8_t*)rxBuffer,	8,1000);
// lukiarray(txBuffer,rxBuffer,8) ;
 printtaa(8);//print 2 and 3 and the rest
 
 lamp1=rxBuffer[2]*256;
 lamp1=lamp1+(rxBuffer[3]);
 lamp1=lamp1/2; //bit zero is extra, an error bit, throw it away., 32768
 lampf=lamp1;
 lampf2=lamp1;
 lampf=lampf*430/32768;  //Rrtd datasheet  page 19
 
strcpy(msg, "");
//sprintf(msg ,"rxBuffer %x \n\r",rxBuffer[laskuri]);
sprintf(msg ,"PT100 Resistance %f4.0 \n\r",lampf);	
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 1000);	
strcpy(msg, "");
lampf=((lampf/100.0)-1.0)/(0.003851);
sprintf(msg ,"Temperature Celsius %f4.0 \n\r",lampf);	
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 1000);	
strcpy(msg, "");		
HAL_SPI_Transmit(&hspi1,(uint8_t*)txBuffer,2,1000);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3,GPIO_PIN_SET);	//cs 1
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//clk 1
//HAL_Delay(5);	
		/* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

>> "debug it as your own coffee"

Sorry, mobile phone posting + autocorrect. I meant, "your own code".

Nonetheless, you always want your coffee bug-free, don't you? ;)

JW

This did the trick.

I'm driving the SS manually and then not only there isn't extra pulses in the SS but also the full amount of bytes is being sent as expected...

Thanks.

Rony.