CAN 1 RX работает в режиме обратной связи, но не в нормальном режиме.

Я использую пользовательскую плату на базе STM32F413RG и пытаюсь запустить на ней некоторые приложения на основе шины CAN.

Я пытаюсь начать с CAN 1 и написал чистый металлический код, используя библиотеку CMSIS для передачи и приема.

Вот код для трех функций - Init, Send и Receive.

void initCAN()
{

    // enable clock
    // note: because CAN2 is a "slave CAN" you have to enable CAN1 clock
    RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
    // and reset CAN1, so request reset
    CAN1->MCR |= CAN_MCR_RESET;
    // wait for it to say it has gone to sleep
    while ((CAN1->MSR & CAN_MSR_SLAK_Msk) == 1) {}

    //CAN1
    // enable port A clock
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;

    __DSB();

    // CAN_RX = CAN1R on PA11, so set alt function
    GPIOA->MODER &= ~GPIO_MODER_MODER11_Msk;
    GPIOA->MODER |= GPIO_MODER_MODER11_1;
    // CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
    GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL11_3 | GPIO_AFRH_AFSEL11_0);
    // CAN_TX = CAN1T on PA12
    GPIOA->MODER &= ~GPIO_MODER_MODER12_Msk;
    GPIOA->MODER |= GPIO_MODER_MODER12_1;
    // open-drain
    GPIOA->OTYPER |= GPIO_OTYPER_OT_11;
    GPIOA->OTYPER |= GPIO_OTYPER_OT_12;
    // CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
    GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL12_3 | GPIO_AFRH_AFSEL12_0);

    //bring it our from sleep by setting the sleep bit in MCR to 0
    CAN1->MCR &= ~CAN_MCR_SLEEP_Msk;

    //if sleep ACK(SLAK) not zero, wait i.e. exited from sleep
    while ((CAN1->MSR & CAN_MSR_SLAK_Msk) != 0) {}

    //put CAN 1 to Init mode
    CAN1->MCR |= CAN_MCR_INRQ;

    // wait for it to say it has gone there
    while ((CAN1->MSR & CAN_MSR_INAK_Msk) != CAN_MSR_INAK_Msk) {}


    uint32_t APB1Clock = SystemCoreClock/2000000; // in MHz


    CAN1->BTR = 0x00050007U;

    CAN1->FMR |= CAN_FMR_FINIT;

    // and make sure the CANSB value is zero
    CAN1->FMR &= ~(CAN_FMR_CAN2SB_Msk);

   //Give 14 filter banks to CAN 1 and 2 each
    CAN1->FMR |= (((uint32_t) 14) << CAN_FMR_CAN2SB_Pos) & CAN_FMR_CAN2SB_Msk;

   // set all as 32 bit filter in identifier mask mode (zeros)
    CAN1->FM1R = 0;

   // use all as 32 bit filter with mask
    CAN1->FS1R |= CAN_FS1R_FSC_Msk;

  // assign FIFO0 to CAN1, and FIFO1 to CAN2 (well, all to FIFO0, except filter 14)
    CAN1->FFA1R = CAN_FFA1R_FFA14;


   // make sure it is deactivated (clear FACT in CAN_FAR)
   CAN1->FA1R &= ~CAN_FA1R_FACT0;
   CAN1 ->FA1R &= ~CAN_FA1R_FACT14;

  // setup a filter that accepts everything (w/ extended id)
  // Each filter bank i (i= 0 to 27 in dual CAN configuration and i= 0 to 13 in single CAN configuration)
  //is composed of two 32-bit registers, CAN_FiR\[2:1\].

  CAN1->sFilterRegister[0].FR1 = CAN_F0R1_FB2;
  CAN1->sFilterRegister[0].FR2 = CAN_F0R1_FB2;
  CAN1->sFilterRegister[14].FR1 = CAN_F0R1_FB2;
  CAN1->sFilterRegister[14].FR2 = CAN_F0R1_FB2;

  // now activate filter
  CAN1->FA1R |= CAN_FA1R_FACT0;
  CAN1->FA1R |= CAN_FA1R_FACT14;

  // take out of init mode for filters
  CAN1->FMR &= ~CAN_FMR_FINIT;

  //loopback mode. need to do it while on init mode
  // CAN1->BTR |= CAN_BTR_LBKM;

 //bring CAN1 out from init mode.
  CAN1->MCR &= ~CAN_MCR_INRQ;

 while ((CAN1->MSR & CAN_MSR_INAK_Msk) != 0) {}

 }

void sendCAN1( uint32_t pgn, uint8_t bytes[], uint8_t len)
{

    // wait for the mailbox to be empty
    while ((CAN1->TSR & CAN_TSR_TME0_Msk) == 0) {};

    // put this in next empty mailbox
    int boxnum = (CAN1->TSR & CAN_TSR_CODE_Msk) >> CAN_TSR_CODE_Pos;

    CAN1->sTxMailBox[boxnum].TDTR &= ~CAN_TDT0R_DLC_Msk;
    CAN1->sTxMailBox[0].TIR = ((pgn << CAN_TI0R_EXID_Pos) & CAN_TI0R_EXID_Msk) | CAN_TI0R_IDE;

    // for standard (11-bit) ids, replace the above with:
    // CAN1->sTxMailBox[boxnum].TIR = ((pgn << CAN_TI0R_STID_Pos) & CAN_TI0R_STID_Msk);

    CAN1->sTxMailBox[boxnum].TDHR = ((bytes[7]<<CAN_TDH0R_DATA7_Pos) |
                                (bytes[6]<<CAN_TDH0R_DATA6_Pos) |
                                (bytes[5]<<CAN_TDH0R_DATA5_Pos) | bytes[4]);

    CAN1->sTxMailBox[boxnum].TDLR = ((bytes[3]<<CAN_TDL0R_DATA3_Pos) |
                                (bytes[2]<<CAN_TDL0R_DATA2_Pos) |
                                (bytes[1]<<CAN_TDL0R_DATA1_Pos) | bytes[0]);

    CAN1->sTxMailBox[boxnum].TDTR = (len << CAN_TDT0R_DLC_Pos) & CAN_TDT0R_DLC_Msk;
    CAN1->sTxMailBox[boxnum].TIR |= CAN_TI0R_TXRQ;

}

uint8_t recCAN1()
{
    uint8_t data[8];
    uint32_t pgn;
    uint8_t len;
    uint8_t msgcount;
    static uint8_t ret = 0;

    // check for any msg in FIFO
    // we only use FIFO 0 here
    msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
    ret += msgcount;
    // read them out one at a time
    while (msgcount > 0)
    {
        pgn = CAN1->sFIFOMailBox[0].RIR >> 3;
        len = CAN1->sFIFOMailBox[0].RDTR & 0xF;
        // NOTE: case fall through is intentional and critical
        switch (len)
        {
        case 8:
            data[7] = (CAN1->sFIFOMailBox[0].RDHR >> 24) & 0xFF;
        case 7:
            data[6] = (CAN1->sFIFOMailBox[0].RDHR >> 16) & 0xFF;
        case 6:
            data[5] = (CAN1->sFIFOMailBox[0].RDHR >> 8) & 0xFF;
        case 5:
            data[4] = CAN1->sFIFOMailBox[0].RDHR & 0xFF;
        case 4:
            data[3] = (CAN1->sFIFOMailBox[0].RDLR >> 24) & 0xFF;
        case 3:
            data[2] = (CAN1->sFIFOMailBox[0].RDLR >> 16) & 0xFF;
        case 2:
            data[1] = (CAN1->sFIFOMailBox[0].RDLR >> 8) & 0xFF;
        case 1:
            data[0] = CAN1->sFIFOMailBox[0].RDLR & 0xFF;
            // do nothing as data is empty
        }
        // process as they are read
       // processCAN(pgn, data, len);

        // release that mailbox
        CAN1->RF0R |= CAN_RF0R_RFOM0;

        // update the message count
        msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
    }
    return ret;
}

Отправка пакета из CAN 1 в порядке. При получении я не вижу изменения статуса в регистрах Rx. Но я вижу, что ACK передается с вывода TX при получении пакета при анализе сигналов.

Статус ошибки CAN 1 полностью пуст (0x0).

Однако, когда я пробую тот же код с активированным режимом Loopback, я вижу сообщение, полученное в регистрах, и мой код тоже его подхватывает.

Прикрепляю скриншоты регистра CAN 1 RF0R в режиме обратной связи, что указывает на прием. Регистры CAN 1, показывающие прием сообщений в режиме обратной связи

Эта область (канал 0 для RX и канал 2 для TX) показывает, что он получает сообщение на RX и отправляет обратно ACK на свой TX в обычном режиме. CAN 1 Rx и Tx в обычном режиме

Я тоже проверил прекращение, и все в порядке. (Добавлено 120 Ом. Во всяком случае, получение ACK, поэтому я думаю, что это не проблема).

У меня нет идей о том, где я могу ошибаться. Нет явных сообщений об ошибках. Однако сообщение Rx не отражается ни в одном из регистров в обычном режиме.


person Shankar S    schedule 15.07.2019    source источник
comment
Пожалуйста, отформатируйте свой код, чтобы он имел правильные отступы и удалил все символы \, чтобы мы могли его прочитать и протестировать.   -  person Benoît    schedule 16.07.2019
comment
@ Бенуа, я отредактировал код. Должны быть лучше.   -  person Shankar S    schedule 16.07.2019
comment
Последняя опечатка CAN1 ->FA1R &= ~CAN_FA1R_FACT14;   -  person Benoît    schedule 16.07.2019
comment
Из справочного руководства в регистре CAN_FMR: to use CAN1 only: stop the clock on CAN2 and/or set the CAN_MCR.INRQ on CAN2 я не видел инструкции, которая делает это явно в вашем коде. Также в комментариях к вашему коду говорится, что вы ничего не фильтруете, но вы устанавливаете CAN_F0R1_FB2 в sFilterRegister, поэтому не все будет принято. Возможно, идентификатор, который вы отправляете, является одним из них.   -  person Benoît    schedule 16.07.2019
comment
Ага. Вот оно. Фильтр устанавливает только прием сообщений с расширенным идентификатором, в то время как я тестировал стандартный идентификатор.   -  person Shankar S    schedule 17.07.2019
comment
Меня отвлек тот факт, что я видел сообщения с тем же фильтром на петле, но не в обычном режиме, чего, я думаю, не должно было быть. В техническом описании говорится, что bxCAN обрабатывает свои собственные переданные сообщения как полученные сообщения и сохраняет их (если они проходят приемную фильтрацию) в почтовом ящике получения. что сейчас выглядит обманчиво.   -  person Shankar S    schedule 17.07.2019
comment
Классическая ошибка при выходе из петли заключается в том, что ваш узел должен иметь какой-то другой узел для связи — кто-то должен подтверждать сообщения, иначе вы быстро перейдете к ошибкам. Для этой цели можно использовать прослушиватели CAN (программа для ПК + адаптер CAN-to-USB), они понадобятся вам, если вы хотите работать с CAN.   -  person Lundin    schedule 19.07.2019
comment
Ты прав. Я действительно использую программу просмотра Pcan с адаптером Systec USB-CAN. Я передал сообщение от него. Но здесь я тестировал только такой, чтобы он всегда оставался в петле или в обычном режиме.   -  person Shankar S    schedule 20.07.2019


Ответы (1)


Из справочного руководства в регистре CAN_FMR: to use CAN1 only: stop the clock on CAN2 and/or set the CAN_MCR.INRQ on CAN2 я не видел инструкции, которая делает это явно в вашем коде.

Также в комментариях к вашему коду говорится, что вы ничего не фильтруете, но устанавливаете CAN_F0R1_FB2 в sFilterRegister, поэтому не все будет принято. Идентификатор, который вы отправляете, является одним из них.

person Benoît    schedule 17.07.2019