Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with SPI Mode 3 on STM32F469 #984

Closed
hshose opened this issue Mar 22, 2023 · 3 comments · Fixed by #994
Closed

Problem with SPI Mode 3 on STM32F469 #984

hshose opened this issue Mar 22, 2023 · 3 comments · Fixed by #994

Comments

@hshose
Copy link
Contributor

hshose commented Mar 22, 2023

I'm trying to use SPI in Mode 3 on STM32F469, like this:

Details (click to see complete main.cpp)

Cs::reset();
RF_CALL_BLOCKING(SpiMaster::transfer(0xaa));
RF_CALL_BLOCKING(SpiMaster::transfer(nullptr, buffer.data(), 1));
Cs::set();
modm::delay(20us);
SpiMaster::setDataMode(SpiMaster::DataMode::Mode3);
modm::delay(20us);
Cs::reset();
RF_CALL_BLOCKING(SpiMaster::transfer(0xaa));
RF_CALL_BLOCKING(SpiMaster::transfer(nullptr, buffer.data(), 1));
Cs::set();
#include <modm/board.hpp>
#include <modm/processing.hpp>

using namespace Board;

using SpiMaster = modm::platform::SpiMaster2;

using Cs   = D9;
using Mosi = D11;
using Miso = D12;
using Sck  = D13;


int
main()
{
    Board::initialize();
    Cs::setOutput(modm::Gpio::High);

    SpiMaster::connect<Miso::Miso, Mosi::Mosi, Sck::Sck>();
    SpiMaster::initialize<Board::SystemClock, 351_kHz>();

    MODM_LOG_INFO       << "==========SPI Mode 3 The Fuck Test==========" << modm::endl;


    std::array<uint8_t,2> buffer;

    Cs::reset();
    RF_CALL_BLOCKING(SpiMaster::transfer(0xaa));
    RF_CALL_BLOCKING(SpiMaster::transfer(nullptr, buffer.data(), 1));
    Cs::set();

    modm::delay(20us);
    SpiMaster::setDataMode(SpiMaster::DataMode::Mode3);
    modm::delay(20us);

    Cs::reset();
    RF_CALL_BLOCKING(SpiMaster::transfer(0xaa));
    RF_CALL_BLOCKING(SpiMaster::transfer(nullptr, buffer.data(), 1));
    Cs::set();

    while (true)
    {
    
        Board::LedOrange::toggle();
    }

    return 0;
}

In the default (mode 0) everything works fine, however, after I change to mode 3, the CS goes high one clock cycle early and there are another 7 (wtf?) clock cycles.

Im a bit puzzled...

image

According to RM0386, it looks like the setDataMode function sets the correct bits in the SPI_CR1 register...

@rleh
Copy link
Member

rleh commented Mar 22, 2023

I can't reproduce the bug on Nucleo-F429ZI (using both SpiMaster1 and SpiMaster2):

image

Code

@chris-durand
Copy link
Member

I can reproduce it on a Nucleo F446ZE:
SCR03

(The scope decoding function is set up for SPI mode 3. Thus, decoding the first two bytes fails although the data is fine).

The issue is that reconfiguring the SPI mode is not allowed while the peripheral is enabled. In the initialize() function it is done correctly.

When I'm doing

SPI2->CR1 &= ~SPI_CR1_SPE;
SpiMaster::setDataMode(SpiMaster::DataMode::Mode3);
SPI2->CR1 |= SPI_CR1_SPE;

everything works as it should:
SCR04

I haven't looked at a solution in detail, but probably the setDataMode() function should take care of disabling the peripheral while changing the setting.

@hshose
Copy link
Contributor Author

hshose commented Apr 6, 2023

The solution by @chris-durand works well. In addition, we had to add __DSB().
This is what a complete lambda inside a configuration handler could look like:

	this->attachConfigurationHandler([]() {
		SPI2->CR1 &= ~SPI_CR1_SPE;
		__DSB();
		SpiMaster::setDataMode(SpiMaster::DataMode::Mode3);
		SPI2->CR1 |= SPI_CR1_SPE;
		__DSB();
	});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants