2022-07-26 07:05 AM
Hello together! :)
I am trying to read the status register 1 of the QSPI Flash W25Q80DV via QSPI. Unfortunately I don't get any data in the buffer. I only get 0x00. The topic of QSPI is still very new to me, so I may have overlooked something obvious here...
Here is the important part of the main code:
/*
* PE7: IO0 = DI
* PE8: IO1 = DO
* PC11: CS
* PB2: CLK
*/
uint8_t txBuffer[3] = {0};
uint8_t rxBuffer[10] = {0};
txBuffer[0] = 0x05; //Read Status Register-01
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, 0); //Drive the CS low
HAL_QSPI_Transmit(&hqspi, txBuffer, 100);//INstructioncode 0x05 for status register 1 shifting to DI pin
HAL_QSPI_Receive(&hqspi, rxBuffer, 100);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, 1);
static void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 255;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 1;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_2;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
/* USER CODE END QUADSPI_Init 2 */
}
Thank you very much!
2022-07-26 03:29 PM
Prescaler looks excessively high.
PC11 is an AF pin not a GPIO
/**
* @brief Reads current status of the QSPI memory.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_GetStatus(void)
{
QSPI_CommandTypeDef s_command = {0};
uint8_t reg;
/* Initialize the read flag status register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_FLAG_STATUS_REG_CMD; // 0x05
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&hqspi, ®, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
2022-08-01 07:40 AM
@Community member thanks for your help! I have now set the PIN as GPIO output and adopted your function and set the prescaler to 1.
Unfortunately, it still doesn't work and I am at a loss here. Here are excerpts from the initialisations and the while-loop...
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, 0); //Drive the CS low
BSP_QSPI_GetStatus();
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, 1); //Drive the CS low
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_QUADSPI_Init(void)
{
/* USER CODE BEGIN QUADSPI_Init 0 */
/* USER CODE END QUADSPI_Init 0 */
/* USER CODE BEGIN QUADSPI_Init 1 */
/* USER CODE END QUADSPI_Init 1 */
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 19;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_2;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
/* USER CODE END QUADSPI_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(USART1_DE_GPIO_Port, USART1_DE_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : PA4 */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PE12 PE13 PE14 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : USART1_DE_Pin */
GPIO_InitStruct.Pin = USART1_DE_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(USART1_DE_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PC11 */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
2022-08-01 09:09 AM
Look, they aren't manually controlled GPIO pins, they should be AF (ALTERNATE FUNCTION) pins controlled by the PERIPHERAL
The PERIPHERAL drives and controls the NCS, CLK, D0 and D1 pins
For CubeMX, likely hidden in the MSP code, so you'll need to dig for that.
Or your implementation in hardware simply doesn't work properly.
The subroutine I showed controls the entire transaction. You don't fiddle with the CS pin, or do the Transmit/Receive outside of the context of a command. You could perhaps, but it would require a lot better understanding of the implementation.
This is illustrative of the use of AF pin designations/use
/**
* @brief QSPI MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* - NVIC configuration for QSPI interrupts
* @param hqspi: QSPI handle pointer
* @retval None
*/
void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
GPIO_InitTypeDef gpio_init_structure;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable the QuadSPI memory interface clock */
QSPI_CLK_ENABLE();
/* Reset the QuadSPI memory interface */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* Enable GPIO clocks */
QSPI_CS_GPIO_CLK_ENABLE();
QSPI_CLK_GPIO_CLK_ENABLE();
QSPI_D0_GPIO_CLK_ENABLE();
QSPI_D1_GPIO_CLK_ENABLE();
QSPI_D2_GPIO_CLK_ENABLE();
QSPI_D3_GPIO_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* QSPI CS GPIO pin configuration */
gpio_init_structure.Pin = QSPI_CS_PIN;
gpio_init_structure.Alternate = QSPI_CS_PIN_AF;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_PULLUP;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure);
/* QSPI CLK GPIO pin configuration */
gpio_init_structure.Pin = QSPI_CLK_PIN;
gpio_init_structure.Alternate = QSPI_CLK_PIN_AF;
gpio_init_structure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure);
/* QSPI D0 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D0_PIN;
gpio_init_structure.Alternate = QSPI_D0_PIN_AF;
HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure);
/* QSPI D1 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D1_PIN;
gpio_init_structure.Alternate = QSPI_D1_PIN_AF;
HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure);
/* QSPI D2 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D2_PIN;
gpio_init_structure.Alternate = QSPI_D2_PIN_AF;
HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure);
/* QSPI D3 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D3_PIN;
gpio_init_structure.Alternate = QSPI_D3_PIN_AF;
HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure);
}
STM32Cube_FW_F7_V1.16.0\Drivers\BSP\STM32F723E-Discovery\stm32f723e_discovery_qspi.c
STM32Cube_FW_F7_V1.16.0\Projects\STM32F723E-Discovery\Examples\QSPI\QSPI_ReadWrite\Src\stm32f7xx_hal_msp.c
2022-08-02 07:21 AM
Thank you for the answer. I will take a closer look at the examples. I now have the following configuration:
/* QSPI CS GPIO pin configuration */
gpio_init_structure.Pin = QSPI_CS_PIN; //Pin 11, GPIOC
gpio_init_structure.Alternate = QSPI_CS_PIN_AF; //GPIO_AF10_QUADSPI
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_PULLUP;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure);
/* QSPI CLK GPIO pin configuration */
gpio_init_structure.Pin = QSPI_CLK_PIN; // GPIO_PIN_2
gpio_init_structure.Alternate = QSPI_CLK_PIN_AF; //GPIO_AF9_QUADSPI
gpio_init_structure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure);
/* QSPI D0 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D0_PIN; // GPIO_PIN_7
gpio_init_structure.Alternate = QSPI_D0_PIN_AF; //GPIO_AF9_QUADSPI
HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure);
/* QSPI D1 GPIO pin configuration */
gpio_init_structure.Pin = QSPI_D1_PIN; //GPIO_PIN_8
gpio_init_structure.Alternate = QSPI_D1_PIN_AF; //GPIO_AF9_QUADSPI
HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure);
In the Main there is only the read function, but this time it is related to the Device ID register.
Unfortunately, it still doesn't work. I'll just check what comes out of the pins with an oscilloscope soon... Sorry, this topic is really quite new to me!
2022-08-02 09:00 AM
Is your USART3 PD8/PD9 connected to a terminal?
uint8_t BSP_QSPI_ReadID(void)
{
QSPI_CommandTypeDef s_command = {0};
uint32_t data = 0;
/* Initialize the read flag status register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = 0x9F; // JEDEC READ ID
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 3; // Width of useful ID
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&hqspi, (void *)&data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
printf("ID:%06X\n", data);
return QSPI_OK;
}
2022-08-02 11:55 AM
USART3 is just connected to a Header :) Why?
2022-08-02 12:21 PM
Because if I build known-to-work code and provide as an .HEX file I can get some feedback as to whether the hardware implementation is viable, or not, without fighting through your SW development processes.
2022-08-02 10:30 PM
This should connect and dump a sector and part ID, on USART3 at 115200 8N1
https://github.com/cturvey/stm32extldr/blob/main/f7_w25q80/DSTAN8_QSPI_2BIT_TEST001.hex
2022-08-06 02:53 PM
Did get in some W25Q80DV parts in today, working on the NUCLEO-F722ZE