Пример #1
0
/**
 * @brief   Wait end of data transaction and performs finalizations.
 *
 * @param[in] sdcp      pointer to the @p SDCDriver object
 * @param[in] n         number of blocks in transaction
 * @param[in] resp      pointer to the response buffer
 *
 * @return              The operation status.
 * @retval HAL_SUCCESS  operation succeeded.
 * @retval HAL_FAILED   operation failed.
 */
static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
                                         uint32_t *resp) {

  /* Note the mask is checked before going to sleep because the interrupt
     may have occurred before reaching the critical zone.*/
  osalSysLock();
  if (sdcp->sdmmc->MASK != 0)
    osalThreadSuspendS(&sdcp->thread);
  if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) {
    osalSysUnlock();
    return HAL_FAILED;
  }

  /* Wait until DMA channel enabled to be sure that all data transferred.*/
  while (sdcp->dma->stream->CR & STM32_DMA_CR_EN)
    ;

  /* DMA event flags must be manually cleared.*/
  dmaStreamClearInterrupt(sdcp->dma);

  sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
  sdcp->sdmmc->DCTRL = 0;
  osalSysUnlock();

  /* Finalize transaction.*/
  if (n > 1)
    return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);

  return HAL_SUCCESS;
}
Пример #2
0
/**
 * @brief   Wait end of data transaction and performs finalizations.
 *
 * @param[in] sdcp      pointer to the @p SDCDriver object
 * @param[in] n         number of blocks in transaction
 * @param[in] resp      pointer to the response buffer
 *
 * @return              The operation status.
 * @retval HAL_SUCCESS  operation succeeded.
 * @retval HAL_FAILED   operation failed.
 */
static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
                                         uint32_t *resp) {

  /* Note the mask is checked before going to sleep because the interrupt
     may have occurred before reaching the critical zone.*/
  osalSysLock();
  if (sdcp->sdmmc->MASK != 0)
    osalThreadSuspendS(&sdcp->thread);
  if ((sdcp->sdmmc->STA & SDMMC_STA_DATAEND) == 0) {
    osalSysUnlock();
    return HAL_FAILED;
  }

  /* Waits for transfer completion at DMA level, then the stream is
     disabled and cleared.*/
  dmaWaitCompletion(sdcp->dma);

  sdcp->sdmmc->ICR = SDMMC_ICR_ALL_FLAGS;
  sdcp->sdmmc->DCTRL = 0;
  osalSysUnlock();

  /* Finalize transaction.*/
  if (n > 1)
    return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);

  return HAL_SUCCESS;
}
Пример #3
0
/**
 * @brief   USB data transfer loop.
 * @details This function must be executed by a system thread in order to
 *          make the USB driver work.
 * @note    The data copy part of the driver is implemented in this thread
 *          in order to not perform heavy tasks withing interrupt handlers.
 *
 * @param[in] p         pointer to the @p USBDriver object
 * @return              The function never returns.
 *
 * @special
 */
msg_t usb_lld_pump(void *p) {
  USBDriver *usbp = (USBDriver *)p;
  stm32_otg_t *otgp = usbp->otg;

#if defined(_CHIBIOS_RT_)
  chRegSetThreadName("usb_lld_pump");
#endif
  osalSysLock();
  while (true) {
    usbep_t ep;
    uint32_t epmask;

    /* Nothing to do, going to sleep.*/
    if ((usbp->state == USB_STOP) ||
        ((usbp->txpending == 0) && !(otgp->GINTSTS & GINTSTS_RXFLVL))) {
      otgp->GINTMSK |= GINTMSK_RXFLVLM;
      osalThreadSuspendS(&usbp->wait);
    }
    osalSysUnlock();

    /* Checks if there are TXFIFOs to be filled.*/
    for (ep = 0; ep <= usbp->otgparams->num_endpoints; ep++) {

      /* Empties the RX FIFO.*/
      while (otgp->GINTSTS & GINTSTS_RXFLVL) {
        otg_rxfifo_handler(usbp);
      }

      epmask = (1 << ep);
      if (usbp->txpending & epmask) {
        bool done;

        osalSysLock();
        /* USB interrupts are globally *suspended* because the peripheral
           does not allow any interference during the TX FIFO filling
           operation.
           Synopsys document: DesignWare Cores USB 2.0 Hi-Speed On-The-Go (OTG)
             "The application has to finish writing one complete packet before
              switching to a different channel/endpoint FIFO. Violating this
              rule results in an error.".*/
        otgp->GAHBCFG &= ~GAHBCFG_GINTMSK;
        usbp->txpending &= ~epmask;
        osalSysUnlock();

        done = otg_txfifo_handler(usbp, ep);

        osalSysLock();
        otgp->GAHBCFG |= GAHBCFG_GINTMSK;
        if (!done)
          otgp->DIEPEMPMSK |= epmask;
        osalSysUnlock();
      }
    }
    osalSysLock();
  }
  osalSysUnlock();
  return 0;
}
Пример #4
0
/**
 * @brief     Read some bites from slave device.
 *
 * @param[in] owp           pointer to the @p onewireDriver object
 * @param[in] txbuf         pointer to the buffer with data to be written
 * @param[in] txbytes       amount of data to be written
 * @param[in] pullup_time   how long strong pull up must be activated. Set
 *                          it to 0 if not needed.
 */
void onewireWrite(onewireDriver *owp, uint8_t *txbuf,
                  size_t txbytes, systime_t pullup_time) {
  PWMDriver *pwmd;
  PWMConfig *pwmcfg;
  size_t mch, sch;

  osalDbgCheck((NULL != owp) && (NULL != txbuf));
  osalDbgCheck((txbytes > 0) && (txbytes <= ONEWIRE_MAX_TRANSACTION_LEN));
  osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");
#if !ONEWIRE_USE_STRONG_PULLUP
  osalDbgAssert(0 == pullup_time,
      "Non zero time is valid only when strong pull enabled");
#endif

  pwmd = owp->config->pwmd;
  pwmcfg = owp->config->pwmcfg;
  mch = owp->config->master_channel;
  sch = owp->config->sample_channel;

  owp->buf = txbuf;
  owp->reg.bit = 0;
  owp->reg.final_timeslot = false;
  owp->reg.bytes = txbytes;

  pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
  pwmcfg->callback = pwm_write_bit_cb;
  pwmcfg->channels[mch].callback = NULL;
  pwmcfg->channels[mch].mode = owp->config->pwmmode;
  pwmcfg->channels[sch].callback = NULL;
  pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED;

#if ONEWIRE_USE_STRONG_PULLUP
  if (pullup_time > 0) {
    owp->reg.state = ONEWIRE_PULL_UP;
    owp->reg.need_pullup = true;
  }
#endif

  ow_bus_active(owp);
  osalSysLock();
  pwmEnablePeriodicNotificationI(pwmd);
  osalThreadSuspendS(&owp->thread);
  osalSysUnlock();

  pwmDisablePeriodicNotification(pwmd);
  ow_bus_idle(owp);

#if ONEWIRE_USE_STRONG_PULLUP
  if (pullup_time > 0) {
    osalThreadSleep(pullup_time);
    owp->config->pullup_release();
    owp->reg.state = ONEWIRE_READY;
  }
#endif
}
Пример #5
0
/**
 * @brief   Receives data from the SPI bus.
 * @details This synchronous function performs a receive operation.
 * @pre     In order to use this function the option @p SPI_USE_WAIT must be
 *          enabled.
 * @pre     In order to use this function the driver must have been configured
 *          without callbacks (@p end_cb = @p NULL).
 * @note    The buffers are organized as uint8_t arrays for data sizes below
 *          or equal to 8 bits else it is organized as uint16_t arrays.
 *
 * @param[in] spip      pointer to the @p SPIDriver object
 * @param[in] n         number of words to receive
 * @param[out] rxbuf    the pointer to the receive buffer
 *
 * @api
 */
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {

  osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));

  osalSysLock();
  osalDbgAssert(spip->state == SPI_READY, "not ready");
  osalDbgAssert(spip->config->end_cb == NULL, "has callback");
  spiStartReceiveI(spip, n, rxbuf);
  (void) osalThreadSuspendS(&spip->thread);
  osalSysUnlock();
}
Пример #6
0
/**
 * @brief   Ignores data on the SPI bus.
 * @details This synchronous function performs the transmission of a series of
 *          idle words on the SPI bus and ignores the received data.
 * @pre     In order to use this function the option @p SPI_USE_WAIT must be
 *          enabled.
 * @pre     In order to use this function the driver must have been configured
 *          without callbacks (@p end_cb = @p NULL).
 *
 * @param[in] spip      pointer to the @p SPIDriver object
 * @param[in] n         number of words to be ignored
 *
 * @api
 */
void spiIgnore(SPIDriver *spip, size_t n) {

  osalDbgCheck((spip != NULL) && (n > 0U));

  osalSysLock();
  osalDbgAssert(spip->state == SPI_READY, "not ready");
  osalDbgAssert(spip->config->end_cb == NULL, "has callback");
  spiStartIgnoreI(spip, n);
  (void) osalThreadSuspendS(&spip->thread);
  osalSysUnlock();
}
Пример #7
0
/**
 * @brief   Performs an ADC conversion.
 * @details Performs a synchronous conversion operation.
 * @note    The buffer is organized as a matrix of M*N elements where M is the
 *          channels number configured into the conversion group and N is the
 *          buffer depth. The samples are sequentially written into the buffer
 *          with no gaps.
 *
 * @param[in] adcp      pointer to the @p ADCDriver object
 * @param[in] grpp      pointer to a @p ADCConversionGroup object
 * @param[out] samples  pointer to the samples buffer
 * @param[in] depth     buffer depth (matrix rows number). The buffer depth
 *                      must be one or an even number.
 * @return              The operation result.
 * @retval MSG_OK       Conversion finished.
 * @retval MSG_RESET    The conversion has been stopped using
 *                      @p acdStopConversion() or @p acdStopConversionI(),
 *                      the result buffer may contain incorrect data.
 * @retval MSG_TIMEOUT  The conversion has been stopped because an hardware
 *                      error.
 *
 * @api
 */
msg_t adcConvert(ADCDriver *adcp,
                 const ADCConversionGroup *grpp,
                 adcsample_t *samples,
                 size_t depth) {
  msg_t msg;

  osalSysLock();
  osalDbgAssert(adcp->thread == NULL, "already waiting");
  adcStartConversionI(adcp, grpp, samples, depth);
  msg = osalThreadSuspendS(&adcp->thread);
  osalSysUnlock();
  return msg;
}
Пример #8
0
/**
 * @brief   Receives data from the SPI bus.
 * @details This synchronous function performs a receive operation.
 * @pre     In order to use this function the option @p SPI_USE_WAIT must be
 *          enabled.
 * @pre     In order to use this function the driver must have been configured
 *          without callbacks (@p end_cb = @p NULL).
 * @note    The buffers are organized as uint8_t arrays for data sizes below
 *          or equal to 8 bits else it is organized as uint16_t arrays.
 *
 * @param[in] spip      pointer to the @p SPIDriver object
 * @param[in] n         number of words to receive
 * @param[out] rxbuf    the pointer to the receive buffer
 *
 * @api
 */
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {

  osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));
#if SPI_SUPPORTS_CIRCULAR
  osalDbgCheck((spip->config->circular == false) || ((n & 1U) == 0U));
#endif

  osalSysLock();
  osalDbgAssert(spip->state == SPI_READY, "not ready");
  spiStartReceiveI(spip, n, rxbuf);
  (void) osalThreadSuspendS(&spip->thread);
  osalSysUnlock();
}
Пример #9
0
/**
 * @brief   Performs a DAC conversion.
 * @details Performs a synchronous conversion operation.
 * @note    The buffer is organized as a matrix of M*N elements where M is the
 *          channels number configured into the conversion group and N is the
 *          buffer depth. The samples are sequentially written into the buffer
 *          with no gaps.
 *
 * @param[in] dacp      pointer to the @p DACDriver object
 * @param[in] grpp      pointer to a @p DACConversionGroup object
 * @param[out] samples  pointer to the samples buffer
 * @param[in] depth     buffer depth (matrix rows number). The buffer depth
 *                      must be one or an even number.
 * @return              The operation result.
 * @retval MSG_OK       Conversion finished.
 * @retval MSG_RESET    The conversion has been stopped using
 *                      @p acdStopConversion() or @p acdStopConversionI(),
 *                      the result buffer may contain incorrect data.
 * @retval MSG_TIMEOUT  The conversion has been stopped because an hardware
 *                      error.
 *
 * @api
 */
msg_t dacConvert(DACDriver *dacp,
                 const DACConversionGroup *grpp,
                 const dacsample_t *samples,
                 size_t depth) {
  msg_t msg;

  osalSysLock();

  dacStartConversionI(dacp, grpp, samples, depth);
  msg = osalThreadSuspendS(&dacp->thread);

  osalSysUnlock();
  return msg;
}
Пример #10
0
/**
 * @brief   Sends a command without data phase.
 * @pre     In order to use this function the option @p QSPI_USE_WAIT must be
 *          enabled.
 * @pre     In order to use this function the driver must have been configured
 *          without callbacks (@p end_cb = @p NULL).
 *
 * @param[in] qspip     pointer to the @p QSPIDriver object
 * @param[in] cmdp      pointer to the command descriptor
 *
 * @api
 */
void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp) {

  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) == QSPI_CFG_DATA_MODE_NONE);

  osalSysLock();

  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");

  qspiStartCommandI(qspip, cmdp);
  (void) osalThreadSuspendS(&qspip->thread);

  osalSysUnlock();
}
Пример #11
0
/**
 * @brief   Returns calculated CRC from last reset
 *
 * @param[in] crcp      pointer to the @p CRCDriver object
 * @param[in] n         size of buf in bytes
 * @param[in] buf       @p buffer location
 *
 * @notapi
 */
uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf) {
#if CRC_USE_DMA == TRUE
  crc_lld_start_calc(crcp, n, buf);
  (void) osalThreadSuspendS(&crcp->thread);
#else
  /**
   * BUG: Only peform byte writes to DR reg if reflect_data is disabled.
   * The STM32 hardware unit seems to incorrectly calculate CRCs when all
   * of the following is true: reflect_data(rev_in) is 0, dma is disable, and
   * you are writing more than a byte into the DR register.
   */
  if (crcp->config->reflect_data != 0) {
    while(n > 3) {
      _crc_lld_calc_word(crcp, *(uint32_t*)buf);
      buf+=4;
      n-=4;
    }
  }

#if STM32_CRC_PROGRAMMABLE == TRUE
  /* Programmable CRC units allow variable register width accesses.*/

  /**
   * BUG: Only peform byte writes to DR reg if reflect_data is disabled.
   * The STM32 hardware unit seems to incorrectly calculate CRCs when all
   * of the following is true: reflect_data(rev_in) is 0, dma is disable, and
   * you are writing more than a byte into the DR register.
   */
  if (crcp->config->reflect_data != 0) {
    while(n > 1) {
      _crc_lld_calc_halfword(crcp, *(uint16_t*)buf);
      buf+=2;
      n-=2;
    }
  }

  while(n > 0) {
    _crc_lld_calc_byte(crcp, *(uint8_t*)buf);
    buf++;
    n--;
  }
#else
  osalDbgAssert(n == 0, "STM32 CRC Unit only supports WORD accesses");
#endif

#endif
  return crcp->crc->DR ^ crcp->config->final_val;
}
Пример #12
0
/**
 * @brief   Performs a transmit transaction on an IN endpoint.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 * @param[in] buf       buffer where to fetch the data to be transmitted
 * @param[in] n         transaction size
 *
 * @return              The operation status.
 * @retval MSG_OK       operation performed successfully.
 * @retval MSG_RESET    driver not in @p USB_ACTIVE state or the operation
 *                      has been aborted by an USB reset or a transition to
 *                      the @p USB_SUSPENDED state.
 *
 * @api
 */
msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) {
  msg_t msg;

  osalSysLock();

  if (usbGetDriverStateI(usbp) != USB_ACTIVE) {
    osalSysUnlock();
    return MSG_RESET;
  }

  usbStartTransmitI(usbp, ep, buf, n);
  msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread);
  osalSysUnlock();

  return msg;
}
Пример #13
0
/**
 * @brief   Sends a command then receives data over the QSPI bus.
 * @pre     In order to use this function the option @p QSPI_USE_WAIT must be
 *          enabled.
 * @pre     In order to use this function the driver must have been configured
 *          without callbacks (@p end_cb = @p NULL).
 *
 * @param[in] qspip     pointer to the @p QSPIDriver object
 * @param[in] cmdp      pointer to the command descriptor
 * @param[in] n         number of bytes to send
 * @param[out] rxbuf    the pointer to the receive buffer
 *
 * @api
 */
void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp,
                 size_t n, uint8_t *rxbuf) {

  osalDbgCheck((qspip != NULL) && (cmdp != NULL));
  osalDbgCheck((n > 0U) && (rxbuf != NULL));
  osalDbgCheck((cmdp->cfg & QSPI_CFG_DATA_MODE_MASK) != QSPI_CFG_DATA_MODE_NONE);

  osalSysLock();

  osalDbgAssert(qspip->state == QSPI_READY, "not ready");
  osalDbgAssert(qspip->config->end_cb == NULL, "has callback");

  qspiStartReceiveI(qspip, cmdp, n, rxbuf);
  (void) osalThreadSuspendS(&qspip->thread);

  osalSysUnlock();
}
Пример #14
0
/**
 * @brief   Wait end of data transaction and performs finalizations.
 *
 * @param[in] sdcp      pointer to the @p SDCDriver object
 * @param[in] n         number of blocks in transaction
 * @param[in] resp      pointer to the response buffer
 *
 * @return              The operation status.
 * @retval HAL_SUCCESS  operation succeeded.
 * @retval HAL_FAILED   operation failed.
 */
static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n,
        uint32_t *resp) {

    /* Note the mask is checked before going to sleep because the interrupt
       may have occurred before reaching the critical zone.*/
    osalSysLock();
    if (sdcp->sdio->MASK != 0)
        osalThreadSuspendS(&sdcp->thread);
    if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) {
        osalSysUnlock();
        return HAL_FAILED;
    }

#if (defined(STM32F4XX) || defined(STM32F2XX))
    /* Wait until DMA channel enabled to be sure that all data transferred.*/
    while (sdcp->dma->stream->CR & STM32_DMA_CR_EN)
        ;

    /* DMA event flags must be manually cleared.*/
    dmaStreamClearInterrupt(sdcp->dma);

    sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
    sdcp->sdio->DCTRL = 0;
    osalSysUnlock();

    /* Wait until interrupt flags to be cleared.*/
    /*while (((DMA2->LISR) >> (sdcp->dma->ishift)) & STM32_DMA_ISR_TCIF)
      dmaStreamClearInterrupt(sdcp->dma);*/
#else
    /* Waits for transfer completion at DMA level, then the stream is
       disabled and cleared.*/
    dmaWaitCompletion(sdcp->dma);

    sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS;
    sdcp->sdio->DCTRL = 0;
    osalSysUnlock();
#endif

    /* Finalize transaction.*/
    if (n > 1)
        return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp);

    return HAL_SUCCESS;
}
Пример #15
0
/**
 * @brief     Generate reset pulse on bus.
 *
 * @param[in] owp       pointer to the @p onewireDriver object
 *
 * @return              Bool flag denoting device presence.
 * @retval true         There is at least one device on bus.
 */
bool onewireReset(onewireDriver *owp) {
  PWMDriver *pwmd;
  PWMConfig *pwmcfg;
  size_t mch, sch;

  osalDbgCheck(NULL != owp);
  osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");

  /* short circuit on bus or any other device transmit data */
  if (PAL_LOW == ow_read_bit(owp))
    return false;

  pwmd = owp->config->pwmd;
  pwmcfg = owp->config->pwmcfg;
  mch = owp->config->master_channel;
  sch = owp->config->sample_channel;


  pwmcfg->period = ONEWIRE_RESET_LOW_WIDTH + ONEWIRE_RESET_SAMPLE_WIDTH;
  pwmcfg->callback = NULL;
  pwmcfg->channels[mch].callback = NULL;
  pwmcfg->channels[mch].mode = owp->config->pwmmode;
  pwmcfg->channels[sch].callback = pwm_reset_cb;
  pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW;

  ow_bus_active(owp);

  osalSysLock();
  pwmEnableChannelI(pwmd, mch, ONEWIRE_RESET_LOW_WIDTH);
  pwmEnableChannelI(pwmd, sch, ONEWIRE_RESET_SAMPLE_WIDTH);
  pwmEnableChannelNotificationI(pwmd, sch);
  osalThreadSuspendS(&owp->thread);
  osalSysUnlock();

  ow_bus_idle(owp);

  /* wait until slave release bus to discriminate short circuit condition */
  osalThreadSleepMicroseconds(500);
  return (PAL_HIGH == ow_read_bit(owp)) && (true == owp->reg.slave_present);
}
Пример #16
0
/**
 * @brief     Read some bites from slave device.
 *
 * @param[in] owp       pointer to the @p onewireDriver object
 * @param[out] rxbuf    pointer to the buffer for read data
 * @param[in] rxbytes   amount of data to be received
 */
void onewireRead(onewireDriver *owp, uint8_t *rxbuf, size_t rxbytes) {
  PWMDriver *pwmd;
  PWMConfig *pwmcfg;
  size_t mch, sch;

  osalDbgCheck((NULL != owp) && (NULL != rxbuf));
  osalDbgCheck((rxbytes > 0) && (rxbytes <= ONEWIRE_MAX_TRANSACTION_LEN));
  osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");

  /* Buffer zeroing. This is important because of driver collects
     bits using |= operation.*/
  memset(rxbuf, 0, rxbytes);

  pwmd = owp->config->pwmd;
  pwmcfg = owp->config->pwmcfg;
  mch = owp->config->master_channel;
  sch = owp->config->sample_channel;

  owp->reg.bit = 0;
  owp->reg.final_timeslot = false;
  owp->buf = rxbuf;
  owp->reg.bytes = rxbytes;

  pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
  pwmcfg->callback = NULL;
  pwmcfg->channels[mch].callback = NULL;
  pwmcfg->channels[mch].mode = owp->config->pwmmode;
  pwmcfg->channels[sch].callback = pwm_read_bit_cb;
  pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW;

  ow_bus_active(owp);
  osalSysLock();
  pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH);
  pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH);
  pwmEnableChannelNotificationI(pwmd, sch);
  osalThreadSuspendS(&owp->thread);
  osalSysUnlock();

  ow_bus_idle(owp);
}
Пример #17
0
/**
 * @brief   Performs tree search on bus.
 * @note    This function does internal 1-wire reset calls every search
 *          iteration.
 *
 * @param[in] owp         pointer to a @p OWDriver object
 * @param[out] result     pointer to buffer for discovered ROMs
 * @param[in] max_rom_cnt buffer size in ROMs count for overflow prevention
 *
 * @return              Count of discovered ROMs. May be more than max_rom_cnt.
 * @retval 0            no ROMs found or communication error occurred.
 */
size_t onewireSearchRom(onewireDriver *owp, uint8_t *result,
                        size_t max_rom_cnt) {
  PWMDriver *pwmd;
  PWMConfig *pwmcfg;
  uint8_t cmd;
  size_t mch, sch;

  osalDbgCheck(NULL != owp);
  osalDbgAssert(ONEWIRE_READY == owp->reg.state, "Invalid state");
  osalDbgCheck((max_rom_cnt <= 256) && (max_rom_cnt > 0));

  pwmd = owp->config->pwmd;
  pwmcfg = owp->config->pwmcfg;
  cmd = ONEWIRE_CMD_SEARCH_ROM;
  mch = owp->config->master_channel;
  sch = owp->config->sample_channel;

  search_clean_start(&owp->search_rom);

  do {
    /* every search must be started from reset pulse */
    if (false == onewireReset(owp))
      return 0;

    /* initialize buffer to store result */
    if (owp->search_rom.reg.devices_found >= max_rom_cnt)
      owp->search_rom.retbuf = result + 8*(max_rom_cnt-1);
    else
      owp->search_rom.retbuf = result + 8*owp->search_rom.reg.devices_found;
    memset(owp->search_rom.retbuf, 0, 8);

    /* clean iteration state */
    search_clean_iteration(&owp->search_rom);

    /**/
    onewireWrite(&OWD1, &cmd, 1, 0);

    /* Reconfiguration always needed because of previous call onewireWrite.*/
    pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
    pwmcfg->callback = NULL;
    pwmcfg->channels[mch].callback = NULL;
    pwmcfg->channels[mch].mode = owp->config->pwmmode;
    pwmcfg->channels[sch].callback = pwm_search_rom_cb;
    pwmcfg->channels[sch].mode = PWM_OUTPUT_ACTIVE_LOW;

    ow_bus_active(owp);
    osalSysLock();
    pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH);
    pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH);
    pwmEnableChannelNotificationI(pwmd, sch);
    osalThreadSuspendS(&owp->thread);
    osalSysUnlock();

    ow_bus_idle(owp);

    if (ONEWIRE_SEARCH_ROM_ERROR != owp->search_rom.reg.result) {
      /* check CRC and return 0 (0 == error) if mismatch */
      if (owp->search_rom.retbuf[7] != onewireCRC(owp->search_rom.retbuf, 7))
        return 0;
      /* store cached result for usage in next iteration */
      memcpy(owp->search_rom.prev_path, owp->search_rom.retbuf, 8);
    }
  }
  while (ONEWIRE_SEARCH_ROM_SUCCESS == owp->search_rom.reg.result);

  /**/
  if (ONEWIRE_SEARCH_ROM_ERROR == owp->search_rom.reg.result)
    return 0;
  else
    return owp->search_rom.reg.devices_found;
}
Пример #18
0
/* Idle requests timer code
 * callback (called from ISR, unlocked state) */
static void keyboard_idle_timer_cb(void *arg) {
  USBDriver *usbp = (USBDriver *)arg;

  osalSysLockFromISR();

  /* check that the states of things are as they're supposed to */
  if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
    /* do not rearm the timer, should be enabled on IDLE request */
    osalSysUnlockFromISR();
    return;
  }

#ifdef NKRO_ENABLE
  if(!keymap_config.nkro && keyboard_idle) {
#else /* NKRO_ENABLE */
  if(keyboard_idle) {
#endif /* NKRO_ENABLE */
    /* TODO: are we sure we want the KBD_ENDPOINT? */
    if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
      usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE);
    }
    /* rearm the timer */
    chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
  }

  /* do not rearm the timer if the condition above fails
   * it should be enabled again on either IDLE or SET_PROTOCOL requests */
  osalSysUnlockFromISR();
}

/* LED status */
uint8_t keyboard_leds(void) {
  return (uint8_t)(keyboard_led_stats & 0xFF);
}

/* prepare and start sending a report IN
 * not callable from ISR or locked state */
void send_keyboard(report_keyboard_t *report) {
  osalSysLock();
  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
    osalSysUnlock();
    return;
  }
  osalSysUnlock();

#ifdef NKRO_ENABLE
  if(keymap_config.nkro) {  /* NKRO protocol */
    /* need to wait until the previous packet has made it through */
    /* can rewrite this using the synchronous API, then would wait
     * until *after* the packet has been transmitted. I think
     * this is more efficient */
    /* busy wait, should be short and not very common */
    osalSysLock();
    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) {
      /* Need to either suspend, or loop and call unlock/lock during
       * every iteration - otherwise the system will remain locked,
       * no interrupts served, so USB not going through as well.
       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread);
    }
    usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t));
    osalSysUnlock();
  } else
#endif /* NKRO_ENABLE */
  { /* boot protocol */
    /* need to wait until the previous packet has made it through */
    /* busy wait, should be short and not very common */
    osalSysLock();
    if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) {
      /* Need to either suspend, or loop and call unlock/lock during
       * every iteration - otherwise the system will remain locked,
       * no interrupts served, so USB not going through as well.
       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
      osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
    }
    usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE);
    osalSysUnlock();
  }
  keyboard_report_sent = *report;
}
Пример #19
0
/**
 * @brief   Put calling thread in suspend and switch driver state
 *
 * @param[in] nandp    pointer to the @p NANDDriver object
 */
static void nand_lld_suspend_thread(NANDDriver *nandp) {

  osalThreadSuspendS(&nandp->thread);
}