Temperature monitoring on B-G431B-ESC1

Hi, all. Some of you may find this quite useful.

I took some time today to figure out how to use temperature monitoring on the B-G431B-ESC1 with simpleFOC, as the board has a thermistor on pin PB14. After looking through some STM32CubeIDE source code, I found the voltage to temperature mapping:

For anyone trying to read the temperature on their own B-G431B-ESC1, just declare PB14 as an input in your setup:
(A_TEMPERATURE is already mapped to PB14 in platformio) Then, to read the temperature, do this:
temp = map(analogRead(A_TEMPERATURE),0,1024,-49,125);
The pin can do 12 bits resolution, but analogRead seems to work with 10 bits or the pin was programmed with a 10-bit resolution somewhere. Idk. This still works great and map() doesn’t work on decimal numbers, anyways, so it’s whatever.

However, disappointingly, this doesn’t work when integrated in a SimpleFOC application. I think the ADC on pin PB14 is shared with another pin and that other pin gets prioritized over PB14 or it’s declared before PB14. Am I right? I just get 0V, -49C with the exact same readTemp() function.

The reason I had to develop this is because my board gets “oh my god hot” even at low speeds. The project I’m doing has…
motor.torque_controller = TorqueControlType::voltage; //torque measured in [V], lol.
motor.controller = MotionControlType::velocity; //velocity measured in [rad/s]
motor.foc_modulation = FOCModulationType::SpaceVectorPWM; //15% more power eventually

I’m running 24V so the required current draw is half that of 12V and the motor has no load and is going at maybe 40% of its max rpm.

My motor.current_limit is set to 10A, but I expect to be getting nowhere near that with a sensored setup. Did I screw up by not setting driver.voltage_limit? It seems redundant to me when I’m already setting motor.current_limit.

I’ll be measuring the driver’s current draw and the motor’s current draw. Curious what I’ll see. Got a clamp meter coming in, but for now I’ll try with a multimeter and some really ‘sus’ wiring on one of the phases. :slight_smile: Edit: using a power meter, I see that I’m drawing 3.6W from my outlet when no motor sketch is uploaded, then a peak of 8W when sensor alignment runs, and then 5.5W afterwards. The chip is toasty warm, regardless. Not hot, no, but…well, I suppose SimpleFOC demands a fair bit of computing power at any point…nah I’m still not convinced. Might try with a second board soon.

I’ve read @Valentine’s thread post here about what to do with motors getting hot or starting to shake, etc., but that’s for an open-loop setup and without current sensing, I think. I know I have motor.torque_controller = TorqueControlType::voltage, but I really don’t want to go about tuning two sets of PID values for current sensing if I don’t have to.

I’m assuming that the declaration for low-side current sensing in the B-G431B-ESC1 I have is correct, since I got it from the board’s hardware-specific example on the simpleFOC github repo:
LowsideCurrentSense currentSense(0.003, -64.0/7.0, A_OP1_OUT, A_OP2_OUT, A_OP3_OUT);

I’ll want to eventually run this motor at higher power (~400W), so I’ve ordered some little heatsinks, fans, and thermal paste, but that’s for when the motor is actually doing big work. At less than 50W output, I expect the driver to run cool. Meanwhile, after sensor alignment, I’m seeing a reading of 45°C on the NTC?? I’ll be confirming this with an infrared gun next week.

Here’s the closed loop sketch I’ve been running: link.
Here’s the temperature reading sketch I’ve been running: link.

Ok. Did some tests.

Target (rad/s) Power meter reading (W) Multimeter reading on one phase (A)
0 5.5 0
5 5.6-5.7 0.4 (0Hz)
10 6.1 0.68 (0Hz)
20 7.9 1.28 (23Hz)
30 10.4 1.88 (34Hz)
40 13.5 2.42 (46Hz)

Hmm I think I can hear/see cogging at 5 rad/s. Motor definitely not completely quiet at 10 rad/s. Sounds like…a muffled, spinning ratchet with very many tiny teeth… I guess you’d call this cogging? Already uncomfortable to touch the MCU at T40, didn’t go to T50. Max is 3000rpm, so that would be T314. Wow. And this is with no load!

I won’t have any huge changes in load in my application, but there will be a mixer spinning through bread dough. It will have to put up quite the fight. Lots of work to be done…

I don’t see anything in the Overview of the ESC mentioning back-drive protection. That’s what you’d call it, yes, when there’s bemf sending (large) current from the motor to the driver due to applied load?

Wondering what to do about the temp and cogging. I think I have to try TorqueControlType::foc_current. I have no other ideas at the moment.

As a side note, when command line (motor.monitor) is telling me 0.7A, the multimeter connected to one phase going into the motor tells me 1.0A (on AC mode). … 1/sqrt(2) = 0.7?? Seems this 1/sqrt(2) relationship holds for current at any target velocity. I’ll have a look at what that relationship is, exactly, a little later. And I’ll see how different the results are with foc_current (without and with 2xPID tuning).

Oh, and I get very different sounds from the motor depending on the speed. At T15, I hear a pretty audible sound once per rotation. At T10, I hear only a faint, constant ratchet. At T20, I hear an audible, maybe 4x per revolution ratchet. Similar at T25. Less so at T30. Definitely there at T50. Musical mystery…or misery.

Have a great weekend, everyone.

Wow, long post! :slight_smile:

First off, the B-G431-ESC1 isn’t so easy to work with, and you seem to be figuring everything out just fine.

Thanks for sharing!!

We know :frowning:
Here’s why: to use the ADC to do low-side sensing requires very precise timings aligned to the PWM, and the chip has to be configured in a very specific way - this isn’t compatible with the more primitive way Arduino’s analogRead() function wants to use the ADC.
The consequence is that we have to extend the ADC functionality in SimpleFOC to allow you to use the ADC for other things as well.

I would always set the driver.voltage_limit as a “backup”. motor.voltage_limit should be set to about half its value.
Whether the motor.current_limit or the motor.voltage_limit is used depends on the mode and whether you have set the motor.phase_resistance
I admit its a bit confusing at the moment, and we hope to make this more user-friendly in upcoming releases.

So the G431 will use less than 100mA of current, unless something is very wrong. It is unlikely to get very hot from anything you do on it. The heat is likely to come from the MOSFETs, or the PCB traces themselves due the current they are carrying.

If you can, check the revision of your board. We have a thread somewhere in the forum where people traced heat problems to the bad layout of a certain board version, IIRC. Something about all the current passing through a single via in the end, or something like that.

The current PID is only used in the torque-current modes. In other modes you can ignore it.

Nope, I don’t think it has many protections. The current sensing is routed to the on-mcu op-amps and comparators in such a way that I believe you could implement something, but its very hardware specific and AFAIK no one has done it yet for SimpleFOC.
So the currents would be dumped into your PSU, if BEMF makes the voltage rise above the PSU voltage… you should try to avoid that situation.

current control, once its working will allow you to keep the currents to levels you want, and thereby also control the temperatures. Once it’s working well.

But honestly, I must repeat my warning not to expect too much from this little board. It’s more of a design study on how to use the G431 for motor control than a real product for real-world use. It comes with all kinds of warnings to that effect, by the way.

For 20A on 1Oz copper, which I assume is what the board is, you need a trace width of 5mm and still get 100°C temperature rise in that copper. For a 1mm wide trace, the rise will be >1000°C, nearby solder will boil off and even the copper will melt/vaporise… 2Oz copper would improve things a bit, but really 20A is the domain of thick copper, 10mm wide traces / planes, heat sinks and much bigger MOSFETs.
Now I know the bus RMS current and the motor current are different things, but I really think you might be expecting too much from this very tiny driver…

But I am interested to learn how far you can push it with heat sink etc… I do advise getting all the control modes worked out at lower voltages / power levels first though… then you can dive into higher power experiments feeling confident the software works.

Thank you for the equally long reply. Really appreciate it.

Will do. Can’t hurt.

motor.voltage_limit and motor.current_limit make perfect sense. Not sure how else you’d do it without requiring users to type in some value for phase resistance. Come to think of it, it’s interesting I don’t see a motor.phase_inductance anywhere in SimpleFOC, but there’s enough functions and parameters to understand as is. Not complaining!

This is bliss to hear.

At least my power supply has a fan on it! … Heat is not the concern in that scenario, something tells me…

I’ll see what I can do. I promised my teammates some results sometime soon, so for now I’ll just try to push the G431. If it fries, so be it. I’d really love to try to get my hands on one of @Valentine’s custom boards…I’ll plan my next steps next week.

Thanks so much for the support @runger .

BIG warning: The easiest way to kill that board is by feeding it too high supply voltage. If your setup generates power because someone/something turns the motor, you definitely need to manage the excess power somehow. I learned it the hard way and killed a few boards. @Valentine proposed a simple schematic to kill the excess voltage. I adapted it to my needs, since then no more problems.

Regarding the temperature measurement: Since the last SFOC release, there is support for reading the analog channels of the potentiometer, the NTC and the supply voltage. I don’t have access to a real computer, and can’t look it up, but it is in the board specific code.


Ok, I found te relevant line of code. To read the raw temperature value on the B-G431B-ESC1, use:

float Temp = _readADCVoltageInline(A_TEMPERATURE, currentSense.params);

where currentSense is your initialized LowsideCurrentSense object. Likewise you can use

float VBus = _readADCVoltageInline(A_VBUS, currentSense.params);            
VBus = VBus * 10.7711;	

to read the bus voltage. I’ll be back home in a week, then I can post the complete conversion to e.g. Celsius.



@Grizzly Thanks so much for this! I believe the conversion to degC is:

temp_degC = (Temp - 0.925) / 0.019

where Temp is the raw value returned from _readADCVoltageInline(A_TEMPERATURE, currentSense.params)

Once you breakout the Hall pads on the bottom, this board is actually really nice to use to learn about SimpleFOC with gimbal motors. You can use the button and the potentiometer to do a lot of cool things!

@wrcman555 here is what I use to convert the temperature. It looks quite complex, but seems to work fine:

static float Ntc2TempV(float ADCVoltage) 
	// Formula: https://www.giangrandi.org/electronics/ntc/ntc.shtml
	const float ResistorBalance = 4700.0;
	const float Beta  = 3425.0F;
	const float RoomTempI = 1.0F/298.15F; //[K]
	const float Rt = ResistorBalance * ((3.3F / ADCVoltage)-1);
	const float R25 = 10000.0F;
	float T = 1.0F/((log(Rt/R25)/Beta)+RoomTempI);
	T = T - 273.15;

	return T;

Ah! Thanks. That seems to work well. Ignore my post above everyone, lol.

Hi all i am very new to the Community and i am encountering a problem trying to sense the temperature on the Board i tried your aproach but it only shows me 0 as output

Do you have current sensing correctly initialized?

nice, hopefully this effort will also be applicable to some degree to the LeptonG4 or quadvrans. Would definitely be good to have that ADC pin working while using simplefoc. There’s lots of uses, reading potentiometers, or even just analog sensors, which although far from ideal are useful sometimes, I used them.

The board always runs pretty hot for some reason.

It’s a bit hard to pierce the above, perhaps some sample code, to read the adc would be in order. I don’t need it, but sample code is always a good idea to summarize findings in a thread like this… Someone is going to ask for some because most people won’t be able to make heads or tails of the above without almost already knowing how to do it already.

i think i have successfully implemented the lowside current sensing. i get values out so i think it was successful but i am not 100 percent sure i am a beginner in the subject and only started dealing with BLDC’s 3 weeks ago as part of my work so i hope i am not asking stupid questions. but how can i know if i have done the current sensing correctly i am enclosing the plots

I am not sure, if the currents which you read are correct. With regard to reading the temp, it just works in the way described above, but only after the current sensing was initialized. Are your friends aw values also just a constant value (you can change the temperature by touching the NTC)?

Low side current sensing is good to go already, good that you got it working in your case though, I posted example code in the thread on the subject.

Edit: that plot looks nothing like a sine wave, it should look like a sine wave.

This is my code so far i was happy that i get the current sensing and had some readings going but i did not know that i should be expecting sinusodial waves. Regarding the Temp i only get zero for VBus no matter if the NPC is roomtemperature or very hot…

#include <Arduino.h>
#include <SimpleFOC.h>

LowsideCurrentSense current_sense = LowsideCurrentSense(0.003f, -64.0f/7.0f, A_OP1_OUT, A_OP2_OUT, A_OP3_OUT);
float VBus = _readADCVoltageInline(A_VBUS, current_sense.params);

// hall sensor instance
HallSensor sensor = HallSensor(A_HALL1, A_HALL2,A_HALL3,8);
BLDCMotor motor = BLDCMotor(8);

// Interrupt routine intialisation
// channel A, B and C callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();

void setup() {



motor.controller = MotionControlType::angle;
current_sense.skip_align = true;


void loop() {



I think, you need to call current_sense.init() before current_sense.linkDriver(&driver). Only after initializing everything, you can use _readADCVoltageInline(). It may be sufficient to have current sensing initialized, but I never checked it. Before all those steps you can still use:

int VBus = analogRead(A_VBUS);
float VBusF = VBus * 3.3/1024.09.381.0909;

Apart from that, initially you asked for temp measurement. Of course, touching the NTC has no effect if you measure VBUS…

As a further remark, it is very useful to check the return codes of the SimpleFOC functions and to include SimpleFOCDebug::enable(); at the beginning of your setup function…


i manged to get the temp reading going with implementing
float VBus = _readADCVoltageInline(A_VBUS, current_sense.params);

float VBusF = Ntc2TempV(VBus); but now it shows around 70 Fahrenheit no matter if it is cool or hot

i might have to look further in the current sensing or could there be another reason for the readings not reacting to temp diffrences

That is probably because you are reading A_VBUS (voltage on the power rail)… and not the temperature. Use A_TEMPERATURE instead of A_VBUS.

Thanks a lot for your help i worked it out now :smiley:

1 Like