STM32H743ZI NUCLEO 144 & LWIP - Can't Ping The Board - stm32

Hope all is going well.
I'm trying to ping STM32H743ZI NUCLEO 144 using LWIP middle-ware. Code generated by CubeMX.
Configurations:
Set the HCLK to 400 MHz
Enabled the CPU ICache and DCache (under Cortex_M7 Configuration)
Enabled MPU (Region0, Region1 & Region2)
Enabled LWIP
Selected LAN8742 as the Driver_PHY (under LwIP>Platform Settings)
DHCP disabled (IP, MASK: 255,255,255,000 , Gateway: Modem IP)
RTOS disabled
LWIP_HTTPD, LWIP_HTTPD_CGI enabled
LWIP_HTTPD_SSI enabled
LWIP_HTTPD_MAX_TAG_NAME_LEN set to 16
ICMP enabled (LWIP_BROADCAST_PING and LWIP_MULTICAST_PING in LwIP Key Options>IPMP Options).
Code Generated for Keil V5
MX_LWIP_Process added to the main function in While loop.
while(1)
{
MX_LWIP_Process();
}
I don't know how should I configure the CubeMX or change the generated code to be able to ping my board.
My_File

this will probably help you (it did for me):
Information about this issue can be found here.
https://community.st.com/s/article/FAQ-Ethernet-not-working-on-STM32H7x3
Memory buffers need to be assigned to RAM that can be accessed by the Ethernet
peripheral.
You may need to adjust the tour stack/heap size.
The default Ethernet GPIOs speed may be too low.
You may need to configure the MPU.
You may likely need to change your linker script.
On this page you will find good information:
https://github.com/MX-Master/STM32H7_Nucleo-H743ZI_Ethernet_LwIP
The HAL_Delay mentioned may not be required, though.
In the file lan8742.c (driver), I added an extra line for the LAN8742_Init function, around line 190, to set auto-negotiation:
// Link did not come up after HW reset.
pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_AUTONEGO_EN);
So that function looks like:
// Used in ethernetif.c, 363, static void low_level_init(struct netif *netif)
int32_t LAN8742_Init(lan8742_Object_t *pObj)
{
uint32_t tickstart = 0, regvalue = 0, addr = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->Is_Initialized == 0)
{
if(pObj->IO.Init != 0)
{
/* GPIO and Clocks initialization */
pObj->IO.Init();
}
/* for later check */
pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1;
/* Get the device address from special mode register */
for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
{
if(pObj->IO.ReadReg(addr, LAN8742_SMR, &regvalue) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
/* Can't read from this device address
continue with next address */
continue;
}
if((regvalue & LAN8742_SMR_PHY_ADDR) == addr)
{
pObj->DevAddr = addr;
status = LAN8742_STATUS_OK;
break;
}
}
if(pObj->DevAddr > LAN8742_MAX_DEV_ADDR)
{
status = LAN8742_STATUS_ADDRESS_ERROR;
}
/* if device address is matched */
if(status == LAN8742_STATUS_OK)
{
/* set a software reset */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_SOFT_RESET) >= 0)
{
/* get software reset status */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) >= 0)
{
tickstart = pObj->IO.GetTick();
/* wait until software reset is done or timeout occurred */
while(regvalue & LAN8742_BCR_SOFT_RESET)
{
if((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO)
{
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
break;
}
}
else
{
status = LAN8742_STATUS_RESET_TIMEOUT;
}
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
}
else
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
}
// Jack 2019-03-25, Link did not come up after HW reset.
pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_AUTONEGO_EN);
if(status == LAN8742_STATUS_OK)
{
tickstart = pObj->IO.GetTick();
/* Wait for 2s to perform initialization */
while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
{
}
pObj->Is_Initialized = 1;
}
return status;
}

Related

UART interrupt on ARM Cortex-M0 not triggering while utilizing FreeRTOS

I am using an STM32F0 with the following std_periph_lib api functions to configure and execute a UART transmit from a FreeRTOS queue.
// Initialization
{
USART_InitTypeDef usart_init;
USART_StructInit(&usart_init);
usart_init.USART_BaudRate = 9600;
USART_Init(s_port[uart].base, &usart_init);
USART_ClearITPendingBit(USART1, USART_FLAG_TXE);
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitTypeDef init_struct = {
.NVIC_IRQChannel = USART1_IRQn,
.NVIC_IRQChannelPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
};
NVIC_Init(&init_struct);
}
// Transmit
// Write all passed data to queue
for (uint8_t i = 0; i < len; i++) {
if (queue_send(&queue, &data[i], 0) != pdTRUE) {
break;
}
}
if (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == SET) {
uint8_t tx_data = 0;
// get first byte from queue to initiate transmission
UBaseType_t cmpl = queue_receive(&queue, &tx_data, 0);
if (cmpl == pdFALSE) { // No data left in queue
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
return status;
}
// Send first byte
USART_SendData(USART1, tx_data);
// Enable TX Interrupts to begin transmission
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}
I have confirmed that the data is received from the queue, and that the USART_SendData and USART_ITConfig execute, but the isr:
void USART1_IRQHandler(void) {
}
is never executed. Does anyone know what may be causing this?
I have read the FreeRTOS docs concerning ARM interrupt structure (here) and have confirmed that my ISR is at a lower logical priority than configMAX_SYSCALL_INTERRUPT_PRIORITY and higher than configKERNEL_INTERRUPT_PRIORITY.

STM32 I2C scan returns different addresses than Arduino

Good day
The goal is to use the LSM9DS0 with a ST chip.
The situation is that the I2C address as returned by the scanner (ST environment) is not the same to that of Arduino I2C scanner. I am using a STM32 Nucleo-F429 and ESP32 devkit.
When I scan for I2C addresses using the below code, it returns the following four addresses:
0x3A
0x3B
0xD6
0xD7
However I have used this very IMU breakout on a ESP32 before and I noticed that the addresses are not the same. When I run the I2C scanning code I get the following addresses.
0x1D
0x6B
STM32 code: Src files were generated by CubeMX. Let me know if the i2c.h/c are required. But they should be pretty standard.
for (uint16_t i = 0; i < 255; i++)
{
if (HAL_I2C_IsDeviceReady(&hi2c1, i, 5, 50) == HAL_OK)
{
HAL_GPIO_TogglePin(LED_RED_PORT, LED_RED_PIN);
char I2cMessage[10];
sprintf(I2cMessage, "%d , 0x%X\r\n", i, i);
HAL_UART_Transmit(&huart2, (uint8_t *)I2cMessage, strlen(I2cMessage), 10);
}
}
Arduino code:
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(115200);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
Does anyone know why this is and is it a problem?
I found the answer in the description of the HAL API. The API requires the 7bt address to be bit shifted to the left by 1bit.
Within the file: stm32F4xx_hal_i2c.c the description of the HAL_I2C_IsDeviceReady() API says the following:
* #param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
Thus, change the IsDeviceReady arguments as follows and it will work.
for (uint16_t i = 0; i < 255; i++)
{
if (HAL_I2C_IsDeviceReady(&hi2c1, i<<1, 5, 10) == HAL_OK)
{
// Do crazy stuff
}
}
This worked for me. Hope it helps anyone with the same issue
one can find I2C devices on an ESP32 using the code below:
void I2Cscanner() {
Serial.println ();
Serial.println ("I2C scanner. Scanning ...");
byte count = 0;
Wire.begin();
for (byte i = 8; i < 120; i++)
{
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
if (Wire.endTransmission () == 0) // Receive 0 = success (ACK response)
{
Serial.print ("Found address: ");
Serial.print (i, DEC);
Serial.print (" (0x");
Serial.print (i, HEX); // PCF8574 7 bit address
Serial.println (")");
count++;
}
}
Serial.print ("Found ");
Serial.print (count, DEC); // numbers of devices
Serial.println (" device(s).");
}

STM32F - SPI with DMA "ErrorCallback" and frames shifted

I am communicating 2 uC (an arduino display as MASTER and STM32F429 as slave).Its communication consists of 10 bytes in full duplex through SPI using DMA, every 150ms.
During some minutes the communication goes very good, both uC are sending their 10 bytes properly. During this time, I have noted that "HAL_SPI_ErrorCallback" function is called becasue I have added a counter within and it is increased little by little, but the comminication still goes well.
My first question is: Is it normal that sometimes ErrorCallback function is called randomly? due to noise or whatever the communication has an instantaneous error... I guess..
Here are a capture of the MISO signal in green, CLK in whie and CS in yellow
On the other hand, after a while (randomly 10 min, 1h ...) the communication is corrupted just in the MISO signal , the STM32 sends the 10 bytes frame but instead of sending Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10, (LSB first)
it sends:
Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9, IT IS MOVED TO RIGTH 1 byte!?!?
Attached you can see the capture "Working.jpg" with byte0 = 0x02 and the rest of the bytes = 0. In the other capture "NOT_working.jpg" is a capture with the problem. Both uC were working properly for a while and suddenly the STM32 uC started to send this frame all the time (the communication frame is byte = 0x02 and the rest of the bytes = 0 in order to see easily this error).
Working.jpg - which is MISO signal sending the frame properly
NOT_working.jpg - which is MISO signal sending the frame incorrectly
I have tried the communication in:
"Init.Mode = DMA_NORMAL" and "DMA_CIRCULAR", and both configuration have the same behaviour.
I have creaged the 2 variables in order to find out the problem:
DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx);
And the the comunications goes well, DMA_counter_RX = 10 BUT DMA_counter_TX = 9. This values are normal. But as soon as the shift error occurs, both DMA counters are = 10.
Also this problem always happens in debug mode when I click on "suspend" (pause) and "resume"(play) as soon as I click on "resume" and the processor continues with the program, the MISO signal is shifted forever.
Additionally I am using TIM1, TIM5, TIM2, TIM3 and TIM4 for other things like PWM and interruptions but not related to SPI...
I have tried to solve this problem modifying all the NVIC priorities for all interruptions and so on but the problem get worst.
I am using System Workbench for STM32 latest version.
Any help is appreciate! Thanks in advance and best regards.
Alejandro
Sorry for long question... :(
Bellow you can see my configuration for SPI and DMA if it can help you:
void MX_DMA_Init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
void MX_SPI6_Init(void)
{
hspi6.Instance = SPI6;
hspi6.Init.Mode = SPI_MODE_SLAVE;
hspi6.Init.Direction = SPI_DIRECTION_2LINES;
hspi6.Init.DataSize = SPI_DATASIZE_8BIT;
hspi6.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi6.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi6.Init.NSS = SPI_NSS_HARD_INPUT;
hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi6.Init.TIMode = SPI_TIMODE_DISABLE;
hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi6.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi6) != HAL_OK)
{
Error_Handler();
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI6)
{
__HAL_RCC_SPI6_CLK_ENABLE();
/**SPI6 GPIO Configuration
PG8 ------> SPI6_NSS
PG12 ------> SPI6_MISO
PG13 ------> SPI6_SCK
PG14 ------> SPI6_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI6;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
hdma_spi6_rx.Instance = DMA2_Stream6;
hdma_spi6_rx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_rx.Init.Mode = DMA_NORMAL;
hdma_spi6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi6_rx);
hdma_spi6_tx.Instance = DMA2_Stream5;
hdma_spi6_tx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_tx.Init.Mode = DMA_NORMAL;
hdma_spi6_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmatx,hdma_spi6_tx);
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(SPI6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);
}
}
During initialization code, I configure SPI6 and DMA as it is described before, just after that I enable communication using:
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
Also it were added the following 2 functions related to SPI communication:
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
STM cube mx automatically created:
void DMA2_Stream5_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream5_IRQn 0 */
/* USER CODE END DMA2_Stream5_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_tx);
/* USER CODE BEGIN DMA2_Stream5_IRQn 1 */
/* USER CODE END DMA2_Stream5_IRQn 1 */
}
/**
* #brief This function handles DMA2 stream6 global interrupt.
*/
void DMA2_Stream6_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream6_IRQn 0 */
/* USER CODE END DMA2_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_rx);
/* USER CODE BEGIN DMA2_Stream6_IRQn 1 */
/* USER CODE END DMA2_Stream6_IRQn 1 */
}
void SPI6_IRQHandler(void)
{
/* USER CODE BEGIN SPI6_IRQn 0 */
/* USER CODE END SPI6_IRQn 0 */
HAL_SPI_IRQHandler(&hspi6);
/* USER CODE BEGIN SPI6_IRQn 1 */
/* USER CODE END SPI6_IRQn 1 */
}
------------------------------EDITED----------------------------
I add 2 captures of the SPI register
SPI registers WORKING
SPI registers ERROR
I finally got the solution, I found what the problem was!
Usually, the CS signal goes from 1 to 0, then MISO and MOSI communicates, and once the communication finishes CS signal goes from 0 to 1, and the STM32F429 continues with the rest of the tasks...
This was happening every 150 ms, that's the period of thime both uC are communicating. But the STM32 uC has another tasks with more priority than SPI communication.
When one of this higher priority starts during SPI communication, and once this higher priority is done then the uC continues with the task was doing ( it was SPI), obviouslythis frame is lost and "HAL_SPI_ErrorCallback" is executed, and then SPI is restarted.If SPI is restarted when CS signal is 1, (spi idle), then there is no problem, SPI is restarted properly and the next frame will be received without problem. BUT if SPI is restarted when CS signal is 0 (STM32 SPI is selected and ready to communicate) then the STM32 is waiting to send and receive an amount of bytes but it will receives less, so an a mismatch of communication bytes is the key of the PROBLEM.
I have solved this issue just adding:
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
while(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8) != GPIO_PIN_SET) // CS signal
{
}
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
I have to modify "WHILE" in order to not stop the processor , but it is the first approximation.
Now the communication is working all the time, but some times a frame is lost (and " HAL_SPI_ErrorCallback" is called) due to higher priority task. But it is normal, a CRC is implemented to note that.
Thanks for helping me and support the support.
I hope this helps to other people.
Best regards.
Alejandro.

NVIC_SystemReset () not working for STM32F4

I am working on STM32F4 board. My IDE is IAR Embedded Work bench. I am trying to do a software reset from code. For that i used API ' NVIC_SystemReset(); ' defined in
core_cm4.h header. But the system reset is not happening.
I tried the same thing in STM32F3, same IDE . I used the function NVIC_SystemReset(); from core_sc300.h header. Using that software reset is happening. I found the definition of functions in both file are same and both controllers are Cortex M4 only.What is the problem with STM32F4 board.? Can any one help me in solving this or can any one suggest an alternative way for system reset in STM32F4.
Please help.
Thanks in advance
In the HAL You can use
HAL_NVIC_SystemReset();
You can use a watch-dog instead:
Call wdg_activate(n) in order to initiate system-reset within n milliseconds
Call wdg_reactivate() in order to reload the counter back to n milliseconds
void wdg_activate(unsigned short num_of_ms)
{
uint8_t prescale_reg;
uint8_t prescale_val;
if (num_of_ms < 1)
{
num_of_ms = 1;
prescale_reg = IWDG_Prescaler_32;
prescale_val = 1;
}
else if (num_of_ms <= 4096)
{
prescale_reg = IWDG_Prescaler_32;
prescale_val = 1;
}
else if (num_of_ms <= 8192)
{
prescale_reg = IWDG_Prescaler_64;
prescale_val = 2;
}
else if (num_of_ms <= 16384)
{
prescale_reg = IWDG_Prescaler_128;
prescale_val = 4;
}
else if (num_of_ms <= 32768)
{
prescale_reg = IWDG_Prescaler_256;
prescale_val = 8;
}
else
{
num_of_ms = 32768;
prescale_reg = IWDG_Prescaler_256;
prescale_val = 8;
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
while (IWDG_GetFlagStatus(IWDG_FLAG_PVU));
IWDG_SetPrescaler(prescale_reg);
while (IWDG_GetFlagStatus(IWDG_FLAG_RVU));
IWDG_SetReload(num_of_ms/prescale_val-1);
IWDG_Enable();
}
void wdg_reactivate()
{
IWDG_ReloadCounter();
}
There have been several iterations of NVIC_SystemReset(). Please post the code for the version you are using. The current [working STM32F4] version that I am using is as follows:
/** \brief System Reset
The function initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}

Erasing page on stm32 fails with FLASH_ERROR_WRP

I am trying to erase one page in flash on an STM32F103RB like so:
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR | FLASH_FLAG_OPTERR);
FLASHStatus = FLASH_ErasePage(Page);
However, FLASH_ErasePage fails producing FLASH_ERROR_WRP
Manually enabling/disabling write protection in the stm32-linker tool doesn't fix the problem.
Basically FLASH_ErasePage fails with WRP error without trying to do anything if there's previous WRP error in the status register.
What comes to your FLASH_ClearFlag call, at least FLASH_FLAG_BSY will cause assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)); to fail (though I'm not really sure what happens in this case).
#define IS_FLASH_CLEAR_FLAG(FLAG) ((((FLAG) & (uint32_t)0xFFFFC0FD) == 0x00000000) && ((FLAG) != 0x00000000))
What is your page address ? Which address are you trying to access ?
For instance, this example is tested on STM32F100C8 in terms of not only erasing but also writing data correctly.
http://www.ozturkibrahim.com/TR/eeprom-emulation-on-stm32/
If using the HAL driver, your code might look like this (cut'n paste from an real project)
static HAL_StatusTypeDef Erase_Main_Program ()
{
FLASH_EraseInitTypeDef ins;
uint32_t sectorerror;
ins.TypeErase = FLASH_TYPEERASE_SECTORS;
ins.Banks = FLASH_BANK_1; /* Do not care, used for mass-erase */
#warning We currently erase from sector 2 (only keep 64KB of flash for boot))
ins.Sector = FLASH_SECTOR_4;
ins.NbSectors = 4;
ins.VoltageRange = FLASH_VOLTAGE_RANGE_3; /* voltage-range defines how big blocks can be erased at the same time */
return HAL_FLASHEx_Erase (&ins, &sectorerror);
}
The internal function in the HAL driver that actually does the work
void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)
{
uint32_t tmp_psize = 0U;
/* Check the parameters */
assert_param(IS_FLASH_SECTOR(Sector));
assert_param(IS_VOLTAGERANGE(VoltageRange));
if(VoltageRange == FLASH_VOLTAGE_RANGE_1)
{
tmp_psize = FLASH_PSIZE_BYTE;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)
{
tmp_psize = FLASH_PSIZE_HALF_WORD;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)
{
tmp_psize = FLASH_PSIZE_WORD;
}
else
{
tmp_psize = FLASH_PSIZE_DOUBLE_WORD;
}
/* If the previous operation is completed, proceed to erase the sector */
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= tmp_psize;
CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);
FLASH->CR |= FLASH_CR_SER | (Sector << POSITION_VAL(FLASH_CR_SNB));
FLASH->CR |= FLASH_CR_STRT;
}
Second thing to check. Is interrupts enabled, and is there any hardware access between the unlock call and the erase call?
I hope this helps