Electrical – STM32F7 CAN message stuck in mailbox and error frames on bus

ccanembeddedstm32

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

Best Answer

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