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

Torque mode, FOC? #11

Open
robcazzaro opened this issue May 31, 2023 · 144 comments
Open

Torque mode, FOC? #11

robcazzaro opened this issue May 31, 2023 · 144 comments

Comments

@robcazzaro
Copy link

Just wondering if you are planning to add FOC and torque mode like the Eferu project, or if you know of any FOC algorithm implemented for the GD32F130C8T6.

If not, I might want to try "merging" your base GD32 code with the FOC algorithm from Eferu

@Candas1
Copy link

Candas1 commented Jun 1, 2023

Hi,

Your nickname rings a bell. Are you in the simpleFOC community?

If you want to port FOC, check this, someone had started to port it, I did small adjustments but couldn't finish as I was busy with something else.

Another idea I had is This
It could potentially lead to use simplefoc but a lot has to happen before (testing/arduino core for gd32, sensor smoothing in simplefoc), so it's more long term

@RoboDurden
Copy link
Owner

RoboDurden commented Jun 1, 2023

Oh yes, https://simplefoc.com/ looks very promising.
And fully object orientend as far as i can see: https://docs.simplefoc.com/source_code

Not only the stm32f1 family but also the stm32f4 family is said to be supported: https://docs.simplefoc.com/stm32_mcu
If the code runs on a bluepill (stm32f103), then it should directly run on an old gen1 board (stm32f103 and gd32f103).
But the doc says that only 1 motor low-side current sensing is possible.

But to my understanding, phase current sensing is only needed without hall sensors. But Candas said the EFeru FOC code needs two phase currents (the third can be derived from the first two).
I think, FOC basically is only the closed loop to control the six mosfet in a rotating coordinate system which makes the closed loop simpler. The rotation should also be able to be found from the hall sensors. But the current sensing is analog whereas the hall sensors are digital...

The docs of SimpleFOC in https://docs.simplefoc.com/code says:

proceed to initializing and configuring the current sense, if available of course. If current sense is not available you can skip this step. The library supports two types of current sense architecture:

    in-line current sensing InlineCurrentSense.
    low-side current sensing LowsideCurrentSense.

That example code looks really nice and it should be straight forward to get two motors (without phase current sensing) running on the old stm32f103 and the new stm32f403 boards !?

There is https://github.com/keyboardio/ArduinoCore-GD32-Keyboardio but maybe only the GD32F303 is supported and not the GD32F130 that is found on these Gen2 boards.

Adding FOC to my Gen2.x repo is not really on my todo list.
At the moment i am merging the two serial communications (Esp32-Hover_master + Hover_master-Hover_slave) into one universal uart communication that can chain several baords. For example a robot arm on a moving platform:

typedef struct __attribute__((packed, aligned(1))) {
   uint16_t cStart = START_FRAME;   // new version
   uint8_t iSize;
   Server2HoverSpeedSteer oMover; // digger moving wheels
   Server2HoverPos oPos1;   // robot arm servo 1
   Server2HoverPos oPos2;   // robot arm servo 2
   uint16_t checksum;
} Server2Hover;

So additional structs Server2HoverTorque or Server2HoverRpm might be in reach.
But these structs should of course be c++ classes derived from an abstarct class Server2HoverControl with an element function (method) Control() that hosts the closed loop needed to control a position or torque or rpm in these classes.

So yes when i have finished a closed loop for positioning a rotation angle, it would be easy to add a torque mode.

@Candas1 i have probed the DIO2032 dual opamp outputs of the gen2.2 board with my dso and they do not seem to be current and voltage:
gen2 2 opamp dso

Do you recognize these outputs (motor was spinning) as tow low-side phase currents ?
Then at least the 2.2 layout might support the EFeru FOC code ?

Greetings from sunny Germany :-)

@Candas1
Copy link

Candas1 commented Jun 1, 2023

No simplefoc cannot handle 2 motors yet.
Phase current is needed for FOC.
Hall sensors are needed for motor angle but as simplefoc was mainly used with encoders, it has not extrapolation of the angle between hall changes yet as Eferu's firmware uses it for SIN and FOC. It's work in progress.

@RoboDurden
Copy link
Owner

Thanks Candas1 for your feedback!
If simpleFOC is truely object oriented then of course it should support as many motors as there are IO pins availble. And all motors should share the same 16 kHz interrupt to handle the foc control loop.
Our hoverbord motors have 90 hall steps per revolution and with 14 rpm/V we have 5-8 revs/s yielding 450-630 Hz.
Should be no problem to make a quadratic extrapolation somehow like s(t) = v*t + 1/2 a * t² to boost that to 16 kHz

We have to find such a solution anyway for the modern stm32f403 boards anyway ?

@robcazzaro
Copy link
Author

Also: the "split boards style" hoverboards all have a processor and drive only one motor, communicating with each other over serial. So, all those are great candidates for Simplefoc. It's the first generation boards that used a single processor driving both motors (and using side boards for the IMUs).

Thanks for the additional links @Candas1 (and, yes, it's me on SimpleFOC forums :). I'll have a look at them, especially the Arduino port,

But the GD code (https://github.com/CommunityGD32Cores/ArduinoCore-GD32) is still pretty untested, so I will need to get a GD32F130 chip, replace it on a Bluepill, and verify that PWM, ADC and timers all work as expected before trying it on a board where the wrong signal can result in magic smoke release from the MOSFETs.

The split board hoverboards are a near perfect source of high power drivers: I just got a 25V/250W hoverboard with a dead battery for $10. Basically $2.5 each for drivers and motors :) Problem is, they all use different processors and it's a crapshoot to know what you will find when you open one, so a generic framework is the best option. And I'm ok using encoders instead of the Hall motors, if that makes SimpleFOC easier to run on them

@Candas1
Copy link

Candas1 commented Jun 2, 2023

Also: the "split boards style" hoverboards all have a processor and drive only one motor, communicating with each other over serial. So, all those are great candidates for Simplefoc. It's the first generation boards that used a single processor driving both motors (and using side boards for the IMUs).

Thanks for the additional links @Candas1 (and, yes, it's me on SimpleFOC forums :). I'll have a look at them, especially the Arduino port,

But the GD code (https://github.com/CommunityGD32Cores/ArduinoCore-GD32) is still pretty untested, so I will need to get a GD32F130 chip, replace it on a Bluepill, and verify that PWM, ADC and timers all work as expected before trying it on a board where the wrong signal can result in magic smoke release from the MOSFETs.

The split board hoverboards are a near perfect source of high power drivers: I just got a 25V/250W hoverboard with a dead battery for $10. Basically $2.5 each for drivers and motors :) Problem is, they all use different processors and it's a crapshoot to know what you will find when you open one, so a generic framework is the best option. And I'm ok using encoders instead of the Hall motors, if that makes SimpleFOC easier to run on them

There is even a i2ccommander that could be used to control more than 2 boards.

Again I am not saying it's easy, this will take time. But if we get there we would have made gd32-arduino and simplefoc better, and we can go further than EFeru's FOC as simplefoc has also position control, it's more maintainable and has more support. Last few months I struggled improving EFeru's FOC because of the Matlab model.
I started this experiment with the sideboards as a proof of concept because those are mostly splitboards without motor control. I already found some issues with gd32-arduino that need to be fixed.

The quickest solution if you only care about FOC and torque would be the link I shared with EFeru's foc. But you need to find a board that has the current sensing.

If you want to go fast, go alone. If you want to go far, go together

@Candas1
Copy link

Candas1 commented Jun 2, 2023

And the work recently done by @RoboDurden to document the different board layout is very useful, we could use those different define.h files

@Candas1
Copy link

Candas1 commented Jun 2, 2023

Thanks Candas1 for your feedback! If simpleFOC is truely object oriented then of course it should support as many motors as there are IO pins availble. And all motors should share the same 16 kHz interrupt to handle the foc control loop. Our hoverbord motors have 90 hall steps per revolution and with 14 rpm/V we have 5-8 revs/s yielding 450-630 Hz. Should be no problem to make a quadratic extrapolation somehow like s(t) = v*t + 1/2 a * t² to boost that to 16 kHz

We have to find such a solution anyway for the modern stm32f403 boards anyway ?

Actually one of the improvements I did on mainboards that I didn't share yet is separating the current sensing and FOC for each motor.

But again mainboards would need even more work on the simpleFOC side, so I would focus on splitboards for now.

The extrapolation is not a problem in normal conditions, but you need to take care of transient cases like when direction changes, EFeru's does this well.

@RoboDurden
Copy link
Owner

RoboDurden commented Jun 2, 2023

Okay i better cancel my uart chain protocol and start with simpleFOC :-)
I was able to compile https://github.com/CommunityGD32Cores/gd32-pio-projects/tree/main/gd32-arduino-blinky
with PlatformIO in VisualCode with the readme.me of https://github.com/CommunityGD32Cores/gd32-pio-projects/

i switched to the available genericGD32F130R8 using the project environment switcher in the bottom taskbar. The R8 has the same hardware as the C8 but offers more io pins in the 64 pin package.
gd32F130xx devices features

Choosing an led pin from one of my defines2-x
https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x/tree/main/HoverBoardGigaDevice/Inc
should make the blinky code make a hoverboard led blink:

#include <Arduino.h>

#ifdef LED_BUILTIN
#define LED LED_BUILTIN
#else 
#define LED PC13
//#define LED PB13
#endif 

void setup(){
    pinMode(LED, OUTPUT);
}

void loop(){
    digitalWrite(LED, LOW);
    delay(500);
    digitalWrite(LED, HIGH);
    delay(500);
}

I will try to upload the bin file later the day. But i am totally new to PIO (platformIO).

@Candas1
Copy link

Candas1 commented Jun 2, 2023

You can also check what I did here

@RoboDurden
Copy link
Owner

Oh yes thanks for the reminder. I was not aware that the sideboards of the gen1 hardware also have a gd32f130 on board.
Sideboards gd32f130c6

Now seeing your serial code I am more confident to build a standalone replacement for gen2.x based on simpleFOC.
But the i2ccommander has more benefits.

@RoboDurden
Copy link
Owner

@robcazzaro if you want to join the gd32 coding and live inside Europe I would be happy to ship you two sideboards with a gd32f130c6 for free :-)
But you should be willing to spend some hours on the project!

@Candas1
Copy link

Candas1 commented Jun 2, 2023

Oh yes thanks for the reminder. I was not aware that the sideboards of the gen1 hardware also have a gd32f130 on board. Sideboards gd32f130c6

Now seeing your serial code I am more confident to build a standalone replacement for gen2.x based on simpleFOC. But the i2ccommander has more benefits.

Step by step
I wanted to start with a proof of concept that is already useful

@RoboDurden
Copy link
Owner

Okay i am able to flash with PlatformIO. The flash header in the image of EFeru was wrong for me:
https://raw.githubusercontent.com/EFeru/hoverboard-sideboard-hack-GD/main/docs/pictures/sideboard_pinout.png

My header needed GND , DIO , CLK , 3.3V

I powered the board with 14V but no led blinking.
So i tried debug but the code seems to halt at startup

gd32F130 first debug

@Candas1 did you succeed with your https://github.com/Candas1/Sideboard-Arduino and the firmware is running and can be debugged ?

@RoboDurden
Copy link
Owner

YES, the Candas1 Sideboad code works. At least i can debug step by step :-)
Tomorrow i will test led output and pwm with his code.
Then i might already try to add the simpleFOC library.
Great work @Candas1 :-)

@robcazzaro
Copy link
Author

@robcazzaro if you want to join the gd32 coding and live inside Europe I would be happy to ship you two sideboards with a gd32f130c6 for free :-) But you should be willing to spend some hours on the project!

Nice collection of sideboards you have, @RoboDurden 😊

I live in the USA, probably shipping cost from Europe would be too much, given the size of those boards. Ordering a couple of Bluepills and GD32F130 from Aliexpress would be around $10, with delivery in <15 days. I have all the necessary tools to swap a processor easily and have done some very fine SMD soldering (0201, BGA). And, now that I think of it, I could get the different GC32 processors used in the split boards, so I could easily test various low level stuff safely. I need to check the HW for the various split boards and ensure I get all the processors used, just in case.

But if you don't mind checking the cost of shipping to Seattle, WA, I'd appreciate if you could let me know the cost, though (I'd pay for shipping)

Definitely happy to cooperate, sounds like a very worthwhile project. Caveat: I'm really good at the low level stuff (debugging, hw registers, timing, etc) and I have a collection of necessary tools (oscilloscope, logic analyzer, etc), not as good at the high level object oriented stuff.

@robcazzaro
Copy link
Author

I took some time to look at the various layouts (I have a layout 2 board), and they all seem to use the GD32F130. Most seem to use the GD32F130C8T6, one uses the GD32F130K8, and if I see correctly the layout 4 uses a GD32F130C6T6. So only the F130 family needs to be supported.

@RoboDurden can you please confirm the above?

C8 is the most complete one, C6 has half the FLASH and half the RAM (32k and 4k), one less 16bit timer, only one I2C and SPI buses. The K8 is the same as the C8, obviously with fewer pins than the C8 (32 vs 48).

We need to pay attention to the memory optimizations, it's easy to run out of FLASH or RAM if the Arduino framework doesn't do a good job (on the C6 only, C8 is not a concern).

Based on the above, I'd get a C8 and a C6 processor to install on a Bluepill, as to be able to test every HW variation. I could get a K8 adapter, but the C8 and K8 are the same internally, so I doubt that the pin routing will cause issues. Having a Bluepill would help troubleshoot HW issues (isolate the processor from the rest of the HW), methinks

@Candas1
Copy link

Candas1 commented Jun 2, 2023

@robcazzaro
Copy link
Author

There are some STM32f103 also https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki/Firmware-Compatibility#splitboards

Good point 😊. But for those a normal Bluepill suffice, and in any case the Arduino support is fully working. Definitely something to keep in mind, but I was focusing on GD32 HW and worried about the quality of the GD32 Arduino port for things like injected mode ADC, timers, DMA, etc

@RoboDurden
Copy link
Owner

RoboDurden commented Jun 2, 2023

And yess, finally i can code object oriented on a GD32. These changes in Candas1 main.cpp do work:

class CIO
{	
private:
	int m_iPin;
public:
	CIO(int iPin);
	void Setup(int iType = INPUT_PULLUP);
	void Set(bool bOn = true);
	bool Get(void);
};

CIO::CIO(int iPin){	m_iPin = iPin;  }
void CIO::Setup(int iType){  pinMode(m_iPin, iType);  }	
void CIO::Set(bool bOn){ digitalWrite(m_iPin,bOn); }	
bool CIO::Get(void){  return digitalRead(m_iPin); }

CIO aoLed[5] = {CIO(LED1_PIN), CIO(LED2_PIN), CIO(LED3_PIN), CIO(LED4_PIN), CIO(LED5_PIN) };

void setup()
{
  // Define Leds as output
  for (int i=0; i<5; i++) aoLed[i].Setup(OUTPUT);
  // Turn all Leds ON for half a second and then OFF
  for (int i=0; i<5; i++) aoLed[i].Set(HIGH);
  delay(500);
  for (int i=0; i<5; i++) aoLed[i].Set(LOW);

@robcazzaro shipping to Seattle will simply take too long for joining the party now. I rather donate $5 via paypal to you so you buy some GD32F130 sideboards on used items platform.
What layout do you have with your split hoverboards ? The original 2.0 or some newer board ?
The 2.0 does not have dedicated gate driver chips and indeed you could shortcut the battery when the highside and lowside mosfet of one phase are set .
With the gate driver chips i have the feeling that they do not allow LO and HI to be high at the same time.

@RoboDurden
Copy link
Owner

I took some time to look at the various layouts (I have a layout 2 board), and they all seem to use the GD32F130. Most seem to use the GD32F130C8T6, one uses the GD32F130K8, and if I see correctly the layout 4 uses a GD32F130C6T6. So only the F130 family needs to be supported.

You mean you have a set of gen2.2 and gen2.4 ? gen2.2 has a K8 on board, gen2.3 and gen2.4 a C8. Maybe the 2.1 layout only has a C6. But this does not really matter. We just have to ensure not to use the additonal hardware of the better MCUs.

I do not see much value in your bluepill approach.
A sideboard with its many LEDs and the two photo diodes for analog input on the backside as well as an IMU via I2c and a uart header is fine to test all the basics.
And when adding the simpleFOC library we will need 3 meaningful hall sensor inputs and 6 mosfet outputs anyway to see something happen.

@RoboDurden
Copy link
Owner

Okay i added the simpleFOC library via https://docs.simplefoc.com/library_platformio
Then adding this code to main.cpp already compiles:

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

// Hall sensor instance
// HallSensor(int hallA, int hallB , int hallC , int pp)
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs
HallSensor sensor = HallSensor(2, 3, 4, 11);

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

But before going further with simpleFOC i should test the bascics the library needs. Timer, interrupts, analogRead i guess.

@Candas1
Copy link

Candas1 commented Jun 2, 2023

I was reading this thread again
https://community.simplefoc.com/t/hoverboard-main-board-with-simplefoc/2610/19?u=candas1

It could be more work for pwm and adc

@RoboDurden
Copy link
Owner

Sure but I should find all the gd32 init code needed in my gen2.x repo

@robcazzaro
Copy link
Author

You mean you have a set of gen2.2 and gen2.4 ? gen2.2 has a K8 on board, gen2.3 and gen2.4 a C8. Maybe the 2.1 layout only has a C6. But this does not really matter. We just have to ensure not to use the additonal hardware of the better MCUs.

I do not see much value in your bluepill approach. A sideboard with its many LEDs and the two photo diodes for analog input on the backside as well as an IMU via I2c and a uart header is fine to test all the basics. And when adding the simpleFOC library we will need 3 meaningful hall sensor inputs and 6 mosfet outputs anyway to see something happen.

I have a "layout 2.0" board, the one without gate drivers. So it's not safe for development for an unproven core like the GD32 one. And I have no way to buy a sideboard. I could try to look for used hoverboards locally, but most sell in the $75-$150 range and it's a crapshoot on what I will find in those. I have bought 2 already, one uses split boards with MM32SPIN05PFOP, which is a really different processor, and one has the layout 2.0 split boards. And I'd rather not kill those 😊

So I was thinking that, if I want to help, my best option is to have a Bluepill with the right processor. Also, in my experience, when chasing problems (like ADC sampling noise), it's convenient to have a known good reference board to identify problems due to the processor quirks vs the board components itself.

Otherwise I can wait until you have a working implementation on the layout 2.0, and at that point use my split boards as development platforms.

Any other suggestion?

@RoboDurden
Copy link
Owner

Okay @robcazzaro it might indeed be more fruitful if we each follow a siglthy different route. So you with a bare gd32 might test and solve problems that I can not.

@robcazzaro
Copy link
Author

Sure but I should find all the gd32 init code needed in my gen2.x repo

In the past I looked at the STM32duino implementation. It relies very heavily on the STM32 HAL, to the point of adding al ot of problems and workarounds for those problems. And SimpleFOC really builds on top of that abstraction, too.

So I expect problems with more complex aspects like injected ADC sampling and timers. I might well be wrong, but I'd be surprised if you don't run into some unexpected behavior due to the differences between the GD32F130 and STM32F103 (to be clear: not doubting your skills). The GD32F103 is pretty much directly compatible, but not the F130. That's where I think that a dev board might be necessary and a good backup to have if anything goes wrong on your side

@Candas1
Copy link

Candas1 commented Jun 2, 2023

I worked on injected adc for stm32f1, I should be able to help on gd32f130.
I have a power supply, oscilloscope, and probably any type of splitboard.

@robcazzaro
Copy link
Author

I worked on injected adc for stm32f1, I should be able to help on gd32f130. I have a power supply, oscilloscope, and probably any type of splitboard.

Whoops. I started looking into the GD32F130 reference manual, and the ADC is significantly simplified compared to the STM32F103. There's no injected mode at all, and many fewer modes...

So a new ADC strategy is needed for GD32F130-based boards

STM32F103 (look at bit 7, 10, 12, 16-19, 22, all "reserved" in the GD32)
image

GD32F130
image

@Candas1
Copy link

Candas1 commented Jun 2, 2023

Weird, I saw that in the spl drivers

void adc_inserted_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time)

@robcazzaro
Copy link
Author

robcazzaro commented Jun 9, 2023

Yes, PB6/PB7 is that second uart port that the EFeru firmware also uses for the Nunchuk I2C control method.
So good when i first get these two pins work as another hardware serial.
Unfortunately, the GD-Arduino-Core does not set the rx/tx in the HardwareSerial::begin() like with the ESP32 but in the constructor.
This does not yet seem to work:

@RoboDurden the Serial port initialization happens here and the pin assignment here

You might want to check if the pin numbers you use (PB6 PB7) are properly mapped to the actual GD32 GPIOs. This is something I can't check without an actual board, but according to this file the pin names seems to be PORTB_6 and PORTB_7. Analog pins seems to use the PA0, PA7, etc convention, but not the digital pins

All the files I mentioned are under C:\Users\ [yourname] .platformio\packages\framework-arduinogd32

@RoboDurden
Copy link
Owner

So i finally got the Serial1 to work on the rx/tx pins PB7/PB6 by directly overwriting in the generic variant.h (https://github.com/CommunityGD32Cores/ArduinoCore-GD32/blob/main/variants/GD32F130C8_GENERIC/variant.h#L133)

/* USART0 */
#define HAVE_HWSERIAL1
#ifndef SERIAL0_RX
#define SERIAL0_RX                  PB7 //  PA10
#endif
#ifndef SERIAL0_TX
#define SERIAL0_TX                  PB6 //  PA9
#endif

It is not sufficient to define at the beginning of the user code in main.cpp

#define SERIAL0_RX  PB7 // set Serial1 rx/tx before it is done in <variant.h>
#define SERIAL0_TX  PB6

Even so VisualCode (VC) greys the define lines in variant.h because they are already defined.
I guess the variant.h is already read before main.cpp :-(

But then i do not see a way for user code to set uart (or i2c) port to different pins without hacking the Arduino-Core.
Typical for the original Arduino cores :-(

I again will try to define a new serial port with HardwareSerial oSerial(uint8_t rx, uint8_t tx, int uart_index); but i did not succeed that way some hours before :-/

The Esp32 Arduino-Core is better in letting the pins be assigned in the HardwareSerial::begin()

Don't know what i should ask the GD32-Arduino-Core community for :-/
Ideas welcome :-)

@RoboDurden
Copy link
Owner

Okay, this works to replace Serial1: HardwareSerial oSerialSteer(PB7, PB6,0); // 1 = uart_index = Serial2 ; 0 = uart_index = Serial1 . setting the index to 1 to use Serial does not seem to work.

@robcazzaro
Copy link
Author

robcazzaro commented Jun 9, 2023

@RoboDurden have you tried with PORTB_6 and PORTB_7 instead of PB6, PB7? The code properly uses pin names to initialize the port, so it's just a matter of finding the right naming convention.

If you don't want to bother digging into the lower levels of the GD32 Arduino code, don't worry: just hardcode things for now and overwrite the files. As soon as I have a working board, I will figure out the Serial code.

The conversion between pin names and GPIO ports is pretty messy in the Arduino frameworks, and even in the SimpleFOC code you need to use weird tricks sometimes to ensure that the pins are mapper properly. It's something I have done before and have a quick way to address it

I'd suggest not ask the GD32 folks for now, let's use them for things we can't figure out between the 3 of us

@RoboDurden
Copy link
Owner

I'd suggest not ask the GD32 folks for now, let's use them for things we can't figure out between the 3 of us

Exactly! That is why i quickly added the oneliner that HardwareSerial oSerialSteer(PB7, PB6,0); will work to reasign Serial1.
Serial2 is still working for our boards as they also have RX/TX = PA3/PA2, except layout 2.2. :-/

@Candas1
Copy link

Candas1 commented Jun 9, 2023

I don't know what caused the 500ms reset after the st-link.exe upload but now with the 3 checkboxes checked it has dissappeared. So now i understand when you wrote to EITHER tell users to check the 3 checkboxes OR handle some watchdog in setup(). But as i was not able to upload working code in visual studio i fear that some watchdog code in setup() would not execute in time to make the visual code upload succeed. Better check the 3 checkboxes.
With my gen2.0 test setup i want the second uart port for serial debug and not the PA2/PA3 master-slave uart :-/ So i can not use your Serial2 but create a new HardwareSerial object with RX/TX = PB7/PB6. That is my next step before proceeding to get an I2C slave working...

The way a HW watchdog usually works, is that once it's set in HW, it's always active and can never be disabled in SW (you can only reset the timer to avoid a reboot). So when flashing over software that used the watchdog, you need to power cycle the processor to disable the watchdog completely after resetting the flag.

So it's important to tell the user to erase the flash and set the right flags, power cycle, then flash the new firmware. Otherwise the flashing operation can be interrupted by the watchdog timer going off. Even if flashing is successful, unless the processor is power cycled, the watchdog timer might still be active

To reset the watchdog:

The counter can be reloaded by writing the value 0xAAAA to the FWDGT_CTL register at anytime.

and the timer value (i.e. how long before reset if not reloaded) is

Free watchdog timer counter reload value. Write 0xAAAA in the FWDGT_CTL register will reload the FWDGT counter.

I'll look at the Serial initialization code for the GD32 Arduino, it's possible that the pin map doesn't include all possible pins

I don't know what caused the 500ms reset after the st-link.exe upload but now with the 3 checkboxes checked it has dissappeared. So now i understand when you wrote to EITHER tell users to check the 3 checkboxes OR handle some watchdog in setup(). But as i was not able to upload working code in visual studio i fear that some watchdog code in setup() would not execute in time to make the visual code upload succeed. Better check the 3 checkboxes.
With my gen2.0 test setup i want the second uart port for serial debug and not the PA2/PA3 master-slave uart :-/ So i can not use your Serial2 but create a new HardwareSerial object with RX/TX = PB7/PB6. That is my next step before proceeding to get an I2C slave working...

The way a HW watchdog usually works, is that once it's set in HW, it's always active and can never be disabled in SW (you can only reset the timer to avoid a reboot). So when flashing over software that used the watchdog, you need to power cycle the processor to disable the watchdog completely after resetting the flag.

So it's important to tell the user to erase the flash and set the right flags, power cycle, then flash the new firmware. Otherwise the flashing operation can be interrupted by the watchdog timer going off. Even if flashing is successful, unless the processor is power cycled, the watchdog timer might still be active

To reset the watchdog:

The counter can be reloaded by writing the value 0xAAAA to the FWDGT_CTL register at anytime.

and the timer value (i.e. how long before reset if not reloaded) is

Free watchdog timer counter reload value. Write 0xAAAA in the FWDGT_CTL register will reload the FWDGT counter.

I'll look at the Serial initialization code for the GD32 Arduino, it's possible that the pin map doesn't include all possible pins

OK then check those option bytes is mandatory. I had already added this link in the readme.
A few months ago I played around with an interesting project, and created my own fork.
It let's you flash firmware from a web app, and I could even adapt it to unlock and set option bytes automatically, and flash the right firmware.

@Candas1
Copy link

Candas1 commented Jun 9, 2023

@Candas1 are you sure that your Serial issues are not due to the GD32 being initialized with the wrong clock? If you used the version of the GD32 core in the repository from a couple of days ago, it was initializing the GD32F130 overclocked to 72MHz, and that is likely to break the Serial port (among other things)

After I opened the clock issue, they added the necessary code to properly initialize the GD32F130, and should now work better

No I don't think so, TX was working fine, and RX failing only after a minute. But when I am back I will check what is the impact of each change.

@Candas1
Copy link

Candas1 commented Jun 9, 2023

@robcazzaro @RoboDurden
This thread will get very messy, I am always tempted to introduce new topics.
Should we create different issues/enhancements in the repository of your choice to capture each topic ?

@RoboDurden
Copy link
Owner

Well this issue has transformed into a nice chat group.
But yes sorry, i already created the uart issue on your Sideboard-Arduino and should not have continued the topic here. But then robcazzaro hat not read it.
So i think that as long as i stumble forward, such a chat is quite nice to have.
If we can identify a topic of universal intereset, we should start a seperate issue on some of the many connected repos.

@robcazzaro
Copy link
Author

@robcazzaro @RoboDurden This thread will get very messy, I am always tempted to introduce new topics. Should we create different issues/enhancements in the repository of your choice to capture each topic ?

Good point @Candas1 and apologies if I made things worse. I tend to get sidetracked a lot 😊

I think we should choose a repository, and create new issues for everything we discover (i.e. things like Serial initialization, specific code ports, etc) and keep the discussion on every issue focused on a single topic. That way it's easy to go back and find stuff and track progress by closing issues

I'll leave it to you to decide where to have the repository and do the initial check-ins (unless we want to use https://github.com/Candas1/Sideboard-Arduino)

@Candas1
Copy link

Candas1 commented Jun 9, 2023

I am not blaming you I am only suggesting.

@RoboDurden had already creating one issue actually.

But it's also true that you might not be aware of all the new issues

@RoboDurden
Copy link
Owner

RoboDurden commented Jun 9, 2023

slow i2c progress: https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/src/main.cpp

gd32-slave receiving string data from esp32_s2_mini-master is working:

void receiveEvent(int iReceived) 
{
  iI2c++;
  OUT2T("\ni2c received",iReceived)

  char temp[iReceived+2];
  temp[iReceived] = 0;
  for (int i=0; i<iReceived; i++) temp[i] = Wire.read();
  OUTLN(temp);
}
void setup()
{
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event

Log output of https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/arduino%20examples/ESP32_Mini_S2_I2c_Uart/ESP32_Mini_S2_I2c_Uart.ino#L52 :

  Wire.beginTransmission(8);
  Wire.print("i2c message");
  byte error = Wire.endTransmission();
i2c received: 11	i2c message
hello from ESP32 S2 Mini
GD32: 253400	0: 1	1: 0	2: 0	angle: 0.14	speed: 0.00	iI2c: 502

i2c received: 11	i2c message
hello from ESP32 S2 Mini
GD32: 253900	0: 1	1: 0	2: 0	angle: 0.14	speed: 0.00	iI2c: 503

i2c received: 11	i2c message
hello from ESP32 S2 Mini
GD32: 254400	0: 1	1: 0	2: 0	angle: 0.14	speed: 0.00	iI2c: 504

00:48 here in Germany, good night :-/

@RoboDurden
Copy link
Owner

Okay @Candas1 i had to fix the i2c_slave_tx code in the GD-Arduino-Core but now i have a working ESP32_master <-> GD32F130_slave GD32_Arduino_Core: ArduinoCore-GD32/issues/99

@Candas1
Copy link

Candas1 commented Jun 11, 2023

Okay @Candas1 i had to fix the i2c_slave_tx code in the GD-Arduino-Core but now i have a working ESP32_master <-> GD32F130_slave GD32_Arduino_Core: ArduinoCore-GD32/issues/99

Oh wow, this is great news.
I will also test your fix with the mpu6050 on the sideboard when I am back home

@RoboDurden
Copy link
Owner

@Candas1 , My fix is for using a GD32 as a slave to be controlled by a master like the i2cCommander use case.
When simply reading/controlling a i2c module like mpu6050 , the GD32 acts as the master, and that is the 99% use case scenario which for sure has been tested 100%.

Now i do not really like i2cCommander any longer as it is very old school in writing/reading single registers.
I would prefer a data structs for each SimpleFOC class and you init the simpleFOC i2c-slave with only sending one byte or word were one of the 8 or 16 bits enable the data-structs you want to request later.
Then a single i2c request would tell the i2c-slave to transmitt all that data you want with crc in one push.
With the old way you have to first transmit the register you want from master to slave and afterwards request data from the slave. As the slave has been told which data you want, it then transmits this data with such stupid switch clauses: I2CCommander.cpp#L244
That (again) ist totally NON-oo. All SimpleFOC classes should be derived from a base class and overwrite a SimpleFOC::toStruct() which returns a c-struct of its (public) data. And the I2CCommander class would simply loop through all simpleFOC objects and fetch-and-transmit these structs.

With my nice little helper functions SerialWrite and SerialRead it is way easier to send structs and have crc error checking on top.
So when you and @robcazzaro will succeed with the driver port, etc. i might very well write my own I2cCommander :-/

@Candas1
Copy link

Candas1 commented Jun 11, 2023

@Candas1 , My fix is for using a GD32 as a slave to be controlled by a master like the i2cCommander use case.
When simply reading/controlling a i2c module like mpu6050 , the GD32 acts as the master, and that is the 99% use case scenario which for sure has been tested 100%.

Now i do not really like i2cCommander any longer as it is very old school in writing/reading single registers.
I would prefer a data structs for each SimpleFOC class and you init the simpleFOC i2c-slave with only sending one byte or word were one of the 8 or 16 bits enable the data-structs you want to request later.
Then a single i2c request would tell the i2c-slave to transmitt all that data you want with crc in one push.
With the old way you have to first transmit the register you want from master to slave and afterwards request data from the slave. As the slave has been told which data you want, it then transmits this data with such stupid switch clauses: I2CCommander.cpp#L244
That (again) ist totally NON-oo. All SimpleFOC classes should be derived from a base class and overwrite a SimpleFOC::toStruct() which returns a c-struct of its (public) data. And the I2CCommander class would simply loop through all simpleFOC objects and fetch-and-transmit these structs.

With my nice little helper functions SerialWrite and SerialRead it is way easier to send structs and have crc error checking on top.
So when you and @robcazzaro will succeed with the driver port, etc. i might very well write my own I2cCommander :-/

Congratulations for your first PR 😜

@Candas1
Copy link

Candas1 commented Jun 14, 2023

Hi guys,

I am back from my unplanned leaves, but I have planned leaves end of next week again.
So not to .lose too much momentum, I will focus on the 6PWM part now.
@RoboDurden what layout are you using now ? I think we should use the same so we can expect the same results.
For testing, I want to find a working board and solder headers on the mosfets for probing with the osciloscope.
If we could start with a layout that has phase current sensing, we would probably save time later when we start to work on the current sense driver.

When 6pwm is working, we could already achieve trapezoidal control, which is what your firmware does now.
I see sensorsmoothing is now in the dev branch of simpleFOC, so it will probably be in the next release. That should help achieve sinusoidal control.
For FOC we will need to work on the current sense driver.
SimpleFOC has a DC current mode, but it's using phase current. I am wondering if it would be possible to add DC current sensing to simpleFOC in the future, to allow torque control on splitboards having DC current but no phase current.

So it's a long journey, but each step will add value.

@RoboDurden , regarding your comments about how i2ccommander is coded. The reason I feel this new Arduino + simpleFOC approach is exciting is because I already see I can develop much faster using libraries. I saw there are libraries for battery management, handling buttons, ibus and what not. When contributing to Eferu's FOC firmware, I had to code everything myself, I for example coded a poor version of commander, which is good for learning but takes a lot of time. Now I would just use the commander from simpleFOC.
We shouldn't end up coding everything from scratch if there is a working solution.

My aim now is to get arduino-gd32 and simplefoc working on the splitboards, for any developer to be able to code his firmware.
Then coding a firmware like Eferu's foc firmware is a lot of work, because you need to document and support for users that are not developers.

@RoboDurden
Copy link
Owner

RoboDurden commented Jun 14, 2023

At the moment i have a 2.0 and a 2.5 test setup. According to your spread sheet https://docs.google.com/spreadsheets/d/15msbDAIMxC2rIkq8Au8vf82ub1qEaS67Lc1cFb86Jpc/edit#gid=0 the 2.0 has two low-side phase currents and the 2.5 even alle 3 low-side. But i have not tested either of these pins yet.
The 2.0 layout is the most common on and when i embark on a 1-2 weeks journey friday i would like to take this more lightweight test setup with me
robosolarwohnmobil

I guess best chances to find a gen2.0 board is to buy an old 25V 7s hoverboard with these bldc motors that have a Mercedes like star on the sides.
gn2 0 motors

Yes i also wanted to add a "i2ccommander" to my gen2.x repo but did not want to code i2c on that stupid low level.
Main motivation with simpleFOC for me is not really FOC but to finally have a c++ foundation.

It would be nice for me to have a drivers/hardware_specific/gd32/gd32_mcu.cpp that compiles successfully because these empty functions from the generic file cover all the missing functionality.
So my approach was to simply copy the geneic file to gd32/gd32_mcu.cpp and then start porting true functionality on the go while F10/F11 step into the code.
That is more emotionally more rewarding then to first port all the functions before being able to compile and debug.

@Candas1
Copy link

Candas1 commented Jun 14, 2023

At the moment i have a 2.0 and a 2.5 test setup. According to your spread sheet https://docs.google.com/spreadsheets/d/15msbDAIMxC2rIkq8Au8vf82ub1qEaS67Lc1cFb86Jpc/edit#gid=0 the 2.0 has two low-side phase currents and the 2.5 even alle 3 low-side. But i have not tested either of these pins yet. The 2.0 layout is the most common on and when i embark on a 1-2 weeks journey friday i would like to take this more lightweight test setup with me robosolarwohnmobil

I guess best chances to find a gen2.0 board is to buy an old 25V 7s hoverboard with these bldc motors that have a Mercedes like star on the sides. gn2 0 motors

Yes i also wanted to add a "i2ccommander" to my gen2.x repo but did not want to code i2c on that stupid low level. Main motivation with simpleFOC for me is not really FOC but to finally have a c++ foundation.

It would be nice for me to have a drivers/hardware_specific/gd32/gd32_mcu.cpp that compiles successfully because these empty functions from the generic file cover all the missing functionality. So my approach was to simply copy the geneic file to gd32/gd32_mcu.cpp and then start porting true functionality on the go while F10/F11 step into the code. That is more emotionally more rewarding then to first port all the functions before being able to compile and debug.

I have all possible splitboards in boxes somewhere, I just need to find it.
I based this spreadsheet on the defines.h files, I think we will need to check if those are accurate.

ok I will start with a gen 2.0 then.
I had already tried to compile before I left, it was working.
But now I need to run the code and see if I get a hardfault, if PWM if ok.

Once I see it's not harming the hardware I will give you a heads up.
I think it's also easy to do something wrong with SimpleFOC at the beginning, so I will make sure we start with proper limits.

@Candas1
Copy link

Candas1 commented Jun 14, 2023

IMG_20230614_102736.jpg

I will check this in the evening

@Candas1
Copy link

Candas1 commented Jun 14, 2023

HnVideoEditor_2023_06_14_172056522.mp4

@RoboDurden
Copy link
Owner

Hallelujah, that looks like you already get the motor spinning :-)
I do not see if you have uart1 or uart2 cable connected.
That white thing with the stlink plugged in might be a usb hub.
The other plugged in device i can not identify.
The blinking leds remind me of my repo that already got the hall sensors working.
If you indeed alredy got the simply block commutation working than i could start to replace my gen2.x repo :-)
Great work @Candas1 (and @robcazzaro i guess) :-)

@Candas1
Copy link

Candas1 commented Jun 14, 2023

I just forked your repository to save time. Including this to my repository now would be a mess.

I just gave a fixed target for my tests, haven't used usart yet.

I never got something working so easily lol, it worked at the first attempt.

I will do more checks and commit later today so you can see what I changed.

@Candas1
Copy link

Candas1 commented Jun 14, 2023

I committed my code here but please be really careful.
I checked that the PWM frequency is 16Khz.
With the little fixed target I have set, it's using 0.134A.
I think it's good enough to play around and understand simpleFOC better. All the different modes are a bit misleading.

This sketch is already using 91% of the flash, the GD32F130C6T6 have really little memory.
I wasn't able to add the serial commander for example, it was exceeding the size.
I need to check if we can optimize the size. @robcazzaro do you have any experience with that ?

The I2C communication you were coding might fit.

@robcazzaro
Copy link
Author

robcazzaro commented Jun 14, 2023

@Candas1 yes, I do have quite a lot of experience optimizing code for size, and I'm sure that especially at the beginning it would be easy to find savings. Later might be hard to find further optimizations

I just tried compiling your project (platformio.ini was missing the SimpleFOC library reference, btw), and Ï see 63.7% RAM used, 86.6% FLASH used

Bad news, the most basic step (using -Os) is already done, so I will need to dig into the elf to understand where the space is used. And from a quick look at the code, elf and linker files, there's nothing obviously easy to optimize, the only thing that caught my eye is the size of the .rodata section (2400 bytes), which seems too big.

The most obvious easy candidate is to remove all the DEBUG prints which are not needed once the code runs. The debug code is supposed to be disabled using -D SIMPLEFOC_DISABLE_DEBUG, but that code ir broken. If I add that option, the compilation aborts: the code expects the debug prints to be in a macro, but the code uses SimpleFOCDebug:: class directly. I hacked a way to disable debug print, and I go from 86.6% down to 83.3%. It's a start

I'll open an issue on disabling the debug print in SimpleFOC (EDIT simplefoc/Arduino-FOC#279)

Do you mind enabling issues in your repository, so I can start creating one for the memory size, as a work item and to discuss tradeoffs

@Candas1
Copy link

Candas1 commented Jun 15, 2023

@Candas1 yes, I do have quite a lot of experience optimizing code for size, and I'm sure that especially at the beginning it would be easy to find savings. Later might be hard to find further optimizations

I just tried compiling your project (platformio.ini was missing the SimpleFOC library reference, btw), and Ï see 63.7% RAM used, 86.6% FLASH used

Bad news, the most basic step (using -Os) is already done, so I will need to dig into the elf to understand where the space is used. And from a quick look at the code, elf and linker files, there's nothing obviously easy to optimize, the only thing that caught my eye is the size of the .rodata section (2400 bytes), which seems too big.

The most obvious easy candidate is to remove all the DEBUG prints which are not needed once the code runs. The debug code is supposed to be disabled using -D SIMPLEFOC_DISABLE_DEBUG, but that code ir broken. If I add that option, the compilation aborts: the code expects the debug prints to be in a macro, but the code uses SimpleFOCDebug:: class directly. I hacked a way to disable debug print, and I go from 86.6% down to 83.3%. It's a start

I'll open an issue on disabling the debug print in SimpleFOC (EDIT simplefoc/Arduino-FOC#279)

Do you mind enabling issues in your repository, so I can start creating one for the memory size, as a work item and to discuss tradeoffs

Thanks a lot!
Actually the platformio.ini has a reference to my own simplefoc fork with the GD32 driver. Your flash usage is 86.6%, mine was 91%, that's probably the overhead of the GD32 functions for advance pwm.
I am sure there might be room for improvement from the arduino-gd32 side as well.

I tried LTO but it's always breaking the program for me.

The look up tables for sin and cos also use quite some space. I am wondering if generating those tables in ram at startup would save any space. We could use libraries like qfplib that are supposed to be smaller and faster.

@Candas1
Copy link

Candas1 commented Jun 15, 2023

@RoboDurden Do you know if the emergency stop is really connected on this layout? If yes it will act as an overcurrent trigger and stop the pwm output. It would only be a matter of enabling This with the right polarity and would be safer.

[EDIT] And probably setting PB12 properly

@Candas1
Copy link

Candas1 commented Jun 15, 2023

Just one thought.
It could be the PWM duty cycle is doubled.
the STM implementation has this value, but I fix the maximum should be 2000.

So don't put a target too high for now.

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

No branches or pull requests

3 participants