Skip to main content
Graduate II
May 20, 2022
Question

Writing in Eprom AT25640 with STM32F429 with SPI

  • May 20, 2022
  • 2 replies
  • 1804 views

Hi forum I am working with micro STM32F429 and I want to read and write an external memory using SPI.

I am following the instructions on the datasheet but sometimes I am able to write sometimes it fails and I am not able to understand why..

Here there is the code of the init of the SPI

void SPI1_Init(void)
{
	/* PA2 = CS,PA5 = SCK, PA7 = SPI1_MOSI */
	GPIOA -> MODER |= ((GPIOA -> MODER) & 0xFFFF33CF) | 0x00008810; 	// AF Function: XX,AF5,AF5
	GPIOA -> OTYPER |= ((GPIOA -> OTYPER) & 0xFFFFFF5B);				// Push-Pull
	GPIOA -> OSPEEDR |= ((GPIOA -> OSPEEDR) & 0xFFFF3FFC) | 0x0000CC30; // Very High Speed
	GPIOA -> PUPDR |= ((GPIOA -> PUPDR) & 0xFFFF33CF);					// No Pull-Up
	GPIOA -> AFR[0] |= ((GPIOA -> AFR[0]) & 0x0F0FF0FF) | 0x50500000;	//
//	GPIOA -> AFR[1] |= ((GPIOA -> AFR[1]) & 0xFFFFFFFF) | 0x00000000;	//
 
	/* PB12 = WRP, PB4 = SPI1_MISO */
	GPIOB -> MODER |= ((GPIOB -> MODER) & 0xFCFFFCFF ) | 0x01000200; 	// AF Function XX,AF5
	GPIOB -> OTYPER |= ((GPIOB -> OTYPER) & 0xFFFFEFEF);				// Push-Pull
	GPIOB -> OSPEEDR |= ((GPIOB -> OSPEEDR) & 0xFCFFFCFF) | 0x03000300;	// Very High Speed
	GPIOB -> PUPDR |= ((GPIOB -> PUPDR) & 0xFCFFFCFF);					// No Pull-Up
	GPIOB -> AFR[0] |= ((GPIOB -> AFR[0]) & 0xFFF0FFFF) | 0x00050000;	//
	GPIOB -> AFR[1] |= ((GPIOB -> AFR[1]) & 0xFFF0FFFF);	//
 
	RCC-> APB2ENR |= RCC_APB2ENR_SPI1EN; // SPI1 Peripheral Clock Enable
 
 HAL_NVIC_SetPriority(SPI1_IRQn, 7, 2);
 
 /* Enable the TIMx global Interrupt */
 HAL_NVIC_EnableIRQ(SPI1_IRQn);
 
 GPIOB -> ODR |= 0x1000; // WP = 1 : PB12
	GPIOA -> ODR |= 0x0004; // CS = 1 : PA2
 SPI1 -> CR1 = 0x0300;
 // clock / 16, bidirectional, output enable, LSB first, spi1 enable, master selection
 SPI1 -> CR1 |= (SPI_CR1_BR_1 | SPI_CR1_BR_2 | SPI_CR1_BIDIOE); // | SPI_CR1_SPE | SPI_CR1_MSTR); // | SPI_CR1_BIDIMODE | SPI_CR1_LSBFIRST);
 SPI1 -> CR1 |= SPI_CR1_MSTR;
 SPI1 -> CR1 |= SPI_CR1_SPE;
}
void SPI1_IRQHandler(void)
{
	volatile unsigned int IIR;
 
	// Checks whether the SPI1 interrupt has occurred or not
	IIR = SPI1 -> SR;
	if(IIR & SPI_SR_RXNE){ // received data
		buf_ee_rd[n_mem] = SPI1 -> DR;
		SPI1 -> SR &= ~SPI_SR_RXNE; // Reset Interrupt Flag
	}
	else;
	if(IIR & SPI_SR_TXE){ // transmit data
		SPI1 -> SR &= ~SPI_SR_TXE; // Reset Interrupt Flag
		if(++n_mem < n_max_byte){
			SPI1 -> DR = *pun_dati; /* buf_ee_wr[n_mem]; */
			pun_dati++;
		}
		else{
		 SPI1 -> CR2 &= ~SPI_CR2_TXEIE; // TX Interrupt Enable
		}
	}
	else;
}

And here there are the functions that I am using for writing

void ee_wr_codice2()
{
	GPIOA -> ODR |= 0x0004 ; //WP = 1 : EE non protetta in scrittura GIOM
	codice[0].word = codice2;
	ee_wr_en();
	buf_ee_wr[1] = 0x1f; /* code addr hi */
	buf_ee_wr[2] = 0xfc; /* code addr lo */
	buf_ee_wr[3] = codice[0].byte[0];
	buf_ee_wr[4] = codice[0].byte[1];
	n_max_byte = 5;
	ee_wr_byte();
	sFLASH_WaitForWriteEnd(); // GIOM
	GPIOA -> ODR &= ~0x0004; //WP = 0 : EE protetta in scrittura GIOM */
}

where

void ee_wr_en()
{
	GPIOA -> ODR &= ~PA2; // CS = 0
	buf_ee_wr[0] = 0x06; /* write enable */
	pun_dati = buf_ee_wr;
	n_mem = 0;
	n_max_byte = 1;
	SPI1 -> DR = *pun_dati;
	pun_dati++;
 SPI1 -> CR2 |= SPI_CR2_TXEIE; // TX Interrupt Enable
	while((SPI1 -> SR) & SPI_SR_BSY);
	GPIOA -> ODR |= PA2; // CS = 1
}

and

void ee_wr_byte()
{
	GPIOA -> ODR &= ~PA2; // CS = 0
	buf_ee_wr[0] = 0x02; /* write data */
	pun_dati = buf_ee_wr;
	n_mem = 0;
	SPI1 -> DR = *pun_dati;
	pun_dati++;
 SPI1 -> CR2 |= SPI_CR2_TXEIE; // TX Interrupt Enable
	while((SPI1 -> SR) & SPI_SR_BSY);
	GPIOA -> ODR |= PA2; // CS = 1
}

moreover

void sFLASH_WaitForWriteEnd(void) /
{
 	unsigned char flashstatus = 0;
	do
	{
		flashstatus = sFLASH_StatusReg();
	}while(flashstatus & 0x01); /* Write in progress */
 
}

and last

unsigned char sFLASH_StatusReg(void) // GIOM
{
 
 unsigned char tmp;
 GPIOA -> ODR &= ~PA2; // CS = 0
 buf_ee_wr[0] = 0x05; /* Read Status Register instruction */
 pun_dati = buf_ee_wr;
 n_mem = 0;
 n_max_byte = 1;
 SPI1 -> DR = *pun_dati;
 pun_dati++;
 SPI1 -> CR2 |= SPI_CR2_TXEIE; // TX Interrupt Enable
 while((SPI1 -> SR) & SPI_SR_BSY);
 tmp = buf_ee_rd[0]; // GIOM68 va bene indice 0 ???
 GPIOA -> ODR |= PA2; // CS = 1
 
 return(tmp);
}

I am wondering if it is iìok the code since in this project they decided to not use the HAL.

In the attachements you can find al the connection of the eprom with the pin of the mcu.

Thanks a lot if you have time to watch and help

    This topic has been closed for replies.

    2 replies

    Graduate II
    May 20, 2022

    >>..the code since in this project they decided to not use the HAL.

    So is it your code, or someone else's?

    If it's not working for you, and you're having to debug it, at some point it might be easier to implement it cleanly, yourself.

    It does seem to use a mishmash of concepts.

    Uses interrupts, but still blocks.

    Weird use of semi-colons on the else statements..

    I might watch the CS signals vs clock/data. Make sure the IO completes to the pin, probably should be using BSRR, and __DMB() memory barrier so the write buffers flush predictably.

    Perhaps use scope, or logic analyzer, triggered when you see failure.

    SGasp.1Author
    Graduate II
    May 20, 2022

    Hi Tesla thanks for the answer..

    The code it is not mine they asked the hep for finding the bug.

    I would use the hal lib if I could but they decided to avoid them ..

    I thinks HAL_SPI_transmit() in blocking mode shoud do the job quite well

    I found someone complaining the same kind of problem ..

    https://forum.arduino.cc/t/having-trouble-with-a-at25640b-eeprom/170756

    They fixed with a delay between the wren command and the command for writing..

    But They use total different functions..

    Except to watch the signals do you see something strange?

    Thanks