CanardRxTransfer payload reading?

Hi,
Seem I have the wrong version of arm-eabi-none-g++ .
Had a lot of trouble but finally got the newer version of compiler on there and it is building, yay!
I’ll try getting it to work now if I can find how the rom is arranged.
Where is the bootoader usually located?
The smaller flash pages are at the beginning (in the f4) so is the boot loader usually at the end?

Thanks.

Hi,
Im trying to figure out how to use this code.
i.e. where is flash size defined?
I found flash offset, but can’t find where you are defining the processor in the code.
I am not sure if CAN is enabled in the sample you sent.
in halconf.h HAL_USE_CAN is defined false.
If I define it to true and define serial options to false it gets an error CAN driver activated but no CAN peripheral assigned.
Do I then need to define the CAN port in the mcuconf file similar to some of the mcuconf files similar to some of the stm32 demo versions under chibios?

Thanks

Hi,

Also How do I add another board?
Ia m using a f413 and it appears this type has not been used before.

Thanks

All ARM-based microcontrollers known to me boot from 0x00000000 so the bootloader is always at the very beginning.

It’s in the linker script named ld.ld located in the root directory. This is where the size of the bootloader itself is defined as well.

This is correct. The sample does not use the CAN driver supplied by the operating system (it’s defective); instead, it uses the driver shipped with Libcanard, which requires no support from the operating system.

The MCU abstractions are managed by ChibiOS, so you should refer to its documentation. Briefly, in the Makefile you will find this section:

# MCU-specific OS includes
include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk

Update it if necessary. Then edit src/os/halconf.h and src/os/board.h.

Hi,
I have modified the files and checked PLLcfgr and cfgr registers and looks ok.
It computes the same timings my other code does but when it gets to canardSTM32Init it fails with error
CANARD_STM32_ERROR_MSR_INAK_NOT_CLEARED when attempting to leave init mode.
I changed optimization back to none to debug it.
Do you have any clues why this may be happening on the kocherga project?
I haven’t got the other hardware to test if this code is working correctly.
My other projects run fine on the same hardware.
Thanks.

This is rather typical for misconfigured or malfunctioning hardware. Before leaving the init mode, the CAN controller waits for 11 consecutive recessive bits to appear on the RX line. The most common reason for this process to time out is for the physical layer to be malfunctioning or for pin remapping to be configured incorrectly. You could re-check the remapping config and also you should sample the RX pin directly to see if it is at the recessive (high, logical 1) level.

Thanks,
will do
Kent

Pavel,
Thanks that solved the problem and got it running.
However now I can manage to program successfully but it will not execute my application correctly.
I then debugged my code with the bootloader still in place and then my code ran correctly.
The only difference in the binary will be the checksum will blank in the debugged code since that is added after building and only for the binary to be programmed in.
I noted that the image should be 8 bytes aligned in the notes , is that taken care of with the populate_app_descriptor script?
As soon as I debug everything works so I’m not sure what is going wrong.
Could it be the watchdog? or something else that is disabled when debugging.
i.e. my code doesn’t use a watchdog yet, so not sure if kocherga or chibios is leaving it on, or it is a clean boot into the application code.
Also once I have gotten this to work how do I get the bootloader to activate when the application is valid?

Thanks,
Kent

Ah yes, it happens. The most likely reason is that the bootloader launches the application incorrectly, e.g. by not disabling interrupts first, or by jumping to the wrong location, or maybe your application is linked incorrectly – check the *.ld file and make sure the bootloader’s space is factored in. When you launch the application using the debugger, it always initializes it from the well-known reset state, so it works.

The most relevant piece is here (under board/board.cpp in the demo I shared):

[[noreturn]]
void bootApplication()
{
    // Loading and validating the application entry point
    const unsigned stacktop   = *reinterpret_cast<unsigned*>(FLASH_BASE + APPLICATION_OFFSET);
    const unsigned entrypoint = *reinterpret_cast<unsigned*>(FLASH_BASE + APPLICATION_OFFSET + 4);


    if ((stacktop <= SRAM_BASE) ||
        (stacktop > (SRAM_BASE + 2 * 1024 * 1024)))
    {
        chibios_rt::System::halt("STACKTOP");
    }


    if ((entrypoint < (FLASH_BASE + APPLICATION_OFFSET)) ||
        (entrypoint >= (FLASH_BASE + getFlashSize())))
    {
        chibios_rt::System::halt("ENTRYPOINT");
    }


    // We cordially extend our thanks to David Sidrane and Ben Dyer, whose ideas have somewhat inspired this thing.
    asm volatile("cpsid i");


    // Deinit all peripherals that may have been used
    // It is crucial to disable ALL peripherals, else a spurious interrupt will crash the application
    RCC->APB1RSTR |=  (RCC_APB1RSTR_CAN1RST | RCC_APB1RSTR_CAN2RST | RCC_APB1RSTR_USART3RST);
    RCC->AHB2RSTR |=  RCC_AHB2RSTR_OTGFSRST;


    // Kill the sys tick
    SysTick->CTRL = 0;


    // Update the vector table location
    asm volatile("dsb");
    asm volatile("isb");
    SCB->VTOR = FLASH_BASE + APPLICATION_OFFSET;
    asm volatile("dsb");


    // Let's roll!
    asm volatile("msr msp, %[stacktop]          \n"
                 "bx       %[entrypoint]        \n"
                 :: [stacktop] "r"(stacktop), [entrypoint] "r"(entrypoint):);


    for (;;) { }        // Noreturn
}

The script will pad the binary automatically if needed. You only need to ensure that the ROM start address in the application’s linker script is aligned at 8 bytes.

Watchdog is not disabled while debugging.

Hi,
I’m just debuggin in to see what kocherga is actually doing.
I have set up my code to run at ofset 0x20000 from the flash base.
I have adjusted the parameters to load the vectors at the correct offset for this.
I have adjusted the parameters in kocherga to offset the code as well.
This is done in 2 places
ld.ld
flash : org = 0x08000000, len = 130816 /48896/
that is 0x20000 -256 to allow for marker section
makefile
APPLICATION_OFFSET = 131072 #49152
move from xc000 to x20000 ( i need more space for no optimization of bootloader for debugging)
However when I debug I find it sets
stacktop = 0x20050000
entrypoint = 0x80265DD
Where is the 65DD coming from?
In my code there is a marker in the binary but dies not exists as the first entry before the rest of the code but rather as a constant in the code relatively close to the start of the binary but not at 0 offset.
I don’t understand how FLASH_BASE + APPLICATION_OFFSET + 4 becomes 0x80265DD when it should be 0x8020004?
I think this is where the problem is, could yo elaborate why this is done and what expectations you have of the binary bearing in mind it is not built with your build system.

Thanks

Hi,
It seems you are also reading/writing to a section of ram at 0x2001ff00, can you explain what you are sharing between the two programs and why?
I was expecting there not to be a shared memory location and interactions to be handled using registers and not hard coded memory maps.

Thanks

The entry and stacktop seem correct once you read the memory at the start of my rom.
So there is something else, either interrupts , the memory area you are writing to or something else.

Hi,
I have managed to debug a bit further and I am getting inak not set occuring when the bootloader runs before my code. I have forced default gpio config and cleared nirqs on start of my code, and ensured can port is reset at start of each initialisation of each port. However the problem will not go away, but code still runs fine when I run my own code without the bootloader. It is extremly difficult to debug since I cannot use the debuufer and can seem to only get one character out the serial port before it dies.
Can you be of any assitance with what the bootloader may be doing to the can port and how I can get everything back t o default state?

Thanks

The 256 reserved bytes of RAM for bootloader-app data exchange contain this structure, defined in /src/app_shared/app_shared.hpp:

/**
 * This struct is used to exchange data between the bootloader and the application.
 * Its format allows for future extensions.
 */
struct AppShared
{
    std::uint32_t reserved_a = 0;                               ///< Reserved for future use
    std::uint32_t reserved_b = 0;                               ///< Reserved for future use

    /*
     * UAVCAN part
     */
    std::uint32_t can_bus_speed = 0;                            ///< App <-> Bootloader
    std::uint8_t uavcan_node_id = 0;                            ///< App <-> Bootloader
    std::uint8_t uavcan_fw_server_node_id = 0;                  ///< App --> Bootloader

    static constexpr std::uint8_t UAVCANFileNameCapacity = 201;
    char uavcan_file_name[UAVCANFileNameCapacity] = {};         ///< App --> Bootloader

    /*
     * General part
     */
    bool stay_in_bootloader = false;                            ///< App --> Bootloader

    /*
     * More reserved fields
     */
    std::uint64_t reserved_c = 0;                               ///< Reserved for future use
    std::uint64_t reserved_d = 0;                               ///< Reserved for future use
};

static_assert(sizeof(AppShared) <= 240, "AppShared may be larger than the amount of allocated memory");
static_assert(sizeof(bool) == 1, "Please redefine bool as uint8_t in the shared struct (should never happen on ARM)");

A compatible definition should be provided in the application, too. As the description says, it is used for passing identified bus parameters to the application and back. Also, when the application invokes the bootloader, it has to communicate to it where to find the new firmware: which node-ID to download it from and what is the name of the file on the server.

Your issues with the debugger make me suspect that you forgot to update your linker script, and your application is actually linked to run from 0x08000000 whereas the bootloader attempts to launch it from a different location. If you could post your code in its entirety, I could have a look and assist.

The entry point is the handler of the reset vector. The handler itself can be located anywhere, in your case, it is at 0x000065DD from the beginning of the image. Everything seems OK here.

Here is the first line of the hex file
:020000040802F0
th 0802 is the upper 16 bits of the address, and is correct.
Here is the memory section of the linker file:

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
/*FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1536K*/
FLASH (rx)      : ORIGIN = 0x8020000, LENGTH = 896K
}

which is correct.
When I debugged it read 0x80265DD as wntry point from the ROM which seems reasonable since it’s after 0x8020000. Note I have also run my code after the debugger and it is toggling LEDS that I have changed to see that the code ran.

I added the following lines to the start of my main.c

LL_AHB1_GRP1_ForceReset  (LL_AHB1_GRP1_PERIPH_ALL);
LL_AHB1_GRP1_ReleaseReset(LL_AHB1_GRP1_PERIPH_ALL);
LL_AHB2_GRP1_ForceReset  (LL_AHB2_GRP1_PERIPH_ALL);
LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_ALL);
LL_AHB3_GRP1_ForceReset  (LL_AHB3_GRP1_PERIPH_ALL);
LL_AHB3_GRP1_ReleaseReset(LL_AHB3_GRP1_PERIPH_ALL);

This still did not help it to run.
The ram area you have written should not affect my code unless my code does not clear that ram at start up but the compiler should 0 any areas that are required to be zero by default.

I can’t post the code in it’s entirety as it contains some proprietary source that is required to remain undisclosed.

From all I can see it is executing from the correct location.
The only other thing I noticed when testing my code on it’s own the 2nd and 3rd can port would fail when the calls where slightly rearranged, which is totally confusing.
In the below code if I separate the calls (uncomment the lines) to init the clocks and pins (CANInit) to do all can ports before calling CANswInit then can port 1 would init ok but 2 and 3 would pass waiting for synchronisation but fail when exiting init mode with inak not cleared. In the code below CANInit initializes the can clocks and gpio pins.

for (Port = CANStrt; Port < CANEnd; Port++)
{
	CANInit((CAN_Init_t*) &CAN_Init[Port]);
//}
//for (Port = CANStrt; Port < CANEnd; Port++)
//{
	//gpioSet(LED2_GPIO_PORT, LED2_PIN,1);
	gNodeID[Port] = parameters[Port+Var_NETID0].val;
	CANswInit(Port, &g_canard[Port], g_canard_memory_pool[Port], sizeof(g_canard_memory_pool[0]),
			(Port == 0) ? (onTransferReceived0) : ((Port == 1) ? (onTransferReceived1) : (onTransferReceived2)), shouldAcceptTransfer, gNodeID[Port],
					filter_configs,ARRAY_SIZE(filter_configs));
	//gpioSet(LED3_GPIO_PORT, LED3_PIN,1);
}

I can post a copy of code but I will need to remove some sections. I’ll see if that is easy to do.
Thanks.

nucleo_f413zh_libcanard.zip (24.9 MB)

The source is attached. This should build under SW4STM (Ac6) .
I manually edited the linker file to move the start address.

Apologies for taking forever to respond. I couldn’t find anything wrong with the application so far, but for completeness, I would also like to have a look at the modified bootloader (with the updated linker script and the new parameters in the Makefile).

Hi,
Thanks Pavel. The main changes for the lnidker file are :
flash : org = 0x08000000, len = 130816 /48896/
and makefile:
APPLICATION_OFFSET = 131072 #49152
and optimisation
USE_OPT += -O0
I changed it t not optimize for debug config so I could trace through,
Other changes re for my board, like clock changes in mcuconf.h
See attached file here

Thank you. Unfortunately, I am going to be unable to assist you any further on this due to the lack of time. Seeing as at this point your problem is not related to UAVCAN at all, I recommend you to seek help in a more general community, such as Stackoverflow or similar. Sorry.

Thank you @pavel.kirienko for sharing this demo.
I have been trying to use Kocherga some months ago, but without the demo and as a first time working on a bootloader, I did not manage to go further.

This time, I would like to use your demo, but I failed to understand how to integrate it with an application.
Do you have a simple application that could be use on top of the kocherga demo?
Or at least for pointers on how to alter a default ChibiOS linker script and the minimal bits that are needed at the application level to interact with the bootloader.

Thanks a lot for all your work.