0
\$\begingroup\$

Since I am rather new to using CAN I'm not sure what information that is relevant but I will try and describe the best I can.

I have a STMF746 that I want to use the CAN bus on. I have PD0(CAN1_Rx), PD1(CAN1_Tx) and PG0(standby driven low) hooked up to a CAN tranceiver.

I should perhaps also mention that I'm using HAL drivers.

My init settings are

hw_return_type can_Open(void)
{
    __HAL_RCC_CAN1_CLK_ENABLE();
    hcan.Instance = CAN1;
    hcan.Init.Mode = CAN_MODE_NORMAL;

    //Should be 125kbit with 75% sampling 
    hcan.Init.Prescaler = 27;
    hcan.Init.BS1 = CAN_BS1_11TQ;
    hcan.Init.BS2 = CAN_BS2_4TQ;
    hcan.Init.SJW = CAN_SJW_2TQ;
    hcan.Init.TTCM = DISABLE;
    hcan.Init.ABOM = ENABLE;
    hcan.Init.AWUM = DISABLE;
    hcan.Init.NART = DISABLE;
    hcan.Init.RFLM = DISABLE;
    hcan.Init.TXFP = DISABLE;
    HAL_CAN_Init(&hcan);

    (&hcan)->Instance->MCR |= CAN_MCR_TXFP;

    rxMsg.FIFONumber = CAN_FIFO0;
    rxMsg.IDE = CAN_ID_STD;

    rxMsg.RTR = CAN_RTR_DATA;
    rxMsg.FMI = 0;
    hcan.pRxMsg = &rxMsg;

    can_SetFilter(0, 0, 0);

    can_recv_fifo = utilFIFO_Create(can_recv_fifo_buf, sizeof(hw_can_msg_type), CAN_FIFO_LENGTH);

    return HW_OK;
}


void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    if(hcan->Instance==CAN1)
    {
        __CAN_CLK_ENABLE();
        __GPIOD_CLK_ENABLE();

        GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        HAL_NVIC_SetPriority(CAN1_TX_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);

        HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);

        HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
    }
}

static void SystemClock_Config(void)
{

    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInit;

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 12;
    RCC_OscInitStruct.PLL.PLLN = 432;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 2;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    HAL_PWREx_ActivateOverDrive();

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV4;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
    PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

}

By using some debugcode I have found that when I try to continously send data all 3 mailboxes are filled and the function

static HAL_StatusTypeDef HAL_CAN_Transmit_IT_local(CAN_HandleTypeDef* hcan)
{
    uint32_t transmitmailbox = CAN_TXSTATUS_NOMAILBOX;

    /* Check the parameters */
    assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
    assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
    assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));

    /* Process Locked */
    __HAL_LOCK(hcan);

    /* Select one empty transmit mailbox */
    if((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
    {
        transmitmailbox = 0;
    }
    else if((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
    {
        transmitmailbox = 1;
    }
    else if((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)
    {
        transmitmailbox = 2;
    }

    if(transmitmailbox != CAN_TXSTATUS_NOMAILBOX)
    {
      /* Set up the Id */
      hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
      if(hcan->pTxMsg->IDE == CAN_ID_STD)
      {
          assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));
          hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21) | \
                                                  hcan->pTxMsg->RTR);
      }
      else
      {
          assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
          hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3) | \
                                                  hcan->pTxMsg->IDE | \
                                                  hcan->pTxMsg->RTR);
      }

      /* Set up the DLC */
      hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
      hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
      hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;

      /* Set up the data field */
      hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3] << 24) |
                                             ((uint32_t)hcan->pTxMsg->Data[2] << 16) |
                                             ((uint32_t)hcan->pTxMsg->Data[1] << 8) |
                                             ((uint32_t)hcan->pTxMsg->Data[0]));
      hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7] << 24) |
                                             ((uint32_t)hcan->pTxMsg->Data[6] << 16) |
                                             ((uint32_t)hcan->pTxMsg->Data[5] << 8) |
                                             ((uint32_t)hcan->pTxMsg->Data[4]));


      /* Set CAN error code to none */
      hcan->ErrorCode = HAL_CAN_ERROR_NONE;

      /* Process Unlocked */
      __HAL_UNLOCK(hcan);

      /* Enable Transmit mailbox empty Interrupt */
      __HAL_CAN_ENABLE_IT(hcan, CAN_IT_TME);

      /* Request transmission */
      hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;
    }
    else
    {
        /* Process Unlocked */
        __HAL_UNLOCK(hcan);
        return HAL_BUSY;
    }

  return HAL_OK;
}

returns HW_OK the first 3 times(3 mailboxes filled). After that I only get HW_BUSY which to me indicates that the mailboxes does not get emptied correctly. And here is where I'm stuck. Being rather new to how CAN works I have no idea where I should look anymore.

When I look with a CAN analyzer on the bus, all I can see are error frames which to me means literally nothing as I havent found any good reference to what kind of errors that triggers an error frame.

My theories are that perhaps the transmit status register

__IO uint32_t              TSR;                 /*!< CAN transmit status register,        Address offset: 0x08          */

does not reset properly. Or that it does not clear it until it has received an Ack from the other node on the bus.

If anyone has any good ideas of what I have done wrong or what I'm missing. I'd really appricate your help.

Feel free to ask questions or ask for more code

\$\endgroup\$

migrated from stackoverflow.com Dec 10 '16 at 0:08

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ Is there another CAN node on the bus? Is the CAN analyser set to ack the messages or is it set to be a passive listener? \$\endgroup\$ – Lundin Dec 8 '16 at 14:10
  • \$\begingroup\$ I have tried both modes. I am currently using the Ack setting so the analyzer should Ack. I have tried connecting a different CAN device and it works fine. But the analyzer is the only thing connected so no other nodes on the bus \$\endgroup\$ – user3660570 Dec 8 '16 at 14:17
  • 1
    \$\begingroup\$ My point is: you always need to have at least one other node on the bus to ack the frames you send, or otherwise your CAN controller will get sad (after failing 127 times) and revert to an error state. All CAN controllers work this way, they must always have someone to talk with, since a bus with just one node doesn't make any sense. To avoid this issue during development with no hardware available, you usually use a "loopback" feature of the controller, to have it "speak with itself". But since you seem to already have the hardware, avoid loopback mode. \$\endgroup\$ – Lundin Dec 8 '16 at 14:44
0
\$\begingroup\$

The problem was simply that the recieving end was not acking properly as suggested by the comments.

\$\endgroup\$
  • \$\begingroup\$ with mbed, you can disable the acknowledge verification with can_instance.mode(CAN::LocalTest); \$\endgroup\$ – yota May 24 '18 at 12:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.