diff options
| author | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2013-02-03 10:29:01 +0000 | 
|---|---|---|
| committer | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2013-02-03 10:29:01 +0000 | 
| commit | 92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0 (patch) | |
| tree | 7137b92e04fff3e94c0db7318dd9611d3c22d45d /os/hal/platforms/STM32/can_lld.c | |
| parent | 184a71345c6a36a9a8664eda8fbcc3ea728267a8 (diff) | |
| download | ChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.tar.gz ChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.tar.bz2 ChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.zip  | |
Added CAN2 support. Tested on the STM32F4xx only.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5105 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/platforms/STM32/can_lld.c')
| -rw-r--r-- | os/hal/platforms/STM32/can_lld.c | 402 | 
1 files changed, 303 insertions, 99 deletions
diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c index 0b4a918db..75de38353 100644 --- a/os/hal/platforms/STM32/can_lld.c +++ b/os/hal/platforms/STM32/can_lld.c @@ -39,11 +39,16 @@  /* Driver exported variables.                                                */
  /*===========================================================================*/
 -/** @brief ADC1 driver identifier.*/
 +/** @brief CAN1 driver identifier.*/
  #if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
  CANDriver CAND1;
  #endif
 +/** @brief CAN2 driver identifier.*/
 +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
 +CANDriver CAND2;
 +#endif
 +
  /*===========================================================================*/
  /* Driver local variables.                                                   */
  /*===========================================================================*/
 @@ -52,101 +57,159 @@ CANDriver CAND1;  /* Driver local functions.                                                   */
  /*===========================================================================*/
 -/*===========================================================================*/
 -/* Driver interrupt handlers.                                                */
 -/*===========================================================================*/
 -
  /**
 - * @brief   CAN1 TX interrupt handler.
 + * @brief   Programs the filters.
   *
 - * @isr
 + * @param[in] can2sb    number of the first filter assigned to CAN2
 + * @param[in] num       number of entries in the filters array, if zero then
 + *                      a default filter is programmed
 + * @param[in] cfp       pointer to the filters array, can be @p NULL if
 + *                      (num == 0)
 + *
 + * @notapi
   */
 -CH_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) {
 +static void can_lld_set_filters(uint32_t can2sb,
 +                         uint32_t num,
 +                         const CANFilter *cfp) {
 -  CH_IRQ_PROLOGUE();
 +  /* Temporarily enabling CAN1 clock.*/
 +  rccEnableCAN1(FALSE);
 +
 +  /* Filters initialization.*/
 +  CAN1->FMR = (CAN1->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT;
 +  if (num > 0) {
 +    uint32_t i, fmask;
 +
 +    /* All filters cleared.*/
 +    CAN1->FA1R = 0;
 +    CAN1->FM1R = 0;
 +    CAN1->FS1R = 0;
 +    CAN1->FFA1R = 0;
 +    for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) {
 +      CAN1->sFilterRegister[i].FR1 = 0;
 +      CAN1->sFilterRegister[i].FR2 = 0;
 +    }
 +
 +    /* Scanning the filters array.*/
 +    for (i = 0; i < num; i++) {
 +      fmask = 1 << cfp->filter;
 +      if (cfp->mode)
 +        CAN1->FM1R |= fmask;
 +      if (cfp->scale)
 +        CAN1->FS1R |= fmask;
 +      if (cfp->assignment)
 +        CAN1->FFA1R |= fmask;
 +      CAN1->sFilterRegister[cfp->filter].FR1 = cfp->register1;
 +      CAN1->sFilterRegister[cfp->filter].FR2 = cfp->register2;
 +      CAN1->FA1R |= fmask;
 +      cfp++;
 +    }
 +  }
 +  else {
 +    /* Setting up a single default filter that enables everything for both
 +       CANs.*/
 +    CAN1->sFilterRegister[0].FR1 = 0;
 +    CAN1->sFilterRegister[0].FR2 = 0;
 +    CAN1->sFilterRegister[can2sb].FR1 = 0;
 +    CAN1->sFilterRegister[can2sb].FR2 = 0;
 +    CAN1->FM1R = 0;
 +    CAN1->FFA1R = 0;
 +    CAN1->FS1R = 1 | (1 << can2sb);
 +    CAN1->FA1R = 1 | (1 << can2sb);
 +  }
 +  CAN1->FMR &= ~CAN_FMR_FINIT;
 +
 +  /* Clock disabled, it will be enabled again in can_lld_start().*/
 +  rccDisableCAN1(FALSE);
 +}
 +
 +/**
 + * @brief   Common TX ISR handler.
 + *
 + * @param[in] canp      pointer to the @p CANDriver object
 + *
 + * @notapi
 + */
 +static void can_lld_tx_handler(CANDriver *canp) {
    /* No more events until a message is transmitted.*/
 -  CAN1->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
 +  canp->can->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
    chSysLockFromIsr();
 -  while (chSemGetCounterI(&CAND1.txsem) < 0)
 -    chSemSignalI(&CAND1.txsem);
 -  chEvtBroadcastI(&CAND1.txempty_event);
 +  while (chSemGetCounterI(&canp->txsem) < 0)
 +    chSemSignalI(&canp->txsem);
 +  chEvtBroadcastI(&canp->txempty_event);
    chSysUnlockFromIsr();
 -
 -  CH_IRQ_EPILOGUE();
  }
 -/*
 - * @brief   CAN1 RX0 interrupt handler.
 +/**
 + * @brief   Common RX0 ISR handler.
   *
 - * @isr
 + * @param[in] canp      pointer to the @p CANDriver object
 + *
 + * @notapi
   */
 -CH_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) {
 +static void can_lld_rx0_handler(CANDriver *canp) {
    uint32_t rf0r;
 -  CH_IRQ_PROLOGUE();
 -
 -  rf0r = CAN1->RF0R;
 +  rf0r = canp->can->RF0R;
    if ((rf0r & CAN_RF0R_FMP0) > 0) {
      /* No more receive events until the queue 0 has been emptied.*/
 -    CAN1->IER &= ~CAN_IER_FMPIE0;
 +    canp->can->IER &= ~CAN_IER_FMPIE0;
      chSysLockFromIsr();
 -    while (chSemGetCounterI(&CAND1.rxsem) < 0)
 -      chSemSignalI(&CAND1.rxsem);
 -    chEvtBroadcastI(&CAND1.rxfull_event);
 +    while (chSemGetCounterI(&canp->rxsem) < 0)
 +      chSemSignalI(&canp->rxsem);
 +    chEvtBroadcastI(&canp->rxfull_event);
      chSysUnlockFromIsr();
    }
    if ((rf0r & CAN_RF0R_FOVR0) > 0) {
      /* Overflow events handling.*/
 -    CAN1->RF0R = CAN_RF0R_FOVR0;
 +    canp->can->RF0R = CAN_RF0R_FOVR0;
      chSysLockFromIsr();
 -    chEvtBroadcastFlagsI(&CAND1.error_event, CAN_OVERFLOW_ERROR);
 +    chEvtBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR);
      chSysUnlockFromIsr();
    }
 -
 -  CH_IRQ_EPILOGUE();
  }
  /**
 - * @brief   CAN1 RX1 interrupt handler.
 + * @brief   Common RX1 ISR handler.
 + * @note    Not used, must not be invoked, defaulted to an halt.
   *
 - * @isr
 + * @param[in] canp      pointer to the @p CANDriver object
 + *
 + * @notapi
   */
 -CH_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) {
 -
 -  CH_IRQ_PROLOGUE();
 -
 -  chSysHalt(); /* Not supported (yet).*/
 +static void can_lld_rx1_handler(CANDriver *canp) {
 -  CH_IRQ_EPILOGUE();
 +  (void)canp;
 +  chSysHalt();
  }
  /**
 - * @brief   CAN1 SCE interrupt handler.
 + * @brief   Common SCE ISR handler.
   *
 - * @isr
 + * @param[in] canp      pointer to the @p CANDriver object
 + *
 + * @notapi
   */
 -CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
 +static void can_lld_sce_handler(CANDriver *canp) {
    uint32_t msr;
 -  CH_IRQ_PROLOGUE();
 -
 -  msr = CAN1->MSR;
 -  CAN1->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI;
 +  msr = canp->can->MSR;
 +  canp->can->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI;
    /* Wakeup event.*/
    if (msr & CAN_MSR_WKUI) {
 -    CAND1.state = CAN_READY;
 -    CAND1.can->MCR &= ~CAN_MCR_SLEEP;
 +    canp->state = CAN_READY;
 +    canp->can->MCR &= ~CAN_MCR_SLEEP;
      chSysLockFromIsr();
 -    chEvtBroadcastI(&CAND1.wakeup_event);
 +    chEvtBroadcastI(&canp->wakeup_event);
      chSysUnlockFromIsr();
    }
    /* Error event.*/
    if (msr & CAN_MSR_ERRI) {
      flagsmask_t flags;
 -    uint32_t esr = CAN1->ESR;
 +    uint32_t esr = canp->can->ESR;
 -    CAN1->ESR &= ~CAN_ESR_LEC;
 +    canp->can->ESR &= ~CAN_ESR_LEC;
      flags = (flagsmask_t)(esr & 7);
      if ((esr & CAN_ESR_LEC) > 0)
        flags |= CAN_FRAMING_ERROR;
 @@ -154,13 +217,131 @@ CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {      chSysLockFromIsr();
      /* The content of the ESR register is copied unchanged in the upper
         half word of the listener flags mask.*/
 -    chEvtBroadcastFlagsI(&CAND1.error_event, flags | (flagsmask_t)(esr < 16));
 +    chEvtBroadcastFlagsI(&canp->error_event, flags | (flagsmask_t)(esr < 16));
      chSysUnlockFromIsr();
    }
 +}
 +
 +/*===========================================================================*/
 +/* Driver interrupt handlers.                                                */
 +/*===========================================================================*/
 +
 +#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
 +/**
 + * @brief   CAN1 TX interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_tx_handler(&CAND1);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +
 +/*
 + * @brief   CAN1 RX0 interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_rx0_handler(&CAND1);
    CH_IRQ_EPILOGUE();
  }
 +/**
 + * @brief   CAN1 RX1 interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_rx1_handler(&CAND1);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +
 +/**
 + * @brief   CAN1 SCE interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_sce_handler(&CAND1);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +#endif /* STM32_CAN_USE_CAN1 */
 +
 +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
 +/**
 + * @brief   CAN2 TX interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_tx_handler(&CAND2);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +
 +/*
 + * @brief   CAN2 RX0 interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_rx0_handler(&CAND2);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +
 +/**
 + * @brief   CAN2 RX1 interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_rx1_handler(&CAND2);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +
 +/**
 + * @brief   CAN2 SCE interrupt handler.
 + *
 + * @isr
 + */
 +CH_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) {
 +
 +  CH_IRQ_PROLOGUE();
 +
 +  can_lld_sce_handler(&CAND2);
 +
 +  CH_IRQ_EPILOGUE();
 +}
 +#endif /* STM32_CAN_USE_CAN2 */
 +
  /*===========================================================================*/
  /* Driver exported functions.                                                */
  /*===========================================================================*/
 @@ -177,6 +358,19 @@ void can_lld_init(void) {    canObjectInit(&CAND1);
    CAND1.can = CAN1;
  #endif
 +#if STM32_CAN_USE_CAN2
 +  /* Driver initialization.*/
 +  canObjectInit(&CAND2);
 +  CAND2.can = CAN2;
 +#endif
 +
 +  /* Filters initialization.*/
 +#if STM32_HAS_CAN2
 +  can_lld_set_filters(STM32_CAN_MAX_FILTERS / 2, 0, NULL);
 +#else
 +  can_lld_set_filters(STM32_CAN_MAX_FILTERS, 0, NULL);
 +#endif
 +
  }
  /**
 @@ -202,6 +396,19 @@ void can_lld_start(CANDriver *canp) {      rccEnableCAN1(FALSE);
    }
  #endif
 +#if STM32_CAN_USE_CAN2
 +  if (&CAND2 == canp) {
 +    nvicEnableVector(STM32_CAN2_TX_NUMBER,
 +                     CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
 +    nvicEnableVector(STM32_CAN2_RX0_NUMBER,
 +                     CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
 +    nvicEnableVector(STM32_CAN2_RX1_NUMBER,
 +                     CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
 +    nvicEnableVector(STM32_CAN2_SCE_NUMBER,
 +                     CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
 +    rccEnableCAN2(FALSE);
 +  }
 +#endif
    /* Entering initialization mode. */
    canp->state = CAN_STARTING;
 @@ -212,56 +419,12 @@ void can_lld_start(CANDriver *canp) {    canp->can->BTR = canp->config->btr;
    /* MCR initialization.*/
    canp->can->MCR = canp->config->mcr;
 -  /* Filters initialization.*/
 -  canp->can->FMR |= CAN_FMR_FINIT;
 -  if (canp->config->num > 0) {
 -    uint32_t i, fmask;
 -    CAN_FilterRegister_TypeDef *cfp;
 -
 -    canp->can->FA1R = 0;
 -    canp->can->FM1R = 0;
 -    canp->can->FS1R = 0;
 -    canp->can->FFA1R = 0;
 -    cfp = canp->can->sFilterRegister;
 -    fmask = 1;
 -    for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) {
 -      if (i < canp->config->num) {
 -        if (canp->config->filters[i].mode)
 -          canp->can->FM1R |= fmask;
 -        if (canp->config->filters[i].scale)
 -          canp->can->FS1R |= fmask;
 -        if (canp->config->filters[i].assignment)
 -          canp->can->FFA1R |= fmask;
 -        cfp->FR1 = canp->config->filters[i].register1;
 -        cfp->FR2 = canp->config->filters[i].register2;
 -        canp->can->FA1R |= fmask;
 -      }
 -      else {
 -        cfp->FR1 = 0;
 -        cfp->FR2 = 0;
 -      }
 -      /* Gives a chance for preemption since this is a rather long loop.*/
 -      chSysUnlock();
 -      cfp++;
 -      fmask <<= 1;
 -      chSysLock();
 -    }
 -  }
 -  else {
 -    /* Setup a default filter.*/
 -    canp->can->sFilterRegister[0].FR1 = 0;
 -    canp->can->sFilterRegister[0].FR2 = 0;
 -    canp->can->FM1R = 0;
 -    canp->can->FFA1R = 0;
 -    canp->can->FS1R = 1;
 -    canp->can->FA1R = 1;
 -  }
 -  canp->can->FMR &= ~CAN_FMR_FINIT;
 +
    /* Interrupt sources initialization.*/
    canp->can->IER = CAN_IER_TMEIE  | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
 -                      CAN_IER_WKUIE  | CAN_IER_ERRIE  | CAN_IER_LECIE  |
 -                      CAN_IER_BOFIE  | CAN_IER_EPVIE  | CAN_IER_EWGIE  |
 -                      CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
 +                   CAN_IER_WKUIE  | CAN_IER_ERRIE  | CAN_IER_LECIE  |
 +                   CAN_IER_BOFIE  | CAN_IER_EPVIE  | CAN_IER_EWGIE  |
 +                   CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
  }
  /**
 @@ -286,6 +449,17 @@ void can_lld_stop(CANDriver *canp) {        rccDisableCAN1(FALSE);
      }
  #endif
 +#if STM32_CAN_USE_CAN2
 +    if (&CAND2 == canp) {
 +      CAN2->MCR = 0x00010002;                   /* Register reset value.    */
 +      CAN2->IER = 0x00000000;                   /* All sources disabled.    */
 +      nvicDisableVector(STM32_CAN2_TX_NUMBER);
 +      nvicDisableVector(STM32_CAN2_RX0_NUMBER);
 +      nvicDisableVector(STM32_CAN2_RX1_NUMBER);
 +      nvicDisableVector(STM32_CAN2_SCE_NUMBER);
 +      rccDisableCAN2(FALSE);
 +    }
 +#endif
    }
  }
 @@ -409,6 +583,36 @@ void can_lld_wakeup(CANDriver *canp) {  }
  #endif /* CAN_USE_SLEEP_MODE */
 +/**
 + * @brief   Programs the filters.
 + * @note    This is an STM32-specific API.
 + *
 + * @param[in] can2sb    number of the first filter assigned to CAN2
 + * @param[in] num       number of entries in the filters array, if zero then
 + *                      a default filter is programmed
 + * @param[in] cfp       pointer to the filters array, can be @p NULL if
 + *                      (num == 0)
 + *
 + * @api
 + */
 +void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp) {
 +
 +  chDbgCheck((can2sb > 1) && (can2sb < STM32_CAN_MAX_FILTERS) &&
 +             (num < STM32_CAN_MAX_FILTERS),
 +             "canSTM32SetFilters");
 +
 +#if STM32_CAN_USE_CAN1
 +  chDbgAssert(CAND1.state == CAN_STOP,
 +              "canSTM32SetFilters(), #1", "invalid state");
 +#endif
 +#if STM32_CAN_USE_CAN2
 +  chDbgAssert(CAND2.state == CAN_STOP,
 +              "canSTM32SetFilters(), #2", "invalid state");
 +#endif
 +
 +  can_lld_set_filters(can2sb, num, cfp);
 +}
 +
  #endif /* HAL_USE_CAN */
  /** @} */
  | 
