Ejemplo n.º 1
0
/**
 * @brief   Writes one block.
 *
 * @param[in] sdcp      pointer to the @p SDCDriver object
 * @param[in] startblk  first block to write
 * @param[out] buf      pointer to the write buffer, it must be aligned to
 *                      four bytes boundary
 * @param[in] n         number of blocks to write
 * @return              The operation status.
 * @retval FALSE        operation succeeded, the requested blocks have been
 *                      written.
 * @retval TRUE         operation failed.
 *
 * @notapi
 */
static bool_t sdc_lld_write_single(SDCDriver *sdcp, uint32_t startblk,
                            const uint8_t *buf) {
  uint32_t resp[1];

  /* Checks for errors and waits for the card to be ready for writing.*/
  if (_sdc_wait_for_transfer_state(sdcp))
    return TRUE;

  /* Prepares the DMA channel for writing.*/
  dmaStreamSetMemory0(STM32_DMA2_STREAM4, buf);
  dmaStreamSetTransactionSize(STM32_DMA2_STREAM4,
                              SDC_BLOCK_SIZE / sizeof (uint32_t));
  dmaStreamSetMode(STM32_DMA2_STREAM4,
                   STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) |
                   STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD |
                   STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC);

  /* Write single block command.*/
  if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
    startblk *= SDC_BLOCK_SIZE;
  if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_BLOCK,
                                 startblk, resp) ||
      SDC_R1_ERROR(resp[0]))
    return TRUE;

  /* Setting up data transfer.
     Options: Controller to Card, Block mode, DMA mode, 512 bytes blocks.*/
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->MASK  = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
                SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE |
                SDIO_MASK_STBITERRIE;
  SDIO->DLEN  = SDC_BLOCK_SIZE;
  SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
                SDIO_DCTRL_DMAEN |
                SDIO_DCTRL_DTEN;

  /* DMA channel activation.*/
  dmaStreamEnable(STM32_DMA2_STREAM4);

  /* Note the mask is checked before going to sleep because the interrupt
     may have occurred before reaching the critical zone.*/
  chSysLock();
  if (SDIO->MASK != 0) {
    chDbgAssert(sdcp->thread == NULL,
                "sdc_lld_write_single(), #1", "not NULL");
    sdcp->thread = chThdSelf();
    chSchGoSleepS(THD_STATE_SUSPENDED);
    chDbgAssert(sdcp->thread == NULL,
                "sdc_lld_write_single(), #2", "not NULL");
  }
  if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
    chSysUnlock();
    goto error;
  }
  dmaStreamDisable(STM32_DMA2_STREAM4);
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->DCTRL = 0;
  chSysUnlock();

  return FALSE;
error:
  dmaStreamDisable(STM32_DMA2_STREAM4);
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->MASK  = 0;
  SDIO->DCTRL = 0;
  return TRUE;
}
Ejemplo n.º 2
0
/**
 * @brief   Reads one or more blocks.
 *
 * @param[in] sdcp      pointer to the @p SDCDriver object
 * @param[in] startblk  first block to read
 * @param[out] buf      pointer to the read buffer, it must be aligned to
 *                      four bytes boundary
 * @param[in] n         number of blocks to read
 * @return              The operation status.
 * @retval FALSE        operation succeeded, the requested blocks have been
 *                      read.
 * @retval TRUE         operation failed, the state of the buffer is uncertain.
 *
 * @notapi
 */
static bool_t sdc_lld_read_multiple(SDCDriver *sdcp, uint32_t startblk,
                                    uint8_t *buf, uint32_t n) {
  uint32_t resp[1];

  /* Checks for errors and waits for the card to be ready for reading.*/
  if (_sdc_wait_for_transfer_state(sdcp))
    return TRUE;

  /* Prepares the DMA channel for reading.*/
  dmaStreamSetMemory0(STM32_DMA2_STREAM4, buf);
  dmaStreamSetTransactionSize(STM32_DMA2_STREAM4,
                              (n * SDC_BLOCK_SIZE) / sizeof (uint32_t));
  dmaStreamSetMode(STM32_DMA2_STREAM4,
                   STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) |
                   STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_PSIZE_WORD |
                   STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC);

  /* Setting up data transfer.
     Options: Card to Controller, Block mode, DMA mode, 512 bytes blocks.*/
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->MASK  = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
                SDIO_MASK_DATAENDIE | SDIO_MASK_STBITERRIE;
  SDIO->DLEN  = n * SDC_BLOCK_SIZE;
  SDIO->DCTRL = SDIO_DCTRL_DTDIR |
                SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
                SDIO_DCTRL_DMAEN |
                SDIO_DCTRL_DTEN;

  /* DMA channel activation.*/
  dmaStreamEnable(STM32_DMA2_STREAM4);

  /* Read multiple blocks command.*/
  if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
    startblk *= SDC_BLOCK_SIZE;
  if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_MULTIPLE_BLOCK,
                                 startblk, resp) ||
      SDC_R1_ERROR(resp[0]))
    goto error;

  chSysLock();
  if (SDIO->MASK != 0) {
    chDbgAssert(sdcp->thread == NULL,
                "sdc_lld_read_multiple(), #1", "not NULL");
    sdcp->thread = chThdSelf();
    chSchGoSleepS(THD_STATE_SUSPENDED);
    chDbgAssert(sdcp->thread == NULL,
                "sdc_lld_read_multiple(), #2", "not NULL");
  }
  if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
    chSysUnlock();
    goto error;
  }
  dmaStreamDisable(STM32_DMA2_STREAM4);
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->DCTRL = 0;
  chSysUnlock();

  return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
error:
  dmaStreamDisable(STM32_DMA2_STREAM4);
  SDIO->ICR   = 0xFFFFFFFF;
  SDIO->MASK  = 0;
  SDIO->DCTRL = 0;
  return TRUE;
}
Ejemplo n.º 3
0
/**
 * @brief   Receives data via the I2C bus as master.
 * @details Number of receiving bytes must be more than 1 on STM32F1x. This is
 *          hardware restriction.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval MSG_OK       if the function succeeded.
 * @retval MSG_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval MSG_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                     uint8_t *rxbuf, size_t rxbytes,
                                     systime_t timeout) {
  msg_t msg;
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Releases the lock from high level driver.*/
  osalSysUnlock();

#if STM32_I2C_USE_DMA == TRUE
  /* RX DMA setup.*/
  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
#else
  i2cp->rxptr   = rxbuf;
  i2cp->rxbytes = rxbytes;
#endif

  /* Calculating the time window for the timeout on the busy bus condition.*/
  start = osalOsGetSystemTimeX();
  end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT);

  /* Waits until BUSY flag is reset or, alternatively, for a timeout
     condition.*/
  while (true) {
    osalSysLock();

    /* If the bus is not busy then the operation can continue, note, the
       loop is exited in the locked state.*/
    if ((dp->ISR & I2C_ISR_BUSY) == 0)
      break;

    /* If the system time went outside the allowed window then a timeout
       condition is returned.*/
    if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) {
      return MSG_TIMEOUT;
    }

    osalSysUnlock();
  }

  /* Setting up the slave address.*/
  i2c_lld_set_address(i2cp, addr);

  /* Setting up the peripheral.*/
  i2c_lld_setup_rx_transfer(i2cp);

#if STM32_I2C_USE_DMA == TRUE
  /* Enabling RX DMA.*/
  dmaStreamEnable(i2cp->dmarx);

  /* Transfer complete interrupt enabled.*/
  dp->CR1 |= I2C_CR1_TCIE;
#else

  /* Transfer complete and RX interrupts enabled.*/
  dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE;
#endif

  /* Starts the operation.*/
  dp->CR2 |= I2C_CR2_START;

  /* Waits for the operation completion or a timeout.*/
  msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);

  /* In case of a software timeout a STOP is sent as an extreme attempt
     to release the bus.*/
  if (msg == MSG_TIMEOUT) {
    dp->CR2 |= I2C_CR2_STOP;
  }

  return msg;
}
Ejemplo n.º 4
0
/**
 * @brief   Starts an ADC conversion.
 *
 * @param[in] adcp      pointer to the @p ADCDriver object
 *
 * @notapi
 */
void adc_lld_start_conversion(ADCDriver *adcp) {
  uint32_t dmamode, ccr, cfgr;
  const ADCConversionGroup *grpp = adcp->grpp;

  chDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0),
              "adc_lld_start_conversion(), #1",
              "odd number of channels in dual mode");

  /* Calculating control registers values.*/
  dmamode = adcp->dmamode;
  ccr     = grpp->ccr | (adcp->adcc->CCR & (ADC_CCR_CKMODE_MASK |
                                            ADC_CCR_MDMA_MASK));
  cfgr    = grpp->cfgr | ADC_CFGR_CONT | ADC_CFGR_DMAEN;
  if (grpp->circular) {
    dmamode |= STM32_DMA_CR_CIRC;
#if STM32_ADC_DUAL_MODE
    ccr  |= ADC_CCR_DMACFG_CIRCULAR;
#else
    cfgr |= ADC_CFGR_DMACFG_CIRCULAR;
#endif
  }

  /* DMA setup.*/
  if (adcp->depth > 1) {
    /* If the buffer depth is greater than one then the half transfer interrupt
       interrupt is enabled in order to allows streaming processing.*/
    dmamode |= STM32_DMA_CR_HTIE;
  }
  dmaStreamSetMemory0(adcp->dmastp, adcp->samples);
#if STM32_ADC_DUAL_MODE
  dmaStreamSetTransactionSize(adcp->dmastp, ((uint32_t)grpp->num_channels/2) *
                                            (uint32_t)adcp->depth);
#else
    dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels *
                                              (uint32_t)adcp->depth);
#endif
  dmaStreamSetMode(adcp->dmastp, dmamode);
  dmaStreamEnable(adcp->dmastp);

  /* Configuring the CCR register with the static settings ORed with
     the user-specified settings in the conversion group configuration
     structure.*/
  adcp->adcc->CCR   = ccr;

  /* ADC setup, if it is defined a callback for the analog watch dog then it
     is enabled.*/
  adcp->adcm->ISR   = adcp->adcm->ISR;
  adcp->adcm->IER   = ADC_IER_OVR | ADC_IER_AWD1;
  adcp->adcm->TR1   = grpp->tr1;
#if STM32_ADC_DUAL_MODE
  adcp->adcm->SMPR1 = grpp->smpr[0];
  adcp->adcm->SMPR2 = grpp->smpr[1];
  adcp->adcm->SQR1  = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
  adcp->adcm->SQR2  = grpp->sqr[1];
  adcp->adcm->SQR3  = grpp->sqr[2];
  adcp->adcm->SQR4  = grpp->sqr[3];
  adcp->adcs->SMPR1 = grpp->ssmpr[0];
  adcp->adcs->SMPR2 = grpp->ssmpr[1];
  adcp->adcs->SQR1  = grpp->ssqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
  adcp->adcs->SQR2  = grpp->ssqr[1];
  adcp->adcs->SQR3  = grpp->ssqr[2];
  adcp->adcs->SQR4  = grpp->ssqr[3];

#else /* !STM32_ADC_DUAL_MODE */
  adcp->adcm->SMPR1 = grpp->smpr[0];
  adcp->adcm->SMPR2 = grpp->smpr[1];
  adcp->adcm->SQR1  = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels);
  adcp->adcm->SQR2  = grpp->sqr[1];
  adcp->adcm->SQR3  = grpp->sqr[2];
  adcp->adcm->SQR4  = grpp->sqr[3];
#endif /* !STM32_ADC_DUAL_MODE */

  /* ADC configuration.*/
  adcp->adcm->CFGR  = cfgr;

  /* Starting conversion.*/
  adcp->adcm->CR   |= ADC_CR_ADSTART;
}
Ejemplo n.º 5
0
/**
 * @brief   Starts a DAC conversion.
 * @details Starts an asynchronous conversion operation.
 * @note    In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the
 *          callback are wrong because two samples are packed in a single
 *          dacsample_t element. This will not be corrected, do not rely
 *          on those parameters.
 * @note    In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated
 *          as a single 16 bits sample and packed into a single dacsample_t
 *          element. The num_channels must be set to one in the group
 *          conversion configuration structure.
 *
 * @param[in] dacp      pointer to the @p DACDriver object
 *
 * @notapi
 */
void dac_lld_start_conversion(DACDriver *dacp) {
  uint32_t n, cr, dmamode;

  /* Number of DMA operations per buffer.*/
  n = dacp->depth * dacp->grpp->num_channels;

  /* Allocating the DMA channel.*/
  bool b = dmaStreamAllocate(dacp->params->dma, dacp->params->dmairqprio,
                             (stm32_dmaisr_t)dac_lld_serve_tx_interrupt,
                             (void *)dacp);
  osalDbgAssert(!b, "stream already allocated");

  /* DMA settings depend on the chosed DAC mode.*/
  switch (dacp->config->datamode) {
  /* Sets the DAC data register */
  case DAC_DHRM_12BIT_RIGHT:
    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR12R1 +
                                              dacp->params->dataoffset);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
    break;
  case DAC_DHRM_12BIT_LEFT:
    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR12L1 +
                                              dacp->params->dataoffset);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
    break;
  case DAC_DHRM_8BIT_RIGHT:
    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR8R1 +
                                              dacp->params->dataoffset);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;

    /* In this mode the size of the buffer is halved because two samples
       packed in a single dacsample_t element.*/
    n = (n + 1) / 2;
    break;
#if STM32_DAC_DUAL_MODE == TRUE
  case DAC_DHRM_12BIT_RIGHT_DUAL:
    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR12RD);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
    n /= 2;
    break;
  case DAC_DHRM_12BIT_LEFT_DUAL:
    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR12LD);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
    n /= 2;
    break;
  case DAC_DHRM_8BIT_RIGHT_DUAL:
    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");

    dmaStreamSetPeripheral(dacp->params->dma, &dacp->params->dac->DHR8RD);
    dmamode = dacp->params->dmamode |
              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
    n /= 2;
    break;
#endif
  default:
    osalDbgAssert(false, "unexpected DAC mode");
    return;
  }

  dmaStreamSetMemory0(dacp->params->dma, dacp->samples);
  dmaStreamSetTransactionSize(dacp->params->dma, n);
  dmaStreamSetMode(dacp->params->dma, dmamode            |
                                      STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
                                      STM32_DMA_CR_HTIE  | STM32_DMA_CR_TCIE);
  dmaStreamEnable(dacp->params->dma);

  /* DAC configuration.*/
#if STM32_DAC_DUAL_MODE == FALSE
  cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << 3) | DAC_CR_TEN1 | DAC_CR_EN1;
  dacp->params->dac->CR &= dacp->params->regmask;
  dacp->params->dac->CR |= cr << dacp->params->regshift;
#else
  dacp->params->dac->CR = 0;
  cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << 3)  | DAC_CR_TEN1 | DAC_CR_EN1
                     | (dacp->grpp->trigger << 19) | DAC_CR_TEN2 | DAC_CR_EN2;
  dacp->params->dac->CR = cr;
#endif
}
Ejemplo n.º 6
0
/**
 * @brief   I2C shared ISR code.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] isr       content of the ISR register to be decoded
 *
 * @notapi
 */
static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
  I2C_TypeDef *dp = i2cp->i2c;

  /* Special case of a received NACK, the transfer is aborted.*/
  if ((isr & I2C_ISR_NACKF) != 0U) {
#if STM32_I2C_USE_DMA == TRUE
    /* Stops the associated DMA streams.*/
    dmaStreamDisable(i2cp->dmatx);
    dmaStreamDisable(i2cp->dmarx);
#endif

    /* Error flag.*/
    i2cp->errors |= I2C_ACK_FAILURE;

    /* Transaction finished sending the STOP.*/
    dp->CR2 |= I2C_CR2_STOP;

    /* Make sure no more interrupts.*/
    dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE);

    /* Errors are signaled to the upper layer.*/
    _i2c_wakeup_error_isr(i2cp);

    return;
  }

#if STM32_I2C_USE_DMA == FALSE
  /* Handling of data transfer if the DMA mode is disabled.*/
  {
    uint32_t cr1 = dp->CR1;

    if (i2cp->state == I2C_ACTIVE_TX) {
      /* Transmission phase.*/
      if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) {
        dp->TXDR = (uint32_t)*i2cp->txptr;
        i2cp->txptr++;
        i2cp->txbytes--;
        if (i2cp->txbytes == 0U) {
          dp->CR1 &= ~I2C_CR1_TXIE;
        }
      }
    }
    else {
      /* Receive phase.*/
      if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) {
        *i2cp->rxptr = (uint8_t)dp->RXDR;
        i2cp->rxptr++;
        i2cp->rxbytes--;
        if (i2cp->rxbytes == 0U) {
          dp->CR1 &= ~I2C_CR1_RXIE;
        }
      }
    }
  }
#endif

  /* Partial transfer handling, restarting the transfer and returning.*/
  if ((isr & I2C_ISR_TCR) != 0U) {
    if (i2cp->state == I2C_ACTIVE_TX) {
      i2c_lld_setup_tx_transfer(i2cp);
    }
    else {
      i2c_lld_setup_rx_transfer(i2cp);
    }
    return;
  }

  /* The following condition is true if a transfer phase has been completed.*/
  if ((isr & I2C_ISR_TC) != 0U) {
    if (i2cp->state == I2C_ACTIVE_TX) {
      /* End of the transmit phase.*/

#if STM32_I2C_USE_DMA == TRUE
      /* Disabling TX DMA channel.*/
      dmaStreamDisable(i2cp->dmatx);
#endif

      /* Starting receive phase if necessary.*/
      if (i2c_lld_get_rxbytes(i2cp) > 0U) {
        /* Setting up the peripheral.*/
        i2c_lld_setup_rx_transfer(i2cp);

#if STM32_I2C_USE_DMA == TRUE
        /* Enabling RX DMA.*/
        dmaStreamEnable(i2cp->dmarx);
#else
        /* RX interrupt enabled.*/
        dp->CR1 |= I2C_CR1_RXIE;
#endif

        /* Starts the read operation.*/
        dp->CR2 |= I2C_CR2_START;

        /* State change.*/
        i2cp->state = I2C_ACTIVE_RX;

        /* Note, returning because the transaction is not over yet.*/
        return;
      }
    }
    else {
      /* End of the receive phase.*/
#if STM32_I2C_USE_DMA == TRUE
      /* Disabling RX DMA channel.*/
      dmaStreamDisable(i2cp->dmarx);
#endif
    }

    /* Transaction finished sending the STOP.*/
    dp->CR2 |= I2C_CR2_STOP;

    /* Make sure no more 'Transfer Complete' interrupts.*/
    dp->CR1 &= ~I2C_CR1_TCIE;

    /* Normal transaction end.*/
    _i2c_wakeup_isr(i2cp);
  }
}
Ejemplo n.º 7
0
/**
 * @brief   Starts an ADC conversion.
 *
 * @param[in] adcp      pointer to the @p ADCDriver object
 *
 * @notapi
 */
void adc_lld_start_conversion(ADCDriver *adcp) {
    uint32_t mode;
    const ADCConversionGroup* grpp = adcp->grpp;

    /* DMA setup.*/
    mode = adcp->dmamode;
    if (grpp->circular) {
        mode |= STM32_DMA_CR_CIRC;
        if (adcp->depth > 1) {
            /* If circular buffer depth > 1, then the half transfer interrupt
               is enabled in order to allow streaming processing.*/
            mode |= STM32_DMA_CR_HTIE;
        }
    }
    dmaStreamSetMemory0(adcp->dmastp, adcp->samples);
    dmaStreamSetTransactionSize(adcp->dmastp,
                                (uint32_t)grpp->num_channels *
                                (uint32_t)adcp->depth);
    dmaStreamSetMode(adcp->dmastp, mode);
    dmaStreamEnable(adcp->dmastp);

#if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC
    if (adcp->adc != NULL)
#endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */
#if STM32_ADC_USE_ADC
    {
        uint32_t cr2 = adcp->adc->CR2 & ADC_CR2_TSVREFE;
        cr2 |= grpp->u.adc.cr2 | ADC_CR2_DMA | ADC_CR2_ADON;
        if ((cr2 & ADC_CR2_SWSTART) != 0)
            cr2 |= ADC_CR2_CONT;
        adcp->adc->CR2   = cr2;

        /* ADC setup.*/
        adcp->adc->SR    = 0;
        adcp->adc->LTR   = grpp->u.adc.ltr;
        adcp->adc->HTR   = grpp->u.adc.htr;
        adcp->adc->SMPR1 = grpp->u.adc.smpr[0];
        adcp->adc->SMPR2 = grpp->u.adc.smpr[1];
        adcp->adc->SQR1  = grpp->u.adc.sqr[0] |
                           ADC_SQR1_NUM_CH(grpp->num_channels);
        adcp->adc->SQR2  = grpp->u.adc.sqr[1];
        adcp->adc->SQR3  = grpp->u.adc.sqr[2];

        /* ADC conversion start, the start is performed using the method
           specified in the CR2 configuration, usually ADC_CR2_SWSTART.*/
        adcp->adc->CR1   = grpp->u.adc.cr1 | ADC_CR1_AWDIE | ADC_CR1_SCAN;
        adcp->adc->CR2   = adcp->adc->CR2;  /* Triggers the conversion start.*/
    }
#endif /* STM32_ADC_USE_ADC */
#if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC
    else if (adcp->sdadc != NULL)
#endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */
#if STM32_ADC_USE_SDADC
    {
        uint32_t cr2 = (grpp->u.sdadc.cr2 & ~SDADC_FORBIDDEN_CR2_FLAGS) |
                       SDADC_CR2_ADON;
        if ((grpp->u.sdadc.cr2 & SDADC_CR2_JSWSTART) != 0)
            cr2 |= SDADC_CR2_JCONT;

        /* Entering initialization mode.*/
        adcp->sdadc->CR1 |= SDADC_CR1_INIT;
        while ((adcp->sdadc->ISR & SDADC_ISR_INITRDY) == 0)
            ;

        /* SDADC setup.*/
        adcp->sdadc->JCHGR    = grpp->u.sdadc.jchgr;
        adcp->sdadc->CONFCHR1 = grpp->u.sdadc.confchr[0];
        adcp->sdadc->CONFCHR2 = grpp->u.sdadc.confchr[1];

        /* Leaving initialization mode.*/
        adcp->sdadc->CR1 &= ~SDADC_CR1_INIT;

        /* SDADC conversion start, the start is performed using the method
           specified in the CR2 configuration, usually SDADC_CR2_JSWSTART.*/
        adcp->sdadc->CR2 = cr2;
    }
#endif /* STM32_ADC_USE_SDADC */
#if STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC
    else {
        chDbgAssert(FALSE, "adc_lld_start_conversion(), #1", "invalid state");
    }
#endif /* STM32_ADC_USE_ADC && STM32_ADC_USE_SDADC */
}
Ejemplo n.º 8
0
void
VSL_Init()
{
    uint32_t tmpreg1 = 0, tmpreg2 = 0;

    // Not available on the Olimex eval card
#if defined (STM32F10X_HD)

    // DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration
    // Once the DAC channel is enabled, the corresponding GPIO pin is automatically 
    // connected to the DAC converter. In order to avoid parasitic consumption, 
    // the GPIO pin should be configured in analog
    // GPIO config now done elsewhere.

    // create a default waveform
    VSL_CreateSineWave( DEFAULT_AMPLITUDE );
 
    // Init timer for 1KHz
    VSL_InitTimer(9, 250);

    // DAC Peripheral clock enable
    rccEnableAPB1((RCC_APB1ENR_DACEN), FALSE );

    // DAC channel1 Configuration
    // Get the DAC CR value */
    tmpreg1 = DAC->CR;
    // Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits */
    tmpreg1 &= ~(CR_CLEAR_MASK << DAC_Channel_1);
    // Configure for the selected DAC channel: buffer output, trigger, wave generation,
    tmpreg2 = (DAC_Trigger_T7_TRGO | DAC_WaveGeneration_None | DAC_LFSRUnmask_Bit0 | DAC_OutputBuffer_Disable);
    // Calculate CR register value depending on DAC_Channel */
    tmpreg1 |= tmpreg2 << DAC_Channel_1;
    // Write to DAC CR */
    DAC->CR = tmpreg1;

    // DMA config
    if( dmaStreamAllocate(vsl_dma, 0, NULL, NULL) == FALSE )
        {
        uint32_t tmpreg = 0;

        tmpreg |= STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_CIRC |
            STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD |
            STM32_DMA_CR_PL(2) | STM32_DMA_CR_MINC;

        dmaStreamSetMode(vsl_dma, tmpreg);

        dmaStreamSetTransactionSize(vsl_dma, WAVE_SAMPLES);
        dmaStreamSetPeripheral(vsl_dma, &DAC->DHR12R1);
        dmaStreamSetMemory0( vsl_dma, (uint32_t)&Sine12bit );

        // Enable DMA2 Channel 3
        dmaStreamEnable(vsl_dma);

        // Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is
        // automatically connected to the DAC converter.
        DAC->CR |= (DAC_CR_EN1 << DAC_Channel_1);

        // Enable DMA for DAC Channel1
        DAC->CR |= (DAC_CR_DMAEN1 << DAC_Channel_1);
        }
#endif
}  
Ejemplo n.º 9
0
/**
 * @brief   Transmits data via the I2C bus as master.
 * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x.
 *          This is hardware restriction.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[in] txbuf     pointer to the transmit buffer
 * @param[in] txbytes   number of bytes to be transmitted
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval RDY_OK       if the function succeeded.
 * @retval RDY_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval RDY_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {
  I2C_TypeDef *dp = i2cp->i2c;
  VirtualTimer vt;
  uint32_t addr_cr2 = addr & I2C_CR2_SADD;

  chDbgCheck(((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))),
             "i2c_lld_master_transmit_timeout");

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2CD_NO_ERROR;

  /* Global timeout for the whole operation.*/
  if (timeout != TIME_INFINITE)
    chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp);

  /* Releases the lock from high level driver.*/
  chSysUnlock();

  /* Waits until BUSY flag is reset and the STOP from the previous operation
     is completed, alternatively for a timeout condition.*/
  while (dp->ISR & I2C_ISR_BUSY) {
    chSysLock();
    if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
      return RDY_TIMEOUT;
    chSysUnlock();
  }

  /* This lock will be released in high level driver.*/
  chSysLock();

  /* Adjust slave address (master mode) for 7-bit address mode */
  if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0)
    addr_cr2 = (addr_cr2 & 0x7f) << 1;

  /* Set slave address field (master mode) */
  dp->CR2 &= ~(I2C_CR2_SADD | I2C_CR2_NBYTES);
  dp->CR2 |= (txbytes << 16) | addr_cr2;

  /* Initializes driver fields */
  i2cp->errors = 0;

  /* TX DMA setup.*/
  dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
  dmaStreamSetMemory0(i2cp->dmatx, txbuf);
  dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);

  /* RX DMA setup.*/
  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);

  /* Enable TX DMA */
  dmaStreamEnable(i2cp->dmatx);

  /* Atomic check on the timer in order to make sure that a timeout didn't
     happen outside the critical zone.*/
  if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
    return RDY_TIMEOUT;

  /* Transmission complete interrupt enabled.*/
  dp->CR1 |= I2C_CR1_TCIE;

  /* Starts the operation as the very last thing.*/
  dp->CR2 &= ~I2C_CR2_RD_WRN;
  dp->CR2 |= I2C_CR2_START;

  /* Waits for the operation completion or a timeout.*/
  i2cp->thread = chThdSelf();
  chSchGoSleepS(THD_STATE_SUSPENDED);
  if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt))
    chVTResetI(&vt);

  return chThdSelf()->p_u.rdymsg;
}
Ejemplo n.º 10
0
Archivo: sound.cpp Proyecto: Kreyl/nute
void Sound_t::ISendNextData() {
//    Uart.Printf("\rSN");
    dmaStreamDisable(VS_DMA);
    IDmaIdle = false;
    // ==== If command queue is not empty, send command ====
    msg_t msg = chMBFetch(&CmdBox, &ICmd.Msg, TIME_IMMEDIATE);
    if(msg == RDY_OK) {
//        Uart.PrintfI("\rvCmd: %A", &ICmd, 4, ' ');
        XCS_Lo();   // Start Cmd transmission
        dmaStreamSetMemory0(VS_DMA, &ICmd);
        dmaStreamSetTransactionSize(VS_DMA, sizeof(VsCmd_t));
        dmaStreamSetMode(VS_DMA, VS_DMA_MODE | STM32_DMA_CR_MINC);  // Memory pointer increase
        dmaStreamEnable(VS_DMA);
    }
    // ==== Send next chunk of data if any ====
    else switch(State) {
        case sndPlaying: {
//            Uart.PrintfI("\rD");
            // Switch buffer if required
            if(PBuf->DataSz == 0) {
                PBuf = (PBuf == &Buf1)? &Buf2 : &Buf1;      // Switch to next buf
//                Uart.Printf("\rB=%u; Sz=%u", ((PBuf == &Buf1)? 1 : 2), PBuf->DataSz);
                if(PBuf->DataSz == 0) { // Previous attempt to read the file failed
                    IDmaIdle = true;
                    PrepareToStop();
                    break;
                }
                else {
                    chSysLock();
                    chEvtSignalI(PThread, VS_EVT_READ_NEXT);    // Read next chunk of file
                    chSysUnlock();
                }
            }
            // Send next piece of data
            XDCS_Lo();  // Start data transmission
            uint32_t FLength = (PBuf->DataSz > 32)? 32 : PBuf->DataSz;
            dmaStreamSetMemory0(VS_DMA, PBuf->PData);
            dmaStreamSetTransactionSize(VS_DMA, FLength);
            dmaStreamSetMode(VS_DMA, VS_DMA_MODE | STM32_DMA_CR_MINC);  // Memory pointer increase
            dmaStreamEnable(VS_DMA);
//            if(PBuf == &Buf1) Uart.Printf("*"); else Uart.Printf("#");
            // Process pointers and lengths
            PBuf->DataSz -= FLength;
            PBuf->PData += FLength;
        } break;

        case sndWritingZeroes:
//            Uart.Printf("\rZ");
            if(ZeroesCount == 0) { // Was writing zeroes, now all over
                State = sndStopped;
                IDmaIdle = true;
//                Uart.Printf("\rvEnd");
                chSysLock();
                chEvtSignalI(PThread, VS_EVT_COMPLETED);
                chSysUnlock();
            }
            else SendZeroes();
            break;

        case sndStopped:
//            Uart.PrintfI("\rI");
            if(!IDreq.IsHi()) IDreq.EnableIrq(IRQ_PRIO_MEDIUM);
            else IDmaIdle = true;
    } // switch
}
Ejemplo n.º 11
0
void Lcd_t::Init(void) {
    BckLt.Init();
    // ==== GPIOs ====
    // Configure LCD_XRES, LCD_XCS, LCD_SCLK & LCD_SDA as Push-Pull output
    PinSetupOut(LCD_GPIO, LCD_XRES, omPushPull);
    PinSetupOut(LCD_GPIO, LCD_XCS,  omPushPull);
    PinSetupOut(LCD_GPIO, LCD_SCLK, omPushPull);
    PinSetupOut(LCD_GPIO, LCD_SDA,  omPushPull);
    // ========================= Init LCD ======================================
    SCLK_Lo();
    XCS_Hi();
    // Reset display
    XRES_Lo();
    chThdSleepMilliseconds(7);
    XRES_Hi();
    IWriteCmd(0xAF);    // display ON
    // Reset display again
    XRES_Lo();
    chThdSleepMilliseconds(7);
    XRES_Hi();
    chThdSleepMilliseconds(7);
    // Initial commands
    IWriteCmd(0xAF);    // display ON
    IWriteCmd(0xA4);    // Set normal display mode
    IWriteCmd(0x2F);    // Charge pump on
    IWriteCmd(0x40);    // Set start row address = 0

#if LCD_MIRROR_Y_AXIS
    IWriteCmd(0xC8);    // Mirror Y axis
#endif
#if LCD_MIRROR_X_AXIS
    IWriteCmd(0xA1);    // Mirror X axis
#endif
    // Set x=0, y=0
    IWriteCmd(0xB0);    // Y axis initialization
    IWriteCmd(0x10);    // X axis initialisation1
    IWriteCmd(0x00);    // X axis initialisation2
    Cls();

#if LCD_DMA_BASED // ================ Switch to USART + DMA ====================
    PinSetupAlterFunc(LCD_GPIO, LCD_SCLK, omPushPull, pudNone, AF7, ps40MHz);
    PinSetupAlterFunc(LCD_GPIO, LCD_SDA,  omPushPull, pudNone, AF7, ps40MHz);
    // ==== USART init ==== clock enabled, idle low, first edge, enable last bit pulse
    rccEnableUSART3(FALSE);
    USART3->CR1 = USART_CR1_UE;     // Enable
    USART3->BRR = Clk.APB1FreqHz / LCD_UART_SPEED;
    USART3->CR2 = USART_CR2_CLKEN | USART_CR2_LBCL; // Enable clock, enable last bit clock
    USART3->CR1 = USART_CR1_UE | USART_CR1_M | USART_CR1_TE;
    USART3->CR3 = USART_CR3_DMAT;   // Enable DMA at transmitter
    // DMA
    dmaStreamAllocate     (LCD_DMA, IRQ_PRIO_LOW, nullptr, NULL);
    dmaStreamSetPeripheral(LCD_DMA, &USART3->DR);
    dmaStreamSetMemory0   (LCD_DMA, IBuf);
    dmaStreamSetTransactionSize(LCD_DMA, LCD_VIDEOBUF_SIZE);
    dmaStreamSetMode      (LCD_DMA, LCD_DMA_TX_MODE);
    // Start transmission
    XCS_Lo();
    dmaStreamEnable(LCD_DMA);
#else

#endif
    chSemInit(&semLcd, 1);
}