2024-06-16 01:15 AM - edited 2024-06-17 06:13 AM
//Clock cycle function.
void clock_cycle(uint8_t clocks){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
for(uint8_t i = 0; i<clocks; i++){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
}
//Insert this in main function
// DO NOT USE BREAKPOINTS. SEQUENCE MUST BE COMPLETED WITHOUT INTERRUPTION
//Step 1
printf("Starting step 1 power loss recovery sequence");
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); //DQ3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); //DQ0
clock_cycle(7);
clock_cycle(9);
clock_cycle(13);
clock_cycle(17);
clock_cycle(25);
clock_cycle(33);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); //DQ3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET); //DQ0
//Step 2
printf("Starting step 2 power loss recovery sequence");
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); //DQ3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); //DQ0
clock_cycle(8);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); //DQ3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET); //DQ0
printf("Completed power loss recovery sequence");
Solved! Go to Solution.
2024-06-16 08:28 AM - edited 2024-06-17 07:06 AM
You're sending a magic sequence of all ONEs to MOSI
You might have to do this sequencing void direct GPIO interaction, not using the SPI peripheral.
And you need a brief break time between sequences with the chip select.
Perhaps use a scope or logic analyzer to confirm the correct pattern if having trouble.
2024-06-16 04:20 AM
Well reverse_bits() is broken.
Is there a slight delay in csHIGH(FM) so next HIGH/LOW has separation.
2024-06-16 04:27 AM
Thank you for taking the time.
That seems to be the case. The write nonvolatile register command requires input data of LSB first so I've corrected the function here. This has not been tested yet.
Additionally, there is no delay in csHIGH(FM). I will implement a 1ms delay. Thank you
static uint8_t reverse_bits(uint8_t byte)
{
byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4;
byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2;
byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1;
return byte;
}
void MT25QL_WriteNONVOL(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM, uint16_t reg_val)
{
uint8_t tData[3];
tData[0] = WRITE_NONVOL_CFG_REG_CMD;
tData[1] = reverse_bits((reg_val >>8) & 0xFF);
tData[2] = reverse_bits(reg_val & 0xFF);
write_enable(hspi, FM);
csLOW(FM);
SPI_Write(hspi, tData, 3);
csHIGH(FM);
//write enable reset is automatic
}
2024-06-16 04:44 AM
>>I will implement a 1ms delay.
That's likely to be slow and excessive.
Could you use DWT CYCCNT or a TIM counting at 1 MHz / 1 us (counting, not interrupting)? Or honestly a 50-100 ns
Test by printing content rather than sending to the IC
What are you writing to WRITE_NONVOL_CFG_REG_CMD, and why?
2024-06-16 04:53 AM
I will take note of that. I'm still new to coding C so I haven't figured out timers yet.
I am trying to reset bit 0 of the nonvolatile cfg to allow 4-byte addressing in commands by default after next reset.
2024-06-16 05:03 AM - edited 2024-06-16 05:05 AM
Ok, but what pattern did you write to the device?
Not sure that writing random values is advisable or recoverable, especially if you've now put the device in DTR, DUAL or QUAD modes, via a 1-bit SPI interface.
Also you shouldn't need to BIT reverse the vector. It should read/write Little Endian
You can check the 3/4-byte mode via the FLAG STATUS REGISTER
There's a simple command to get it in the right mode ENTER 4-BYTE ADDRESS MODE B7h
Don't use NON-VOLATILE settings until you've got more experience, and have validated all the read methods.
2024-06-16 05:19 AM
I don't know what pattern was written. I coded an initialization function (without testing which was a mistake) that would copy the current nonvolatile cfg, reset bit 0, then write to nonvolatile cfg using the initial code provided which is now the current issue.
There is a section in the documentation called the Power Loss and Interface Rescue functions to reset the device to a fixed state (extended SPI) which is what I'm currently trying to do. However, I am having trouble understanding the documentation and have implemented it as shown below.
However, when testing this code, the device is still inaccessible only returning 0xFF consistently in read ID and other read functions.
Power Loss Recovery and Interface Rescue functions
HAL_StatusTypeDef MT25QL_InterfaceRescue(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM)
{
// Step 1: Recovery sequence
recovery_sequence(hspi, FM, 7); // Example for 7 clock cycles
recovery_sequence(hspi, FM, 9);
recovery_sequence(hspi, FM, 13);
recovery_sequence(hspi, FM, 17);
recovery_sequence(hspi, FM, 25);
recovery_sequence(hspi, FM, 33);
// Step 2: Interface rescue
interface_rescue(hspi, FM);
return HAL_OK;
}
HAL_StatusTypeDef MT25QL_PowerLossRecovery(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM)
{
// Step 1: Recovery sequence
recovery_sequence(hspi, FM, 7); // Example for 7 clock cycles
recovery_sequence(hspi, FM, 9);
recovery_sequence(hspi, FM, 13);
recovery_sequence(hspi, FM, 17);
recovery_sequence(hspi, FM, 25);
recovery_sequence(hspi, FM, 33);
// Step 2: Power Loss Recovery
power_loss_recovery(hspi, FM);
return HAL_OK;
}
Helper functions
static void recovery_sequence(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM, uint8_t clock_cycles) {
uint8_t dummy_data[34] = {DUMMY_CLOCKS}; // Max needed cycles is 34
csLOW(FM);
SPI_Write(hspi, dummy_data, clock_cycles);
csHIGH(FM);
}
static void power_loss_recovery(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM) {
uint8_t dummy_data[8] = {DUMMY_CLOCKS};
csLOW(FM);
SPI_Write(hspi, dummy_data, 8);
csHIGH(FM);
//HAL_Delay(1); // Ensure tSHSL2 >= 50ns
}
static void interface_rescue(SPI_HandleTypeDef *hspi, MT25QL_FM_NO_t FM) {
uint8_t dummy_data[16] = {DUMMY_CLOCKS};
csLOW(FM);
SPI_Write(hspi, dummy_data, 16);
csHIGH(FM);
//HAL_Delay(1); // Ensure tSHSL2 >= 50ns
}
2024-06-16 06:44 AM
What's DUMMY_CLOCK in this context? One byte in the array.
Says to set DQ0 Bit HIGH on the pin interface, and DQ3/HOLD pin HIGH, and then clocking
Do you even connect the DQ3/HOLD pin in your design? Use a pull-up?
2024-06-16 08:17 AM
DUMMY_CLOCK is 0xFF in my code. Yes, DQ0 is connected to my MOSI line and DQ3 is held high by default using a GPIO pin.
Question, if I'm understanding this correctly, I should be sending 7 bits, cs HIGH, csLOW, 9 bits, cs HIGH, csLOW, then 13 bits, and so on?
My current implementation sends bytes currently so 7 bytes * 8 clocks / byte = 56 clock cycles.
2024-06-16 08:28 AM - edited 2024-06-17 07:06 AM
You're sending a magic sequence of all ONEs to MOSI
You might have to do this sequencing void direct GPIO interaction, not using the SPI peripheral.
And you need a brief break time between sequences with the chip select.
Perhaps use a scope or logic analyzer to confirm the correct pattern if having trouble.