Bare metal I2C breaks ChibiOS i2cMasterTransmit

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: RoccoMarco, lbednarz, tfAteba

matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

Dear All,

currently I'm done with the development of my ChibiOS application. In order to do firmware updates, we need to have a bootloader.
The bootloader is (due to its size) a bare metal app that reads a I2C register to determine to jump to the ChibiOS app (flash : org = 0x0800F000, len = 452k) or stay in bootmode (flash : org = 0x08000000, len = 60k) to receive the new firmware and flash the binary at offset 0XF000.

The startup and determination whether to jump to app or stay in boot works fine; As does the jumping to the ChibiOS app. I reach the ChibiOS-main function (through the reset handler) and when I try to do a i2cMasterTransmitTimeout both the SCL and SDA are pulled low, but no byte emerges the STM32 F103VET6. The i2cAcquireBus function seems to be successful. After that the whole MCU freezes and I get "Warn : Timeout (1000ms) waiting for ACK=OK/FAULT in JTAG-DP transaction" in my GDB. Only a power cycle can revive the STM32.

When I run the ChibiOS app standalone from 0x08000000 (thus without bootloader) it all works like a charm.

The jump_to_application function looks like this:

Code: Select all

void jump_to_application()
{
    typedef void (*pFunction)(void);

    pFunction Jump_To_Application;
    /* variable that will be loaded with the start address of the application */
    vu32* JumpAddress;
    const vu32* ApplicationAddress = (vu32*) APPLICATION_ADDRESS;

    /* get jump address from application vector table */
    JumpAddress = (vu32*) ApplicationAddress[1];

    /* load this address into function pointer */
    Jump_To_Application = (pFunction) JumpAddress;
#if defined(BOOT_MAX7311)
    /* Disable and reset I2C1 PHY */
    I2C_Cmd(I2C1, DISABLE);
    
I2C_DeInit(I2C1);
#endif
    /* reset all interrupts to default */
    NVIC_DeInit();
    /* set stack pointer as in application's vector table */
    __MSR_MSP((u32) (ApplicationAddress[0]));
    Jump_To_Application();
}
 

It makes no difference whether I run the I2C_Cmd(I2C1, DISABLE); or not.

I'm quite stuck on this one. I hope one of you could help me out :oops:

Thanks in advance,

Matis

Edit; When halting the target after entering the i2cMasterTransmitTimeout function. The I2C1_SR1->SB is altered from 0 to 1, so the PHY is in the "Start bit send (Master)" state. But nothing more happens. Not even the timeout is triggered.
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by barthess »

I need more information. Try to explain step by step:
1) what you do (describe in details)
2) what you expect
3) what you got

What functions

Code: Select all

I2C_Cmd(I2C1, DISABLE);
    I2C_DeInit(I2C1);
do?

Why bare metal bootloader instead of ChibiOS based if your bootloader code
matis wrote:bootmode (flash : org = 0x08000000, len = 60k)

occupy 60k of flash space? I could shrink my own ChibiOS loader to 1025 bytes without killing of NVIC table.
matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

barthess wrote:I need more information. Try to explain step by step:
1) what you do (describe in details)
The bootloader accepts bytes from a UART bus. This can be commands or firmware bytes (for updating). It can also decide (from a bit in a MAX7311 I2C slave) to switch (jump) to application mode or to stay in bootmode to flash new firmware. At this moment I force the boot application to jump to application app. It reads the resetvector from the offset, disable its interrupts and then jumps to the resetvector where the whole initialization starts.
2) what you expect
I expected that jumping from boot app to application app should reinit the whole STM32 with all the PHY's working.
3) what you got

I got a boot application (bare metal) that does UART, I2C, EEPROM, SPI interfacing like it should. (standalone)
I got a application application (based on ChibiOS) that does UART, I2C, EEPROM, SPI interfacing like it should. (standalone)

When jumping from bootmode app to the resetvector of the application app and going through the ChibiOS-main its gets stuck with the first external (PHY) interfacing. The halInit succeeded, the chSysInit succeeded, but when I reach the point where I want to read the MAX7311 the whole app freezes and the MCU breaks. So bad that it isn't recoverable through JTAG.
What functions

Code: Select all

I2C_Cmd(I2C1, DISABLE);
    I2C_DeInit(I2C1);
do?

Those are standard STM32 FW-lib functions, the same as included in the chibios/ext/stm32lib.zip file.
Why bare metal bootloader instead of ChibiOS based if your bootloader code
matis wrote:bootmode (flash : org = 0x08000000, len = 60k)

occupy 60k of flash space? I could shrink my own ChibiOS loader to 1025 bytes without killing of NVIC table.

Because the work was already done in a pre-ChibiOS state. The size of the bin file of the current bootloader is 41KB. The fact while the booloader is this big, is because of it is a regular application, just like the application application, but universal for a lot of different products.

Now I'm trying to work with two ChibiOS-apps, where the one jumps to the other and vice versa. But I'm struggling with the debugger at the moment.

Thanks for your help so far. I really appreciate it, while this is the last step in my development.
matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

matis wrote:Now I'm trying to work with two ChibiOS-apps, where the one jumps to the other and vice versa. But I'm struggling with the debugger at the moment.

My bad, I tried to flash the .elf file instead of the .bin file.

What I've got now:
Two ChibiOS applications (lets call them for ease boot and user application) that are exactly the same. The first is as offset 0 with length of 256k the second is at offset 0x40000 with length of 256k. What I try to achieve is the following: Ping pong between the two applications.

I rewrote the bare metal function to a ChibiOS one that looks like this:

Code: Select all

    typedef void (*pFunction)(void);

    pFunction Jump_To_Application;
    /* variable that will be loaded with the start address of the application */
    vu32* JumpAddress;
    const vu32* ApplicationAddress = (vu32*) APPLICATION_ADDRESS;

    /* get jump address from application vector table */
    JumpAddress = (vu32*) ApplicationAddress[1];

    /* load this address into function pointer */
    Jump_To_Application = (pFunction) JumpAddress;
    /* reset all interrupts to default */
    chSysDisable();
    /* set stack pointer as in application's vector table */
    __set_MSP((u32) (ApplicationAddress[0]));
    Jump_To_Application(); 


Unfortunately, the boot application crashes when trying to make the jump:
stacktrace wrote:Thread [1] (Suspended: Signal 'SIGINT' received. Description: Interrupt.)
7 _unhandled_exception() vectors.c:289 0x0800b390
6 <signal handler called>() 0xfffffff1
5 chSysTimerHandlerI() chsys.c:139 0x0800b776
4 SysTickVector() chcore_v7m.c:45 0x0800b3be
3 <signal handler called>() 0xfffffffd
2 <symbol is not available> 0x55555554
1 <symbol is not available> 0x55555554


Hope this helps you pinpoint the problem a little more.
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by barthess »

Strange issue.
matis wrote:After that the whole MCU freezes and I get "Warn : Timeout (1000ms) waiting for ACK=OK/FAULT in JTAG-DP transaction" in my GDB

I have observed such behavior in two cases: when mcu putted to deep sleep state and when I manually disable mcu's jtag pins.
matis wrote:My bad, I tried to flash the .elf file instead of the .bin file.

Are absolutely sure that you flash correct bin files in correct offsets? Previously, when I played with my bootloader the OpenOCD written wrong bin file because it was started from bootloader directory. In my case I must restart OpenOCD in my main application directory after flashing bootloader from bootloder directory.
matis wrote:The i2cAcquireBus function seems to be successful. After that the whole MCU freezes

Can you dig with you JTAG as deep as possible to catch what function called just before JTAG turns unusable?
matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

barthess wrote:Strange issue.

Agreed ;)
I have observed such behavior in two cases: when mcu putted to deep sleep state and when I manually disable mcu's jtag pins.
That seems to be right, while chSysDisable() disables all ports.
Are absolutely sure that you flash correct bin files in correct offsets? Previously, when I played with my bootloader the OpenOCD written wrong bin file because it was started from bootloader directory. In my case I must restart OpenOCD in my main application directory after flashing bootloader from bootloder directory.

Yes I'm quite sure :)
My gdb commands looks like this:
monitor soft_reset_halt
monitor wait_halt
monitor poll
monitor flash probe 0
monitor stm32x mass_erase 0
monitor flash write_bank 0 /home/chibios/sandbox/boot_app/prj/build/ch.bin 0
monitor flash write_bank 0 /home/chibios/sandbox/user_app/prj/build/ch.bin 0x40000
monitor soft_reset_halt
thbreak main
continue

What I do is the following. I use the commands above to flash the STM. After that, I halt the CPU, switch to my user_app project, place a breakpoint at the main function and restart the STM. It starts the boot_app and when I trigger a function within the boot_app, the jump_to_application function is called, at that point my debugger breaks on the user_app main function. When I start stepping, I at randomly lines get unhandled exceptions. The good news is, that the fix below, makes the unhandled exception function be run in user_app stack and not from the boot_app stack as it was in the first posts.

My problem seems to have much similarities with this topic: viewtopic.php?f=2&t=229
What I also changed (after reading the topic stated above) was the CORTEX_VTOR_INIT for the user_app from 0x00000000 to 0x00040000. But that doesn't seems to change anything. Except the unhandled exeption function as said before.
Can you dig with you JTAG as deep as possible to catch what function called just before JTAG turns unusable?

I'm gonna give that a try :)
matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

I think I found where it might go wrong.

When I leave the boot_app I disable all ports.
In the user_app main, just after enabling the HAL (and thus ports including interrupts), I get interrupts from USART1_IRQHandler before I even started the UART1 in user_app. I think that the boot_app interrupt vector is used in the user_app.
Is there a way to check?
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by barthess »

matis wrote: I get interrupts from USART1_IRQHandler before I even started the UART1 in user_app

I would try to manually disable interrupts from all peripherals and than clear all interrupts flags before jumping to user app.
matis wrote:I think that the boot_app interrupt vector is used in the user_app.

This things is out of my understanding area.
matis
Posts: 53
Joined: Fri Jul 01, 2011 1:46 pm

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by matis »

barthess wrote:
matis wrote: I get interrupts from USART1_IRQHandler before I even started the UART1 in user_app

I would try to manually disable interrupts from all peripherals and than clear all interrupts flags before jumping to user app.

That seems to fix the problem sofar when jumping from ChibiOS to ChibiOS. Unfortunatly I can't define the CORTEX_VTOR_INIT any other than in the chcore_v7m.h
User avatar
barthess
Posts: 861
Joined: Wed Dec 08, 2010 7:55 pm
Been thanked: 7 times

Re: Bare metal I2C breaks ChibiOS i2cMasterTransmit

Post by barthess »

matis wrote:Unfortunatly I can't define the CORTEX_VTOR_INIT any other than in the chcore_v7m.h

define it in chconf.h. Works in my case.
Post Reply