2020-01-22 06:49 AM
Hi All,
We have problem reading register values from L9945. We use STM32G474RE to communicate with it and the project was made using current STM32CubeMX and its FreeRTOS.
Here are the SPI parameters in main.c:
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
Here is the code using a HAL call to send and receive the register values, including temporary logging to produce raw sent/received output:
std::optional<uint32_t> nowtech::L9945::read(uint32_t const aCommand) noexcept {
std::optional<uint32_t> result;
prepareDataToSend(cFixedPatternValues[aCommand] | cMaskRead);
mPinChipSelect.write(Gpio::State::cOn);
auto log = Log::i(nowtech::LogTopics::system); log << " read out: "; for (int i = 0; i < cSizeofRegister * 2u; ++i) log << LC::cX2 << mDataOut[i] << ' '; log << Log::end;
if(aCommand < cRegisterCount && HAL_SPI_TransmitReceive(mSpiHandle, mDataOut, mDataIn, cSizeofRegister * 2u, mSpiTimeout) == HAL_OK) {
auto log = Log::i(nowtech::LogTopics::system); log << " read in: "; for (int i = 0; i < cSizeofRegister * 2u; ++i) log << LC::cX2 << mDataIn[i] << ' '; log << Log::end;
uint32_t value = (static_cast<uint32_t>(mDataIn[4]) << 24u) |
(static_cast<uint32_t>(mDataIn[5]) << 16u) |
(static_cast<uint32_t>(mDataIn[6]) << 8u) |
mDataIn[7];
if(value == cInvalidResponse || calculateParity(value) == cInvalidParity) {
mReadCache[aCommand] = cInvalidResponse;
}
else {
mReadCache[aCommand] = value;
result = value;
}
}
else { // perhaps store HAL error, but not now
}
mPinChipSelect.write(Gpio::State::cOff);
return result;
}
Now we first set SPI input select on channel 1 to true (write to reg 0). Then read the battery voltage (read from reg 13) and then SPI input select (read from reg 0).
defaultTask 0000025 SYSTEM write out: 00 02 00 01 f0 00 00 01
defaultTask 0000025 SYSTEM write in: f3 40 7c bf 00 02 00 01
defaultTask 0000025 SYSTEM read out: da aa aa ab f0 00 00 01
defaultTask 0000025 SYSTEM read in: f3 40 7c bf da aa aa ab
defaultTask 0000026 SYSTEM read out: 08 00 00 01 f0 00 00 01
defaultTask 0000026 SYSTEM read in: f3 40 7c bf 08 00 00 01
Although the write seems to function, the read merely echoes back the command used to initiate the read process. The voltage and temperature values are independent of the actual situation. Actually no matter what are the bits 1-26 in a read command, their values will be returned as long as the parity is correctly set.
For all operations, the last command is intentionally corrupt (invalid reg and parity bit).
Here is a logic analyzer screenshot for the voltage read process:
...and from the SPI select bit read process:
What can be the problem?
Thank you in advance.
Best regards: Balázs Bámer
Solved! Go to Solution.
2020-01-23 03:03 AM
I reply to myself. A collegue has pointed out that perhaps the L9945 wants to forward the command to its siblings via daisy chain. And yes, this was the case. Turning off CS between two words yields correct SPI communication.
2020-01-23 03:03 AM
I reply to myself. A collegue has pointed out that perhaps the L9945 wants to forward the command to its siblings via daisy chain. And yes, this was the case. Turning off CS between two words yields correct SPI communication.