Forum Discussion
Hi miscellaneous-mice,
Please try following 4 items on your side and see anyone can solve the issue.
Item 1: Manually Increase Dummy Cycle Configuration
Although the datasheet specifies 8 dummy clocks, the Cyclone V QSPI controller in indirect mode sometimes requires an additional cycle to compensate for internal delays.
Try setting dummy cycles to 16 (equivalent to 2 bytes) to check alignment:
read_cfg.dummy_cycles = 16; // Attempt to increase dummy cycles
Forces the controller to wait longer before data arrival, ensuring the internal FIFO pointer points to the first valid data.
Item 2: Verify and Force Address Length Configuration
You set .addr_size = 2 (representing 3 bytes). Ensure the register is actually written after calling alt_qspi_device_size_config_set.
More importantly, explicitly reset certain controller states before switching back to Quad mode or before each Indirect read.
Attempt to execute a small STIG read (e.g., reading the status register) before performing an indirect read to “wake up” or synchronize the controller to Single SPI mode:
// Perform a small STIG operation to synchronize status before indirect read
uint8_t dummy_sr;
alt_qspi_stig_rd_cmd(0x05, 0, 1, &dummy_sr, timeout); // Read Status Register
// Then perform indirect read
alt_qspi_read(dst, src, size);
Item 3: Correcting Post-Read Offset (Software Workaround)
If you confirm the hardware behavior is reading an extra 0xFF (this has appeared in errata for some Flash controllers, where Indirect Read always includes a leading dummy byte), you can handle it at the software level:
Allocate 1 extra byte when allocating the buffer.
After reading, shift the pointer back by 1 byte, or skip the first byte during copying.
// Temporary buffer, allocate 1 extra byte
uint8_t temp_buf[size + 1];
// Execute read operation
alt_qspi_read(temp_buf, src, size + 1); // Note: Length must match here, or read only size while ignoring the first byte
// Data actually starts at temp_buf[1]
memcpy(dst, temp_buf + 1, size);
Verification method: If you observe temp_buf[0] always being 0xFF while temp_buf[1] contains correct data like 97, this confirms a fixed 1-byte leading offset in the controller.
Item 4: Check alignment of INDRDCNT and INDRDSTADDR
Cyclone V QSPI data register accesses sometimes require 4-byte alignment.
If your dst pointer is not 4-byte aligned, or size is not a multiple of 4, the memcpy inside the HAL library may fail, or misalignment may occur when the hardware FIFO pops.
Ensure the dst pointer is 4-byte aligned (((uint32_t)dst % 4) == 0).
If size is small, try rounding up to a multiple of 4 for reads, then truncating to valid data.
Archer_Altera
- miscellaneous-mice8 hours ago
New Contributor
Hi Archer_Altera,
Thanks for the update, really appreciate the solution. Regarding the solutions
1) I tried to manually increase the dummy cycles, but that wouldn't help as the number of dummy cycles required for OTP read (0x4B) is 8 dummy cycles, so data would be shifted if made to 16.
2) The address width is 24-bit which is 3 bytes, which wouldn't work either as per the QSPI flash documentation for OTP Read. But as you specified running small STIG commands before executing indirect read does synchronize the controller to single SPI mode (but data still comes shifted by a single byte)
3) This is a good work-around, but the issue arises when the read happens from address 0x0. As the data is shifted right by a single byte, byte[0] cannot be retreived (lowest byte of the read data). Hence the exact byte at address 0x0 cannot be retreived using this workaround.
4) Byte alignment check is done in alt_qspi_read itself, so this check would be reduntant.I have figured out the issue, it is related to configuration in devrd register.
- The modebit is enabled by default on bootup for Quad read (0xEC) / write (0x34) configuration , therefore this adds extra cycles in read operation which shifts the data bits by 1 byte for Single mode commands like Fast read (0xB), OTP read (0x4B), etc.
- Here even though the modebit value is specified as '0' on reset, and although my ARM application does not set this bit anywhere, I think this bit is getting configured from the uboot itself. There I temporarily disable this bit for doing OTP read (0x4B) using alt_qspi_mode_bit_disable.
Hence the resulting code will look something like this :
... // Code specified previously for OTP Read configuration
alt_qspi_mode_bit_disable();
alt_qspi_read(dst, src, size);
...