MagneticSensorSPI and MA730 sensor

I’ve bought a couple of MA730 14bit magnetic sensors and am intending to use them in SPI mode.

I’m finding that the MagneticSensorSPI class isn’t working great ‘out of the box’ and I’m guessing it really only works with a AS5047U. By not great - it returns the lower 8bits shitfed up 6bits and some random bits at the end.

I can get the MA730 to work better by borrowing code from:

That library uses SPI_MODE3 instead of SPI_MODE1 and doesn’t send a command to read - it simply listens. It also has a long running spi.beginTransaction()

So I guess the question I’m asking is should ma730 be implemented as a separate sensor class or should MagneticSensorSPI squeeze in logic for both.

As a side note this sensor (and the library above) supports SSI and PWM - both on the roadmap. It also supports incremental encoder output which I think is the mode @David_Gonzalez is using on his older Janus board.

@Owen_Williams I did use the MA730 for the Janus Controller, but only the ABI signals and they worked perfectly :slight_smile: .

I recently got the AS5147 for my new boards and I’m having a lot of trouble getting them to work. I connected the ABI signals as well as SPI, but I’m testing ABI first. I have a peace of code that I always use to test ABI encoders and the AS5147 worked perfectly, but if I try to use the encoder class of the library and print the position (getAngle) it seems like the interrupts aren’t working properly and the position printed is not the value it should be.

I wonder if maybe the library should allow the user to pass the positions each loop iteration so that we can write our own peace of code and have the library be less hardware specific. What do you think?

It’s possible that it is a timer thing. I.e. the timer used to count the encoder is being used/prescaled for something else?

Have you tried if the sensor encoder class works alone, i.e no BldcMotor

I’ve got an as5147u and can do some testing if you like. Isn’t SPI preferable? It’ll give absolute angle which means you can skip calibration step.

I think your idea about being able to pass your own values might work in loop but is harder to do for initFOC calibration. It isn’t too difficult to write your own sensor implementation, that would be preferable.

Please do, I’d appreciate your help. :slight_smile:

I just tested the SPI sensor of the library out of the box and it didn’t work. I found this peace of code online and needed to add a bit of delay between transfers for it to work. I don’t understand why this is written like this and it seems it only works at 10mhz.

#include <SPI.h>

//Set Slave Select Pin
//MOSI, MISO, CLK are handeled automatically
int CSN = 16;
unsigned int angle;

void setup() {

  Serial.begin(115200);

  //Set Pin Modes
  pinMode(CSN, OUTPUT);
  //Set Slave Select High to Start i.e disable chip
  digitalWrite(CSN, HIGH);
  //Initialize SPI
  SPI.begin();
  Serial.println(MOSI);
  Serial.println(MISO);
  Serial.println(SCK);
}

void loop() {

  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));

  //Send the Command Frame
  digitalWrite(CSN, LOW);
  delayMicroseconds(1);
  int resp = SPI.transfer16(0xFFFF);
  digitalWrite(CSN,HIGH);

  delayMicroseconds(10);
  //Serial.println(resp);

  //Read data frame
  digitalWrite(CSN, LOW);
  delayMicroseconds(1);
  angle = SPI.transfer16(0xC000);
  digitalWrite(CSN, HIGH);
  SPI.endTransaction();

  delayMicroseconds(10);
  //Serial.println(angle);

  angle = (angle & (0x3FFF));

  float pos = ( (unsigned long) angle)*360UL/16384UL;

  Serial.println(pos);

  delay(10);

}

And you’re right, for the calibration it might be tricky. I guess maybe something like a framework (maybe an empty .cpp) for the users to implement their position taking and have the library do all the work: calibration, velocity calculation, etc.

I take it that you are still talking about the as5147u not working out of the box?

I’m pretty sure MagneticSensorSPI worked for me, although it took me a while because I’d wired it up wrong. I’ll give it another go, soon. I don’t think the register address is correct for as5147. That code look like it’s for ma730

My bad, yes, everything I said on my previous post is about the AS5147, the code I posted worked, the MagneticSensorSPI didn’t work for me.

I am using MT6816, and it work well, not using the MagneticSensorSPI but derived another class from class Sensor. I also want to try MA730 and making the test board, it had been sent to factory, and I will get it on Sunday.

Because the as5048 built-in ADC significant bit problem. Because there are significant bits in all ADC circuits, the real effective output accuracy is lower than the physical accuracy due to the influence of op amp noise and nonlinearity in AD sampling processing. For example, the effective precision of 14 bit ADC circuit is 11 bits. The physical ADC bits of as5048 are 14 bits, and the output effective precision is 11 bits. Therefore, the output jitter of the last three bits is normal. If higher precision is needed, the multi sampling data can be added and averaged, such as 20 times of data average, so as to get higher accuracy.
In addition, “magnetic sensor SPI” uses 8bit to read twice, and then reads back the data again. The time efficiency is half as low as that! According to the manual of 5048b, it is 16bit, not 8bit.

I’ve tried another magnetic encoder “tle5012b”, which is better than 5048b.

By the way, thank you again. I got a piece of drv8323. In your simplest way, SPI communication is successful… At present, I refer to the method in VESC project, and use software to simulate SPI, which is also successful! Arduino and STM32, no matter which one, SPI library files are written so that beginners look too difficult to understand.

@David_Gonzalez - your code worked for me. But I think you got lucky.
(I’m new to SPI so please point out my mistakes)

int resp = SPI.transfer16(0xFFFF);
Your asking for data from sensors 0xFFFF register. Note the actual value stored in your resp variable is isn’t necessarily 0xFFFF register! The resp is ‘here is the value from your previous command’. The first time we enter this loop the response is whatever the sensor feels like returning! Think of the register argument as queueing up a request for next time.

The datasheet does not have a 0xFFFF register. I think it may have therefore ignored this instruction. Register should be 0xCFFF (error corrected angle). You don’t need to store the response. I’d therefor change above line to:
SPI.transfer16(0xCFFF);

Later you call
angle = SPI.transfer16(0xC000);
So you are saying 'store value from last command into angle and queue up a read on 0xC000 (which also doesn’t exist in datasheet). I’d probably change this to
angle = SPI.transfer16(0x0000);

0x0000 register is described on datasheet as ‘no operation’.

I tried the MagneticSensorSPI code also and it worked ‘out of the box’ with ESP32 and AS5047U. It should work for you. I suspect you are supplying the wrong register argument in constructor.
Try this:

#include <SimpleFOC.h>

//  CS 16
//  SCLK 18
//  MISO 19
//  MOSI 23

MagneticSensorSPI sensor = MagneticSensorSPI(16, 14, 0x3FFF);

void setup() {
  // monitoring port
  Serial.begin(115200);

  // initialise magnetic sensor hardware
  sensor.init();

  Serial.println("Sensor ready");
  _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
  Serial.print(sensor.getAngle());
  Serial.print("\t-\t");
  Serial.println(sensor.getVelocity());
}

Of interest (to me) is that you can also get a smoothed velocity out by reading 0xCFFC. It’s 14bit twos complement so needs some massaging:

  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));

  //Send the Command Frame
  digitalWrite(CSN, LOW);
  delayMicroseconds(1);
  SPI.transfer16(0xCFFC);
  digitalWrite(CSN,HIGH);
  delayMicroseconds(1);

  //Read data frame
  digitalWrite(CSN, LOW);
  delayMicroseconds(1);
  uint16_t raw_velocity = SPI.transfer16(0x0000);
  digitalWrite(CSN, HIGH);
  delayMicroseconds(1);
  SPI.endTransaction();

  raw_velocity = (raw_velocity & (0x3FFF));

  int16_t vel = (int16_t) (raw_velocity > 8192 ? raw_velocity - 16384 : raw_velocity);
  Serial.println(vel);

Units are degrees/second

@Owen_Williams I tried the code as you suggested but it didn’t work. I went into the MagneticSensorSPI.cpp and changed

settings = SPISettings(1000000, MSBFIRST, SPI_MODE1); 

to

settings = SPISettings(10000000, MSBFIRST, SPI_MODE1);

and it did work, as in I can print a position and seems to be ok, unfortunately I haven’t been able to make the whole system work just yet.
Where do you find these registers? I can’t find such things on the datasheet. The smoothed velocity might be a game changer for some applications.

@blackblue007 I’m glad you got your DRV8323 working with my really simplistic SPI example.

The SPI registers for AS5147u are listed on figure 33 page 26 of the datasheet:
https://ams.com/documents/20143/36005/AS5147U_AS5247U_DS000639_3-00.pdf/cdee4919-55ab-4336-fd4c-33301bb486be

Another pair of registers that are interesting are agc (gain) and magnitude. These will tell you if your magnet is the right distance from the sensor. This sensor comes with a magnet (N35H, 8mm diameter; 3mm diametric). But the MA730 did not. I’m using these for my MA730 (10x = £3).

You should be able to go as slow as you like with SPI. I wonder if you have noise on your CLK pin or something? You haven’t added any pullups/downs have you? Not normally needed if you are using standard pins.

That explains it. I’ve got the AS5147p, not the As5147u. Both seem rather expensive, it might be a better bet to still go with the MA730 in the future.
None of the sensors I’ve bought has come with a magnet, the only magnets I have are some rather long ones that I managed to find in Mexico.

I’ll check my CLK pin for noise, but I don’t think that is the problem. I don’t have pull up/down, though I share the CLK, miso and mosi pins with the DRV8305.

“I’ll check my CLK pin for noise, but I don’t think that is the problem. I don’t have pull up/down, though I share the CLK, miso and mosi pins with the DRV8305.”

–>share the CLK, miso and mosi pins!!!

Therefore, your “miso”-pin should be pulled up in hardware mode.

Hey Guys,

This is an interesting topic. The MagneticSensorSPI is not too robust, it is just an implementation that worked well on AS5047 and AS5048. This was the idea.
But I would argue that AS5147, MA730 and similar dont need a new class.

Essenstially all the spi sesnsors do the same thing:
CS on >
send address >
CS off >
(wait a bit) >
CS on >
transfer data request >
CS off

This is implemented in the library at the moment. There are sensors that do not need this intial address but are wired to send the data directly after the first request. These sensors would not need to have MOSI pin connected (very attractive for Arduino UNO) and this is not complicated to implement.

Therefore I would prefer to implement all the SPI in the same class.
At the moment this class has almost no configuration.

The clock is an important parameter and that is definitely something that we will make configurable. Maybe also the wait times in between send requests.

@David_Gonzalez Ecnoder class code is the simplest encoder code has the simplest encoder logic possible :smiley:
If this doesn’t work then there is a problem with something else, maybe timers as @Owen_Williams suggested.
Maybe also the 3.3V/5V compatibility or something like that.

@Owen_Williams the SSI mode I would certainly like to implement in this library. And this library seems to do it very elegantly, using SPI class. This code works well for your sensor?

@Antun_Skuric - I’ve added support for MA730 and made i2c and spi more configurable wrt clock_speed, mode, parity bits, etc. See new PR in github targeting dev branch.

1 Like

@blackblue007 I got the waveforms of the sensor working properly :slight_smile:
This is MISO and CLK

This is MOSI and CLK

Thanks for the help @Antun_Skuric and @Owen_Williams. I haven’t tried to use ABI since I’ve beenusing SPI, but it seems like all the problems I was having were because of hardware. Issues I detailed at ESP32 Brushless controller - Dagor (work in progress).

2 Likes

Ordered some ma730 today:)

Sir Owen:) Ive got an MA730 Sitting hooked up on the desk here:), the official Monolithic Power systems lib for it reads out the data nice but I am having a little bit of bother finding what to you from your pull request to have a working example for my esp32. Any hints would be appreciated.