2024-06-03 11:00 AM - last edited on 2024-06-03 11:48 AM by Tesla DeLorean
Dear All,
I am struggling with getting an MT25QL128 chip to work fully on my board.
The connection of the flash chip to my STM32U599NJH6Q is like this:
On the MCU side this corresponds to this configuration to the CubeMX:
I am quite confident that my custom hardware works, because I am able to read the ID of the chip like this:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the System Power */
SystemPower_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
MX_FDCAN1_Init();
MX_FLASH_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_ADC4_Init();
MX_SDMMC1_SD_Init();
MX_OCTOSPI2_Init();
/* USER CODE BEGIN 2 */
OSPI_RegularCmdTypeDef sCommand = {0};
uint8_t data[20 /*40*/] ={0}; // Six to read pair of 3-byte ID's from dual banked IC
sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.Instruction = 0x9F;
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.NbData = sizeof(data);
sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand.DummyCycles = 0;
if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
if (HAL_OSPI_Receive(&hospi2, data, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
while (1) {
uint8_t line[128]={0};
snprintf(line, sizeof(line), "ID: ");
HAL_UART_Transmit(&huart2, line, sizeof(line), HAL_MAX_DELAY);
for (int i = 0; i < sizeof(data); i++) {
memset(line, 0, sizeof(line));
snprintf(line, sizeof(line), "0x%02X ", data[i]);
HAL_UART_Transmit(&huart2, line, sizeof(line), HAL_MAX_DELAY);
}
memset(line, 0, sizeof(line));
snprintf(line, sizeof(line), "\r\n");
HAL_UART_Transmit(&huart2, line, sizeof(line), HAL_MAX_DELAY);
HAL_Delay(10000);
}
}
I am stuck beyond this point. I have seen on the AN5050 document that there is a sample that interfaces a QSPI PSRAM. I thought that this sample would steer me to the right direction, even though RAM and FLASH are quite different, but so far I have not been able to make any success in writing and reading data to the external flash.
Furthermore, I have seen the OSPI_NOR_MemoryMapped example found in the examples for the STM32U575I-EV in the STM32Cube_FW_U5_V1.5.0. This sample though is meant for an OCTOSPI flash and I am not sure how to modify it to fit my use case (if it can be modified at all to fit this hardware).
So any samples, tutorials or directions on how to tackle this issue would be very helpful.
Ideally I would like a solution configuring the device to Memory mapped mode.
Best regards,
Giannis
2024-06-03 11:50 AM - edited 2024-06-03 11:55 AM
The Memory Mapped read just needs a Command Template, exactly how you'd use it in the direct/command mode. The peripheral just stuffs the .Address field in the Memory Mapped operation to the memory.
You've got 95% of the pattern right there with the JEDEC READ ID
The template could likely used the READ (1-bit) and READ DUAL (2-bit) with no further configuration or mode setting on the MICRON part.
Please enumerate the pin usage for this board, ie GPIO for CLK, NCS, D0..D3
2024-06-03 11:57 PM
Thanks a lot for you reply.
The pinout is:
NCS -> PA0
CLK -> PF4
D0 -> PF0
D1 -> PF1
D2 -> PF2
D3 -> PF3
I did not get the part of the Command Template. Also, I am not sure how to erase, then write and read. I tried the code for the PSRAM in AN5050, but I was not successful. Any ideas?
2024-06-04 01:23 AM
Hello @G_Anastasopoulos ,
Could you please check the OCTOSPI configuration like as Devise Size, Sample shifting and Delay hold quarter cycle.
The size of the OSPI memory in bytes and expressed in 2^n. For 128MBits = 16Mbytes = 2^24. In STM32CubeMx, the device size field is set to 24.
Sample shifting (SSHT) recommended to be enabled in STR mode and disabled in DTR mode.
Delay hold quarter cycle (DHQC) enabled in DTR mode and disabled in STR mode.
Also could you please refer to memory datasheet and check the dummy cycle required for read and write operation.
Could you please share the memory datasheet and your project?
I hope this help you.
Thank you.
Kaouthar
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-06-04 02:09 AM
Try using the Data Sheet for the MT25QL128 for the basis of the Erase 64KB command and Write Page 256-byte.
Look at STs code for QSPI support of.the MT25QL512 parts.
The PSRAM stuff isn't going to be very helpful.
2024-06-04 02:15 AM
This is the datasheet of the chip I am using:
https://gr.mouser.com/datasheet/2/671/mict_s_a0004849555_1-2290852.pdf
Previously I had the device size set to 23. I was under the impression that it needed to be 2^(n-1). Anyway, I have changed it now.
While I was trying out different things, I was able to write to the flash an example line and using the code in the AN5050 sample (6.2 case III) for the QSPI RAM in MemoryMapped mode, I am able to read something from the flash when the flash is put in MemoryMapped mode.
So my missing links, if I have understood things properly:
1) Exit QuadMode: From what I see in my code, once I call the EnterQuadMode from the AN5050, I am no longer able to read the ID of the device in the way I was doing it before.
2) EnableWrite: I have seen in several NOR examples that this action is required, but I was not able to successfully perform it on my device. The samples that I was looking at where meant for OCTOSPI flash and although I tried to modify the parameters, I was not successful.
3) Erase: Either erase the complete flash or the page that I am trying to write to.
4) Write: Be able to store a buffer to a given address. I think that the base address of my flash on my setup is
#define OCTOSPI2_BASE (0x70000000UL) /*!< OCTOSPI2 memories accessible over AHB base address */
So I need to offset the address by this much in order to write to the correct address.
Thanks a lot for your time and assistance
2024-06-04 03:07 AM
I assume that you are referring to this example:
https://github.com/STMicroelectronics/stm32-external-loader/tree/contrib/QSPI_Drivers/MT25QL512
If yes, I have tried to apply it, but with no success.
I am attaching the files I am using for the CSP functions modified by me in order to work with the OSPI peripheral.
This code does seem to execute correctly, but when I am trying to read in memory mapped mode I am reading 00s.
I am putting here my main.c:
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t var = 0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the System Power */
SystemPower_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
MX_FDCAN1_Init();
MX_FLASH_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_ADC4_Init();
MX_SDMMC1_SD_Init();
MX_OCTOSPI2_Init();
/* USER CODE BEGIN 2 */
CSP_QUADSPI_Init();
for (var = 0; var < MEMORY_SECTOR_SIZE; var++) {
buffer_test[var] = (var & 0xFF);
}
for (var = 0; var < SECTORS_COUNT; var++) {
if (CSP_QSPI_EraseSector(var * MEMORY_SECTOR_SIZE, (var + 1) * MEMORY_SECTOR_SIZE - 1) != HAL_OK) {
while (1) {}
}
if (CSP_QSPI_WriteMemory(buffer_test, var * MEMORY_SECTOR_SIZE, sizeof(buffer_test)) != HAL_OK) {
while (1) {}
}
}
if (CSP_QSPI_EnableMemoryMappedMode() != HAL_OK) {
while (1) {}
}
for (var = 0; var < SECTORS_COUNT; var++) {
memcpy(buffer_receive, (uint8_t*) (OCTOSPI2_BASE + var * MEMORY_SECTOR_SIZE), sizeof(buffer_receive));
if (memcmp(buffer_test, buffer_receive, sizeof(buffer_test)) != HAL_OK) {
while (1) {}
}
}
while(1){
HAL_GPIO_TogglePin(LED_STATUS_GPIO_Port, LED_STATUS_Pin);
HAL_Delay(1000);
}
}
I am suspecting that there is something wrong with the addresses used for reading and writing
2024-06-04 09:37 AM
Hi @G_Anastasopoulos ,
Could you please check the Dummy cycle. I noted in the driver code "qspi_flash.c" specifically in the the function "CSP_QSPI_EnableMemoryMappedMode(void)", the command-address-data is set to 1-1-4 which is for extended SPI, and dummy cycle set for 10 in "qspi_flash.h" , which is intended for Quad SPI mode as mentioned in the memory datasheet. However, according to the datasheet, dummy cycle configuration for extended SPI should be 8. Therefore, I suggest changing the "DUMMY_CLOCK_CYCLES_READ_QUAD" to "DUMMY_CLOCK_CYCLES_READ" = 8 in the "qspi_flash.h".
Thank you.
Kaouthar
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-06-04 10:34 AM
Tentative External Loader build for OCTOSPI2 / U599 / MT25QL128
https://github.com/cturvey/stm32extldr/blob/main/u5_mt25q128/README.md
2024-06-04 11:24 AM
//******************************************************************************
static uint8_t BSP_OSPI_Read(OSPI_HandleTypeDef *hospi, uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef sCommand = {0};
sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
/* Initialize the read command */
sCommand.Instruction = 0x3B; // DUAL (MOST COMPATIBLE)
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.DataMode = HAL_OSPI_DATA_2_LINES;
sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand.DummyCycles = 8;
#ifdef USE_ADR32
sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
#else
sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
#endif // USE_ADR32
sCommand.Address = ReadAddr & 0x0FFFFFFF; // Ensure Masking
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.NbData = Size;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(OSPI_ERROR);
}
/* Transmission of the data */
if (HAL_OSPI_Receive(hospi, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(OSPI_ERROR);
}
return(OSPI_OK);
}
//******************************************************************************