CommunityGD32Cores / platform-gd32

PlatformIO platform for ARM-based GD32{F,E,L,W} chips. Work in Progress!
67 stars 28 forks source link

Are weak symbols supported? #41

Closed gagipro closed 1 year ago

gagipro commented 1 year ago

Hello,

I saw many issues like those one : https://github.com/platformio/platform-ststm32/issues/468 https://github.com/platformio/platform-ststm32/issues/205

and I was wondering if someone knows if there can be same issue with : platform = https://github.com/CommunityGD32Cores/platform-gd32.git framework = spl

thanks in advance

maxgerhardt commented 1 year ago

This is PlatformIO-core dependent, we don't try and fix this or modify linking order in the core. So yes, if you do have weak functions (especially common for interrupt service routines) that are implemented in libraries, better set lib_archive = no.

If you want a more concrete answer, I'll need to you to provide a concrete example that fails to link correctly.

gagipro commented 1 year ago

This is PlatformIO-core dependent, we don't try and fix this or modify linking order in the core. So yes, if you do have weak functions (especially common for interrupt service routines) that are implemented in libraries, better set lib_archive = no.

If you want a more concrete answer, I'll need to you to provide a concrete example that fails to link correctly.

Hello Max, it links but interrupt handlers never get triggered, i will try to make a custom link command to see if it changes something in the behavior and let you know.

Thanks a lot

maxgerhardt commented 1 year ago

objdump -d the .elf file and grep for the interrupt function. If the whole function code is there for it, it's not a linking fault and the error is elsewhere. That's a 10 second way to eliminate it.

gagipro commented 1 year ago

objdump -d the .elf file and grep for the interrupt function. If the whole function code is there for it, it's not a linking fault and the error is elsewhere. That's a 10 second way to eliminate it.

Thanks again Max, I´ll do it as soon as I´m in front of the pc.

Regards

gagipro commented 1 year ago

objdump -d the .elf file and grep for the interrupt function. If the whole function code is there for it, it's not a linking fault and the error is elsewhere. That's a 10 second way to eliminate it.

ok did that and the whole TIMERx_IRQHandler for each declared TIMER are there, so the issue is somewhere else...

Do you have any clue why our TIMERs are not triggerd, I tried to implement also to decalre VTOR table without any luck...

thanks

maxgerhardt commented 1 year ago

Have you tried using one of the minimal GD32 SPL examples for your chip that use TimerX? https://github.com/CommunityGD32Cores/gigadevice-firmware-and-docs/tree/main/GD32F30x/GD32F30x_Firmware_Library_V2.1.4/Examples/TIMER

gagipro commented 1 year ago

Have you tried using one of the minimal GD32 SPL examples for your chip that use TimerX? https://github.com/CommunityGD32Cores/gigadevice-firmware-and-docs/tree/main/GD32F30x/GD32F30x_Firmware_Library_V2.1.4/Examples/TIMER

Yes I tried same implementation but I only have the tft of my 3dprinter and I can print some variables, I don´t have a whole development environment.

It´s for this issue :

https://github.com/bigtreetech/BIGTREETECH-TouchScreenFirmware/issues/2391

here's the dump :

DUMP.txt

I tried also to add a solution I found in this document : https://community.platformio.org/t/custom-board-build-error-gd32f470-eval/29388/24

/ Vector Table base offset /

define VECT_TAB_OFFSET 0x00 / This value must be a multiple of 0x200. /

void SystemInit(void) { ... system_clock_config();

ifdef VECT_TAB_SRAM

nvic_vector_table_set(NVIC_VECTTAB_RAM, VECT_TAB_OFFSET);

else

nvic_vector_table_set(NVIC_VECTTAB_FLASH, VECT_TAB_OFFSET);

endif

... }

without any luck of course

maxgerhardt commented 1 year ago

I can at least test on a GD32F303CC with a debugging probe. Do you have a minimal, stripped down project that tries to use Timerx that I can just test?

gagipro commented 1 year ago

I can at least test on a GD32F303CC with a debugging probe. Do you have a minimal, stripped down project that tries to use Timerx that I can just test?

I have only this : https://github.com/ciotto/BIGTREETECH-TouchScreenFirmware/tree/MKS-GD-TFt28-debug/TFT/src/Libraries

perhaps you will see an issue directly.

maxgerhardt commented 1 year ago

So this is about TIMER2_IRQHandler as defined in TFT\src\User\Hal\buzzer.c?

gagipro commented 1 year ago

So this is about TIMER2_IRQHandler as defined in TFT\src\User\Hal\buzzer.c?

There is also a TIMER6 handler in os_timer.c but I tried to read flag and both don´t work.

maxgerhardt commented 1 year ago

What is the exact chip name written on your chip?

gagipro commented 1 year ago

What is the exact chip name written on your chip?

Gd32f305vct6

gagipro commented 1 year ago

I found this : GD32F303xx microcontrollers where the flash memory density ranges between 128 and 512 Kbytes are called High-density devices (GD32F30X_HD). GD32F303xx microcontrollers where the flash memory density is over 512 Kbytes are called Extra-density devices (GD32F30X_XD). GD32F305xx and GD32F307xx microcontrollers are called connectivity line devices (GD32F30X_CL).

Flash Memory 256K RAM 96K

so, with a Gd32f305vct6, it seems we are facing GD32F30X_CL...

maxgerhardt commented 1 year ago

Exactly. But this series does have Timer2 at least per the startup file. The address of the function (+1 for THUMB execution) also ends up in the vector table as I checked. So I think this is rather a problem in code than incapable hardware.

gagipro commented 1 year ago

Exactly. But this series does have Timer2 at least per the startup file. The address of the function (+1 for THUMB execution) also ends up in the vector table as I checked. So I think this is rather a problem in code than incapable hardware.

Ok Max but if you have a look to the repo and the issue, you´ll see that we have no clue at all.

If we have a final binary firmware that works and a custom one, do you think it´s possible to isolate at least the offsets or differences between them?

Thanks in advance

ciotto commented 1 year ago

Hi, the vector table of the original firmware uses TIMER2.

I flashed the 2 different examples but seems that TIMER2_IRQHandler is never called.

@maxgerhardt you know if breakpoint works on interrupt?

maxgerhardt commented 1 year ago

Yes breakpoint works on interrupts.

What exact example are you flashing? Can you upload the project?

ciotto commented 1 year ago

TIMER2_inputcapture and TIMER2_pwminputcapture. Is not so clean but you can find my tests on this branch, last 2 commits.

Thank you for your help!

maxgerhardt commented 1 year ago

This demo is based on the GD32307C-EVAL-V1.1 board, it shows how to use the TIMER peripheral to measure the frequency and duty cycle of an external signal.

Both example require an external signal that is fed into specific pins for the timer hardware to measure. How do you generate that signal?

ciotto commented 1 year ago

Oh damn! There is an example that doesn't require an external signal?

maxgerhardt commented 1 year ago

The simplest possible example would be a periodic up or downcounter with a capture/compare interrupt. The examples in the SDK either don't use interrupt functions or do use interrupts but require external signals. I'll quickyl write the most basic example and test it.

But I can already tell you that timer interrupts 100% work. We use them in the ArduinoCore-GD32 to output PWM / call functions periodically.

See https://github.com/CommunityGD32Cores/gd32-pio-projects/blob/main/gd32-arduino-pwm-out/src/main.cpp and https://github.com/CommunityGD32Cores/ArduinoCore-GD32/blob/main/cores/arduino/gd32/timer.c.

ciotto commented 1 year ago

Yes, probably there is some missing configuration in our project. If I find a working example I can try to find the differences.

Just to be sure, TIMERx interrupt can be triggered without an external signal?

maxgerhardt commented 1 year ago

Yes. You can just tell TIMERx to start counting up (using the system clock source diveded by a prescalar), and when the desired value is reached the channel can throw an interrupt. No external signal needed.

And as expected, in my minimal project, the Timer2 works just fine.

grafik

I will update the project shortly.

maxgerhardt commented 1 year ago

See https://github.com/maxgerhardt/gd32-spl-timer.

Some caveats for your project might be:

The above example blinks the PC13 LED on a standard Bluepill board with a GD32F303CC. Make sure to select the GD32F305VC environment in the project environment selector in the bottom taskbar. These binaries are not compatible with each other, running a binary built for the F303CC will not work on a F305VC and vice-versa.

And remember that you can attach a debugger at any time and read out the peripheral registers for the RCU (clock unit), the timers (timer configuration, current count, active interrupt bits and masks), this should help you.

ciotto commented 1 year ago

Thank you so much! Tomorrow I'll try.

ciotto commented 1 year ago

I couldn't wait, it works! Tomorrow I try to compare your simple project with the BTT one.

maxgerhardt commented 1 year ago

Great to hear it works in the minimal example.

And also actually I've just read the F30x reference manual a bit to understand these timers better. In my example I'm "using" channel 0 interrupts, specifically the output compare function. This will trigger when the counter of the timer matches the value in the CH0VAL register. CH0VAL is by default 0 and is not explicitly initialized in the code. When the counting is started in the timer at count = 0 in an up-counter fashion, up until the value where 1000 milliseconds are expired, the up counter automatically reloads to 0 after expiring. This then lets the CH0VAL match the count and the hardware generates a channel 0 output compare interrupt.

This is a bit unusual to a channel timer like this, I think usually you would go via the "timer update" interrupt ("Once the counter reaches the counter reload value, the counter will start counting up from 0 again. The update event is generated at each counter overflow.."). This seems more natural than using channel 0.

When rewriting the code to use timer update interrupts it justs works as before: https://gist.github.com/maxgerhardt/92e320690fe4dafeefb4be938cef8a3e

Of course the timer can do more like direct PWM output on the dedicted TimerXChannelY pins per the datasheet, but the update timer interrupt is pretty universal and can trigger arbitrary GPIO pin toggles.

ciotto commented 1 year ago

Great! This version works also with TIMER6, the previous one doesn't work.

I moved also the example inside the BTT project but doesn't work. This project uses a custom linker in order to relocate the firmware at address 0x08007000 and the example works only if I use 0x08000000 as base address.

So I supposed that on this version of the board, the bootloader never relocates the vector table.

I tried to call nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x7000); but seems useless.

Have you experience with relocated vector tables?

maxgerhardt commented 1 year ago

So I supposed that on this version of the board, the bootloader never relocates the vector table.

So what's the value of SCB->VTOR when the first instruction of your firmware (at 0x08007000) is executed? You do seem to have a SWD debugger like a STLink to check that or print it to make sure?

maxgerhardt commented 1 year ago

Do you have the bootloader binary of just a dump of the first 0x7000 bytes of flash of your board? Can you upload it?

gagipro commented 1 year ago

Do you have the bootloader binary of just a dump of the first 0x7000 bytes of flash of your board? Can you upload it?

It´s possible to dump it with an stlink ?

maxgerhardt commented 1 year ago

Yes. Connect an ST-Link via GND, SWDIO and SWCLK to the board, power up the board regularly, use the ST-Link utility to connect to the chip, set start address 0x800000 and size 0x7000, width 8 bits, then File->Save File As -> flash.bin

grafik

gagipro commented 1 year ago

Yes. Connect an ST-Link via GND, SWDIO and SWCLK to the board, power up the board regularly, use the ST-Link utility to connect to the chip, set start address 0x800000 and size 0x7000, width 8 bits, then File->Save File As -> flash.bin

grafik

Probably @ciotto will be able to do it when he see this message.

Thanks a lot for your help

ciotto commented 1 year ago

Sorry, I'm not in front of my PC now, but I already dumped the bootloader and Is available here.

Dumped from address 0x0 with st-info.

ciotto commented 1 year ago

Anyway, in BTT firmware SCB->VTOR is correctly setted to 0x08007000, I checked and the value is right.

gagipro commented 1 year ago

So I supposed that on this version of the board, the bootloader never relocates the vector table.

So what's the value of SCB->VTOR when the first instruction of your firmware (at 0x08007000) is executed? You do seem to have a SWD debugger like a STLink to check that or print it to make sure?

with the stlink it's possible to trace this VTOR address on an original firmware?

gagipro commented 1 year ago

bootloader.txt

bootloader only

gagipro commented 1 year ago

image

it seems that in original firmware, there is something with PTR_USART2 after disabling irq and then reenabling irq after. I see no such things in our custom firmware...

I tried in main and also in SystemInit : __disable_irq(); SCB->VTOR = VECT_TAB_FLASH; __enable_irq();

but no luck

gagipro commented 1 year ago

Hello @maxgerhardt it seems I manage to make timers works like this :

https://github.com/bigtreetech/BIGTREETECH-TouchScreenFirmware/issues/2391#issuecomment-1455162067

Do you think it´s normal behavior?

Thanks to explain to us if you understand please.

Still I have issue with usart, perhaps not initialized the correct gd32 way or missing reenabling some other interrupt after bootloader jump, if you have any idea.

Thanks in advance

gagipro commented 1 year ago

@maxgerhardt Thanks Max, I solved it : set the pin remapping on right usart and now everything's ok.

Thanks a lot for your time.