2024-03-22 06:25 AM - edited 2024-03-22 07:24 AM
I am working with an STM32F107VCT6TR MCU to communicate with an M95M04-DRMN6TP component over SPI3.
The pins are set up as follows:
PB7(93) -> HOLD(7)
PB6(92) -> W(3)
PA15(77) -> S(1)
PB5(91) SPI3_MOSI -> D(5)
PB4(90) SPI3_MISO -> Q(2)
PB3(89) SPI3_SCK -> C(6)
Hardware NSS Signal is disabled, in preference to running the NSS signal via Software using PA15 low when I want to communicate with the component, and high otherwise, per the M95M04-DR datasheet. I've tried enabling the hardware NSS signal, but that approach did not seem to work well for me (and elsewhere on the forum, people seemed to not recommend this approach). I have no other components that require communicating over SPI3, so I thought it might work for me, but... oh well.
Clock parameters are set CPOL low, CPHA 1 Edge. Data Size is 8 bits, with the First Bit set as MSB First. Frame Format is set to Motorola. This matches the first SPI mode supported by the M95M04-DR, to include ensuring MSB is set First.
I've looked at how other folks communicate over SPI, and about the only thing different that I see when working with this component is the need to send instructions and receive responses, which seem relatively well-defined in the datasheet. Other oddities include the HOLD and W pins, but I don't think I need to use these for my current application.
This out of the way, I want to WRITE to the EEPROM, then READ what I have written to validate that it is there.
To do this, I set PA15 low first, send WREN (a 'write enable' command), then set PA15 high, delaying by 10 milliseconds (which should seem like an eternity, but I don't quite know how long I should wait to ensure the component reads this as high, and thus executes the instruction).
Then, I set PA15 low again, send WRITE, send the uint32_t address I want to use to store (I think for my test I've set it to 0), then the data I want to store in the EEPROM, and set PA15 high to indicate that I've finished.
I receive no errors for any of this. All data is sent using HAL_SPI_Transmit(&hspi3, [data], [data_size], 100) without timing out.
Then, I set PA15 low, send READ, send the uint32_t address I want to read (again, 0), and receive the same size as I sent, before setting PA16 high again, using HAL_SPI_Receive(&hspi3, [data], [data_size], 100) to do the reading.
I always receive all-bits-on for everything, which is the default data within the EEPROM.
This is not what I want to see, of course.
Out of curiousity, I tried using the M95M04-DR's RDSR command to read the status register, on the odd chance maybe I might learn something from this. It also returns all-bits-on for the result, no matter when I call it.. I can call it before writing anything, reading anything... doesn't matter, it always returns all-bits-on. Which, according to the datasheet, should indicate that it won't receive instructions, since one of those bits is the "WIP" bit, a read-only flag indicating if the device is busy. This also means the WEL and BP0, BP1 bits are all on... which shouldn't be the state of things when it first starts (unless BP0/BP1 were set using a WRSR instruction, which I never used).
For whatever it's worth, I am writing the firmware, but another employee is handling the hardware, so if this is a hardware issue, I'll need to relay that to my coworker. Still, what I described above is all I know about how the hardware is connected, short of maybe some additional details in the schematic:
(which isn't really much more than what I've already written, I suppose... except to note that the board I currently have has a correction for the SPI3_MOSI, so what you see in the schematic for that is not what I am working with on the corrected board... rely instead on what I wrote earlier in this post).
In case it matters, here's some relevant code, short of what the ioc generates:
void StartS()
{
HAL_GPIO_WritePin(EEPROM_S_GPIO_Port, EEPROM_S_Pin, GPIO_PIN_RESET);
}
void StopS()
{
HAL_GPIO_WritePin(EEPROM_S_GPIO_Port, EEPROM_S_Pin, GPIO_PIN_SET);
}
HAL_StatusTypeDef EEPROM_SetWhy(uint16_t* where, uint16_t why, HAL_StatusTypeDef err)
{
if (where != NULL)
*where = *where | why;
StopS();
return err;
}
HAL_StatusTypeDef EEPROM_Write(uint32_t addr, const char* data, size_t size, uint16_t* why)
{
HAL_StatusTypeDef result = HAL_OK;
if ((result = EEPROM_WriteEnable(why)) != HAL_OK)
return EEPROM_SetWhy(why, ERR_EEPROM_WRITE_ENABLE, result);
StartS();
if ((result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&EEPROM_WRITE, 1, 100)) != HAL_OK) {
return EEPROM_SetWhy(why, ERR_EEPROM_COMMAND_TRANSMIT, result);
}
result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&addr, sizeof(addr), 100);
if (result != HAL_OK) {
return EEPROM_SetWhy(why, ERR_EEPROM_SEND_DATA, result);
}
result = HAL_SPI_Transmit(&hspi3, (uint8_t*)data, size, 100);
if (result != HAL_OK) {
return EEPROM_SetWhy(why, ERR_EEPROM_SEND_DATA, result);
}
StopS();
return result;
}
HAL_StatusTypeDef EEPROM_Read(uint32_t addr, char* data, size_t size, uint16_t* why)
{
HAL_StatusTypeDef result = HAL_OK;
StartS();
if ((result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&EEPROM_READ, 1, 100)) != HAL_OK)
return EEPROM_SetWhy(why, ERR_EEPROM_COMMAND_TRANSMIT, result);
result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&addr, sizeof(addr), 100);
if (result != HAL_OK) {
return EEPROM_SetWhy(why, ERR_EEPROM_COMMAND_TRANSMIT, result);
}
if ((result = HAL_SPI_Receive(&hspi3, (uint8_t *) data, size, 100)) != HAL_OK)
return EEPROM_SetWhy(why, ERR_EEPROM_READING_DATA, result);
StopS();
return result;
}
HAL_StatusTypeDef EEPROM_WriteEnable(uint16_t* why)
{
HAL_StatusTypeDef result = HAL_OK;
StartS();
if ((result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&EEPROM_WREN, 1, 100)) != HAL_OK)
{
return EEPROM_SetWhy(why, ERR_EEPROM_WRITE_ENABLE, result);
}
StopS();
HAL_Delay(10);
return result;
}
Is there anything obvious, or even not-obvious, that I am missing here? I don't understand why the RDSR is always returning -1.
Solved! Go to Solution.
2024-04-04 04:14 AM
The M95M04-DRMN6TP has a HOLD and W pin. These pins also influence whether or not one may communicate with the component properly, and need to be HIGH to permit communications.
I went into the .ioc file, expanded System Core, selected GPIO, selected the pins going to S, W, and HOLD, and set 'GPIO Output level' to 'High' so that gpio.c would set these to high during initialization.
This resolved the problem. I can communicate with the component properly now.
2024-03-22 07:18 AM
Have you used a scope or logic analyser to see what's happening on the wires?
@treyvr wrote:Hopefully, someday, the folks who maintain this website may find a way to allow us to post code more comfortably, as this is not optimal... but I understand the challange
They have provided this button:
Which gives code looking like this:
HAL_StatusTypeDef EEPROM_WriteEnable( uint16_t* why )
{
HAL_StatusTypeDef result = HAL_OK;
StartS();
if ((result = HAL_SPI_Transmit(&hspi3, (uint8_t*)&EEPROM_WREN, 1, 100)) != HAL_OK)
{
return EEPROM_SetWhy( why, ERR_EEPROM_WRITE_ENABLE, result );
}
StopS();
HAL_Delay(10);
return result;
}
There's a Feedback Forum for feedback on the forum itself:
2024-03-22 07:21 AM
RE: Scope
Unfortunately, I lack a good scope to examine the wires. I'll have to ask my coworker to do that.
RE: Formatting
Argh... I should have used that. I'll see if I can edit the post accordingly.
2024-04-04 04:14 AM
The M95M04-DRMN6TP has a HOLD and W pin. These pins also influence whether or not one may communicate with the component properly, and need to be HIGH to permit communications.
I went into the .ioc file, expanded System Core, selected GPIO, selected the pins going to S, W, and HOLD, and set 'GPIO Output level' to 'High' so that gpio.c would set these to high during initialization.
This resolved the problem. I can communicate with the component properly now.