-
Notifications
You must be signed in to change notification settings - Fork 5
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
GD32 timer initialization is not working properly #4
Comments
Your waveforms are smoothed due to the presence of load on the GPIO pins. But you can clearly see the same spikes I was seeing in the CH2, and those will kill the MOSFETs over time I'll look at the initialization code and see what's going on. The same code on STM32 produces absolutely clean signals. That could explain the noisy motor control you and @RoboDurden are seeing BTW: you might want to use something like https://www.eevblog.com/forum/testgear/rigol-screen-capture-vcl-windows-application/ it works either via USB or LAN, and it's lightweight and fast |
But are you sure the spikes are not due to the cc mode? With the code from my repository I don't think I have the spikes. I didn't know about that capture program, thanks |
One idea, I have never used the splitboard firmware so I assumed it was working well, but I saw something weird in the code but I haven't had time to investigate. I am wondering if this code is the problem. |
My plan is to run the STM32 code, dump the register content, run the GD32 code dump as well, and compare the two. As much as the HAL is different from the SPL, the underlying registers are the same, so the values in the end must be the same Just haven't had time to do it yet :) please continue to work on the rest of the code, and I promise I'll get this working |
Hmm it could really be that, stm32duino enables it, but it was disabled in the splitboard firmware. |
No forget it, I think it happens when you change the duty cycle. This doesn't happen in your case. But still worth checking. |
I made some progress, not as much as I wanted. There are 3 problems with the timer as is:
I captured more scope images using the values 0, 5, 9 out of a max of 10V, i.e. 0%, 50%, 90%. The names of the files are processor-phase-percent and I have B, G and Y in order for both Now GD32 in same order. Note that the GPIO outputs are high when low for the STM32, and vice versa. So 90% is actually 10%, 0 is actually wrong, both signals are high which should not happen. 50% looks identical, but it's reversed as well. This will obviously cause problem to the FOC motor control, since the voltages are wrong. The phase G and B being swapped is not as critical for motor control, as long as the motor connections are ok the code I used in this for both projects
|
I almost figured out the glitch. It happens when a new PWM value is written to the timer registers (new PWM value, or in the case of my sample code simply re-writes the existing value). The sample code is setting PWM values as quickly as the loop time, which is why I see so many glitches with the loop containing only a single pwm command. Probably in the STM32 there is a register setting to seamlessly update the register values without glitching the timer, and it's not set for GD32. I'll see if I can find it EDIT: by commenting out the following 2 lines, the glitch disappears
As for the timer polarity, it's a problem with register CHCTL0, which is set to 0x7070 but must be 0x6868 like in the STM32. It can be fixed by changing the lines following this to the below
With these 2 fixes, the only remaining problem is understanding why a PWM value of 0 results in both outputs being 0. I'm too tired to figure that out tonight :) |
It's 6am here, I can take over the shift 😜 |
The European shift tales over 😂 As you saw, I solved the glitch and reversed values. What is missing and critical is the wrong values for 0 pwm (and possibly 100%, I haven't checked). Then the swapped G and B phases, which I'm almost sure are simply a channel swap |
I see you already enabled the shadow register as mentioned here, this is best practice that was missing in the original firmware. Are you sure this hasn't solved some of the glitches ? About the PWM being inverted, that's also coming from the original firmware, and EFeru's firmware has the same. This is usually done to center the low side ON time for ADC sampling, see (1) on the picture: Regarding this:
SimpleFOC also seems to turn the phase OFF, that's probably why you see both high side and low side being low. It's called HIGH IMPEDANCE. I also have some splitboards with STM32F103 chips, so I could try comparing how the firmware behaves on those boards. If later you need the counter to stop during debug, I added this but it's commented. This is how STM describes it : I also noticed the old firmware was using this. I am not sure we want that. This will enable the timer output after each PWM cycle if it's disabled. We need to check if disabling the driver works as expected. |
Well, my goal was to get the GD32 SimpleFOC driver work the same as the STM32. If we want SimpleFOC to work without surprises, we need to follow the same conventions and have the PWM timer work the same (phase voltage and all). The 2 lines I commented out here https://github.com/Candas1/Arduino-FOC/blob/7cff1faa6acc47b04dabed47e230265bfb99a875/src/drivers/hardware_specific/gd32/gd32_mcu.cpp#L158 cause the glitch. The STM32 code for that function is much more complex and does a lot more, but I'm not sure that it writes to the same register as the GD32. I haven't fully followed that code yet and it's possible that we need more than just commenting out two lines. The "high impedance" phase_off code is still needed, but not yet called for now. That is definitely needed. The inverted output must be changed. Otherwise SimpleFOC sends, say, a 10V out of 12V on a phase, but the GD32 driver will send ~2V instead.... not good :) And we still have a problem with 0V and possibly Vmax, not sure yet. I'll work on that today |
Yes I agree, I commented the same in the other thread. Touching any of this code, the motor stops spinning, I need to find how to make it work without the glitch.
|
When you are saying G and B phases are reversed, are you talking about the BLDCDriver6PWM function call ? |
Just came across this, it can be useful. |
Yes. If I call the below
I get the wrong 0% on pins A10/B15, 50% on A9/B14 and 90% on A8/B13. On the STM32 with the same definitions, I get as expected 0% on pins A9/B14, 50% on A10/B15 and 90% on A8/B13. The pins assigned to timer channels must have a problem. Incidentally, the current code has the pin names in the function parameters, but the code uses the macros defined in the settings instead |
I was afraid of this, thanks for checking. The simplest workaround is to check if the timer is already enabled and only call the function to enable it if not enabled. Unlike the PWM call I use for test, the motor control very likely turns off a phase in certain parts of the rotation, and with the current code commented out, the timer is never re-enabled. I will do it today, pretty trivial to check if the timer is already enabled or not |
ok I got what you mean, you think enabling over and over again generates the glitch. Makes sense. |
I wouldn't worry about that. On an STM32 or GD32, checking a register takes as many assembly instruction as checking a variable value. All registers are memory mapped and accessible with no delays :) If you look at the STM32 code, that function is almost a hundred lines of code calling other function. On the GD32, it's going to be just a simple register read, binary and and a check, which is going to be super fast |
I tried a lot of things but still it didn't improve. |
@Candas1 , @robcazzaro , you make me happy and i fear that i can contribute little to that low level library confsusion. I do not understand how the 6 gate driver pins are mapped to the pwm interrupts!
But when i look at the GD32 implementation of that function, the 6 params are never used at all:
So i wonder how our gd32_mcu.cpp is able to drive the 6 mosfet pins at all ? |
For the moment the gd32 driver is using fixed pins, it's not using the parameters from this function. |
So the swapping of But then i want to mention (like @robcazzaro ?) that Maybe i could beautify your "for the moment" code with the Arduino-Core helper functions that retrieve the port and pin from single values |
I would rather have something that works and then beautify it. |
I'll take over now for the Seattle shift :) @RoboDurden to add to what @Candas1 says, the SimpleFOC is written for generic boards and a variety of processors. It tries to use every possible pin combination, and there is a lot of code devoted to ensure that the timer/pin combination is the right one. There are STM32 processors with multiple usable timers and pins, unlike in our case. Granted, if we wanted the GD32 code to be truly generic, we would need to use the pins passed in the call, but for now we are focusing on getting it at least usable, then make it more generic. The reason why almost all the pins in the SimpleFOC code are global, is that the Arduino pin naming convention is crazy and some pins have multiple possible uses. In a case with the STM32G431, I needed to use a pin for the encoder (which uses a timer in encoder mode), and that pin was PB7. But I needed to use the PB_7_ALT1 version to properly set the pin in the timer. The Arduino code has no provision to identify which of the multiple functions a pin can use. So the workaround was to instantiate the encoder with PB7, then set encoder._pinB to PB_7_ALT1 (https://community.simplefoc.com/t/encoder-skips-pulses/2884/38) It's very hard to write generic code that works on every possible processor family and processors inside a family. The SimpleFOC team did a pretty amazing job, hacks and all |
For now channels (not pins), can be swapped here. |
This code is taken from gd32/pinmap.c
|
We need much more than that to get it to work that way. |
so here the dso comparison between the simpleFOC firmware and the gen2.x binary: https://youtu.be/T1nndQ1UpqM The gen2.x firmware does a rect wave when not spinning the motor, which i think is needed for layouts without dedicated gate driver chips because the rectangle wave form for the low-side mosfet drives a charge pump to generate the 40+14V to drive the hi-side mosfets. But i may be wrong about that. |
Thanks for the additional screenshots Methinks that both the gen2 firmware and SimpleFOC send power to the motor to keep it in place, powered, and prevent movement when speed is 0. Only when freewheeling the motor phases are all off. When the motor is static, I'm sure that SimpleFOC keeps the phases energized to prevent movement when speed is 0. The reason why the gen2 has a square wave when not moving, is probably because they apply a much stronger force to hold them motor, while with the settings we have now, SimpelFOC only applies a weak current to hold the motor. So gen2 uses roughly half the voltage for each phase, while SimpleFOC uses probably10-15% of the voltage. Changing the torque settings in SimpleFOC would increase that PWM value, and get to a square wave, too Easy to verify: try moving the wheel by hand when powered on and not rotating, and you should feel a string resistance to movement, stronger in gen2 than SimpleFOC |
No, not really. With SimpleFOC, the current only rises from 30 mA (@ 26V, setting the 6 gate ouputs back to And for sure the not changing 50% duty square wave on hiside and loside of the gen2 with speed = 0 must cancel each other out, otherwise some uncontroled current would flow. 22:03 here in Germany now and i only have a 3W led lamp here in my solar powered train station. Too dark to probe the gate pins now. Maybe you can fully understand how that C1 capacitor is driven to generate the 14+40V: When the lo-side mosfet is closed (conducting), C1 is charged, when it is open, its voltage adds to the middle point of that half bridge (= source of hi-side mosfet) and the gate of the hi-side can be driven by that voltage. |
Got it, thanks for the additional info! |
SimpleFOC has a very good documentation, this can help understand how it works. Sorry guys I couldn't check anything and I leave soon. |
@Candas1 , @robcazzaro , is the gd32_mcu.cpp now already good enough that i could begin with master-slave uart communication and i2c control that would replace my Gen2.x repo ? I would be happy to delete my Split_Hoverboard_SimpleFOC original and this one here from Candas becomes the lead. |
In my opinion, it's good enough to be used, and should already be as good as the motor control in gen2 firmware? I haven't tried debugging after the recent changes, I would still not do it without a power supply. Now we need to make a better use of simplefoc. We could create a list of tasks, agree on the priorities, align on the dependencies not to impact each other. Like a real project 😂 |
I started to list some ideas here. |
It could be this is happening because I kept the voltage_limit low to play it safe for the tests. limits.png |
If we do not set the voltage limit, it will be equal to the power supply voltage, so the duty cycle should be 50% with target 0 as the modulation is centered |
Indeed yes :-)
produces the same 50% duty square rect at target speed 0 :-)
|
I think so |
But the max speed is already reached at about 12.0. Setting it higher will only make the motor spin longer at the max of 12.0. So either that is the max or there is a clamp somewhere in the library. |
That's weird. And the max duty cycle is 100%, do you know the max speed you reach in rpm? |
for that i would need to get the uart debug output working so i can log the rpm. |
You could try simplefocdebug and monitoring that I added recently |
Yes, the initialization code is robust and safe to use, I'll add the few missing things (as per your spreadsheet) soon, but none makes a real difference for now
Yes, good idea. Please feel free to assign any low level tasks to me as a default. I'm much more useful working at that level, and you both are much more knowledgeable about the motors and their control |
Here another dso test that compares the voltage differences of Gen2.x vs SimpleFOC between pahse blue and yellow at max speed: https://youtu.be/DFzkf_X7WHU The dso output should reflect the current flowing through the blue-yellow windings and be proportional to the speed ?! Both binaries produce these double pulses also at max speed. I guess that is okay because we have a vector addition of the three sets of coils, and even at max speed, one set must vary its current to achive a rotating vector. But this is only 1/3 of the motor coils, so the 90% duty cycle overlaps with green-blue and green-yellow anyway. When i click on Custom->Update_SimpleFOC that succeeds.
|
@RoboDurden to update only the GD32 Arduino framework To update, use a PlatformIO core CLI and execute
Also, please note this part in your error message
|
thanks. How do i stash on the cli ?
|
No idea, sorry. In cases like these I simply copy the files to a temp location on my disk, discard them and update. If needed, I manually merge the files by copying the relevant lines in the IDE. Not very elegant, I admit 😁 I never took the time to learn how GIT commands work from Platformio. But it's all here https://docs.platformio.org/en/stable/integration/ci/github-actions.html |
Thanks @robcazzaro , after removing |
@RoboDurden if you want to discard changes, you can do so from the UI, too, much easier than chasing the right files on disk. If you right click on the file name itself, it also offers more options (like discard changes) From that UI it's easy to see what needs to be changed to unblock the updates, and decide what to do |
the poor motor behavior of the SimpleFOC binary is still the same :-/ |
In the past, I had problems with SimpleFOC due to the limited speed of the encoder readings. The Arduino interrupt handling code has a lot of overhead, made worse by the various processor layers. If the code handling the hall sensors is not fast enough, speed is limited by that. And we are using a 48MHz processor, pretty slow all considered. I don't have time today, though. Over the weekend, I'll look at ways to speed up the interrupt handler and see if that improves anything. |
BTW: we should open a new issue every time we discover a problem like this one. Otherwise things become hard to follow. The motor performance is not a timer issue 😉 |
There is some improvement in the next release simplefoc/Arduino-FOC#270 |
As per #1 (comment), there is a serious problem with the timer initialization
I'm opening this as a work item.
The text was updated successfully, but these errors were encountered: