B-G431B-ESC1 Flash Memory Latency Setting

The “sensorless” guys figured out that the default settings for the B-G431B-ESC1 are suboptimal and there is documentation from STM supporting that. In order to improve the performance of the board one has to modify one constant in variant_B_G431B_ESC1.cpp (FLASH_LATENCY_8 → FLASH_LATENCY_4) in one line of code (it is the only occurence in there). This speeds up code execution from flash significantly. I have implemented it and everything was great and fast, except for one thing: Reading from SPI is a problem now. In my setup with an SPI connected AS5047 sensor I cannot read the magnitude of the magnetic field anymore, the sensor will always return the position instead. My best guess is that this is a timing issue (only one bit differs between the address for reading the angle (3FFE or 3FFF) and reading the magnitude (3FFD). I have tried this in different setups and it is repeatable, even without power to the motor, just USB power and turning the motor by hand. To further complicate things, my cheap, crappy USB scope is to slow to analyse this and if I hook up the same cheap thing as logic analyzer, it fails with 8 wait states as well, so I might be facing an electrical problem. A simple code sequence to test the behaviour is:

while (true)
	int m1 = sensor.readMagnitude();

Normaly the readings should be fairly stable, but in the bad case It reads the angle of the sensor.
Any ideas or similar observations? It would be a pitty if we cannot use the optimized settings for the flash latency…

I presume you are using MagneticSensorSPI.h.

What does your MagneticSensorSPIConfig_s look like. The simplefoc code flips a couple of bits for parity and read/write - perhaps it is always flipping that bit to 1?

MagneticSensorSPIConfig_s AS5147_SPI = {
  .spi_mode = SPI_MODE1,
  .clock_speed = 1000000,
  .bit_resolution = 14,
  .angle_register = 0x3FFF,
  .data_start_bit = 13,
  .command_rw_bit = 14,
  .command_parity_bit = 15

… sets bit 14 and 15.

If the above is a red herring, then you could try slowing the clock down to 250,000. Technically it is possible to switch speed for each beginTransaction so you could read magnitude slow and angle fast.

This sounds suspiciously like the issue with the MT6835, which was caused by an inappropriate order of operations with the nCS pin.

Here’s the as5047u code

uint16_t AS5047U::spi_transfer16(uint16_t outdata) {
	if (nCS>=0)
		digitalWrite(nCS, 0);
	uint16_t result = spi->transfer16(outdata);
	if (nCS>=0)
		digitalWrite(nCS, 1);
	errorflag = ((result&AS5047U_ERROR)>0);
	warningflag = ((result&AS5047U_WARNING)>0);
	return result;

Here’s the MT6835 read angle code

uint32_t MT6835::readRawAngle21(){
    uint8_t data[6]; // transact 48 bits
    data[0] = (MT6835_OP_ANGLE<<4);
    data[1] = MT6835_REG_ANGLE1;
    data[2] = 0;
    data[3] = 0;
    data[4] = 0;
    data[5] = 0;
    if (nCS >= 0)
        digitalWrite(nCS, LOW);
    spi->transfer(data, 6);
    if (nCS >= 0)
        digitalWrite(nCS, HIGH);
    laststatus = data[4]&0x07;
    lastcrc = data[5];
    return (data[2] << 13) | (data[3] << 5) | (data[4] >> 3);

Seeing these, could you change the order of the if statement for nCS and begin/end transaction to match the mt6835 and try it?

1 Like

I tried to follow your hints, but I am using the ckass MagneticSensorAS5047, which looks quite different from you posted. and it is directly derived from Sensor and not MagneticSensor. While checking this however, I found that here is another class MagneticSensorAS5047U, which would match my sensor exactly, but I am not aware of any relevant differences between those sensors. Also, I could not identify any functional differences in the code, but I cannot simply replace one of the two by the other, since many names are different. Also, I tried lowering the speed, but it made no difference.

At first, I thought that must be it, but unfortunatetly, no change :disappointed_relieved:.

Meanwhile I also tried the MagneticSensorAS5047U and reduced my program to the bare minimum, but no change. 8 waitstates are fine, with 4 the sensor fails. It’s a pitty, since 30% more speed are really tempting. Nevertheless, I’ll give up here, since I do not really need it and without a proper scope I just don’t know what is going on on the SPI. I will see if I can borrow a scope and then come back to it, but that’s going to take some time.

I think I’ve got one of those sensors, I’ll try to see if I can replicate the issue.

I think a cheap logic analyzer should be able to make useful measurements so long as the bus frequency is below 10MHz or so, that’s what I’ve been using. Something like this: https://www.amazon.com/HiLetgo-Analyzer-Ferrite-Channel-Arduino/dp/B077LSG5P2/

I have something like this, a Hantek 6022BL and it is supposed to work up to 20MHz. The software either the free one or the one from Hantek is however not anything I would call fun to use. I am never sure what I do there, it takes 15 minutes to get it work since it requires special USB drivers, trigger functions are very much restricted and the PC/Laptop is never where you need the scope. In theory the scope should be fine for this purpose, but either I am to stupid to operate it or it just isn’t suitable. Or, maybe I just want a RigolDHO900… I could have an analog problem as well since connecting the logic analyzer probes also leads to wrong SPI readings, but it still doesn’t explain the dependence on flash wait states, since it is a hardware SPI. Anyway, don’t worry, it is more a nice to have for me than a real problem, 5kHz loop frequency are easy enough (but 8kHz…).

I just got a new rigol dho814, its nice. :slight_smile: The $12 logic analyzer with sigrok pulseview software is better for troubleshooting logic problems with SPI than the scope, but obviously can’t do analog troubleshooting.

If connecting the scope changes the behavior it sounds like an analog problem. I’m not sure why the flash latency would impact it other than when stuff goes faster, little stuff can start to matter more.

Being that you’re using the bg431esc with an spi sensor, what’s the cabling to the sensor look like? If possible, you could use the ABI interface on your sensor with the stm32 hw encoder class, and get loop rates of 20-35khz similar to what I reported on discord. I assume the pin assignments conflict with the SPI bus, so you’d need to program the sensor, then switch the wiring over.

The AS5047U is a “more professional” version of the sensor, with some extra features. These include some filtering functions the D and P versions don’t have, and importantly, 24 and 32 bit SPI transfers including CRC checks.
The U version supports 16 bit transfers on read operations (then there is no CRC) but for SPI writes you have to use 24 or 32bit transfers, and include a CRC checksum.

The MagneticSensorAS5047U implements the 24bit SPI writes, compared to the MagneticSensorAS5047 class, which only handles 16 bit SPI reads/writes. So it is important to use the right driver, or you won’t be able to write any settings.

I think this is a good candidate idea to try. Assuming you’re using the MagneticSensorAS5047U driver now to match your chip, you can change it in this line: https://github.com/simplefoc/Arduino-FOC-drivers/blob/76be5381511fedd02006cb18cbff18644fa15995/src/encoders/as5047u/AS5047U.cpp#L296
Basically, move line 296 to be above line 294.

I am aware of those differences, but since I am only reading from the sensor it shouldn’t matter and in fact, it works all fine with the 8WS settings. Nevertheless, I followed your advice of course and have also tried the MagneticSensorAS5047U class with and without swapped code lines and the effect was exactly the same.
Anyway, as I wrote before, for me this is a nice to have since everything is working fast enough with 8WS. I just would like to understand the problem and make sure it is not a real problem which is obscured in the 8WS case.

Just as background info: I have four sensors in action, two are AS5147 and two are AS5047U (should be at least, if JLC did it right). This comes from the time when you had to take which ever components you could get… I want to stay with SPI since I want to detect loose magnets in an early stage to avoid fried ECSs etc. My magnets are invisible and difficult to reach, so monitoring the magnetic magnitude is a good feature. SPI also allows me to use sensor calibration.

Hey @Grizzly,

Thanks so much for trying it out. In that case, it seems the SPI timing bug we found with MT6835 isn’t the same problem here.

I must admit I have no idea why this is happening - perhaps the SPI clock setup has to be done differently for 4-waits?

This is how I’m configuring the MT6835 SPI on the other board that I use with the g431 at 4-waits. I still haven’t had a chance to test with the sensor and dev board I have on hand, unfortunately.

SPISettings myMT6835SPISettings(168000000 / 10, MT6835_BITORDER, SPI_MODE3);
MagneticSensorMT6835 sensor = MagneticSensorMT6835(ENC_CS, myMT6835SPISettings);

Here’s a link to the clock config for that board.

1 Like

That’s exactly what I do as well (but with a different sensor of course).

Finally I found some time to look into this problem again and I believe I found the reason for the failure. Between two command sequences, the CS signal is kept low for most of the time and only before the start of the next sequence it is briefly taken high and then immediately low again. In the good case it is high for app. 1us, in the bad case for app. 250ns and therefore out of spec for the sensor (>350ns required). I did not yet look into the code, but, @runger, is there a reason for keeping the CS low for so long? Is that required for anything (SSI…)?

The good news is, I got it to work somehow, the sad news is that it’s neither clean nor do I fully understand all potential side effects. The main problem seems that my CS pin is one, which is supported by the hardware as CS (PA15=SPI1_NSS). This leads to conflicts and the HAL wants handle the CS instead of leaving it to the SPI class. After the HAl initialized SPI, the pin mode is reset and it can’t be used as GPIO anymore. The work around is to reset the mode again in AS5047U::spi_transfer16(). In principle, it would be nice, to leave the CS handling to the hardware, but I did not get that to work, nor could I tell it to leave the port untouched. It is not trivial, since we have various layers of software that deal with the CS pin. SimpleFOC checks if it is <0, the SPI class checks if it is NC, which is an enum resolving to 0xffffffff, which may or may not be <0, depending on the data type and finally, there is the HAL, which does its own thing that I did not yet understand.

This is happening even when you don’t pass the pin to the SPI object during initialisation of the SPI?

Purely through passing the pin to beginTransaction()?

I’m surprised!

1 Like

OMG, as so often, the problem is in front of the computer! I completely misunderstood the usage and passed the pin to both objects! If the problem fixes the code, it works fine :wink: (as far as I can tell so far)!