Skip to main content
Graduate
October 2, 2024
Solved

Problems with SPI3 on STM32H725ZGT6 device

  • October 2, 2024
  • 1 reply
  • 1154 views

Hello

I would like to make SPI3 on my board with STM32H725ZGT6 micro-controller work.

Here is my initialization:

void MX_SPI3_Init(void) {
	GPIO_InitTypeDef GPIO_InitStruct;

	/* SPI3 parameter configuration*/
	hspi3.Instance = SPI3;
	hspi3.Init.Mode = SPI_MODE_MASTER;
	hspi3.Init.Direction = SPI_DIRECTION_2LINES;
	hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
	hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
	hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
	hspi3.Init.NSS = SPI_NSS_SOFT;
	hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
	hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
	hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
	hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
	hspi3.Init.CRCPolynomial = 0x0;
	hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
	hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
	hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
	hspi3.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
	hspi3.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
	hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
	hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
	hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
	hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
	hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
	if (HAL_SPI_Init(&hspi3) != HAL_OK) {
		Error_Handler();
	}
	//Now lets make our initialization

	__HAL_RCC_SPI3_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();

	spi3UInttmp=(RCC->APB1LENR);
	sprintf(print_string,"SPI3 Device: APB1LENR register = 0x%x\n",spi3UInttmp);
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));

	/**SPI1 GPIO Configuration
 	PC10 ------> SPI1_SCK
	PC11 ------> SPI1_MISO
 	PC12 ------> SPI1_MOSI
	 */
	GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);


	(SPI3->CR1)|=0x00000001; //enable SPI
	(SPI3->CR1)&=0xfffffffe; //disable SPI

	/* SPI3 interrupt Init */
// HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(SPI3_IRQn);
// writeSPI3Index=0;
// readSPI3Index=0;



	(RCC->CFGR)&=0x0000ffff;
	(RCC->CFGR)|=0x60000000; //uC clock output 2 -> pll1_p_ck
	(RCC->CFGR)|=0x14000000; //division by 10
	(RCC->CFGR)|=0x00c00000; //uC clock output 1 -> pll1_q_ck
	(RCC->CFGR)|=0x00280000; //division by 10

	/**Clock Output 2
 	PC9 ------> MCO2
	 */
	GPIO_InitStruct.Pin = GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	/**Clock Output 1
 	PA8 ------> MCO1
	 */
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

void spiGeneral_Init(void) {
	GPIO_InitTypeDef GPIO_InitStruct;

	MX_SPI3_Init();
	/* PD11, PD12, PD13, - SPI address Decoder pins - Output */
	GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

	DEC_DISABLE_RESET

#if 0
	GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate = 0x0;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,1);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,1);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,1);
#endif

	sprintf(print_string,"SPI3 Device -> RCC source control register: RCC_CR = 0x%x\n",(unsigned int)(RCC->CR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device -> RCC clock configuration register: RCC_CFGR = 0x%x\n",(unsigned int)(RCC->CFGR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device -> RCC PLL configuration register: RCC_PLLCFGR = 0x%x\n",(unsigned int)(RCC->PLLCFGR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device -> RCC domain 2 kernel clock configuration register: RCC_D2CCIP1R = 0x%x\n",(unsigned int)(RCC->D2CCIP1R));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device -> RCC APB1 clock enable register: RCC_APB1LENR = 0x%x\n",(unsigned int)(RCC->APB1LENR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device -> RCC APB1 clock LP enable register: RCC_APB1LLPENR = 0x%x\n",(unsigned int)(RCC->APB1LLPENR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));


}

 

After calling this initialization I get this printout:

SPI3 Device: APB1LENR register = 0xa28000
SPI3 Device -> RCC source control register: RCC_CR = 0x303f025
SPI3 Device -> RCC clock configuration register: RCC_CFGR = 0x74e8001b
SPI3 Device -> RCC PLL configuration register: RCC_PLLCFGR = 0x1ff000d
SPI3 Device -> RCC domain 2 kernel clock configuration register: RCC_D2CCIP1R = 0x0
SPI3 Device -> RCC APB1 clock enable register: RCC_APB1LENR = 0xa28000
SPI3 Device -> RCC APB1 clock LP enable register: RCC_APB1LLPENR = 0xeaffc3ff

I assume that the 3 clocks are present on SPI3 block. I can measure both pll1_q_ck (on pin MCO1 -> PA8 - 97 is 55MHz with divider 10) and pll1_p_ck (on pin MCO2 -> PC9 - 96 is 11MHz with divider 10) with an oscilloscope on the pins of the micro-controller.

Then I am periodically sending 6 bytes of information to the transmit buffer to this function:

unsigned int i_spi, i_spiTimeout;
//for now limited to 16 bytes in one frame
unsigned char SPI3_TxRx(unsigned char device, unsigned char *dataRx, unsigned char *dataTx, unsigned int datalength) { //sending and receiving 8 bit data stream
	(SPI3->CR1)&=0xfffffffe; //disable SPI

	(SPI3->CFG1)&=0x8fffffff; //Master baud rate to 000
	(SPI3->CFG1)|=0x70000000; //Master baud rate to SPI master clock/256

	(SPI3->CFG1)&=0xffbfffff; //disable CRC calculation
//	(SPI3->CFG1)|=0x00400000; //enable CRC calculation
//	(SPI3->CFG1)&=0xffe0ffff; //reset CRCSIZE value
//	(SPI3->CFG1)|=0x00070000; //set CRCSIZE to 8bit
	(SPI3->CFG1)&=0xfffffe1f; //reset FIFO Threshold
//	(SPI3->CFG1)|=0x000001e0; //set FIFO Threshold level to 16 data
	(SPI3->CFG1)&=0xfffffff0; //reset DSIZE number of bits in the data frame
	(SPI3->CFG1)|=0x00000007; //set DSIZE to 8 bit data frame

	(SPI3->CFG2)|=0x10000000; //SPI is always in the control of associated GPIOs
	(SPI3->CFG2)&=0xbfffffff; //SSOE is disabled
//	(SPI3->CFG2)&=0xfdffffff; //CPOL is 0 -> sck is 0 when idle
	(SPI3->CFG2)|=0x02000000; //CPOL is 1 -> sck is 1 when idle
	(SPI3->CFG2)&=0xfeffffff; //CPHA is 0 -> first clock transition is the first data capture edge
//	(SPI3->CFG2)|=0x01000000; //CPHA is 1 -> the second clock transition is the first data capture edge
	(SPI3->CFG2)&=0xff7fffff; //LSBFIRST is 0 -> MSB is transmitted first
//	(SPI3->CFG2)|=0x00800000; //LSBFIRST is 1 -> LSB is transmitted first
//	(SPI3->CFG2)&=0xffbfffff; //MASTER is 0 -> device configured as slave
	(SPI3->CFG2)|=0x00400000; //MASTER is 1 -> device configured as master
	(SPI3->CFG2)&=0xffc7ffff; //SPI Motorola
//	(SPI3->CFG2)|=0x00080000; //SPI TI
	(SPI3->CFG2)&=0xfff9ffff; //COMM is full duplex
//	(SPI3->CFG2)|=0x00020000; //COMM is simplex transmitter
	(SPI3->CFG2)&=0xffffff0f; //MIDI - master inter data idleness -> no delay
	(SPI3->CFG2)|=0x00000050; //MIDI - master inter data idleness -> 5 SPI clock cycles

	(SPI3->IER)&=0x00000000; //disable all interrupts

	sprintf(print_string,"SPI3 Device: Status register 1 = 0x%x\n",(unsigned int)(SPI3->SR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));

	(SPI3->IFCR)|=0x0ff8; //clear all flags
	(SPI3->CR1)|=0x00000001; //enable SPI

	(SPI3->CR2)=datalength; //TSIZE number of data for current transfer
//	(SPI3->CR2)=0; //TSIZE number of data for current transfer
//	(SPI3->CR2)&=0x0000ffff; //TSER is 0, only one buffer to transmit
//	(SPI3->CR2)|=0xffff0000; //TSER is 0, only one buffer to transmit





	for(i_spi=0;i_spi<datalength;i_spi++) {
		*((__IO uint8_t *)SPI3->TXDR) = *((unsigned char *)dataTx);
//		*((__IO unsigned short int *)SPI3->TXDR) = *((unsigned char *)dataTx);
//		*((__IO unsigned int *)SPI3->TXDR) = *((unsigned char *)dataTx);
	}

	(SPI3->CR1)|=0x00000100; //master transfer start


	sprintf(print_string,"SPI3 Device: Status register 2 = 0x%x\n",(unsigned int)(SPI3->SR));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
	sprintf(print_string,"SPI3 Device: CR2 register = 0x%x\n",(unsigned int)(SPI3->CR2));
	writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));


	//wait till all bytes are transmitted and all received
	i_spiTimeout=0;
	while(((SPI3->SR)|0x00000008)!=0x00000008) { //check EOT bit for end of transfer
		i_spiTimeout++;
		if(i_spiTimeout>100000) {
			sprintf(print_string,"Error: SPI3 Device: EOT bit not set. Status register = 0x%x\n",(unsigned int)(SPI3->SR));
			writeMessageRS232(PRIMARY_COM_PORT, (uint8_t *)print_string, strlen(print_string));
			break;
//			return 1;
		}
	}
	for(i_spi=0;i_spi<datalength;i_spi++) {
		*((unsigned char *)dataRx) = *((__IO uint8_t *)SPI3->RXDR);
	}
	return 0;
}

 

The output to my console for the first 3 messages which I would like to send:

SPI3 Device: Status register 1 = 0x1202
SPI3 Device: Status register 2 = 0x202
SPI3 Device: CR2 register = 0x6
Error: SPI3 Device: EOT bit not set. Status register = 0x202

SPI3 Device: Status register 1 = 0x202
SPI3 Device: Status register 2 = 0x202
SPI3 Device: CR2 register = 0x6
Error: SPI3 Device: EOT bit not set. Status register = 0x202

SPI3 Device: Status register 1 = 0x202
SPI3 Device: Status register 2 = 0x202
SPI3 Device: CR2 register = 0x6
Error: SPI3 Device: EOT bit not set. Status register = 0x202

I see no activity on the SPI3 IO pins, no clock, no output. If I am controlling this pins PC10, PC11, P12 as a GPIO I can do that without problems. But no working SPI3. What I am doing wrong?

 

    This topic has been closed for replies.
    Best answer by TDK

    Code is a bit of a mess. Not many people want to sort through register fields by value to figure it out. Using the standard CMSIS header defines will make it infinitely more readable.

    > for(i_spi=0;i_spi<datalength;i_spi++) {
    >   *((__IO uint8_t *)SPI3->TXDR) = *((unsigned char *)dataTx);
    > }

    You're sending the first character datalength times. No incrementation is done. Not the main problem.

    Also, this code reads the value at TXDR, then dereferences it and writes to that location. Not what you want. Could be causing a crash, but otherwise not the main problem. You should be doing:

    for(i_spi=0;i_spi<datalength; i_spi++) {
     *((__IO uint8_t *)&SPI3->TXDR) = dataTx[i_spi];
    }

     

    > *((unsigned char *)dataRx) = *((__IO uint8_t *)SPI3->RXDR);

    Same issue with this code. Missing & and not incrementing. Not the main problem.

     

    > (SPI3->CR1)|=0x00000100; //master transfer start

    Looks like you want to set the CSTART bit, but you're off by one. CSTART is bit 9, so it should be either of these. Preferably the one with the CMSIS define.

    SPI3->CR1 |= 0x00000200;
    SPI3->CR1 |= SPI_CR1_CSTART;

     

    Note that your scheme where you send all characters before you receive any characters will only work if all characters fit within the FIFO which is something like 4 or 8 words long.

    1 reply

    Super User
    October 2, 2024

    Does HAL_SPI_TransmitReceive() produce the correct output?

    SMali.3Author
    Graduate
    October 2, 2024

    Yes, using HAL_SPI_TransmitReceive() I get the expected output MOSI with CLK signal. I will go deeper into my code to see why it is not working. Thank you very much for the hint.

    TDKAnswer
    Super User
    October 2, 2024

    Code is a bit of a mess. Not many people want to sort through register fields by value to figure it out. Using the standard CMSIS header defines will make it infinitely more readable.

    > for(i_spi=0;i_spi<datalength;i_spi++) {
    >   *((__IO uint8_t *)SPI3->TXDR) = *((unsigned char *)dataTx);
    > }

    You're sending the first character datalength times. No incrementation is done. Not the main problem.

    Also, this code reads the value at TXDR, then dereferences it and writes to that location. Not what you want. Could be causing a crash, but otherwise not the main problem. You should be doing:

    for(i_spi=0;i_spi<datalength; i_spi++) {
     *((__IO uint8_t *)&SPI3->TXDR) = dataTx[i_spi];
    }

     

    > *((unsigned char *)dataRx) = *((__IO uint8_t *)SPI3->RXDR);

    Same issue with this code. Missing & and not incrementing. Not the main problem.

     

    > (SPI3->CR1)|=0x00000100; //master transfer start

    Looks like you want to set the CSTART bit, but you're off by one. CSTART is bit 9, so it should be either of these. Preferably the one with the CMSIS define.

    SPI3->CR1 |= 0x00000200;
    SPI3->CR1 |= SPI_CR1_CSTART;

     

    Note that your scheme where you send all characters before you receive any characters will only work if all characters fit within the FIFO which is something like 4 or 8 words long.