RoboDurden / Hoverboard-Firmware-Hack-Gen2.x

with different defines_2-x.h for different board layouts :-) Compiles with Keil version 6
GNU General Public License v3.0
78 stars 27 forks source link

Torque mode, FOC? #11

Open robcazzaro opened 1 year ago

robcazzaro commented 1 year ago

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 commented 1 year ago

There is no way we are not going to succeed with all the Support we get

robcazzaro commented 1 year ago

We forked ArduinoFOC and started to port 6PWM using some of the setup.c code.

Just one doubt, I think this code is wrong.

Those chips are not 72Mhz but 48Mhz, that must have been left from the STM32F103 code. That means the PWM on this firmware is probably not running at 16khz, have you ever checked @RoboDurden ?

Please note that when I was looking at the initialization code I noticed this

We need to check what is actually used in the code we are compiling, and if needed define it properly.

Are the sideboards using a crystal oscillator? If not, the initialization code must use the internal oscillator. Incidentally, problems with this initialization could also cause UART problems (beyond the ones fixed by the GD32 Arduino community)

EDIT: the clock init code in the GD32 repository is older than the one currently in the 3.3.4 SPL. The new code has a define for a 48MHz clock using the internal oscillator, as follows. I'll open an issue in the GD32 repository to use the latest files (we need to define __SYSTEM_CLOCK_48M_PLL_IRC8M_DIV2 __SYSTEM_CLOCK_48M_PLL_IRC8M_DIV2 )

/* system frequency define */
#define __IRC8M           (IRC8M_VALUE)            /* internal 8 MHz RC oscillator frequency */
#define __HXTAL           (HXTAL_VALUE)            /* high speed crystal oscillator frequency */
#define __SYS_OSC_CLK     (__IRC8M)                /* main oscillator frequency */

#define VECT_TAB_OFFSET  (uint32_t)0x00            /* vector table base offset */

/* select a system clock by uncommenting the following line */
//#define __SYSTEM_CLOCK_8M_HXTAL              (__HXTAL)
//#define __SYSTEM_CLOCK_8M_IRC8M              (__IRC8M)
//#define __SYSTEM_CLOCK_48M_PLL_HXTAL         (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_48M_PLL_IRC8M_DIV2    (uint32_t)(48000000)
#define __SYSTEM_CLOCK_72M_PLL_HXTAL         (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2    (uint32_t)(72000000)`

Here is the new issue I just opened https://github.com/CommunityGD32Cores/ArduinoCore-GD32/issues/98

I'm also attaching the correct clock init code, to use instead of the one currently in the Arduino tree C:\Users\ [yourname] .platformio\packages\framework-arduinogd32\system\GD32F1x0_firmware\CMSIS\GD\GD32F1x0\Source\system_gd32f1x0.c

EDIT: this issue has already been fixed by the GD32 Arduino project and an update ready for download. Clock configuration is done in platformio.ini

build_flags = 
  -D __PIO_DONT_SET_CLOCK_SOURCE__
  -D __SYSTEM_CLOCK_48M_PLL_IRC8M_DIV2=48000000

system_gd32f1x0.zip

RoboDurden commented 1 year ago

Okay i first turned the chaos on my desk (writing table) into a Gen2.0 test setup: Gen2 0 test setup But have problems installing firmware.bin (Keil works but the board hangs for about 30 seconds before running. PIO can not upload. ST-Link.exe does upload binary but code does not seem to work. The Gen2.0 is a C8 mcu.)

Back to the Gen2.5 setup i can send text data manually via uart-dongle or every 100 ms "hello from ESP32 S2 Mini" and the firmware simply returns every data received on RX: https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/src/main.cpp#L154 (I have added some debug macros to unify uart and SeggerRtt (not tested yet): https://github.com/RoboDurden/Split_Hoverboard_SimpleFOC/blob/main/include/defines.h#L43 )

hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00
hello from ESP32 S2 Mini
0: 0    1: 0    2: 1    angle: 6.70 speed: 0.00

No failure of RX after several minutes. Don't think it makes a difference if i send strings instead of structs.

Candas1 commented 1 year ago

In my case data was sent every 10ms, that could lead to the issue. Unfortunately I had to travel abroad this morning so I can't test next few days.

Candas1 commented 1 year ago

@RoboDurden have you selected the right chip/environment when flashing the gd32f130c8/gen 2 board?

RoboDurden commented 1 year ago

Yes i select to propper C8 enviroment (i removed the STM32F103 enviroments from your platfomio.ini). I can succesfully flash the C6 and C8 binaries with st-flash.exe st-flash write firmware.bin 0x8000000 and both C6 and C8 binaries work (at least for 500ms). Because the code execution resets after about 500ms. I can change the led blinking at the beginning of my setup() to see that after about 500ms, the setup() restarts:

  for (int i=0; i<LED_Count; i++) 
  {
    aoLed[i].Init();
    aoLed[i].Set(HIGH);
    delay(100);
    aoLed[i].Set(LOW);
  }

I also notice that when i remove

  oKeepOn.Init();
  oKeepOn.Set(true);  // now we can release the on button :-)

at the very beginning of the setup(), the led blink less bright but the board does not shut off. But again resets after 500ms.

So there might indeed be some hardware difference of the 2.0 layout that causes troubles.

VisualCode does at least erase the same binary i can upload via st-link.exe but the VC upload fails and no led blinking any longer:

Processing GD32F130C8 (platform: https://github.com/CommunityGD32Cores/platform-gd32.git; board: genericGD32F130C8; framework: arduino)
------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/gd32/genericGD32F130C8.html
PLATFORM: GD GD32 (1.0.0+sha.3424e66) > GD32F130C8 (8k RAM, 64k Flash)
HARDWARE: GD32F130C8T6 48MHz, 8KB RAM, 64KB Flash
DEBUG: Current (stlink) External (blackmagic, cmsis-dap, jlink, sipeed-rv-debugger, stlink)
PACKAGES:
 - framework-arduinogd32 @ 4.20000.210603+sha.d0cf857
 - tool-dfuutil @ 1.9.200310
 - tool-gdlinkcli @ 2.40611.220807+sha.74386ec
 - tool-openocd-gd32 @ 2.1100.211207 (11.0)
 - tool-stm32duino @ 1.0.2
 - toolchain-gccarmnoneeabi @ 1.90201.191206 (9.2.1)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 12 compatible libraries
Scanning dependencies...
Dependency Graph
|-- Simple FOC @ 2.3.0
Building in release mode
Checking size .pio\build\GD32F130C8\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [====      ]  38.5% (used 3152 bytes from 8192 bytes)
Flash: [==        ]  22.1% (used 14452 bytes from 65536 bytes)
Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, gdlinkcli, jlink, serial, sipeed-rv-debugger, stlink
CURRENT: upload_protocol = stlink
Uploading .pio\build\GD32F130C8\firmware.elf
xPack OpenOCD x86_64 Open On-Chip Debugger 0.11.0+dev (2021-12-07-17:33)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
debug_level: 1

hla_swd
0
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08001b2c msp: 0x20002000
** Programming Started **
Error: timed out while waiting for target halted
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x41000003 pc: 0x08001b74 msp: 0x20001fe0
Error: error waiting for target flash write algorithm
Error: error writing to flash at address 0x08000000 at offset 0x00000000
embedded:startup.tcl:1136: Error: ** Programming Failed **
in procedure 'program' 
in procedure 'program_error' called at file "embedded:startup.tcl", line 1201
at file "embedded:startup.tcl", line 1136
*** [upload] Error 1
=============================================================== [FAILED] Took 14.16 seconds ===============================================================

Environment    Status    Duration
-------------  --------  ------------
GD32F130C8     FAILED    00:00:14.164
========================================================== 1 failed, 0 succeeded in 00:00:14.164 ========================================================== 

 *  The terminal process "C:\Users\PAN CF-LX6\.platformio\penv\Scripts\platformio.exe 'run', '--target', 'upload', '--environment', 'GD32F130C8'" terminated with exit code: 1. 
 *  Terminal will be reused by tasks, press any key to close it. 

Maybe this 500ms resets make VC-upload fail. I will continue with my working 2.5 setup but @robcazzaro only has the 2.0 layout ?

Candas1 commented 1 year ago

I haven't tried any c8 chip yet. It's just supposed to have more memory. Have you set all the option bytes in stlink utility? 204760632-2c34a410-8f81-4047-af29-b0386676ff55

Candas1 commented 1 year ago

Maybe we need to reset the Watchdog , I am not sure if there is any function for that in the arduino core

RoboDurden commented 1 year ago

Excellent knowlede @Candas1 :-) Indeed at the time i had unlocked the gen2.0 board i did not yet know to also activate all (three) checkboxes. And i forgot that with the gen2.5 i did check the three checkboxes. Now uploading and debugging works fine. Big thanks !

The watchdog in the gen2.x repo is setup by Watchdog_init(void): https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x/blob/c350d800c7913a62c501d02a916795ebcdea70dc/HoverBoardGigaDevice/Src/setup.c#LL68C11-L68C24 As the Adruino-Core does not seem to do this, we need not reset it i guess.

Candas1 commented 1 year ago

Excellent knowlede @Candas1 :-) Indeed at the time i had unlocked the gen2.0 board i did not yet know to also activate all (three) checkboxes. And i forgot that with the gen2.5 i did check the three checkboxes. Now uploading and debugging works fine. Big thanks !

The watchdog in the gen2.x repo is setup by Watchdog_init(void): https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x/blob/c350d800c7913a62c501d02a916795ebcdea70dc/HoverBoardGigaDevice/Src/setup.c#LL68C11-L68C24 As the Adruino-Core does not seem to do this, we need not reset it i guess.

Great news So either we would instruct the users to set all the checkboxes, or we could find a solution in the future to handle the watchdog, it could be a good safety feature.

Candas1 commented 1 year ago

It seems it was already identified as an enhancement

RoboDurden commented 1 year ago

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...

Candas1 commented 1 year ago

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...

Beware of this

RoboDurden commented 1 year ago

Nice. From my side I still need to figure out why usart RX fails after some time. I need to get I2C to work as well. I found out the default pins for I2C are not the ones we use on sideboards. We use PB6 and PB7.

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:


#ifdef DEBUG_UART
  HardwareSerial oSerialSteer(PB7, PB6,1);  // 1 = uart_index = Serial2
  #undef DEBUG_UART
  #define DEBUG_UART oSerialSteer
#endif
robcazzaro commented 1 year ago

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

robcazzaro commented 1 year ago

@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

robcazzaro commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

IMG_20230614_102736.jpg

I will check this in the evening

Candas1 commented 1 year ago

https://github.com/RoboDurden/Hoverboard-Firmware-Hack-Gen2.x/assets/20670049/0999f5cd-8f07-4f53-af70-201f38b073ed

RoboDurden commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

@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 https://github.com/simplefoc/Arduino-FOC/issues/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 commented 1 year ago

@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 https://github.com/simplefoc/Arduino-FOC/issues/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 commented 1 year ago

@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 commented 1 year ago

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.