Skip to content

fix #3863 Add an mbed API that allows the init of the CAN at the bus frequency #4165

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

Merged
merged 12 commits into from
May 26, 2017

Conversation

adustm
Copy link
Member

@adustm adustm commented Apr 11, 2017

Description

If the bus is using a much higher frequency than the default value chosen in the init function, the device cannot synchronize and is blocked (see #3863 for details). The device needs an IDLE frame on the CAN bus to synchronize, but if the device is not set with the correct frequency, the IDLE frame may never be detected.
for instance: initialize CAN at 100kbps. It needs an idle frame on the CAN bus to synchronize (ie: 110us to have 11 consecutive recessive bits). If the bus is at 500kbs and highly busy due to another device, 110us of consecutive recessive bits does not occur. I have only 58us in my use case.
Adding the frequency parameter to the CAN class (same as done in serial api for baud rates) allows us to initialize and synchronize the CAN device even if the bus is often busy.

Status

READY

Steps to test or reproduce

Have a 1st device with high bus occupation with the following code:

#include "mbed.h"
DigitalOut led2(LED2);
Serial pc(USBTX,USBRX);

int main()
{
    int mycnt=0;
    pc.baud(115200);
    pc.printf("main()\r\n");
    CAN can1(PA_11, PA_12); // only for NUCLEO_F446RE
    pc.printf("created can\r\n");
    can1.frequency(500000);
    pc.printf("set frequency \r\n");

    unsigned int id = 0x539;
    char i =0xC7;
    CANMessage tx_msg(id, &i, sizeof(i));
    bool sent = false;

    while(1) {
        if (can1.write(tx_msg)) {
            mycnt++;
            printf("Sent %u: %d\n", id, i);
            sent = true;
        }
        wait_ms(10);
        led2 = !led2;
    }
}

Have the current device trying to initialize. Without the PR, NUCLEO_F767ZI cannot exit from the init function (because HW cannot syncrhonize). With the PR, it can synchronize if the init function is modifying the frequency (we can see the printf "created can") with the following code:

#include "mbed.h"
DigitalOut led2(LED2);
Serial pc(USBTX,USBRX);

int main()
{
    pc.baud(115200);
    pc.printf("main()\r\n");
    CAN can2(PD_0, PD_1); //without the PR
    CAN can2(PD_0, PD_1, 500000); //with the PR
    pc.printf("created can\r\n");
    can2_ptr = &can2;
    //can2.frequency(500000); // without the PR
    pc.printf("set frequency \r\n");
    CANMessage msg;

    while(1) {
        if(can2.read(msg)) {
            pc.printf("<-*******Message received:id=%x,data=",msg.id);
            for(int i=0; i<8; i++) {
                pc.printf("%x,",msg.data[i] );
            }
            pc.printf("\n\r");
            led2 = !led2;
        }
    }
}

cc @bperry730 @ohagendorf

@tommikas
Copy link
Contributor

Getting a linking error when building with armcc at least for NUMAKER_PFM_NUC472 and UBLOX_EVK_ODIN_W2 targets.

Error: L6218E: Undefined symbol can_init_freq (referred from CAN.o).
Finished: 0 information, 0 warning and 1 error messages.

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 12, 2017

Thanks @tommikas .

@adustm Adding new HAL function introduces a requirement for all targets that support CAN to have this function implemented. Therefore to make this addition, we should implement it for all targets that support CAN. There are not that many. We can create a devel branch here for this.

@ohagendorf
Copy link
Contributor

Unfortunately, I think the solution will not solve the problem in every case.

We found the problem the first time in a test application, one sending mcu and one receiving mcu. Each second a single CAN message was send with a CAN bus frequency of 1MHz. We just call the constructor without a following call of can.frequency so the default 1MHz were used. From time to time the receiving mcu didn’t start – it stopped in the constructor in can_init during the execution of can_frequency(obj, 100000) in the second while ((can->MSR & CAN_MSR_INAK) == CAN_MSR_INAK).
The suggested PR will not solve this problem, I think.

The other application was an automotive RADAR sensor connected over CAN with an STM Nucleo. The sensor starts with an init message with a maximal message rate until it gets its config from another CAN node. In this scenario the bus will never be idle long enough to set the frequency to the requested 500kHz.

The same functionality realised only with Cube HAL function works without problems since a couple of days. We just used a CAN example from an eval board from the Cube library and adapted it to our hardware.

@adustm
Copy link
Member Author

adustm commented Apr 13, 2017

Thanks @0xc0170 and @tommikas for your comments. I agree for the separate development branch if needed. At the moment, it seems we still have another issue. I will need to fix it before we go for the devel branch.

Hello @ohagendorf

The same functionality realised only with Cube HAL function works without problems since a couple of days. We just used a CAN example from an eval board from the Cube library and adapted it to our hardware.

Did you have a chance to check the differences between mbed and Cube settings wrt CAN HW registers or clocks or RCC registers ?

@ohagendorf
Copy link
Contributor

Hello @adustm
I have the time (and the plan) to do that during the next days. I have both projects are available.

@adustm
Copy link
Member Author

adustm commented Apr 13, 2017

Hi @ohagendorf
Could you provide me the values that you write within your Cube sw in

    CanHandle.Init.SJW = ;
    CanHandle.Init.BS1 = ;
    CanHandle.Init.BS2 = ;
    CanHandle.Init.Prescaler = ;

I've seen differences between Cube code and mbed-os code: the above parameters + a timeout exit.
Is it possible that you comment this timeout and check if it still works (or check if the Init function runs out with the HAL_TIMEOUT error ?) ?

Could you also provide me with the rate of the CANbus at boot time ?

Kind regards

@theotherjimmy
Copy link
Contributor

bump @adustm @ohagendorf What's the status on this?

@adustm
Copy link
Member Author

adustm commented Apr 24, 2017

Hello @theotherjimmy
I've been confirmed that we need to be able to initialize the CAN at the can bus frequency.
The new interface is mandatory. I am working on adding it on every CAN devices of mbed-os.

I don't have any news on the fact that it does not solve the issue from @ohagendorf but I am thinking about handling this in a separate PR (at least by detecting a timeout and by sending an error code)
Cheers

@adustm
Copy link
Member Author

adustm commented Apr 24, 2017

Hello, I think I've added every can_init_freq for every CAN platforms.
I've compiled every boards with GCC_ARM
I've linked every mbed-5 boards with GCC_ARM and the following mail.cpp.
I hope it fits the need.

#include "mbed.h"

Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN* can2_ptr;//(PD_0, PD_1);

Serial pc(USBTX,USBRX);

int main()
{
    pc.printf("main()\r\n");
  #if defined(TARGET_LPC1549)
  // LPC1549 support only single CAN channel
  CAN can2(D2, D3, 500000);
  #elif defined(TARGET_B96B_F446VE)
  // B96B_F446VE support only single CAN channel
  CAN can2(PD_0, PD_1, 500000);
  #elif defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F072RB) || \
        defined(TARGET_NUCLEO_F042K6) || defined(TARGET_NUCLEO_F334R8) || \
        defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F303K8) || \
        defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_F446RE) || \
        defined(TARGET_DISCO_F429ZI)  || defined(TARGET_NUCLEO_F103RB) || \
        defined(TARGET_NUCLEO_F746ZG) || defined(TARGET_NUCLEO_L476RG) || \
        defined(TARGET_NUCLEO_F412ZG) || \
        defined(TARGET_NUCLEO_L432KC) || defined(TARGET_DISCO_F303VC)
  CAN can2(PA_11, PA_12, 500000);
  #elif defined(TARGET_DISCO_F469NI) ||defined(TARGET_DISCO_F746NG) || \
        defined(TARGET_NUCLEO_F207ZG)
  CAN can2(PB_8, PB_9, 500000);
  #elif defined(TARGET_NUMAKER_PFM_NUC472)
  CAN can2(PA_0, PA_1, 500000);
  #elif defined(TARGET_NUMAKER_PFM_M453)
  CAN can2(PA_13, PA_12, 500000);
  #elif defined(TARGET_UBLOX_C027)
  CAN can2(CANRD, CANTD, 500000);
  #elif defined(TARGET_RZ_A1H) || defined(TARGET_VK_RZ_A1H)
  CAN can2(P7_8, P7_9, 500000);
  #else
  CAN can2(p9, p10, 500000);
  #endif
    pc.printf("created can\r\n");
    can2_ptr = &can2;
    CANMessage msg;

    while(1) {
        if(can2.read(msg)) {
            pc.printf("<-*******Message received:id=%x,data=",msg.id);
            for(int i=0; i<8; i++) {
                pc.printf("%x,",msg.data[i] );
            }
            pc.printf("\n\r");
            led2 = !led2;
        }
    }
}

Kind regards
Armelle

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 25, 2017

@cyliangtw @TomoYamanaka @mmahadevan108 please review, as this PR touches your platforms as well. What do you think about CAN init freq proposal?

@cyliangtw
Copy link
Contributor

This PR is fine to our platforms, it could support backward compatibility.

Copy link
Contributor

@TomoYamanaka TomoYamanaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your changing.

In TARGET_RZ_A1H and TARGET_VK_RZ_A1H.
if you keep this change, f of CAN::CAN(PinName rd, PinName td, int f) will not be referenced anywhere.
Therefore, please let me suggest to add two changinges.

First changing:
I would like to add can_frequency(obj, hz); in the below.
https://github.com/ARMmbed/mbed-os/pull/4165/files#diff-d349510c34424b620ac131c682689558L576
https://github.com/ARMmbed/mbed-os/pull/4165/files#diff-cab74c93ed52cd8f693385e5f4885084L593

Second changing:
I would like to change can_init_freq(obj, rd, td, 0); to can_init_freq(obj, rd, td, 100000); in the below.
https://github.com/ARMmbed/mbed-os/pull/4165/files#diff-d349510c34424b620ac131c682689558R579
https://github.com/ARMmbed/mbed-os/pull/4165/files#diff-cab74c93ed52cd8f693385e5f4885084R596

@mmahadevan108
Copy link
Contributor

please update can_api.c file in TARGET_LPC408X/TARGET_LPC4088_DM

@adustm
Copy link
Member Author

adustm commented Apr 27, 2017

Thank you all for your remarks

@TomoYamanaka san,
I have added can_frequency in the can_init_freq function. Please be aware that I cannot test this modification (I don't have a platform )

Hello @mmahadevan108
I have added the modification in LPC4088_DM can_api.c

and I have rebased the pull request

Kind regards
Armelle

@mmahadevan108
Copy link
Contributor

@adustm. Thank you, changes look fine to me.

@adustm adustm changed the title fix #3862 Add an mbed API that allows the init of the CAN at the bus frequency fix #3863 Add an mbed API that allows the init of the CAN at the bus frequency Apr 27, 2017
@adustm
Copy link
Member Author

adustm commented Apr 28, 2017

Hi @0xc0170
Could I have details about the Cam CI uvisor Build & Test failures, please ?

@adbridge
Copy link
Contributor

adbridge commented May 2, 2017

restart uvisor

@screamerbg
Copy link
Contributor

@0xc0170 @adbridge Can we retest this or provide info on what's failing?

@adbridge
Copy link
Contributor

adbridge commented May 4, 2017

It's failing due to periodic issues with the Uvisor CI and the parallel threads that the compiler uses leaking data. I will restart it again!

@adbridge
Copy link
Contributor

adbridge commented May 4, 2017

retest uvisor

@adbridge
Copy link
Contributor

adbridge commented May 4, 2017

@TomoYamanaka @cyliangtw Could you please confirm you are also happy with the updates and sign off the review so that we can get this merged in ? Thanks

@cyliangtw
Copy link
Contributor

Thanks of this modification. The change is fine to me after review code.

@adbridge
Copy link
Contributor

/morph test-nightly

@adbridge
Copy link
Contributor

retest uvisor

@mbed-bot
Copy link

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test-nightly

Output

mbed Build Number: 250

Test failed!

@0xc0170
Copy link
Contributor

0xc0170 commented May 18, 2017

/morph test-nightly

@0xc0170
Copy link
Contributor

0xc0170 commented May 18, 2017

retest uvisor

@adbridge
Copy link
Contributor

/morph test-nightly

@adbridge
Copy link
Contributor

retest uvisor

@mbed-bot
Copy link

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test-nightly

Output

mbed Build Number: 296

Test failed!

@bridadan
Copy link
Contributor

We had a K64F that was behind on firmware updates and was showing failures. It has been updated now.

/morph test-nightly

@mbed-bot
Copy link

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test-nightly

Output

mbed Build Number: 311

Test failed!

@adustm
Copy link
Member Author

adustm commented May 23, 2017

Hello @bridadan @adbridge , the K64F is in TIMEOUT-ERROR.
I just tested an extract of it myself and here is the result:

+--------------+---------------+----------------------------------+--------+--------------------+-------------+
| target       | platform_name | test suite                       | result | elapsed_time (sec) | copy_method |
+--------------+---------------+----------------------------------+--------+--------------------+-------------+
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | OK     | 18.3               | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-dev_null      | OK     | 20.76              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-echo          | OK     | 29.66              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-flashiap      | OK     | 16.7               | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-generic_tests | OK     | 18.36              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | OK     | 25.67              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-rtc           | OK     | 28.12              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-stl_features  | OK     | 18.61              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-ticker        | OK     | 49.93              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-timeout       | OK     | 27.49              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-wait_us       | OK     | 27.48              | shell       |
+--------------+---------------+----------------------------------+--------+--------------------+-------------+
mbedgt: test suite results: 11 OK
mbedgt: test case report:
+--------------+---------------+----------------------------------+-------------------------------------+--------+--------+--------+--------------------+
| target       | platform_name | test suite                       | test case                           | passed | failed | result | elapsed_time (sec) |
+--------------+---------------+----------------------------------+-------------------------------------+--------+--------+--------+--------------------+
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %e %E float formatting   | 1      | 0      | OK     | 0.06               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %f %f float formatting   | 1      | 0      | OK     | 0.06               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %g %g float formatting   | 1      | 0      | OK     | 0.06               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %i %d integer formatting | 1      | 0      | OK     | 0.07               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %u %d integer formatting | 1      | 0      | OK     | 0.07               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: %x %E integer formatting | 1      | 0      | OK     | 0.06               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: strpbrk                  | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-c_strings     | C strings: strtok                   | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-dev_null      | tests-mbed_drivers-dev_null         | 1      | 0      | OK     | 20.76              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-echo          | Echo server: x16                    | 1      | 0      | OK     | 1.99               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-echo          | Echo server: x32                    | 1      | 0      | OK     | 3.84               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-echo          | Echo server: x64                    | 1      | 0      | OK     | 7.58               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-flashiap      | FlashIAP - init                     | 1      | 0      | OK     | 0.04               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-flashiap      | FlashIAP - program                  | 1      | 0      | OK     | 0.1                |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-flashiap      | FlashIAP - program errors           | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-generic_tests | Basic                               | 1      | 0      | OK     | 0.03               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-generic_tests | Blinky                              | 1      | 0      | OK     | 0.03               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-generic_tests | C++ heap                            | 1      | 0      | OK     | 0.09               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-generic_tests | C++ stack                           | 1      | 0      | OK     | 0.15               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 1ms LowPowerTimeout                 | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 1sec LowPowerTimeout                | 1      | 0      | OK     | 1.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 1sec LowPowerTimeout from deepsleep | 1      | 0      | OK     | 1.08               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 1sec LowPowerTimeout from sleep     | 1      | 0      | OK     | 1.06               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 500us LowPowerTimeout               | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-lp_timeout    | 5sec LowPowerTimeout                | 1      | 0      | OK     | 5.04               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-rtc           | RTC strftime                        | 1      | 0      | OK     | 10.53              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-stl_features  | STL std::equal                      | 1      | 0      | OK     | 0.04               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-stl_features  | STL std::sort abs                   | 1      | 0      | OK     | 0.04               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-stl_features  | STL std::sort greater               | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-stl_features  | STL std::transform                  | 1      | 0      | OK     | 0.05               |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-ticker        | Timers: 1x ticker                   | 1      | 0      | OK     | 11.07              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-ticker        | Timers: 2x callbacks                | 1      | 0      | OK     | 11.06              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-ticker        | Timers: 2x tickers                  | 1      | 0      | OK     | 11.06              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-timeout       | Timers: toggle on/off               | 1      | 0      | OK     | 11.07              |
| K64F-GCC_ARM | K64F          | tests-mbed_drivers-wait_us       | Timers: wait_us                     | 1      | 0      | OK     | 11.17              |
+--------------+---------------+----------------------------------+-------------------------------------+--------+--------+--------+--------------------+
mbedgt: test case results: 35 OK

I guess there is an issue in your testbench somewhere. Could you try and solve it, please ?

@adbridge
Copy link
Contributor

/morph test-nightly

@adbridge
Copy link
Contributor

retest uvisor

@adbridge
Copy link
Contributor

@adustm I've restarted the jobs, if they fail again we may have a broken device in the CI @studavekar

@mbed-bot
Copy link

Result: ABORTED

Your command has finished executing! Here's what you wrote!

/morph test-nightly

Output

mbed Build Number: 317

Test failed!

@studavekar
Copy link
Contributor

Apologies have aborted few of the jobs which failed and on one of device. CI seems to unstable now with the devices.

Will re-trigger the tests after checking few jobs.

@studavekar
Copy link
Contributor

/morph test-nightly

@mbed-bot
Copy link

Result: SUCCESS

Your command has finished executing! Here's what you wrote!

/morph test-nightly

Output

mbed Build Number: 326

All builds and test passed!

@sg-
Copy link
Contributor

sg- commented May 26, 2017

@Looks good although the can_init looks useless at this point so should be considered for deprecation. Second note is that HAL setting the default frequency seems wrong, although was the way it was apparently. Shall we remove can_init in another PR and use the constructor to set a default frequency across all CAN object using CAN::CAN(PinName rd, PinName td)

@sg- sg- merged commit d11289b into ARMmbed:master May 26, 2017
@adustm adustm deleted the can_init branch May 29, 2017 08:32
@adustm
Copy link
Member Author

adustm commented May 29, 2017

Shall we remove can_init in another PR and use the constructor to set a default frequency across all CAN object using CAN::CAN(PinName rd, PinName td)

@sg- for sure the old can_init is not usefull anymore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.